expose new sorting options in test scheduler options; move things around

This commit is contained in:
Damien Elmes 2021-05-13 15:23:16 +10:00
parent a1bd6b481d
commit dbbcb3e38c
15 changed files with 184 additions and 75 deletions

View File

@ -21,8 +21,9 @@ deck-config-review-limit-tooltip =
The maximum number of review cards to show in a day, The maximum number of review cards to show in a day,
if cards are ready for review. if cards are ready for review.
## New Cards section ## Learning/Relearning section
deck-config-learning-relearning-title = Learning/Relearning
deck-config-learning-steps = Learning steps deck-config-learning-steps = Learning steps
# Please don't translate '5m' or '2d' # Please don't translate '5m' or '2d'
-deck-config-delay-hint = Delays can be in minutes (eg "5m"), or days (eg "2d"). -deck-config-delay-hint = Delays can be in minutes (eg "5m"), or days (eg "2d").
@ -32,21 +33,56 @@ deck-config-learning-steps-tooltip =
The Good button will advance to the next step, which is 10 minutes by default. The Good button will advance to the next step, which is 10 minutes by default.
Once all steps have been passed, the card will become a review card, and Once all steps have been passed, the card will become a review card, and
will appear on a different day. { -deck-config-delay-hint } will appear on a different day. { -deck-config-delay-hint }
deck-config-graduating-interval-tooltip =
The number of days to wait before showing a card again, after the Good button
is pressed on the final learning step.
deck-config-easy-interval-tooltip =
The number of days to wait before showing a card again, after the Easy button
is used to immediately remove a card from learning.
## Lapses section
deck-config-relearning-steps = Relearning steps deck-config-relearning-steps = Relearning steps
deck-config-relearning-steps-tooltip = deck-config-relearning-steps-tooltip =
Zero or more delays, separated by spaces. By default, pressing the Again Zero or more delays, separated by spaces. By default, pressing the Again
button on a review card will show it again 10 minutes later. If no delays button on a review card will show it again 10 minutes later. If no delays
are provided, the card will have its interval changed, without entering are provided, the card will have its interval changed, without entering
relearning. { -deck-config-delay-hint } relearning. { -deck-config-delay-hint }
deck-config-interday-step-priority = Interday step priority
deck-config-interday-step-priority-tooltip = When to show (re)learning cards that cross a day boundary.
deck-config-review-mix-mix-with-reviews = Mix with reviews
deck-config-review-mix-show-after-reviews = Show after reviews
deck-config-review-mix-show-before-reviews = Show before reviews
## New Cards section
deck-config-graduating-interval-tooltip =
The number of days to wait before showing a card again, after the Good button
is pressed on the final learning step.
deck-config-easy-interval-tooltip =
The number of days to wait before showing a card again, after the Easy button
is used to immediately remove a card from learning.
deck-config-new-insertion-order = Insertion order
deck-config-new-insertion-order-tooltip =
Controls the position (due #) new cards are assigned when you add new cards.
Cards with a lower due # will be shown first when reviewing. Changing this
option will automatically update the existing position of new cards.
deck-config-new-insertion-order-sequential = Sequential (show oldest cards first)
deck-config-new-insertion-order-random = Random
deck-config-sort-order = Sort order
deck-config-sort-order-tooltip =
After today's new cards have been gathered, this option controls the order
they are then presented in. The default is to sort by card template first, to avoid
multiple cards of the same note from being shown in succession.
deck-config-sort-order-card-template-then-position = Card template, then position
deck-config-sort-order-card-template-then-random = Card template, then random
deck-config-sort-order-position = Position (siblings together)
deck-config-sort-order-random = Random
deck-config-new-priority = Priority
deck-config-new-priority-tooltip = When to show new cards in a study session.
## Review section
deck-config-review-sort-order-tooltip =
After today's review cards have been gathered, this option controls the order
they are then presented in. The default is to sort by due date, then shuffle, so
that if you have a backlog of reviews, the cards that have been waiting longest
will be shown first. The other choices can be useful when you have a large backlog
and want to tackle it in a different way.
deck-config-sort-order-due-date-then-random = Due date, then random
deck-config-sort-order-ascending-intervals = Ascending intervals
deck-config-sort-order-descending-intervals = Descending intervals
deck-config-leech-threshold-tooltip = deck-config-leech-threshold-tooltip =
The number of times Again needs to be pressed on a review card before it is The number of times Again needs to be pressed on a review card before it is
marked as a leech. Leeches are cards that consume a lot of your time, and marked as a leech. Leeches are cards that consume a lot of your time, and
@ -60,7 +96,8 @@ deck-config-leech-action-tooltip =
## Burying section ## Burying section
deck-config-burying-title = Burying deck-config-bury-new-siblings = Bury new siblings until the next day
deck-config-bury-review-siblings = Bury review siblings until the next day
deck-config-bury-tooltip = deck-config-bury-tooltip =
Whether other cards of the same note (eg reverse cards, adjacent Whether other cards of the same note (eg reverse cards, adjacent
cloze deletions) will be delayed until the next day. cloze deletions) will be delayed until the next day.

View File

@ -142,7 +142,7 @@ class Collection:
supportedSchedulerVersions = (1, 2) supportedSchedulerVersions = (1, 2)
def schedVer(self) -> Any: def schedVer(self) -> Literal[1, 2]:
ver = self.conf.get("schedVer", 1) ver = self.conf.get("schedVer", 1)
if ver in self.supportedSchedulerVersions: if ver in self.supportedSchedulerVersions:
return ver return ver

View File

@ -1134,7 +1134,7 @@ title="%s" %s>%s</button>""" % (
if deck["dyn"]: if deck["dyn"]:
aqt.dialogs.open("FilteredDeckConfigDialog", self, deck_id=deck["id"]) aqt.dialogs.open("FilteredDeckConfigDialog", self, deck_id=deck["id"])
else: else:
if KeyboardModifiersPressed().shift: if KeyboardModifiersPressed().shift or self.col.schedVer() == 1:
aqt.deckconf.DeckConf(self, deck) aqt.deckconf.DeckConf(self, deck)
else: else:
DeckOptionsDialog(self) DeckOptionsDialog(self)

View File

@ -55,16 +55,19 @@ class Preferences(QDialog):
form = self.form form = self.form
scheduling = self.prefs.scheduling scheduling = self.prefs.scheduling
version = scheduling.scheduler_version
form.dayLearnFirst.setVisible(version == 2)
# fixme: force on for v3
form.legacy_timezone.setVisible(version >= 2)
form.newSpread.setVisible(version < 3)
form.lrnCutoff.setValue(int(scheduling.learn_ahead_secs / 60.0)) form.lrnCutoff.setValue(int(scheduling.learn_ahead_secs / 60.0))
form.newSpread.addItems(list(newCardSchedulingLabels(self.mw.col).values())) form.newSpread.addItems(list(newCardSchedulingLabels(self.mw.col).values()))
form.newSpread.setCurrentIndex(scheduling.new_review_mix) form.newSpread.setCurrentIndex(scheduling.new_review_mix)
form.dayLearnFirst.setChecked(scheduling.day_learn_first) form.dayLearnFirst.setChecked(scheduling.day_learn_first)
form.dayOffset.setValue(scheduling.rollover) form.dayOffset.setValue(scheduling.rollover)
if scheduling.scheduler_version < 2: form.legacy_timezone.setChecked(not scheduling.new_timezone)
form.dayLearnFirst.setVisible(False)
form.legacy_timezone.setVisible(False)
else:
form.legacy_timezone.setChecked(not scheduling.new_timezone)
reviewing = self.prefs.reviewing reviewing = self.prefs.reviewing
form.timeLimit.setValue(int(reviewing.time_limit_secs / 60.0)) form.timeLimit.setValue(int(reviewing.time_limit_secs / 60.0))

View File

@ -925,6 +925,7 @@ message DeckConfigsForUpdate {
CurrentDeck current_deck = 2; CurrentDeck current_deck = 2;
DeckConfig defaults = 3; DeckConfig defaults = 3;
bool schema_modified = 4; bool schema_modified = 4;
bool v3_scheduler = 5;
} }
message UpdateDeckConfigsIn { message UpdateDeckConfigsIn {
@ -1147,7 +1148,7 @@ message Preferences {
NEW_FIRST = 2; NEW_FIRST = 2;
} }
// read only // read only; 1-3
uint32 scheduler_version = 1; uint32 scheduler_version = 1;
uint32 rollover = 2; uint32 rollover = 2;

View File

@ -37,6 +37,7 @@ impl Collection {
.storage .storage
.get_collection_timestamps()? .get_collection_timestamps()?
.schema_changed_since_sync(), .schema_changed_since_sync(),
v3_scheduler: self.get_bool(BoolKey::Sched2021),
}) })
} }

View File

@ -45,7 +45,13 @@ impl Collection {
Ok(Scheduling { Ok(Scheduling {
scheduler_version: match self.scheduler_version() { scheduler_version: match self.scheduler_version() {
crate::config::SchedulerVersion::V1 => 1, crate::config::SchedulerVersion::V1 => 1,
crate::config::SchedulerVersion::V2 => 2, crate::config::SchedulerVersion::V2 => {
if self.get_bool(BoolKey::Sched2021) {
3
} else {
2
}
}
}, },
rollover: self.rollover_for_current_scheduler()? as u32, rollover: self.rollover_for_current_scheduler()? as u32,
learn_ahead_secs: self.learn_ahead_secs(), learn_ahead_secs: self.learn_ahead_secs(),

View File

@ -57,6 +57,7 @@ ts_library(
"icons.ts", "icons.ts",
"lib.ts", "lib.ts",
"steps.ts", "steps.ts",
"strings.ts",
"textInputModal.ts", "textInputModal.ts",
], ],
module_name = "deckoptions", module_name = "deckoptions",

View File

@ -1,27 +0,0 @@
<!--
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 "lib/i18n";
import CheckBox from "./CheckBox.svelte";
import type { DeckOptionsState } from "./lib";
export let state: DeckOptionsState;
let config = state.currentConfig;
let defaults = state.defaults;
</script>
<h2>{tr.deckConfigBuryingTitle()}</h2>
<CheckBox
label={tr.schedulingBuryRelatedNewCardsUntilThe()}
tooltip={tr.deckConfigBuryTooltip()}
defaultValue={defaults.buryNew}
bind:value={$config.buryNew} />
<CheckBox
label={tr.schedulingBuryRelatedReviewsUntilTheNext()}
tooltip={tr.deckConfigBuryTooltip()}
defaultValue={defaults.buryReviews}
bind:value={$config.buryReviews} />

View File

@ -4,10 +4,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
--> -->
<script lang="ts"> <script lang="ts">
import DailyLimits from "./DailyLimits.svelte"; import DailyLimits from "./DailyLimits.svelte";
import LearningOptions from "./LearningOptions.svelte";
import NewOptions from "./NewOptions.svelte"; import NewOptions from "./NewOptions.svelte";
import BuryingOptions from "./BuryingOptions.svelte";
import AdvancedOptions from "./AdvancedOptions.svelte"; import AdvancedOptions from "./AdvancedOptions.svelte";
import LapseOptions from "./LapseOptions.svelte"; import ReviewOptions from "./ReviewOptions.svelte";
import GeneralOptions from "./GeneralOptions.svelte"; import GeneralOptions from "./GeneralOptions.svelte";
import Addons from "./Addons.svelte"; import Addons from "./Addons.svelte";
import type { DeckOptionsState } from "./lib"; import type { DeckOptionsState } from "./lib";
@ -27,9 +27,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<div> <div>
<DailyLimits {state} /> <DailyLimits {state} />
<LearningOptions {state} />
<NewOptions {state} /> <NewOptions {state} />
<LapseOptions {state} /> <ReviewOptions {state} />
<BuryingOptions {state} />
<GeneralOptions {state} /> <GeneralOptions {state} />
<Addons {state} /> <Addons {state} />
<AdvancedOptions {state} /> <AdvancedOptions {state} />

View File

@ -0,0 +1,40 @@
<!--
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 "lib/i18n";
import StepsInput from "./StepsInput.svelte";
import EnumSelector from "./EnumSelector.svelte";
import type { DeckOptionsState } from "./lib";
import { reviewMixChoices } from "./strings";
export let state: DeckOptionsState;
let config = state.currentConfig;
let defaults = state.defaults;
</script>
<h2>{tr.deckConfigLearningRelearningTitle()}</h2>
<StepsInput
label={tr.deckConfigLearningSteps()}
tooltip={tr.deckConfigLearningStepsTooltip()}
defaultValue={defaults.learnSteps}
value={$config.learnSteps}
on:changed={(evt) => ($config.learnSteps = evt.detail.value)} />
<StepsInput
label={tr.deckConfigRelearningSteps()}
tooltip={tr.deckConfigRelearningStepsTooltip()}
defaultValue={defaults.relearnSteps}
value={$config.relearnSteps}
on:changed={(evt) => ($config.relearnSteps = evt.detail.value)} />
{#if state.v3Scheduler}
<EnumSelector
label={tr.deckConfigInterdayStepPriority()}
tooltip={tr.deckConfigInterdayStepPriorityTooltip()}
choices={reviewMixChoices()}
defaultValue={defaults.interdayLearningMix}
bind:value={$config.interdayLearningMix} />
{/if}

View File

@ -5,17 +5,24 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="ts"> <script lang="ts">
import * as tr from "lib/i18n"; import * as tr from "lib/i18n";
import SpinBox from "./SpinBox.svelte"; import SpinBox from "./SpinBox.svelte";
import StepsInput from "./StepsInput.svelte"; import CheckBox from "./CheckBox.svelte";
import EnumSelector from "./EnumSelector.svelte"; import EnumSelector from "./EnumSelector.svelte";
import type { DeckOptionsState } from "./lib"; import type { DeckOptionsState } from "./lib";
import { reviewMixChoices } from "./strings";
export let state: DeckOptionsState; export let state: DeckOptionsState;
let config = state.currentConfig; let config = state.currentConfig;
let defaults = state.defaults; let defaults = state.defaults;
const newOrderChoices = [ const newFetchOrderChoices = [
tr.schedulingShowNewCardsInOrderAdded(), tr.deckConfigNewInsertionOrderSequential(),
tr.schedulingShowNewCardsInRandomOrder(), tr.deckConfigNewInsertionOrderRandom(),
];
const newSortOrderChoices = [
tr.deckConfigSortOrderCardTemplateThenPosition(),
tr.deckConfigSortOrderCardTemplateThenRandom(),
tr.deckConfigSortOrderPosition(),
tr.deckConfigSortOrderRandom(),
]; ];
let stepsExceedGraduatingInterval: string; let stepsExceedGraduatingInterval: string;
@ -37,13 +44,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<h2>{tr.schedulingNewCards()}</h2> <h2>{tr.schedulingNewCards()}</h2>
<StepsInput
label={tr.deckConfigLearningSteps()}
tooltip={tr.deckConfigLearningStepsTooltip()}
defaultValue={defaults.learnSteps}
value={$config.learnSteps}
on:changed={(evt) => ($config.learnSteps = evt.detail.value)} />
<SpinBox <SpinBox
label={tr.schedulingGraduatingInterval()} label={tr.schedulingGraduatingInterval()}
tooltip={tr.deckConfigGraduatingIntervalTooltip()} tooltip={tr.deckConfigGraduatingIntervalTooltip()}
@ -58,8 +58,31 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
defaultValue={defaults.graduatingIntervalEasy} defaultValue={defaults.graduatingIntervalEasy}
bind:value={$config.graduatingIntervalEasy} /> bind:value={$config.graduatingIntervalEasy} />
<EnumSelector {#if state.v3Scheduler}
label={tr.schedulingOrder()} <EnumSelector
choices={newOrderChoices} label={tr.deckConfigNewInsertionOrder()}
defaultValue={defaults.newCardFetchOrder} tooltip={tr.deckConfigNewInsertionOrderTooltip()}
bind:value={$config.newCardFetchOrder} /> choices={newFetchOrderChoices}
defaultValue={defaults.newCardFetchOrder}
bind:value={$config.newCardFetchOrder} />
<EnumSelector
label={tr.deckConfigSortOrder()}
tooltip={tr.deckConfigSortOrderTooltip()}
choices={newSortOrderChoices}
defaultValue={defaults.newCardSortOrder}
bind:value={$config.newCardSortOrder} />
<EnumSelector
label={tr.deckConfigNewPriority()}
tooltip={tr.deckConfigNewPriorityTooltip()}
choices={reviewMixChoices()}
defaultValue={defaults.newMix}
bind:value={$config.newMix} />
{/if}
<CheckBox
label={tr.deckConfigBuryNewSiblings()}
tooltip={tr.deckConfigBuryTooltip()}
defaultValue={defaults.buryNew}
bind:value={$config.buryNew} />

View File

@ -5,7 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="ts"> <script lang="ts">
import * as tr from "lib/i18n"; import * as tr from "lib/i18n";
import SpinBox from "./SpinBox.svelte"; import SpinBox from "./SpinBox.svelte";
import StepsInput from "./StepsInput.svelte"; import CheckBox from "./CheckBox.svelte";
import EnumSelector from "./EnumSelector.svelte"; import EnumSelector from "./EnumSelector.svelte";
import type { DeckOptionsState } from "./lib"; import type { DeckOptionsState } from "./lib";
@ -13,18 +13,24 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let config = state.currentConfig; let config = state.currentConfig;
let defaults = state.defaults; let defaults = state.defaults;
const reviewOrderChoices = [
tr.deckConfigSortOrderDueDateThenRandom(),
tr.deckConfigSortOrderAscendingIntervals(),
tr.deckConfigSortOrderDescendingIntervals(),
];
const leechChoices = [tr.actionsSuspendCard(), tr.schedulingTagOnly()]; const leechChoices = [tr.actionsSuspendCard(), tr.schedulingTagOnly()];
</script> </script>
<div> <div>
<h2>{tr.schedulingLapses()}</h2> <h2>{tr.schedulingReviews()}</h2>
<StepsInput <EnumSelector
label={tr.deckConfigRelearningSteps()} label={tr.deckConfigSortOrder()}
tooltip={tr.deckConfigRelearningStepsTooltip()} tooltip={tr.deckConfigReviewSortOrderTooltip()}
defaultValue={defaults.relearnSteps} choices={reviewOrderChoices}
value={$config.relearnSteps} defaultValue={defaults.reviewOrder}
on:changed={(evt) => ($config.relearnSteps = evt.detail.value)} /> bind:value={$config.reviewOrder} />
<SpinBox <SpinBox
label={tr.schedulingLeechThreshold()} label={tr.schedulingLeechThreshold()}
@ -39,4 +45,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
choices={leechChoices} choices={leechChoices}
defaultValue={defaults.leechAction} defaultValue={defaults.leechAction}
bind:value={$config.leechAction} /> bind:value={$config.leechAction} />
<CheckBox
label={tr.deckConfigBuryReviewSiblings()}
tooltip={tr.deckConfigBuryTooltip()}
defaultValue={defaults.buryReviews}
bind:value={$config.buryReviews} />
</div> </div>

View File

@ -57,6 +57,7 @@ export class DeckOptionsState {
readonly currentDeck: pb.BackendProto.DeckConfigsForUpdate.CurrentDeck; readonly currentDeck: pb.BackendProto.DeckConfigsForUpdate.CurrentDeck;
readonly defaults: ConfigInner; readonly defaults: ConfigInner;
readonly addonComponents: Writable<DynamicSvelteComponent[]>; readonly addonComponents: Writable<DynamicSvelteComponent[]>;
readonly v3Scheduler: boolean;
private targetDeckId: number; private targetDeckId: number;
private configs: ConfigWithCount[]; private configs: ConfigWithCount[];
@ -82,6 +83,7 @@ export class DeckOptionsState {
0, 0,
this.configs.findIndex((c) => c.config.id === this.currentDeck.configId) this.configs.findIndex((c) => c.config.id === this.currentDeck.configId)
); );
this.v3Scheduler = data.v3Scheduler;
// decrement the use count of the starting item, as we'll apply +1 to currently // decrement the use count of the starting item, as we'll apply +1 to currently
// selected one at display time // selected one at display time

10
ts/deckoptions/strings.ts Normal file
View File

@ -0,0 +1,10 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import * as tr from "lib/i18n";
export const reviewMixChoices = (): string[] => [
tr.deckConfigReviewMixMixWithReviews(),
tr.deckConfigReviewMixShowAfterReviews(),
tr.deckConfigReviewMixShowBeforeReviews(),
];