Questify: Fix Circular Deps. (#1057)

* Fix Circular Deps.

* Restore Questify after upstream merge
This commit is contained in:
Etorix 2026-05-07 08:26:20 -07:00 • committed by GitHub
parent b50f96db75
commit 75ed11b8fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 207 additions and 157 deletions

View file

@ -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",

View file

@ -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();
}

View file

@ -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 (

View file

@ -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"
/>
<SettingsRow>
@ -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; }}
/>
</SettingsRowItem>
<SettingsRowItem className="volume-slider-row-item">
@ -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; }}
/>
</SettingsRowItem>
</SettingsRow>
@ -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; }}
/>
</SettingsRowItem>
</SettingsRow>
@ -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; }}
/>
</SettingsRowItem>
</SettingsRow>

View file

@ -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();
}

View file

@ -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 (

View file

@ -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);

View file

@ -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<string>();
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);

View file

@ -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<string, string[]>;
resumeQuestIDs: Record<string, { timestamp: number, questIDs: string[]; }>;
}
type QuestifySettings = Settings["plugins"][typeof QUESTIFY_PLUGIN_NAME] & QuestifySettingsOverrides;
export function getQuestifySettings(): QuestifySettings {
return Settings.plugins[QUESTIFY_PLUGIN_NAME] as QuestifySettings;
}
export function useQuestifySettings<K extends keyof QuestifySettings & string>(keys: readonly K[]): Pick<QuestifySettings, K> {
return useSettings(keys.map(key => `plugins.${QUESTIFY_PLUGIN_NAME}.${key}`) as any).plugins[QUESTIFY_PLUGIN_NAME] as unknown as Pick<QuestifySettings, K>;
}
export function getCurrentUserId(userId?: string): string | null {
return userId ?? UserStore.getCurrentUser()?.id ?? null;
}

View file

@ -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<typeof setInterval> = 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) {

View file

@ -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 {

View file

@ -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,

View file

@ -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;
}

View file

@ -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<void> {
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;
}

View file

@ -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<Quest[] | null> {
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<Quest[] | nul
const newIncludedExcludedQuests = newExcludedQuests.filter(quest => 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,

View file

@ -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;
}

View file

@ -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<string, string> {
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;