Move (most) FSRS options into their own section

This commit is contained in:
Damien Elmes 2024-03-17 18:25:25 +07:00
parent e9d3b46d47
commit c462f64862
4 changed files with 145 additions and 90 deletions

View file

@ -12,16 +12,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import HelpModal from "../components/HelpModal.svelte"; import HelpModal from "../components/HelpModal.svelte";
import Item from "../components/Item.svelte"; import Item from "../components/Item.svelte";
import SettingTitle from "../components/SettingTitle.svelte"; import SettingTitle from "../components/SettingTitle.svelte";
import SwitchRow from "../components/SwitchRow.svelte";
import TitledContainer from "../components/TitledContainer.svelte"; import TitledContainer from "../components/TitledContainer.svelte";
import { type HelpItem, HelpItemScheduler } from "../components/types"; import { type HelpItem, HelpItemScheduler } from "../components/types";
import CardStateCustomizer from "./CardStateCustomizer.svelte"; import CardStateCustomizer from "./CardStateCustomizer.svelte";
import FsrsOptions from "./FsrsOptions.svelte";
import GlobalLabel from "./GlobalLabel.svelte";
import type { DeckOptionsState } from "./lib"; import type { DeckOptionsState } from "./lib";
import SpinBoxFloatRow from "./SpinBoxFloatRow.svelte"; import SpinBoxFloatRow from "./SpinBoxFloatRow.svelte";
import SpinBoxRow from "./SpinBoxRow.svelte"; import SpinBoxRow from "./SpinBoxRow.svelte";
import Warning from "./Warning.svelte";
export let state: DeckOptionsState; export let state: DeckOptionsState;
export let api: Record<string, never>; export let api: Record<string, never>;
@ -32,51 +28,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const fsrs = state.fsrs; const fsrs = state.fsrs;
const settings = { const settings = {
fsrs: {
title: "FSRS",
help: tr.deckConfigFsrsTooltip(),
url: HelpPage.DeckOptions.fsrs,
},
maximumInterval: { maximumInterval: {
title: tr.schedulingMaximumInterval(), title: tr.schedulingMaximumInterval(),
help: tr.deckConfigMaximumIntervalTooltip(), help: tr.deckConfigMaximumIntervalTooltip(),
url: HelpPage.DeckOptions.maximumInterval, url: HelpPage.DeckOptions.maximumInterval,
}, },
desiredRetention: {
title: tr.deckConfigDesiredRetention(),
help: tr.deckConfigDesiredRetentionTooltip(),
sched: HelpItemScheduler.FSRS,
},
sm2Retention: { sm2Retention: {
title: tr.deckConfigSm2Retention(), title: tr.deckConfigSm2Retention(),
help: tr.deckConfigSm2RetentionTooltip(), help: tr.deckConfigSm2RetentionTooltip(),
sched: HelpItemScheduler.FSRS, sched: HelpItemScheduler.FSRS,
}, },
modelWeights: {
title: tr.deckConfigWeights(),
help: tr.deckConfigWeightsTooltip(),
sched: HelpItemScheduler.FSRS,
},
rescheduleCardsOnChange: {
title: tr.deckConfigRescheduleCardsOnChange(),
help: tr.deckConfigRescheduleCardsOnChangeTooltip(),
sched: HelpItemScheduler.FSRS,
},
ignoreRevlogsBeforeMs: {
title: tr.deckConfigIgnoreBefore(),
help: tr.deckConfigIgnoreBeforeTooltip(),
sched: HelpItemScheduler.FSRS,
},
computeOptimalWeights: {
title: tr.deckConfigComputeOptimalWeights(),
help: tr.deckConfigComputeOptimalWeightsTooltip(),
sched: HelpItemScheduler.FSRS,
},
computeOptimalRetention: {
title: tr.deckConfigComputeOptimalRetention(),
help: tr.deckConfigComputeOptimalRetentionTooltip(),
sched: HelpItemScheduler.FSRS,
},
startingEase: { startingEase: {
title: tr.schedulingStartingEase(), title: tr.schedulingStartingEase(),
help: tr.deckConfigStartingEaseTooltip(), help: tr.deckConfigStartingEaseTooltip(),
@ -122,8 +83,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
modal.show(); modal.show();
carousel.to(index); carousel.to(index);
} }
$: fsrsClientWarning = $fsrs ? tr.deckConfigFsrsOnAllClients() : "";
</script> </script>
<TitledContainer title={tr.deckConfigAdvancedTitle()}> <TitledContainer title={tr.deckConfigAdvancedTitle()}>
@ -139,19 +98,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}} }}
/> />
<DynamicallySlottable slotHost={Item} {api}> <DynamicallySlottable slotHost={Item} {api}>
<Item>
<SwitchRow bind:value={$fsrs} defaultValue={false}>
<SettingTitle
on:click={() =>
openHelpModal(Object.keys(settings).indexOf("fsrs"))}
>
<GlobalLabel title={settings.fsrs.title} />
</SettingTitle>
</SwitchRow>
</Item>
<Warning warning={fsrsClientWarning} />
<Item> <Item>
<SpinBoxRow <SpinBoxRow
bind:value={$config.maximumReviewInterval} bind:value={$config.maximumReviewInterval}
@ -254,11 +200,19 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</SpinBoxFloatRow> </SpinBoxFloatRow>
</Item> </Item>
{:else} {:else}
<FsrsOptions <SpinBoxFloatRow
{state} bind:value={$config.sm2Retention}
openHelpModal={(key) => defaultValue={defaults.sm2Retention}
openHelpModal(Object.keys(settings).indexOf(key))} min={0.5}
/> max={1.0}
>
<SettingTitle
on:click={() =>
openHelpModal(Object.keys(settings).indexOf("sm2Retention"))}
>
{tr.deckConfigSm2Retention()}
</SettingTitle>
</SpinBoxFloatRow>
{/if} {/if}
<Item> <Item>

View file

@ -16,6 +16,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import ConfigSelector from "./ConfigSelector.svelte"; import ConfigSelector from "./ConfigSelector.svelte";
import DailyLimits from "./DailyLimits.svelte"; import DailyLimits from "./DailyLimits.svelte";
import DisplayOrder from "./DisplayOrder.svelte"; import DisplayOrder from "./DisplayOrder.svelte";
import FsrsOptionsOuter from "./FsrsOptionsOuter.svelte";
import HtmlAddon from "./HtmlAddon.svelte"; import HtmlAddon from "./HtmlAddon.svelte";
import LapseOptions from "./LapseOptions.svelte"; import LapseOptions from "./LapseOptions.svelte";
import type { DeckOptionsState } from "./lib"; import type { DeckOptionsState } from "./lib";
@ -107,6 +108,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</Row> </Row>
{/if} {/if}
<Row class="row-columns">
<FsrsOptionsOuter {state} api={{}} />
</Row>
<Row class="row-columns"> <Row class="row-columns">
<AdvancedOptions {state} api={advancedOptions} /> <AdvancedOptions {state} api={advancedOptions} />
</Row> </Row>

View file

@ -268,17 +268,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<Warning warning={desiredRetentionWarning} className={retentionWarningClass} /> <Warning warning={desiredRetentionWarning} className={retentionWarningClass} />
<SpinBoxFloatRow
bind:value={$config.sm2Retention}
defaultValue={defaults.sm2Retention}
min={0.5}
max={1.0}
>
<SettingTitle on:click={() => openHelpModal("sm2Retention")}>
{tr.deckConfigSm2Retention()}
</SettingTitle>
</SpinBoxFloatRow>
<div class="ms-1 me-1"> <div class="ms-1 me-1">
<WeightsInputRow <WeightsInputRow
bind:value={$config.fsrsWeights} bind:value={$config.fsrsWeights}
@ -289,27 +278,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{tr.deckConfigWeights()} {tr.deckConfigWeights()}
</SettingTitle> </SettingTitle>
</WeightsInputRow> </WeightsInputRow>
</div>
<div class="m-2">
<SwitchRow bind:value={$fsrsReschedule} defaultValue={false}>
<SettingTitle on:click={() => openHelpModal("rescheduleCardsOnChange")}>
<GlobalLabel title={tr.deckConfigRescheduleCardsOnChange()} />
</SettingTitle>
</SwitchRow>
{#if $fsrsReschedule}
<Warning warning={tr.deckConfigRescheduleCardsWarning()} />
{/if}
</div>
<div class="m-2">
<b>{tr.deckConfigComputeOptimalWeights()}</b>
<input <input
bind:value={$config.weightSearch} bind:value={$config.weightSearch}
placeholder={defaultWeightSearch} placeholder={defaultWeightSearch}
class="w-100 mb-1" class="w-100 mb-1"
/> />
<DateInput bind:date={$config.ignoreRevlogsBeforeDate}>
<SettingTitle on:click={() => openHelpModal("ignoreBefore")}>
{tr.deckConfigIgnoreBefore()}
</SettingTitle>
</DateInput>
<button <button
class="btn {computingWeights ? 'btn-warning' : 'btn-primary'}" class="btn {computingWeights ? 'btn-warning' : 'btn-primary'}"
disabled={!computingWeights && computing} disabled={!computingWeights && computing}
@ -332,11 +311,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{tr.deckConfigEvaluateButton()} {tr.deckConfigEvaluateButton()}
{/if} {/if}
</button> </button>
<DateInput bind:date={$config.ignoreRevlogsBeforeDate}>
<SettingTitle on:click={() => openHelpModal("ignoreBefore")}>
{tr.deckConfigIgnoreBefore()}
</SettingTitle>
</DateInput>
{#if computingWeights || checkingWeights}<div> {#if computingWeights || checkingWeights}<div>
{computeWeightsProgressString} {computeWeightsProgressString}
</div>{/if} </div>{/if}
@ -344,6 +318,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<Warning warning={lastOptimizationWarning} className="alert-warning" /> <Warning warning={lastOptimizationWarning} className="alert-warning" />
</div> </div>
<div class="m-2">
<SwitchRow bind:value={$fsrsReschedule} defaultValue={false}>
<SettingTitle on:click={() => openHelpModal("rescheduleCardsOnChange")}>
<GlobalLabel title={tr.deckConfigRescheduleCardsOnChange()} />
</SettingTitle>
</SwitchRow>
{#if $fsrsReschedule}
<Warning warning={tr.deckConfigRescheduleCardsWarning()} />
{/if}
</div>
<div class="m-2"> <div class="m-2">
<details> <details>
<summary>{tr.deckConfigComputeOptimalRetention()} (experimental)</summary> <summary>{tr.deckConfigComputeOptimalRetention()} (experimental)</summary>

View file

@ -0,0 +1,110 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import * as tr from "@tslib/ftl";
import { HelpPage } from "@tslib/help-page";
import type Carousel from "bootstrap/js/dist/carousel";
import type Modal from "bootstrap/js/dist/modal";
import DynamicallySlottable from "../components/DynamicallySlottable.svelte";
import HelpModal from "../components/HelpModal.svelte";
import Item from "../components/Item.svelte";
import SettingTitle from "../components/SettingTitle.svelte";
import SwitchRow from "../components/SwitchRow.svelte";
import TitledContainer from "../components/TitledContainer.svelte";
import { type HelpItem, HelpItemScheduler } from "../components/types";
import FsrsOptions from "./FsrsOptions.svelte";
import GlobalLabel from "./GlobalLabel.svelte";
import type { DeckOptionsState } from "./lib";
import Warning from "./Warning.svelte";
export let state: DeckOptionsState;
export let api: Record<string, never>;
const fsrs = state.fsrs;
const settings = {
fsrs: {
title: "FSRS",
help: tr.deckConfigFsrsTooltip(),
url: HelpPage.DeckOptions.fsrs,
},
desiredRetention: {
title: tr.deckConfigDesiredRetention(),
help: tr.deckConfigDesiredRetentionTooltip(),
sched: HelpItemScheduler.FSRS,
},
modelWeights: {
title: tr.deckConfigWeights(),
help:
tr.deckConfigWeightsTooltip() +
"\n\n" +
tr.deckConfigComputeOptimalWeightsTooltip(),
sched: HelpItemScheduler.FSRS,
},
ignoreRevlogsBeforeMs: {
title: tr.deckConfigIgnoreBefore(),
help: tr.deckConfigIgnoreBeforeTooltip(),
sched: HelpItemScheduler.FSRS,
},
rescheduleCardsOnChange: {
title: tr.deckConfigRescheduleCardsOnChange(),
help: tr.deckConfigRescheduleCardsOnChangeTooltip(),
sched: HelpItemScheduler.FSRS,
},
computeOptimalRetention: {
title: tr.deckConfigComputeOptimalRetention(),
help: tr.deckConfigComputeOptimalRetentionTooltip(),
sched: HelpItemScheduler.FSRS,
},
};
const helpSections = Object.values(settings) as HelpItem[];
let modal: Modal;
let carousel: Carousel;
function openHelpModal(index: number): void {
modal.show();
carousel.to(index);
}
$: fsrsClientWarning = $fsrs ? tr.deckConfigFsrsOnAllClients() : "";
</script>
<TitledContainer title={"FSRS"}>
<HelpModal
title={"FSRS"}
url={HelpPage.DeckOptions.fsrs}
slot="tooltip"
fsrs={$fsrs}
{helpSections}
on:mount={(e) => {
modal = e.detail.modal;
carousel = e.detail.carousel;
}}
/>
<DynamicallySlottable slotHost={Item} {api}>
<Item>
<SwitchRow bind:value={$fsrs} defaultValue={false}>
<SettingTitle
on:click={() =>
openHelpModal(Object.keys(settings).indexOf("fsrs"))}
>
<GlobalLabel title={settings.fsrs.title} />
</SettingTitle>
</SwitchRow>
</Item>
<Warning warning={fsrsClientWarning} />
{#if $fsrs}
<FsrsOptions
{state}
openHelpModal={(key) =>
openHelpModal(Object.keys(settings).indexOf(key))}
/>
{/if}
</DynamicallySlottable>
</TitledContainer>