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;