diff --git a/frontend/src/html/pages/settings.html b/frontend/src/html/pages/settings.html index 7049cbd4ee1f..c8c3f579abf0 100644 --- a/frontend/src/html/pages/settings.html +++ b/frontend/src/html/pages/settings.html @@ -131,12 +131,27 @@
Normal is the classic typing test experience. Expert fails the test if you submit (press space) an incorrect word. Master fails if you press a - single incorrect key (meaning you have to achieve 100% accuracy). + single incorrect key (meaning you have to achieve 100% accuracy). Custom + allows you to set a custom accuracy threshold in words mode.
-
- - - +
+
+ +
+
+ + + + +
diff --git a/frontend/src/ts/config/metadata.ts b/frontend/src/ts/config/metadata.ts index 481faf990236..120aa7fecf15 100644 --- a/frontend/src/ts/config/metadata.ts +++ b/frontend/src/ts/config/metadata.ts @@ -246,6 +246,21 @@ export const configMetadata: ConfigMetadataObject = { changeRequiresRestart: true, group: "behavior", }, + difficultyCustomAccuracy: { + key: "difficultyCustomAccuracy", + fa: { icon: "fa-star" }, + displayString: "custom difficulty accuracy", + changeRequiresRestart: true, + group: "behavior", + overrideConfig: ({ currentConfig }) => { + if (currentConfig.difficulty !== "custom") { + return { + difficulty: "custom", + }; + } + return {}; + }, + }, quickRestart: { key: "quickRestart", fa: { icon: "fa-redo-alt" }, diff --git a/frontend/src/ts/constants/default-config.ts b/frontend/src/ts/constants/default-config.ts index c2fea2f0d058..ec659bac3573 100644 --- a/frontend/src/ts/constants/default-config.ts +++ b/frontend/src/ts/constants/default-config.ts @@ -33,6 +33,7 @@ const obj: Config = { fontSize: 2, freedomMode: false, difficulty: "normal", + difficultyCustomAccuracy: 100, blindMode: false, quickEnd: false, caretStyle: "default", diff --git a/frontend/src/ts/elements/modes-notice.ts b/frontend/src/ts/elements/modes-notice.ts index 39c5e41679a8..d873ad7ae13e 100644 --- a/frontend/src/ts/elements/modes-notice.ts +++ b/frontend/src/ts/elements/modes-notice.ts @@ -141,6 +141,10 @@ export async function update(): Promise { testModesNotice.appendHtml( ``, ); + } else if (Config.difficulty === "custom") { + testModesNotice.appendHtml( + ``, + ); } if (Config.blindMode) { diff --git a/frontend/src/ts/pages/settings.ts b/frontend/src/ts/pages/settings.ts index 62fe8c4f5057..1f5ed8fb1248 100644 --- a/frontend/src/ts/pages/settings.ts +++ b/frontend/src/ts/pages/settings.ts @@ -438,6 +438,15 @@ async function fillSettingsPage(): Promise { }, }); + handleConfigInput({ + input: qsr(".pageSettings .section[data-config-name='difficulty'] input"), + configName: "difficultyCustomAccuracy", + validation: { + schema: true, + inputValueConvert: Number, + }, + }); + handleConfigInput({ input: qsr(".pageSettings .section[data-config-name='minBurst'] input"), configName: "minBurstCustomSpeed", diff --git a/frontend/src/ts/test/test-timer.ts b/frontend/src/ts/test/test-timer.ts index 26cf66b694e3..0188771d2897 100644 --- a/frontend/src/ts/test/test-timer.ts +++ b/frontend/src/ts/test/test-timer.ts @@ -157,17 +157,16 @@ function checkIfFailed( ): boolean { if (timerDebug) console.time("fail conditions"); TestInput.pushKeypressesToHistory(); - TestInput.pushErrorToHistory(); - TestInput.pushAfkToHistory(); + if ( - Config.minWpm === "custom" && - wpmAndRaw.wpm < Config.minWpmCustomSpeed && - TestState.activeWordIndex > 3 + Config.difficulty === "custom" && + Config.mode === "words" && + acc < Config.difficultyCustomAccuracy ) { if (timer !== null) clearTimeout(timer); SlowTimer.clear(); slowTimerCount = 0; - timerEvent.dispatch({ key: "fail", value: "min speed" }); + timerEvent.dispatch({ key: "fail", value: "custom difficulty" }); return true; } if (Config.minAcc === "custom" && acc < Config.minAccCustom) { diff --git a/packages/schemas/src/configs.ts b/packages/schemas/src/configs.ts index 77c257a54834..67497c6bdf45 100644 --- a/packages/schemas/src/configs.ts +++ b/packages/schemas/src/configs.ts @@ -336,6 +336,11 @@ export type MinWpmCustomSpeed = z.infer; export const MinimumAccuracyCustomSchema = z.number().nonnegative().max(100); export type MinimumAccuracyCustom = z.infer; +export const DifficultyCustomAccuracySchema = z.number().nonnegative().max(100); +export type DifficultyCustomAccuracy = z.infer< + typeof DifficultyCustomAccuracySchema +>; + export const MinimumBurstCustomSpeedSchema = z.number().nonnegative(); export type MinimumBurstCustomSpeed = z.infer< typeof MinimumBurstCustomSpeedSchema @@ -392,6 +397,7 @@ export const ConfigSchema = z // behavior difficulty: DifficultySchema, + difficultyCustomAccuracy: DifficultyCustomAccuracySchema, quickRestart: QuickRestartSchema, repeatQuotes: RepeatQuotesSchema, resultSaving: z.boolean(), diff --git a/packages/schemas/src/shared.ts b/packages/schemas/src/shared.ts index 7a1f5b570d07..2915428cbdf0 100644 --- a/packages/schemas/src/shared.ts +++ b/packages/schemas/src/shared.ts @@ -3,7 +3,12 @@ import { StringNumberSchema } from "./util"; import { LanguageSchema } from "./languages"; //used by config and shared -export const DifficultySchema = z.enum(["normal", "expert", "master"]); +export const DifficultySchema = z.enum([ + "normal", + "expert", + "master", + "custom", +]); export type Difficulty = z.infer; //used by user and config