Add support for changing language

This commit is contained in:
Neeraj Gupta
2023-04-07 17:40:47 +05:30
parent 0629789a22
commit 66ee9ef1a6
11 changed files with 242 additions and 9 deletions

View File

@@ -22,6 +22,11 @@ class App extends StatefulWidget {
final Locale locale;
const App({Key key, this.locale = const Locale("en")}) : super(key: key);
static void setLocale(BuildContext context, Locale newLocale) {
_AppState state = context.findAncestorStateOfType<_AppState>();
state.setLocale(newLocale);
}
@override
State<App> createState() => _AppState();
}
@@ -29,6 +34,12 @@ class App extends StatefulWidget {
class _AppState extends State<App> {
StreamSubscription<SignedOutEvent> _signedOutEvent;
StreamSubscription<SignedInEvent> _signedInEvent;
Locale locale;
setLocale(Locale newLocale) {
setState(() {
locale = newLocale;
});
}
@override
void initState() {
@@ -42,6 +53,7 @@ class _AppState extends State<App> {
setState(() {});
}
});
locale = widget.locale;
UpdateService.instance.shouldUpdate().then((shouldUpdate) {
if (shouldUpdate) {
Future.delayed(Duration.zero, () {
@@ -80,7 +92,7 @@ class _AppState extends State<App> {
theme: lightTheme,
darkTheme: dartTheme,
debugShowCheckedModeBanner: false,
locale: widget.locale,
locale: locale,
supportedLocales: appSupportedLocales,
localeListResolutionCallback: localResolutionCallBack,
localizationsDelegates: const [
@@ -99,7 +111,7 @@ class _AppState extends State<App> {
theme: lightThemeData,
darkTheme: darkThemeData,
debugShowCheckedModeBanner: false,
locale: widget.locale,
locale: locale,
supportedLocales: appSupportedLocales,
localeListResolutionCallback: localResolutionCallBack,
localizationsDelegates: const [

View File

@@ -108,5 +108,6 @@
"passwordStrengthModerate": "Mittel",
"confirmPassword": "Bestätigen Sie das Passwort",
"close": "Schließen",
"oopsSomethingWentWrong": "Ups, da ist etwas schief gelaufen."
"oopsSomethingWentWrong": "Ups, da ist etwas schief gelaufen.",
"selectLanguage": "Sprache auswählen"
}

View File

@@ -118,6 +118,8 @@
"passwordStrengthModerate": "Moderate",
"confirmPassword": "Confirm password",
"close": "Close",
"oopsSomethingWentWrong": "Oops, Something went wrong."
"oopsSomethingWentWrong": "Oops, Something went wrong.",
"selectLanguage": "Select language",
"language": "Language"
}

View File

@@ -2,5 +2,6 @@
"counterAppBarTitle": "Contador",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
}
},
"selectLanguage": "Valitse kieli"
}

View File

@@ -111,5 +111,6 @@
"passwordStrengthModerate": "Modéré",
"confirmPassword": "Confirmer le mot de passe",
"close": "Fermer",
"oopsSomethingWentWrong": "Oops ! Une erreur s'est produite."
"oopsSomethingWentWrong": "Oops ! Une erreur s'est produite.",
"selectLanguage": "Sélectionnez la langue"
}

View File

@@ -112,5 +112,6 @@
"passwordStrengthModerate": "Mediocre",
"confirmPassword": "Conferma la password",
"close": "Chiudi",
"oopsSomethingWentWrong": "Oops, qualcosa è andato storto."
"oopsSomethingWentWrong": "Oops, qualcosa è andato storto.",
"selectLanguage": "Seleziona lingua"
}

View File

@@ -8,7 +8,7 @@ const List<Locale> appSupportedLocales = <Locale>[
Locale('en'),
Locale('de'),
Locale('fr'),
Locale('fi'),
Locale('it'),
];
Locale localResolutionCallBack(locales, supportedLocales) {
@@ -25,13 +25,17 @@ Locale localResolutionCallBack(locales, supportedLocales) {
Future<Locale> getLocale() async {
final String? savedLocale =
(await SharedPreferences.getInstance()).getString('locale');
if (savedLocale != null) {
if (savedLocale != null &&
appSupportedLocales.contains(Locale(savedLocale))) {
return Locale(savedLocale);
}
return const Locale('en');
}
Future<void> setLocale(Locale locale) async {
if (!appSupportedLocales.contains(locale)) {
throw Exception('Locale $locale is not supported by the app');
}
await (await SharedPreferences.getInstance())
.setString('locale', locale.languageCode);
}

View File

@@ -2,11 +2,13 @@
import 'dart:async';
import 'package:ente_auth/app/view/app.dart';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/core/event_bus.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/events/trigger_logout_event.dart';
import "package:ente_auth/l10n/l10n.dart";
import 'package:ente_auth/locale.dart';
import 'package:ente_auth/ui/account/email_entry_page.dart';
import 'package:ente_auth/ui/account/login_page.dart';
import 'package:ente_auth/ui/account/logout_dialog.dart';
@@ -14,6 +16,9 @@ import 'package:ente_auth/ui/account/password_entry_page.dart';
import 'package:ente_auth/ui/account/password_reentry_page.dart';
import 'package:ente_auth/ui/common/gradient_button.dart';
import 'package:ente_auth/ui/home_page.dart';
import 'package:ente_auth/ui/settings/language_picker.dart';
import 'package:ente_auth/utils/navigation_util.dart';
import 'package:flutter/foundation.dart';
import "package:flutter/material.dart";
class OnboardingPage extends StatefulWidget {
@@ -59,6 +64,30 @@ class _OnboardingPageState extends State<OnboardingPage> {
children: [
Column(
children: [
kDebugMode
? GestureDetector(
child: const Align(
alignment: Alignment.topRight,
child: Text("Lang"),
),
onTap: () async {
final locale = await getLocale();
routeToPage(
context,
DeviceLimitPickerPage(
appSupportedLocales,
(locale) async {
await setLocale(locale);
App.setLocale(context, locale);
},
locale,
),
).then((value) {
setState(() {});
});
},
)
: const SizedBox(),
Image.asset(
"assets/sheild-front-gradient.png",
width: 200,

View File

@@ -0,0 +1,13 @@
//This method returns a newly declared list with separators. It will not
//modify the original list
import 'package:flutter/widgets.dart';
List<Widget> addSeparators(List<Widget> listOfWidgets, Widget separator) {
final int initialLength = listOfWidgets.length;
final listOfWidgetsWithSeparators = <Widget>[];
listOfWidgetsWithSeparators.addAll(listOfWidgets);
for (var i = 1; i < initialLength; i++) {
listOfWidgetsWithSeparators.insert((2 * i) - 1, separator);
}
return listOfWidgetsWithSeparators;
}

View File

@@ -1,6 +1,9 @@
// @dart=2.9
import 'package:ente_auth/app/view/app.dart';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/locale.dart';
import 'package:ente_auth/services/local_authentication_service.dart';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:ente_auth/ui/account/change_email_dialog.dart';
@@ -10,6 +13,7 @@ import 'package:ente_auth/ui/components/captioned_text_widget.dart';
import 'package:ente_auth/ui/components/expandable_menu_item_widget.dart';
import 'package:ente_auth/ui/components/menu_item_widget.dart';
import 'package:ente_auth/ui/settings/common_settings.dart';
import 'package:ente_auth/ui/settings/language_picker.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:ente_auth/utils/navigation_util.dart';
import 'package:flutter/material.dart';
@@ -20,6 +24,7 @@ class AccountSectionWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return ExpandableMenuItemWidget(
title: "Account",
selectionOptionsWidget: _getSectionOptions(context),
@@ -28,6 +33,7 @@ class AccountSectionWidget extends StatelessWidget {
}
Column _getSectionOptions(BuildContext context) {
final l10n = context.l10n;
List<Widget> children = [];
children.addAll([
sectionOptionSpacing,
@@ -119,6 +125,29 @@ class AccountSectionWidget extends StatelessWidget {
},
),
sectionOptionSpacing,
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: l10n.language,
),
pressedColor: getEnteColorScheme(context).fillFaint,
trailingIcon: Icons.chevron_right_outlined,
trailingIconIsMuted: true,
onTap: () async {
final locale = await getLocale();
routeToPage(
context,
DeviceLimitPickerPage(
appSupportedLocales,
(locale) async {
await setLocale(locale);
App.setLocale(context, locale);
},
locale,
),
);
},
),
sectionOptionSpacing,
]);
return Column(
children: children,

View File

@@ -0,0 +1,140 @@
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:ente_auth/ui/components/captioned_text_widget.dart';
import 'package:ente_auth/ui/components/divider_widget.dart';
import 'package:ente_auth/ui/components/menu_item_widget.dart';
import 'package:ente_auth/ui/components/separators.dart';
import 'package:ente_auth/ui/components/title_bar_title_widget.dart';
import 'package:ente_auth/ui/components/title_bar_widget.dart';
import 'package:flutter/material.dart';
class DeviceLimitPickerPage extends StatelessWidget {
final List<Locale> supportedLocales;
final ValueChanged<Locale> onLocaleChanged;
final Locale currentLocale;
const DeviceLimitPickerPage(
this.supportedLocales,
this.onLocaleChanged,
this.currentLocale, {
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Scaffold(
body: CustomScrollView(
primary: false,
slivers: <Widget>[
TitleBarWidget(
flexibleSpaceTitle: TitleBarTitleWidget(
title: l10n.selectLanguage,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 20,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ClipRRect(
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: ItemsWidget(
supportedLocales,
onLocaleChanged,
currentLocale,
),
),
// MenuSectionDescriptionWidget(
// content: S.of(context).maxDeviceLimitSpikeHandling(50),
// )
],
),
);
},
childCount: 1,
),
),
const SliverPadding(padding: EdgeInsets.symmetric(vertical: 12)),
],
),
);
}
}
class ItemsWidget extends StatefulWidget {
final List<Locale> supportedLocales;
final ValueChanged<Locale> onLocaleChanged;
final Locale currentLocale;
const ItemsWidget(
this.supportedLocales,
this.onLocaleChanged,
this.currentLocale, {
Key? key,
}) : super(key: key);
@override
State<ItemsWidget> createState() => _ItemsWidgetState();
}
class _ItemsWidgetState extends State<ItemsWidget> {
late Locale currentDeviceLimit;
List<Widget> items = [];
@override
void initState() {
currentDeviceLimit = widget.currentLocale;
super.initState();
}
@override
Widget build(BuildContext context) {
items.clear();
for (Locale deviceLimit in widget.supportedLocales) {
items.add(
_menuItemForPicker(deviceLimit),
);
}
items = addSeparators(
items,
DividerWidget(
dividerType: DividerType.menuNoIcon,
bgColor: getEnteColorScheme(context).fillFaint,
),
);
return Column(
mainAxisSize: MainAxisSize.min,
children: items,
);
}
Widget _menuItemForPicker(Locale locale) {
return MenuItemWidget(
key: ValueKey(locale.toString()),
menuItemColor: getEnteColorScheme(context).fillFaint,
captionedTextWidget: CaptionedTextWidget(
title: locale.languageCode,
),
trailingIcon: currentDeviceLimit == locale ? Icons.check : null,
alignCaptionedTextToLeft: true,
isTopBorderRadiusRemoved: true,
isBottomBorderRadiusRemoved: true,
showOnlyLoadingState: true,
onTap: () async {
widget.onLocaleChanged(locale);
currentDeviceLimit = locale;
setState(() {});
},
);
}
}