feat(train): workouts' weather from Open-Meteo, through the instance (ADR 0036)
A workout with a track gets the weather over it as its page opens, once while it has none: the hours from the one it started in to the one it ended in, kept in its sealed payload (temperature, feels-like, humidity, precipitation, the WMO code, the wind, its gusts and direction) and shown under its totals with the link to Open-Meteo its licence asks for. Train's server asks Open-Meteo in the person's place (the `weather` endpoint), so Open-Meteo never sees their address: the place rounded to two decimals (also on the phone), a span of at most 48 hours, the forecast API for recent spans and the archive for older ones, for people signed in, at most 30 requests a person a minute, nothing kept or logged. On by default; `WEATHER=off` switches it off, and `OPEN_METEO_API_KEY` moves it to the paid hosts for an instance used commercially. Health Connect's fingerprint leaves the weather out, so keeping it writes nothing again. No table and no migration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
508994be3a
commit
3f7b409e80
5 changed files with 2503 additions and 7 deletions
|
|
@ -707,5 +707,18 @@
|
|||
"strengthNextUp": "Als Nächstes: {exercise}",
|
||||
"strengthBarAndPlates": "{bar}-kg-Stange, jede Seite: {plates}",
|
||||
"strengthHandlesAndPlates": "{bar}-kg-Griffe, jede Seite: {plates}",
|
||||
"strengthWeightShort": "{weight} kg unter dem Plan"
|
||||
"strengthWeightShort": "{weight} kg unter dem Plan",
|
||||
"weatherHeading": "Wetter",
|
||||
"weatherConditions": "{conditions, select, clear{Klar} partlyCloudy{Teils bewölkt} cloudy{Bedeckt} fog{Nebel} drizzle{Nieselregen} rain{Regen} freezingRain{Gefrierender Regen} snow{Schnee} rainShowers{Schauer} snowShowers{Schneeschauer} thunderstorm{Gewitter} other{Wetter}}",
|
||||
"weatherTemperature": "{temperature} °C",
|
||||
"weatherTemperatureRange": "{low}–{high} °C",
|
||||
"weatherFeelsLike": "Gefühlt {temperature} °C",
|
||||
"weatherWind": "Wind {speed} km/h aus {direction}",
|
||||
"weatherWindNoDirection": "Wind {speed} km/h",
|
||||
"weatherCalm": "Kaum Wind",
|
||||
"weatherGusts": "Böen bis {speed} km/h",
|
||||
"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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -890,5 +890,27 @@
|
|||
"strengthHandlesAndPlates": "{bar} kg handles, each side: {plates}",
|
||||
"@strengthHandlesAndPlates": {"placeholders": {"bar": {"type": "String"}, "plates": {"type": "String"}}},
|
||||
"strengthWeightShort": "{weight} kg below what was planned",
|
||||
"@strengthWeightShort": {"placeholders": {"weight": {"type": "String"}}}
|
||||
"@strengthWeightShort": {"placeholders": {"weight": {"type": "String"}}},
|
||||
"weatherHeading": "Weather",
|
||||
"weatherConditions": "{conditions, select, clear{Clear} partlyCloudy{Partly cloudy} cloudy{Overcast} fog{Fog} drizzle{Drizzle} rain{Rain} freezingRain{Freezing rain} snow{Snow} rainShowers{Showers} snowShowers{Snow showers} thunderstorm{Thunderstorm} other{Weather}}",
|
||||
"@weatherConditions": {"placeholders": {"conditions": {"type": "String"}}, "description": "What the sky did over a workout, from Open-Meteo's weather code."},
|
||||
"weatherTemperature": "{temperature} °C",
|
||||
"@weatherTemperature": {"placeholders": {"temperature": {"type": "String"}}},
|
||||
"weatherTemperatureRange": "{low}–{high} °C",
|
||||
"@weatherTemperatureRange": {"placeholders": {"low": {"type": "String"}, "high": {"type": "String"}}},
|
||||
"weatherFeelsLike": "Felt like {temperature} °C",
|
||||
"@weatherFeelsLike": {"placeholders": {"temperature": {"type": "String"}}},
|
||||
"weatherWind": "Wind {speed} km/h from the {direction}",
|
||||
"@weatherWind": {"placeholders": {"speed": {"type": "String"}, "direction": {"type": "String"}}},
|
||||
"weatherWindNoDirection": "Wind {speed} km/h",
|
||||
"@weatherWindNoDirection": {"placeholders": {"speed": {"type": "String"}}},
|
||||
"weatherCalm": "Hardly any wind",
|
||||
"weatherGusts": "gusts up to {speed} km/h",
|
||||
"@weatherGusts": {"placeholders": {"speed": {"type": "String"}}},
|
||||
"weatherDirection": "{direction, select, n{north} ne{north-east} e{east} se{south-east} s{south} sw{south-west} w{west} nw{north-west} other{wind}}",
|
||||
"@weatherDirection": {"placeholders": {"direction": {"type": "String"}}, "description": "Where the wind came from, as in \"from the south-west\"."},
|
||||
"weatherPrecipitation": "{amount} mm fell",
|
||||
"@weatherPrecipitation": {"placeholders": {"amount": {"type": "String"}}},
|
||||
"weatherDry": "Nothing fell",
|
||||
"weatherBy": "Weather data by Open-Meteo.com"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4257,6 +4257,84 @@ abstract class AppLocalizations {
|
|||
/// In en, this message translates to:
|
||||
/// **'{weight} kg below what was planned'**
|
||||
String strengthWeightShort(String weight);
|
||||
|
||||
/// No description provided for @weatherHeading.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Weather'**
|
||||
String get weatherHeading;
|
||||
|
||||
/// What the sky did over a workout, from Open-Meteo's weather code.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{conditions, select, clear{Clear} partlyCloudy{Partly cloudy} cloudy{Overcast} fog{Fog} drizzle{Drizzle} rain{Rain} freezingRain{Freezing rain} snow{Snow} rainShowers{Showers} snowShowers{Snow showers} thunderstorm{Thunderstorm} other{Weather}}'**
|
||||
String weatherConditions(String conditions);
|
||||
|
||||
/// No description provided for @weatherTemperature.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{temperature} °C'**
|
||||
String weatherTemperature(String temperature);
|
||||
|
||||
/// No description provided for @weatherTemperatureRange.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{low}–{high} °C'**
|
||||
String weatherTemperatureRange(String low, String high);
|
||||
|
||||
/// No description provided for @weatherFeelsLike.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Felt like {temperature} °C'**
|
||||
String weatherFeelsLike(String temperature);
|
||||
|
||||
/// No description provided for @weatherWind.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Wind {speed} km/h from the {direction}'**
|
||||
String weatherWind(String speed, String direction);
|
||||
|
||||
/// No description provided for @weatherWindNoDirection.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Wind {speed} km/h'**
|
||||
String weatherWindNoDirection(String speed);
|
||||
|
||||
/// No description provided for @weatherCalm.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Hardly any wind'**
|
||||
String get weatherCalm;
|
||||
|
||||
/// No description provided for @weatherGusts.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'gusts up to {speed} km/h'**
|
||||
String weatherGusts(String speed);
|
||||
|
||||
/// Where the wind came from, as in "from the south-west".
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{direction, select, n{north} ne{north-east} e{east} se{south-east} s{south} sw{south-west} w{west} nw{north-west} other{wind}}'**
|
||||
String weatherDirection(String direction);
|
||||
|
||||
/// No description provided for @weatherPrecipitation.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{amount} mm fell'**
|
||||
String weatherPrecipitation(String amount);
|
||||
|
||||
/// No description provided for @weatherDry.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Nothing fell'**
|
||||
String get weatherDry;
|
||||
|
||||
/// No description provided for @weatherBy.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Weather data by Open-Meteo.com'**
|
||||
String get weatherBy;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -2735,4 +2735,92 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
String strengthWeightShort(String weight) {
|
||||
return '$weight kg unter dem Plan';
|
||||
}
|
||||
|
||||
@override
|
||||
String get weatherHeading => 'Wetter';
|
||||
|
||||
@override
|
||||
String weatherConditions(String conditions) {
|
||||
String _temp0 = intl.Intl.selectLogic(
|
||||
conditions,
|
||||
{
|
||||
'clear': 'Klar',
|
||||
'partlyCloudy': 'Teils bewölkt',
|
||||
'cloudy': 'Bedeckt',
|
||||
'fog': 'Nebel',
|
||||
'drizzle': 'Nieselregen',
|
||||
'rain': 'Regen',
|
||||
'freezingRain': 'Gefrierender Regen',
|
||||
'snow': 'Schnee',
|
||||
'rainShowers': 'Schauer',
|
||||
'snowShowers': 'Schneeschauer',
|
||||
'thunderstorm': 'Gewitter',
|
||||
'other': 'Wetter',
|
||||
},
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherTemperature(String temperature) {
|
||||
return '$temperature °C';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherTemperatureRange(String low, String high) {
|
||||
return '$low–$high °C';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherFeelsLike(String temperature) {
|
||||
return 'Gefühlt $temperature °C';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherWind(String speed, String direction) {
|
||||
return 'Wind $speed km/h aus $direction';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherWindNoDirection(String speed) {
|
||||
return 'Wind $speed km/h';
|
||||
}
|
||||
|
||||
@override
|
||||
String get weatherCalm => 'Kaum Wind';
|
||||
|
||||
@override
|
||||
String weatherGusts(String speed) {
|
||||
return 'Böen bis $speed km/h';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherDirection(String direction) {
|
||||
String _temp0 = intl.Intl.selectLogic(
|
||||
direction,
|
||||
{
|
||||
'n': 'Nord',
|
||||
'ne': 'Nordost',
|
||||
'e': 'Ost',
|
||||
'se': 'Südost',
|
||||
's': 'Süd',
|
||||
'sw': 'Südwest',
|
||||
'w': 'West',
|
||||
'nw': 'Nordwest',
|
||||
'other': 'Wind',
|
||||
},
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherPrecipitation(String amount) {
|
||||
return '$amount mm Niederschlag';
|
||||
}
|
||||
|
||||
@override
|
||||
String get weatherDry => 'Trocken';
|
||||
|
||||
@override
|
||||
String get weatherBy => 'Wetterdaten von Open-Meteo.com';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2722,6 +2722,94 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
String strengthWeightShort(String weight) {
|
||||
return '$weight kg below what was planned';
|
||||
}
|
||||
|
||||
@override
|
||||
String get weatherHeading => 'Weather';
|
||||
|
||||
@override
|
||||
String weatherConditions(String conditions) {
|
||||
String _temp0 = intl.Intl.selectLogic(
|
||||
conditions,
|
||||
{
|
||||
'clear': 'Clear',
|
||||
'partlyCloudy': 'Partly cloudy',
|
||||
'cloudy': 'Overcast',
|
||||
'fog': 'Fog',
|
||||
'drizzle': 'Drizzle',
|
||||
'rain': 'Rain',
|
||||
'freezingRain': 'Freezing rain',
|
||||
'snow': 'Snow',
|
||||
'rainShowers': 'Showers',
|
||||
'snowShowers': 'Snow showers',
|
||||
'thunderstorm': 'Thunderstorm',
|
||||
'other': 'Weather',
|
||||
},
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherTemperature(String temperature) {
|
||||
return '$temperature °C';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherTemperatureRange(String low, String high) {
|
||||
return '$low–$high °C';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherFeelsLike(String temperature) {
|
||||
return 'Felt like $temperature °C';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherWind(String speed, String direction) {
|
||||
return 'Wind $speed km/h from the $direction';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherWindNoDirection(String speed) {
|
||||
return 'Wind $speed km/h';
|
||||
}
|
||||
|
||||
@override
|
||||
String get weatherCalm => 'Hardly any wind';
|
||||
|
||||
@override
|
||||
String weatherGusts(String speed) {
|
||||
return 'gusts up to $speed km/h';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherDirection(String direction) {
|
||||
String _temp0 = intl.Intl.selectLogic(
|
||||
direction,
|
||||
{
|
||||
'n': 'north',
|
||||
'ne': 'north-east',
|
||||
'e': 'east',
|
||||
'se': 'south-east',
|
||||
's': 'south',
|
||||
'sw': 'south-west',
|
||||
'w': 'west',
|
||||
'nw': 'north-west',
|
||||
'other': 'wind',
|
||||
},
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String weatherPrecipitation(String amount) {
|
||||
return '$amount mm fell';
|
||||
}
|
||||
|
||||
@override
|
||||
String get weatherDry => 'Nothing fell';
|
||||
|
||||
@override
|
||||
String get weatherBy => 'Weather data by Open-Meteo.com';
|
||||
}
|
||||
|
||||
/// The translations for English, as used in the United Kingdom (`en_GB`).
|
||||
|
|
|
|||
Loading…
Reference in a new issue