import { MutableRefObject } from "react"; import { toast } from "react-toastify"; import { runInAction } from "mobx"; import { sprintf } from "sprintf-js"; import CryptoJS from "crypto-js"; import { TFunction } from "i18next"; import SiteComponent from "src/site/SiteComponent"; import { Avatar, Site, SiteView, SiteYell, SiteViewHandler, AbilitySiteYell, } from "src/site/Site"; import { formatText, getAbilityUpText, getDefaultAvatarID, getGenreText, getSiteName, } from "src/Utility"; import { wwwAPI, wwwAXIOS } from "src/Www"; const EventPB = require("src/Event_pb"); const getSiteYellItem = ({ avatarID, avatarName, siteYell, date, siteYellID, }: { avatarID: string; avatarName: string; siteYell: string; date: number; siteYellID: number; }): SiteYell | null => { const dateText = new Date(date).toLocaleTimeString(); switch (avatarName) { case "@Enter": return { siteYellID, avatarID, avatarName: siteYell, siteYellVariety: avatarName, date: dateText, }; case "@Quit": return { siteYellID, avatarID, avatarName: siteYell, siteYellVariety: avatarName, date: dateText, }; case "@Site": return { siteYellID, avatarID, avatarName: siteYell, siteYellVariety: avatarName, date: dateText, }; case "@Net": return { siteYellID, avatarID, avatarName: siteYell, siteYellVariety: avatarName, date: dateText, }; case "@Notify": return { siteYellID, avatarID, siteYellVariety: avatarName, date: dateText, siteYell, }; case "@Wiped": return { siteYellID, avatarID, avatarName: siteYell, siteYellVariety: avatarName, date: dateText, }; case "@Invite": case "@Comment": case "@Ability": case "@Level": case "@TV": return { siteYellID, avatarID, siteYellVariety: avatarName, date: dateText, siteYell: JSON.parse(siteYell), }; case "": return { siteYellID, siteYellVariety: "", siteYell, }; default: return { siteYellID, siteYellVariety: null, date: dateText, avatarID, avatarName, siteYell, }; } }; export default function setSiteStore() { return { avatars: [] as Avatar[], siteYells: [] as SiteYell[], sites: [] as Site[], isSignInOpened: false, isSiteWindowOpened: false, isSiteCipherWindowOpened: false, isNewSiteWindowOpened: false, isConfigureOpened: false, targetSiteID: "", siteNotify: "", saveData: window.localStorage.getItem("saveData") === "true", autoEnterNotify: window.localStorage.getItem("autoEnterNotify") !== "false", autoEnterDefault: window.localStorage.getItem("autoEnterDefault") !== "false", autoEnterPlatform: window.localStorage.getItem("autoEnterPlatform") !== "false", isEditable: true, input: "", siteViews: [] as SiteView[], siteAvatarID: "", siteAvatarName: "", isSignedIn: false, isSiteYellsViewLowest: true, isVisible: false, isLoading: true, lastPendingSiteYell: undefined as SiteYell | undefined, isPendingSiteYellOpened: false, isAvatarsOpened: false, setEventHandler( siteYellsView: MutableRefObject<HTMLDivElement | null>, t: TFunction, ) { const autoEnter = () => { if (this.autoEnterNotify) { SiteComponent.send({ eventID: EventPB.Event.EventID.ENTER_SITE, text: JSON.stringify({ siteID: "00000000-0000-0000-0000-000000000000", siteCipher: "", }), }); } if (this.autoEnterDefault) { SiteComponent.send({ eventID: EventPB.Event.EventID.ENTER_SITE, text: JSON.stringify({ siteID: "00000000-0000-0000-0000-000000000001", siteCipher: "", }), }); } if (this.autoEnterPlatform) { SiteComponent.send({ eventID: EventPB.Event.EventID.ENTER_SITE, text: JSON.stringify({ siteID: "00000000-0000-0000-0000-000000000002", siteCipher: "", }), }); } }; const autoSignIn = () => { if (window.localStorage.getItem("autoSignIn") === "true") { SiteComponent.send({ eventID: EventPB.Event.EventID.SIGN_IN, text: JSON.stringify({ avatarID: window.localStorage.getItem("avatarID") ?? "", avatarCipher: CryptoJS.AES.decrypt( window.localStorage.getItem("avatarCipher") ?? "", "591A6F91-2A27-4A88-88FA-0FEB7CB5FD94", ).toString(CryptoJS.enc.Utf8), }), }); } }; const doNotify = (avatarID: string, toNotify: string, siteID: string) => { if ( !["denied", "default"].includes(Notification?.permission) && !this.isVisible ) { const siteView = this.getSiteView(siteID); if (siteView?.wasNotify === false) { new Notification("Qwilight", { body: toNotify, icon: `${wwwAPI}/drawing?avatarID=${encodeURIComponent( getDefaultAvatarID(avatarID), )}&drawingVariety=0`, }); siteView.wasNotify = true; } } }; SiteComponent.setEventDefaultHandler(({ eventID, text }) => { switch (eventID) { case EventPB.Event.EventID.ESTABLISH: if (text) { const { avatarID, avatarName } = JSON.parse(text); this.setSiteAvatar(avatarID, avatarName); this.setLoading(false); autoEnter(); const totem = window.sessionStorage.getItem("totem"); if (totem) { SiteComponent.send({ eventID: EventPB.Event.EventID.SIGN_IN, text: totem, }); } else { autoSignIn(); } } break; case EventPB.Event.EventID.FAILED_VALIDATE_TOTEM: autoSignIn(); break; // EventPB.Event.EventID.SIGN_IN case undefined: if (text) { this.setSignInOpened(false); const { totem, avatarID, avatarName } = JSON.parse(text); if (totem !== window.sessionStorage.getItem("totem")) { toast.success(sprintf(t("signedInText"), avatarName)); } window.sessionStorage.setItem("totem", totem); this.setSiteAvatar(avatarID, avatarName); this.setSignedIn(true); autoEnter(); } break; case EventPB.Event.EventID.NOT_SIGN_IN: if (text) { toast.success(sprintf(t("notSignedInText"), this.siteAvatarName)); window.sessionStorage.removeItem("totem"); const { avatarID, avatarName } = JSON.parse(text); this.setSiteAvatar(avatarID, avatarName); this.setSignedIn(false); autoEnter(); } break; case EventPB.Event.EventID.SITE_YELL: if (text) { const { siteID, avatarID, avatarName, siteYell, siteYellID, date, } = JSON.parse(text); const siteYellItem = getSiteYellItem({ avatarID, avatarName, siteYell, date, siteYellID, }); if (siteYellItem) { this.putSiteYell(siteID, siteYellItem, false); if (this.targetSiteID === siteID) { this.putTargetSiteYell(siteYellItem, false); if ( avatarID === this.siteAvatarID || this.isSiteYellsViewLowest ) { this.siteYellsViewMove(siteYellsView); } else { this.lastPendingSiteYell = siteYellItem; this.setPendingSiteYellOpened(true); } } else { this.setModifiedSiteViews(siteID, (siteView) => { siteView.isNew = true; }); } } const ltDate = new Date(Number(date)).toLocaleTimeString(); let toNotify = ""; switch (avatarName) { case "@Notify": if (this.targetSiteID === siteID) { this.siteNotify = siteYell; } else { const siteView = this.getSiteView(siteID); if (siteView) { siteView.siteNotify = siteYell; } } toNotify = `${t("siteYellTaehui")} (${ltDate}) ${siteYell}`; break; case "@Comment": { const { avatarName, artist, title, genre, levelText, stand } = JSON.parse(siteYell); toNotify = `${avatarName} (${ltDate}) ${levelText} ${artist} - ${title} ${getGenreText( genre, )} ${sprintf(t("standUnit"), formatText(stand))}`; break; } case "@Ability": { toNotify = getAbilityUpText( t, JSON.parse(siteYell) as AbilitySiteYell, ); break; } case "@Level": { const { title } = JSON.parse(siteYell); toNotify = sprintf(t("wwwLevelClearText"), title); break; } case "@Enter": { toNotify = `${siteYell} ${ltDate} ${t("siteYellEnter")}`; break; } case "@Quit": { toNotify = `${siteYell} ${ltDate} ${t("siteYellQuit")}`; break; } case "@Invite": { const { avatarName, siteName } = JSON.parse(siteYell); toNotify = `${avatarName} (${ltDate}) ${sprintf( t("siteYellInvite"), siteName, )}`; break; } case "@TV": { const { title, text } = JSON.parse(siteYell); toNotify = `${text} (${ltDate}) ${sprintf( t("siteYellTV"), title, )}`; break; } case "@Wiped": toNotify = `${avatarName} (${ltDate}) ${t("wipedSiteYell")}`; break; case "": toNotify = siteYell; break; case null: toNotify = `${avatarName} (${ltDate}) ${siteYell}`; break; } if (toNotify) { doNotify(avatarID, toNotify, siteID); } } break; case EventPB.Event.EventID.MODIFY_SITE_YELL: if (text) { const { siteID, siteYell, siteYellID } = JSON.parse(text); this.doModifySiteYell(siteID, siteYell, siteYellID); if (this.targetSiteID === siteID) { this.doModifyTargetSiteYell(siteYell, siteYellID); } } break; case EventPB.Event.EventID.ERASE_SITE_YELL: if (text) { const { siteID, siteYellID } = JSON.parse(text); this.wipeSiteYell(siteID, siteYellID); if (this.targetSiteID === siteID) { this.wipeTargetSiteYell(siteYellID); } } break; case EventPB.Event.EventID.GET_SITE_YELLS: if (text) { const { current } = siteYellsView; if (current) { const lastPosition1BeforeCalled = current.scrollHeight - current.clientHeight; const { siteID, data } = JSON.parse(text); data .reverse() .map(getSiteYellItem) .forEach((siteYellItem: SiteYell) => { this.putSiteYell(siteID, siteYellItem, true); if (this.targetSiteID === siteID) { this.putTargetSiteYell(siteYellItem, true); } }); setTimeout(() => { current.scrollTop = current.scrollHeight - current.clientHeight - lastPosition1BeforeCalled; }, 0); } } break; case EventPB.Event.EventID.CALL_SITE_AVATAR: if (text) { const { siteID, siteName, situationValue, data, siteHand } = JSON.parse(text); const avatars = data.map( ({ avatarID, avatarName, avatarConfigure, isValve, isAudioInput, }: { avatarID: string; avatarName: string; avatarConfigure: number; isValve: boolean; isAudioInput: boolean; }) => { return { avatarID, avatarName, avatarConfigure, isSiteHand: avatarID === siteHand, isMe: this.siteAvatarID === avatarID, isValve, isAudioInput, }; }, ); this.setModifiedSiteViews(siteID, (siteView) => { siteView.siteName = getSiteName(siteName, t); siteView.avatars = avatars; siteView.siteHand = siteHand; siteView.situationValue = situationValue; }); if (siteID === this.targetSiteID) { this.setAvatars(avatars); } } break; case EventPB.Event.EventID.ENTER_SITE: if (text) { const { siteID, siteNotify, isEditable, isNetMode, data } = JSON.parse(text); this.putSiteView({ siteID, isEditable, isNew: false, wasNotify: false, siteNotify, siteName: "", siteHand: "", situationValue: 0, isNetMode, avatars: [], siteYells: data.map(getSiteYellItem), }); this.onSiteIDModified(siteID, siteYellsView); } break; case EventPB.Event.EventID.QUIT_SITE: if (text) { this.quitSiteView(text); this.onSiteIDModified( this.siteViews[this.siteViews.length - 1]?.siteID, siteYellsView, ); } break; case EventPB.Event.EventID.WARNING: toast.warning(text); break; case EventPB.Event.EventID.NOTIFY_YES: toast.success(text); break; case EventPB.Event.EventID.NOTIFY_INFO: toast.info(text); break; case EventPB.Event.EventID.POST_FILE: if (text) { this.setInput(text); } break; } }); }, setEventCloseHandler( siteYellsView: MutableRefObject<HTMLDivElement | null>, ) { SiteComponent.setEventCloseHandler(() => { this.setSiteAvatar("", ""); this.setSignedIn(false); this.onSiteIDModified("", siteYellsView); this.wipeSiteViews(); this.setLoading(true); }); }, setPendingSiteYellOpened(isPendingSiteYellOpened: boolean) { this.isPendingSiteYellOpened = isPendingSiteYellOpened; }, setLoading(isLoading: boolean) { this.isLoading = isLoading; }, setSiteAvatar(siteAvatarID: string, siteAvatarName: string) { this.siteAvatarID = siteAvatarID; this.siteAvatarName = siteAvatarName; SiteComponent.setAvatarID(this.siteAvatarID); }, putSiteYell(siteID: string, siteYell: SiteYell, isGetSiteYell: boolean) { const siteView = this.getSiteView(siteID); if (isGetSiteYell) { siteView?.siteYells?.unshift(siteYell); } else { siteView?.siteYells?.push(siteYell); } }, putTargetSiteYell(siteYell: SiteYell, isGetSiteYell: boolean) { if (isGetSiteYell) { this.siteYells.unshift(siteYell); } else { this.siteYells.push(siteYell); } }, doModifySiteYell(siteID: string, siteYell: string, siteYellID: number) { const targetSiteYell = this.getSiteView(siteID)?.siteYells?.find( (siteYell) => siteYell.siteYellID === siteYellID, ); if (targetSiteYell) { targetSiteYell.siteYell = siteYell; } }, doModifyTargetSiteYell(siteYell: string, siteYellID: number) { const targetSiteYell = this.siteYells?.find( (siteYell) => siteYell.siteYellID === siteYellID, ); if (targetSiteYell) { targetSiteYell.siteYell = siteYell; } }, wipeSiteYell(siteID: string, siteYellID: number) { const siteYells = this.getSiteView(siteID)?.siteYells; if (siteYells) { const i = siteYells.findIndex( (siteYell) => siteYell.siteYellID === siteYellID, ); const siteYell = siteYells[i]; siteYells.splice(i, 1, { siteYellID, avatarID: siteYell.avatarID, avatarName: siteYell.avatarName, siteYellVariety: "@Wiped", date: siteYell.date, }); } }, wipeTargetSiteYell(siteYellID: number) { const i = this.siteYells.findIndex( (siteYell) => siteYell.siteYellID === siteYellID, ); const siteYell = this.siteYells[i]; this.siteYells.splice(i, 1, { siteYellID, avatarID: siteYell.avatarID, avatarName: siteYell.avatarName, siteYellVariety: "@Wiped", date: siteYell.date, }); }, setModifiedSiteViews(targetSiteID: string, onModified: SiteViewHandler) { const tmpSiteView = this.siteViews.find( ({ siteID }) => targetSiteID === siteID, ); if (tmpSiteView) { onModified(tmpSiteView); } }, setInput(input: string) { this.input = input; }, setSaveData(saveData: boolean) { this.saveData = saveData; }, setAutoEnterNotify(autoEnterNotify: boolean) { this.autoEnterNotify = autoEnterNotify; }, setAutoEnterDefault(autoEnterDefault: boolean) { this.autoEnterDefault = autoEnterDefault; }, setAutoEnterPlatform(autoEnterPlatform: boolean) { this.autoEnterPlatform = autoEnterPlatform; }, async getSites(t: TFunction) { const { status, data } = await wwwAXIOS.get<Site[]>("/sites"); if (status === 200) { runInAction(() => { this.sites = data.map( ({ siteID, siteName, siteConfigure, hasCipher, avatarCount }) => { return { siteID, siteName: getSiteName(siteName, t), siteConfigure, hasCipher, avatarCount, }; }, ); this.setSiteWindowOpened(true); }); } }, setSignInOpened(isSignInOpened: boolean) { this.isSignInOpened = isSignInOpened; }, setSiteWindowOpened(isSiteWindowOpened: boolean) { this.isSiteWindowOpened = isSiteWindowOpened; }, setSiteCipherWindowOpened(isSiteCipherWindowOpened: boolean) { this.isSiteCipherWindowOpened = isSiteCipherWindowOpened; }, setNewSiteWindowOpened(isNewSiteWindowOpened: boolean) { this.isNewSiteWindowOpened = isNewSiteWindowOpened; }, setConfigureOpened(isConfigureOpened: boolean) { this.isConfigureOpened = isConfigureOpened; }, setSiteYellsViewLowest(isSiteYellsViewLowest: boolean) { this.isSiteYellsViewLowest = isSiteYellsViewLowest; }, getSiteView(targetSiteID: string) { return this.siteViews.find(({ siteID }) => siteID === targetSiteID); }, onSiteIDModified( siteID: string, siteYellsView: MutableRefObject<HTMLDivElement | null>, ) { this.targetSiteID = siteID; const siteView = this.getSiteView(siteID); if (siteView) { if (this.isVisible) { siteView.wasNotify = false; } this.setModifiedSiteViews(siteID, (siteView) => { siteView.isNew = false; }); this.isEditable = siteView.isEditable; this.siteNotify = siteView.siteNotify; this.avatars = [...siteView.avatars]; this.siteYells = [...siteView.siteYells]; this.siteYellsViewMove(siteYellsView); } else { this.isEditable = false; this.siteNotify = ""; this.avatars = []; this.siteYells = []; } }, setVisible() { return (this.isVisible = document.visibilityState === "visible"); }, siteYellsViewMove(siteYellsView: MutableRefObject<HTMLDivElement | null>) { setTimeout(() => { const { current } = siteYellsView; if (current) { current.scrollTop = current.scrollHeight; } }, 0); }, setAvatarsOpened(isAvatarsOpened: boolean) { this.isAvatarsOpened = isAvatarsOpened; }, setSignedIn(isSignedIn: boolean) { this.isSignedIn = isSignedIn; }, setAvatars(avatars: Avatar[]) { this.avatars = avatars; }, putSiteView(siteView: SiteView) { this.siteViews.push(siteView); }, quitSiteView(siteID: string) { this.siteViews.splice( this.siteViews.findIndex((siteView) => siteView.siteID === siteID), 1, ); }, wipeSiteViews() { this.siteViews = []; }, }; }