feat(app): the UI foundation: theme, tabs and routes, strings
The app gets its look and navigation before more features land on them.
- Theme (core/theme/): hand-written light and dark Material 3 colour schemes around
cobalt and copper; ThemeExtras for the colours Material has no role for (states, the
four FSRS ratings); the 20 colours a person can give content. Tests hold text to WCAG
AA contrast on each palette colour and on the dark theme's primary colour and surface.
- Layout and shared widgets: Material 3's window-size classes (core/layout/);
SectionCard, AppLoadingIndicator, confirmDestructiveAction and FoundById
(core/widget/). Lucide icons.
- Navigation with go_router: four tabs (Home, Library, Explore, Profile), each keeping
its own stack of screens, as a navigation rail with the app's icon from 600 dp and as
a navigation bar below; choosing the open tab again returns to its first screen. A
studyset's screen sits in the library; studying, cards and settings cover the tabs.
- Routes carry ids: FoundById finds the item in the repository's live list, so a
studyset deleted on another device, or an old link, says it no longer exists. A
screen that deletes its own item keeps showing it while it closes, rather than
flashing that message.
- Every person gets an app of their own (PersonApp, lib/src/app/): a
MaterialApp.router with its own GoRouter and PersonScope around the navigator, built
by SessionGate inside the person's keyed subtree. Screens read the person's
repositories wherever they are built, so the static route() helpers and the listener
that closed every pushed screen on a change of person are gone: a change of person
now disposes the whole router and starts again at home.
- The account dialog becomes the Profile tab, with Settings (sign out, delete the
account, About) behind a gear. A waiting GitHub sign-in now keeps waiting while
another tab shows; a change of person still cancels it.
- The new screens' strings come from Flutter's gen-l10n (English for now). The
generated files are committed, left out of analysis and formatting, and written
anew by `flutter pub get`, so CI's check of generated code also catches stale ones.
Widget tests now start the whole app (test/support/pump_app.dart) at the screen's path
and move through it as a person would, by tabs and taps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 00:18:31 +02:00
{
"@@locale": "en",
"appTitle": "Halkyon Learn",
"@appTitle": {"description": "The app's name, e.g. in the window title and the rail's logo."},
"shellTabHome": "Home",
"shellTabLibrary": "Library",
"shellTabExplore": "Explore",
"shellTabProfile": "Profile",
"homeTitle": "Home",
"libraryTitle": "Library",
feat(app): the library: a grid of studyset cards, search and archive
The library tab becomes a grid of studyset cards (up to 400 dp wide, all
equally tall), starred ones first, and the archive as a section of its own
below, closed until opened and counting what rests there. It lists the top
level: studysets without a parent, those whose parent is gone, and those in
a cycle (ADR 0004). Each card's progress follows the studysets and every
change of a card, here or synced, and is worked out again after a study
session; a slow, older working out never overwrites a newer one.
- Search: a field below the app bar filters by title and secondary title,
opens the archive while it finds something there, and says when nothing
matches; closing it shows everything again.
- Creating and editing: a sheet with the title, the secondary title (typed
in capitals, as every surface shows it) and the colour, picked from the
palette's twenty, whose names are localised; a new studyset is cobalt,
and an existing one keeps its colour, even one only a newer app version
knows, until another is picked. Create waits for a title. Closing the
sheet with changes asks first. It can't be swiped away: a bottom sheet
swiped away closes without asking its PopScope (Flutter issue 152120,
still open), so such sheets have no drag handle and close by their close
button, the back gesture or a tap beside them, which all ask.
- Archiving doesn't ask, since nothing is lost; it offers to undo, as does
unarchiving. Deleting asks, then deletes the studyset with its cards, each
blanked first.
- The create button floats in compact windows and slides away while
reading onwards; from medium windows on it sits in the app bar.
The old list and its title-only dialog are gone; the studyset screen's
tests create studysets through the sheet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 00:53:51 +02:00
"libraryNewStudyset": "New studyset",
"libraryEmpty": "No studysets yet",
"libraryUnreadable": "Couldn't read your studysets.",
"libraryArchivedSection": "Archived",
"librarySearchTooltip": "Search",
"librarySearchHint": "Search studysets",
"librarySearchClearTooltip": "Clear query",
"librarySearchCloseTooltip": "Close search",
"librarySearchNoMatches": "No studysets match your search",
"libraryStudysetArchived": "Studyset archived",
"libraryStudysetUnarchived": "Studyset unarchived",
2026-10-01 08:55:39 +02:00
"libraryStudysetDeleted": "Studyset deleted",
feat(app): the library: a grid of studyset cards, search and archive
The library tab becomes a grid of studyset cards (up to 400 dp wide, all
equally tall), starred ones first, and the archive as a section of its own
below, closed until opened and counting what rests there. It lists the top
level: studysets without a parent, those whose parent is gone, and those in
a cycle (ADR 0004). Each card's progress follows the studysets and every
change of a card, here or synced, and is worked out again after a study
session; a slow, older working out never overwrites a newer one.
- Search: a field below the app bar filters by title and secondary title,
opens the archive while it finds something there, and says when nothing
matches; closing it shows everything again.
- Creating and editing: a sheet with the title, the secondary title (typed
in capitals, as every surface shows it) and the colour, picked from the
palette's twenty, whose names are localised; a new studyset is cobalt,
and an existing one keeps its colour, even one only a newer app version
knows, until another is picked. Create waits for a title. Closing the
sheet with changes asks first. It can't be swiped away: a bottom sheet
swiped away closes without asking its PopScope (Flutter issue 152120,
still open), so such sheets have no drag handle and close by their close
button, the back gesture or a tap beside them, which all ask.
- Archiving doesn't ask, since nothing is lost; it offers to undo, as does
unarchiving. Deleting asks, then deletes the studyset with its cards, each
blanked first.
- The create button floats in compact windows and slides away while
reading onwards; from medium windows on it sits in the app bar.
The old list and its title-only dialog are gone; the studyset screen's
tests create studysets through the sheet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 00:53:51 +02:00
"libraryDeleteTitle": "Delete studyset?",
feat(app): the studyset screen with its topics, the tree's own screen
A studyset's screen, as decided with the tree (2026-09-30/10-01):
- A breadcrumb from the library down to the studyset; its steps go up
(replacing the location, so back leads further up), and steps that
don't fit fold into a "…" listing them, nearest first.
- From expanded windows on, two columns: the description over the topics,
the flashcards beside them, Study and Add material in the app bar. Below
that, the topics are in a drawer, opened from a bar at the bottom that
also holds Study and Add material and slides away while reading onwards;
the back button stays where a drawer would have taken its place.
- The topics: "All topics" for the whole studyset, then the studysets
inside it in their order, each with the study it invites, what it holds
and its options (edit, delete), opening on top of this screen; a switch
rearranges them by dragging; "New sub-studyset" creates one inside.
- Study covers the studyset with everything inside it ("Learn 12" while
something is due). Add material offers flashcards for now.
- Options: Edit (the sheet, now with the description, edited in the whole
window, and for a studyset inside another the colour of the one it is
in, which a new one takes at first), Move to… (the tree and the top
level, without the studyset itself and what is inside it), Archive or
Unarchive with Undo, Delete with Undo, which closes the screen.
- The description cut short when long, the whole a tap away; the licence
as the last line, linking to its text where that is known.
The list's bloc, scoped to a parent, lists its children, works out the
studyset's own progress, creates inside it, reorders and moves. The card
list leaves adding and studying to the screen. The inline editing of the
title and description, and its bloc, are gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 12:59:20 +02:00
"libraryDeleteMessage": "It is deleted with everything inside it and all their cards, on all your devices. You can undo this for a few seconds.",
feat(app): the library: a grid of studyset cards, search and archive
The library tab becomes a grid of studyset cards (up to 400 dp wide, all
equally tall), starred ones first, and the archive as a section of its own
below, closed until opened and counting what rests there. It lists the top
level: studysets without a parent, those whose parent is gone, and those in
a cycle (ADR 0004). Each card's progress follows the studysets and every
change of a card, here or synced, and is worked out again after a study
session; a slow, older working out never overwrites a newer one.
- Search: a field below the app bar filters by title and secondary title,
opens the archive while it finds something there, and says when nothing
matches; closing it shows everything again.
- Creating and editing: a sheet with the title, the secondary title (typed
in capitals, as every surface shows it) and the colour, picked from the
palette's twenty, whose names are localised; a new studyset is cobalt,
and an existing one keeps its colour, even one only a newer app version
knows, until another is picked. Create waits for a title. Closing the
sheet with changes asks first. It can't be swiped away: a bottom sheet
swiped away closes without asking its PopScope (Flutter issue 152120,
still open), so such sheets have no drag handle and close by their close
button, the back gesture or a tap beside them, which all ask.
- Archiving doesn't ask, since nothing is lost; it offers to undo, as does
unarchiving. Deleting asks, then deletes the studyset with its cards, each
blanked first.
- The create button floats in compact windows and slides away while
reading onwards; from medium windows on it sits in the app bar.
The old list and its title-only dialog are gone; the studyset screen's
tests create studysets through the sheet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 00:53:51 +02:00
"libraryDeleteConfirm": "Delete",
"studysetSheetCreateTitle": "Create studyset",
"studysetSheetEditTitle": "Edit studyset",
"studysetSheetCreate": "Create",
"studysetSheetSave": "Save",
"studysetSheetTitleLabel": "Title",
"studysetSheetSecondaryLabel": "Secondary title",
"studysetSheetSecondaryHelper": "Shown as a small label above the title.",
"studysetSheetColor": "Color",
"studysetSheetDiscardTitle": "Discard changes?",
"studysetSheetDiscardMessage": "You have unsaved changes to this studyset. Discard them and close the form?",
"studysetSheetDiscardConfirm": "Discard",
"paletteColorName": "{name, select, carrot{Carrot} cerise{Cerise} cobalt{Cobalt} copper{Copper} enzian{Enzian} fern{Fern} forest{Forest} ocean{Ocean} olive{Olive} pacific{Pacific} pickle{Pickle} pine{Pine} pink{Pink} plum{Plum} purple{Purple} reef{Reef} sahara{Sahara} slateblue{Slate blue} soil{Soil} strawberry{Strawberry} other{{name}}}",
"@paletteColorName": {"description": "A colour of the palette content can take, by its stored name.", "placeholders": {"name": {"type": "String"}}},
"colorPickerLabel": "Color: {color}",
"@colorPickerLabel": {"placeholders": {"color": {"type": "String"}}},
feat(app): the UI foundation: theme, tabs and routes, strings
The app gets its look and navigation before more features land on them.
- Theme (core/theme/): hand-written light and dark Material 3 colour schemes around
cobalt and copper; ThemeExtras for the colours Material has no role for (states, the
four FSRS ratings); the 20 colours a person can give content. Tests hold text to WCAG
AA contrast on each palette colour and on the dark theme's primary colour and surface.
- Layout and shared widgets: Material 3's window-size classes (core/layout/);
SectionCard, AppLoadingIndicator, confirmDestructiveAction and FoundById
(core/widget/). Lucide icons.
- Navigation with go_router: four tabs (Home, Library, Explore, Profile), each keeping
its own stack of screens, as a navigation rail with the app's icon from 600 dp and as
a navigation bar below; choosing the open tab again returns to its first screen. A
studyset's screen sits in the library; studying, cards and settings cover the tabs.
- Routes carry ids: FoundById finds the item in the repository's live list, so a
studyset deleted on another device, or an old link, says it no longer exists. A
screen that deletes its own item keeps showing it while it closes, rather than
flashing that message.
- Every person gets an app of their own (PersonApp, lib/src/app/): a
MaterialApp.router with its own GoRouter and PersonScope around the navigator, built
by SessionGate inside the person's keyed subtree. Screens read the person's
repositories wherever they are built, so the static route() helpers and the listener
that closed every pushed screen on a change of person are gone: a change of person
now disposes the whole router and starts again at home.
- The account dialog becomes the Profile tab, with Settings (sign out, delete the
account, About) behind a gear. A waiting GitHub sign-in now keeps waiting while
another tab shows; a change of person still cancels it.
- The new screens' strings come from Flutter's gen-l10n (English for now). The
generated files are committed, left out of analysis and formatting, and written
anew by `flutter pub get`, so CI's check of generated code also catches stale ones.
Widget tests now start the whole app (test/support/pump_app.dart) at the screen's path
and move through it as a person would, by tabs and taps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 00:18:31 +02:00
feat(app): the library's studyset card
A studyset in the library: a bar in its colour, its title with the secondary
title as a kicker, what it holds, and beside the title the action it
invites inside a ring its mature cards fill, with a badge counting the due
cards (at most "99+", growing inwards so it never passes the card's edge).
The action is a review when reviews are due, studying when only new cards
are, and adding content otherwise, which opens the studyset: the card only
invites a session that has something to study. A long press stars it, as
does the star, which a hovering pointer reveals and which stays while
starred; the options edit, archive or unarchive, and delete it. An archived
studyset rests: dimmed, neutral, paused. Until its progress is known, a
muted bar stands in for "No content yet", which it might not be.
A starred star is amber, dark enough in the light theme to stand out from
the cards as a graphic must (3:1), a colour the theme extras now hold. It is
Material's filled star: Lucide has no filled one, and the fill is what says
the star is on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 00:40:52 +02:00
"studysetCountFlashcards": "{count, plural, =1{1 flashcard} other{{count} flashcards}}",
"@studysetCountFlashcards": {"placeholders": {"count": {"type": "int"}}},
"studysetNoContent": "No content yet",
"studysetActionReview": "Review",
"studysetActionStudy": "Study",
"studysetActionAdd": "Add content",
"studysetArchived": "Archived",
"studysetStar": "Star",
"studysetUnstar": "Unstar",
"studysetOptions": "Options",
"studysetMenuEdit": "Edit",
"studysetMenuArchive": "Archive",
"studysetMenuUnarchive": "Unarchive",
"studysetMenuDelete": "Delete",
feat(app): the studyset screen with its topics, the tree's own screen
A studyset's screen, as decided with the tree (2026-09-30/10-01):
- A breadcrumb from the library down to the studyset; its steps go up
(replacing the location, so back leads further up), and steps that
don't fit fold into a "…" listing them, nearest first.
- From expanded windows on, two columns: the description over the topics,
the flashcards beside them, Study and Add material in the app bar. Below
that, the topics are in a drawer, opened from a bar at the bottom that
also holds Study and Add material and slides away while reading onwards;
the back button stays where a drawer would have taken its place.
- The topics: "All topics" for the whole studyset, then the studysets
inside it in their order, each with the study it invites, what it holds
and its options (edit, delete), opening on top of this screen; a switch
rearranges them by dragging; "New sub-studyset" creates one inside.
- Study covers the studyset with everything inside it ("Learn 12" while
something is due). Add material offers flashcards for now.
- Options: Edit (the sheet, now with the description, edited in the whole
window, and for a studyset inside another the colour of the one it is
in, which a new one takes at first), Move to… (the tree and the top
level, without the studyset itself and what is inside it), Archive or
Unarchive with Undo, Delete with Undo, which closes the screen.
- The description cut short when long, the whole a tap away; the licence
as the last line, linking to its text where that is known.
The list's bloc, scoped to a parent, lists its children, works out the
studyset's own progress, creates inside it, reorders and moves. The card
list leaves adding and studying to the screen. The inline editing of the
title and description, and its bloc, are gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 12:59:20 +02:00
"studysetMenuMove": "Move to…",
"studysetTabFlashcards": "Flashcards",
"studysetFlashcardsEmpty": "No flashcards yet",
"studysetFlashcardsEmptyHint": "Add some to start studying.",
"studysetAddMaterial": "Add material",
"studysetCreateFlashcards": "Create flashcards",
"studysetStudy": "Study",
"studysetLearnCount": "Learn {count}",
"@studysetLearnCount": {"placeholders": {"count": {"type": "int"}}},
"studysetOpenTopics": "Show topics",
"studysetTopics": "Topics",
"studysetAllTopics": "All topics",
"studysetNewSubStudyset": "New sub-studyset",
"studysetSubStudysetsEmpty": "No sub-studysets yet.",
"studysetSubStudysetsEmptyHint": "Break this studyset into milestones or lessons.",
"studysetReorder": "Reorder",
"studysetReorderDone": "Done",
"studysetDragToReorder": "Drag to reorder",
"studysetMoveTitle": "Move studyset to",
"studysetMoveTopLevel": "Top level",
"studysetMoveCurrent": "Where it is now",
"studysetMoveConfirm": "Move",
"studysetMoveShowInside": "Show what is inside",
"studysetMoveHideInside": "Hide what is inside",
"studysetMoved": "Moved to {destination}.",
"@studysetMoved": {"placeholders": {"destination": {"type": "String"}}},
"studysetReadMore": "Read more",
"studysetDescriptionTitle": "Description",
"studysetDescriptionEditTitle": "Edit description",
"studysetDescriptionSave": "Save",
"studysetSheetDescription": "Description",
"studysetSheetDescriptionAdd": "Add a description",
"studysetSheetInheritColor": "Same color as the studyset it is in",
feat(app): the library's studyset card
A studyset in the library: a bar in its colour, its title with the secondary
title as a kicker, what it holds, and beside the title the action it
invites inside a ring its mature cards fill, with a badge counting the due
cards (at most "99+", growing inwards so it never passes the card's edge).
The action is a review when reviews are due, studying when only new cards
are, and adding content otherwise, which opens the studyset: the card only
invites a session that has something to study. A long press stars it, as
does the star, which a hovering pointer reveals and which stays while
starred; the options edit, archive or unarchive, and delete it. An archived
studyset rests: dimmed, neutral, paused. Until its progress is known, a
muted bar stands in for "No content yet", which it might not be.
A starred star is amber, dark enough in the light theme to stand out from
the cards as a graphic must (3:1), a colour the theme extras now hold. It is
Material's filled star: Lucide has no filled one, and the fill is what says
the star is on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 00:40:52 +02:00
feat(app): the UI foundation: theme, tabs and routes, strings
The app gets its look and navigation before more features land on them.
- Theme (core/theme/): hand-written light and dark Material 3 colour schemes around
cobalt and copper; ThemeExtras for the colours Material has no role for (states, the
four FSRS ratings); the 20 colours a person can give content. Tests hold text to WCAG
AA contrast on each palette colour and on the dark theme's primary colour and surface.
- Layout and shared widgets: Material 3's window-size classes (core/layout/);
SectionCard, AppLoadingIndicator, confirmDestructiveAction and FoundById
(core/widget/). Lucide icons.
- Navigation with go_router: four tabs (Home, Library, Explore, Profile), each keeping
its own stack of screens, as a navigation rail with the app's icon from 600 dp and as
a navigation bar below; choosing the open tab again returns to its first screen. A
studyset's screen sits in the library; studying, cards and settings cover the tabs.
- Routes carry ids: FoundById finds the item in the repository's live list, so a
studyset deleted on another device, or an old link, says it no longer exists. A
screen that deletes its own item keeps showing it while it closes, rather than
flashing that message.
- Every person gets an app of their own (PersonApp, lib/src/app/): a
MaterialApp.router with its own GoRouter and PersonScope around the navigator, built
by SessionGate inside the person's keyed subtree. Screens read the person's
repositories wherever they are built, so the static route() helpers and the listener
that closed every pushed screen on a change of person are gone: a change of person
now disposes the whole router and starts again at home.
- The account dialog becomes the Profile tab, with Settings (sign out, delete the
account, About) behind a gear. A waiting GitHub sign-in now keeps waiting while
another tab shows; a change of person still cancels it.
- The new screens' strings come from Flutter's gen-l10n (English for now). The
generated files are committed, left out of analysis and formatting, and written
anew by `flutter pub get`, so CI's check of generated code also catches stale ones.
Widget tests now start the whole app (test/support/pump_app.dart) at the screen's path
and move through it as a person would, by tabs and taps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 00:18:31 +02:00
"exploreTitle": "Explore",
"exploreEmpty": "Studysets that others share will appear here.",
"profileTitle": "Profile",
"profileSettingsTooltip": "Settings",
"profileIdentified": "Your progress is kept with your account.",
"profileAnonymous": "Progress is saved on this device. Sign in to keep it.",
"profileSignInWithGitHub": "Sign in with GitHub",
"profileSignInFailed": "Couldn't sign in with GitHub.",
"profileContinueInBrowser": "Continue in your browser.",
"profileSwitchTitle": "Switch to your GitHub account?",
"profileSwitchMessage": "This GitHub account already has progress from another device. The studysets on this device can't be combined with it yet: if you switch, they are deleted.",
"profileSwitchStay": "Stay anonymous",
"profileSwitchConfirm": "Switch",
"settingsTitle": "Settings",
"settingsAccount": "Account",
"settingsSignOut": "Sign out",
"settingsSignOutTitle": "Sign out?",
"settingsSignOutAnonymousMessage": "This account can't be signed into again, so signing out deletes it with its progress.",
"settingsDeleteAccount": "Delete account",
"settingsDeleteTitle": "Delete your account?",
"settingsDeleteMessage": "Everything you have, your studysets, cards and reviews, is deleted on the server and on all your devices. This can't be undone.",
"settingsAbout": "About Halkyon Learn",
2026-10-01 16:57:57 +02:00
"tagsReadFailed": "Couldn't read the tags.",
"tagPickerTitle": "Tags",
"tagPickerManage": "Manage tags",
"tagPickerSearchLabel": "Search or create a tag",
"tagPickerCreate": "Create \"{name}\"",
"@tagPickerCreate": {"placeholders": {"name": {"type": "String"}}},
"tagSheetCreateTitle": "Create tag",
"tagSheetEditTitle": "Edit tag",
"tagSheetNameLabel": "Name",
"tagSheetNameHelper": "Stored and displayed in lowercase.",
"tagSheetNameExists": "The tag '{name}' exists already.",
"@tagSheetNameExists": {"placeholders": {"name": {"type": "String"}}},
"tagSheetNameMerges": "There is a tag '{name}' already: saving merges this one into it.",
"@tagSheetNameMerges": {"placeholders": {"name": {"type": "String"}}},
"tagSheetColor": "Color",
"tagSheetCreate": "Create",
"tagSheetSave": "Save",
"tagManageTitle": "Manage tags",
"tagManageEmpty": "No tags yet. Add one below.",
"tagManageAdd": "Add tag",
"tagManageRow": "{name} ({count})",
"@tagManageRow": {"description": "A tag in the list of tags, with how many flashcards have it.", "placeholders": {"name": {"type": "String"}, "count": {"type": "int"}}},
"tagManageEdit": "Edit tag",
"tagManageDelete": "Delete tag",
"tagDeleteTitle": "Delete the tag '{name}'?",
"@tagDeleteTitle": {"placeholders": {"name": {"type": "String"}}},
"tagDeleteMessage": "{count, plural, =0{It isn't on any flashcards.} =1{It is removed from 1 flashcard, on all your devices.} other{It is removed from {count} flashcards, on all your devices.}}",
"@tagDeleteMessage": {"placeholders": {"count": {"type": "int"}}},
"tagDeleteConfirm": "Delete",
"tagDeleted": "Deleted the tag '{name}'",
"@tagDeleted": {"placeholders": {"name": {"type": "String"}}},
2026-10-01 17:30:24 +02:00
"studySettingsTitle": "Session settings",
"studySettingsFilterByTags": "Filter by tags",
"studySettingsFilterHint": "Study only the flashcards with any of the tags chosen.",
"studySettingsNoTags": "No tags yet. Add tags to your flashcards to filter them here.",
"studySettingsReset": "Reset",
"studySettingsSave": "Save",
2026-10-01 16:57:57 +02:00
"cardTagsLabel": "Tags",
"cardTagsAdd": "Add tags",
"cardTagsEdit": "Edit tags",
"cardFilterTooltip": "Filter",
"cardFilterTitle": "Filter",
"cardFilterTag": "Tag",
"cardFilterAllTags": "All tags",
"cardFilterNoTags": "None of these flashcards has a tag yet.",
"cardFilterClear": "Clear all",
"cardFilterApply": "Apply",
"cardFilterNothing": "No flashcards have this tag.",
"cardListMore": "More",
"cardListManageTags": "Manage tags",
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>
2026-10-01 18:42:25 +02:00
"composerTitle": "Create flashcards",
"composerTitleFor": "Create flashcards for \"{title}\"",
"@composerTitleFor": {"placeholders": {"title": {"type": "String"}}},
"composerSaving": "Saving…",
"composerSaveFailed": "Save failed — retry",
"composerAllSaved": "All changes saved",
"composerNewFlashcard": "New flashcard",
"composerCollapseStack": "Collapse stack",
"composerExpandStack": "Expand stack",
"composerStatusSaving": "Saving",
"composerStatusSaved": "Saved",
"composerStatusFailed": "Save failed",
"composerSaveFailedInline": "Save failed.",
"composerRetry": "Retry",
"composerEmptyPane": "Add a flashcard to get started.",
"composerKindFlashcard": "Flashcard",
"composerKindVocabulary": "Vocabulary",
"composerKindMatching": "Matching",
"composerKindMap": "Map",
"composerLabelFront": "Front",
"composerLabelQuestion": "Question",
"composerLabelExpression": "Expression",
"composerLabelPrompt": "Prompt",
"composerLabelBack": "Back",
"composerLabelAnswers": "Answers",
"composerLabelAnswer": "Answer",
"composerPlaceholderFront": "Add question",
"composerPlaceholderExpression": "Add expression",
"composerPlaceholderPrompt": "Add prompt",
"composerAddAnswer": "Add answer",
"composerCorrectAnswer": "Correct answer",
"composerWrongAnswer": "Wrong answer",
"composerRemoveAnswer": "Remove answer",
"composerPin": "Pin {field}: keep it for the next card",
"@composerPin": {"placeholders": {"field": {"type": "String"}}},
"composerUnpin": "Unpin {field}: clear it for the next card",
"@composerUnpin": {"placeholders": {"field": {"type": "String"}}},
"composerTags": "Tags",
"composerAddTags": "Add tags",
"composerMoreActions": "More actions",
"composerDuplicate": "Duplicate",
"composerClearFields": "Clear fields",
"composerDelete": "Delete",
"composerDeleteTitle": "Delete this flashcard?",
"composerDeleteDraftMessage": "The draft will be removed from this session. It has not been saved.",
"composerDeleteSavedMessage": "The flashcard will be removed from the studyset, on all your devices.",
"composerDiscardTitle": "{count, plural, =1{Discard unsaved flashcard?} other{Discard unsaved flashcards?}}",
"@composerDiscardTitle": {"placeholders": {"count": {"type": "int"}}},
"composerDiscardMessage": "{count, plural, =1{1 flashcard hasn't been saved yet. Leaving now will discard it.} other{{count} flashcards haven't been saved yet. Leaving now will discard them.}}",
"@composerDiscardMessage": {"placeholders": {"count": {"type": "int"}}},
"composerDiscardConfirm": "Discard",
"composerConflict": "This flashcard was changed differently on two devices. Choose the version to keep of each part below.",
"composerKeepThis": "Keep this",
"vocabularyReading": "Reading",
"vocabularyReadingHint": "Kana reading",
"vocabularyMeanings": "Meanings",
"vocabularyPrimaryMeaningHint": "Primary meaning",
"vocabularyMeaningHint": "Meaning",
"vocabularyAddMeaning": "Add meaning",
"vocabularyRemoveMeaning": "Remove meaning",
"matchingCategories": "Categories",
"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.",
"matchingCategory": "Category {number}",
"@matchingCategory": {"placeholders": {"number": {"type": "int"}}},
"matchingAddCategory": "Add category",
"matchingAddCategoryBlocked": "Add an item first: a card can't have more categories than items",
"matchingRemoveCategory": "Remove category",
"matchingMinCategories": "At least two categories required",
"matchingItems": "Items",
"matchingItemsHint": "The draggable items. Assign every item to its correct category: an unassigned item can never be placed right.",
"matchingItem": "Item {number}",
"@matchingItem": {"placeholders": {"number": {"type": "int"}}},
"matchingAddItem": "Add item",
"matchingUnassigned": "Unassigned",
"matchingRemoveItem": "Remove item",
"matchingMinItems": "At least two items required",
2026-10-01 18:58:54 +02:00
"cardTileOptions": "Options",
"cardTileEdit": "Edit",
"cardTileDelete": "Delete",
"cardTileUntitled": "Untitled",
"cardTileConflict": "Changed on two devices",
feat(app): study sessions in rounds, by card type, cramming and reversed
A session studies a round of up to the settings' cards per round. In
spaced repetition a card leaves the round once it is a day or more away,
one rated lower comes back when due; cramming walks every card once,
round after round, its reviews moving no schedule, with going back and
on. Asking the back first (a toggle in the header, saved in the
settings) asks front/back and vocabulary cards their back, on their own
schedule. Each type studies its way: a word shows its reading and
meanings, a multiple-choice card is picked and checked, a matching card
sorted by dragging or tapping and checked; then the person rates (Bad,
OK, Good, Perfect, each with when the card comes back). Progress shows
as pills, or a tally bar while cramming; a round ends with how it went.
The session settings gain the mode, cards per round, new cards per day
and the order.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 19:29:21 +02:00
"studyClose": "Close session",
"studyBackFirstOn": "Showing the back of cards first: tap to revert",
"studyBackFirstOff": "Show the back of cards first",
"studyShowAnswer": "Show answer",
"studyCheck": "Check",
"studyRatingBad": "Bad",
"studyRatingOk": "OK",
"studyRatingGood": "Good",
"studyRatingPerfect": "Perfect",
"studyNothingTitle": "Nothing to study right now",
"studyNothingBody": "Come back later when more cards are due.",
"studyNextDue": "The next card is due in {interval}.",
"@studyNextDue": {"placeholders": {"interval": {"type": "String"}}},
"studyDone": "Done",
"studyRoundDone": "Round complete",
"studyContinue": "Continue learning",
"studyPrevious": "Previous card",
"studyNext": "Next card",
"studyReading": "Reading",
"studyMeanings": "Meanings",
"studyPlaceItems": "Drag each item onto its category, or tap an item and then a category.",
"studyMinutes": "{count} min",
"@studyMinutes": {"placeholders": {"count": {"type": "int"}}},
"studyHours": "{count} h",
"@studyHours": {"placeholders": {"count": {"type": "int"}}},
"studyDays": "{count, plural, =1{1 day} other{{count} days}}",
"@studyDays": {"placeholders": {"count": {"type": "int"}}},
"studyMonths": "{count, plural, =1{1 month} other{{count} months}}",
"@studyMonths": {"placeholders": {"count": {"type": "int"}}},
"studyYears": "{count, plural, =1{1 year} other{{count} years}}",
"@studyYears": {"placeholders": {"count": {"type": "int"}}},
"studyFilteredBy": "{count, plural, =1{Narrowed to 1 tag} other{Narrowed to {count} tags}}",
"@studyFilteredBy": {"placeholders": {"count": {"type": "int"}}},
"studySettingsCardsPerRound": "Cards per round",
"studySettingsNewPerDay": "New cards per day",
"studySettingsNewPerDayHint": "How many never-studied cards each studyset starts a day. Due reviews are never limited.",
"studySettingsUnlimited": "Unlimited",
"studySettingsSortBy": "Sort by",
"studySettingsLearnMode": "Learn mode",
"studyModeSpaced": "Spaced repetition",
"studyModeSpacedHint": "Due cards on their schedules; ratings move them.",
"studyModeCram": "Cram",
"studyModeCramHint": "Walk every card without touching the schedules.",
"studySortOldestFirst": "Oldest first",
"studySortRandom": "Random",
"studySortNewestFirst": "Newest first",
"studyFewer": "Fewer",
"studyMore": "More",
2026-10-01 19:34:44 +02:00
"studysetMenuReset": "Reset progress",
"studysetResetTitle": "Reset progress?",
"studysetResetMessage": "Every flashcard in it, and in the studysets inside it, starts afresh as new, on all your devices. Your study history stays. You can undo this for a few seconds.",
"studysetResetConfirm": "Reset",
"studysetResetDone": "Progress reset",
2026-10-01 19:56:29 +02:00
"mapUnknown": "This map needs a newer version of the app.",
"mapPickRegion": "Tap the region that answers the question; pinch or scroll to zoom.",
"mapNonePicked": "No region picked yet",
"composerPlaceholderQuestion": "Add question",
"composerLabelRegion": "Answer",
feat(app): the home dashboard: streak, goal, week, activity
Home opens on a study dashboard. The streak's flame sits in the app bar
and opens a sheet of how it stands this week. Below: the study goal (a
ring of the day's or week's progress, set and removed in its sheet), the
week (each day studied, rested, missed or to come with the cards falling
due; days to go back and on; today or a day to come made a rest day),
and a year of activity as a heatmap, its weekdays staying in view while
the weeks scroll. A long press arranges the dashboard: drag a widget
elsewhere, hide or show it; the arrangement is synced.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 22:13:34 +02:00
"homeStreakTooltip": "Study streak",
"homeArrange": "Arrange widgets",
"homeDone": "Done",
"homeDragToReorder": "Drag to reorder",
"homeShowWidget": "Show {label}",
"@homeShowWidget": {"placeholders": {"label": {"type": "String"}}},
"homeHideWidget": "Hide {label}",
"@homeHideWidget": {"placeholders": {"label": {"type": "String"}}},
"homeAllHidden": "All widgets are hidden",
"homeAllHiddenHint": "Long-press here to bring some back.",
"homeWidgetGoal": "Study goal",
"homeWidgetWeek": "Week overview",
"homeWidgetActivity": "Activity heatmap",
"homeActivityTitle": "Your activity",
"streakDays": "{count, plural, =1{1 day streak} other{{count} day streak}}",
"streakStart": "Study today to start your streak.",
"streakGrow": "Keep it going: study at least once a day to grow your streak.",
"streakFirstDay": "Review some cards today to light the first day.",
"streakComeBack": "Come back tomorrow to keep your streak.",
"streakKeepAlive": "Study today to keep your streak alive.",
"goalEditTitle": "Edit study goal",
"goalSetTitle": "Set a study goal",
"goalDescriptionDaily": "Review a number of flashcards each day. Every card you rate counts.",
"goalDescriptionWeekly": "Review a number of flashcards each week, from Monday. Every card you rate counts.",
"goalPeriod": "Period",
"goalPerDay": "Per day",
"goalPerWeek": "Per week",
"goalCardsPerDay": "Cards per day",
"goalCardsPerWeek": "Cards per week",
"goalSave": "Save goal",
"goalRemove": "Remove goal",
"goalEmptySubtitle": "Review a set number of cards each day or week.",
"goalDailyHeadline": "Daily goal",
"goalWeeklyHeadline": "Weekly goal",
"goalProgressToday": "{reviewed} of {target} cards today",
"@goalProgressToday": {"placeholders": {"reviewed": {"type": "int"}, "target": {"type": "int"}}},
"goalProgressThisWeek": "{reviewed} of {target} cards this week",
"@goalProgressThisWeek": {"placeholders": {"reviewed": {"type": "int"}, "target": {"type": "int"}}},
"goalMet": "Goal met: nice work!",
"goalRemaining": "{count} to go",
"@goalRemaining": {"placeholders": {"count": {"type": "int"}}},
"weekToday": "Today",
"weekPreviousDay": "Previous day",
"weekNextDay": "Next day",
"weekRestDay": "Rest day",
"weekDueCount": "{count, plural, =1{1 card due} other{{count} cards due}}",
"@weekDueCount": {"placeholders": {"count": {"type": "int"}}},
"heatmapLess": "Less",
"heatmapMore": "More",
"heatmapTotal": "{count, plural, =1{1 activity in the last year} other{{count} activities in the last year}}",
"@heatmapTotal": {"placeholders": {"count": {"type": "int"}}},
"heatmapDay": "{count, plural, =0{Nothing} =1{1 activity} other{{count} activities}} · {date}",
"@heatmapDay": {"placeholders": {"count": {"type": "int"}, "date": {"type": "String"}}},
feat(app): the UI foundation: theme, tabs and routes, strings
The app gets its look and navigation before more features land on them.
- Theme (core/theme/): hand-written light and dark Material 3 colour schemes around
cobalt and copper; ThemeExtras for the colours Material has no role for (states, the
four FSRS ratings); the 20 colours a person can give content. Tests hold text to WCAG
AA contrast on each palette colour and on the dark theme's primary colour and surface.
- Layout and shared widgets: Material 3's window-size classes (core/layout/);
SectionCard, AppLoadingIndicator, confirmDestructiveAction and FoundById
(core/widget/). Lucide icons.
- Navigation with go_router: four tabs (Home, Library, Explore, Profile), each keeping
its own stack of screens, as a navigation rail with the app's icon from 600 dp and as
a navigation bar below; choosing the open tab again returns to its first screen. A
studyset's screen sits in the library; studying, cards and settings cover the tabs.
- Routes carry ids: FoundById finds the item in the repository's live list, so a
studyset deleted on another device, or an old link, says it no longer exists. A
screen that deletes its own item keeps showing it while it closes, rather than
flashing that message.
- Every person gets an app of their own (PersonApp, lib/src/app/): a
MaterialApp.router with its own GoRouter and PersonScope around the navigator, built
by SessionGate inside the person's keyed subtree. Screens read the person's
repositories wherever they are built, so the static route() helpers and the listener
that closed every pushed screen on a change of person are gone: a change of person
now disposes the whole router and starts again at home.
- The account dialog becomes the Profile tab, with Settings (sign out, delete the
account, About) behind a gear. A waiting GitHub sign-in now keeps waiting while
another tab shows; a change of person still cancels it.
- The new screens' strings come from Flutter's gen-l10n (English for now). The
generated files are committed, left out of analysis and formatting, and written
anew by `flutter pub get`, so CI's check of generated code also catches stale ones.
Widget tests now start the whole app (test/support/pump_app.dart) at the screen's path
and move through it as a person would, by tabs and taps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-01 00:18:31 +02:00
"commonCancel": "Cancel",
"commonClose": "Close",
"commonUndo": "Undo",
"commonTryAgain": "Try again",
"sessionUnreachable": "Couldn't reach the server.",
"notFoundGone": "This no longer exists. It may have been deleted on another device."
}