diff --git a/src/equicordplugins/questify/components/questButton.tsx b/src/equicordplugins/questify/components/questButton.tsx index 460ec03ab..41c07ea06 100644 --- a/src/equicordplugins/questify/components/questButton.tsx +++ b/src/equicordplugins/questify/components/questButton.tsx @@ -10,10 +10,10 @@ import { findComponentByCodeLazy } from "@webpack"; import { ContextMenuApi, Menu, NavigationRouter, useState } from "@webpack/common"; import type { CSSProperties, JSX, MouseEvent } from "react"; -import { initialQuestDataFetched } from ".."; +import { getQuestifySettings, useQuestifySettings } from "../settings/access"; import type { QuestButtonAction, QuestButtonDisplayMode, QuestButtonIndicatorMode } from "../settings/def"; import { getIgnoredQuestIDs, ignoreAllQuests, resetIgnoredQuests } from "../settings/ignoredQuests"; -import { settings } from "../settings/store"; +import { initialQuestDataFetched } from "../state"; import { fetchAndAlertQuests } from "../utils/fetching"; import { decimalToRGB, formatLowerBadge, isDarkish, leftClick, middleClick, q, QUEST_PAGE, rightClick } from "../utils/ui"; import { openQuestifySettingsModal } from "./settingsModal"; @@ -139,7 +139,7 @@ export function showQuestButton(displayMode: QuestButtonDisplayMode, badgeCount: } export function disguiseHomeButton(pathname: string): boolean { - const buttonSettings = settings.use(["questButtonDisplay", "questButtonBadgeCount", "isOnQuestsPage"]); + const buttonSettings = useQuestifySettings(["questButtonDisplay", "questButtonBadgeCount", "isOnQuestsPage"]); if (!showQuestButton(buttonSettings.questButtonDisplay, buttonSettings.questButtonBadgeCount, buttonSettings.isOnQuestsPage)) { return false; @@ -190,7 +190,7 @@ function getQuestButtonLowerBadgeProps( export function QuestButtonContextMenu({ dummy = false }: { dummy?: boolean; }): JSX.Element { const navId = q(dummy ? "dummy-quest-button-context-menu" : "quest-button-context-menu"); - const markAllIgnoredDisabled = dummy || settings.store.questButtonBadgeCount <= 0; + const markAllIgnoredDisabled = dummy || getQuestifySettings().questButtonBadgeCount <= 0; const resetIgnoredDisabled = dummy || getIgnoredQuestIDs().length <= 0; const fetchQuestsDisabled = dummy; @@ -232,7 +232,7 @@ export function QuestButton(): JSX.Element { questButtonMiddleClickAction, questButtonRightClickAction, questButtonIndicator, - } = settings.use([ + } = useQuestifySettings([ "isOnQuestsPage", "questButtonBadgeColor", "questButtonDisplay", diff --git a/src/equicordplugins/questify/components/questButtonSettings.tsx b/src/equicordplugins/questify/components/questButtonSettings.tsx index f53ff07bb..6378bc130 100644 --- a/src/equicordplugins/questify/components/questButtonSettings.tsx +++ b/src/equicordplugins/questify/components/questButtonSettings.tsx @@ -7,10 +7,10 @@ import { QuestRewardType, QuestTaskType } from "@vencord/discord-types/enums"; import type { JSX } from "react"; +import { getQuestifySettings, useQuestifySettings } from "../settings/access"; import { type QuestButtonAction, type QuestButtonDisplayMode, type QuestButtonIncludedTypes, type QuestButtonIndicatorMode } from "../settings/def"; import { startAutoFetchingQuests } from "../settings/fetching"; import { validateIgnoredQuests } from "../settings/ignoredQuests"; -import { settings } from "../settings/store"; import { canShowBadge, canShowButton, canShowPill } from "../utils/ui"; import { DummyQuestButton } from "./questButton"; import { type ManaSelectOption, SettingsCard, SettingsColorPicker, SettingsDescription, SettingsHeader, SettingsRow, SettingsRowItem, SettingsSelect, SettingsSubheader } from "./shared"; @@ -76,7 +76,7 @@ const questButtonRewardTypeManaOptions = toManaOptions(questButtonRewardTypeOpti const questButtonQuestTypeManaOptions = toManaOptions(questButtonQuestTypeOptions); export function QuestButtonSetting(): JSX.Element { - const questButton = settings.use([ + const questButton = useQuestifySettings([ "disableQuestsEverything", "questButtonDisplay", "questButtonIncludedTypes", @@ -102,36 +102,36 @@ export function QuestButtonSetting(): JSX.Element { function updateQuestButtonDisplay(value: string | string[] | null) { if (typeof value !== "string") return; - settings.store.questButtonDisplay = value as QuestButtonDisplayMode; + getQuestifySettings().questButtonDisplay = value as QuestButtonDisplayMode; startAutoFetchingQuests(true); } function updateQuestButtonIndicator(value: string | string[] | null) { if (typeof value !== "string") return; - settings.store.questButtonIndicator = value as QuestButtonIndicatorMode; + getQuestifySettings().questButtonIndicator = value as QuestButtonIndicatorMode; startAutoFetchingQuests(true); } function updateQuestButtonAction(key: "questButtonLeftClickAction" | "questButtonMiddleClickAction" | "questButtonRightClickAction", value: string | string[] | null) { if (typeof value !== "string") return; - settings.store[key] = value as QuestButtonAction; + getQuestifySettings()[key] = value as QuestButtonAction; } function updateBadgeColor(value: number | null) { - settings.store.questButtonBadgeColor = value; + getQuestifySettings().questButtonBadgeColor = value; } function updateIncludedTypes(options: readonly QuestButtonIncludedTypeOption[], value: string | string[] | null) { const selectedValues = new Set(Array.isArray(value) ? value : value ? [value] : []); - const nextIncludedTypes = { ...settings.store.questButtonIncludedTypes }; + const nextIncludedTypes = { ...getQuestifySettings().questButtonIncludedTypes }; for (const option of options) { nextIncludedTypes[option.value] = selectedValues.has(String(option.value)); } - settings.store.questButtonIncludedTypes = nextIncludedTypes; + getQuestifySettings().questButtonIncludedTypes = nextIncludedTypes; validateIgnoredQuests(); } diff --git a/src/equicordplugins/questify/components/questFeaturesSetting.tsx b/src/equicordplugins/questify/components/questFeaturesSetting.tsx index a388c1c86..d540a6930 100644 --- a/src/equicordplugins/questify/components/questFeaturesSetting.tsx +++ b/src/equicordplugins/questify/components/questFeaturesSetting.tsx @@ -7,8 +7,8 @@ import { QuestTaskType } from "@vencord/discord-types/enums"; import type { JSX } from "react"; +import { getQuestifySettings, useQuestifySettings } from "../settings/access"; import { autoCompleteQuestTaskTypes, defaultAllowChangingDangerousSettings, defaultAutoCompleteQuestsSimultaneously, defaultAutoCompleteQuestTypes, defaultCompleteVideoQuestsQuicker, defaultMakeMobileVideoQuestsDesktopCompatible, defaultResumeInterruptedQuests, isDesktopCompatible } from "../settings/def"; -import { settings } from "../settings/store"; import { Alerts, q } from "../utils/ui"; import { ManaButton, type ManaSelectOption, SettingsCard, SettingsDescription, SettingsHeader, SettingsNotice, SettingsParagraph, SettingsSelect, SettingsSubheader, SettingsSubtleSwitch } from "./shared"; @@ -119,7 +119,7 @@ function SettingsAllowDangerousButton({ } export function QuestFeaturesSetting(): JSX.Element { - const questFeatures = settings.use([ + const questFeatures = useQuestifySettings([ "disableQuestsEverything", "disableSponsoredBanner", "disableRelocationNotices", @@ -148,7 +148,7 @@ export function QuestFeaturesSetting(): JSX.Element { const selectedKeys = new Set(Array.isArray(value) ? value : value ? [value] : []); for (const { key } of disableFeatureOptions) { - settings.store[key] = selectedKeys.has(key); + getQuestifySettings()[key] = selectedKeys.has(key); } } @@ -174,12 +174,12 @@ export function QuestFeaturesSetting(): JSX.Element { nextAutoCompleteQuestTypes[questType] = nextValue; } - settings.store.autoCompleteQuestTypes = nextAutoCompleteQuestTypes; + getQuestifySettings().autoCompleteQuestTypes = nextAutoCompleteQuestTypes; } function updateDisableEverything(checked: boolean) { function setDisableEverything() { - settings.store.disableQuestsEverything = checked; + getQuestifySettings().disableQuestsEverything = checked; } if (checked) { @@ -196,17 +196,19 @@ export function QuestFeaturesSetting(): JSX.Element { } function resetDangerousSettings() { - settings.store.allowChangingDangerousSettings = defaultAllowChangingDangerousSettings; - settings.store.autoCompleteQuestsSimultaneously = defaultAutoCompleteQuestsSimultaneously; - settings.store.completeVideoQuestsQuicker = defaultCompleteVideoQuestsQuicker; - settings.store.makeMobileVideoQuestsDesktopCompatible = defaultMakeMobileVideoQuestsDesktopCompatible; - settings.store.resumeInterruptedQuests = defaultResumeInterruptedQuests; - settings.store.autoCompleteQuestTypes = { ...defaultAutoCompleteQuestTypes }; + const settings = getQuestifySettings(); + + settings.allowChangingDangerousSettings = defaultAllowChangingDangerousSettings; + settings.autoCompleteQuestsSimultaneously = defaultAutoCompleteQuestsSimultaneously; + settings.completeVideoQuestsQuicker = defaultCompleteVideoQuestsQuicker; + settings.makeMobileVideoQuestsDesktopCompatible = defaultMakeMobileVideoQuestsDesktopCompatible; + settings.resumeInterruptedQuests = defaultResumeInterruptedQuests; + settings.autoCompleteQuestTypes = { ...defaultAutoCompleteQuestTypes }; } function updateDangerousAccess(checked: boolean) { function setDangerousAccess() { - settings.store.allowChangingDangerousSettings = checked; + getQuestifySettings().allowChangingDangerousSettings = checked; } if (checked) { @@ -221,7 +223,7 @@ export function QuestFeaturesSetting(): JSX.Element { } function updateModifyValue(key: QuestModifySettingKey, checked: boolean) { - settings.store[key] = checked; + getQuestifySettings()[key] = checked; } return ( diff --git a/src/equicordplugins/questify/components/questNotificationsSetting.tsx b/src/equicordplugins/questify/components/questNotificationsSetting.tsx index b52581945..3a834eb02 100644 --- a/src/equicordplugins/questify/components/questNotificationsSetting.tsx +++ b/src/equicordplugins/questify/components/questNotificationsSetting.tsx @@ -8,8 +8,8 @@ import { type AudioPlayerInterface, createAudioPlayer, defaultAudioNames } from import { useEffect, useMemo, useRef, useState } from "@webpack/common"; import type { JSX, MouseEvent } from "react"; +import { getQuestifySettings, useQuestifySettings } from "../settings/access"; import { startAutoFetchingQuests } from "../settings/fetching"; -import { settings } from "../settings/store"; import { q } from "../utils/ui"; import { ManaSelectFormattedOption, ManaSelectOption, SettingsCard, SettingsDescription, SettingsHeader, SettingsRow, SettingsRowItem, SettingsSelect, SettingsSlider, SettingsSubheader, SettingsSubtleSwitch } from "./shared"; @@ -137,7 +137,7 @@ function QuestNotificationSoundSelect({ } export function QuestNotificationsSetting(): JSX.Element { - const questNotifications = settings.use([ + const questNotifications = useQuestifySettings([ "newExcludedQuestAlertSound", "newExcludedQuestAlertVolume", "newQuestAlertSound", @@ -188,7 +188,7 @@ export function QuestNotificationsSetting(): JSX.Element { if (value != null && typeof value !== "string") return; const interval = value == null ? 0 : Number(value); - settings.store.questFetchInterval = interval; + getQuestifySettings().questFetchInterval = interval; startAutoFetchingQuests(true); } @@ -201,7 +201,7 @@ export function QuestNotificationsSetting(): JSX.Element { checked={questNotifications.notifyOnQuestComplete} disabled={disabled} label="Show a notification when a Quest is completed:" - onChange={checked => { settings.store.notifyOnQuestComplete = checked; }} + onChange={checked => { getQuestifySettings().notifyOnQuestComplete = checked; }} bottomSpacing="5" /> @@ -213,7 +213,7 @@ export function QuestNotificationsSetting(): JSX.Element { value={questNotifications.questCompletedAlertSound} playingSound={playingSound} onPreview={sound => previewSound(sound, questNotifications.questCompletedAlertVolume)} - onChange={value => { settings.store.questCompletedAlertSound = value; }} + onChange={value => { getQuestifySettings().questCompletedAlertSound = value; }} /> @@ -222,7 +222,7 @@ export function QuestNotificationsSetting(): JSX.Element { className="inline-volume-slider" disabled={disabled} value={questNotifications.questCompletedAlertVolume} - onChange={value => { settings.store.questCompletedAlertVolume = value; }} + onChange={value => { getQuestifySettings().questCompletedAlertVolume = value; }} /> @@ -233,7 +233,7 @@ export function QuestNotificationsSetting(): JSX.Element { label="Show a notification when new Quests are detected:" bottomSpacing="5" onChange={checked => { - settings.store.notifyOnNewQuests = checked; + getQuestifySettings().notifyOnNewQuests = checked; startAutoFetchingQuests(true); }} /> @@ -247,7 +247,7 @@ export function QuestNotificationsSetting(): JSX.Element { playingSound={playingSound} onPreview={sound => previewSound(sound, questNotifications.newQuestAlertVolume)} onChange={value => { - settings.store.newQuestAlertSound = value; + getQuestifySettings().newQuestAlertSound = value; startAutoFetchingQuests(true); }} /> @@ -258,7 +258,7 @@ export function QuestNotificationsSetting(): JSX.Element { className="inline-volume-slider" disabled={disabled} value={questNotifications.newQuestAlertVolume} - onChange={value => { settings.store.newQuestAlertVolume = value; }} + onChange={value => { getQuestifySettings().newQuestAlertVolume = value; }} /> @@ -269,7 +269,7 @@ export function QuestNotificationsSetting(): JSX.Element { label="Show a notification when new excluded Quests are detected:" bottomSpacing="5" onChange={checked => { - settings.store.notifyOnNewExcludedQuests = checked; + getQuestifySettings().notifyOnNewExcludedQuests = checked; startAutoFetchingQuests(true); }} tooltip={{ @@ -288,7 +288,7 @@ export function QuestNotificationsSetting(): JSX.Element { playingSound={playingSound} onPreview={sound => previewSound(sound, questNotifications.newExcludedQuestAlertVolume)} onChange={value => { - settings.store.newExcludedQuestAlertSound = value; + getQuestifySettings().newExcludedQuestAlertSound = value; startAutoFetchingQuests(true); }} tooltip={{ @@ -304,7 +304,7 @@ export function QuestNotificationsSetting(): JSX.Element { className="inline-volume-slider" disabled={disabled} value={questNotifications.newExcludedQuestAlertVolume} - onChange={value => { settings.store.newExcludedQuestAlertVolume = value; }} + onChange={value => { getQuestifySettings().newExcludedQuestAlertVolume = value; }} /> diff --git a/src/equicordplugins/questify/components/questTilesSetting.tsx b/src/equicordplugins/questify/components/questTilesSetting.tsx index ec6e98e62..b0d51b0c7 100644 --- a/src/equicordplugins/questify/components/questTilesSetting.tsx +++ b/src/equicordplugins/questify/components/questTilesSetting.tsx @@ -9,9 +9,9 @@ import { findComponentByCodeLazy } from "@webpack"; import { QuestStore, useEffect, useMemo, useRef, useState, useStateFromStores } from "@webpack/common"; import type { JSX, SyntheticEvent } from "react"; +import { getQuestifySettings, useQuestifySettings } from "../settings/access"; import { defaultQuestTileClaimedColorSetting, defaultQuestTileExpiredColorSetting, defaultQuestTileIgnoredColorSetting, defaultQuestTileUnclaimedColorSetting, type QuestTileColorSetting, type QuestTileGradient } from "../settings/def"; import { rerenderQuests } from "../settings/rerender"; -import { settings } from "../settings/store"; import { getQuestTileClasses, getQuestTileStyle } from "../utils/questTiles"; import { q } from "../utils/ui"; import { ManaButton, type ManaSelectOption, SettingsCard, SettingsColorPicker, SettingsDescription, SettingsHeader, SettingsRow, SettingsRowItem, SettingsSelect, SettingsSubheader } from "./shared"; @@ -194,7 +194,7 @@ function DummyQuestPreview({ } export function QuestTilesSetting(): JSX.Element { - const questTiles = settings.use([ + const questTiles = useQuestifySettings([ "disableQuestsEverything", "questTileUnclaimedColor", "questTileClaimedColor", @@ -211,7 +211,7 @@ export function QuestTilesSetting(): JSX.Element { function updateColor(key: QuestTileColorKey, nextColor: QuestTileColorSetting): void { setPreviewColorKey(key); - settings.store[key] = nextColor; + getQuestifySettings()[key] = nextColor; } function updateColorValue(key: QuestTileColorKey, setting: QuestTileColorSetting, value: number | null): void { @@ -233,14 +233,14 @@ export function QuestTilesSetting(): JSX.Element { function updateGradient(value: string | string[] | null): void { if (typeof value !== "string") return; - settings.store.questTileGradient = value as QuestTileGradient; + getQuestifySettings().questTileGradient = value as QuestTileGradient; } function updatePreload(value: string | string[] | null): void { if (typeof value !== "string") return; const preload = value === "true"; - settings.store.questTilePreload = preload; + getQuestifySettings().questTilePreload = preload; rerenderQuests(); } diff --git a/src/equicordplugins/questify/components/reorderQuestsSetting.tsx b/src/equicordplugins/questify/components/reorderQuestsSetting.tsx index a39c618ee..b2f51b8d8 100644 --- a/src/equicordplugins/questify/components/reorderQuestsSetting.tsx +++ b/src/equicordplugins/questify/components/reorderQuestsSetting.tsx @@ -6,9 +6,9 @@ import type { JSX } from "react"; +import { getQuestifySettings, useQuestifySettings } from "../settings/access"; import { defaultQuestOrder, type QuestOrderStatus, type QuestSubsort } from "../settings/def"; import { rerenderQuests } from "../settings/rerender"; -import { settings } from "../settings/store"; import { type ManaSelectOption, SettingsCard, SettingsDescription, SettingsHeader, SettingsRow, SettingsRowItem, SettingsSelect, SettingsSubheader, SettingsSubtleSwitch } from "./shared"; const questStatusOptions = [ @@ -83,7 +83,7 @@ function sanitizeQuestOrder(order: unknown): QuestOrderStatus[] { } export function ReorderQuestsSetting(): JSX.Element { - const reorderQuests = settings.use([ + const reorderQuests = useQuestifySettings([ "disableQuestsEverything", "questOrder", "unclaimedSubsort", @@ -110,19 +110,19 @@ export function ReorderQuestsSetting(): JSX.Element { } nextOrder[index] = nextStatus; - settings.store.questOrder = nextOrder; + getQuestifySettings().questOrder = nextOrder; rerenderQuests(); } function updateSubsort(key: "unclaimedSubsort" | "claimedSubsort" | "ignoredSubsort" | "expiredSubsort", value: string | string[] | null): void { if (typeof value !== "string") return; - settings.store[key] = value; + getQuestifySettings()[key] = value; rerenderQuests(); } function updateRememberSetting(key: "rememberQuestPageSort" | "rememberQuestPageFilters", checked: boolean): void { - settings.store[key] = checked; + getQuestifySettings()[key] = checked; } return ( diff --git a/src/equicordplugins/questify/components/settingsModal.tsx b/src/equicordplugins/questify/components/settingsModal.tsx index 8fc8ce838..4b741c9d3 100644 --- a/src/equicordplugins/questify/components/settingsModal.tsx +++ b/src/equicordplugins/questify/components/settingsModal.tsx @@ -8,8 +8,8 @@ import PluginModal from "@components/settings/tabs/plugins/PluginModal"; import { openModal } from "@utils/modal"; import type { Plugin } from "@utils/types"; -import { setSettingsModalOpen } from ".."; import { promptToRestartIfDirty } from "../settings/restartTracking"; +import { setSettingsModalOpen } from "../state"; export function openQuestifySettingsModal(plugin: Plugin): void { setSettingsModalOpen(true); diff --git a/src/equicordplugins/questify/index.tsx b/src/equicordplugins/questify/index.tsx index 5a4faea25..a1a6f10cf 100644 --- a/src/equicordplugins/questify/index.tsx +++ b/src/equicordplugins/questify/index.tsx @@ -11,7 +11,7 @@ import { addServerListElement, removeServerListElement, ServerListRenderPosition import { Settings } from "@api/Settings"; import { ErrorBoundary } from "@components/index"; import { EquicordDevs } from "@utils/constants"; -import definePlugin from "@utils/types"; +import definePlugin, { StartAt } from "@utils/types"; import type { Quest, QuestUserStatus } from "@vencord/discord-types"; import { findComponentByCodeLazy, onceReady } from "@webpack"; import { QuestStore } from "@webpack/common"; @@ -19,11 +19,13 @@ import type { JSX } from "react"; import { disguiseHomeButton, QuestButton, showQuestButton } from "./components/questButton"; import { QuestTileContextMenu } from "./components/questTileContextMenu"; +import { getQuestifySettings } from "./settings/access"; import { resetQuestsToResume, startAutoFetchingQuests, stopAutoFetchingQuests } from "./settings/fetching"; import { validateIgnoredQuests } from "./settings/ignoredQuests"; import { rerenderQuests, useQuestRerender } from "./settings/rerender"; import { disposeRestartTracking, initializeRestartTracking, promptToRestartIfDirty } from "./settings/restartTracking"; import { settings } from "./settings/store"; +import { getSettingsModalOpen, initialQuestDataFetched, setInitialQuestDataFetched, setSettingsModalOpen } from "./state"; import { canAutoCompleteQuest, getActiveAutoCompletes, getQuestAutoCompleteProgress, getQuestButtonProps, getQuestPanelSubtitleText, hasEnabledAutoCompleteQuestTypes, processQuestForAutoComplete, resumeInterruptedAutoCompletes, setHeartbeatStackTracePatchSucceeded, setVideoProgressStackTracePatchSucceeded, stopAllAutoCompletes, stopAutoCompletesForRunningGames, stopQuestAutoComplete } from "./utils/completion"; import { canOpenDevToolsWindow, fetchAndDispatchQuests, openDevToolsWindow, snakeToCamel } from "./utils/fetching"; import { normalizeQuestName } from "./utils/filtering"; @@ -32,23 +34,12 @@ import { getQuestPanelOverride, getQuestPanelPercentComplete, shouldForceQuestPa import { getLastFilterChoices, getLastSortChoice, getQuestTileClasses, getQuestTileStyle, setLastFilterChoices, setLastSortChoice, shouldPreloadQuestAssets, sortQuests } from "./utils/questTiles"; import { formatLowerBadge, QUEST_PAGE } from "./utils/ui"; -let settingsModalOpen = false; - -export function setSettingsModalOpen(open: boolean): void { - settingsModalOpen = open; -} - -function getSettingsModalOpen(): boolean { - return settingsModalOpen; -} - -export let initialQuestDataFetched = false; let isSwitchingAccount = false; let didAttemptAutoCompleteResume = false; const notifiedCompletedQuests = new Set(); function setOnQuestsPage(force?: boolean): void { - settings.store.isOnQuestsPage = force ?? (window.location.pathname === QUEST_PAGE); + getQuestifySettings().isOnQuestsPage = force ?? (window.location.pathname === QUEST_PAGE); } function startPerAccountTasks(source: string): void { @@ -110,6 +101,7 @@ export default definePlugin({ tags: ["Appearance", "Customisation", "Privacy", "Utility"], authors: [EquicordDevs.Etorix], dependencies: ["AudioPlayerAPI", "ServerListAPI"], + startAt: StartAt.Init, // Needed in order to beat Read All Messages to inserting above the server list. settings, canOpenDevToolsWindow, @@ -165,7 +157,7 @@ export default definePlugin({ // Prevents the DMs Quests tab from counting as part of the // DM button highlight logic while the Quest button is visible. find: "GLOBAL_DISCOVERY),", - predicate: () => !settings.store.disableQuestsEverything && showQuestButton(settings.store.questButtonDisplay, 1, true), + predicate: () => !getQuestifySettings().disableQuestsEverything && showQuestButton(getQuestifySettings().questButtonDisplay, 1, true), replacement: { match: /(pathname:(\i)}.{0,400}?return )/, replace: "$1$self.disguiseHomeButton($2)?false:" @@ -174,7 +166,7 @@ export default definePlugin({ { // Hides the Quest icon on members list nameplates. find: '("ActivityStatus"),', - predicate: () => settings.store.disableQuestsEverything || settings.store.disableMembersListPromo, + predicate: () => getQuestifySettings().disableQuestsEverything || getQuestifySettings().disableMembersListPromo, replacement: { match: /(,hasQuest:)(?=\i=!1)/, replace: ",questifyInvalid1:" @@ -183,7 +175,7 @@ export default definePlugin({ { // Hides the Friends List "Active Now" promotion. find: "`application-stream-", - predicate: () => settings.store.disableQuestsEverything || settings.store.disableFriendsListPromo, + predicate: () => getQuestifySettings().disableQuestsEverything || getQuestifySettings().disableFriendsListPromo, replacement: [ { match: /(?<=let{party:\i,onChannelContextMenu:\i,)quest:(\i)/, @@ -194,7 +186,7 @@ export default definePlugin({ { // Hides Quests tab in the Discovery page. find: "GLOBAL_DISCOVERY_SIDEBAR},", - predicate: () => settings.store.disableQuestsEverything || settings.store.disableRelocationNotices, + predicate: () => getQuestifySettings().disableQuestsEverything || getQuestifySettings().disableRelocationNotices, replacement: [ { match: /(GLOBAL_DISCOVERY_TABS).map/, @@ -205,7 +197,7 @@ export default definePlugin({ { // Hides Quests tab in the DMs tab list. find: ".QUEST_HOME):", - predicate: () => settings.store.disableQuestsEverything, + predicate: () => getQuestifySettings().disableQuestsEverything, replacement: [ { match: /(?<="family-center"\):null,)/, @@ -217,7 +209,7 @@ export default definePlugin({ // Hides the sponsored banner on the Quests page. find: "resetSortingFiltering(),requestAnimationFrame", group: true, - predicate: () => !settings.store.disableQuestsEverything && settings.store.disableSponsoredBanner, + predicate: () => !getQuestifySettings().disableQuestsEverything && getQuestifySettings().disableSponsoredBanner, replacement: [ { match: /(?<=(\i),isLoading:(\i)}=\(0,\i.\i\)\(\);)/, @@ -229,7 +221,7 @@ export default definePlugin({ // Hides the Quest & Orbs badges on user profiles. find: ".MODAL]:26", group: true, - predicate: () => !settings.store.disableQuestsEverything && settings.store.disableOrbsAndQuestsBadges, + predicate: () => !getQuestifySettings().disableQuestsEverything && getQuestifySettings().disableOrbsAndQuestsBadges, replacement: [ { match: /(badges:\i)/, @@ -240,7 +232,7 @@ export default definePlugin({ { // Overrides the account panel Quest popup and progress display. find: "QUESTS_BAR,questId", - predicate: () => settings.store.disableAccountPanelPromo || !settings.store.disableAccountPanelQuestProgress, + predicate: () => getQuestifySettings().disableAccountPanelPromo || !getQuestifySettings().disableAccountPanelQuestProgress, replacement: { match: /(?<=function\(\){)(let (\i)=\(0,\i.\i\)\(\);)/, replace: "void $self.useQuestRerender();$1$2=$self.getQuestPanelOverride($2);" @@ -250,7 +242,7 @@ export default definePlugin({ // Prevents fetching Quests. find: 'type:"QUESTS_FETCH_CURRENT_QUESTS_BEGIN"', group: true, - predicate: () => settings.store.disableQuestsEverything, + predicate: () => getQuestifySettings().disableQuestsEverything, replacement: [ { // QUESTS_FETCH_CURRENT_QUESTS_BEGIN @@ -267,7 +259,7 @@ export default definePlugin({ { // Fixes the progress tracking for Quests. find: ",{progressTextAnimation:", - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: { match: /(let{percentComplete:.{0,115}?children:\i}=)(\i)/, replace: "const questifyProgress=$self.getQuestPanelPercentComplete({...$2,quest:$2.children?.props?.quest});$1Object.assign({},$2,questifyProgress??{})" @@ -276,7 +268,7 @@ export default definePlugin({ { // Overrides the title and subtitle to provide more useful information for Quests being completed. find: '"progress-title"', - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: { match: /(?<={quest:(\i).{0,250}?return.{0,150}?,percentComplete:\i.{0,280}?"progress-title",children.{0,115}?children:)(\i.{0,50}"progress-subtitle",isTextTransition:!0,children.{0,115}?children:)/, replace: "$self.normalizeQuestName($1)??$2$self.getQuestPanelSubtitleText($1)??" @@ -285,7 +277,7 @@ export default definePlugin({ { // Formats the Orbs balance on the Quests page with locale string formatting. find: '("BalanceCounter")', - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: [ { match: /(`\${(\i).toFixed\(0\)}`.length)/, @@ -301,7 +293,7 @@ export default definePlugin({ // Removes stack traces from Quest auto-complete network actions and marks both patches as healthy. find: "NetworkActionNames.QUEST_VIDEO_PROGRESS,", group: true, - predicate: () => !settings.store.disableQuestsEverything && hasEnabledAutoCompleteQuestTypes(), + predicate: () => !getQuestifySettings().disableQuestsEverything && hasEnabledAutoCompleteQuestTypes(), replacement: [ { match: /(async function \i\(\i,\i\)\{await \i\.\i\.post\(\{url:\i\.\i\.QUESTS_VIDEO_PROGRESS.{0,200}?stack_trace:)Error\(\)\.stack\?\?""/, @@ -316,7 +308,7 @@ export default definePlugin({ { find: "resetSortingFiltering(),requestAnimationFrame", group: true, - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: [ { // Subscribes the Quest page sort/filter state to Questify rerenders. @@ -348,7 +340,7 @@ export default definePlugin({ { find: "config.taskConfigV2.tasks).length)return", group: true, - predicate: () => !settings.store.disableQuestsEverything && hasEnabledAutoCompleteQuestTypes(), + predicate: () => !getQuestifySettings().disableQuestsEverything && hasEnabledAutoCompleteQuestTypes(), replacement: [ { // Overwrite button props for UNENROLLED Quests. @@ -365,7 +357,7 @@ export default definePlugin({ { // Overwrite button props for Quest bar. find: "QUESTS_BAR,questId", - predicate: () => !settings.store.disableQuestsEverything && hasEnabledAutoCompleteQuestTypes(), + predicate: () => !getQuestifySettings().disableQuestsEverything && hasEnabledAutoCompleteQuestTypes(), replacement: { match: /(?<=SELECT&&!\i&&!\i,(\i)=null;)(return )(\i\?\i=\(0,\i.\i\)\(\i,{quest:(\i))/, replace: "const questifyButton=$self.enrolledIncompleteButton({quest:$4});$2questifyButton?$1=questifyButton:$3" @@ -374,7 +366,7 @@ export default definePlugin({ { // Keeps Questify completion progress visible when Discord marks the native Quest bar dismissed. find: "prevIsQuestAccepted:", - predicate: () => !settings.store.disableQuestsEverything && !settings.store.disableAccountPanelQuestProgress, + predicate: () => !getQuestifySettings().disableQuestsEverything && !getQuestifySettings().disableAccountPanelQuestProgress, replacement: { match: /(?<=isLoading:\i}=\(0,\i.\i\)\(\),\i=\i\.useContext\(\i\.\i\)\|\|\i&&)(\i)/, replace: "($1||$self.shouldForceQuestPanelVisible(arguments[0].quest))" @@ -383,7 +375,7 @@ export default definePlugin({ { find: ".rowIndex,trackGuildAndChannelMetadata", group: true, - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: [ { // Prevent the platform selector if the Quest is auto-completable. @@ -423,7 +415,7 @@ export default definePlugin({ { find: ".rowIndex,trackGuildAndChannelMetadata", group: true, - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: [ { // Subscribes each Quest tile to Questify's manual rerender trigger. @@ -455,7 +447,7 @@ export default definePlugin({ { // Adds the Questify sort option to Discord's Quest sort enum. find: "SUGGESTED=\"suggested\",", - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: { match: /(?<=\(\((\i)=\{\}\))(?=\.SUGGESTED="suggested",)/, replace: ".QUESTIFY=\"questify\",$1" @@ -464,7 +456,7 @@ export default definePlugin({ { // Labels the injected Questify sort option in the dropdown. find: "has no rewards configured`", - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: { match: /(?=case (\i\.\i)\.SUGGESTED)/, replace: "case $1.QUESTIFY:return\"Questify\";" @@ -473,7 +465,7 @@ export default definePlugin({ { find: "CLAIMED=\"claimed\",", group: true, - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: [ { // Runs Questify sorting in the hook-safe Quest list path and tracks manual rerenders. @@ -506,7 +498,7 @@ export default definePlugin({ // Sorts the "Claimed Quests" tabs. find: ".ALL)}):(", group: true, - predicate: () => !settings.store.disableQuestsEverything, + predicate: () => !getQuestifySettings().disableQuestsEverything, replacement: [ { match: /(return \i&&0===\i.length.{0,150}?children:)\[\.\.\.(\i).{0,100}?claimedAt\?\?""\)\)/, @@ -543,7 +535,7 @@ export default definePlugin({ CHANNEL_SELECT() { setOnQuestsPage(); }, QUESTS_FETCH_CURRENT_QUESTS_SUCCESS(data: { quests: Quest[]; }): void { - initialQuestDataFetched = true; + setInitialQuestDataFetched(true); QL.log("QUESTS_FETCH_CURRENT_QUESTS_SUCCESS", data); validateIgnoredQuests(data.quests); resumeAutoCompletesIfReady(); @@ -573,14 +565,14 @@ export default definePlugin({ if (completedRecently && !claimedAt && !notifiedCompletedQuests.has(userStatus!.questId)) { notifiedCompletedQuests.add(userStatus!.questId); - if (settings.store.notifyOnQuestComplete) { + if (getQuestifySettings().notifyOnQuestComplete) { notifyQuestCompletion(QuestStore.getQuest(userStatus!.questId)); } - if (settings.store.questCompletedAlertSound) { + if (getQuestifySettings().questCompletedAlertSound) { playAudio( - settings.store.questCompletedAlertSound, - { volume: Math.max(0, Math.min(100, settings.store.questCompletedAlertVolume)) } + getQuestifySettings().questCompletedAlertSound, + { volume: Math.max(0, Math.min(100, getQuestifySettings().questCompletedAlertVolume)) } ); } } @@ -596,13 +588,13 @@ export default definePlugin({ }, LOGIN_SUCCESS(): void { - if (!isSwitchingAccount || settings.store.disableQuestsEverything) { + if (!isSwitchingAccount || getQuestifySettings().disableQuestsEverything) { return; } else { isSwitchingAccount = false; } - initialQuestDataFetched = false; + setInitialQuestDataFetched(false); didAttemptAutoCompleteResume = false; startPerAccountTasks("LOGIN_SUCCESS"); }, @@ -614,7 +606,7 @@ export default definePlugin({ isSwitchingAccount = true; } - initialQuestDataFetched; + setInitialQuestDataFetched(false); stopPerAccountTasks("LOGOUT"); }, @@ -631,10 +623,10 @@ export default definePlugin({ start() { initializeRestartTracking(settings); - addServerListElement(ServerListRenderPosition.Above, this.renderQuestifyButton, 1); + addServerListElement(ServerListRenderPosition.Above, this.renderQuestifyButton); onceReady.then(() => { - if (!settings.store.disableQuestsEverything) { + if (!getQuestifySettings().disableQuestsEverything) { startPerAccountTasks("PLUGIN_START"); } else { removeServerListElement(ServerListRenderPosition.Above, this.renderQuestifyButton); diff --git a/src/equicordplugins/questify/settings/access.ts b/src/equicordplugins/questify/settings/access.ts new file mode 100644 index 000000000..c05eec17d --- /dev/null +++ b/src/equicordplugins/questify/settings/access.ts @@ -0,0 +1,29 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2026 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { Settings, useSettings } from "@api/Settings"; +import { UserStore } from "@webpack/common"; + +export const QUESTIFY_PLUGIN_NAME = "Questify"; + +interface QuestifySettingsOverrides { + ignoredQuestIDs: Record; + resumeQuestIDs: Record; +} + +type QuestifySettings = Settings["plugins"][typeof QUESTIFY_PLUGIN_NAME] & QuestifySettingsOverrides; + +export function getQuestifySettings(): QuestifySettings { + return Settings.plugins[QUESTIFY_PLUGIN_NAME] as QuestifySettings; +} + +export function useQuestifySettings(keys: readonly K[]): Pick { + return useSettings(keys.map(key => `plugins.${QUESTIFY_PLUGIN_NAME}.${key}`) as any).plugins[QUESTIFY_PLUGIN_NAME] as unknown as Pick; +} + +export function getCurrentUserId(userId?: string): string | null { + return userId ?? UserStore.getCurrentUser()?.id ?? null; +} diff --git a/src/equicordplugins/questify/settings/fetching.ts b/src/equicordplugins/questify/settings/fetching.ts index dafd335af..4c669d3fe 100644 --- a/src/equicordplugins/questify/settings/fetching.ts +++ b/src/equicordplugins/questify/settings/fetching.ts @@ -8,13 +8,14 @@ import type { Quest } from "@vencord/discord-types"; import { fetchAndAlertQuests } from "../utils/fetching"; import { QL } from "../utils/logging"; -import { getCurrentUserId, settings } from "./store"; +import { getCurrentUserId, getQuestifySettings } from "./access"; let autoFetchInterval: null | ReturnType = null; const minimumAutoFetchIntervalValue = 30 * 60; // 30 minutes const maximumAutoFetchIntervalValue = 12 * 60 * 60; // 12 hours export function autoFetchCompatible(): boolean { + const settings = getQuestifySettings(); const { newExcludedQuestAlertSound, newQuestAlertSound, @@ -23,8 +24,8 @@ export function autoFetchCompatible(): boolean { notifyOnNewQuests, questButtonDisplay: displayMode, questButtonIndicator: indicatorMode - } = settings.store; - const fetching = !settings.store.disableQuestsEverything && questFetchInterval > 0; + } = settings; + const fetching = !settings.disableQuestsEverything && questFetchInterval > 0; const notificationsCompatible = notifyOnNewQuests || notifyOnNewExcludedQuests || Boolean(newQuestAlertSound) || Boolean(newExcludedQuestAlertSound); let buttonCompatible = false; @@ -54,7 +55,7 @@ export function startAutoFetchingQuests(force: boolean = false): void { stopAutoFetchingQuests(); } - const { questFetchInterval } = settings.store; + const { questFetchInterval } = getQuestifySettings(); const interval = Math.min(Math.max(questFetchInterval, minimumAutoFetchIntervalValue), maximumAutoFetchIntervalValue); autoFetchInterval = setInterval(() => { void fetchAndAlertQuests("AUTO_FETCH"); }, interval * 1000); QL.info("START_AUTO_FETCHING_QUESTS", { autoFetchIntervalID: autoFetchInterval, questFetchInterval, questFetchIntervalClamped: interval }); @@ -69,7 +70,7 @@ export function stopAutoFetchingQuests(): void { } export function resetQuestsToResume(quest?: Quest, userId?: string): void { - const { resumeQuestIDs } = settings.store; + const { resumeQuestIDs } = getQuestifySettings(); const key = getCurrentUserId(userId); if (!key) { diff --git a/src/equicordplugins/questify/settings/ignoredQuests.ts b/src/equicordplugins/questify/settings/ignoredQuests.ts index 6517389d3..fa3006674 100644 --- a/src/equicordplugins/questify/settings/ignoredQuests.ts +++ b/src/equicordplugins/questify/settings/ignoredQuests.ts @@ -9,27 +9,28 @@ import { QuestStore } from "@webpack/common"; import type { QuestIncludedTypes } from "../utils/filtering"; import { countIncludedUnclaimedQuests, getQuestStatus, QuestStatus } from "../utils/questState"; +import { getQuestifySettings } from "./access"; import { ignoredQuestIDsKey } from "./def"; import { rerenderQuests } from "./rerender"; -import { settings } from "./store"; function validateQuestBadgeCount(): void { - const questButtonIncludedTypes = settings.store.questButtonIncludedTypes as QuestIncludedTypes; + const settings = getQuestifySettings(); + const questButtonIncludedTypes = settings.questButtonIncludedTypes as QuestIncludedTypes; const quests = Array.from(QuestStore.quests.values()); const ignoredQuestIds = getIgnoredQuestIDs(); const count = countIncludedUnclaimedQuests(quests, ignoredQuestIds, questButtonIncludedTypes); - settings.store.questButtonBadgeCount = count; + settings.questButtonBadgeCount = count; } export function getIgnoredQuestIDs(): string[] { - const { ignoredQuestIDs } = settings.store; + const { ignoredQuestIDs } = getQuestifySettings(); const ignoredQuestIDsForKey = Array.from(ignoredQuestIDs[ignoredQuestIDsKey] ?? []); return ignoredQuestIDsForKey; } function setIgnoredQuestIDs(questIDs: string[]): void { - settings.store.ignoredQuestIDs[ignoredQuestIDsKey] = questIDs; + getQuestifySettings().ignoredQuestIDs[ignoredQuestIDsKey] = questIDs; } export function validateIgnoredQuests(qs?: Quest[]): void { diff --git a/src/equicordplugins/questify/settings/store.ts b/src/equicordplugins/questify/settings/store.ts index ed655b961..a0faddbf0 100644 --- a/src/equicordplugins/questify/settings/store.ts +++ b/src/equicordplugins/questify/settings/store.ts @@ -7,14 +7,14 @@ import { definePluginSettings, PlainSettings, SettingsStore } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { OptionType } from "@utils/types"; -import { UserStore } from "@webpack/common"; +import { QuestButtonSetting } from "../components/questButtonSettings"; +import { QuestFeaturesSetting } from "../components/questFeaturesSetting"; +import { QuestNotificationsSetting } from "../components/questNotificationsSetting"; +import { QuestTilesSetting } from "../components/questTilesSetting"; +import { ReorderQuestsSetting } from "../components/reorderQuestsSetting"; import { defaultAllowChangingDangerousSettings, defaultAutoCompleteQuestsSimultaneously, defaultAutoCompleteQuestTypes, defaultClaimedSubsort, defaultCompleteVideoQuestsQuicker, defaultDisableAccountPanelPromo, defaultDisableAccountPanelQuestProgress, defaultDisableFriendsListPromo, defaultDisableMembersListPromo, defaultDisableOrbsAndQuestsBadges, defaultDisableQuestsEverything, defaultDisableRelocationNotices, defaultDisableSponsoredBanner, defaultExpiredSubsort, defaultIgnoredQuestIDs, defaultIgnoredSubsort, defaultIsOnQuestsPage, defaultLastQuestPageFilters, defaultLastQuestPageSort, defaultLeftClickAction, defaultMakeMobileVideoQuestsDesktopCompatible, defaultMiddleClickAction, defaultNewExcludedQuestAlertSound, defaultNewExcludedQuestAlertVolume, defaultNewQuestAlertSound, defaultNewQuestAlertVolume, defaultNotifyOnNewExcludedQuests, defaultNotifyOnNewQuests, defaultNotifyOnQuestComplete, defaultQuestButtonBadgeColor, defaultQuestButtonBadgeCount, defaultQuestButtonDisplay, defaultQuestButtonIncludedTypes, defaultQuestButtonIndicator, defaultQuestCompletedAlertSound, defaultQuestCompletedAlertVolume, defaultQuestFetchInterval, defaultQuestOrder, defaultQuestTileClaimedColorSetting, defaultQuestTileExpiredColorSetting, defaultQuestTileGradient, defaultQuestTileIgnoredColorSetting, defaultQuestTilePreload, defaultQuestTileUnclaimedColorSetting, defaultRememberQuestPageFilters, defaultRememberQuestPageSort, defaultResumeInterruptedQuests, defaultResumeQuestIDs, defaultRightClickAction, defaultUnclaimedSubsort, type QuestButtonAction, type QuestButtonDisplayMode, type QuestButtonIncludedTypes, type QuestButtonIndicatorMode, type QuestOrderStatus } from "./def"; -export function getCurrentUserId(userId?: string): string | null { - return userId ?? UserStore.getCurrentUser()?.id ?? null; -} - const MIGRATION_TARGET = 1; const CURRENT_SETTINGS = PlainSettings.plugins.Questify; @@ -41,7 +41,7 @@ export const settings = definePluginSettings({ }, questFeatures: { type: OptionType.COMPONENT, - component: ErrorBoundary.wrap(() => { const { QuestFeaturesSetting } = require("../components/questFeaturesSetting"); return QuestFeaturesSetting(); }) as any, + component: ErrorBoundary.wrap(QuestFeaturesSetting) as any, description: "Select which Quest features to disable.", }, disableQuestsEverything: { @@ -143,7 +143,7 @@ export const settings = definePluginSettings({ }, questButton: { type: OptionType.COMPONENT, - component: ErrorBoundary.wrap(() => { const { QuestButtonSetting } = require("../components/questButtonSettings"); return QuestButtonSetting(); }) as any, + component: ErrorBoundary.wrap(QuestButtonSetting) as any, description: "Customize the Quest button in the server list.", }, questButtonDisplay: { @@ -197,7 +197,7 @@ export const settings = definePluginSettings({ }, questNotifications: { type: OptionType.COMPONENT, - component: ErrorBoundary.wrap(() => { const { QuestNotificationsSetting } = require("../components/questNotificationsSetting"); return QuestNotificationsSetting(); }) as any, + component: ErrorBoundary.wrap(QuestNotificationsSetting) as any, description: "Configure Quest completed and new Quest detected notifications.", }, notifyOnQuestComplete: { @@ -262,7 +262,7 @@ export const settings = definePluginSettings({ }, questTiles: { type: OptionType.COMPONENT, - component: ErrorBoundary.wrap(() => { const { QuestTilesSetting } = require("../components/questTilesSetting"); return QuestTilesSetting(); }) as any, + component: ErrorBoundary.wrap(QuestTilesSetting) as any, description: "Customize the appearance of Quest tiles in the Quests page.", }, questTileUnclaimedColor: { @@ -304,7 +304,7 @@ export const settings = definePluginSettings({ reorderQuests: { type: OptionType.COMPONENT, description: "Sort Quests by their status.", - component: ErrorBoundary.wrap(() => { const { ReorderQuestsSetting } = require("../components/reorderQuestsSetting"); return ReorderQuestsSetting(); }) as any, + component: ErrorBoundary.wrap(ReorderQuestsSetting) as any, }, questOrder: { type: OptionType.CUSTOM, diff --git a/src/equicordplugins/questify/state.ts b/src/equicordplugins/questify/state.ts new file mode 100644 index 000000000..5522d2adc --- /dev/null +++ b/src/equicordplugins/questify/state.ts @@ -0,0 +1,20 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2026 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +export let initialQuestDataFetched = false; +let settingsModalOpen = false; + +export function setInitialQuestDataFetched(fetched: boolean): void { + initialQuestDataFetched = fetched; +} + +export function setSettingsModalOpen(open: boolean): void { + settingsModalOpen = open; +} + +export function getSettingsModalOpen(): boolean { + return settingsModalOpen; +} diff --git a/src/equicordplugins/questify/utils/completion.ts b/src/equicordplugins/questify/utils/completion.ts index eb0816edb..54f600e62 100644 --- a/src/equicordplugins/questify/utils/completion.ts +++ b/src/equicordplugins/questify/utils/completion.ts @@ -10,11 +10,11 @@ import { QuestTaskType } from "@vencord/discord-types/enums"; import { findByCodeLazy, findLazy } from "@webpack"; import { FluxDispatcher, QuestStore, RestAPI, showToast, Toasts } from "@webpack/common"; +import { getCurrentUserId, getQuestifySettings } from "../settings/access"; import { autoCompleteQuestTaskTypes, isDesktopCompatible } from "../settings/def"; import { resetQuestsToResume } from "../settings/fetching"; import { getIgnoredQuestIDs } from "../settings/ignoredQuests"; import { rerenderQuests } from "../settings/rerender"; -import { getCurrentUserId, settings } from "../settings/store"; import { AuthorizedAppsStore } from "./fetching"; import { normalizeQuestName } from "./filtering"; import { QL } from "./logging"; @@ -218,7 +218,7 @@ function showBrokenAutoCompleteToast(): void { } export function hasEnabledAutoCompleteQuestTypes(): boolean { - return autoCompleteQuestTaskTypes.some(questType => settings.store.autoCompleteQuestTypes[questType]); + return autoCompleteQuestTaskTypes.some(questType => getQuestifySettings().autoCompleteQuestTypes[questType]); } function isAutoCompleteRuntimeReady(notify: boolean = false): boolean { @@ -251,7 +251,7 @@ export function getAutoCompleteQuestTarget(task: QuestTask): AutoCompleteQuestTa return { raw, - adjusted: Math.max(0, raw - (isVideoQuestTask(task.type) && settings.store.completeVideoQuestsQuicker ? videoQuestLeeway : 0)), + adjusted: Math.max(0, raw - (isVideoQuestTask(task.type) && getQuestifySettings().completeVideoQuestsQuicker ? videoQuestLeeway : 0)), }; } @@ -295,7 +295,7 @@ function getEffectiveAutoCompleteTaskType(task: QuestTask, quest: Quest): QuestT function isAutoCompleteQuestTaskEnabled(quest: Quest, task: QuestTask): boolean { const taskType = getEffectiveAutoCompleteTaskType(task, quest); const compatible = isDesktopCompatible(taskType); - const enabled = settings.store.autoCompleteQuestTypes[taskType] === true; + const enabled = getQuestifySettings().autoCompleteQuestTypes[taskType] === true; return compatible && enabled && getQuestAutoCompleteKind(task) != null; } @@ -328,12 +328,12 @@ function updateResumeState(questIDs: string[] = getResumeQuestIds()): void { return; } - if (!settings.store.resumeInterruptedQuests || questIDs.length === 0) { - delete settings.store.resumeQuestIDs[userId]; + if (!getQuestifySettings().resumeInterruptedQuests || questIDs.length === 0) { + delete getQuestifySettings().resumeQuestIDs[userId]; return; } - settings.store.resumeQuestIDs[userId] = { + getQuestifySettings().resumeQuestIDs[userId] = { timestamp: Date.now(), questIDs, }; @@ -386,12 +386,12 @@ function formatQuestTime(seconds: number, prepositional: boolean = false): strin } function isQuestQueuedForResume(questId: string): boolean { - if (!settings.store.resumeInterruptedQuests) { + if (!getQuestifySettings().resumeInterruptedQuests) { return false; } const userId = getCurrentUserId(); - const resumeState = userId ? settings.store.resumeQuestIDs[userId] : null; + const resumeState = userId ? getQuestifySettings().resumeQuestIDs[userId] : null; return Boolean(resumeState && !isResumeStateExpired(resumeState.timestamp) && resumeState.questIDs.includes(questId)); } @@ -419,7 +419,7 @@ export function getQuestCompletionState(quest: Quest, options: QuestButtonTextOp const target = getAutoCompleteQuestTarget(task).adjusted; const enrolledAt = quest.userStatus?.enrolledAt ? new Date(quest.userStatus.enrolledAt) : null; const storedProgress = activeEntry?.progress ?? getQuestStoredProgress(quest, task) ?? 0; - const elapsedProgress = !activeEntry && enrolledAt && isVideoQuestTask(task.type) && settings.store.completeVideoQuestsQuicker + const elapsedProgress = !activeEntry && enrolledAt && isVideoQuestTask(task.type) && getQuestifySettings().completeVideoQuestsQuicker ? Math.max(0, (Date.now() - enrolledAt.getTime()) / 1000) : 0; const progress = Math.min(target, Math.max(storedProgress, elapsedProgress)); @@ -757,7 +757,7 @@ async function runVideoQuest(quest: Quest, entry: AutoCompleteEntry, target: Aut const completionTarget = target.adjusted; const enrolledAt = new Date(quest.userStatus.enrolledAt); const initialStoredProgress = getQuestStoredProgress(quest, entry.task) ?? 0; - const initialProgress = settings.store.completeVideoQuestsQuicker + const initialProgress = getQuestifySettings().completeVideoQuestsQuicker ? clampFloat(Math.max(1, (Date.now() - enrolledAt.getTime()) / 1000)) : Math.max(0, initialStoredProgress); let displayedProgress = clampFloat(Math.min(completionTarget, initialProgress)); @@ -989,14 +989,14 @@ async function runEntry(quest: Quest, entry: AutoCompleteEntry): Promise { resetQuestsToResume(quest); updateResumeState(); - if (!settings.store.autoCompleteQuestsSimultaneously && !suppressQueueDrain) { + if (!getQuestifySettings().autoCompleteQuestsSimultaneously && !suppressQueueDrain) { runNextQueuedQuest(); } } } function runNextQueuedQuest(): void { - if (suppressQueueDrain || settings.store.autoCompleteQuestsSimultaneously || hasRunningQueuedAutoComplete()) { + if (suppressQueueDrain || getQuestifySettings().autoCompleteQuestsSimultaneously || hasRunningQueuedAutoComplete()) { return; } @@ -1054,7 +1054,7 @@ export function processQuestForAutoComplete(quest: Quest, options: AutoCompleteS activeAutoCompletes.set(quest.id, entry); - if (settings.store.autoCompleteQuestsSimultaneously) { + if (getQuestifySettings().autoCompleteQuestsSimultaneously) { void runEntry(quest, entry); } else { updateResumeState(); @@ -1065,7 +1065,7 @@ export function processQuestForAutoComplete(quest: Quest, options: AutoCompleteS questId: quest.id, questName, source, - mode: settings.store.autoCompleteQuestsSimultaneously ? "simultaneous" : "queue", + mode: getQuestifySettings().autoCompleteQuestsSimultaneously ? "simultaneous" : "queue", taskType: entry.task.type, }); @@ -1103,7 +1103,7 @@ export function stopQuestAutoComplete(questOrId: Quest | string, options: AutoCo updateResumeState(resumeQuestIds); - if (!settings.store.autoCompleteQuestsSimultaneously && !suppressQueueDrain) { + if (!getQuestifySettings().autoCompleteQuestsSimultaneously && !suppressQueueDrain) { runNextQueuedQuest(); } @@ -1147,19 +1147,19 @@ export function stopAutoCompletesForRunningGames(gameIds: string[]): boolean { } export function resumeInterruptedAutoCompletes(): void { - if (!settings.store.resumeInterruptedQuests) { + if (!getQuestifySettings().resumeInterruptedQuests) { return; } const userId = getCurrentUserId(); - const resumeState = userId ? settings.store.resumeQuestIDs[userId] : null; + const resumeState = userId ? getQuestifySettings().resumeQuestIDs[userId] : null; if (!userId || !resumeState?.questIDs.length) { return; } if (isResumeStateExpired(resumeState.timestamp)) { - delete settings.store.resumeQuestIDs[userId]; + delete getQuestifySettings().resumeQuestIDs[userId]; QL.info("AUTO_COMPLETE_RESUME_EXPIRED", { userId, timestamp: resumeState.timestamp, maxAge: resumeExpiryMs }); return; } diff --git a/src/equicordplugins/questify/utils/fetching.ts b/src/equicordplugins/questify/utils/fetching.ts index 9253a010d..512d5b847 100644 --- a/src/equicordplugins/questify/utils/fetching.ts +++ b/src/equicordplugins/questify/utils/fetching.ts @@ -13,8 +13,8 @@ import { findByCodeLazy, findStoreLazy } from "@webpack"; import { QuestStore, RestAPI } from "@webpack/common"; import { NavigationRouter } from "@webpack/common/utils"; +import { getQuestifySettings } from "../settings/access"; import { questIsIgnored } from "../settings/ignoredQuests"; -import { settings } from "../settings/store"; import { getNewQuests, normalizeQuestName, type QuestIncludedTypes, questMatchesIncludedTypes } from "./filtering"; import { QL } from "./logging"; import { QUEST_PAGE } from "./ui"; @@ -138,14 +138,15 @@ function notifyNewQuests(quests: Quest[], excluded: boolean): void { } export async function fetchAndAlertQuests(source: string): Promise { - const alertSound = settings.store.newQuestAlertSound; - const alertVolume = settings.store.newQuestAlertVolume; - const excludedAlertSound = settings.store.newExcludedQuestAlertSound; - const excludedAlertVolume = settings.store.newExcludedQuestAlertVolume; - const shouldFetchExcludedQuests = settings.store.notifyOnNewExcludedQuests || Boolean(excludedAlertSound); + const settings = getQuestifySettings(); + const alertSound = settings.newQuestAlertSound; + const alertVolume = settings.newQuestAlertVolume; + const excludedAlertSound = settings.newExcludedQuestAlertSound; + const excludedAlertVolume = settings.newExcludedQuestAlertVolume; + const shouldFetchExcludedQuests = settings.notifyOnNewExcludedQuests || Boolean(excludedAlertSound); const currentQuests = Array.from(QuestStore.quests.values()); const currentExcludedQuestIds = new Set(Array.from(QuestStore.excludedQuests.values()).map(quest => quest.id)); - const includedTypes = settings.store.questButtonIncludedTypes as QuestIncludedTypes; + const includedTypes = settings.questButtonIncludedTypes as QuestIncludedTypes; await fetchAndDispatchQuests(); await sleep(1000); @@ -172,8 +173,8 @@ export async function fetchAndAlertQuests(source: string): Promise questMatchesIncludedTypes(quest, includedTypes) && !questIsIgnored(quest.id)); const shouldAlert = Boolean(alertSound) && newIncludedQuests.length > 0; const shouldAlertExcluded = Boolean(excludedAlertSound) && newIncludedExcludedQuests.length > 0; - const shouldNotify = settings.store.notifyOnNewQuests && newIncludedQuests.length > 0; - const shouldNotifyExcluded = settings.store.notifyOnNewExcludedQuests && newIncludedExcludedQuests.length > 0; + const shouldNotify = settings.notifyOnNewQuests && newIncludedQuests.length > 0; + const shouldNotifyExcluded = settings.notifyOnNewExcludedQuests && newIncludedExcludedQuests.length > 0; QL.info("FETCH_AND_ALERT_QUESTS_NEW_QUESTS", { source, diff --git a/src/equicordplugins/questify/utils/questState.ts b/src/equicordplugins/questify/utils/questState.ts index a880a41e5..509d8ef0b 100644 --- a/src/equicordplugins/questify/utils/questState.ts +++ b/src/equicordplugins/questify/utils/questState.ts @@ -8,8 +8,8 @@ import type { Quest } from "@vencord/discord-types"; import { QuestTaskType } from "@vencord/discord-types/enums"; import { QuestStore } from "@webpack/common"; +import { getQuestifySettings, useQuestifySettings } from "../settings/access"; import { ignoredQuestIDsKey } from "../settings/def"; -import { settings } from "../settings/store"; import { getActiveAutoCompletes, getAutoCompleteQuestTarget, getQuestAutoCompleteEntry } from "./completion"; import { type QuestIncludedTypes, questMatchesIncludedTypes } from "./filtering"; @@ -147,7 +147,7 @@ export function getQuestStoredProgress(quest: Quest, task: QuestTask): number | } function getCurrentIgnoredQuestIds(): string[] { - return Array.from(settings.store.ignoredQuestIDs[ignoredQuestIDsKey] ?? []); + return Array.from(getQuestifySettings().ignoredQuestIDs[ignoredQuestIDsKey] ?? []); } function getAutoCompleteShowcaseQuest(): Quest | null { @@ -208,7 +208,7 @@ function getMostRecentlyCompletedUnclaimedQuest(): Quest | null { } export function getQuestPanelOverride(quest: Quest | null): Quest | null { - const panelState = settings.use(["disableQuestsEverything", "disableAccountPanelPromo", "disableAccountPanelQuestProgress"]); + const panelState = useQuestifySettings(["disableQuestsEverything", "disableAccountPanelPromo", "disableAccountPanelQuestProgress"]); if (panelState.disableQuestsEverything) { return null; @@ -228,7 +228,9 @@ export function getQuestPanelOverride(quest: Quest | null): Quest | null { } export function shouldForceQuestPanelVisible(quest: Quest | null): boolean { - if (!quest || settings.store.disableQuestsEverything || settings.store.disableAccountPanelQuestProgress) { + const settings = getQuestifySettings(); + + if (!quest || settings.disableQuestsEverything || settings.disableAccountPanelQuestProgress) { return false; } diff --git a/src/equicordplugins/questify/utils/questTiles.ts b/src/equicordplugins/questify/utils/questTiles.ts index af24881f8..297316118 100644 --- a/src/equicordplugins/questify/utils/questTiles.ts +++ b/src/equicordplugins/questify/utils/questTiles.ts @@ -7,9 +7,9 @@ import type { Quest, QuestTaskWatchVideo, QuestTaskWatchVideoOnMobile } from "@vencord/discord-types"; import { QuestTaskType } from "@vencord/discord-types/enums"; +import { getQuestifySettings, useQuestifySettings } from "../settings/access"; import { defaultClaimedSubsort, defaultExpiredSubsort, defaultIgnoredSubsort, defaultQuestOrder, defaultUnclaimedSubsort, type QuestOrderStatus, type QuestSubsort, type QuestTileColorSetting, type QuestTileGradient } from "../settings/def"; import { getIgnoredQuestIDs } from "../settings/ignoredQuests"; -import { settings } from "../settings/store"; import { getQuestStatus, QuestStatus } from "./questState"; import { adjustRGB, decimalToRGB, isDarkish, q, type RGB } from "./ui"; @@ -84,7 +84,7 @@ function getGradientClass(gradient: QuestTileGradient): string | null { } export function getQuestTileClasses(originalClasses: string, quest: Quest & { dummyColor?: QuestTileColorSetting; }, gradientOverride?: QuestTileGradient): string { - const questTiles = settings.use([ + const questTiles = useQuestifySettings([ "disableQuestsEverything", "ignoredQuestIDs", "questTileUnclaimedColor", @@ -127,7 +127,7 @@ export function getQuestTileClasses(originalClasses: string, quest: Quest & { du } export function getQuestTileStyle(quest: (Quest & { dummyColor?: QuestTileColorSetting; }) | null): Record { - const questTiles = settings.use([ + const questTiles = useQuestifySettings([ "disableQuestsEverything", "ignoredQuestIDs", "questTileUnclaimedColor", @@ -243,7 +243,7 @@ export function hasInjectedDesktopVideoCompatibility(quest?: Quest | string | nu } export function sortQuests(quests: Quest[], skip?: boolean): Quest[] { - const questSorting = settings.use([ + const questSorting = useQuestifySettings([ "disableQuestsEverything", "ignoredQuestIDs", "makeMobileVideoQuestsDesktopCompatible", @@ -321,17 +321,19 @@ export function sortQuests(quests: Quest[], skip?: boolean): Quest[] { } export function shouldPreloadQuestAssets(): boolean { - return !settings.store.disableQuestsEverything && settings.store.questTilePreload; + const settings = getQuestifySettings(); + + return !settings.disableQuestsEverything && settings.questTilePreload; } export function getLastSortChoice(): string | null { - const { rememberQuestPageSort, lastQuestPageSort } = settings.store; + const { rememberQuestPageSort, lastQuestPageSort } = getQuestifySettings(); return rememberQuestPageSort ? lastQuestPageSort : "questify"; } export function setLastSortChoice(sort: string): void { - settings.store.lastQuestPageSort = sort || "questify"; + getQuestifySettings().lastQuestPageSort = sort || "questify"; } function getFilterChoiceKey({ group, filter }: { group: string; filter: string; }): string { @@ -339,7 +341,7 @@ function getFilterChoiceKey({ group, filter }: { group: string; filter: string; } export function getLastFilterChoices(): { group: string, filter: string; }[] | null { - const { rememberQuestPageFilters, lastQuestPageFilters } = settings.store; + const { rememberQuestPageFilters, lastQuestPageFilters } = getQuestifySettings(); return rememberQuestPageFilters ? Object.values(lastQuestPageFilters).map(item => JSON.parse(JSON.stringify(item))) @@ -348,7 +350,7 @@ export function getLastFilterChoices(): { group: string, filter: string; }[] | n export function setLastFilterChoices(filters: { group: string, filter: string; }[] | null): void { if (!filters?.length) { - settings.store.lastQuestPageFilters = {}; + getQuestifySettings().lastQuestPageFilters = {}; return; } @@ -357,7 +359,7 @@ export function setLastFilterChoices(filters: { group: string, filter: string; } return; } - settings.store.lastQuestPageFilters = JSON.parse(JSON.stringify(filters)).reduce((acc, item) => { + getQuestifySettings().lastQuestPageFilters = JSON.parse(JSON.stringify(filters)).reduce((acc, item) => { acc[getFilterChoiceKey(item)] = item; return acc;