mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-02-16 14:29:35 +00:00
添加语言切换
This commit is contained in:
parent
e0deb84123
commit
e06c834d0e
21 changed files with 1416 additions and 281 deletions
|
|
@ -12,18 +12,17 @@ part 'app_settings.g.dart';
|
|||
@freezed
|
||||
class AppSettings with _$AppSettings {
|
||||
const factory AppSettings({
|
||||
@Default('zh') String language,
|
||||
@Default(ThemeSettings()) ThemeSettings themeSettings,
|
||||
@Default(PlayerSettings()) PlayerSettings playerSettings,
|
||||
@Default(SleepTimerSettings()) SleepTimerSettings sleepTimerSettings,
|
||||
@Default(DownloadSettings()) DownloadSettings downloadSettings,
|
||||
@Default(NotificationSettings()) NotificationSettings notificationSettings,
|
||||
@Default(ShakeDetectionSettings())
|
||||
ShakeDetectionSettings shakeDetectionSettings,
|
||||
@Default(ShakeDetectionSettings()) ShakeDetectionSettings shakeDetectionSettings,
|
||||
@Default(HomePageSettings()) HomePageSettings homePageSettings,
|
||||
}) = _AppSettings;
|
||||
|
||||
factory AppSettings.fromJson(Map<String, dynamic> json) =>
|
||||
_$AppSettingsFromJson(json);
|
||||
factory AppSettings.fromJson(Map<String, dynamic> json) => _$AppSettingsFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
|
@ -37,17 +36,14 @@ class ThemeSettings with _$ThemeSettings {
|
|||
@Default(true) bool useCurrentPlayerThemeThroughoutApp,
|
||||
}) = _ThemeSettings;
|
||||
|
||||
factory ThemeSettings.fromJson(Map<String, dynamic> json) =>
|
||||
_$ThemeSettingsFromJson(json);
|
||||
factory ThemeSettings.fromJson(Map<String, dynamic> json) => _$ThemeSettingsFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class PlayerSettings with _$PlayerSettings {
|
||||
const factory PlayerSettings({
|
||||
@Default(MinimizedPlayerSettings())
|
||||
MinimizedPlayerSettings miniPlayerSettings,
|
||||
@Default(ExpandedPlayerSettings())
|
||||
ExpandedPlayerSettings expandedPlayerSettings,
|
||||
@Default(MinimizedPlayerSettings()) MinimizedPlayerSettings miniPlayerSettings,
|
||||
@Default(ExpandedPlayerSettings()) ExpandedPlayerSettings expandedPlayerSettings,
|
||||
@Default(1) double preferredDefaultVolume,
|
||||
@Default(1) double preferredDefaultSpeed,
|
||||
@Default([1, 1.25, 1.5, 1.75, 2]) List<double> speedOptions,
|
||||
|
|
@ -60,8 +56,7 @@ class PlayerSettings with _$PlayerSettings {
|
|||
@Default(true) bool configurePlayerForEveryBook,
|
||||
}) = _PlayerSettings;
|
||||
|
||||
factory PlayerSettings.fromJson(Map<String, dynamic> json) =>
|
||||
_$PlayerSettingsFromJson(json);
|
||||
factory PlayerSettings.fromJson(Map<String, dynamic> json) => _$PlayerSettingsFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
|
@ -144,8 +139,7 @@ class DownloadSettings with _$DownloadSettings {
|
|||
@Default(3) int maxConcurrentByGroup,
|
||||
}) = _DownloadSettings;
|
||||
|
||||
factory DownloadSettings.fromJson(Map<String, dynamic> json) =>
|
||||
_$DownloadSettingsFromJson(json);
|
||||
factory DownloadSettings.fromJson(Map<String, dynamic> json) => _$DownloadSettingsFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
|
@ -202,8 +196,7 @@ class ShakeDetectionSettings with _$ShakeDetectionSettings {
|
|||
@Default(ShakeDirection.horizontal) ShakeDirection direction,
|
||||
@Default(5) double threshold,
|
||||
@Default(ShakeAction.resetSleepTimer) ShakeAction shakeAction,
|
||||
@Default({ShakeDetectedFeedback.vibrate})
|
||||
Set<ShakeDetectedFeedback> feedback,
|
||||
@Default({ShakeDetectedFeedback.vibrate}) Set<ShakeDetectedFeedback> feedback,
|
||||
@Default(0.5) double beepVolume,
|
||||
|
||||
/// the duration to wait before the shake detection is enabled again
|
||||
|
|
@ -241,6 +234,5 @@ class HomePageSettings with _$HomePageSettings {
|
|||
@Default(false) bool showPlayButtonOnListenAgainShelf,
|
||||
}) = _HomePageSettings;
|
||||
|
||||
factory HomePageSettings.fromJson(Map<String, dynamic> json) =>
|
||||
_$HomePageSettingsFromJson(json);
|
||||
factory HomePageSettings.fromJson(Map<String, dynamic> json) => _$HomePageSettingsFromJson(json);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ AppSettings _$AppSettingsFromJson(Map<String, dynamic> json) {
|
|||
|
||||
/// @nodoc
|
||||
mixin _$AppSettings {
|
||||
String get language => throw _privateConstructorUsedError;
|
||||
ThemeSettings get themeSettings => throw _privateConstructorUsedError;
|
||||
PlayerSettings get playerSettings => throw _privateConstructorUsedError;
|
||||
SleepTimerSettings get sleepTimerSettings =>
|
||||
|
|
@ -48,7 +49,8 @@ abstract class $AppSettingsCopyWith<$Res> {
|
|||
_$AppSettingsCopyWithImpl<$Res, AppSettings>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{ThemeSettings themeSettings,
|
||||
{String language,
|
||||
ThemeSettings themeSettings,
|
||||
PlayerSettings playerSettings,
|
||||
SleepTimerSettings sleepTimerSettings,
|
||||
DownloadSettings downloadSettings,
|
||||
|
|
@ -80,6 +82,7 @@ class _$AppSettingsCopyWithImpl<$Res, $Val extends AppSettings>
|
|||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? language = null,
|
||||
Object? themeSettings = null,
|
||||
Object? playerSettings = null,
|
||||
Object? sleepTimerSettings = null,
|
||||
|
|
@ -89,6 +92,10 @@ class _$AppSettingsCopyWithImpl<$Res, $Val extends AppSettings>
|
|||
Object? homePageSettings = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
language: null == language
|
||||
? _value.language
|
||||
: language // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
themeSettings: null == themeSettings
|
||||
? _value.themeSettings
|
||||
: themeSettings // ignore: cast_nullable_to_non_nullable
|
||||
|
|
@ -203,7 +210,8 @@ abstract class _$$AppSettingsImplCopyWith<$Res>
|
|||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{ThemeSettings themeSettings,
|
||||
{String language,
|
||||
ThemeSettings themeSettings,
|
||||
PlayerSettings playerSettings,
|
||||
SleepTimerSettings sleepTimerSettings,
|
||||
DownloadSettings downloadSettings,
|
||||
|
|
@ -240,6 +248,7 @@ class __$$AppSettingsImplCopyWithImpl<$Res>
|
|||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? language = null,
|
||||
Object? themeSettings = null,
|
||||
Object? playerSettings = null,
|
||||
Object? sleepTimerSettings = null,
|
||||
|
|
@ -249,6 +258,10 @@ class __$$AppSettingsImplCopyWithImpl<$Res>
|
|||
Object? homePageSettings = null,
|
||||
}) {
|
||||
return _then(_$AppSettingsImpl(
|
||||
language: null == language
|
||||
? _value.language
|
||||
: language // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
themeSettings: null == themeSettings
|
||||
? _value.themeSettings
|
||||
: themeSettings // ignore: cast_nullable_to_non_nullable
|
||||
|
|
@ -285,7 +298,8 @@ class __$$AppSettingsImplCopyWithImpl<$Res>
|
|||
@JsonSerializable()
|
||||
class _$AppSettingsImpl implements _AppSettings {
|
||||
const _$AppSettingsImpl(
|
||||
{this.themeSettings = const ThemeSettings(),
|
||||
{this.language = 'zh',
|
||||
this.themeSettings = const ThemeSettings(),
|
||||
this.playerSettings = const PlayerSettings(),
|
||||
this.sleepTimerSettings = const SleepTimerSettings(),
|
||||
this.downloadSettings = const DownloadSettings(),
|
||||
|
|
@ -296,6 +310,9 @@ class _$AppSettingsImpl implements _AppSettings {
|
|||
factory _$AppSettingsImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$AppSettingsImplFromJson(json);
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final String language;
|
||||
@override
|
||||
@JsonKey()
|
||||
final ThemeSettings themeSettings;
|
||||
|
|
@ -320,7 +337,7 @@ class _$AppSettingsImpl implements _AppSettings {
|
|||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettings(themeSettings: $themeSettings, playerSettings: $playerSettings, sleepTimerSettings: $sleepTimerSettings, downloadSettings: $downloadSettings, notificationSettings: $notificationSettings, shakeDetectionSettings: $shakeDetectionSettings, homePageSettings: $homePageSettings)';
|
||||
return 'AppSettings(language: $language, themeSettings: $themeSettings, playerSettings: $playerSettings, sleepTimerSettings: $sleepTimerSettings, downloadSettings: $downloadSettings, notificationSettings: $notificationSettings, shakeDetectionSettings: $shakeDetectionSettings, homePageSettings: $homePageSettings)';
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -328,6 +345,8 @@ class _$AppSettingsImpl implements _AppSettings {
|
|||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$AppSettingsImpl &&
|
||||
(identical(other.language, language) ||
|
||||
other.language == language) &&
|
||||
(identical(other.themeSettings, themeSettings) ||
|
||||
other.themeSettings == themeSettings) &&
|
||||
(identical(other.playerSettings, playerSettings) ||
|
||||
|
|
@ -348,6 +367,7 @@ class _$AppSettingsImpl implements _AppSettings {
|
|||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
language,
|
||||
themeSettings,
|
||||
playerSettings,
|
||||
sleepTimerSettings,
|
||||
|
|
@ -374,7 +394,8 @@ class _$AppSettingsImpl implements _AppSettings {
|
|||
|
||||
abstract class _AppSettings implements AppSettings {
|
||||
const factory _AppSettings(
|
||||
{final ThemeSettings themeSettings,
|
||||
{final String language,
|
||||
final ThemeSettings themeSettings,
|
||||
final PlayerSettings playerSettings,
|
||||
final SleepTimerSettings sleepTimerSettings,
|
||||
final DownloadSettings downloadSettings,
|
||||
|
|
@ -385,6 +406,8 @@ abstract class _AppSettings implements AppSettings {
|
|||
factory _AppSettings.fromJson(Map<String, dynamic> json) =
|
||||
_$AppSettingsImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get language;
|
||||
@override
|
||||
ThemeSettings get themeSettings;
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ part of 'app_settings.dart';
|
|||
|
||||
_$AppSettingsImpl _$$AppSettingsImplFromJson(Map<String, dynamic> json) =>
|
||||
_$AppSettingsImpl(
|
||||
language: json['language'] as String? ?? 'zh',
|
||||
themeSettings: json['themeSettings'] == null
|
||||
? const ThemeSettings()
|
||||
: ThemeSettings.fromJson(
|
||||
|
|
@ -40,6 +41,7 @@ _$AppSettingsImpl _$$AppSettingsImplFromJson(Map<String, dynamic> json) =>
|
|||
|
||||
Map<String, dynamic> _$$AppSettingsImplToJson(_$AppSettingsImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'language': instance.language,
|
||||
'themeSettings': instance.themeSettings,
|
||||
'playerSettings': instance.playerSettings,
|
||||
'sleepTimerSettings': instance.sleepTimerSettings,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:flutter_settings_ui/flutter_settings_ui.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:vaani/generated/l10n.dart';
|
||||
import 'package:vaani/router/router.dart';
|
||||
import 'package:vaani/settings/app_settings_provider.dart';
|
||||
import 'package:vaani/settings/models/app_settings.dart' as model;
|
||||
|
|
@ -18,14 +19,13 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
const AppSettingsPage({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final appSettings = ref.watch(appSettingsProvider);
|
||||
final sleepTimerSettings = appSettings.sleepTimerSettings;
|
||||
|
||||
final locales = {'en': 'English', 'zh': '中文'};
|
||||
return SimpleSettingsPage(
|
||||
title: const Text('App Settings'),
|
||||
title: Text(S.of(context).appSettings),
|
||||
sections: [
|
||||
// General section
|
||||
SettingsSection(
|
||||
|
|
@ -34,25 +34,42 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
vertical: 8.0,
|
||||
),
|
||||
title: Text(
|
||||
'General',
|
||||
S.of(context).general,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
tiles: [
|
||||
SettingsTile(
|
||||
title: const Text('Player Settings'),
|
||||
title: Text(S.of(context).language),
|
||||
leading: const Icon(Icons.play_arrow),
|
||||
description: const Text(
|
||||
'Customize the player settings',
|
||||
trailing: DropdownButton(
|
||||
value: appSettings.language,
|
||||
items: S.delegate.supportedLocales.map((locale) {
|
||||
return DropdownMenuItem(
|
||||
value: locale.languageCode,
|
||||
child: Text(locales[locale.languageCode] ?? 'unknown'),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
ref.read(appSettingsProvider.notifier).update(
|
||||
appSettings.copyWith(
|
||||
language: value!,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
description: Text(S.of(context).languageDescription),
|
||||
),
|
||||
SettingsTile(
|
||||
title: Text(S.of(context).playerSettings),
|
||||
leading: const Icon(Icons.play_arrow),
|
||||
description: Text(S.of(context).playerSettingsDescription),
|
||||
onPressed: (context) {
|
||||
context.pushNamed(Routes.playerSettings.name);
|
||||
},
|
||||
),
|
||||
NavigationWithSwitchTile(
|
||||
title: const Text('Auto Turn On Sleep Timer'),
|
||||
description: const Text(
|
||||
'Automatically turn on the sleep timer based on the time of day',
|
||||
),
|
||||
title: Text(S.of(context).autoTurnOnSleepTimer),
|
||||
description: Text(S.of(context).automaticallyDescription),
|
||||
leading: sleepTimerSettings.autoTurnOnTimer
|
||||
? const Icon(Symbols.time_auto, fill: 1)
|
||||
: const Icon(Symbols.timer_off, fill: 1),
|
||||
|
|
@ -69,10 +86,10 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
},
|
||||
),
|
||||
NavigationWithSwitchTile(
|
||||
title: const Text('Shake Detector'),
|
||||
title: Text(S.of(context).shakeDetector),
|
||||
leading: const Icon(Icons.vibration),
|
||||
description: const Text(
|
||||
'Customize the shake detector settings',
|
||||
description: Text(
|
||||
S.of(context).shakeDetectorDescription,
|
||||
),
|
||||
value: appSettings.shakeDetectionSettings.isEnabled,
|
||||
onPressed: (context) {
|
||||
|
|
@ -96,36 +113,30 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
vertical: 8.0,
|
||||
),
|
||||
title: Text(
|
||||
'Appearance',
|
||||
S.of(context).appearance,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
tiles: [
|
||||
SettingsTile.navigation(
|
||||
leading: const Icon(Icons.color_lens),
|
||||
title: const Text('Theme Settings'),
|
||||
description: const Text(
|
||||
'Customize the app theme',
|
||||
),
|
||||
title: Text(S.of(context).themeSettings),
|
||||
description: Text(S.of(context).themeSettingsDescription),
|
||||
onPressed: (context) {
|
||||
context.pushNamed(Routes.themeSettings.name);
|
||||
},
|
||||
),
|
||||
SettingsTile(
|
||||
title: const Text('Notification Media Player'),
|
||||
title: Text(S.of(context).notificationMediaPlayer),
|
||||
leading: const Icon(Icons.play_lesson),
|
||||
description: const Text(
|
||||
'Customize the media player in notifications',
|
||||
),
|
||||
description: Text(S.of(context).notificationMediaPlayerDescription),
|
||||
onPressed: (context) {
|
||||
context.pushNamed(Routes.notificationSettings.name);
|
||||
},
|
||||
),
|
||||
SettingsTile.navigation(
|
||||
leading: const Icon(Icons.home_filled),
|
||||
title: const Text('Home Page Settings'),
|
||||
description: const Text(
|
||||
'Customize the home page',
|
||||
),
|
||||
title: Text(S.of(context).homePageSettings),
|
||||
description: Text(S.of(context).homePageSettingsDescription),
|
||||
onPressed: (context) {
|
||||
context.pushNamed(Routes.homePageSettings.name);
|
||||
},
|
||||
|
|
@ -140,15 +151,15 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
vertical: 8.0,
|
||||
),
|
||||
title: Text(
|
||||
'Backup and Restore',
|
||||
S.of(context).backupAndRestore,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
tiles: [
|
||||
SettingsTile(
|
||||
title: const Text('Copy to Clipboard'),
|
||||
title: Text(S.of(context).copyToClipboard),
|
||||
leading: const Icon(Icons.copy),
|
||||
description: const Text(
|
||||
'Copy the app settings to the clipboard',
|
||||
description: Text(
|
||||
S.of(context).copyToClipboardDescription,
|
||||
),
|
||||
onPressed: (context) async {
|
||||
// copy to clipboard
|
||||
|
|
@ -159,18 +170,16 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
);
|
||||
// show toast
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Settings copied to clipboard'),
|
||||
SnackBar(
|
||||
content: Text(S.of(context).copyToClipboardToast),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
SettingsTile(
|
||||
title: const Text('Restore'),
|
||||
title: Text(S.of(context).restore),
|
||||
leading: const Icon(Icons.restore),
|
||||
description: const Text(
|
||||
'Restore the app settings from the backup',
|
||||
),
|
||||
description: Text(S.of(context).restoreDescription),
|
||||
onPressed: (context) {
|
||||
// show a dialog to get the backup
|
||||
showDialog(
|
||||
|
|
@ -184,33 +193,29 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
|
||||
// a button to reset the app settings
|
||||
SettingsTile(
|
||||
title: const Text('Reset App Settings'),
|
||||
title: Text(S.of(context).resetAppSettings),
|
||||
leading: const Icon(Icons.settings_backup_restore),
|
||||
description: const Text(
|
||||
'Reset the app settings to the default values',
|
||||
),
|
||||
description: Text(S.of(context).resetAppSettingsDescription),
|
||||
onPressed: (context) async {
|
||||
// confirm the reset
|
||||
final res = await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Reset App Settings'),
|
||||
content: const Text(
|
||||
'Are you sure you want to reset the app settings?',
|
||||
),
|
||||
title: Text(S.of(context).resetAppSettings),
|
||||
content: Text(S.of(context).resetAppSettingsDialog),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
child: const Text('Cancel'),
|
||||
child: Text(S.of(context).cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
child: const Text('Reset'),
|
||||
child: Text(S.of(context).reset),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
@ -242,14 +247,14 @@ class RestoreDialogue extends HookConsumerWidget {
|
|||
|
||||
final settingsInputController = useTextEditingController();
|
||||
return AlertDialog(
|
||||
title: const Text('Restore Backup'),
|
||||
title: Text(S.of(context).restoreBackup),
|
||||
content: Form(
|
||||
key: formKey,
|
||||
child: TextFormField(
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Backup',
|
||||
hintText: 'Paste the backup here',
|
||||
labelText: S.of(context).backup,
|
||||
hintText: S.of(context).restoreBackupHint,
|
||||
// clear button
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(Icons.clear),
|
||||
|
|
@ -260,7 +265,7 @@ class RestoreDialogue extends HookConsumerWidget {
|
|||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please paste the backup here';
|
||||
return S.of(context).restoreBackupValidator;
|
||||
}
|
||||
try {
|
||||
// try to decode the backup
|
||||
|
|
@ -268,7 +273,7 @@ class RestoreDialogue extends HookConsumerWidget {
|
|||
jsonDecode(value),
|
||||
);
|
||||
} catch (e) {
|
||||
return 'Invalid backup';
|
||||
return S.of(context).restoreBackupInvalid;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
|
@ -281,8 +286,8 @@ class RestoreDialogue extends HookConsumerWidget {
|
|||
if (formKey.currentState!.validate()) {
|
||||
if (settings.value == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Invalid backup'),
|
||||
SnackBar(
|
||||
content: Text(S.of(context).restoreBackupInvalid),
|
||||
),
|
||||
);
|
||||
return;
|
||||
|
|
@ -291,19 +296,19 @@ class RestoreDialogue extends HookConsumerWidget {
|
|||
settingsInputController.clear();
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Settings restored'),
|
||||
SnackBar(
|
||||
content: Text(S.of(context).restoreBackupSuccess),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Invalid backup'),
|
||||
SnackBar(
|
||||
content: Text(S.of(context).restoreBackupInvalid),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Text('Restore'),
|
||||
child: Text(S.of(context).restore),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:vaani/generated/l10n.dart';
|
||||
|
||||
class OkButton<T> extends StatelessWidget {
|
||||
const OkButton({
|
||||
|
|
@ -12,7 +13,7 @@ class OkButton<T> extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return TextButton(
|
||||
onPressed: onPressed,
|
||||
child: const Text('OK'),
|
||||
child: Text(S.of(context).ok),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +33,7 @@ class CancelButton extends StatelessWidget {
|
|||
onPressed?.call();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Cancel'),
|
||||
child: Text(S.of(context).cancel),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue