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>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-28 17:06:31 +01:00
commit 09f61c3b0a
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
5 changed files with 1513 additions and 8 deletions

View file

@ -129,5 +129,20 @@
"workoutStrokeRateChart": "Schlagzahl",
"workoutPowerChart": "Leistung",
"recordAutoPauseRowingHint": "Wenn du aufhörst zu rudern, weiter mit dem nächsten Schlag",
"recordingMetres": "Meter"
"recordingMetres": "Meter",
"healthTitle": "Health Connect",
"healthHint": "Trainings mit anderen Apps auf diesem Telefon teilen",
"healthUnavailable": "Health Connect ist auf diesem Telefon nicht da. Ab Android 14 ist es eingebaut, davor eine eigene App.",
"healthNeedsUpdate": "Aktualisiere die App Health Connect, um sie mit Train zu nutzen.",
"healthWrite": "Meine Trainings schreiben",
"healthWriteHint": "Jedes Training auf diesem Telefon, auf dem neuesten Stand, wenn du es bearbeitest oder löschst",
"healthWriteRefused": "Health Connect hat das zurückgenommen. Erlaube es dort, um es wieder einzuschalten.",
"healthRefused": "Health Connect hat es nicht erlaubt. Du kannst es in seinen Einstellungen erlauben.",
"healthOpenSettings": "Health Connect öffnen",
"healthWhy": "Warum Train fragt",
"healthRationaleTitle": "Train und Health Connect",
"healthRationaleWrite": "Train schreibt deine Trainings erst in Health Connect, wenn du es einschaltest: jedes mit Strecke, Herzfrequenz, Tempo, Leistung, Distanz und Anstieg, damit andere Apps auf diesem Telefon sie nutzen können. Bearbeitest oder löschst du ein Training in Train, geschieht das dort auch.",
"healthRationaleRead": "Train liest die Trainings anderer Apps erst, wenn du es einschaltest, und nur von den Apps, die du wählst: Ihre Herzfrequenz, Distanz und Leistung kommen als Trainings in Train, mit deinem Schlüssel versiegelt, bevor sie mit deiner Instanz abgeglichen werden, die sie nicht lesen kann.",
"healthRationaleNothingElse": "Was Train dort liest, wird dir gezeigt und niemandem sonst, und für nichts anderes genutzt. Schaltest du einen Schalter aus oder nimmst eine Erlaubnis in Health Connect zurück, hört es auf."
}

View file

@ -174,5 +174,21 @@
"workoutStrokeRateChart": "Stroke rate",
"workoutPowerChart": "Power",
"recordAutoPauseRowingHint": "When you stop rowing, going on with the next stroke",
"recordingMetres": "metres"
"recordingMetres": "metres",
"healthTitle": "Health Connect",
"healthHint": "Share workouts with other apps on this phone",
"@healthHint": {"description": "Under Health Connect in the account sheet."},
"healthUnavailable": "Health Connect isn't on this phone. Android 14 and later have it built in; before 14, it's an app of its own.",
"healthNeedsUpdate": "Update the Health Connect app to use it with Train.",
"healthWrite": "Write my workouts",
"healthWriteHint": "Every workout on this phone, kept up to date as you edit or delete it",
"healthWriteRefused": "Health Connect took this back. Allow it there to turn it on again.",
"healthRefused": "Health Connect didn't allow it. You can allow it in its settings.",
"healthOpenSettings": "Open Health Connect",
"healthWhy": "Why Train asks",
"healthRationaleTitle": "Train and Health Connect",
"healthRationaleWrite": "Train writes your workouts to Health Connect only once you turn it on: each one with its route, heart rate, speed, power, distance and climb, so that other apps on this phone can use them. A workout edited or deleted in Train is edited or deleted there too.",
"healthRationaleRead": "Train reads other apps' workouts only once you turn it on, and only from the apps you choose: their heart rate, distance and power come into Train as workouts, sealed with your key before they're synced to your instance, which can't read them.",
"healthRationaleNothingElse": "What Train reads there is shown to you and nobody else, and isn't used for anything else. Turning a switch off, or taking a permission back in Health Connect, stops it."
}

View file

@ -825,6 +825,90 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'metres'**
String get recordingMetres;
/// No description provided for @healthTitle.
///
/// In en, this message translates to:
/// **'Health Connect'**
String get healthTitle;
/// Under Health Connect in the account sheet.
///
/// In en, this message translates to:
/// **'Share workouts with other apps on this phone'**
String get healthHint;
/// No description provided for @healthUnavailable.
///
/// In en, this message translates to:
/// **'Health Connect isn\'t on this phone. Android 14 and later have it built in; before 14, it\'s an app of its own.'**
String get healthUnavailable;
/// No description provided for @healthNeedsUpdate.
///
/// In en, this message translates to:
/// **'Update the Health Connect app to use it with Train.'**
String get healthNeedsUpdate;
/// No description provided for @healthWrite.
///
/// In en, this message translates to:
/// **'Write my workouts'**
String get healthWrite;
/// No description provided for @healthWriteHint.
///
/// In en, this message translates to:
/// **'Every workout on this phone, kept up to date as you edit or delete it'**
String get healthWriteHint;
/// No description provided for @healthWriteRefused.
///
/// In en, this message translates to:
/// **'Health Connect took this back. Allow it there to turn it on again.'**
String get healthWriteRefused;
/// No description provided for @healthRefused.
///
/// In en, this message translates to:
/// **'Health Connect didn\'t allow it. You can allow it in its settings.'**
String get healthRefused;
/// No description provided for @healthOpenSettings.
///
/// In en, this message translates to:
/// **'Open Health Connect'**
String get healthOpenSettings;
/// No description provided for @healthWhy.
///
/// In en, this message translates to:
/// **'Why Train asks'**
String get healthWhy;
/// No description provided for @healthRationaleTitle.
///
/// In en, this message translates to:
/// **'Train and Health Connect'**
String get healthRationaleTitle;
/// No description provided for @healthRationaleWrite.
///
/// In en, this message translates to:
/// **'Train writes your workouts to Health Connect only once you turn it on: each one with its route, heart rate, speed, power, distance and climb, so that other apps on this phone can use them. A workout edited or deleted in Train is edited or deleted there too.'**
String get healthRationaleWrite;
/// No description provided for @healthRationaleRead.
///
/// In en, this message translates to:
/// **'Train reads other apps\' workouts only once you turn it on, and only from the apps you choose: their heart rate, distance and power come into Train as workouts, sealed with your key before they\'re synced to your instance, which can\'t read them.'**
String get healthRationaleRead;
/// No description provided for @healthRationaleNothingElse.
///
/// In en, this message translates to:
/// **'What Train reads there is shown to you and nobody else, and isn\'t used for anything else. Turning a switch off, or taking a permission back in Health Connect, stops it.'**
String get healthRationaleNothingElse;
}
class _AppLocalizationsDelegate

View file

@ -450,4 +450,55 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get recordingMetres => 'Meter';
@override
String get healthTitle => 'Health Connect';
@override
String get healthHint =>
'Trainings mit anderen Apps auf diesem Telefon teilen';
@override
String get healthUnavailable =>
'Health Connect ist auf diesem Telefon nicht da. Ab Android 14 ist es eingebaut, davor eine eigene App.';
@override
String get healthNeedsUpdate =>
'Aktualisiere die App Health Connect, um sie mit Train zu nutzen.';
@override
String get healthWrite => 'Meine Trainings schreiben';
@override
String get healthWriteHint =>
'Jedes Training auf diesem Telefon, auf dem neuesten Stand, wenn du es bearbeitest oder löschst';
@override
String get healthWriteRefused =>
'Health Connect hat das zurückgenommen. Erlaube es dort, um es wieder einzuschalten.';
@override
String get healthRefused =>
'Health Connect hat es nicht erlaubt. Du kannst es in seinen Einstellungen erlauben.';
@override
String get healthOpenSettings => 'Health Connect öffnen';
@override
String get healthWhy => 'Warum Train fragt';
@override
String get healthRationaleTitle => 'Train und Health Connect';
@override
String get healthRationaleWrite =>
'Train schreibt deine Trainings erst in Health Connect, wenn du es einschaltest: jedes mit Strecke, Herzfrequenz, Tempo, Leistung, Distanz und Anstieg, damit andere Apps auf diesem Telefon sie nutzen können. Bearbeitest oder löschst du ein Training in Train, geschieht das dort auch.';
@override
String get healthRationaleRead =>
'Train liest die Trainings anderer Apps erst, wenn du es einschaltest, und nur von den Apps, die du wählst: Ihre Herzfrequenz, Distanz und Leistung kommen als Trainings in Train, mit deinem Schlüssel versiegelt, bevor sie mit deiner Instanz abgeglichen werden, die sie nicht lesen kann.';
@override
String get healthRationaleNothingElse =>
'Was Train dort liest, wird dir gezeigt und niemandem sonst, und für nichts anderes genutzt. Schaltest du einen Schalter aus oder nimmst eine Erlaubnis in Health Connect zurück, hört es auf.';
}

View file

@ -447,6 +447,56 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get recordingMetres => 'metres';
@override
String get healthTitle => 'Health Connect';
@override
String get healthHint => 'Share workouts with other apps on this phone';
@override
String get healthUnavailable =>
'Health Connect isn\'t on this phone. Android 14 and later have it built in; before 14, it\'s an app of its own.';
@override
String get healthNeedsUpdate =>
'Update the Health Connect app to use it with Train.';
@override
String get healthWrite => 'Write my workouts';
@override
String get healthWriteHint =>
'Every workout on this phone, kept up to date as you edit or delete it';
@override
String get healthWriteRefused =>
'Health Connect took this back. Allow it there to turn it on again.';
@override
String get healthRefused =>
'Health Connect didn\'t allow it. You can allow it in its settings.';
@override
String get healthOpenSettings => 'Open Health Connect';
@override
String get healthWhy => 'Why Train asks';
@override
String get healthRationaleTitle => 'Train and Health Connect';
@override
String get healthRationaleWrite =>
'Train writes your workouts to Health Connect only once you turn it on: each one with its route, heart rate, speed, power, distance and climb, so that other apps on this phone can use them. A workout edited or deleted in Train is edited or deleted there too.';
@override
String get healthRationaleRead =>
'Train reads other apps\' workouts only once you turn it on, and only from the apps you choose: their heart rate, distance and power come into Train as workouts, sealed with your key before they\'re synced to your instance, which can\'t read them.';
@override
String get healthRationaleNothingElse =>
'What Train reads there is shown to you and nobody else, and isn\'t used for anything else. Turning a switch off, or taking a permission back in Health Connect, stops it.';
}
/// The translations for English, as used in the United Kingdom (`en_GB`).