Commit graph halkyon/apps/train/halkyon_train_flutter/pubspec.yaml
Author SHA1 Message Date
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
1aa633fdc7
chore(release): train-v0.5.0
All checks were successful
CI / check (push) Successful in 52m2s
CI / deploy (push) Successful in 1m5s
Build 5.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 14:38:00 +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
224f6ed8e8
chore(release): train-v0.4.0
All checks were successful
CI / check (push) Successful in 48m23s
CI / deploy (push) Successful in 1m5s
Build 4.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-05 10:39:28 +01:00
cee4427a56
chore(release): train-v0.3.0
Some checks failed
CI / deploy (push) Has been cancelled
CI / check (push) Has been cancelled
Build 3.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 15:20:11 +01:00
478171dd87
chore(release): train-v0.2.0
All checks were successful
CI / check (push) Successful in 42m35s
CI / deploy (push) Successful in 1m5s
Build 2.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-03 17:33:08 +01:00
7727317c68
feat(app): what's new after an update, drafted by the release tool (ADR 0030, D61)
halkyon_app's WhatsNew reads what each release changed from the app's
assets/whats_new/ (<version>.<language>.txt, English and German, a change
a line): after an update a sheet lists every release since the one the
device showed last, newest first, once; Settings shows the running
version's again, above About. Nothing on a fresh install.

tool/release.dart drafts the missing texts from the commits that count
after "Go on?" (German marked TRANSLATE:), opens them in the editor until
they fit (no mark left, F-Droid's 500 characters) and commits them with
the version. The English is the Forgejo notes' What's new, each language
F-Droid's changelog of the build, written at publishing and copied in by
tool/fdroid_repo.sh. Learn and Train bundle their texts, Learn's 0.22.0
and Train's 0.1.0 written to start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-31 19:36:20 +01:00
d4d749eb9f
feat(train): Home, Maps, Record, Groups and Profile in Learn's frame, washed in carrot (ADR 0030, D60)
Train's tabs are Strava's five where one screen with four tabs at its
top had held workouts, days, plans and routes: Home the workouts, Maps
the routes, Record recording and the interval plans, Groups a screen
saying they come later, Profile the days and the way to the account.
A device that doesn't record has no Record tab, its plans beside the
days in Profile.

The frame is halkyon_ui's NavigationFrame, driven by go_router as
Learn's: a workout's page opens in Home and a day's in Profile with the
tabs beside them; the route and plan editors and the recording cover
them, their content handed over as it is. Every tab washes down from the
top in carrot, the warm end of Train's icon, as Learn's in cobalt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 23:52:48 +01:00
3336fe4eca
feat(train): signing in to Jellyfin and marking playlists (ADR 0030, D47)
Music's decisions as D47, and its first part: the music screen from the
account sheet, on Android, signs in to the person's Jellyfin with Quick
Connect, else a password, and lists their playlists of music to mark
for running. The token is in the keyring, the server and the marks in
the person's music.json, nothing on Train's server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:53:03 +01:00
5ff9b2e053
feat(train): routes out and in as GPX (ADR 0030, D45)
A route's page shares it as GPX 1.1 (Android's share sheet, else saved
where the person chooses): its way a track with elevations, its
waypoints and turns as named points. A GPX file comes in from the Routes
tab or, on Android, opened with Train or shared to it; it is planned
along the paths through its points or kept as drawn, then named and
saved as a new route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:53:03 +01:00
a2997e87af
feat(train): a route's map kept offline on request (ADR 0030, D45)
A saved route's page has Keep the map offline: the tiles within 2 km of
its way at zooms 10 to 16 (never above the source's own), shared between
routes, kept again as the route changes and let go with it. The style,
its sprites and the instance's map source are kept as last read, and
every map reads a kept tile before the network, so a map draws with no
network at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:53:03 +01:00
cd72cf6ccc
feat(train): setting up and keeping the Polar Loop (ADR 0030, D34–D36)
On Android, the Loop through Polar's BLE SDK 8.3.0 (from JitPack, asked
for Polar's group alone, its files pinned by SHA-256 in Gradle's
verification metadata): LoopBridge.kt over app.halkyon.train/loop, the
first-time use's figures mapped and checked in LoopSetup.kt, tested on
the JVM. PolarLoop per person remembers the band in loop.json, connects
while the app is open, sets its clock at each connection, keeps what it
tells (battery, charging, firmware), offers a changed profile and sends
it only when asked (D35: first-time use writes a new user identifier
each time), and lets the band go by a factory reset after asking. The
setup sheet finds Loops nearest first and asks only for what the
profile lacks; Polar's defaults (60, 220 less the age, a VO2max from
Polar's fitness tables) go to the band alone.

Polar's SDK is not free software (D36, correcting D32): the app's AGPL
gains a section 7 permission for linking it, LICENSE.md names it, and
its licence and bundled notices join the licence list on Android.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:52:55 +01:00
09f61c3b0a
feat(train): workouts written to Health Connect (ADR 0030, D31)
A Health Connect row in the account sheet opens its screen: Write my
workouts, off until turned on, Health Connect asking as it is. Then
every workout this phone holds is written there (its session with its
pauses and route, heart rate, speed and the rower's watts as samples,
distance and elevation gained), and written again or deleted as it
changes, here or through a sync, and as the app opens. Client IDs come
from the workout's ID, a version counts up with each change; what was
written is kept in the person's health_connect.json, never synced. A
permission taken back in Health Connect turns writing off and says so;
Health Connect's link to Train's rationale opens a screen of its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:52:53 +01:00
405577050d
feat(train): the workouts listed, and each one's page with its map (ADR 0030, D22-D24)
Home lists the person's workouts newest first under their months, each
with its activity's icon, its name (else the time of day's and the
activity's), when it started, its distance, moving time and pace or
speed; those this device can't open come last, locked. A workout's page
shows its track on the instance's map source (flutter_map with
vector_map_tiles, pinned at 9.0.0-beta.13), in pieces between its
pauses, start and end marked; its totals with the elevation gained;
its splits per kilometre on foot, per 5 km cycling; pace or speed and
elevation over the distance, drawn by the app's own painter; and what
the map's source sees. Its name and notes are edited there; deleting
asks first and can be undone for a moment from home (halkyon_app's
DelayedDeletions, TrainPerson.deletions).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:52:50 +01:00
6171ff10a0
feat(train): a person's workouts opened with them (ADR 0030, D14, D15)
TrainPerson now opens the person's own sync database in their folder,
halkyon_app's SyncService behind AppCompatibility (the module's basics'
minimumAppBuild against the build package_info_plus reads), their key
and their workouts, and closes them in that order, the key last. As in
Learn, a person's data waits for the one before to close, since signing
in again opens the same database. The pubspec's dependencies are sorted
again (clock had gone before flutter).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:52:48 +01:00
61fc5c5f7c
feat(train): the person's key on Train's devices (ADR 0030, D15)
TrainKeys holds the one key everything of Train's is sealed with: made
on the first write where the account's keys are, kept in the synced
content_key rows sealed to the account, opened on the person's other
devices. Only keys sealed under Train's own IDs open, so the instance
can't relabel one, and a key the account sealed for another app never
counts; two devices that each made one offline write with the older. A
device without the account's keys opens and writes nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:52:47 +01:00
d34e2b751b
feat(train): a workout's and its series' payloads (ADR 0030, D14)
A workout's payload is JSON naming its activity, times, name, notes and
totals; a series is cut into chunks of at most 10 minutes, each its
times and columns as differences from the value before, gzipped before
it is sealed (ten minutes of positions at a fix a second take a few KB).
A payload of a newer schema, an unknown activity or kind, or a blank one
is skipped, never read half.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:52:47 +01:00
7b20851a0a
feat(train): the sync engine and Train's first models (ADR 0030, D14)
Train's server syncs with serverpod_offline_sync as Learn's does, and
holds three synced tables, every payload sealed on the devices:
content_key (the person's data key, sealed to the account), workout (its
type, times, name and totals, changed when edited) and workout_series
(chunks of a workout's samples, written once). A person's space goes
with them, with everything in it.

The migration only adds: the three tables, each indexed on spaceId and
cascading with its space (a series also with its workout), and the sync
engine's own tables.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:52:47 +01:00
ece9ce9697
feat: the apps' icons as one family, drawn by one tool (ADR 0031)
tool/app_icons.py at the root replaces Learn's and Todo's scripts: each
app's Lucide glyph (lucide-static 1.50.0) drawn by librsvg, fading from
cobalt through the colours ADR 0031 names, then every platform's
launcher icon through flutter_launcher_icons, Windows' .ico with every
size, and Learn's snap icon.

Learn's icon becomes the graduation cap, its window's on Linux too, with
Lucide's notice in its licence list; the kingfisher stays the emblem on
the rail and the launch screen. Todo's becomes list-todo, Train's bike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:52:45 +01:00
7b5fbee913
feat(train): Halkyon Train's shell, Todo's copied and renamed (ADR 0030, D12)
apps/train with halkyon_train_server, _client and _flutter, as Todo's:
halkyon_base configured by trainBase(), its own register alone and a
member of the instance's where the operator names one, the app on
halkyon_app's gates with Train's frame, account sheet and About, texts
in British English and German that speak of workouts, app.halkyon.train
on Android, iOS, Linux, macOS and Windows.

Where it differs from Todo: development ports of its own (8180 to 8190),
so it runs beside Learn's server; one initial migration with the schema
Todo's migrations end at (the same tables, compared line by line), not
Todo's seventeen; and Todo's icon as a placeholder until the icon tool
of ADR 0031 draws Train's bike. The workspace, the licences, the READMEs
and AGENTS.md name it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-30 15:52:45 +01:00