Commit graph halkyon/apps/learn/halkyon_learn_flutter
Author SHA1 Message Date
99b75645ad
feat(learn): exporting shows its steps, counts and percent, with Abort
Exporting a studyset said "Exporting…" in a snack bar until the place to
keep it was asked. It now shows a sheet with its steps (reading the
content, gathering files for an archive, packing), how many of the step's
items are done and the percent of all of it, and Abort, which keeps
nothing (decided 9 Nov 2026); then asks where to keep the file as before.

Both exporters check between studysets, and the archive's between files;
packing runs on its isolate to its end, its result dropped once aborted.
ExportCubit runs an export's work behind the sheet (runExport), which
says how it ended: made, failed (a file missing named as before) or
aborted.

Whats-New: Exporting shows its steps and how far it has come, and Abort stops it.
Whats-New-De: Der Export zeigt seine Schritte und wie weit er ist, und „Abbrechen“ beendet ihn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 16:19:55 +01:00
7cba684513
feat(learn): an Anki deck's import shows its steps, counts and percent, with Abort
Importing an Anki deck showed one bar and "Importing…". It now says which
of its four steps it is in (copying files, writing flashcards, tagging,
bringing over the review history), how many of the step's items are done
and the percent of all of it, and offers Abort (decided 9 Nov 2026), as
the archive's import does.

The importer checks between files and batches of cards. Aborted, it
deletes what it wrote: a studyset it made for the deck for good with all
of it; importing into an existing studyset, the cards it wrote there and
the topics it made for subdecks, leaving what the studyset held before;
and the files' rows it made, not those the person had. Tags it made stay.
Once everything is written, Abort no longer undoes it.

Whats-New: Importing an Anki deck shows its steps and how far it has come, and Abort stops it, keeping nothing of it.
Whats-New-De: Der Import eines Anki-Decks zeigt seine Schritte und wie weit er ist, und „Abbrechen“ beendet ihn, ohne etwas davon zu behalten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 16:19:54 +01:00
5f7cb70c3c
feat(learn): an archive's import shows its steps, counts and percent, with Abort
Importing a Halkyon archive showed one bar. It now says which of its three
steps it is in (copying files; writing studysets, flashcards and notes;
bringing over the progress), how many of the step's items are done and the
percent of all of it, and offers Abort (decided 9 Nov 2026).

The copier checks between items, never leaving one half written, and
keeps a trail of what it wrote: the top studyset once made, and the files'
rows it made (not those the person had, found before each file is added).
Aborted, the importer deletes the top studyset for good with everything
inside it, as Delete now does (the reviews, answers and pages read going
with their cards, steps and PDFs), and those rows; the tags it made stay,
as names the person may well use anyway. Once all of it is written, Abort
no longer undoes it.

WorkProgress, WorkStages and AbortSignal (core/work/) and
WorkProgressView (core/widget/) are shared with the Anki import and the
exports, which follow.

Whats-New: Importing an archive shows its steps and how far it has come, and Abort stops it, keeping nothing of it.
Whats-New-De: Der Import eines Archivs zeigt seine Schritte und wie weit er ist, und „Abbrechen“ beendet ihn, ohne etwas davon zu behalten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 16:19:54 +01:00
c5eceda383
feat(ui): on a phone, the floating button sits just above the navigation bar, its screen's fade under it
Each tab's screen paints the bar's fade beneath its own button
(FrameFade as its bottomNavigationBar, extendBody), so the button stands
16 pixels above the bar, as Material's, instead of above the fade; the
frame keeps its own fade for screens without one, and gets it back while
a page is pushed over the screen.

Whats-New: On a phone, the + button now sits just above the navigation bar.
Whats-New-De: Auf dem Handy sitzt der +-Knopf jetzt direkt über der Navigationsleiste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 14:23:00 +01:00
f47f6b23b5
fix(learn): a tab whose material is in its topics says so in the middle, as an empty tab does
The tab saying that its material is in the studyset's topics stood at the
top of the room below the tabs, while an empty tab's message stands in
its middle (SliverCentered), so switching between them moved the message
up and down (the developer's review, 9 Nov 2026). It stands in the middle
too now.

Whats-New: A studyset's tab whose material is in its topics now says so in the middle, as empty tabs do.
Whats-New-De: Ein Tab eines Lernsets, dessen Material in seinen Themen liegt, sagt das jetzt in der Mitte, wie leere Tabs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 14:22:59 +01:00
cc7511f060
feat(ui): in dark mode, filled and floating buttons in cobalt itself, white on it
In dark mode the primary colour is cobalt lightened (#AEB9FF), readable as
text and thin marks on the dark surfaces, and filled buttons took it: Todo's
send button glared bright beside everything else; floating buttons took
Material's dark primary container. Both are cobalt itself now, white on it,
as in light mode (decision 6 of the developer's list, 9 Nov 2026); links,
tabs and switches keep the lighter tone. Filled icon buttons take no theme
of their own in Flutter (the icon buttons' theme is the plain ones' too),
so they take filledIconButtonStyle: Learn's study and send buttons,
Todo's send buttons and Locate me, Meditate's stop dictating.

Whats-New: In dark mode, filled buttons and the + button are cobalt with a white icon, no longer a bright light blue.
Whats-New-De: Im dunklen Modus sind gefüllte Schaltflächen und die +-Schaltfläche kobaltblau mit weißem Symbol statt grell hellblau.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 14:22:59 +01:00
560de2ed93
fix(ui): on a phone, a snack bar stands above the screen's floating button
Below medium windows the frame's scaffold showed the screens' snack bars,
under the floating button of the screen's own scaffold, so a tap on a
snack bar's Undo hit the button instead (found 9 Nov 2026, Todo's Undo
after deleting the completed tasks). The screens get a messenger of their
own there, and their scaffolds lift the snack bars above their buttons, as
Material places them. From medium windows on the frame's scaffold still
shows them, once: a messenger shows a snack bar on each of its scaffolds
not inside another, as two panes side by side are. As the window grows
past a phone's, the phone's snack bars go, since a scaffold whose
messenger changes keeps the one it showed for good.

Whats-New: On a phone, a message's Undo is no longer hidden under the + button.
Whats-New-De: Auf dem Handy liegt das Rückgängig einer Meldung nicht mehr unter der +-Schaltfläche.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 14:22:56 +01:00
3bccf127d0
feat(learn): PDFs up to 100 MB
The books of the old app's library run past the 50 MB a PDF could have
(decided 2026-10-03); the server and the app take up to 100 MB now. Other
files keep their own, smaller limit.

Whats-New: PDFs can now be up to 100 MB.
Whats-New-De: PDFs dürfen jetzt bis zu 100 MB groß sein.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 14:22:55 +01:00
551140621b
feat(learn,train,todo,meditate): the icons on a white tile again, coloured by the system's theme on Android and iOS (ADR 0031, D9, D10)
D10 returns every icon to D1's white tile, D8's dark one undone, the
gradients as D5 gives them (cobalt holds about 5.7 : 1 against white).

D9 adds the variants the systems colour by their theme, all from the same
glyph at the same place, drawn by tool/app_icons.py and written into the
projects by flutter_launcher_icons: Android's monochrome layer, which
themed icons tint (Android 13 and later), and iOS's dark and tinted icons
(iOS 18 and later), the dark one keeping D8's lift of 30 % towards white
on iOS's own dark background. macOS needs an Icon Composer file made on a
Mac and keeps the plain icon until then.

Whats-New: The app's icon is white again, and takes the system's colours where Android or iOS themes its icons.
Whats-New-De: Das App-Symbol ist wieder weiß und nimmt die Farben des Systems an, wo Android oder iOS seine Symbole einfärbt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 14:22:49 +01:00
f76268ff37
chore(release): learn-v0.26.0
Some checks failed
CI / check (push) Has been cancelled
CI / deploy (push) Has been cancelled
Build 29.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 14:02:57 +01:00
1a3034fd31
feat(learn,todo,train,meditate): the apps' icons on a dark tile (ADR 0031, D8)
All checks were successful
CI / check (push) Successful in 50m47s
CI / deploy (push) Successful in 4m49s
Each icon's Lucide glyph now sits on the apps' dark background (#131520)
instead of white, its cobalt-to-colour gradient lifted 30 % towards white
so the glyph keeps above 4.5 : 1 against the tile. tool/app_icons.py
holds the tile and the lift; the pubspecs give Android's adaptive icon
and iOS's the same background. Every platform's icon is regenerated.

Whats-New: The app's icon now sits on a dark background.
Whats-New-De: Das App-Symbol hat jetzt einen dunklen Hintergrund.
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 11:48:43 +01:00
c36bd83c6a
feat(learn,todo,meditate): dictate through the phone's voice input app (ADR 0038, D18)
On Android the microphone now opens the app handling
RECOGNIZE_SPEECH (FUTO Voice Input, Google's), the default the person
chose in Android, and puts the text it returns where the cursor stood,
as Dictation does; cancelled, nothing. Only where none is installed, or
it can't be opened, does speech_to_text listen in line as before.

halkyon_app: VoiceInputApp (one listen, an answer once closed) on the
channel app.halkyon/voice_input, which DeviceSpeechInput asks first at
every listen, answering SpeechStart.finished so that Dictation doesn't
listen again; speech_to_text isn't touched on that route, so our app
asks for no microphone. SpeechInput.listen and Dictation.start take the
prompt the voice input app shows (the field's hint).

Each app: VoiceInput.kt (queryIntentActivities, startActivityForResult,
the first of EXTRA_RESULTS) attached in MainActivity, which hands it
activity results, and RECOGNIZE_SPEECH among the manifest's queries.
The privacy pages of Learn and Meditate say so.

Our own Whisper and Meditate's dream recordings are dropped (D18).

Whats-New: The microphone now dictates through your phone's voice input app, such as FUTO Voice Input.
Whats-New-De: Das Mikrofon diktiert jetzt über die Spracheingabe-App deines Telefons, etwa FUTO Voice Input.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:42 +01:00
4940230ef1
perf(learn): a rated card gives way to the next one at once
Rating a card while studying waited for its review to be written, then
for the card's schedule to be replayed, before the next card showed.
StudySessionBloc now starts keeping the review and shows what comes
next at once: the card's new place in the round is worked out from its
reviews with the new one counted as if kept already
(ReviewRepository.schedulesAsStudied's pending, each review counted
once should it be kept by then).

Should keeping it fail, the step leaves the session's Undo, the rating
leaves its accuracy, and the card comes back where it stood, saying so
(withRatingFailed), as a failed rating did before. An Undo of a rating
still being kept waits for it and takes it back once kept; one that
couldn't be kept has nothing to take back, and the Undo has brought
the card back already.

Whats-New: While studying, the next flashcard shows the moment you rate one.
Whats-New-De: Beim Lernen kommt die nächste Karteikarte, sobald du eine bewertet hast.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:42 +01:00
d6b2bec113
perf(learn): flashcards moved in the card browser go at once, in one write
Moving the chosen cards to another studyset wrote them one at a time,
each looking up its privacy keys and writing its row, while the
browser still showed them. CardBrowserBloc now shows the move at once
(gone from here, or after the cards of the studyset they go into where
the browser shows it, _withMoves) and puts them back where the move
fails, counting the failure for the screen's snack bar
(moveFailures, cardBrowserMoveFailed).

CardRepository.moveTo hands the gateway every card's new position at
once (CardGateway.updateStudysets): SyncCardGateway reads them in one
query, checks every card's key before changing any (one private card
among them refuses the whole move, as before for each), rekeys those
that need it, and updates every row in one write and one sync request.
updateStudyset delegates to it.

Whats-New: Flashcards moved to another studyset in the card browser move at once.
Whats-New-De: Im Karteikarten-Browser in ein anderes Lernset verschobene Karteikarten sind sofort dort.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:41 +01:00
107e6f9913
perf(learn): discussions and feedback show what the person does at once
In a discussion, accepting an answer (or none), hiding or showing a post
and deleting one waited for the instance with every action disabled
(busy). DiscussionBloc now shows the discussion as the action leaves it
at once (Discussion.withAccepted, withPost, DiscussionPost.copyWith), the
actions staying available, and puts it back as it was where the instance
refuses (the refusal's snack bar as before) or can't be reached, then
reads it anew. Answering, commenting and editing still wait, as what
the instance makes of them is theirs to say.

In the feedback inbox, a thread opened shows read at once, a failure to
record it said to nobody (the next read shows the truth), and a decision
(closing, reopening, hiding, showing, declining) shows at once and is
put back with the failure's snack bar where it isn't written
(FeedbackThread.seen, decided). Accepting a suggestion still waits, as
it changes the author's content and can fail with SuggestionNotTaken.

Whats-New: Accepting, hiding and deleting in discussions, and closing or declining feedback, show at once.
Whats-New-De: Annehmen, Ausblenden und Löschen in Diskussionen sowie Schließen oder Ablehnen von Rückmeldungen zeigen sich sofort.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:41 +01:00
891e9dfd75
perf(learn): a conversation deleted goes at once, with an Undo
Deleting a kept conversation asked first and then waited while its
turns were blanked and deleted. It now goes as a card or a note does:
ConversationDeletions, a DelayedDeletions opened with the person's
data, takes it off the history at once (the list leaves out what is
pending), offers Undo for a moment on the sheet (hasSnackBars), and
blanks and deletes it once that is over; a deletion that fails shows
the conversation again, as every DelayedDeletions does. The question
before deleting goes, as Undo replaces it.

Whats-New: A conversation with an assistant is deleted at once, and Undo brings it back.
Whats-New-De: Eine Unterhaltung mit einem Assistenten wird sofort gelöscht, und „Rückgängig“ holt sie zurück.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:40 +01:00
920e1c6c13
perf(learn): Delete now leaves Recently deleted at once
Deleting a studyset for good blanks and deletes every card, note, path
and PDF of its subtree before the studyset's row goes, which took about
3 s while the studyset stayed in Recently deleted. Now the repository's
Recently deleted leaves it out at once (StudysetRepository.leaving and
stay, applied to the value last read without reading again), the
deletion runs in the background, still one at a time in
StudysetDeletions' queue, and where it fails the studyset shows there
again, read anew with what is left of it, and a snack bar says so.

Whats-New: Delete now in Recently deleted takes a studyset away at once.
Whats-New-De: „Jetzt löschen“ unter „Zuletzt gelöscht“ entfernt ein Lernset sofort.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:40 +01:00
56f40d4d65
refactor(ui,learn,todo,train,meditate): the navigation bar's one look, the debug section gone
The developer decided on 8 Nov 2026, after trying the variants on the
phone: the wave in the colour of the screen in view, without Material's
ripple, the indicator kept and there at once, a 1.2 s wave, top corners
of 20 dp, the bar's own neutral surface. Learn's bar stays cobalt, the
colour its tabs wash in, rather than its icon's purple.

So the bar has one look: FlushNavigationBar.waveDuration and
cornerRadius are constants, and the debug section goes from the four
Settings screens with what it switched (NavigationBarDebugSection,
debugNavigationBarStyle, effectiveNavigationBarStyle, the style record
and the variants A, C and F, the speeds, the corners and the tinted
surface). Their tests go too; those stating the look kept stay. Learn's
sign-out helper no longer has to scroll past the section.

ADR 0030's amendment of D60, the halkyon_ui README and Learn's
AGENTS.md record the decision and the alternatives set aside.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:39 +01:00
60d53ed262
feat(ui,learn): the navigation bar in the colour of the screen in view
The developer's review of 8 Nov 2026: the bar follows the screen in view
rather than one colour per app, so a Todo project of its own colour gives
the bar that colour while it shows. The wave, the chosen destination's
icon and label and its indicator take ScreenTint.color, the colour the
screen in view claims through its TopGradient; the frame's accent, the
app's colour, stays only for the moment before any screen claims one,
since ScreenTint itself starts at cobalt, which would be wrong for Todo,
Train and Meditate. Learn's tabs claim cobalt, their wash, so its bar is
cobalt there now, not purple.

A colour changing on the same tab (a project opening) passes into the
next over 300 ms, at once with animations off. A wave paints in that
colour as it goes: it starts in the colour of the screen being left, as
the arriving one claims its own only once it shows, a frame later, and
passes into it with the rest of the bar.

A person's colours may be light, so the chosen destination's colour is
made legible (readableTone, halkyon_ui): a palette colour starts from its
own text tone as Todo's dates take it (its outline in light mode, its
fill in dark), any other colour from itself, then darkens towards black
in light mode and lightens towards white in dark, only until it reads at
4.5:1 on the bar and on its indicator. Every palette colour is tested in
both themes, on the neutral and the tinted surface. This also lifts
Learn's label, which read at about 3:1.

The debug section gains Bar surface, neutral or tinted: tinted mixes 6 %
of the screen's colour into the bar's own surface in light mode and 8 %
in dark, changing with it. Neutral by default, and in the shipping style.

Whats-New: The navigation bar takes the colour of the screen you're on, such as a project's own.
Whats-New-De: Die Navigationsleiste nimmt die Farbe des Bildschirms an, auf dem du bist, etwa die eines Projekts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:38 +01:00
45fd6595e1
feat(ui,learn,todo,train,meditate): a wave in the app's colour over the navigation bar
The developer's choice of 7 Nov 2026 (the mockup's variant E): a tap on
another destination sends a radial glow in the app's colour over the bar
from that destination's centre, solid to 35 % of its radius and gone at
70 %, growing to cover the bar (cubic(.2, .7, .2, 1)) while it fades from
half its strength in dark mode and a third in light, over 1.2 s, behind
the destinations and clipped to the bar. None for the destination already
chosen, none with animations off, and none for a tab changed without a
tap (a link, back): the wave answers the finger. The destination chosen
takes the app's colour, its indicator tinted 22 % with it, without
Material's ripple or the indicator growing; the bar's top corners are
rounded, 20 dp, the screen showing through them.

Each app gives the frame its colour (NavigationFrame's accent, from
PaletteColor): Learn's purple, its icon's last colour, Todo's strawberry,
Train's carrot and Meditate's fern, their screens' wash.

For trying it on a phone, a debug build's Settings has a section
Navigation bar (debug), halkyon_ui's NavigationBarDebugSection, switching
live, in memory alone: the variant (A Material only, C the wave with
Material's fill, E without it, F without the indicator too), the wave's
time (0.7 to 2 s) and the corners (0 to 28 dp). Release builds never read
it and show shippingNavigationBarStyle, the debug section's start: to
remove it, delete the section from the four Settings screens and
debugNavigationBarStyle, and let effectiveNavigationBarStyle return the
shipping style.

Whats-New: Tapping a tab sends a soft wave in the app's colour across the navigation bar, now with rounded corners.
Whats-New-De: Ein Tipp auf einen Tab schickt eine sanfte Welle in der Farbe der App über die Navigationsleiste, jetzt mit abgerundeten Ecken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:37 +01:00
05db5e2f45
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.

halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.

Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:37 +01:00
648dfe4051
refactor(learn): the editor's general parts move to halkyon_editor (ADR 0033, D37)
Todo stores editor documents too, so the document, the editor, its view,
the format bar, links, the clipboard, scripts and EditorBlocks move, with
their strings and tests, to a shared package on the same appflowy_editor
fork. What is Learn's alone stays in Learn on top of it, and what the
editor took from it directly is inverted: EditorBlocks gains textMarks,
formatActions and onEditorClosed, RichContentEditor a wrapEditor, and an
InsertableBlock's name takes the BuildContext. Learn's screens use
LearnContentEditor and LearnContentView, which add Learn's blocks and the
grammar check. Learn behaves as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-07 21:49:48 +01:00
34a693f365
fix(learn): a chosen chip keeps its icon
The check Material draws on a chosen chip covered the icon of the rest
day's chip and of the card browser's status chips, as in Meditate. Their
colour says they are chosen, as in Explore's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 22:55:30 +01:00
53313978f1
chore(release): learn-v0.25.0
All checks were successful
CI / check (push) Successful in 47m20s
CI / deploy (push) Successful in 1m2s
Build 28.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 11:06:33 +01:00
23d3bcb4ca
feat(app,learn): the device's appearance and language, halkyon_app's, as Learn's Settings show them
The developer asked for Todo, Train and Meditate to offer Learn's
Appearance and Language (ADR 0014's amendment of 4 Nov 2026). Their
model, store, cubit and card move into halkyon_app: Appearance and Look
(a BCP 47 tag, null for the device's language), FileLookStore keeping it
in the app's support folder as JSON written by rename (per device, not
synced, read before the first frame), LookCubit for the apps to provide
above InstanceGate, and LookSettingsCard / DeviceLookCard with the texts
moved from Learn's arbs (look*, the same words). Each app passes the
languages it speaks, named in their own language.

Learn keeps its stored choice where it was, among its DeviceSettings,
and feeds the shared card from them: no migration, so nobody's language
or appearance moves, and nothing changes on its screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:40 +01:00
a7638e5e54
feat(learn): Settings' dictionaries on this device, one row a language
The developer's review of 4 Nov 2026. "Japanese on this device" becomes
"Dictionaries on this device", with one row a language: its name at the
start, what the device holds or that the download failed beneath it, and
its action at the end (Download with its size, the progress, Remove),
built as a list of rows so Korean's and Chinese's line up beneath
later. Japanese's is the only one now. The help speaks of a language's
dictionaries in general, then of what Japanese's hold (MeCab's, JMdict).

Whats-New: Settings lists the dictionaries on this device by language, each with its own Download or Remove.
Whats-New-De: Die Einstellungen listen die Wörterbücher auf diesem Gerät nach Sprache, jede mit eigenem Herunterladen oder Entfernen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:39 +01:00
12bc31b982
fix(learn): a widget dropped while arranging Home stays where it was dropped, and its handle drags at once
Arranging Home kept no order of its own: a drop showed the old order
until the layout saved came back through the settings, once the
dashboard's changes settled 300 ms later, so the widget snapped back and
then jumped. _Arranging now holds the layout as arranged, shows each
change at once and saves it behind, taking a layout from the settings
only once its own changes are back (or, with none pending, as changed
on another device). The handle was an IconButton with an empty
onPressed inside the drag listener, whose tap and tooltip competed with
the drag; it is a plain icon now, named for screen readers.

Whats-New: Arranging Home's widgets, a widget stays where you drop it, and dragging starts at once.
Whats-New-De: Beim Anordnen der Widgets auf der Startseite bleibt ein Widget, wo du es ablegst, und das Ziehen beginnt sofort.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:39 +01:00
bda09a2959
feat(learn): Add material no longer offers flashcards from a text (ADR 0021, D56 amended)
The developer's review of 4 Nov 2026. The entry goes from a studyset's
Add material, and with it the sheet for pasting a text
(proposeCardsFromText, _TextSheet), its three texts and proposeCards'
fromStudyset, which only it set to false. A note's and a PDF page's
flashcards stay; their tests now drive the proposals sheet from a note.

Whats-New: Add material no longer offers Flashcards from a text; a note's or a PDF page's flashcards stay.
Whats-New-De: Material hinzufügen bietet keine Karteikarten aus einem Text mehr an; die aus einer Notiz oder einer PDF-Seite bleiben.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:38 +01:00
bc4953aaf8
fix(learn,ui): the open assistant field holds still: no flicker, no sliding away, no resizing under the keyboard (ADR 0021, D69)
Inside a studyset the field flickered as it opened and closed: the
floating location switched between a raised centre and the centre,
which Scaffold animates by scaling the button out and in. It keeps one
location now, raised above the licence line by padding. While open it
no longer slides away as the studyset or the Library scrolls
(ScrollHidingFab.pinned, new), and the keyboard covers Home, the
Library, a studyset and a session rather than shrinking them; the field
lifts itself by as much of the keyboard as reaches above it.
NavigationFrame no longer resizes for the keyboard itself, leaving it
to each tab's own scaffold, which still does by default (Todo's,
Train's and Meditate's tests pass unchanged).

Whats-New: Inside a studyset, the question field opens without flickering, stays while you scroll, and the screen no longer jumps when the keyboard comes.
Whats-New-De: In einem Lernset öffnet sich das Fragefeld ohne Flackern, bleibt beim Scrollen stehen, und der Bildschirm springt nicht mehr, wenn die Tastatur kommt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:38 +01:00
f45ed98d52
feat(learn): one assistant field across the app, kept from tab to tab (ADR 0021, D69)
Each screen's button kept its own open state and its own draft, so the
question half written on the Library was gone on Home. ComposerCubit,
provided beside ConversationDockCubit, now holds whether the field is
open and the draft (text, files attached, parts chosen) for every
button. Switching tabs keeps it as it is (AppShell says so before
goBranch); going to another screen within a tab, or over the tabs, keeps
it open only while something is written or attached. Only the button of
the screen at the router's location unfolds, so no tab kept alive
behind holds a second field.

Whats-New: The question you are writing stays open as you switch tabs.
Whats-New-De: Die Frage, die du schreibst, bleibt offen, wenn du den Tab wechselst.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:38 +01:00
b4b27a1d0c
feat(learn,app): the field's row as one, its model by name in its provider's colour, the microphone dictating (ADR 0021, D69)
The developer's review of 4 Nov 2026. Below the question, × and + stand
at the start, who answers is centred and the conversations and the
microphone stand at the end, every button the same rounded square, the
microphone listening and Send too. The row above the text ("Only what I
choose · 2 parts") goes, as +'s sheet offers the same choice; a web
search gets + with that row alone. Who answers shows its model's name
alone ('Haiku 4.5', AssistantProvider.modelName: Anthropic's without
"Claude", others as they are), outlined in its provider's colour (D60).
The microphone is halkyon_app's Dictation: what is said goes where the
cursor stands, and it listens again after each pause until stopped. It
gives way to Send once anything could be sent, as Claude's field does.

Whats-New: The question's buttons are in one row: close and + on the left, who answers in the middle, Conversations and the microphone on the right.
Whats-New: What goes along is chosen under +, for the web search too.
Whats-New: Who answers shows the model's name, in its provider's colour.
Whats-New: The microphone keeps listening after a pause, writing where the cursor is, until you stop it.
Whats-New-De: Die Knöpfe der Frage stehen in einer Reihe: Schließen und + links, wer antwortet in der Mitte, Unterhaltungen und Mikrofon rechts.
Whats-New-De: Was mitgeht, wählst du unter +, auch für die Websuche.
Whats-New-De: Wer antwortet, zeigt den Namen des Modells, in der Farbe seines Anbieters.
Whats-New-De: Das Mikrofon hört nach einer Pause weiter zu und schreibt, wo der Cursor steht, bis du es stoppst.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:37 +01:00
2d27451cb8
fix(app,learn,meditate): a device without speech recognition says so, and how to get one
On GrapheneOS, which installs no recogniser, the microphone did nothing
and stayed listening: speech_to_text's initialize throws a
PlatformException (recognizerNotAvailable) there rather than answering
false, and DeviceSpeechInput let it through. A listen now answers how it
went (SpeechStart: listening, noRecognizer, unavailable) and never
throws; Learn's field and Meditate's dream say that no speech
recognition is installed and name two to install (FUTO Voice Input,
Google's speech services), in halkyon_app's texts. It also passes
androidNoBluetooth, as the apps declare no Bluetooth permission the
plugin would otherwise ask for.

Whats-New: Where the device has no speech recognition, the microphone says so and how to get one.
Whats-New-De: Wo das Gerät keine Spracherkennung hat, sagt das Mikrofon das und wie du eine bekommst.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:37 +01:00
00212bf49c
feat(learn): voice mode goes, as a spoken conversation isn't wanted (ADR 0021, D68 withdrawn)
The developer's review of 4 Nov 2026: "an actual conversation with the AI
chatbot is not desirable and necessary". The field's voice-mode button,
the screen it opened, reading answers aloud and its texts go, and with
them flutter_tts, its patched copy in third_party/ (one override fewer),
the TTS_SERVICE query in the manifest and the plugin's registrants. The
microphone stays and dictates into the question. ImageApproval is the
conversation sheet's own again, as only voice mode needed it.

Whats-New: Voice mode is gone; the microphone dictates into your question.
Whats-New-De: Der Sprachmodus ist weg; das Mikrofon diktiert in deine Frage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:36 +01:00
3310ffa1cd
chore(release): learn-v0.24.0
All checks were successful
CI / check (push) Successful in 45m15s
CI / deploy (push) Successful in 1m0s
Build 27.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 15:29:48 +01:00
438ce20dbf
build: Android's built-in Kotlin, the three plugins applying KGP themselves patched in third_party/
AGP 9 compiles Kotlin itself (android.builtInKotlin=true in every app),
and warns that applying the Kotlin Gradle Plugin will soon fail.
flutter_web_auth_2 5.1.0, keyboard_height_plugin 0.3.0 and flutter_tts
4.2.5 still apply it unconditionally, so their pub releases are copied
into third_party/ with only their android/build.gradle changed, and
the root overrides them by path (third_party/README.md says when to
drop each). The servers' images copy third_party/, as pub refuses an
override whose path is missing. third_party/ isn't our own code: left
out of the analysis and the format check.

All four apps' APKs build without the warning. A Kotlin daemon's
session file that slipped into Train's android/ goes, and every app's
android/.gitignore keeps .kotlin/ out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:13 +01:00
86f221d02f
style(learn): the photo picker formatted
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:11 +01:00
918080ce46
Merge branch 'learn-fb' into integration 2026-11-04 09:32:06 +01:00
df713431dd
feat(learn): the lock beside a studyset no longer changes its privacy, which Edit does
The developer's review of 3 Nov 2026: a studyset is made private, or
non-private, in Edit alone. The lock's sheet still says what its privacy
means, offers publishing one that isn't private, and finishes one only
partly private.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:05 +01:00
830aea10fe
feat(learn,app): explanations wait behind a question mark beside their title
What explains a setting or a section, rather than what is the person's
own, moves behind halkyon_ui's HelpButton, beside its title through the
new ExplainedTitle (the developer's review of 3 Nov 2026): in Learn's
settings (citations, the Pomodoro timer, grammar, the web search,
Jellyfin, the device's dictionaries, counting one's learning), the study
settings, export's progress, the Jellyfin tags and the study button's
back first; in halkyon_app, setting up a password, adding SimpleLogin,
own keys not allowed, the profile page's link back and the operator's
grant sheet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:05 +01:00
c984678c5b
feat(learn): voice mode, a conversation spoken as Claude's "Let's talk" (ADR 0021, D68)
Beside the field's microphone, a button opens voice mode over the whole
screen: a glow rising from below, a big microphone, and +, who answers,
the speaker and End in one row. It listens with the device's recogniser,
asks what was heard in one kept conversation, reads the answer aloud
with the device's speech (flutter_tts, its Markdown left out) and
listens again. On Linux there is none, as there is no microphone; where
nothing reads aloud, answers are shown as text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:04 +01:00
7be31dcbfc
feat(learn): + opens a sheet as Claude's, Camera, Photos and Files, and what goes along in rounded rows
Following the developer's review of 3 Nov 2026 (ADR 0021, D67):

- + below the assistant's field, and below a conversation's follow-up,
  opens "Add to your question" as Claude's "Add to session": three big
  tiles side by side, Camera (where the device takes photos) and Photos
  for an assistant reading images, and Files; below them, in the field, a
  row leading to what goes along, showing how far the assistant looks and
  how many parts are chosen.
- Camera and Photos through image_picker (flutter.dev's own): the camera's
  own app and the system's photo picker, no permission asked on Android, a
  file dialog on the desktop, which has no Camera; photos made at most
  2048 pixels a side, read on the device like any file attached.
- What goes along is chosen in rounded rows, as Claude's Permission, in
  place of radio buttons and chips: how far it looks with a tick, private
  studysets with a switch, the parts each with a tick, a card's image with
  its thumbnail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:04 +01:00
a7904bac05
feat(learn): a studyset is made private in Edit, no longer from its options
The developer's review of 3 Nov 2026: Make private and Make non-private
leave a studyset's options (its card's menu, its screen's); a top-level
studyset's Edit has a Visibility section instead, its switch making it
private, or non-private, at once once the person agreed in the dialog as
before (ADR 0019), not on Save, and what that means behind the question
mark. A topic's Edit offers none, its privacy being its tree's. The lock on
a studyset's card still explains its privacy and keeps its own button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:04 +01:00
96b1a0fc64
feat(learn): the assistant's field spans the screen, its buttons boxed and still as who answers changes
Following the developer's review of 3 Nov 2026 (ADR 0021, D67):

- Unfolded in the Library, the field spans the screen between its margins,
  as on Home and a studyset: it fell short on the right, by the padding
  around the two folded buttons, which now stands only around those.
- Who answers stands right before the buttons at the right, which no longer
  shift as its name changes (Claude Haiku, Claude Opus): it fills the space
  left, aligned to its end, rather than a share of it.
- Every button of the field and of a conversation's follow-up is boxed, a
  tile a shade above the field with rounded corners, as Claude's apps have
  them; who answers too.
- On a studyset with a licence, the unfolded field takes its usual place
  over the licence's line rather than squeezing in above it; folded, its
  row still keeps clear of the line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:03 +01:00
8c70ad98a1
feat(app): an authenticator's key copied, marked sensitive, and its code six digits
A phone without a camera whose authenticator doesn't open otpauth: had no
way but typing the key. It is copied again, the key alone (ADR 0017
amended, the developer's decision of 3 Nov 2026): on Android through each
app's SensitiveClipboard.kt, marked EXTRA_IS_SENSITIVE, so Gboard and the
system show no preview and keep it out of their histories; elsewhere through
Flutter's clipboard. Emptied 60 seconds later if the clipboard still holds
it. The recovery phrase and codes stay never copied.

The code's field counted "/7", taking an optional space for a seventh
character: it now takes six digits alone, a pasted space dropped, and counts
nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:01 +01:00
603218ef96
refactor(app): the device's speech recognition moves from Learn into halkyon_app, with dictation into a text
Learn's `SpeechInput` and `DeviceSpeechInput` (ADR 0021, D67) are
halkyon_app's now, and its `FakeSpeechInput` is in `testing.dart`, so
Meditate's dream journal (ADR 0038, D15) listens through the same code.
Learn imports them from there and behaves as before: its composer and
its tests are unchanged but for the imports, and `DeviceSpeechInput()`
asks for what it asked before.

`DeviceSpeechInput` takes three options, off by default:
- `preferOnDevice`: on Android, recognition on the device where it can
  (Android 12 on), else offline; should that fail before a word is
  heard (not a pause), it listens as Android otherwise does from then
  on.
- `pauseFor`: how long a pause may last before the recogniser stops.
- `listenFor`: how long one listen may last at most.

`Dictation` writes what is heard where the cursor stands
(`DictationInsertion`: in place of a selection, set apart by a space),
shows the words so far, and listens again after each pause while it is
on, stopping by itself after three listens running heard nothing.

speech_to_text moves from Learn's pubspec to halkyon_app's, the lock
unchanged. Todo, Train and Meditate link the plugin now; their
generated plugin registrants (macOS, Windows) say so. An app declares
the microphone itself, and Todo and Train declare none, so nothing
there can listen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:31:58 +01:00
996e584338
chore(release): learn-v0.23.0
All checks were successful
CI / check (push) Successful in 40m57s
CI / deploy (push) Successful in 1m1s
Build 26.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-03 17:47:36 +01:00
ac387b5250
feat(icons): every icon fades from cobalt into its app's backdrop; Learn shows its own inside the app; Train's dumbbell (ADR 0031, D5 to D7)
All checks were successful
CI / check (push) Successful in 41m0s
CI / deploy (push) Successful in 4m37s
Each icon now ends in the colour its app's screens wash down from: Learn cobalt into
purple, Todo through violet into strawberry (Learn's former gradient), Train unchanged
into carrot, Meditate's to come through pacific into fern (Todo's former). Train's glyph
is Lucide's dumbbell, Meditate's will be the sprout.

Learn shows its graduation cap atop the rail, on the launch screen and on halkyon_app's
screens, as Todo and Train show theirs; the kingfisher leaves the app and stays the
F-Droid repository's icon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-02 23:12:20 +01:00
b7b0b937fe
feat(app): one Profile for every app, the person's own tab first, then each app's (ADR 0014)
The public profile was already one per person for every service of an
instance (the register, ADR 0016); its app side was Learn's alone. It
moves into halkyon_app: the model, the repository on the module's
endpoints, the form, the avatar drawn on the device and the sheet with
someone's profile. They take the Public prefix (PublicProfileRepository,
BasePublicProfileGateway), as Train's own ProfileRepository holds the
body's figures. AppDependencies gains profiles and files, the picker the
avatar is chosen with, which moves out of Learn too.

HalkyonProfile is every app's Profile screen: the person's own tab first,
the same in every app (the account and the ways they sign in, the app's
own cards, then the public profile), then the app's own tabs, folding into
the title. Learn adds its inbox and Statistics. Train adds Progress, Days
and, where nothing records, Plans, and so opens on the person's tab, no
longer on Progress. Todo, which has no Profile tab, opens it from a row at
the top of Browse, where Todoist keeps the account.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-02 11:11:11 +01:00
a0bb75f1ad
feat(learn): pick up learning on Home, the studysets studied latest first, and Progress closer to Vaia's
Home gets a widget of its own, Pick up learning, below the goal: the
studysets at the top of the library that were studied, the one rated last
first, so one studied long ago sinks. Three show, the others behind Show
more. Each shows its name, which opens it, how much is learnt, when it was
last studied, and today's task (cards to review, new cards to learn), which
starts studying it, outlined while reviews wait. The progress is the
library's, worked out once for every screen; when each was last studied
comes from the reviews Home reads anyway. With nothing studied it takes no
room.

A dashboard arranged before it gets the widget below the goal, wherever
the goal is: a widget a layout misses now goes after the one before it in
a new dashboard, no longer at the end.

On a studyset's Progress, the tiles are filled without an outline, To
review has a history icon (amber while cards are due), the learnt bar is
thicker, and the exam follows the figures, as Vaia asks for its date
there: an invitation to choose it, opening the study plan's sheet, or,
once chosen, how ready the person is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-02 09:17:07 +01:00
447e00c52a
feat(learn): the assistant's field laid out as Claude's, with files attached and questions spoken, and no Check (ADR 0021, D67)
The question's text stands above its buttons: + attaching files, who
answers as a chip (Effort now a submenu of it), the conversations kept,
and the microphone while nothing is written, which gives way to the
button sending. What goes along is one row above the text, opening a
sheet with how far the assistant looks and the parts to send. A
conversation's follow-up has the same + and microphone.

Files are read on the device: an image goes as itself to an assistant
that reads images, a PDF as its pages' text, a text file as its text,
each cut at 20,000 characters and labelled by its name after the
question.

Voice is the device's own speech recognition (speech_to_text: Android,
Apple, Windows; none on Linux), in the app's language, the microphone
asked for once tapped. The privacy page says that Android's recogniser
may send the sound to Google or the phone's maker.

The field's Check goes, with its LanguageTool sheet (amending ADR 0024);
the editors' underlining and Why? stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-02 08:46:37 +01:00