Commit graph halkyon/apps/todo/halkyon_todo_flutter/test
Author SHA1 Message Date
e11ed481ce
feat(todo): a sub-task opens in its task's sheet, back returning to it
A sub-task tapped in a task's sheet opened a sheet of its own over it,
so Grocery List > Dairy > Milk stacked three. It now takes the sheet's
place, as the steps of the sheet's path already did (TaskTile's onOpen),
and the sheet keeps the tasks it showed: the system's back returns to
the last. Back is caught with a BackButtonListener, not a PopScope,
which would also hold back a tap beside the sheet, a swipe and Escape:
those close the sheet whole. A picker open over the sheet is closed by
back first.

Whats-New: A sub-task opens in its task's sheet instead of over it; back returns to the task.
Whats-New-De: Eine Unteraufgabe öffnet sich im Blatt ihrer Aufgabe statt darüber; Zurück führt zur Aufgabe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:35 +01:00
a71d80fc2d
fix(todo): a task row's check stands by its title's first line
The round check sat in the middle of the row, so on a row with a
description, a date or a long title it stood below the title. As
Todoist's it now stands by the title's first line. ListTile centres its
leading or tops it at its padding, never at the title's line, so the
check and the texts share the tile's title, the texts lowered by half
of what the check's 48 dp tap target is taller than a line (computed
from the text scale, the tap target kept).

Whats-New: A task's circle stands beside the first line of its title.
Whats-New-De: Der Kreis einer Aufgabe steht neben der ersten Zeile ihres Titels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:34 +01:00
8a677e0845
feat(todo): Today counts its tasks under its title
As Todoist's, Today's app bar says how many tasks it holds, those
overdue and those due today together ("3 tasks"). TabScreen takes an
optional subtitle for it, left out while tasks are being chosen, when
the title counts those instead.

Whats-New: Today says how many tasks are overdue or due today under its title.
Whats-New-De: „Heute“ zeigt unter dem Titel, wie viele Aufgaben überfällig oder heute fällig sind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:34 +01:00
b043d5ef9e
fix(todo): editing a project keeps its Display
Edit project built the project anew from its name, colour and position,
so saving it reset its Display (layout, grouping, sorting, filters) to
the first one. It now changes the name and colour of the project as it
is.

Whats-New: Editing a project no longer resets its Display.
Whats-New-De: Ein Projekt zu bearbeiten setzt seine Anzeige nicht mehr zurück.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:34 +01:00
33917c6042
fix(todo): a time picked in the date sheet kept however the sheet closes
The date sheet returned a date only from its days and No date: a time or
a duration picked and the sheet then closed by its X, a swipe or a tap
beside it gave nothing back, so the task kept no time. The sheet now
keeps the date the time makes as it is picked, on the task's day or
today where it had none (as Todoist), and pickTaskDate returns it when
the sheet closes without a choice. Quick add uses the same sheet.

Whats-New: A time picked for a task's date is kept, however you close the Date sheet.
Whats-New-De: Eine Uhrzeit für das Datum einer Aufgabe bleibt, wie auch immer du das Blatt „Datum“ schließt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 08:58:33 +01:00
ef80453fa0
feat(todo,meditate): what a setting does behind its question mark
The developer's review of 3 Nov 2026 (ADR 0033, D25): an explanation stands
one tap away, behind halkyon_ui's HelpButton beside the setting's name,
rather than always below it. Todo: resetting sub-tasks, the automatic
reminder (its value stays below), counting a recurrence from completion.
Meditate: keeping the screen on, the streak, the morning's dream prompt.
What is the person's own (a value, a count) stays in view; an empty list's
message and quick add's hint about highlighted words, shown only while
there are some, stay too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:08 +01:00
140a283d0e
feat(todo): a task's sheet partway up and its parts in rounded boxes, as Todoist's
The developer's review of 3 Nov 2026 (ADR 0033, D24): on a phone the sheet
opens as high as its content, at most 65 % of the window, the list above it
in view, and is dragged up to the whole window or down to close; its title,
description, date and reminders each in a rounded box, its priority, labels,
deadline and project as a row of chips (named "Priority", "Labels",
"Deadline" while unset), and its sub-tasks in a box ending in Add sub-task.
Where sheets are dialogs, and in the pane beside the list, the same parts.
Todo keeps no comments, so the sheet has no comment field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:07 +01:00
8438caa489
feat(todo): quick add a small bar docked above the keyboard, as Todoist's
The developer's review of 3 Nov 2026 (ADR 0033, D23): in place of the tall
sheet with its title and Add button, a rounded bar just above the keyboard,
the list still in view behind a lighter barrier: the title, then a row of
boxed buttons (+ for the description and the deadline, the date, the
priority, the labels, the project), each its icon alone until something is
set, and a send button. Its buttons show from the start rather than once
typing begins (D15 had them come with the first letter). Where sheets are
dialogs, the same bar in a dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:07 +01:00
c7ad78f88d
feat(todo): Display's layouts as pictures with radio buttons, its rows grouped in rounded boxes
As Todoist's (the developer's review of 3 Nov 2026, ADR 0033, D22): each
layout a phone's outline with its picture, its name below on one line (no
"Calenda/r" split across two), a radio button marking the one in use; the
switches, the sorting and the filters each a group in a rounded box under a
plain heading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:06 +01:00
753527aed3
feat(todo): rows in rounded boxes, Today as Todoist's, lists pulled to sync, a project's own colour
From the developer's review of 3 Nov 2026 (ADR 0033, D19 to D21):
- Today's tab shows today's day in its calendar, Browse the menu's lines,
  Display's button Lucide's square-menu.
- A task's row stands in a rounded box, the rows of a list a group rounded
  at its ends; the box is the row's own surface, so a chosen row's colour no
  longer shows under Upcoming's pinned week strip as the list scrolls. Its
  project and section end the line of its date at the row's right edge.
- Today has at most two groups: what is overdue, folding under its heading,
  and today's, headed "Tuesday, 3 Nov" ("Dienstag, 3. Nov."), without a
  "· Today" after it; Upcoming's days take the same form.
- Upcoming's way back to today shows whenever another day is picked.
- Today, Upcoming, the Inbox and every project pulled down sync now, an
  empty list too, as Learn's.
- A project's screen washes in its own colour, as a studyset's in Learn.
- "Add section" in place of "New section".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:32:06 +01:00
f5b657dfad
feat(todo): reminders at a time of their own planned and set in a task's sheet, durations in its date sheet
planReminders plans each reminder at a time of its own of an open task,
whatever its date, under an ID of its own; the notification says
"Reminder" for a task without a time. The task's sheet always has its
reminders' row: those before its time where it has one, those at a time
of their own each with its remove button and "Remind at a time" (a day,
then a time), the permission asked as a first one is chosen. The date
sheet sets a duration once there is a time (none, 15 minutes to 4
hours, as Todoist's), a time cleared taking it with it. Recorded as
ADR 0033, D18 (the developer's, 3 Nov 2026).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:31:55 +01:00
d40eca6e50
feat(todo): quick add reads on before a day, durations, every !30m and !1pm
`on` (German `am`) before a day is taken with it, as `at` before a time;
`for 2h`, `for 1h30m`, `for 90 min`, `für 1,5 Std.` set the date's
duration where there is a time, and stay text without one; every `!30m`
counts, each once, sorted, a task without a date due at the latest; and
`!1pm`, `!13:00`, `!tomorrow 9am`, `!Monday 8:30` are reminders at a time
of their own, a time without a day on the task's day, else the next to
come. Todoist's newsletter's four examples parse whole (ADR 0033, D18).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:31:55 +01:00
3c68a22a5f
feat(todo): a task holds reminders at a time of their own, and keeps the fields it doesn't know
ReminderTime is a day and minutes after midnight, the wall clock without
a zone as TaskDate's; a task's reminderTimes are written as
[{"day", "time"}] and left out where there are none, so older payloads
read with none. The payload's schema stays 1 (as D17's view): what a
newer version wrote at its top that this one doesn't read is kept in
TaskContent.unknown and written back beneath the fields it knows, so a
task changed here keeps it (ADR 0033, D18).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 09:31:54 +01:00
e61d3abb4f
build(todo): Todo deployable beside Learn's server, and released as an APK, on F-Droid and as a snap (ADR 0033, step 5)
deploy/compose.todo.yaml adds Todo's server at todo.halkyon.eu, a member
of Learn's register, its database halkyon_todo in the instance's
PostgreSQL, its image built as Train's. redeploy.sh and backup.sh go over
every app server .env switches on (train, todo). Each compose file names
its server to the register in a variable of its own
(INSTANCE_MEMBER_TRAIN, INSTANCE_MEMBER_TODO), which halkyon_base adds to
INSTANCE_MEMBERS, each address once, as a second compose file's default
would have replaced Train's.

apps/todo/release.dart configures the release tool for Todo's APK and
snap: a key of its own (pinned once made; until then nothing is
released), the F-Droid listing (Time, NonFreeNet), and the snap from
apps/todo/snap/, which the tool builds in a clone of the repository at the
tag with that folder in place of snap/, as snapcraft builds one recipe a
folder and the root's is Learn's. What's new for 0.1.0 in English and
German, now shown. Android's backup and transfer are off, as Train's
(D53): the reminders scheduled keep their tasks' titles unsealed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-02 16:04:00 +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
e26ba47fb9
feat(todo): Snooze on a reminder on iOS, macOS and Windows (ADR 0033, D4)
Apple's systems take actions from categories registered at start: one
for each length a snooze can be, its action in the language the app
starts in, not to the foreground, so that iOS snoozes in the plugin's
isolate with the app closed (AppDelegate registers the plugins for it).
Windows hands back only the button's arguments, which carry the
notification's ID and payload. macOS and Windows launch the app for an
action while it is closed, and the gateway snoozes what launched it as
it starts. Not yet tried on any of the three devices.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 21:57:00 +01:00
0b6f79244f
feat(todo): a project's Calendar as a month on wide windows (ADR 0033, D17)
From 720 pixels of the Calendar's own width on, a month grid in place
of the agenda: the month's weeks from the week's first day, the days
of the months beside it muted, each day with as many of its tasks as
fit and the rest counted, opening the day's tasks in a sheet; past
days with their overdue and done tasks. A task held and dropped on
another day moves there (moveTask), a day's free space tapped adds a
task on it, a line tapped opens its task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 21:57:00 +01:00
0373f723e7
feat(todo): 3-day grid's blocks dragged to another day and time, or onto All day (ADR 0033, D17)
A block held and dragged moves its task to another of the three days
shown and another time, its top snapping to a quarter hour, the time it
would take shown under the pointer, its duration, recurrence and
reminders kept; dropped on a day's All day it loses its time and
duration. Either can be undone for a moment. A later time of a repeating
task doesn't move. DayDropArea's move is now moveTask, shared by both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 21:56:55 +01:00
51ebed41cd
feat(todo): Settings' Tasks and Reminders, with Snooze on a reminder (ADR 0033, D4)
Settings gains Todo's own groups, kept in the person's sealed settings
row on every device. Tasks: the weekday weeks start on (the language's
unless set), which the week strip, the date and repeat pickers and the
filters follow; and whether a recurring task done opens its sub-tasks
again (on at first). Reminders: an automatic reminder (none at first)
that TaskRepository writes into a task gaining a time without reminders
of its own, and how long a reminder is snoozed for (15 minutes at first).

Each reminder's notification has a Snooze action on Android and Linux:
the reminder comes back that much later under an ID of its own,
scheduled from what the notification carries, so on Android with the
app closed too (the plugin's ActionBroadcastReceiver declared); the plan
of the person's reminders leaves snoozed ones alone. iOS, macOS and
Windows get it later.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 20:25:15 +01:00
2939437c74
feat(todo): a project's Calendar, Upcoming's Display and its 3-day grid (ADR 0033, D17)
A project's Display gains the Calendar layout: Upcoming's week strip
and agenda, now shared as DayAgenda, over the project's tasks it keeps,
with No date beside the month and Future occurrences, each repeating
task also on the days it will come back (calendarOf on Repeat.next),
muted, neither ticked off nor dragged.

Upcoming gets a Display of its own, the same sheet over another target
(DisplayTarget): Agenda or 3-day, done tasks, future occurrences,
sorting, the filters by deadline, priority and label, and in the grid
Colouring by priority, label or project. It is kept in the person's
settings, one sealed row under an ID keyed by the account in the new
synced table todo_settings (migration settings: the table, its index
on spaceId and its foreign key to the space, cascading on delete).

The 3-day grid shows today and the two days after, stepped or swiped
three at a time: tasks without a time all day, timed ones as blocks as
long as they last, overlapping ones side by side (layOutDay). A long
press on a half hour adds a task there for half an hour; Overdue opens
the overdue tasks with Reschedule.

The board's separator builder names its BuildContext, as the root's
analyzer plugin asks (never_discard_build_context).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 20:01:00 +01:00
e4fbfb54d1
feat(todo): a project laid out as a board, its columns its sections (ADR 0033, D17)
The Display's new Layout picks List or Board. The board has a column
for the tasks in no section, then one a section with its menu, each
task a card and each column ending with Add task, a last column adding
a section; grouped otherwise, a column a group. Narrower than a medium
width it pages one column at a time with dots below; from it on the
columns stand side by side. Cards drag within and between columns as
rows do (D16), every scrollable they are in scrolling at its edges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 18:51:15 +01:00
7d1de304c8
feat(todo): each project's Display: completed tasks, grouping, sorting and filters, synced (ADR 0033, D17)
- A Display button beside a project's menu (the Inbox's too), a dot
  on it while the project shows otherwise than at first, opens its
  sheet: completed tasks, grouping (date, deadline, added date,
  priority, label), sorting (name, date, deadline, added date,
  priority), filters by date, deadline, priority and label, and
  Reset all.
- The choices live in the project's sealed payload (ProjectView,
  written only once set), so every device shows the project alike.
- Grouped, the groups stand in the sections' place under pinned
  headings; rows are dragged only while sorted by hand by sections.
- Show done tasks moves from the menu into Display.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 18:41:12 +01:00
c83f7c46ff
feat(todo): Upcoming's tasks dragged onto another day (ADR 0033, D16)
A row of Upcoming, overdue ones too, held and dropped on another day
moves there, its time, duration and recurrence kept; Moved to … offers
Undo. The tint over a day a drag hovers is laid beside the rows, not
around them, which paint on the Material beneath.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 17:58:06 +01:00
7fe74ed0d5
feat(todo): quick add suggests projects and labels as # and @ are typed (ADR 0033, D15)
Up to five projects or labels whose name, or a word of it, starts with
what follows the symbol show below the title; one tapped completes it.
None for a symbol inside a word (C#), nor once a name is typed whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 17:32:52 +01:00
36f1e9a25c
feat(todo): tasks dragged into place or under another, the add button dropped where the task goes (ADR 0033, D16)
- A project's row, held, is dragged before or after another, or a
  little to the right to become its sub-task, or onto a section's
  heading; its sub-tasks go with it, and Order changed offers Undo
  (TaskRepository.place). The list scrolls at its edges.
- The add button is dragged onto a project's list to add the task
  between two rows, onto a day in Upcoming for that day, onto Today
  for today; dropped back on its place, an ×, it gives up.
- Holding a row now drags it; a swipe to the right selects it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 17:28:37 +01:00
4960234a63
feat(todo): tasks chosen together, quick add reading what is typed (ADR 0033, D14, D15)
- A section's heading stays atop a project's list while its tasks
  scroll beneath it (slivers, PinnedHeaderSliver).
- Upcoming's month unfolds in place beneath its strip, from its name
  or its handle; a button beside the month goes back to today.
- Tasks are chosen together: a row swiped right or held, or Select
  tasks in Today's, Upcoming's and a project's menu; a bar of date,
  move, labels, priority and more (complete, duplicate, deadline,
  delete) takes the navigation bar's place. A row swiped left asks
  for its date.
- TaskRepository.move moves tasks with their sub-tasks.
- parseQuickAdd reads #project, @label (an unknown one made),
  {deadline}, !!1 and p1 to p4, !30m, dates, times and recurrences
  (tomorrow 9am, Mon 18:00, ev Tue 7pm, every 2 days, every weekday),
  from a table of words per language: English, and German beside it.
- Each token is highlighted and shown on its chip; a tap keeps it as
  text, and a chip picked takes it out of the title.
- Quick add shows its title alone at first, its chips once typing
  starts, and the description and deadline behind its + (the
  description also from the down arrow).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 16:53:59 +01:00
b908019969
feat(todo): dialogs on the desktop, the tabs reordered, a task's path and menu (ADR 0033, D11 to D14)
- halkyon_ui: showAdaptiveSheet shows a dialog on Linux, macOS and Windows
  at every width (bottom sheets stay on phones and tablets below expanded
  windows), so Learn and Train follow; SheetScaffold takes a heading in
  the title's place and may leave out its close button.
- Todo: the tabs are Inbox, Today, Upcoming, Browse, Today still opening;
  `serverpod start` launches the app on Linux, as it has no web build.
- A task's sheet shows where the task is (its project, an icon once tasks
  are above it, and the tasks above it, each opening what it names) and a
  ⋮ menu in place of its close button: when it was added (its UUID v7),
  Duplicate with its sub-tasks, hiding its done sub-tasks (synced in its
  payload), Close in the pane, Delete after asking. The description's icon
  stays by its first line.
- A row names its project and section at the end of its date's line; every
  menu entry has its icon.
- Learn: a studyset's path starts at the Library tab's icon, named by its
  tooltip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 16:53:38 +01:00
666e8dbcbb
feat(todo): reminders on the device, Upcoming's week strip, the task pane and search (ADR 0033, D2, D5, D8)
A task with a time takes reminders, minutes before it, in its sealed
payload; each device plans the coming ones whenever the tasks change and
schedules them with the system through flutter_local_notifications
(Android, iOS, macOS, Windows; on Linux the running app shows them), at
the minute where Android allows exact alarms. Notifying is asked for
when a task first gets a reminder; signing out or switching person
cancels them. Upcoming gets its week strip: the month opening
Material's calendar, the weeks before and after, a dot under each day
with tasks; a day picked scrolls the agenda to it, and scrolling moves
the strip along. From expanded windows on, a task opens in a pane
beside the list rather than in a dialog. Search, from every tab's app
bar, finds projects by name and tasks by every word typed, in their
title, description or labels, whatever the case and accents, on the
device alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 12:16:19 +01:00
aa013f5a00
feat(todo): recurring tasks, set through a picker (ADR 0033, D7)
A task's date may recur: every n days, weeks (on which weekdays),
months (on its day, or its nth or last weekday), years, from its date
or from when it is done, until a day or for n times. Done, it moves on
to the next day after both its date and today, its deadline as far, its
time kept, its done sub-tasks open again and when it was done kept in
its payload; undo writes all of it back. The date sheet offers the rules
that fit the task's day and a rule of the person's own; rows show a
recurring date with its own icon, the task sheet the rule in words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 12:15:51 +01:00
030c62ddde
feat(todo): Today, Upcoming, Inbox, projects, quick add and the task sheet (ADR 0033, D8, D9)
The tabs hold the person's tasks: Today what is overdue (Reschedule
moving it all to a day, times kept) and what is due today; Upcoming the
overdue ones and the next four weeks day by day; Inbox and each
project's screen from Browse the tasks above and in their sections, done
ones on asking; Browse the projects with their open counts and the
labels. A task's row shows its check in its priority's colour, its date
in the colour of how near it is, its deadline, its sub-tasks done and
its labels; quick add takes its title, date, priority, project, labels
and description and stays for the next; its sheet edits all of it, adds
sub-tasks and deletes it with them after asking. Colours are the
palette's, cerise for overdue and P1 against the strawberry wash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 10:25:34 +01:00
bd3710ae58
feat(todo): the person's tasks, sections and labels, sealed and synced (ADR 0033, D6)
A table's rows are sealed for their table and row by one SealedRows,
which the repositories of projects, sections, tasks and labels share,
each table with its own sync gateway, a deletion blanking its rows first
in one transaction. A task's payload holds its title, description,
project, section, parent, place, date (a day, an optional wall-clock
time and duration), deadline, priority, labels and when it was done;
deleting a task deletes its sub-tasks, and a project or a section goes
with its tasks. Rows that don't open show locked; a device without the
account's keys writes nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 01:14:54 +01:00
60a8f5b617
feat(todo): the person's projects, sealed and synced, the Inbox made once (ADR 0033, D5, D6)
TodoPerson opens the person's own sync database in their folder,
halkyon_app's SyncService behind AppCompatibility, their key (TodoKeys,
Train's copied with Todo's own key IDs) and their projects, and closes
them in that order, the key last. A project is sealed for its row; a
readable, foreign or moved row shows locked, and a device without the
account's keys reads and writes nothing. The Inbox is the row under an
ID keyed by the account, so every device makes the same one and the
instance can't tell which it is; it can't be deleted. Settings shows
Sync's card first and the cog its dot while sync fails, as Learn's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 01:05:31 +01:00
492c657980
feat(todo): the four tabs in Todo's frame, washed in strawberry, Settings from Browse
ADR 0033, step 1: go_router with a StatefulShellRoute and halkyon_ui's
NavigationFrame as Train's (D1), the tabs Today, Upcoming, Inbox and
Browse, each saying tasks come later (D2), every screen washing down in
strawberry (D3), and Settings over the tabs from Browse's cog, grouped in
cards: the operator's, the account, What's new and About Halkyon Todo,
the version below (D4). The account sheet and the empty home go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-01 00:57:44 +01:00
36899cdc3b
feat(app,learn,todo): the assistants in Settings and on the operator's screen
ADR 0021, step 2's app half. halkyon_app asks the module's assistant
endpoints (ServerpodAssistantGateway, ServerpodAssistantOperatorGateway)
and a person's own provider directly (halkyon_llm), behind
AssistantRepository: an AssistantChoice is a GrantedAssistant, asked
through the instance, which counts it, or a PersonalAssistant with the
person's own key, which the instance never sees. assistant_messages.dart
turns a conversation into the endpoint's models and back.

AssistantsCard, for an app's settings: what is granted and left of its
limits, agreed to once on a sheet saying what goes where, the person's
use by UTC month, the instance's privacy page, and their own assistants
where the operator allows own keys (kept ones stay listed, unasked,
where it doesn't). AssistantGrantsCard on InstanceOperatorScreen: grants
by handle with their limits in the pricing's unit, changed and taken
back after asking, everyone's use by month; a found account's menu
grants too. Nothing shows where nothing is offered or can be read.
package:halkyon_app/assistant_models.dart holds the models in pure Dart.

Learn keeps own assistants in the person's settings (ownAssistants,
schema 12, SettingsOwnAssistants); SettingsRepository.update refuses
(OwnAssistantRefused) to write a key where the settings would not be
sealed (SettingsGateway.seals). Learn depends on halkyon_llm directly.
Todo wires the gateways; a member offers no assistant. No feature asks
an assistant yet (step 3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-26 07:17:07 +01:00
31b9c17850
feat(app,learn,todo): the operator's "This instance" card, screen and badge (ADR 0021, step 1)
Whoever operates the instance approves, refuses and suspends accounts
and names other operators in the app (D21 to D24, D34):

- halkyon_app: InstanceOperatorRepository on
  ServerpodInstanceOperatorGateway (the module's instanceOperator
  endpoint; refusals as OperatorFailed: notFound, isOperator,
  lastOperator, notAllowed for 401 and 403, failed), in AppDependencies.
  OperatingCubit counts the accounts that wait: asked as the person's
  app opens, after every change, and every 5 minutes only while they
  operate the instance, so nobody else's app keeps asking.
  InstanceOperatorCard (or its tiles) and WaitingAccountsBadge show
  nothing at all for anyone else. InstanceOperatorScreen, laid out as
  Settings: the accounts that wait, each showing its four words to read
  out before Approve (D33), Refuse for new ones after asking; who
  operates, Take back after asking, the last always kept; Name an
  operator by handle; Find an account by the start of its handle, with
  Suspend after asking and Name as operator. English and German texts
  ("Admin" as the role word in German).
- Learn: the card right after the Sync card in Settings, which the
  cogs' count leads to as their dot leads to Sync; the count on the
  Settings cogs of Home and Profile.
- Todo: the tiles in the account sheet and the count on its button.
  Todo's server is a member, whose `operating()` is always null, so
  nothing shows there until it holds the register.

Tests: the gateway's mapping, the repository, both cubits with their
denials, the card, the badge and the screen; Learn's Settings shows the
card and the count to an operator and neither to anyone else.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-26 07:17:05 +01:00
4e33133733
feat(base,app)!: GitHub signs nobody in any more (ADR 0020, D36)
Every account signs in with SimpleLogin or a password now, so GitHub
goes from the module, the shared app package, Learn and Todo, ahead of
ADR 0017's GITHUB_SIGN_IN_ENDS.

- halkyon_base: no `gitHubSignIn` endpoint, GitHub identity provider or
  GitHub refusals; no `githubClientId`/`githubClientSecret`, no
  `GITHUB_SIGN_IN_ENDS` and no `forgetGitHubAccounts`; the register
  loses `account-with-github`. `SignInWays.gitHub`, the basics'
  `gitHubClientId` and `gitHubSignInEnds`, and `PasswordRefusal`'s
  `signInAgain` and `noAddress` go. A first password takes a code
  mailed to the person's own address; an account without one sets none
  (`wrongCredentials`).
- Learn's server: `instance.info()` without `gitHubClientId`, the
  pruning without GitHub, and `minimumAppBuild` 24, as builds up to 23
  (v0.20.0) require `SignInWays.gitHub`: the server deploys with the
  release of build 24.
- halkyon_app: no GitHub button or problems on the start screen, no
  password offered after a GitHub sign-in, and `ServerpodAuthGateway`
  without the browser half only GitHub used (`(client, base:)`). The
  account section offers a first password only to an account with an
  address. `LoopbackWebAuth` and the apps' schemes stay, SimpleLogin's
  ways back.
- Learn's Profile lists no GitHub; the texts go (English, German).
- Serverpod's `serverpod_auth_idp_github_account` stays, as its
  migrations make it; a row goes with its account, and ADR 0020's D36
  gives operators the SQL to delete those left.
- deploy/: compose.yaml and .env.example without GitHub. The READMEs,
  AGENTS.md files and ADR 0017 amended.

BREAKING CHANGE: builds up to 23 can't read the instance's answers
about an account's ways in; minimumAppBuild is 24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-26 07:16:39 +01:00
5b9df73756
feat(app)!: no anonymous accounts on the device (ADR 0020, D4, D25)
Every account has a way in, so the apps make no anonymous account any
more. The start screen shows whenever nobody is signed in, a first
start included, and offers SimpleLogin, a password and GitHub for those
who have it, with no start without an account. An instance out of reach
is said so, with Try again, and one offering no way to create an account
too. An anonymous account's session left from before is deleted as the
app starts (D25), falling back to signing out on the device.

What only anonymous accounts needed goes: signing in anonymously, the
signed-out mark, adding GitHub to an account and switching to a GitHub
account from the Profile tab (with its Cancel, the only one), an
anonymous device's own keys, the warning that signing out deletes the
account, and the texts about keeping progress. Settings says on which
instance the account is signed in. Learn's publishing, reports and
suggestions and its learner count no longer ask whether the person has
an identity: everyone signed in has one.

The server still offers anonymous sign-in until the next commit, so
older apps keep working until v0.20.0 raises the minimum build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 16:14:37 +02:00
fad12b4411
feat(app): adding SimpleLogin to an account (ADR 0020, D21, D23)
All checks were successful
CI / check (push) Successful in 32m34s
CI / deploy (push) Has been skipped
halkyon_app reads where the device's person stands with SimpleLogin
(nothing to show, linked, or missing) and shows it in SimpleLoginSection,
which each app places above the password part: Add SimpleLogin, once
added one more way in. GitHub is added to nobody where SimpleLogin is
offered, and Learn's Profile offers an anonymous person SimpleLogin
alone there (D23).

No cut-off day, reminder or banner (D24): with the developer the only
person on learn.halkyon.eu, the cut-off is the operator taking GitHub's
OAuth app out of the deploy's settings once that account has SimpleLogin.
ADR 0020 records it and drops step 5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 13:00:28 +02:00
3a93dc4fd8
feat(app): signing in with SimpleLogin, its sheet and the start screen's offer (ADR 0020)
All checks were successful
CI / check (push) Successful in 31m49s
CI / deploy (push) Has been skipped
Where the instance offers SimpleLogin, the start screen offers it first,
saying that the instance keeps only the SimpleLogin ID, and opens a sheet
that waits for SimpleLogin's page in the browser (Cancel ends the wait),
then: for someone new, the choice between creating an account (the
suggested handle or another, checked with the instance, the password
twice, the recovery phrase shown once and three of its words typed back,
nothing reaching the instance before) and linking theirs again with its
handle and recovery phrase; for an account, its password opening its
keys; for an account of before, the keys made with the handle it lacks.
SimpleLoginCubit holds the steps, each refusal shown where it is mended
(a handle's on the handle, a sign-in to begin again on the browser's),
and closing the sheet stops waiting on the loopback.

The suggested handle is never checked: the instance suggests none that
anybody has, and every answer about a handle counts against its limit
(D5). The fake's handle rule is now the module's.

Learn and Todo build it with SimpleLogin's browser (halkyon_oidc_flutter,
now a direct dependency of both, with their names on the loopback's
page), their schemes and their loopback ports (43823, 43824), as the
instance's forwarding page has them. Their tests offer no SimpleLogin;
halkyon_app's test the sheet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-24 09:17:50 +02:00
24ccf2a0ab
fix(todo): what failed on the account sheet shows on it
The sheet holds snack bars of its own (`hasSnackBars`), so a failed
deletion, sign-out or reading of the account says so on it rather than
behind its barrier.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-23 14:13:07 +02:00
19aabb0266
fix(app): GitHub's refusals say why, and no hint adds GitHub where passwords are offered
Where an instance offers password sign-in, GitHub is added to nobody (ADR
0017, D2), yet the start screen still said "then add GitHub" after a GitHub
account nobody has, and every refusal but an unknown account read
"Couldn't sign in with GitHub." (the end-to-end test of 21 Oct).

- The gateway tells from one read of the basics whether GitHub signs in and
  whether it is added to people (`gitHubOffer`, in place of
  `gitHubClientId`); the GitHub bloc keeps it (`Ready.linking`) for the
  profile, with why an attempt failed (`Ready.problem`).
- The instance's `usePassword`, `deprecated` and `ended` become problems of
  their own (`gitHubSignInProblemOf`), worded by `gitHubProblemText` and on
  the start screen; an anonymous person refused a link is told the GitHub
  account is nobody's and offered the password instead.
- Where passwords are offered, the start screen offers an account to create
  in place of the app's hint on adding GitHub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-23 14:13:06 +02:00
012f2375a5
fix(app): the short reading's nits on the device
- Deleting an identified account whose security can't be read (the
  instance out of reach) says so and deletes nothing; it went on to a
  deletion by the session alone, refused for an account with a password,
  and the person saw a spinner, then nothing. A refusal still leaves the
  session's own deletion.
- InstanceChoice's sharesStorage is required, so no app leaves it out and
  removes a folder another instance uses.
- A PasswordUnlock forgotten is spent: its secrets read again fail
  (StateError) rather than make a proof or a wrapping of zeros.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-23 14:13:05 +02:00
a4819c3d39
feat(app): sign in with a password and TOTP on the device
ADR 0017, step 3: halkyon_app's side, which Learn and Todo take.

- The account's cryptography on the device (`SodiumAccountCrypto`):
  halkyon_keys and SRP's client half, each step on an isolate of its
  own. sodium hands out results as views of native memory its
  finalizers free once the isolate that made them ends, so everything
  crossing back is copied first: a view read freed memory and crashed
  the process.
- `PasswordGateway` on the module's endpoints (steps without a session
  through a client holding none; an authenticator set up with a session
  granted but not yet the device's), and `PasswordRepository` running
  the flows: signing in (M2 checked, the keys opened before anything is
  trusted), signing up, a password for someone signed in, an account
  never finished, the authenticators, recovery codes, changing the
  password, a new recovery phrase, and getting back in.
- The unlocked keys in the system's keyring per instance and person
  (`SecureAccountKeyStore`), gone once another person signs in or
  nobody, and with the instance's removal.
- The screens: the start screen's Sign in and Create an account (and
  when GitHub sign-in ends), the sign-in sheet (codes, recovery codes,
  an account never finished, a lost authenticator), the account's setup
  (the recovery phrase shown once, three random words typed back before
  anything reaches the instance; the authenticator's QR code, drawn
  with pub.dev's qr; the recovery codes), getting back in, and the
  account section (`AccountSecuritySection`).
- `FileSaver` moves from Learn into halkyon_app, for the phrase and the
  codes in Todo too; `AppDependencies` names it and `passwords`.
- halkyon_keys rebuilds account keys from the secret keys a device kept;
  the key proof's message is in halkyon_base_client, checked against
  the register's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-23 14:12:41 +02:00
87500b7c6b
refactor(halkyon_app): the account section, About, the language and countries' names, shared
What Learn and Todo each held now comes from halkyon_app:
- AccountTiles: whose account on which instance, switching, signing
  out (asking first for an anonymous account, as it deletes it) and
  deleting it (asking first), the app's own words passed in.
- showAppAbout: the app's name, version, icon and legalese as it gives
  them, the source of what the instance runs (AppDependencies gains
  sourceCodeUrl), the app's own parts, the licence list.
- resolveAppLocale: the first preferred language the app speaks, never
  by country alone, British English otherwise.
- AssetCountryNames, the default of InstanceGate and InstanceScope:
  Unicode CLDR 48.2's territory names in English and German
  (tool/country_names.py, 7.6 KB), Hong Kong, Macao, Myanmar and
  Palestine by their short names as Learn's world map has them, so
  Todo says "Germany (EU)" where it said "DE (EU)".

Learn's texts read as before in every language; its About bloc and
gateway, its country names from the world map and the keys only the
moved code used are gone, as are Todo's copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-22 18:11:08 +02:00
6871e3763b
feat(todo): the app on halkyon_app, with its own icon
Todo's app is halkyon_app's instance and session gates with Todo's
frame ("Todo" under "Halkyon", its icon, its own sentences) and an
instance check accepting only `todo`; TodoDependencies on an instance,
an empty TodoPerson per person, nothing kept or synced yet. A person
sees an empty home and their account: whose it is on which instance,
switching account, signing out and deleting it (each asking first where
it deletes), and About with the source of what the instance runs and
the licence list. Texts in British English and German. App ID
app.halkyon.todo on every platform, GitHub's callback scheme registered
on Android, no web build.

Its icon is Lucide's list-checks (lucide-static 1.50.0) in the brand's
blues on white: tool/app_icons.py draws its strokes with Pillow and
writes every platform's launcher icon; Lucide's ISC notice joins the
licence list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-22 18:11:06 +02:00
314a901fa1
chore: Halkyon Todo's scaffold joins the repository in apps/todo
Its server, client and app as `serverpod create` made them, with the
switch to server-side sessions that was waiting uncommitted, as files:
its one commit holds the scaffold alone.

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