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:
Tizian 「ティツィアーン」 2026-11-02 13:59:41 +01:00
commit 3f7b409e80
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -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