feat(train): reminders to move and workouts suggested from the steps (ADR 0037)

Settings' Moving more, on Android: a reminder to get up after an idle
time, and a suggested walk or run, each off until turned on (then every
30 minutes, weekdays 9:00 to 18:00, not 12:00 to 13:00, each value the
person's), turning on asking for the activity and notification
permissions.

A WorkManager job every 15 minutes reads the phone's step counter and
keeps two hours of readings. It reminds where fewer than 50 steps came
over the idle time, all of it within the hours and outside the break,
on the person's days, never while Train records or the phone is in a
car (Android's car mode, or a car's Bluetooth audio or hands-free). It
suggests a walk or a run where the last span averaged a walking or
running cadence, once an hour; tapped, the Record sheet for it opens.
The decisions are pure Kotlin (Movement.kt), tested on the JVM; the
notifications' words are the app's, written into the job's
configuration as the person's app opens.

Polar's SDK sets neither the band's inactivity alert nor tells of one
without an all-day connection, hence the phone's steps (ADR 0037).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-02 14:32:02 +01:00
commit e4585b478d
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -720,5 +720,26 @@
"weatherDirection": "{direction, select, n{Nord} ne{Nordost} e{Ost} se{Südost} s{Süd} sw{Südwest} w{West} nw{Nordwest} other{Wind}}",
"weatherPrecipitation": "{amount} mm Niederschlag",
"weatherDry": "Trocken",
"weatherBy": "Wetterdaten von Open-Meteo.com"
"weatherBy": "Wetterdaten von Open-Meteo.com",
"movementTitle": "Mehr bewegen",
"movementHint": "Erinnerungen aufzustehen und Trainings, wenn du dich bewegst",
"movementRemind": "Ans Bewegen erinnern",
"movementRemindHint": "Wenn das Handy eine Weile kaum einen Schritt gezählt hat; nie beim Aufzeichnen oder im Auto.",
"movementIdle": "Nach",
"movementIdleMinutes": "{minutes} Min. ohne Bewegung",
"movementHours": "Uhrzeit",
"movementBreak": "Pause",
"movementBreakHint": "Darin keine Erinnerungen.",
"movementDays": "Tage",
"movementSuggest": "Trainings vorschlagen",
"movementSuggestHint": "Wenn deine Schritte nach Gehen oder Laufen aussehen und nichts aufzeichnet: tippen, um den Rest aufzuzeichnen. Die eigene Erkennung deines Loop ist auf seiner Seite.",
"movementUnavailable": "Dieses Handy zählt keine Schritte, kann also weder erinnern noch vorschlagen.",
"movementRefused": "Train braucht dafür die Berechtigungen für körperliche Aktivität und Benachrichtigungen.",
"movementLate": "Die Schritte werden alle 15 Minuten gezählt, eine Erinnerung kann also etwas später kommen.",
"movementChannel": "Mehr bewegen",
"movementRemindTitle": "Zeit für Bewegung",
"movementRemindText": "{minutes} Minuten kaum ein Schritt. Lust auf einen kurzen Spaziergang?",
"movementWalkingTitle": "Unterwegs zu Fuß?",
"movementRunningTitle": "Beim Laufen?",
"movementSuggestText": "Tippen, um den Rest aufzuzeichnen."
}