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:
parent
3f7b409e80
commit
e4585b478d
5 changed files with 1882 additions and 30 deletions
|
|
@ -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."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -912,5 +912,28 @@
|
|||
"weatherPrecipitation": "{amount} mm fell",
|
||||
"@weatherPrecipitation": {"placeholders": {"amount": {"type": "String"}}},
|
||||
"weatherDry": "Nothing fell",
|
||||
"weatherBy": "Weather data by Open-Meteo.com"
|
||||
"weatherBy": "Weather data by Open-Meteo.com",
|
||||
"movementTitle": "Moving more",
|
||||
"movementHint": "Reminders to get up, and workouts suggested as you move",
|
||||
"movementRemind": "Remind me to move",
|
||||
"movementRemindHint": "When the phone counted hardly a step for a while; never while recording or in a car.",
|
||||
"movementIdle": "After",
|
||||
"movementIdleMinutes": "{minutes} min still",
|
||||
"@movementIdleMinutes": {"placeholders": {"minutes": {"type": "int"}}},
|
||||
"movementHours": "Hours",
|
||||
"movementBreak": "Break",
|
||||
"movementBreakHint": "No reminders over it.",
|
||||
"movementDays": "Days",
|
||||
"movementSuggest": "Suggest workouts",
|
||||
"movementSuggestHint": "When your steps look like a walk or a run and nothing records: tap to record the rest of it. Your Loop's own detection is on its screen.",
|
||||
"movementUnavailable": "This phone doesn't count steps, so it can neither remind nor suggest.",
|
||||
"movementRefused": "Train needs the physical activity and notification permissions for this.",
|
||||
"movementLate": "The steps are counted every 15 minutes, so a reminder can come a little late.",
|
||||
"movementChannel": "Moving more",
|
||||
"movementRemindTitle": "Time to move",
|
||||
"movementRemindText": "{minutes} minutes with hardly a step. Up for a short walk?",
|
||||
"@movementRemindText": {"placeholders": {"minutes": {"type": "int"}}},
|
||||
"movementWalkingTitle": "Out for a walk?",
|
||||
"movementRunningTitle": "Out for a run?",
|
||||
"movementSuggestText": "Tap to record the rest of it."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4335,6 +4335,132 @@ abstract class AppLocalizations {
|
|||
/// In en, this message translates to:
|
||||
/// **'Weather data by Open-Meteo.com'**
|
||||
String get weatherBy;
|
||||
|
||||
/// No description provided for @movementTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Moving more'**
|
||||
String get movementTitle;
|
||||
|
||||
/// No description provided for @movementHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Reminders to get up, and workouts suggested as you move'**
|
||||
String get movementHint;
|
||||
|
||||
/// No description provided for @movementRemind.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Remind me to move'**
|
||||
String get movementRemind;
|
||||
|
||||
/// No description provided for @movementRemindHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'When the phone counted hardly a step for a while; never while recording or in a car.'**
|
||||
String get movementRemindHint;
|
||||
|
||||
/// No description provided for @movementIdle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'After'**
|
||||
String get movementIdle;
|
||||
|
||||
/// No description provided for @movementIdleMinutes.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{minutes} min still'**
|
||||
String movementIdleMinutes(int minutes);
|
||||
|
||||
/// No description provided for @movementHours.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Hours'**
|
||||
String get movementHours;
|
||||
|
||||
/// No description provided for @movementBreak.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Break'**
|
||||
String get movementBreak;
|
||||
|
||||
/// No description provided for @movementBreakHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No reminders over it.'**
|
||||
String get movementBreakHint;
|
||||
|
||||
/// No description provided for @movementDays.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Days'**
|
||||
String get movementDays;
|
||||
|
||||
/// No description provided for @movementSuggest.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Suggest workouts'**
|
||||
String get movementSuggest;
|
||||
|
||||
/// No description provided for @movementSuggestHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'When your steps look like a walk or a run and nothing records: tap to record the rest of it. Your Loop\'s own detection is on its screen.'**
|
||||
String get movementSuggestHint;
|
||||
|
||||
/// No description provided for @movementUnavailable.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'This phone doesn\'t count steps, so it can neither remind nor suggest.'**
|
||||
String get movementUnavailable;
|
||||
|
||||
/// No description provided for @movementRefused.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Train needs the physical activity and notification permissions for this.'**
|
||||
String get movementRefused;
|
||||
|
||||
/// No description provided for @movementLate.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The steps are counted every 15 minutes, so a reminder can come a little late.'**
|
||||
String get movementLate;
|
||||
|
||||
/// No description provided for @movementChannel.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Moving more'**
|
||||
String get movementChannel;
|
||||
|
||||
/// No description provided for @movementRemindTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Time to move'**
|
||||
String get movementRemindTitle;
|
||||
|
||||
/// No description provided for @movementRemindText.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{minutes} minutes with hardly a step. Up for a short walk?'**
|
||||
String movementRemindText(int minutes);
|
||||
|
||||
/// No description provided for @movementWalkingTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Out for a walk?'**
|
||||
String get movementWalkingTitle;
|
||||
|
||||
/// No description provided for @movementRunningTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Out for a run?'**
|
||||
String get movementRunningTitle;
|
||||
|
||||
/// No description provided for @movementSuggestText.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Tap to record the rest of it.'**
|
||||
String get movementSuggestText;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -2823,4 +2823,77 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get weatherBy => 'Wetterdaten von Open-Meteo.com';
|
||||
|
||||
@override
|
||||
String get movementTitle => 'Mehr bewegen';
|
||||
|
||||
@override
|
||||
String get movementHint =>
|
||||
'Erinnerungen aufzustehen und Trainings, wenn du dich bewegst';
|
||||
|
||||
@override
|
||||
String get movementRemind => 'Ans Bewegen erinnern';
|
||||
|
||||
@override
|
||||
String get movementRemindHint =>
|
||||
'Wenn das Handy eine Weile kaum einen Schritt gezählt hat; nie beim Aufzeichnen oder im Auto.';
|
||||
|
||||
@override
|
||||
String get movementIdle => 'Nach';
|
||||
|
||||
@override
|
||||
String movementIdleMinutes(int minutes) {
|
||||
return '$minutes Min. ohne Bewegung';
|
||||
}
|
||||
|
||||
@override
|
||||
String get movementHours => 'Uhrzeit';
|
||||
|
||||
@override
|
||||
String get movementBreak => 'Pause';
|
||||
|
||||
@override
|
||||
String get movementBreakHint => 'Darin keine Erinnerungen.';
|
||||
|
||||
@override
|
||||
String get movementDays => 'Tage';
|
||||
|
||||
@override
|
||||
String get movementSuggest => 'Trainings vorschlagen';
|
||||
|
||||
@override
|
||||
String get 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.';
|
||||
|
||||
@override
|
||||
String get movementUnavailable =>
|
||||
'Dieses Handy zählt keine Schritte, kann also weder erinnern noch vorschlagen.';
|
||||
|
||||
@override
|
||||
String get movementRefused =>
|
||||
'Train braucht dafür die Berechtigungen für körperliche Aktivität und Benachrichtigungen.';
|
||||
|
||||
@override
|
||||
String get movementLate =>
|
||||
'Die Schritte werden alle 15 Minuten gezählt, eine Erinnerung kann also etwas später kommen.';
|
||||
|
||||
@override
|
||||
String get movementChannel => 'Mehr bewegen';
|
||||
|
||||
@override
|
||||
String get movementRemindTitle => 'Zeit für Bewegung';
|
||||
|
||||
@override
|
||||
String movementRemindText(int minutes) {
|
||||
return '$minutes Minuten kaum ein Schritt. Lust auf einen kurzen Spaziergang?';
|
||||
}
|
||||
|
||||
@override
|
||||
String get movementWalkingTitle => 'Unterwegs zu Fuß?';
|
||||
|
||||
@override
|
||||
String get movementRunningTitle => 'Beim Laufen?';
|
||||
|
||||
@override
|
||||
String get movementSuggestText => 'Tippen, um den Rest aufzuzeichnen.';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2810,6 +2810,79 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get weatherBy => 'Weather data by Open-Meteo.com';
|
||||
|
||||
@override
|
||||
String get movementTitle => 'Moving more';
|
||||
|
||||
@override
|
||||
String get movementHint =>
|
||||
'Reminders to get up, and workouts suggested as you move';
|
||||
|
||||
@override
|
||||
String get movementRemind => 'Remind me to move';
|
||||
|
||||
@override
|
||||
String get movementRemindHint =>
|
||||
'When the phone counted hardly a step for a while; never while recording or in a car.';
|
||||
|
||||
@override
|
||||
String get movementIdle => 'After';
|
||||
|
||||
@override
|
||||
String movementIdleMinutes(int minutes) {
|
||||
return '$minutes min still';
|
||||
}
|
||||
|
||||
@override
|
||||
String get movementHours => 'Hours';
|
||||
|
||||
@override
|
||||
String get movementBreak => 'Break';
|
||||
|
||||
@override
|
||||
String get movementBreakHint => 'No reminders over it.';
|
||||
|
||||
@override
|
||||
String get movementDays => 'Days';
|
||||
|
||||
@override
|
||||
String get movementSuggest => 'Suggest workouts';
|
||||
|
||||
@override
|
||||
String get movementSuggestHint =>
|
||||
'When your steps look like a walk or a run and nothing records: tap to record the rest of it. Your Loop\'s own detection is on its screen.';
|
||||
|
||||
@override
|
||||
String get movementUnavailable =>
|
||||
'This phone doesn\'t count steps, so it can neither remind nor suggest.';
|
||||
|
||||
@override
|
||||
String get movementRefused =>
|
||||
'Train needs the physical activity and notification permissions for this.';
|
||||
|
||||
@override
|
||||
String get movementLate =>
|
||||
'The steps are counted every 15 minutes, so a reminder can come a little late.';
|
||||
|
||||
@override
|
||||
String get movementChannel => 'Moving more';
|
||||
|
||||
@override
|
||||
String get movementRemindTitle => 'Time to move';
|
||||
|
||||
@override
|
||||
String movementRemindText(int minutes) {
|
||||
return '$minutes minutes with hardly a step. Up for a short walk?';
|
||||
}
|
||||
|
||||
@override
|
||||
String get movementWalkingTitle => 'Out for a walk?';
|
||||
|
||||
@override
|
||||
String get movementRunningTitle => 'Out for a run?';
|
||||
|
||||
@override
|
||||
String get movementSuggestText => 'Tap to record the rest of it.';
|
||||
}
|
||||
|
||||
/// The translations for English, as used in the United Kingdom (`en_GB`).
|
||||
|
|
|
|||
Loading…
Reference in a new issue