ChannelDeck/ChannelDeckStore.tsx

126 lines
4 KiB
TypeScript

import { proxyLazyWebpack } from "@webpack";
import { Flux, FluxDispatcher, PopoutActions, PopoutWindowStore, SnowflakeUtils } from "@webpack/common";
import DeckPopout from "./components/DeckPopout";
import { DataStore } from "@api/index";
export interface ChannelDeck {
id: string;
name: string;
color?: number;
columns: DeckColumn[];
open: boolean;
}
export interface DeckColumn {
channelId: string,
width: `${number}px` | `${number}%`;
}
export const ChannelDeckStore = proxyLazyWebpack(() => {
class ChannelDeckStore extends Flux.Store {
public _decks = new Map<string, ChannelDeck>();
public loaded = false;
public pageUnloading = false;
public windowKeyPrefix = "DISCORD_VC_CHANNELDECK_";
public dataStoreKey = "ChannelDeck_Decks";
public createDeck(deckState: Partial<Omit<ChannelDeck, "id">>) {
const deck = {
id: SnowflakeUtils.fromTimestamp(Date.now()),
name: "",
columns: [],
open: false,
...deckState
};
this.setDeck(deck);
return deck;
}
public getDeck(id: string) {
return this._decks.get(id);
}
public setDeck(deck: ChannelDeck, noWrite?: boolean) {
this._decks.set(deck.id, deck);
const { id } = deck;
const windowKey = this.windowKeyPrefix + id;
// @ts-ignore
if (deck?.open && !PopoutWindowStore.getWindowOpen(windowKey))
PopoutActions.open(
windowKey,
(key) => <DeckPopout deckId={id} windowKey={key} />, {
defaultWidth: 1200,
defaultHeight: 960
});
// We cannot add a beforeunload event to the window here, it will be never fired as Discord has their own handler.
// @ts-ignore
if (!deck?.open && PopoutWindowStore.getWindowOpen(windowKey))
this.getDeckWindow(id).close();
if (noWrite || !this.loaded) return;
this.writeData();
this.emitChange();
};
public deleteDeck(deck: ChannelDeck) {
// Close window
this.setDeck({ ...deck, open: false }, true);
this._decks.delete(deck.id);
this.writeData();
// @ts-ignore
delete PopoutWindowStore.getState()[this.windowKeyPrefix + deck.id];
// @ts-ignore
PopoutWindowStore.persist();
this.emitChange();
}
public getDecks() {
return this._decks.values();
}
public getDeckWindow(id: string) {
return PopoutWindowStore.getWindow(this.windowKeyPrefix + id);
}
// Workaround for Discord's beforeunload event
public syncClosedWindows() {
if (this.pageUnloading) return;
this._decks.forEach((deck) => {
// @ts-ignore
if (deck.open && !PopoutWindowStore.getWindowOpen(this.windowKeyPrefix + deck.id))
this.setDeck({ ...deck, open: false });
});
}
public async loadData() {
this.loaded = true;
const decks: Map<string, ChannelDeck> | undefined = await DataStore.get(this.dataStoreKey);
if (decks) {
this._decks.clear();
decks.forEach(deck => this.setDeck(deck, true));
}
}
public async unloadData() {
// closes all decks
this.loaded = false;
this._decks.forEach(deck => this.setDeck({ ...deck, open: false }, true));
this._decks.clear();
}
public async writeData() {
await DataStore.set(this.dataStoreKey, this._decks);
}
}
const store = new ChannelDeckStore(FluxDispatcher, {
});
window.addEventListener("beforeunload", () => store.pageUnloading = true);
PopoutWindowStore.addChangeListener(() => store.syncClosedWindows());
return store;
});;