The Record sheet gains a Heart rate row: a sheet looks for straps advertising the Heart Rate Service, the nearest first, once nearby devices are allowed, and the one chosen is remembered in the person's folder; it records with every workout unless switched off for one. The recorder service connects to it with Android's own Bluetooth API, no package (D26), parses Heart Rate Measurement in Kotlin (tested on the JVM), writes each rate and the strap's state to the recording file, and asks for a lost strap again for as long as it records. The recording screen shows the heart rate, and "Strap lost" while it is gone; a workout's page shows the heart's average and highest rate, each split's average and its chart. iOS's recording waits for a Mac (D25), after the rower. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
708 lines
21 KiB
Dart
708 lines
21 KiB
Dart
import 'dart:async';
|
||
|
||
import 'package:flutter/foundation.dart';
|
||
import 'package:flutter/widgets.dart';
|
||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||
import 'package:intl/intl.dart' as intl;
|
||
|
||
import 'app_localizations_de.dart';
|
||
import 'app_localizations_en.dart';
|
||
|
||
// ignore_for_file: type=lint
|
||
|
||
/// Callers can lookup localized strings with an instance of AppLocalizations
|
||
/// returned by `AppLocalizations.of(context)`.
|
||
///
|
||
/// Applications need to include `AppLocalizations.delegate()` in their app's
|
||
/// `localizationDelegates` list, and the locales they support in the app's
|
||
/// `supportedLocales` list. For example:
|
||
///
|
||
/// ```dart
|
||
/// import 'l10n/app_localizations.dart';
|
||
///
|
||
/// return MaterialApp(
|
||
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||
/// supportedLocales: AppLocalizations.supportedLocales,
|
||
/// home: MyApplicationHome(),
|
||
/// );
|
||
/// ```
|
||
///
|
||
/// ## Update pubspec.yaml
|
||
///
|
||
/// Please make sure to update your pubspec.yaml to include the following
|
||
/// packages:
|
||
///
|
||
/// ```yaml
|
||
/// dependencies:
|
||
/// # Internationalization support.
|
||
/// flutter_localizations:
|
||
/// sdk: flutter
|
||
/// intl: any # Use the pinned version from flutter_localizations
|
||
///
|
||
/// # Rest of dependencies
|
||
/// ```
|
||
///
|
||
/// ## iOS Applications
|
||
///
|
||
/// iOS applications define key application metadata, including supported
|
||
/// locales, in an Info.plist file that is built into the application bundle.
|
||
/// To configure the locales supported by your app, you’ll need to edit this
|
||
/// file.
|
||
///
|
||
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
|
||
/// Then, in the Project Navigator, open the Info.plist file under the Runner
|
||
/// project’s Runner folder.
|
||
///
|
||
/// Next, select the Information Property List item, select Add Item from the
|
||
/// Editor menu, then select Localizations from the pop-up menu.
|
||
///
|
||
/// Select and expand the newly-created Localizations item then, for each
|
||
/// locale your application supports, add a new item and select the locale
|
||
/// you wish to add from the pop-up menu in the Value field. This list should
|
||
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
|
||
/// property.
|
||
abstract class AppLocalizations {
|
||
AppLocalizations(String locale)
|
||
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
|
||
|
||
final String localeName;
|
||
|
||
static AppLocalizations of(BuildContext context) {
|
||
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
|
||
}
|
||
|
||
static const LocalizationsDelegate<AppLocalizations> delegate =
|
||
_AppLocalizationsDelegate();
|
||
|
||
/// A list of this localizations delegate along with the default localizations
|
||
/// delegates.
|
||
///
|
||
/// Returns a list of localizations delegates containing this delegate along with
|
||
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
|
||
/// and GlobalWidgetsLocalizations.delegate.
|
||
///
|
||
/// Additional delegates can be added by appending to this list in
|
||
/// MaterialApp. This list does not have to be used at all if a custom list
|
||
/// of delegates is preferred or required.
|
||
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
|
||
<LocalizationsDelegate<dynamic>>[
|
||
delegate,
|
||
GlobalMaterialLocalizations.delegate,
|
||
GlobalCupertinoLocalizations.delegate,
|
||
GlobalWidgetsLocalizations.delegate,
|
||
];
|
||
|
||
/// A list of this localizations delegate's supported locales.
|
||
static const List<Locale> supportedLocales = <Locale>[
|
||
Locale('de'),
|
||
Locale('en'),
|
||
Locale('en', 'GB'),
|
||
Locale('en', 'US'),
|
||
];
|
||
|
||
/// The app's name: the window's title, and where halkyon_app's texts name the app.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Halkyon Train'**
|
||
String get appTitle;
|
||
|
||
/// The app's word in its wordmark, under "Halkyon".
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Train'**
|
||
String get launchProduct;
|
||
|
||
/// No description provided for @instanceFirstStartSubtitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Choose the instance to keep your workouts on. Someone runs each one; you can add others later.'**
|
||
String get instanceFirstStartSubtitle;
|
||
|
||
/// No description provided for @homeEmptyTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'No workouts yet'**
|
||
String get homeEmptyTitle;
|
||
|
||
/// No description provided for @homeEmptyHint.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Workouts recorded on your phone show here.'**
|
||
String get homeEmptyHint;
|
||
|
||
/// No description provided for @accountTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Account'**
|
||
String get accountTitle;
|
||
|
||
/// No description provided for @accountDeleteMessage.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Your account is deleted on the server and on all your devices. This can\'t be undone.'**
|
||
String get accountDeleteMessage;
|
||
|
||
/// No description provided for @aboutTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'About'**
|
||
String get aboutTitle;
|
||
|
||
/// No description provided for @homeRecordHint.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Record one with the button below.'**
|
||
String get homeRecordHint;
|
||
|
||
/// No description provided for @recordAction.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Record'**
|
||
String get recordAction;
|
||
|
||
/// No description provided for @recordBack.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Back to the recording'**
|
||
String get recordBack;
|
||
|
||
/// No description provided for @recordSheetTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Record a workout'**
|
||
String get recordSheetTitle;
|
||
|
||
/// No description provided for @activityRunning.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Running'**
|
||
String get activityRunning;
|
||
|
||
/// No description provided for @activityWalking.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Walking'**
|
||
String get activityWalking;
|
||
|
||
/// No description provided for @activityHiking.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Hiking'**
|
||
String get activityHiking;
|
||
|
||
/// No description provided for @activityCycling.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Cycling'**
|
||
String get activityCycling;
|
||
|
||
/// No description provided for @activityIndoorRowing.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Rowing indoors'**
|
||
String get activityIndoorRowing;
|
||
|
||
/// The switch for auto-pause, as the recording starts.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Pause by itself'**
|
||
String get recordAutoPause;
|
||
|
||
/// No description provided for @recordAutoPauseHint.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'When you stand still, and going on as you move again'**
|
||
String get recordAutoPauseHint;
|
||
|
||
/// No description provided for @recordStart.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Start'**
|
||
String get recordStart;
|
||
|
||
/// No description provided for @recordLocationRefused.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Train needs your location to record this. You can allow it in the system\'s settings.'**
|
||
String get recordLocationRefused;
|
||
|
||
/// No description provided for @recordingWaitingForGps.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Waiting for GPS'**
|
||
String get recordingWaitingForGps;
|
||
|
||
/// Before a fix precise enough: how far off the last one may be.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Waiting for GPS · ±{metres} m'**
|
||
String recordingWaitingForGpsAccuracy(int metres);
|
||
|
||
/// How far off the last fix may be.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'GPS ±{metres} m'**
|
||
String recordingGpsAccuracy(int metres);
|
||
|
||
/// Under the time, lower case: the time moved, pauses left out.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'moving time'**
|
||
String get recordingMovingTime;
|
||
|
||
/// No description provided for @recordingDistance.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'distance'**
|
||
String get recordingDistance;
|
||
|
||
/// No description provided for @recordingPace.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'pace'**
|
||
String get recordingPace;
|
||
|
||
/// No description provided for @recordingSpeed.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'speed'**
|
||
String get recordingSpeed;
|
||
|
||
/// No description provided for @recordingDistanceValue.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'{km} km'**
|
||
String recordingDistanceValue(String km);
|
||
|
||
/// Minutes and seconds a kilometre takes.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'{pace} /km'**
|
||
String recordingPaceValue(String pace);
|
||
|
||
/// No description provided for @recordingSpeedValue.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'{kmh} km/h'**
|
||
String recordingSpeedValue(String kmh);
|
||
|
||
/// Train paused the recording by itself (auto-pause).
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Paused: not moving'**
|
||
String get recordingPausedAuto;
|
||
|
||
/// No description provided for @recordingPausedByHand.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Paused'**
|
||
String get recordingPausedByHand;
|
||
|
||
/// No description provided for @recordingPause.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Pause'**
|
||
String get recordingPause;
|
||
|
||
/// No description provided for @recordingResume.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Resume'**
|
||
String get recordingResume;
|
||
|
||
/// No description provided for @recordingStop.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Stop'**
|
||
String get recordingStop;
|
||
|
||
/// No description provided for @recordingHoldToStop.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Hold Stop to end the workout'**
|
||
String get recordingHoldToStop;
|
||
|
||
/// No description provided for @recordingStoppedTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Save this workout?'**
|
||
String get recordingStoppedTitle;
|
||
|
||
/// No description provided for @recordingSave.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Save'**
|
||
String get recordingSave;
|
||
|
||
/// No description provided for @recordingDiscard.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Discard'**
|
||
String get recordingDiscard;
|
||
|
||
/// No description provided for @recordingDiscardTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Discard this workout?'**
|
||
String get recordingDiscardTitle;
|
||
|
||
/// No description provided for @recordingDiscardMessage.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Its time and track are deleted from this device. This can\'t be undone.'**
|
||
String get recordingDiscardMessage;
|
||
|
||
/// No description provided for @recordingSaveFailed.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'It can\'t be saved on this device, which doesn\'t hold your account\'s keys. It stays here until it can be.'**
|
||
String get recordingSaveFailed;
|
||
|
||
/// No description provided for @recordingCutOffTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'A recording was cut off'**
|
||
String get recordingCutOffTitle;
|
||
|
||
/// A recording found unfinished as the app opened: when it started and its last sample.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'A recording from {start} was cut off. Save it up to {end}, or discard it?'**
|
||
String recordingCutOffMessage(String start, String end);
|
||
|
||
/// The name of the recording's notification channel, in the system's settings.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Recording'**
|
||
String get recordingNotificationChannel;
|
||
|
||
/// The notification's title while paused.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'{activity} · paused'**
|
||
String recordingNotificationPaused(String activity);
|
||
|
||
/// A workout's name where the person gave none: the time of day it started (morning 5–12, afternoon 12–17, evening 17–22, night) and its activity, as Strava names them.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'{when, select, morning_running{Morning run} morning_walking{Morning walk} morning_hiking{Morning hike} morning_cycling{Morning ride} morning_indoorRowing{Morning row} afternoon_running{Afternoon run} afternoon_walking{Afternoon walk} afternoon_hiking{Afternoon hike} afternoon_cycling{Afternoon ride} afternoon_indoorRowing{Afternoon row} evening_running{Evening run} evening_walking{Evening walk} evening_hiking{Evening hike} evening_cycling{Evening ride} evening_indoorRowing{Evening row} night_running{Night run} night_walking{Night walk} night_hiking{Night hike} night_cycling{Night ride} night_indoorRowing{Night row} other{Workout}}'**
|
||
String workoutName(String when);
|
||
|
||
/// No description provided for @workoutLocked.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Locked workout'**
|
||
String get workoutLocked;
|
||
|
||
/// Under a workout this device can't open (its key is missing here).
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'This device doesn\'t hold the key it\'s sealed with.'**
|
||
String get workoutLockedHint;
|
||
|
||
/// No description provided for @workoutEdit.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Edit'**
|
||
String get workoutEdit;
|
||
|
||
/// No description provided for @workoutEditTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Edit workout'**
|
||
String get workoutEditTitle;
|
||
|
||
/// No description provided for @workoutNameLabel.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Name'**
|
||
String get workoutNameLabel;
|
||
|
||
/// No description provided for @workoutNotesLabel.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Notes'**
|
||
String get workoutNotesLabel;
|
||
|
||
/// No description provided for @workoutSave.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Save'**
|
||
String get workoutSave;
|
||
|
||
/// No description provided for @workoutDelete.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Delete'**
|
||
String get workoutDelete;
|
||
|
||
/// No description provided for @workoutDeleteTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Delete this workout?'**
|
||
String get workoutDeleteTitle;
|
||
|
||
/// No description provided for @workoutDeleteMessage.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'It\'s deleted on all your devices.'**
|
||
String get workoutDeleteMessage;
|
||
|
||
/// No description provided for @workoutDeleted.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Workout deleted'**
|
||
String get workoutDeleted;
|
||
|
||
/// No description provided for @workoutMovingTime.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'moving time'**
|
||
String get workoutMovingTime;
|
||
|
||
/// Lower case, under a figure: from start to end, pauses included.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'whole time'**
|
||
String get workoutTotalTime;
|
||
|
||
/// No description provided for @workoutDistance.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'distance'**
|
||
String get workoutDistance;
|
||
|
||
/// No description provided for @workoutPace.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'pace'**
|
||
String get workoutPace;
|
||
|
||
/// No description provided for @workoutSpeed.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'speed'**
|
||
String get workoutSpeed;
|
||
|
||
/// Lower case, under a figure: the elevation gained.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'climbed'**
|
||
String get workoutClimb;
|
||
|
||
/// No description provided for @workoutClimbValue.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'{metres} m'**
|
||
String workoutClimbValue(int metres);
|
||
|
||
/// No description provided for @workoutSplits.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Splits'**
|
||
String get workoutSplits;
|
||
|
||
/// A kilometre's split, its number.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'km {number}'**
|
||
String workoutSplitKm(int number);
|
||
|
||
/// A cycling split of 5 km: where it starts and ends.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'{from}–{to} km'**
|
||
String workoutSplitFiveKm(int from, int to);
|
||
|
||
/// No description provided for @workoutPaceChart.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Pace'**
|
||
String get workoutPaceChart;
|
||
|
||
/// No description provided for @workoutSpeedChart.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Speed'**
|
||
String get workoutSpeedChart;
|
||
|
||
/// No description provided for @workoutElevationChart.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Elevation'**
|
||
String get workoutElevationChart;
|
||
|
||
/// Under a workout's map: what the map's source sees.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Map by {name}: it sees your device\'s address and the area shown, not your track.'**
|
||
String workoutMapSource(String name);
|
||
|
||
/// A link to the map source's page about what it keeps.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'What {name} keeps'**
|
||
String workoutMapSourceAbout(String name);
|
||
|
||
/// No description provided for @workoutMapUnavailable.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'The map can\'t be loaded now.'**
|
||
String get workoutMapUnavailable;
|
||
|
||
/// No description provided for @workoutNotFound.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'This workout is gone.'**
|
||
String get workoutNotFound;
|
||
|
||
/// No description provided for @recordHeartRate.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Heart rate'**
|
||
String get recordHeartRate;
|
||
|
||
/// On the Record sheet, under Heart rate, where no strap is chosen.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'No strap'**
|
||
String get recordNoStrap;
|
||
|
||
/// No description provided for @strapSheetTitle.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Heart-rate strap'**
|
||
String get strapSheetTitle;
|
||
|
||
/// No description provided for @strapSearching.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Looking for straps nearby…'**
|
||
String get strapSearching;
|
||
|
||
/// No description provided for @strapSearchingHint.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Put the strap on: most wake up only once they touch skin.'**
|
||
String get strapSearchingHint;
|
||
|
||
/// Under a strap found: its signal is strong.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'close by'**
|
||
String get strapNear;
|
||
|
||
/// Under a strap found: its signal is weak.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'further off'**
|
||
String get strapFar;
|
||
|
||
/// A strap that sends no name.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Unnamed strap'**
|
||
String get strapUnnamed;
|
||
|
||
/// No description provided for @strapForget.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Forget strap'**
|
||
String get strapForget;
|
||
|
||
/// No description provided for @strapRefused.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Train needs nearby devices to find your strap. You can allow it in the system\'s settings.'**
|
||
String get strapRefused;
|
||
|
||
/// No description provided for @strapBluetoothOff.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Bluetooth is off. Turn it on to find your strap.'**
|
||
String get strapBluetoothOff;
|
||
|
||
/// Under the heart rate, lower case.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'heart rate'**
|
||
String get recordingHeartRate;
|
||
|
||
/// While recording: the strap is out of reach or off; Train keeps asking for it.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Strap lost'**
|
||
String get recordingStrapLost;
|
||
|
||
/// Lower case, under a figure.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'average heart rate'**
|
||
String get workoutAverageHeartRate;
|
||
|
||
/// Lower case, under a figure.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'highest heart rate'**
|
||
String get workoutMaxHeartRate;
|
||
|
||
/// No description provided for @workoutBpmValue.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'{bpm} bpm'**
|
||
String workoutBpmValue(int bpm);
|
||
|
||
/// No description provided for @workoutHeartRateChart.
|
||
///
|
||
/// In en, this message translates to:
|
||
/// **'Heart rate'**
|
||
String get workoutHeartRateChart;
|
||
}
|
||
|
||
class _AppLocalizationsDelegate
|
||
extends LocalizationsDelegate<AppLocalizations> {
|
||
const _AppLocalizationsDelegate();
|
||
|
||
@override
|
||
Future<AppLocalizations> load(Locale locale) {
|
||
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
|
||
}
|
||
|
||
@override
|
||
bool isSupported(Locale locale) =>
|
||
<String>['de', 'en'].contains(locale.languageCode);
|
||
|
||
@override
|
||
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||
}
|
||
|
||
AppLocalizations lookupAppLocalizations(Locale locale) {
|
||
// Lookup logic when language+country codes are specified.
|
||
switch (locale.languageCode) {
|
||
case 'en':
|
||
{
|
||
switch (locale.countryCode) {
|
||
case 'GB':
|
||
return AppLocalizationsEnGb();
|
||
case 'US':
|
||
return AppLocalizationsEnUs();
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Lookup logic when only language code is specified.
|
||
switch (locale.languageCode) {
|
||
case 'de':
|
||
return AppLocalizationsDe();
|
||
case 'en':
|
||
return AppLocalizationsEn();
|
||
}
|
||
|
||
throw FlutterError(
|
||
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
|
||
'an issue with the localizations generation tool. Please file an issue '
|
||
'on GitHub with a reproducible sample app and the gen-l10n configuration '
|
||
'that was used.',
|
||
);
|
||
}
|