diff --git a/frontend/src/html/pages/test.html b/frontend/src/html/pages/test.html index 49f01e1ba8a9..dd649439c014 100644 --- a/frontend/src/html/pages/test.html +++ b/frontend/src/html/pages/test.html @@ -22,6 +22,8 @@
; - +import { QuoteData } from "@monkeytype/schemas/quotes"; +import { + Quote as QuoteType, + QuoteWithTextSplit as QuoteWithTextSplitType, +} from "../types/quotes"; + +export type Quote = QuoteType; +export type QuoteWithTextSplit = QuoteWithTextSplitType; type QuoteCollection = { quotes: Quote[]; length: number; diff --git a/frontend/src/ts/db.ts b/frontend/src/ts/db.ts index 59110acbbb68..7ccc52509428 100644 --- a/frontend/src/ts/db.ts +++ b/frontend/src/ts/db.ts @@ -181,7 +181,7 @@ export async function initSnapshot(): Promise{ setSolidSnapshot(dbSnapshot); } } -export async function getLocalPB ( +export function getLocalPB ( mode: M, mode2: Mode2 , punctuation: boolean, @@ -190,7 +190,7 @@ export async function getLocalPB ( difficulty: Difficulty, lazyMode: boolean, funboxes: FunboxMetadata[], -): Promise { +): PersonalBest | undefined { if (!funboxes.every((f) => f.canGetPb)) { return undefined; } diff --git a/frontend/src/ts/elements/last-10-average.ts b/frontend/src/ts/elements/last-10-average.ts index a40c92ce8919..60a926fa4d37 100644 --- a/frontend/src/ts/elements/last-10-average.ts +++ b/frontend/src/ts/elements/last-10-average.ts @@ -1,16 +1,16 @@ import * as Misc from "../utils/misc"; import * as Numbers from "@monkeytype/util/numbers"; import { Config } from "../config/store"; -import * as TestWords from "../test/test-words"; -import { getUserAverage10 } from "../collections/results"; +import { getUserAverage10Once } from "../collections/results"; +import { getCurrentQuote } from "../states/test"; let averageWPM = 0; let averageAcc = 0; export async function update(): Promise { - const mode2 = Misc.getMode2(Config, TestWords.currentQuote); + const mode2 = Misc.getMode2(Config, getCurrentQuote()); - const average = await getUserAverage10({ ...Config, mode2 }); + const average = await getUserAverage10Once({ ...Config, mode2 }); const wpm = Numbers.roundTo2(average.wpm); const acc = Numbers.roundTo2(average.acc); diff --git a/frontend/src/ts/elements/modes-notice.ts b/frontend/src/ts/elements/modes-notice.ts index 1315ef9a678c..11cfa01876c6 100644 --- a/frontend/src/ts/elements/modes-notice.ts +++ b/frontend/src/ts/elements/modes-notice.ts @@ -1,13 +1,9 @@ -import * as PaceCaret from "../test/pace-caret"; -import * as TestState from "../test/test-state"; import * as DB from "../db"; import * as Last10Average from "../elements/last-10-average"; import { __nonReactive } from "../collections/tags"; import { Config } from "../config/store"; -import * as TestWords from "../test/test-words"; import { configEvent, type ConfigEventKey } from "../events/config"; -import { isAuthenticated } from "../states/core"; -import * as CustomTextState from "../legacy-states/custom-text-name"; +import { getCustomTextIndicator, isAuthenticated } from "../states/core"; import { getLanguageDisplayString } from "../utils/strings"; import Format from "../singletons/format"; import { getActiveFunboxes, getActiveFunboxNames } from "../test/funbox/list"; @@ -17,6 +13,10 @@ import { wordsHaveNewline, wordsHaveTab, getLoadedChallenge, + isRepeated, + isPaceRepeat, + getPaceCaretWpm, + getCurrentQuote, } from "../states/test"; configEvent.subscribe(({ key }) => { @@ -50,7 +50,7 @@ const testModesNotice = qsr(".pageTest #testModesNotice"); export async function update(): Promise { testModesNotice.empty(); - if (TestState.isRepeated && Config.mode !== "quote") { + if (isRepeated() && Config.mode !== "quote") { testModesNotice.appendHtml( ` repeated`, ); @@ -87,16 +87,13 @@ export async function update(): Promise{ ); } - const customTextName = CustomTextState.getCustomTextName(); - const isLong = CustomTextState.isCustomTextLong(); - if (Config.mode === "custom" && customTextName !== "" && isLong) { + if (Config.mode === "custom" && getCustomTextIndicator()?.isLong) { testModesNotice.appendHtml( ` ${escapeHTML( - customTextName, + getCustomTextIndicator()?.name, )} (shift + enter to save progress)`, ); } - const loadedChallenge = getLoadedChallenge(); if (loadedChallenge !== null) { testModesNotice.appendHtml( @@ -156,11 +153,8 @@ export async function update(): Promise{ ); } - if ( - Config.paceCaret !== "off" || - (Config.repeatedPace && TestState.isPaceRepeat) - ) { - const speed = Format.typingSpeed(PaceCaret.settings?.wpm ?? 0, { + if (Config.paceCaret !== "off" || (Config.repeatedPace && isPaceRepeat())) { + const speed = Format.typingSpeed(getPaceCaretWpm() ?? 0, { showDecimalPlaces: false, suffix: ` ${Config.typingSpeedUnit}`, }); @@ -207,8 +201,8 @@ export async function update(): Promise { if (!isAuthenticated()) { return; } - const mode2 = getMode2(Config, TestWords.currentQuote); - const pb = await DB.getLocalPB( + const mode2 = getMode2(Config, getCurrentQuote()); + const pb = DB.getLocalPB( Config.mode, mode2, Config.punctuation, diff --git a/frontend/src/ts/event-handlers/test.ts b/frontend/src/ts/event-handlers/test.ts index 78746fc0a4bc..dd9c9cb9b43b 100644 --- a/frontend/src/ts/event-handlers/test.ts +++ b/frontend/src/ts/event-handlers/test.ts @@ -2,7 +2,6 @@ import * as Commandline from "../commandline/commandline"; import { Config } from "../config/store"; import * as EditResultTagsModal from "../modals/edit-result-tags"; import { __nonReactive } from "../collections/tags"; -import * as TestWords from "../test/test-words"; import { showNoticeNotification, showErrorNotification, @@ -12,9 +11,9 @@ import { showQuoteReportModal } from "../states/quote-report"; import * as PractiseWordsModal from "../modals/practise-words"; import { navigate } from "../controllers/route-controller"; import { getMode2 } from "../utils/misc"; -import { ConfigKey } from "@monkeytype/schemas/configs"; -import { ListsObjectKeys } from "../commandline/lists"; import { qs } from "../utils/dom"; +import { getCurrentQuote } from "../states/test"; +import { CommandlineSubgroupKey } from "../commandline/types"; const testPage = qs(".pageTest"); @@ -22,7 +21,7 @@ testPage?.onChild("click", "#testModesNotice .textButton", async (event) => { const target = event.childTarget as HTMLElement; const attr = target?.getAttribute("commands"); if (attr === null) return; - Commandline.show({ subgroupOverride: attr as ConfigKey | ListsObjectKeys }); + Commandline.show({ subgroupOverride: attr as CommandlineSubgroupKey }); }); testPage?.onChild("click", "#testModesNotice .textButton", async (event) => { @@ -47,19 +46,21 @@ testPage?.onChild("click", ".tags .editTagsButton", () => { }); qs(".pageTest #rateQuoteButton")?.on("click", async () => { - if (TestWords.currentQuote === null) { + const currentQuote = getCurrentQuote(); + if (currentQuote === null) { showErrorNotification("Failed to show quote rating popup: no quote"); return; } - showQuoteRateModal(TestWords.currentQuote); + showQuoteRateModal(currentQuote); }); qs(".pageTest #reportQuoteButton")?.on("click", async () => { - if (TestWords.currentQuote === null) { + const currentQuote = getCurrentQuote(); + if (currentQuote === null) { showErrorNotification("Failed to show quote report popup: no quote"); return; } - showQuoteReportModal(TestWords.currentQuote?.id); + showQuoteReportModal(currentQuote?.id); }); testPage?.onChild("click", "#practiseWordsButton", () => { diff --git a/frontend/src/ts/input/handlers/keydown.ts b/frontend/src/ts/input/handlers/keydown.ts index 569b65d14b02..4fad0c51b631 100644 --- a/frontend/src/ts/input/handlers/keydown.ts +++ b/frontend/src/ts/input/handlers/keydown.ts @@ -14,7 +14,6 @@ import * as KeyConverter from "../../utils/key-converter"; import * as ShiftTracker from "../../test/shift-tracker"; import { canQuickRestart } from "../../utils/quick-restart"; import * as CustomText from "../../test/custom-text"; -import * as CustomTextState from "../../legacy-states/custom-text-name"; import { getLastBailoutAttempt, setCorrectShiftUsed, @@ -26,6 +25,7 @@ import { } from "../../test/funbox/list"; import { Keycode } from "../../constants/keys"; import { wordsHaveTab } from "../../states/test"; +import { getCustomTextIndicator } from "../../states/core"; export async function handleTab(e: KeyboardEvent, now: number): Promise { if (wordsHaveTab() && !e.shiftKey) { @@ -49,7 +49,7 @@ export async function handleEnter( Config.words, Config.time, CustomText.getData(), - CustomTextState.isCustomTextLong() ?? false, + getCustomTextIndicator()?.isLong ?? false, ) ) { const delay = Date.now() - getLastBailoutAttempt(); diff --git a/frontend/src/ts/legacy-states/custom-text-name.ts b/frontend/src/ts/legacy-states/custom-text-name.ts deleted file mode 100644 index dd648a093a1e..000000000000 --- a/frontend/src/ts/legacy-states/custom-text-name.ts +++ /dev/null @@ -1,18 +0,0 @@ -let customTestName = ""; // It should be empty when the text is not saved or a saved text has been modified -let isLong: boolean | undefined = false; - -export function getCustomTextName(): string { - return customTestName; -} - -export function isCustomTextLong(): boolean | undefined { - return isLong; -} - -export function setCustomTextName( - newName: string, - long: boolean | undefined, -): void { - customTestName = newName; - isLong = long; -} diff --git a/frontend/src/ts/states/core.ts b/frontend/src/ts/states/core.ts index c50a6dfdf6ee..6e500553b8ca 100644 --- a/frontend/src/ts/states/core.ts +++ b/frontend/src/ts/states/core.ts @@ -1,5 +1,7 @@ import { createSignal } from "solid-js"; +import { CommandlineSubgroupKey } from "../commandline/types"; import { PageName } from "../pages/page"; +import { showModal } from "./modals"; export const [getActivePage, setActivePage] = createSignal ("loading"); export const [getVersion, setVersion] = createSignal<{ @@ -36,3 +38,14 @@ export const [isUserVerified, setUserVerified] = createSignal(false); export const [getSelectedProfileName, setSelectedProfileName] = createSignal< string | undefined >(undefined); + +export function showCommandLineForConfig( + selector: CommandlineSubgroupKey, +): void { + setCommandlineSubgroup(selector); + showModal("Commandline"); +} + +export const [getCustomTextIndicator, setCustomTextIndicator] = createSignal< + { name: string; isLong: boolean } | undefined +>(undefined); diff --git a/frontend/src/ts/states/quote-rate.ts b/frontend/src/ts/states/quote-rate.ts index 7e3275cbad94..ce030c74dbeb 100644 --- a/frontend/src/ts/states/quote-rate.ts +++ b/frontend/src/ts/states/quote-rate.ts @@ -14,12 +14,12 @@ type QuoteStats = { language?: Language; }; -const [currentQuote, setCurrentQuote] = createSignal (null); +const [selectedQuote, setSelectedQuote] = createSignal(null); const [quoteStats, setQuoteStats] = createSignal< QuoteStats | null | Record>(null); -export { currentQuote, quoteStats }; +export { selectedQuote, quoteStats }; export function clearQuoteStats(): void { setQuoteStats(null); @@ -42,7 +42,7 @@ export async function getQuoteStats( ): Promise { if (!quote) return; - setCurrentQuote(quote); + setSelectedQuote(quote); const response = await Ape.quotes.getRating({ query: { quoteId: quote.id, language: quote.language }, }); @@ -71,6 +71,6 @@ export function updateQuoteStats(stats: QuoteStats): void { } export function showQuoteRateModal(quote: Quote): void { - setCurrentQuote(quote); + setSelectedQuote(quote); showModal("QuoteRate"); } diff --git a/frontend/src/ts/states/test.ts b/frontend/src/ts/states/test.ts index 845c2fda9f9e..5fa87ce392b2 100644 --- a/frontend/src/ts/states/test.ts +++ b/frontend/src/ts/states/test.ts @@ -1,10 +1,11 @@ import { createSignal, createEffect } from "solid-js"; import { Challenge } from "@monkeytype/schemas/challenges"; import { getConfig } from "../config/store"; -import { getActivePage } from "./core"; + import { canQuickRestart } from "../utils/quick-restart"; import { getData as getCustomTextData } from "../test/custom-text"; -import { isCustomTextLong } from "../legacy-states/custom-text-name"; +import { getActivePage, getCustomTextIndicator } from "./core"; +import { QuoteWithTextSplit } from "../types/quotes"; export const [wordsHaveNewline, setWordsHaveNewline] = createSignal(false); export const [wordsHaveTab, setWordsHaveTab] = createSignal(false); @@ -15,6 +16,13 @@ export const [getResultVisible, setResultVisible] = createSignal(false); export const [getFocus, setFocus] = createSignal(false); export const [isLongTest, setIsLongTest] = createSignal(false); +export const [isRepeated, setIsRepeated] = createSignal(false); +export const [isPaceRepeat, setIsPaceRepeat] = createSignal(false); +export const [getPaceCaretWpm, setPaceCaretWpm] = createSignal< + number | undefined +>(undefined); +export const [getCurrentQuote, setCurrentQuote] = + createSignal (null); createEffect(() => { getActivePage(); // depend on active page @@ -24,7 +32,7 @@ createEffect(() => { getConfig.words, getConfig.time, getCustomTextData(), - isCustomTextLong() ?? false, + getCustomTextIndicator()?.isLong ?? false, ), ); }); diff --git a/frontend/src/ts/test/pace-caret.ts b/frontend/src/ts/test/pace-caret.ts index 80de9f36c749..27244a9b6452 100644 --- a/frontend/src/ts/test/pace-caret.ts +++ b/frontend/src/ts/test/pace-caret.ts @@ -8,7 +8,11 @@ import { configEvent } from "../events/config"; import { getActiveFunboxes } from "./funbox/list"; import { Caret } from "../elements/caret"; import { qsr } from "../utils/dom"; -import { getUserAverage10, getUserDailyBest } from "../collections/results"; +import { + getUserAverage10Once, + getUserDailyBestOnce, +} from "../collections/results"; +import { getCurrentQuote, isPaceRepeat, setPaceCaretWpm } from "../states/test"; type Settings = { wpm: number; @@ -23,23 +27,20 @@ type Settings = { let startTimestamp = 0; -export let settings: Settings | null = null; +let settings: Settings | null = null; export const caret = new Caret(qsr("#paceCaret"), Config.paceCaretStyle); let lastTestWpm = 0; export function setLastTestWpm(wpm: number): void { - if ( - !TestState.isPaceRepeat || - (TestState.isPaceRepeat && wpm > lastTestWpm) - ) { + if (!isPaceRepeat() || (isPaceRepeat() && wpm > lastTestWpm)) { lastTestWpm = wpm; } } export function resetCaretPosition(): void { - if (Config.paceCaret === "off" && !TestState.isPaceRepeat) return; + if (Config.paceCaret === "off" && !isPaceRepeat()) return; if (Config.mode === "zen") return; caret.hide(); @@ -57,21 +58,19 @@ export function resetCaretPosition(): void { export async function init(): Promise { caret.hide(); - const mode2 = Misc.getMode2(Config, TestWords.currentQuote); + const mode2 = Misc.getMode2(Config, getCurrentQuote()); let wpm = 0; if (Config.paceCaret === "pb") { wpm = - ( - await DB.getLocalPB( - Config.mode, - mode2, - Config.punctuation, - Config.numbers, - Config.language, - Config.difficulty, - Config.lazyMode, - getActiveFunboxes(), - ) + DB.getLocalPB( + Config.mode, + mode2, + Config.punctuation, + Config.numbers, + Config.language, + Config.difficulty, + Config.lazyMode, + getActiveFunboxes(), )?.wpm ?? 0; } else if (Config.paceCaret === "tagPb") { wpm = getActiveTagsPB( @@ -84,16 +83,17 @@ export async function init(): Promise { Config.lazyMode, ); } else if (Config.paceCaret === "average") { - wpm = Math.round((await getUserAverage10({ ...Config, mode2 })).wpm); + wpm = Math.round((await getUserAverage10Once({ ...Config, mode2 })).wpm); } else if (Config.paceCaret === "daily") { - wpm = Math.round((await getUserDailyBest({ ...Config, mode2 })).wpm); + wpm = Math.round((await getUserDailyBestOnce({ ...Config, mode2 })).wpm); } else if (Config.paceCaret === "custom") { wpm = Config.paceCaretCustomSpeed; - } else if (Config.paceCaret === "last" || TestState.isPaceRepeat) { + } else if (Config.paceCaret === "last" || isPaceRepeat()) { wpm = lastTestWpm; } if (wpm === undefined || wpm < 1 || Number.isNaN(wpm)) { settings = null; + setPaceCaretWpm(undefined); return; } @@ -111,6 +111,7 @@ export async function init(): Promise { wordsStatus: {}, timeout: null, }; + setPaceCaretWpm(wpm); } export async function update(expectedStepEnd: number): Promise { diff --git a/frontend/src/ts/test/practise-words.ts b/frontend/src/ts/test/practise-words.ts index b1ee407c3dfd..1099d4afd7cf 100644 --- a/frontend/src/ts/test/practise-words.ts +++ b/frontend/src/ts/test/practise-words.ts @@ -6,9 +6,9 @@ import { setConfig } from "../config/setters"; import * as CustomText from "./custom-text"; import * as TestInput from "./test-input"; import { configEvent } from "../events/config"; -import { setCustomTextName } from "../legacy-states/custom-text-name"; import { Mode } from "@monkeytype/schemas/shared"; import { CustomTextSettings } from "@monkeytype/schemas/results"; +import { setCustomTextIndicator } from "../states/core"; type Before = { mode: Mode | null; @@ -165,7 +165,7 @@ export function init( 5, ); - setCustomTextName("practise", undefined); + setCustomTextIndicator({ name: "practice", isLong: false }); before.mode = mode; before.punctuation = punctuation; diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts index 1e1f9ee65ead..62ba53b833c3 100644 --- a/frontend/src/ts/test/result.ts +++ b/frontend/src/ts/test/result.ts @@ -15,7 +15,7 @@ import { showSuccessNotification, addNotificationWithLevel, } from "../states/notifications"; -import { isAuthenticated } from "../states/core"; +import { getCustomTextIndicator, isAuthenticated } from "../states/core"; import { getQuoteStats } from "../states/quote-rate"; import * as GlarsesMode from "../legacy-states/glarses-mode"; import * as SlowTimer from "../legacy-states/slow-timer"; @@ -33,7 +33,6 @@ import * as TodayTracker from "./today-tracker"; import { configEvent } from "../events/config"; import * as Focus from "./focus"; import * as CustomText from "./custom-text"; -import * as CustomTextState from "./../legacy-states/custom-text-name"; import * as Funbox from "./funbox/funbox"; import Format from "../singletons/format"; import confetti from "canvas-confetti"; @@ -58,9 +57,9 @@ import { z } from "zod"; import * as TestState from "./test-state"; import { blurInputElement } from "../input/input-element"; import * as ConnectionState from "../legacy-states/connection"; -import { currentQuote } from "./test-words"; import { qs, qsa } from "../utils/dom"; import { getTheme } from "../states/theme"; +import { getCurrentQuote } from "../states/test"; let result: CompletedEvent; let minChartVal: number; @@ -295,7 +294,7 @@ function applyFakeChartData(): void { export async function updateChartPBLine(): Promise { const themecolors = getTheme(); - const localPb = await DB.getLocalPB( + const localPb = DB.getLocalPB( result.mode, result.mode2, result.punctuation ?? false, @@ -510,7 +509,7 @@ export async function updateCrown(dontSave: boolean): Promise { console.debug("Result can get PB:", canGetPb.value, canGetPb.reason ?? ""); if (canGetPb.value) { - const localPb = await DB.getLocalPB( + const localPb = DB.getLocalPB( Config.mode, result.mode2, Config.punctuation, @@ -535,7 +534,7 @@ export async function updateCrown(dontSave: boolean): Promise { ); } } else { - const localPb = await DB.getLocalPB( + const localPb = DB.getLocalPB( Config.mode, result.mode2, Config.punctuation, @@ -1050,7 +1049,7 @@ export async function update( qs("main #result #rateQuoteButton")?.hide(); qs("main #result #reportQuoteButton")?.hide(); } else { - updateRateQuote(currentQuote); + updateRateQuote(getCurrentQuote()); qs("main #result #reportQuoteButton")?.show(); } qs("main #result .stats .dailyLeaderboard")?.hide(); @@ -1090,7 +1089,7 @@ export async function update( Config.words, Config.time, CustomText.getData(), - CustomTextState.isCustomTextLong() ?? false, + getCustomTextIndicator()?.isLong ?? false, ); if (Config.alwaysShowWordsHistory && canQuickRestart && !GlarsesMode.get()) { diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts index 87b70ad1883f..17f74bce35b5 100644 --- a/frontend/src/ts/test/test-logic.ts +++ b/frontend/src/ts/test/test-logic.ts @@ -11,7 +11,6 @@ import { showSuccessNotification, } from "../states/notifications"; import * as CustomText from "./custom-text"; -import * as CustomTextState from "../legacy-states/custom-text-name"; import * as TestStats from "./test-stats"; import * as PractiseWords from "./practise-words"; import * as ShiftTracker from "./shift-tracker"; @@ -27,8 +26,17 @@ import * as TodayTracker from "./today-tracker"; import * as ChallengeContoller from "../controllers/challenge-controller"; import { clearQuoteStats } from "../states/quote-rate"; import * as Result from "./result"; -import { getActivePage, isAuthenticated } from "../states/core"; import { + getActivePage, + getCustomTextIndicator, + isAuthenticated, +} from "../states/core"; +import { + getCurrentQuote, + isPaceRepeat, + isRepeated, + setIsPaceRepeat, + setIsRepeated, setResultVisible, setWordsHaveNewline, setWordsHaveTab, @@ -157,10 +165,7 @@ export function startTest(now: number): boolean { } try { - if ( - Config.paceCaret !== "off" || - (Config.repeatedPace && TestState.isPaceRepeat) - ) { + if (Config.paceCaret !== "off" || (Config.repeatedPace && isPaceRepeat())) { PaceCaret.start(); } } catch (e) {} @@ -219,7 +224,7 @@ export function restart(options = {} as RestartOptions): void { Config.words, Config.time, CustomText.getData(), - CustomTextState.isCustomTextLong() ?? false, + getCustomTextIndicator()?.isLong ?? false, ) ) { let message = "Use your mouse to confirm."; @@ -241,7 +246,7 @@ export function restart(options = {} as RestartOptions): void { } } - if (TestState.isRepeated) { + if (isRepeated()) { options.withSameWordset = true; } @@ -260,10 +265,11 @@ export function restart(options = {} as RestartOptions): void { } } + const currentQuote = getCurrentQuote(); if ( Config.mode === "quote" && - TestWords.currentQuote !== null && - Config.language.startsWith(TestWords.currentQuote.language) && + currentQuote !== null && + Config.language.startsWith(currentQuote.language) && Config.repeatQuotes === "typing" && (TestState.isActive || failReason !== "") ) { @@ -352,8 +358,8 @@ export function restart(options = {} as RestartOptions): void { repeatWithPace = true; } - TestState.setRepeated(options.withSameWordset ?? false); - TestState.setPaceRepeat(repeatWithPace); + setIsRepeated(options.withSameWordset ?? false); + setIsPaceRepeat(repeatWithPace); TestInitFailed.hide(); TestState.setTestInitSuccess(true); const initResult = await init(); @@ -512,7 +518,7 @@ async function init(): Promise { mode: Config.mode, mode2: Misc.getMode2(Config, null), funbox: Config.funbox, - currentQuote: TestWords.currentQuote, + currentQuote: getCurrentQuote(), }); let wordsHaveTab = false; @@ -618,8 +624,7 @@ export function areAllTestWordsGenerated(): boolean { TestWords.words.length >= CustomText.getLimitValue() && CustomText.getLimitValue() !== 0) || (Config.mode === "quote" && - TestWords.words.length >= - (TestWords.currentQuote?.textSplit?.length ?? 0)) || + TestWords.words.length >= (getCurrentQuote()?.textSplit?.length ?? 0)) || (Config.mode === "custom" && CustomText.getLimitMode() === "section" && WordsGenerator.sectionIndex >= CustomText.getLimitValue() && @@ -825,7 +830,7 @@ function buildCompletedEvent( language = Strings.removeLanguageSize(Config.language); } - const quoteLength = TestWords.currentQuote?.group ?? -1; + const quoteLength = getCurrentQuote()?.group ?? -1; const completedEvent: Omit = { wpm: stats.wpm, @@ -839,7 +844,7 @@ function buildCompletedEvent( charTotal: stats.allChars, acc: stats.acc, mode: Config.mode, - mode2: Misc.getMode2(Config, TestWords.currentQuote), + mode2: Misc.getMode2(Config, getCurrentQuote()), quoteLength: quoteLength, punctuation: Config.punctuation, numbers: Config.numbers, @@ -898,8 +903,8 @@ export async function finish(difficultyFailed = false): Promise { TestUI.onTestFinish(); - if (TestState.isRepeated && Config.mode === "quote") { - TestState.setRepeated(false); + if (isRepeated() && Config.mode === "quote") { + setIsRepeated(false); } // in case the tests ends with a keypress (not a word submission) @@ -1070,7 +1075,7 @@ export async function finish(difficultyFailed = false): Promise { showNoticeNotification("Test invalid - AFK detected"); TestStats.setInvalid(); dontSave = true; - } else if (TestState.isRepeated) { + } else if (isRepeated()) { showNoticeNotification("Test invalid - repeated"); TestStats.setInvalid(); dontSave = true; @@ -1111,7 +1116,7 @@ export async function finish(difficultyFailed = false): Promise { // test is valid - if (TestState.isRepeated || difficultyFailed) { + if (isRepeated() || difficultyFailed) { if (Config.resultSaving) { const testSeconds = completedEvent.testDuration; const afkseconds = completedEvent.afkDuration; @@ -1124,9 +1129,9 @@ export async function finish(difficultyFailed = false): Promise { } } - const customTextName = CustomTextState.getCustomTextName(); - const isLong = CustomTextState.isCustomTextLong(); - if (Config.mode === "custom" && customTextName !== "" && isLong) { + const customTextName = getCustomTextIndicator()?.name; + const isLong = getCustomTextIndicator()?.isLong; + if (Config.mode === "custom" && customTextName !== undefined && isLong) { // Let's update the custom text progress if ( TestState.bailedOut || @@ -1211,9 +1216,9 @@ export async function finish(difficultyFailed = false): Promise { difficultyFailed, failReason, afkDetected, - TestState.isRepeated, + isRepeated(), tooShort, - TestWords.currentQuote, + getCurrentQuote(), dontSave, ); @@ -1312,7 +1317,7 @@ async function saveResult( if (data.isPb !== undefined && data.isPb) { //new pb - const localPb = await DB.getLocalPB( + const localPb = DB.getLocalPB( result.mode, result.mode2, result.punctuation, diff --git a/frontend/src/ts/test/test-state.ts b/frontend/src/ts/test/test-state.ts index c0976ab8b075..b91b97163f7f 100644 --- a/frontend/src/ts/test/test-state.ts +++ b/frontend/src/ts/test/test-state.ts @@ -1,7 +1,5 @@ import { promiseWithResolvers } from "../utils/misc"; -export let isRepeated = false; -export let isPaceRepeat = false; export let isActive = false; export let bailedOut = false; export let selectedQuoteId = @@ -13,14 +11,6 @@ export let isDirectionReversed = false; export let testRestarting = false; export let resultVisible = false; -export function setRepeated(tf: boolean): void { - isRepeated = tf; -} - -export function setPaceRepeat(tf: boolean): void { - isPaceRepeat = tf; -} - export function setActive(tf: boolean): void { isActive = tf; } diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index 4d8b099f00c5..40b1df8e48d2 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -68,7 +68,7 @@ import { } from "../utils/dom"; import { getTheme } from "../states/theme"; import { skipBreakdownEvent } from "../states/header"; -import { wordsHaveNewline } from "../states/test"; +import { getCurrentQuote, wordsHaveNewline } from "../states/test"; export const updateHintsPositionDebounced = Misc.debounceUntilResolved( updateHintsPosition, @@ -1141,7 +1141,7 @@ export async function scrollTape(noAnimation = false): Promise { } export function updatePremid(): void { - const mode2 = Misc.getMode2(Config, TestWords.currentQuote); + const mode2 = Misc.getMode2(Config, getCurrentQuote()); let fbtext = ""; if (Config.funbox.length > 0) { fbtext = ` ${Config.funbox.join(" ")}`; diff --git a/frontend/src/ts/test/test-words.ts b/frontend/src/ts/test/test-words.ts index 5ab6bf4337a1..b8ddae67d6ff 100644 --- a/frontend/src/ts/test/test-words.ts +++ b/frontend/src/ts/test/test-words.ts @@ -1,4 +1,3 @@ -import { QuoteWithTextSplit } from "../controllers/quotes-controller"; import * as TestState from "./test-state"; class Words { @@ -58,11 +57,6 @@ class Words { export const words = new Words(); export let hasNumbers = false; -export let currentQuote = null as QuoteWithTextSplit | null; - -export function setCurrentQuote(rq: QuoteWithTextSplit | null): void { - currentQuote = rq; -} export function setHasNumbers(tf: boolean): void { hasNumbers = tf; diff --git a/frontend/src/ts/test/timer-progress.ts b/frontend/src/ts/test/timer-progress.ts index 89a41bc521e9..2c9f8963aa11 100644 --- a/frontend/src/ts/test/timer-progress.ts +++ b/frontend/src/ts/test/timer-progress.ts @@ -9,6 +9,7 @@ import { configEvent } from "../events/config"; import { applyReducedMotion } from "../utils/misc"; import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-frame"; import { animate } from "animejs"; +import { getCurrentQuote } from "../states/test"; const barEl = document.querySelector("#barTimerProgress .bar") as HTMLElement; const barOpacityEl = document.querySelector( @@ -206,7 +207,7 @@ export function update(): void { outof = CustomText.getLimitValue(); } if (Config.mode === "quote") { - outof = TestWords.currentQuote?.textSplit.length ?? 1; + outof = getCurrentQuote()?.textSplit.length ?? 1; } if (Config.timerStyle === "bar") { const percent = Math.floor( diff --git a/frontend/src/ts/test/words-generator.ts b/frontend/src/ts/test/words-generator.ts index d9c08d0744e7..95895c4ddbfd 100644 --- a/frontend/src/ts/test/words-generator.ts +++ b/frontend/src/ts/test/words-generator.ts @@ -6,7 +6,6 @@ import QuotesController, { Quote, QuoteWithTextSplit, } from "../controllers/quotes-controller"; -import * as TestWords from "./test-words"; import * as BritishEnglish from "./british-english"; import * as LazyMode from "./lazy-mode"; import * as EnglishPunctuation from "./english-punctuation"; @@ -28,6 +27,7 @@ import { WordGenError } from "../utils/word-gen-error"; import { showLoaderBar, hideLoaderBar } from "../states/loader-bar"; import { PolyglotWordset } from "./funbox/funbox-functions"; import { LanguageObject } from "@monkeytype/schemas/languages"; +import { getCurrentQuote, isRepeated, setCurrentQuote } from "../states/test"; //pin implementation const random = Math.random; @@ -375,10 +375,11 @@ async function applyBritishEnglishToWord( ): Promise { if (!Config.britishEnglish) return word; if (!Config.language.includes("english")) return word; + const currentQuote = getCurrentQuote(); if ( Config.mode === "quote" && - TestWords.currentQuote?.britishText !== undefined && - TestWords.currentQuote?.britishText !== "" + currentQuote?.britishText !== undefined && + currentQuote?.britishText !== "" ) { return word; } @@ -424,7 +425,7 @@ export function getLimit(): number { let limit = 100; - const currentQuote = TestWords.currentQuote; + const currentQuote = getCurrentQuote(); if (Config.mode === "quote" && currentQuote === null) { throw new WordGenError("Random quote is null"); @@ -498,12 +499,12 @@ async function getQuoteWordList( language: LanguageObject, wordOrder?: FunboxWordOrder, ): Promise { - if (TestState.isRepeated) { + if (isRepeated()) { if (currentWordset === null) { throw new WordGenError("Current wordset is null"); } - TestWords.setCurrentQuote(previousRandomQuote); + setCurrentQuote(previousRandomQuote); // need to re-reverse the words if the test is repeated // because it will be reversed again in the generateWords function @@ -579,17 +580,18 @@ async function getQuoteWordList( rq.textSplit = rq.text.split(" "); } - TestWords.setCurrentQuote(rq as QuoteWithTextSplit); + setCurrentQuote(rq as QuoteWithTextSplit); - if (TestWords.currentQuote === null) { + const currentQuote = getCurrentQuote(); + if (currentQuote === null) { throw new WordGenError("Random quote is null"); } - if (TestWords.currentQuote.textSplit === undefined) { + if (currentQuote.textSplit === undefined) { throw new WordGenError("Random quote textSplit is undefined"); } - return TestWords.currentQuote.textSplit; + return currentQuote.textSplit; } let currentWordset: Wordset | null = null; @@ -610,11 +612,11 @@ let previousRandomQuote: QuoteWithTextSplit | null = null; export async function generateWords( language: LanguageObject, ): Promise { - if (!TestState.isRepeated) { + if (!isRepeated()) { previousGetNextWordReturns = []; } - previousRandomQuote = TestWords.currentQuote; - TestWords.setCurrentQuote(null); + previousRandomQuote = getCurrentQuote(); + setCurrentQuote(null); currentSection = []; sectionIndex = 0; sectionHistory = []; @@ -705,7 +707,7 @@ export async function generateWords( i++; } - const quote = TestWords.currentQuote; + const quote = getCurrentQuote(); if (Config.mode === "quote" && quote === null) { throw new WordGenError("Random quote is null"); @@ -745,7 +747,7 @@ export async function getNextWord( previousWord2: string | undefined, ): Promise { console.debug("Getting next word", { - isRepeated: TestState.isRepeated, + isRepeated: isRepeated(), currentWordset, wordIndex, language: currentLanguage, @@ -765,7 +767,7 @@ export async function getNextWord( //because quote test can be repeated in the middle of a test //we cant rely on data inside previousGetNextWordReturns //because it might not include the full quote - if (TestState.isRepeated && Config.mode !== "quote") { + if (isRepeated() && Config.mode !== "quote") { const repeated = previousGetNextWordReturns[wordIndex]; if (repeated === undefined) { diff --git a/frontend/src/ts/types/quotes.ts b/frontend/src/ts/types/quotes.ts new file mode 100644 index 000000000000..a7d95b6a0b2e --- /dev/null +++ b/frontend/src/ts/types/quotes.ts @@ -0,0 +1,11 @@ +import { Language } from "@monkeytype/schemas/languages"; +import { QuoteDataQuote } from "@monkeytype/schemas/quotes"; +import { RequiredProperties } from "../utils/misc"; + +export type Quote = QuoteDataQuote & { + group: number; + language: Language; + textSplit?: string[]; +}; + +export type QuoteWithTextSplit = RequiredProperties ; diff --git a/frontend/src/ts/ui.ts b/frontend/src/ts/ui.ts index 3ed96ce48f05..2283c1870186 100644 --- a/frontend/src/ts/ui.ts +++ b/frontend/src/ts/ui.ts @@ -5,9 +5,12 @@ import * as TestState from "./test/test-state"; import { configEvent } from "./events/config"; import { debounce, throttle } from "throttle-debounce"; import * as TestUI from "./test/test-ui"; -import { getActivePage, getGlobalOffsetTop } from "./states/core"; +import { + getActivePage, + getCustomTextIndicator, + getGlobalOffsetTop, +} from "./states/core"; import { isDevEnvironment } from "./utils/env"; -import { isCustomTextLong } from "./legacy-states/custom-text-name"; import { canQuickRestart } from "./utils/quick-restart"; import { FontName } from "@monkeytype/schemas/fonts"; import { qs, qsr } from "./utils/dom"; @@ -86,7 +89,7 @@ window.addEventListener("beforeunload", (event) => { Config.words, Config.time, CustomText.getData(), - isCustomTextLong() ?? false, + getCustomTextIndicator()?.isLong ?? false, ) ) { //ignore