126 lines
4 KiB
TypeScript
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;
|
|
});;
|