feat(app): the card composer, for many cards in one sitting

Create flashcards, and tapping a card, open the composer: the stack of
cards on the left (New flashcard on top, the new ones, then the stored
ones; collapsible), the card being written on the right, saved as the
person leaves it (another card, the pane, the screen, the app). The
title says how saving stands; leaving with cards that couldn't be saved
asks first. A card has its tags and their pin, an action menu
(duplicate, clear, delete), the type switch (flashcard, vocabulary,
matching), the front, and below a line its answer side: one answer or
several to mark right or wrong, the reading and meanings, or categories
and items. Fields changed differently on two devices show every version
to keep one. The single-card editor goes.

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-01 18:42:25 +02:00
commit 0afc22d454
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -521,6 +521,246 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get cardListManageTags => 'Manage tags';
@override
String get composerTitle => 'Create flashcards';
@override
String composerTitleFor(String title) {
return 'Create flashcards for \"$title\"';
}
@override
String get composerSaving => 'Saving…';
@override
String get composerSaveFailed => 'Save failed — retry';
@override
String get composerAllSaved => 'All changes saved';
@override
String get composerNewFlashcard => 'New flashcard';
@override
String get composerCollapseStack => 'Collapse stack';
@override
String get composerExpandStack => 'Expand stack';
@override
String get composerStatusSaving => 'Saving';
@override
String get composerStatusSaved => 'Saved';
@override
String get composerStatusFailed => 'Save failed';
@override
String get composerSaveFailedInline => 'Save failed.';
@override
String get composerRetry => 'Retry';
@override
String get composerEmptyPane => 'Add a flashcard to get started.';
@override
String get composerKindFlashcard => 'Flashcard';
@override
String get composerKindVocabulary => 'Vocabulary';
@override
String get composerKindMatching => 'Matching';
@override
String get composerKindMap => 'Map';
@override
String get composerLabelFront => 'Front';
@override
String get composerLabelQuestion => 'Question';
@override
String get composerLabelExpression => 'Expression';
@override
String get composerLabelPrompt => 'Prompt';
@override
String get composerLabelBack => 'Back';
@override
String get composerLabelAnswers => 'Answers';
@override
String get composerLabelAnswer => 'Answer';
@override
String get composerPlaceholderFront => 'Add question';
@override
String get composerPlaceholderExpression => 'Add expression';
@override
String get composerPlaceholderPrompt => 'Add prompt';
@override
String get composerAddAnswer => 'Add answer';
@override
String get composerCorrectAnswer => 'Correct answer';
@override
String get composerWrongAnswer => 'Wrong answer';
@override
String get composerRemoveAnswer => 'Remove answer';
@override
String composerPin(String field) {
return 'Pin $field: keep it for the next card';
}
@override
String composerUnpin(String field) {
return 'Unpin $field: clear it for the next card';
}
@override
String get composerTags => 'Tags';
@override
String get composerAddTags => 'Add tags';
@override
String get composerMoreActions => 'More actions';
@override
String get composerDuplicate => 'Duplicate';
@override
String get composerClearFields => 'Clear fields';
@override
String get composerDelete => 'Delete';
@override
String get composerDeleteTitle => 'Delete this flashcard?';
@override
String get composerDeleteDraftMessage =>
'The draft will be removed from this session. It has not been saved.';
@override
String get composerDeleteSavedMessage =>
'The flashcard will be removed from the studyset, on all your devices.';
@override
String composerDiscardTitle(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: 'Discard unsaved flashcards?',
one: 'Discard unsaved flashcard?',
);
return '$_temp0';
}
@override
String composerDiscardMessage(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other:
'$count flashcards haven\'t been saved yet. Leaving now will discard them.',
one: '1 flashcard hasn\'t been saved yet. Leaving now will discard it.',
);
return '$_temp0';
}
@override
String get composerDiscardConfirm => 'Discard';
@override
String get composerConflict =>
'This flashcard was changed differently on two devices. Choose the version to keep of each part below.';
@override
String get composerKeepThis => 'Keep this';
@override
String get vocabularyReading => 'Reading';
@override
String get vocabularyReadingHint => 'Kana reading';
@override
String get vocabularyMeanings => 'Meanings';
@override
String get vocabularyPrimaryMeaningHint => 'Primary meaning';
@override
String get vocabularyMeaningHint => 'Meaning';
@override
String get vocabularyAddMeaning => 'Add meaning';
@override
String get vocabularyRemoveMeaning => 'Remove meaning';
@override
String get matchingCategories => 'Categories';
@override
String get matchingCategoriesHint =>
'The drop-zone cards learners drag items onto. Each category needs at least one item, so a card can\'t have more categories than items.';
@override
String matchingCategory(int number) {
return 'Category $number';
}
@override
String get matchingAddCategory => 'Add category';
@override
String get matchingAddCategoryBlocked =>
'Add an item first: a card can\'t have more categories than items';
@override
String get matchingRemoveCategory => 'Remove category';
@override
String get matchingMinCategories => 'At least two categories required';
@override
String get matchingItems => 'Items';
@override
String get matchingItemsHint =>
'The draggable items. Assign every item to its correct category: an unassigned item can never be placed right.';
@override
String matchingItem(int number) {
return 'Item $number';
}
@override
String get matchingAddItem => 'Add item';
@override
String get matchingUnassigned => 'Unassigned';
@override
String get matchingRemoveItem => 'Remove item';
@override
String get matchingMinItems => 'At least two items required';
@override
String get commonCancel => 'Cancel';