Skip to content

Commit 32ea025

Browse files
committed
Add language setting
1 parent 1d042d5 commit 32ea025

File tree

8 files changed

+177
-13
lines changed

8 files changed

+177
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
### V 1.1.5
22

33
- Hide Eargear triggers if no Ears are paired
4+
- Add setting to change the app language
45

56
### V 1.1.4
67

lib/Frontend/pages/settings.dart

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1+
import 'package:choice/choice.dart';
2+
import 'package:country_flags/country_flags.dart';
13
import 'package:flex_color_picker/flex_color_picker.dart';
24
import 'package:flutter/material.dart';
5+
import 'package:flutter_localized_locales/flutter_localized_locales.dart';
36
import 'package:flutter_riverpod/flutter_riverpod.dart';
47
import 'package:wakelock_plus/wakelock_plus.dart';
58

69
import '../../Backend/Bluetooth/bluetooth_manager.dart';
710
import '../../Backend/Definitions/Device/device_definition.dart';
811
import '../../Backend/logging_wrappers.dart';
912
import '../../constants.dart';
13+
import '../../l10n/app_localizations.dart';
1014
import '../go_router_config.dart';
1115
import '../translation_string_definitions.dart';
16+
import '../utils.dart';
1217

1318
class Settings extends ConsumerStatefulWidget {
1419
const Settings({super.key});
@@ -36,6 +41,7 @@ class _SettingsState extends ConsumerState<Settings> {
3641
body: ListView(
3742
controller: _controller,
3843
children: [
44+
LanguagePicker(),
3945
ListTile(
4046
leading: const Icon(Icons.color_lens),
4147
title: Text(
@@ -253,3 +259,114 @@ class _SettingsState extends ConsumerState<Settings> {
253259
_controller.dispose();
254260
}
255261
}
262+
263+
class LanguagePicker extends StatelessWidget {
264+
final ChoicePromptBuilder<Locale>? anchorBuilder;
265+
266+
const LanguagePicker({
267+
super.key,
268+
this.anchorBuilder,
269+
});
270+
271+
@override
272+
Widget build(BuildContext context) {
273+
return PromptedChoice<Locale>.single(
274+
title: appLanguageSelectorTitle(),
275+
promptDelegate: ChoicePrompt.delegateBottomSheet(useRootNavigator: true, enableDrag: true, maxHeightFactor: 0.8),
276+
itemCount: AppLocalizations.supportedLocales.length,
277+
modalHeaderBuilder: ChoiceModal.createHeader(
278+
automaticallyImplyLeading: true,
279+
actionsBuilder: [],
280+
),
281+
anchorBuilder: anchorBuilder,
282+
modalFooterBuilder: ChoiceModal.createFooter(
283+
mainAxisAlignment: MainAxisAlignment.center,
284+
children: [
285+
(choiceController) {
286+
return FilledButton(
287+
onPressed: choiceController.value.isNotEmpty ? () => choiceController.closeModal(confirmed: true) : null,
288+
child: Row(
289+
mainAxisAlignment: MainAxisAlignment.center,
290+
children: [
291+
const Icon(Icons.check),
292+
const Padding(
293+
padding: EdgeInsets.symmetric(horizontal: 4),
294+
),
295+
Text(
296+
triggersDefSelectSaveLabel(),
297+
style: Theme.of(context).textTheme.labelLarge!.copyWith(
298+
color: getTextColor(
299+
Theme.of(context).colorScheme.primary,
300+
),
301+
),
302+
),
303+
],
304+
),
305+
);
306+
},
307+
],
308+
),
309+
onChanged: (value) async {
310+
if (value != null) {
311+
HiveProxy.put(settings, selectedLocale, value.toLanguageTag());
312+
initLocale();
313+
}
314+
},
315+
confirmation: true,
316+
value: AppLocalizations.supportedLocales
317+
.where(
318+
(element) => element.toLanguageTag() == HiveProxy.getOrDefault(settings, selectedLocale, defaultValue: ""),
319+
)
320+
.firstOrNull,
321+
itemBuilder: (ChoiceController<Locale> state, int index) {
322+
Locale locale = AppLocalizations.supportedLocales[index];
323+
return RadioListTile(
324+
value: locale,
325+
onChanged: (Locale? value) {
326+
state.select(locale);
327+
},
328+
groupValue: state.single,
329+
title: Text(LocaleNames.of(context)!.nameOf(locale.toLanguageTag().replaceAll("-", "_")) ?? locale.toLanguageTag()),
330+
secondary: Builder(builder: (context) {
331+
if (locale.countryCode != null) {
332+
return CountryFlag.fromCountryCode(locale.countryCode!.replaceAll("zh", "zh-cn"));
333+
} else {
334+
return CountryFlag.fromLanguageCode(locale.languageCode.replaceAll("zh", "zh-cn"));
335+
}
336+
}),
337+
);
338+
},
339+
);
340+
return ListTile(
341+
title: Text("Language"),
342+
trailing: DropdownMenu<Locale>(
343+
width: MediaQuery.of(context).size.width / 3,
344+
onSelected: (value) {
345+
if (value != null) {
346+
HiveProxy.put(settings, selectedLocale, value.toLanguageTag());
347+
}
348+
},
349+
initialSelection: AppLocalizations.supportedLocales
350+
.where(
351+
(element) => element.toLanguageTag() == HiveProxy.getOrDefault(settings, selectedLocale, defaultValue: ""),
352+
)
353+
.firstOrNull,
354+
dropdownMenuEntries: AppLocalizations.supportedLocales
355+
.map(
356+
(e) => DropdownMenuEntry(
357+
label: LocaleNames.of(context)!.nameOf(e.toLanguageTag().replaceAll("-", "_")) ?? e.toLanguageTag(),
358+
value: e,
359+
leadingIcon: Builder(builder: (context) {
360+
if (e.countryCode != null) {
361+
return CountryFlag.fromCountryCode(e.countryCode!.replaceAll("zh", "zh-cn"));
362+
} else {
363+
return CountryFlag.fromLanguageCode(e.languageCode.replaceAll("zh", "zh-cn"));
364+
}
365+
}),
366+
),
367+
)
368+
.toList(),
369+
),
370+
);
371+
}
372+
}

lib/Frontend/translation_string_definitions.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,3 +443,5 @@ String morePageCoverPromoDescription({required String couponCode}) =>
443443
String morePageTranslateTitle() => Intl.message('Localization', name: 'morePageTranslateTitle', desc: 'The title for the button on the More page to push users to assist in translating the app');
444444

445445
String morePageTranslateDescription() => Intl.message('Help us Translate the app into your language', name: 'morePageTranslateDescription', desc: 'The description for the button on the More page to push users to assist in translating the app');
446+
447+
String appLanguageSelectorTitle() => Intl.message('App Language', name: 'appLanguageSelectorTitle', desc: 'The title for the button and dialog to select the app language');

lib/Frontend/utils.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:dio/dio.dart';
33
import 'package:dio_smart_retry/dio_smart_retry.dart';
44
import 'package:flutter/material.dart';
55
import 'package:flutter/services.dart';
6+
import 'package:intl/intl.dart';
67
import 'package:logarte/logarte.dart';
78
import 'package:logging/logging.dart';
89
import 'package:permission_handler/permission_handler.dart';
@@ -13,6 +14,9 @@ import 'package:wordpress_client/wordpress_client.dart';
1314

1415
import '../Backend/logging_wrappers.dart';
1516
import '../Backend/version.dart';
17+
import '../constants.dart';
18+
import '../l10n/app_localizations.dart';
19+
import '../l10n/messages_all_locales.dart';
1620

1721
LocalPlatform platform = const LocalPlatform();
1822

@@ -40,6 +44,22 @@ Future<bool> getBluetoothPermission(Logger logger) async {
4044
return granted;
4145
}
4246

47+
Future<void> initLocale() async {
48+
final String defaultLocale = platform.localeName; // Returns locale string in the form 'en_US'
49+
50+
String? locale = AppLocalizations.supportedLocales
51+
.where(
52+
(element) => element.toLanguageTag() == HiveProxy.getOrDefault(settings, selectedLocale, defaultValue: ""),
53+
)
54+
.map(
55+
(e) => e.toLanguageTag(),
56+
)
57+
.firstOrNull;
58+
59+
await initializeMessages(locale ?? defaultLocale);
60+
Intl.defaultLocale = locale ?? defaultLocale;
61+
}
62+
4363
final dioLogger = Logger('Dio');
4464

4565
Dio? _dio;

lib/constants.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const String casualModeDelayMax = 'casualModeDelayMax';
2929
const String tailBlogWifiOnly = 'tailBlogWifiOnly';
3030
const String triggerActionCooldown = 'triggerActionCooldown';
3131
const String gearConnectRetryAttempts = 'gearConnectRetryAttempts';
32+
const String selectedLocale = 'selectedLocale';
3233

3334
// Settings Default value
3435
const bool kitsuneModeDefault = false;

lib/main.dart

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import 'package:feedback_sentry/feedback_sentry.dart';
77
import 'package:flutter/foundation.dart';
88
import 'package:flutter/material.dart';
99
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
10+
import 'package:flutter_localized_locales/flutter_localized_locales.dart';
1011
import 'package:flutter_native_splash/flutter_native_splash.dart';
1112
import 'package:flutter_riverpod/flutter_riverpod.dart';
1213
import 'package:hive_ce_flutter/adapters.dart';
13-
import 'package:intl/intl.dart';
1414
import 'package:logging/logging.dart';
1515
import 'package:package_info_plus/package_info_plus.dart';
1616
import 'package:path_provider/path_provider.dart';
@@ -33,7 +33,6 @@ import 'Frontend/translation_string_definitions.dart';
3333
import 'Frontend/utils.dart';
3434
import 'constants.dart';
3535
import 'l10n/app_localizations.dart';
36-
import 'l10n/messages_all_locales.dart';
3736

3837
FutureOr<SentryEvent?> beforeSend(SentryEvent event, Hint hint) async {
3938
bool reportingEnabled = HiveProxy.getOrDefault(settings, "allowErrorReporting", defaultValue: true);
@@ -216,15 +215,6 @@ Future<void> initHive() async {
216215
await Hive.openBox<BaseStoredDevice>(devicesBox);
217216
}
218217

219-
Future<void> initLocale() async {
220-
final String defaultLocale = platform.localeName; // Returns locale string in the form 'en_US'
221-
mainLogger.info("Locale: $defaultLocale");
222-
223-
bool localeLoaded = await initializeMessages(defaultLocale);
224-
Intl.defaultLocale = defaultLocale;
225-
mainLogger.info("Loaded locale: $defaultLocale $localeLoaded");
226-
}
227-
228218
class TailApp extends ConsumerWidget {
229219
TailApp({super.key}) {
230220
// Platform messages may fail, so we use a try/catch PlatformException.
@@ -265,7 +255,7 @@ class TailApp extends ConsumerWidget {
265255
theme: buildTheme(Brightness.light, color),
266256
darkTheme: buildTheme(Brightness.dark, color),
267257
routerConfig: router,
268-
localizationsDelegates: AppLocalizations.localizationsDelegates,
258+
localizationsDelegates: [LocaleNamesLocalizationsDelegate(), ...AppLocalizations.localizationsDelegates],
269259
supportedLocales: AppLocalizations.supportedLocales,
270260
themeMode: ThemeMode.system,
271261
debugShowCheckedModeBanner: false,

pubspec.lock

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,14 @@ packages:
298298
url: "https://pub.dev"
299299
source: hosted
300300
version: "3.1.2"
301+
country_flags:
302+
dependency: "direct main"
303+
description:
304+
name: country_flags
305+
sha256: "66726c7070d60c2f90c4a1d58980e9188fa04335d6287e98aef835461019c3c2"
306+
url: "https://pub.dev"
307+
source: hosted
308+
version: "3.2.0"
301309
coverage:
302310
dependency: transitive
303311
description:
@@ -660,6 +668,14 @@ packages:
660668
description: flutter
661669
source: sdk
662670
version: "0.0.0"
671+
flutter_localized_locales:
672+
dependency: "direct main"
673+
description:
674+
name: flutter_localized_locales
675+
sha256: "478d10535edf07292e34cb4c757882edeeaf96d5e3dbb04b42733038bd41dd3f"
676+
url: "https://pub.dev"
677+
source: hosted
678+
version: "2.0.5"
663679
flutter_markdown:
664680
dependency: "direct main"
665681
description:
@@ -870,6 +886,22 @@ packages:
870886
url: "https://pub.dev"
871887
source: hosted
872888
version: "1.0.5"
889+
jovial_misc:
890+
dependency: transitive
891+
description:
892+
name: jovial_misc
893+
sha256: "4301011027d87b8b919cb862db84071a34448eadbb32cc8d40fe505424dfe69a"
894+
url: "https://pub.dev"
895+
source: hosted
896+
version: "0.9.2"
897+
jovial_svg:
898+
dependency: transitive
899+
description:
900+
name: jovial_svg
901+
sha256: "5e45b05845c8cbfec99ea32f177473ab2573d2c48479b29922c44ad329881d72"
902+
url: "https://pub.dev"
903+
source: hosted
904+
version: "1.1.25"
873905
js:
874906
dependency: transitive
875907
description:

pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ dependencies:
7676
git:
7777
url: https://github.com/Codel1417/packages.flutter
7878
path: packages/pdfx
79-
79+
flutter_localized_locales: ^2.0.5
80+
country_flags: ^3.2.0
8081
# Dio HTTP
8182
dio: ^5.8.0+1
8283
dio_smart_retry: ^7.0.1

0 commit comments

Comments
 (0)