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

@ -6617,6 +6617,160 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get planLearningPaths => 'Learning paths';
@override
String get examPrepare => 'Prepare for an exam';
@override
String get examPrepareHint =>
'Choose what it covers and its date, and get a pace that gets you there.';
@override
String get examChange => 'Change the exam';
@override
String examDaysLeft(int count, String date) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: 'In $count days, $date',
one: 'Tomorrow, $date',
zero: 'Today, $date',
);
return '$_temp0';
}
@override
String examPast(String date) {
return 'It was on $date';
}
@override
String get examPlanGone => 'This exam plan is gone';
@override
String examCardsStarted(int started, int total) {
String _temp0 = intl.Intl.pluralLogic(
total,
locale: localeName,
other: '$started of $total flashcards started',
one: '$started of 1 flashcard started',
);
return '$_temp0';
}
@override
String examPagesRead(int read, int total) {
String _temp0 = intl.Intl.pluralLogic(
total,
locale: localeName,
other: '$read of $total pages read',
one: '$read of 1 page read',
);
return '$_temp0';
}
@override
String get examPaceTitle => 'Your pace';
@override
String examPaceNew(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count new flashcards a day',
one: '1 new flashcard a day',
);
return '$_temp0';
}
@override
String examPaceSteps(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count steps a week',
one: '1 step a week',
);
return '$_temp0';
}
@override
String examPacePages(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count pages a day',
one: '1 page a day',
);
return '$_temp0';
}
@override
String get examPaceDone => 'Everything new is learnt: review until the exam.';
@override
String get examStudy => 'Study for the exam';
@override
String get examSheetHelp =>
'Choose what the exam covers and when it is. Everything new is then spread so that it is learnt a week before, leaving the last week for reviews. Only you see the date.';
@override
String get examDate => 'Exam date';
@override
String get examSheetPlans => 'This studyset’s exam plans';
@override
String get examSheetFromTags => 'From the level tags';
@override
String get examSheetNoPlans =>
'No exam plans yet. Make one from this studyset’s topics and tags.';
@override
String get examRemove => 'Stop preparing';
@override
String examPlanTopicCount(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count topics',
one: '1 topic',
);
return '$_temp0';
}
@override
String get examPlanNew => 'New exam plan';
@override
String get examPlanEdit => 'Edit exam plan';
@override
String get examPlanHelp =>
'An exam plan names what an exam covers: whole topics, with their flashcards, learning paths and PDFs, and flashcards with certain tags. It is published with the studyset.';
@override
String get examPlanName => 'Name';
@override
String get examPlanNameHint => 'e.g. Final exam';
@override
String get examPlanTopics => 'Topics it covers whole';
@override
String get examPlanTags => 'Flashcards with these tags';
@override
String get examPlanEmpty =>
'This studyset has no topics or tagged flashcards to choose from yet.';
@override
String get examPlanDelete => 'Delete plan';
@override
String get jellyfinTitle => 'Jellyfin';