feat(studyset): prepare for an exam, with plans, a date and the pace to it

A studyset plans for exams: each plan names what an exam covers, the
topics it takes whole (with their flashcards, learning paths and PDFs)
and the tags whose flashcards it takes from anywhere in the studyset.
The author's plans are published with the studyset (payload schema 7,
`examPlans`); copying a release and taking a newer one point their
topics at the copy's own studysets. Plans are also offered from level
tags: JLPT N5 to N1, HSK 1 to 7-9 and KRDict's levels, each taking the
levels below it, as the exams do.

The person chooses a plan and the exam's day (`exam`), which stays
theirs: the server leaves it out of a release, as a PDF's deadline.
The study plan then shows the days left, how many of the plan's
flashcards were started, its paths' steps done and its PDFs' pages
read, and the pace that gets everything new learnt a week before the
exam (by the exam when two weeks or fewer are left): new flashcards a
day, steps a week, pages a day. Study for the exam studies only what
the plan covers, its new cards at that pace (counted as the day began)
and every review due.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-14 14:26:08 +02:00
commit dd6c567ad0
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -6677,6 +6677,161 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get planLearningPaths => 'Lernpfade';
@override
String get examPrepare => 'Auf eine Prüfung vorbereiten';
@override
String get examPrepareHint =>
'Wähle, was sie abdeckt und wann sie ist, und bekomme ein Tempo, das dich hinbringt.';
@override
String get examChange => 'Prüfung ändern';
@override
String examDaysLeft(int count, String date) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: 'In $count Tagen, $date',
one: 'Morgen, $date',
zero: 'Heute, $date',
);
return '$_temp0';
}
@override
String examPast(String date) {
return 'Sie war am $date';
}
@override
String get examPlanGone => 'Diesen Prüfungsplan gibt es nicht mehr';
@override
String examCardsStarted(int started, int total) {
String _temp0 = intl.Intl.pluralLogic(
total,
locale: localeName,
other: '$started von $total Karteikarten begonnen',
one: '$started von 1 Karteikarte begonnen',
);
return '$_temp0';
}
@override
String examPagesRead(int read, int total) {
String _temp0 = intl.Intl.pluralLogic(
total,
locale: localeName,
other: '$read von $total Seiten gelesen',
one: '$read von 1 Seite gelesen',
);
return '$_temp0';
}
@override
String get examPaceTitle => 'Dein Tempo';
@override
String examPaceNew(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count neue Karteikarten am Tag',
one: '1 neue Karteikarte am Tag',
);
return '$_temp0';
}
@override
String examPaceSteps(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Schritte pro Woche',
one: '1 Schritt pro Woche',
);
return '$_temp0';
}
@override
String examPacePages(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Seiten am Tag',
one: '1 Seite am Tag',
);
return '$_temp0';
}
@override
String get examPaceDone =>
'Alles Neue ist gelernt: bis zur Prüfung wiederholen.';
@override
String get examStudy => 'Für die Prüfung lernen';
@override
String get examSheetHelp =>
'Wähle, was die Prüfung abdeckt und wann sie ist. Alles Neue wird dann so verteilt, dass es eine Woche vorher gelernt ist und die letzte Woche zum Wiederholen bleibt. Das Datum siehst nur du.';
@override
String get examDate => 'Prüfungsdatum';
@override
String get examSheetPlans => 'Prüfungspläne dieses Lernsets';
@override
String get examSheetFromTags => 'Aus den Stufen-Tags';
@override
String get examSheetNoPlans =>
'Noch keine Prüfungspläne. Erstelle einen aus den Themen und Tags dieses Lernsets.';
@override
String get examRemove => 'Nicht mehr vorbereiten';
@override
String examPlanTopicCount(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Themen',
one: '1 Thema',
);
return '$_temp0';
}
@override
String get examPlanNew => 'Neuer Prüfungsplan';
@override
String get examPlanEdit => 'Prüfungsplan bearbeiten';
@override
String get examPlanHelp =>
'Ein Prüfungsplan nennt, was eine Prüfung abdeckt: ganze Themen mit ihren Karteikarten, Lernpfaden und PDFs, und Karteikarten mit bestimmten Tags. Er wird mit dem Lernset veröffentlicht.';
@override
String get examPlanName => 'Name';
@override
String get examPlanNameHint => 'z. B. Abschlussprüfung';
@override
String get examPlanTopics => 'Themen, die sie ganz abdeckt';
@override
String get examPlanTags => 'Karteikarten mit diesen Tags';
@override
String get examPlanEmpty =>
'Dieses Lernset hat noch keine Themen oder Karteikarten mit Tags zur Auswahl.';
@override
String get examPlanDelete => 'Plan löschen';
@override
String get jellyfinTitle => 'Jellyfin';