feat(app): a card browser to search, filter, sort and change many cards at once

Browse beside the flashcards' tab opens the studyset's cards over the
tabs (with everything inside it when it has sub-studysets), laid out as
the older design had it:
- a grid of tiles (each card's two sides) or one card at a time beside
  the list (on a phone above a strip of them, swiped through), as last
  left for the studyset on this device;
- a search over front, back, reading, meanings, hints, explanation and
  tag names, katakana found as hiragana and kana by romaji;
- sorting by own order, newest, oldest, A–Z (words by reading), due
  first; a filter sheet by kind, tag and state (new, learning, due,
  buried, reported);
- choosing cards (a toggle; shift-click or long-press for a range,
  select all) to move into another or a new studyset, add or remove
  tags, start afresh, or delete with Undo; the actions in the row on
  wide windows, in a bar at the foot below.

Moving cards between studysets is new in the card repository and its
gateway (studysetId and position written, named columns).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-09 14:21:01 +02:00
commit 42c57bd40a
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -7070,6 +7070,474 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Don\'t suggest again'**
String get pomodoroTopBarDismiss;
/// No description provided for @cardBrowserTitle.
///
/// In en, this message translates to:
/// **'Flashcards'**
String get cardBrowserTitle;
/// No description provided for @cardBrowserTitleWithName.
///
/// In en, this message translates to:
/// **'{title} — flashcards'**
String cardBrowserTitleWithName(String title);
/// No description provided for @cardBrowserTitleSubtree.
///
/// In en, this message translates to:
/// **'{title} (incl. sub-studysets)'**
String cardBrowserTitleSubtree(String title);
/// No description provided for @cardBrowserBrowse.
///
/// In en, this message translates to:
/// **'Browse'**
String get cardBrowserBrowse;
/// No description provided for @cardBrowserBrowseTooltip.
///
/// In en, this message translates to:
/// **'Browse flashcards'**
String get cardBrowserBrowseTooltip;
/// No description provided for @cardBrowserStudy.
///
/// In en, this message translates to:
/// **'Study'**
String get cardBrowserStudy;
/// No description provided for @cardBrowserEditor.
///
/// In en, this message translates to:
/// **'Editor'**
String get cardBrowserEditor;
/// No description provided for @cardBrowserMore.
///
/// In en, this message translates to:
/// **'More'**
String get cardBrowserMore;
/// No description provided for @cardBrowserImport.
///
/// In en, this message translates to:
/// **'Import flashcards'**
String get cardBrowserImport;
/// No description provided for @cardBrowserGrid.
///
/// In en, this message translates to:
/// **'Grid'**
String get cardBrowserGrid;
/// No description provided for @cardBrowserDetail.
///
/// In en, this message translates to:
/// **'Detail'**
String get cardBrowserDetail;
/// No description provided for @cardBrowserSearch.
///
/// In en, this message translates to:
/// **'Search'**
String get cardBrowserSearch;
/// No description provided for @cardBrowserSort.
///
/// In en, this message translates to:
/// **'Sort'**
String get cardBrowserSort;
/// No description provided for @cardBrowserFilter.
///
/// In en, this message translates to:
/// **'Filter'**
String get cardBrowserFilter;
/// No description provided for @cardBrowserSelect.
///
/// In en, this message translates to:
/// **'Select'**
String get cardBrowserSelect;
/// No description provided for @cardBrowserSortManual.
///
/// In en, this message translates to:
/// **'Manual order'**
String get cardBrowserSortManual;
/// No description provided for @cardBrowserSortNewest.
///
/// In en, this message translates to:
/// **'Newest first'**
String get cardBrowserSortNewest;
/// No description provided for @cardBrowserSortOldest.
///
/// In en, this message translates to:
/// **'Oldest first'**
String get cardBrowserSortOldest;
/// No description provided for @cardBrowserSortAlphabetical.
///
/// In en, this message translates to:
/// **'A–Z (front)'**
String get cardBrowserSortAlphabetical;
/// No description provided for @cardBrowserSortDue.
///
/// In en, this message translates to:
/// **'Due first'**
String get cardBrowserSortDue;
/// No description provided for @cardBrowserSearchHint.
///
/// In en, this message translates to:
/// **'Search flashcards'**
String get cardBrowserSearchHint;
/// No description provided for @cardBrowserCloseSearch.
///
/// In en, this message translates to:
/// **'Close search'**
String get cardBrowserCloseSearch;
/// No description provided for @cardBrowserClearQuery.
///
/// In en, this message translates to:
/// **'Clear query'**
String get cardBrowserClearQuery;
/// No description provided for @cardBrowserFilterTitle.
///
/// In en, this message translates to:
/// **'Filter flashcards'**
String get cardBrowserFilterTitle;
/// No description provided for @cardBrowserFilterType.
///
/// In en, this message translates to:
/// **'Type'**
String get cardBrowserFilterType;
/// No description provided for @cardBrowserTypeAll.
///
/// In en, this message translates to:
/// **'All cards'**
String get cardBrowserTypeAll;
/// No description provided for @cardBrowserTypeFrontBack.
///
/// In en, this message translates to:
/// **'Q&A only'**
String get cardBrowserTypeFrontBack;
/// No description provided for @cardBrowserTypeMultipleChoice.
///
/// In en, this message translates to:
/// **'Multiple-choice only'**
String get cardBrowserTypeMultipleChoice;
/// No description provided for @cardBrowserTypeVocabulary.
///
/// In en, this message translates to:
/// **'Words only'**
String get cardBrowserTypeVocabulary;
/// No description provided for @cardBrowserTypeMatching.
///
/// In en, this message translates to:
/// **'Matching only'**
String get cardBrowserTypeMatching;
/// No description provided for @cardBrowserTypeMap.
///
/// In en, this message translates to:
/// **'Maps only'**
String get cardBrowserTypeMap;
/// No description provided for @cardBrowserFilterTag.
///
/// In en, this message translates to:
/// **'Tag'**
String get cardBrowserFilterTag;
/// No description provided for @cardBrowserAllTags.
///
/// In en, this message translates to:
/// **'All tags'**
String get cardBrowserAllTags;
/// No description provided for @cardBrowserFilterStatus.
///
/// In en, this message translates to:
/// **'Status'**
String get cardBrowserFilterStatus;
/// No description provided for @cardBrowserStatusNew.
///
/// In en, this message translates to:
/// **'New'**
String get cardBrowserStatusNew;
/// No description provided for @cardBrowserStatusLearning.
///
/// In en, this message translates to:
/// **'Learning'**
String get cardBrowserStatusLearning;
/// No description provided for @cardBrowserStatusDue.
///
/// In en, this message translates to:
/// **'Due'**
String get cardBrowserStatusDue;
/// No description provided for @cardBrowserStatusBuried.
///
/// In en, this message translates to:
/// **'Buried'**
String get cardBrowserStatusBuried;
/// No description provided for @cardBrowserStatusReported.
///
/// In en, this message translates to:
/// **'Reported'**
String get cardBrowserStatusReported;
/// No description provided for @cardBrowserClearAll.
///
/// In en, this message translates to:
/// **'Clear all'**
String get cardBrowserClearAll;
/// No description provided for @cardBrowserApply.
///
/// In en, this message translates to:
/// **'Apply'**
String get cardBrowserApply;
/// No description provided for @cardBrowserEmptyTitle.
///
/// In en, this message translates to:
/// **'No flashcards yet'**
String get cardBrowserEmptyTitle;
/// No description provided for @cardBrowserEmptyHint.
///
/// In en, this message translates to:
/// **'Create some to browse them here.'**
String get cardBrowserEmptyHint;
/// No description provided for @cardBrowserCreate.
///
/// In en, this message translates to:
/// **'Create flashcards'**
String get cardBrowserCreate;
/// No description provided for @cardBrowserNoMatches.
///
/// In en, this message translates to:
/// **'No flashcards match'**
String get cardBrowserNoMatches;
/// No description provided for @cardBrowserNoMatchesHint.
///
/// In en, this message translates to:
/// **'Try a different search or filter.'**
String get cardBrowserNoMatchesHint;
/// No description provided for @cardBrowserClearFilters.
///
/// In en, this message translates to:
/// **'Clear search & filters'**
String get cardBrowserClearFilters;
/// No description provided for @cardBrowserRetry.
///
/// In en, this message translates to:
/// **'Retry'**
String get cardBrowserRetry;
/// No description provided for @cardBrowserPrevious.
///
/// In en, this message translates to:
/// **'Previous'**
String get cardBrowserPrevious;
/// No description provided for @cardBrowserNext.
///
/// In en, this message translates to:
/// **'Next'**
String get cardBrowserNext;
/// No description provided for @cardBrowserBuried.
///
/// In en, this message translates to:
/// **'Buried'**
String get cardBrowserBuried;
/// No description provided for @cardBrowserSelectAll.
///
/// In en, this message translates to:
/// **'Select all'**
String get cardBrowserSelectAll;
/// No description provided for @cardBrowserDeselectAll.
///
/// In en, this message translates to:
/// **'Deselect all'**
String get cardBrowserDeselectAll;
/// No description provided for @cardBrowserSelected.
///
/// In en, this message translates to:
/// **'{count} selected'**
String cardBrowserSelected(int count);
/// No description provided for @cardBrowserRangeHintTouch.
///
/// In en, this message translates to:
/// **'Long-press another card to select everything in between.'**
String get cardBrowserRangeHintTouch;
/// No description provided for @cardBrowserRangeHintPointer.
///
/// In en, this message translates to:
/// **'Shift-click another card to select everything in between.'**
String get cardBrowserRangeHintPointer;
/// No description provided for @cardBrowserMove.
///
/// In en, this message translates to:
/// **'Move'**
String get cardBrowserMove;
/// No description provided for @cardBrowserAddTags.
///
/// In en, this message translates to:
/// **'Add tags'**
String get cardBrowserAddTags;
/// No description provided for @cardBrowserRemoveTags.
///
/// In en, this message translates to:
/// **'Remove tags'**
String get cardBrowserRemoveTags;
/// No description provided for @cardBrowserResetProgress.
///
/// In en, this message translates to:
/// **'Reset progress'**
String get cardBrowserResetProgress;
/// No description provided for @cardBrowserDelete.
///
/// In en, this message translates to:
/// **'Delete'**
String get cardBrowserDelete;
/// No description provided for @cardBrowserMoreActions.
///
/// In en, this message translates to:
/// **'More actions'**
String get cardBrowserMoreActions;
/// No description provided for @cardBrowserDone.
///
/// In en, this message translates to:
/// **'Done'**
String get cardBrowserDone;
/// No description provided for @cardBrowserDeleted.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 flashcard deleted} other{{count} flashcards deleted}}'**
String cardBrowserDeleted(int count);
/// No description provided for @cardBrowserMoveTitle.
///
/// In en, this message translates to:
/// **'{count, plural, =1{Move 1 flashcard to} other{Move {count} flashcards to}}'**
String cardBrowserMoveTitle(int count);
/// No description provided for @cardBrowserMoved.
///
/// In en, this message translates to:
/// **'{count, plural, =1{Moved 1 flashcard to “{title}”} other{Moved {count} flashcards to “{title}”}}'**
String cardBrowserMoved(int count, String title);
/// No description provided for @cardBrowserAddTagsTitle.
///
/// In en, this message translates to:
/// **'{count, plural, =1{Add tags to 1 flashcard} other{Add tags to {count} flashcards}}'**
String cardBrowserAddTagsTitle(int count);
/// No description provided for @cardBrowserAddTo.
///
/// In en, this message translates to:
/// **'{count, plural, =1{Add to 1 flashcard} other{Add to {count} flashcards}}'**
String cardBrowserAddTo(int count);
/// No description provided for @cardBrowserRemoveTagsTitle.
///
/// In en, this message translates to:
/// **'{count, plural, =1{Remove tags from 1 flashcard} other{Remove tags from {count} flashcards}}'**
String cardBrowserRemoveTagsTitle(int count);
/// No description provided for @cardBrowserRemoveFrom.
///
/// In en, this message translates to:
/// **'{count, plural, =1{Remove from 1 flashcard} other{Remove from {count} flashcards}}'**
String cardBrowserRemoveFrom(int count);
/// No description provided for @cardBrowserNoTags.
///
/// In en, this message translates to:
/// **'No tags yet. Create tags from a flashcard\'s editor, then apply them here.'**
String get cardBrowserNoTags;
/// No description provided for @cardBrowserNoTagsOnCards.
///
/// In en, this message translates to:
/// **'The flashcards chosen have no tags.'**
String get cardBrowserNoTagsOnCards;
/// No description provided for @cardBrowserTagsAdded.
///
/// In en, this message translates to:
/// **'{tags, plural, =1{Added 1 tag to {count, plural, =1{1 flashcard} other{{count} flashcards}}} other{Added {tags} tags to {count, plural, =1{1 flashcard} other{{count} flashcards}}}}'**
String cardBrowserTagsAdded(int tags, int count);
/// No description provided for @cardBrowserTagsRemoved.
///
/// In en, this message translates to:
/// **'{tags, plural, =1{Removed 1 tag from {count, plural, =1{1 flashcard} other{{count} flashcards}}} other{Removed {tags} tags from {count, plural, =1{1 flashcard} other{{count} flashcards}}}}'**
String cardBrowserTagsRemoved(int tags, int count);
/// No description provided for @cardBrowserResetTitle.
///
/// In en, this message translates to:
/// **'{count, plural, =1{Start 1 flashcard afresh?} other{Start {count} flashcards afresh?}}'**
String cardBrowserResetTitle(int count);
/// No description provided for @cardBrowserResetMessage.
///
/// In en, this message translates to:
/// **'They count as new again. Their reviews stay in your history and streaks.'**
String get cardBrowserResetMessage;
/// No description provided for @cardBrowserResetConfirm.
///
/// In en, this message translates to:
/// **'Reset'**
String get cardBrowserResetConfirm;
/// No description provided for @cardBrowserReset.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 flashcard starts afresh} other{{count} flashcards start afresh}}'**
String cardBrowserReset(int count);
}
class _AppLocalizationsDelegate