feat(app): learning paths in the studyset screen: worked through and written
- A Paths tab before Flashcards and Notes: each path with its title and secondary title, dimmed once completed; Edit, Reset progress (with an undo) and Delete (with an undo) behind its options. The studyset opens on its paths while one is unfinished, on its flashcards otherwise. - "Create a path" in Add material asks for the titles in a sheet and opens the new path to write; "Import a path (JSON)" reads a file in the import format, says what came in and how many blocks were left out (images and animations: the app never fetches from the web). - The player: one step at a time at reading width, a bar of the steps above, Back and "Check answers" / "Continue" / "Finish" below. It opens at the first unfinished step; an exercise passes only once answered right, as often as it takes; after a check, only the learner's own picks are marked, with the author's feedback; sources behind a chip; a finish screen leading to the next path. Words and items are dragged into place, or tapped into place for phones. - Writing: the path's screen (titles, description, tags, steps added by kind, reordered, deleted with an undo) and the step's (title, text with the format bar, its kind's exercise, feedback for right and wrong in the whole window, sources). The step saves on what it started from, as notes do, read-only while devices disagree until a version is kept. - The library and the topics count paths; steps done count on the dashboard, for the streak and the activity. - The rich-text screen for a studyset's description moves to core, for the steps' feedback too, and gains the format bar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
91f6376b93
commit
e4bfe3bdeb
1 changed files with 6310 additions and 65 deletions
|
|
@ -406,6 +406,618 @@ abstract class AppLocalizations {
|
|||
/// **'Notes'**
|
||||
String get studysetTabNotes;
|
||||
|
||||
/// No description provided for @studysetTabPaths.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Paths'**
|
||||
String get studysetTabPaths;
|
||||
|
||||
/// No description provided for @studysetCreatePath.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Create a path'**
|
||||
String get studysetCreatePath;
|
||||
|
||||
/// No description provided for @pathImportMenu.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Import a path (JSON)'**
|
||||
String get pathImportMenu;
|
||||
|
||||
/// No description provided for @pathImportFileType.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Learning path (JSON)'**
|
||||
String get pathImportFileType;
|
||||
|
||||
/// No description provided for @pathImported.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =1{Imported \"{title}\" with 1 step.} other{Imported \"{title}\" with {count} steps.}}'**
|
||||
String pathImported(String title, int count);
|
||||
|
||||
/// No description provided for @pathImportSkipped.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =1{1 block was left out: images and animations aren\'t imported.} other{{count} blocks were left out: images and animations aren\'t imported.}}'**
|
||||
String pathImportSkipped(int count);
|
||||
|
||||
/// No description provided for @pathImportFailed.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Couldn\'t import this file. {reason}'**
|
||||
String pathImportFailed(String reason);
|
||||
|
||||
/// No description provided for @pathImportUnreadable.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'It isn\'t text in UTF-8.'**
|
||||
String get pathImportUnreadable;
|
||||
|
||||
/// No description provided for @pathsEmpty.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No paths yet'**
|
||||
String get pathsEmpty;
|
||||
|
||||
/// No description provided for @pathsEmptyHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'A path leads through a lesson, step by step.'**
|
||||
String get pathsEmptyHint;
|
||||
|
||||
/// No description provided for @pathOptions.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Path options'**
|
||||
String get pathOptions;
|
||||
|
||||
/// No description provided for @pathEdit.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Edit'**
|
||||
String get pathEdit;
|
||||
|
||||
/// No description provided for @pathResetProgress.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Reset progress'**
|
||||
String get pathResetProgress;
|
||||
|
||||
/// No description provided for @pathProgressReset.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Progress reset'**
|
||||
String get pathProgressReset;
|
||||
|
||||
/// No description provided for @pathDelete.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Delete'**
|
||||
String get pathDelete;
|
||||
|
||||
/// No description provided for @pathDeleteTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Delete path?'**
|
||||
String get pathDeleteTitle;
|
||||
|
||||
/// No description provided for @pathDeleteMessage.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'This path and its steps will be removed from the studyset. You can undo this for a few seconds.'**
|
||||
String get pathDeleteMessage;
|
||||
|
||||
/// No description provided for @pathDeleteConfirm.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Delete'**
|
||||
String get pathDeleteConfirm;
|
||||
|
||||
/// No description provided for @pathDeleted.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Path deleted'**
|
||||
String get pathDeleted;
|
||||
|
||||
/// No description provided for @pathCreateTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'New path'**
|
||||
String get pathCreateTitle;
|
||||
|
||||
/// No description provided for @pathCreate.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Create'**
|
||||
String get pathCreate;
|
||||
|
||||
/// No description provided for @pathTitleLabel.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Title'**
|
||||
String get pathTitleLabel;
|
||||
|
||||
/// No description provided for @pathTitleRequired.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'A path needs a title.'**
|
||||
String get pathTitleRequired;
|
||||
|
||||
/// No description provided for @pathSecondaryTitleLabel.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Secondary title'**
|
||||
String get pathSecondaryTitleLabel;
|
||||
|
||||
/// No description provided for @pathSecondaryTitleHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'E.g. the title in the language you learn'**
|
||||
String get pathSecondaryTitleHint;
|
||||
|
||||
/// No description provided for @pathEditTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Edit path'**
|
||||
String get pathEditTitle;
|
||||
|
||||
/// No description provided for @pathDescription.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Description'**
|
||||
String get pathDescription;
|
||||
|
||||
/// No description provided for @pathAddDescription.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add a description'**
|
||||
String get pathAddDescription;
|
||||
|
||||
/// No description provided for @pathDescriptionEditTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Path description'**
|
||||
String get pathDescriptionEditTitle;
|
||||
|
||||
/// No description provided for @pathAddTags.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add tags'**
|
||||
String get pathAddTags;
|
||||
|
||||
/// No description provided for @pathTags.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Tags'**
|
||||
String get pathTags;
|
||||
|
||||
/// No description provided for @pathSteps.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Steps'**
|
||||
String get pathSteps;
|
||||
|
||||
/// No description provided for @pathStepsEmpty.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No steps yet'**
|
||||
String get pathStepsEmpty;
|
||||
|
||||
/// No description provided for @pathStepsEmptyHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Pick a step type to start writing the lesson.'**
|
||||
String get pathStepsEmptyHint;
|
||||
|
||||
/// No description provided for @pathAddStep.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add step'**
|
||||
String get pathAddStep;
|
||||
|
||||
/// No description provided for @pathReorder.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Reorder'**
|
||||
String get pathReorder;
|
||||
|
||||
/// No description provided for @pathReorderDone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Done'**
|
||||
String get pathReorderDone;
|
||||
|
||||
/// No description provided for @pathStepDelete.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Delete step'**
|
||||
String get pathStepDelete;
|
||||
|
||||
/// No description provided for @pathStepDeleted.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Step deleted'**
|
||||
String get pathStepDeleted;
|
||||
|
||||
/// No description provided for @stepUntitled.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Untitled step'**
|
||||
String get stepUntitled;
|
||||
|
||||
/// No description provided for @stepKindInfo.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Info'**
|
||||
String get stepKindInfo;
|
||||
|
||||
/// No description provided for @stepKindSingleChoice.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Single choice'**
|
||||
String get stepKindSingleChoice;
|
||||
|
||||
/// No description provided for @stepKindMultipleChoice.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Multiple choice'**
|
||||
String get stepKindMultipleChoice;
|
||||
|
||||
/// No description provided for @stepKindDragAndDrop.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Drag and drop'**
|
||||
String get stepKindDragAndDrop;
|
||||
|
||||
/// No description provided for @stepKindFillInTheBlank.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Fill in the blank'**
|
||||
String get stepKindFillInTheBlank;
|
||||
|
||||
/// No description provided for @stepEditTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Edit step'**
|
||||
String get stepEditTitle;
|
||||
|
||||
/// No description provided for @stepTitleHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Title'**
|
||||
String get stepTitleHint;
|
||||
|
||||
/// No description provided for @stepOptions.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Options'**
|
||||
String get stepOptions;
|
||||
|
||||
/// No description provided for @stepOptionHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Option {number}'**
|
||||
String stepOptionHint(int number);
|
||||
|
||||
/// No description provided for @stepAddOption.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add option'**
|
||||
String get stepAddOption;
|
||||
|
||||
/// No description provided for @stepRemoveOption.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Remove option'**
|
||||
String get stepRemoveOption;
|
||||
|
||||
/// No description provided for @stepCorrectOption.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The right one'**
|
||||
String get stepCorrectOption;
|
||||
|
||||
/// No description provided for @stepCorrectOptions.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Right ones'**
|
||||
String get stepCorrectOptions;
|
||||
|
||||
/// No description provided for @stepCategories.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Categories'**
|
||||
String get stepCategories;
|
||||
|
||||
/// No description provided for @stepCategoryHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Category {number}'**
|
||||
String stepCategoryHint(int number);
|
||||
|
||||
/// No description provided for @stepAddCategory.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add category'**
|
||||
String get stepAddCategory;
|
||||
|
||||
/// No description provided for @stepRemoveCategory.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Remove category'**
|
||||
String get stepRemoveCategory;
|
||||
|
||||
/// No description provided for @stepItems.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Items'**
|
||||
String get stepItems;
|
||||
|
||||
/// No description provided for @stepItemHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Item {number}'**
|
||||
String stepItemHint(int number);
|
||||
|
||||
/// No description provided for @stepAddItem.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add item'**
|
||||
String get stepAddItem;
|
||||
|
||||
/// No description provided for @stepRemoveItem.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Remove item'**
|
||||
String get stepRemoveItem;
|
||||
|
||||
/// No description provided for @stepItemCategory.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Belongs to'**
|
||||
String get stepItemCategory;
|
||||
|
||||
/// No description provided for @stepPassage.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Passage'**
|
||||
String get stepPassage;
|
||||
|
||||
/// No description provided for @stepPassageHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Type ___ (three underscores) wherever a word should be dropped in.'**
|
||||
String get stepPassageHint;
|
||||
|
||||
/// No description provided for @stepBlankHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Word for gap {number}'**
|
||||
String stepBlankHint(int number);
|
||||
|
||||
/// No description provided for @stepIncomplete.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Not ready to answer yet: fill in every field and choose what is right.'**
|
||||
String get stepIncomplete;
|
||||
|
||||
/// No description provided for @stepFeedbackRight.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Feedback after a right answer'**
|
||||
String get stepFeedbackRight;
|
||||
|
||||
/// No description provided for @stepFeedbackWrong.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Feedback after a wrong answer'**
|
||||
String get stepFeedbackWrong;
|
||||
|
||||
/// No description provided for @stepFeedbackNone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'None'**
|
||||
String get stepFeedbackNone;
|
||||
|
||||
/// No description provided for @stepSources.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sources'**
|
||||
String get stepSources;
|
||||
|
||||
/// No description provided for @stepAddSource.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add source'**
|
||||
String get stepAddSource;
|
||||
|
||||
/// No description provided for @stepRemoveSource.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Remove source'**
|
||||
String get stepRemoveSource;
|
||||
|
||||
/// No description provided for @stepSourceAuthors.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Authors'**
|
||||
String get stepSourceAuthors;
|
||||
|
||||
/// No description provided for @stepSourceYear.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Year'**
|
||||
String get stepSourceYear;
|
||||
|
||||
/// No description provided for @stepSourceTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Title'**
|
||||
String get stepSourceTitle;
|
||||
|
||||
/// No description provided for @stepSourceUrl.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Link'**
|
||||
String get stepSourceUrl;
|
||||
|
||||
/// No description provided for @stepSourcesCount.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =1{1 source} other{{count} sources}}'**
|
||||
String stepSourcesCount(int count);
|
||||
|
||||
/// No description provided for @stepConflict.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'This step was changed differently on another device. Keep one version to go on writing.'**
|
||||
String get stepConflict;
|
||||
|
||||
/// No description provided for @stepFieldTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Title'**
|
||||
String get stepFieldTitle;
|
||||
|
||||
/// No description provided for @stepFieldBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Text'**
|
||||
String get stepFieldBody;
|
||||
|
||||
/// No description provided for @stepFieldExercise.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Exercise'**
|
||||
String get stepFieldExercise;
|
||||
|
||||
/// No description provided for @stepFieldRightFeedback.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Feedback after a right answer'**
|
||||
String get stepFieldRightFeedback;
|
||||
|
||||
/// No description provided for @stepFieldWrongFeedback.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Feedback after a wrong answer'**
|
||||
String get stepFieldWrongFeedback;
|
||||
|
||||
/// No description provided for @stepFieldSources.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sources'**
|
||||
String get stepFieldSources;
|
||||
|
||||
/// No description provided for @runnerClose.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Close'**
|
||||
String get runnerClose;
|
||||
|
||||
/// No description provided for @runnerEditStep.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Edit step'**
|
||||
String get runnerEditStep;
|
||||
|
||||
/// No description provided for @runnerBack.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Back'**
|
||||
String get runnerBack;
|
||||
|
||||
/// No description provided for @runnerCheck.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Check answers'**
|
||||
String get runnerCheck;
|
||||
|
||||
/// No description provided for @runnerContinue.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Continue'**
|
||||
String get runnerContinue;
|
||||
|
||||
/// No description provided for @runnerFinish.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Finish'**
|
||||
String get runnerFinish;
|
||||
|
||||
/// No description provided for @runnerRight.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Correct!'**
|
||||
String get runnerRight;
|
||||
|
||||
/// No description provided for @runnerWrong.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Not quite'**
|
||||
String get runnerWrong;
|
||||
|
||||
/// No description provided for @runnerAlreadyRight.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'You already answered this correctly.'**
|
||||
String get runnerAlreadyRight;
|
||||
|
||||
/// No description provided for @runnerSelectAll.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Select all that apply.'**
|
||||
String get runnerSelectAll;
|
||||
|
||||
/// No description provided for @runnerDragHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Drag each item into the category it belongs to, or tap it and then the category. Tap a placed item to take it back.'**
|
||||
String get runnerDragHint;
|
||||
|
||||
/// No description provided for @runnerBlankHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Drag a word into each gap, or tap it and then the gap. Tap a placed word to take it back.'**
|
||||
String get runnerBlankHint;
|
||||
|
||||
/// No description provided for @runnerEmpty.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'This path has no steps yet.'**
|
||||
String get runnerEmpty;
|
||||
|
||||
/// No description provided for @runnerFinished.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'You finished this path'**
|
||||
String get runnerFinished;
|
||||
|
||||
/// No description provided for @runnerFinishedSteps.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =1{1 step complete.} other{{count} steps complete.}}'**
|
||||
String runnerFinishedSteps(int count);
|
||||
|
||||
/// No description provided for @runnerNextPath.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Continue to next path'**
|
||||
String get runnerNextPath;
|
||||
|
||||
/// No description provided for @runnerBackToStudyset.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Back to studyset'**
|
||||
String get runnerBackToStudyset;
|
||||
|
||||
/// No description provided for @studysetCountPaths.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =1{1 path} other{{count} paths}}'**
|
||||
String studysetCountPaths(int count);
|
||||
|
||||
/// No description provided for @studysetCreateNote.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
@ -730,11 +1342,11 @@ abstract class AppLocalizations {
|
|||
/// **'Edit description'**
|
||||
String get studysetDescriptionEditTitle;
|
||||
|
||||
/// No description provided for @studysetDescriptionSave.
|
||||
/// No description provided for @richTextSave.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Save'**
|
||||
String get studysetDescriptionSave;
|
||||
String get richTextSave;
|
||||
|
||||
/// No description provided for @studysetSheetDescription.
|
||||
///
|
||||
|
|
|
|||
Loading…
Reference in a new issue