Added: settings entry to switch the locale dynamically.
This commit is contained in:
parent
118d39659c
commit
c00526a5be
|
|
@ -2,12 +2,13 @@ import 'dart:io';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:quickgui/src/globals.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'package:window_size/window_size.dart';
|
||||
|
||||
import 'src/app.dart';
|
||||
import 'src/mixins/app_version.dart';
|
||||
import 'src/model/app_theme.dart';
|
||||
import 'src/model/app_settings.dart';
|
||||
import 'src/model/operating_system.dart';
|
||||
import 'src/model/option.dart';
|
||||
import 'src/model/version.dart';
|
||||
|
|
@ -20,7 +21,12 @@ Future<List<OperatingSystem>> loadOperatingSystems(bool showUbuntus) async {
|
|||
OperatingSystem? currentOperatingSystem;
|
||||
Version? currentVersion;
|
||||
|
||||
stdout.split('\n').skip(1).where((element) => element.isNotEmpty).map((e) => e.trim()).forEach((element) {
|
||||
stdout
|
||||
.split('\n')
|
||||
.skip(1)
|
||||
.where((element) => element.isNotEmpty)
|
||||
.map((e) => e.trim())
|
||||
.forEach((element) {
|
||||
var chunks = element.split(",");
|
||||
Tuple5 supportedVersion;
|
||||
if (chunks.length == 4) // Legacy version of quickget
|
||||
|
|
@ -32,7 +38,8 @@ Future<List<OperatingSystem>> loadOperatingSystems(bool showUbuntus) async {
|
|||
}
|
||||
|
||||
if (currentOperatingSystem?.code != supportedVersion.item2) {
|
||||
currentOperatingSystem = OperatingSystem(supportedVersion.item1, supportedVersion.item2);
|
||||
currentOperatingSystem =
|
||||
OperatingSystem(supportedVersion.item1, supportedVersion.item2);
|
||||
output.add(currentOperatingSystem!);
|
||||
currentVersion = null;
|
||||
}
|
||||
|
|
@ -40,7 +47,8 @@ Future<List<OperatingSystem>> loadOperatingSystems(bool showUbuntus) async {
|
|||
currentVersion = Version(supportedVersion.item3);
|
||||
currentOperatingSystem!.versions.add(currentVersion!);
|
||||
}
|
||||
currentVersion!.options.add(Option(supportedVersion.item4, supportedVersion.item5));
|
||||
currentVersion!.options
|
||||
.add(Option(supportedVersion.item4, supportedVersion.item5));
|
||||
});
|
||||
|
||||
return output;
|
||||
|
|
@ -48,6 +56,7 @@ Future<List<OperatingSystem>> loadOperatingSystems(bool showUbuntus) async {
|
|||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
// Don't forget to also change the size in linux/my_application.cc:50
|
||||
setWindowMinSize(const Size(692, 580));
|
||||
setWindowMaxSize(const Size(692, 580));
|
||||
gOperatingSystems = await loadOperatingSystems(false);
|
||||
|
|
@ -55,7 +64,7 @@ void main() async {
|
|||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => AppTheme()),
|
||||
ChangeNotifierProvider(create: (_) => AppSettings()),
|
||||
],
|
||||
builder: (context, _) => const App(),
|
||||
),
|
||||
|
|
|
|||
120
lib/src/app.dart
120
lib/src/app.dart
|
|
@ -1,12 +1,16 @@
|
|||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:gettext_i18n/gettext_i18n.dart';
|
||||
import 'package:window_size/window_size.dart';
|
||||
import 'package:quickgui/src/supported_locales.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'globals.dart';
|
||||
import 'mixins/preferences_mixin.dart';
|
||||
import 'model/app_theme.dart';
|
||||
import 'model/app_settings.dart';
|
||||
import 'pages/main_page.dart';
|
||||
|
||||
class App extends StatefulWidget {
|
||||
|
|
@ -19,56 +23,33 @@ class App extends StatefulWidget {
|
|||
class _AppState extends State<App> with PreferencesMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder<bool?>(
|
||||
future: getPreference<bool>(prefThemeMode),
|
||||
builder: (context, AsyncSnapshot<bool?> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.data != null) {
|
||||
context.read<AppTheme>().useDarkModeSilently = snapshot.data!;
|
||||
}
|
||||
return Consumer<AppTheme>(
|
||||
builder: (context, appTheme, _) => MaterialApp(
|
||||
return FutureBuilder<SharedPreferences>(
|
||||
future: SharedPreferences.getInstance(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.data != null) {
|
||||
var appSettings = context.read<AppSettings>();
|
||||
appSettings.setActiveLocaleSilently(
|
||||
snapshot.data?.getString(prefCurrentLocale) ??
|
||||
Platform.localeName);
|
||||
appSettings.useDarkModeSilently =
|
||||
snapshot.data!.getBool(prefThemeMode) as bool;
|
||||
return Consumer<AppSettings>(
|
||||
builder: (context, appSettings, _) => MaterialApp(
|
||||
theme: ThemeData(primarySwatch: Colors.pink),
|
||||
darkTheme: ThemeData.dark(),
|
||||
themeMode: appTheme.themeMode,
|
||||
themeMode: appSettings.themeMode,
|
||||
home: const MainPage(),
|
||||
supportedLocales: const [
|
||||
/*
|
||||
* List of locales (language + country) we have translations for.
|
||||
*
|
||||
* If there is a file for the tuple (langue, country) in assets/lib/i18n, then this
|
||||
* will be used for translation.
|
||||
*
|
||||
* If there is not, then we'll look for a file for the language only.
|
||||
*
|
||||
* If there is no file for the language code, we'll fallback to the english file.
|
||||
*
|
||||
* Example : let's say the locale is fr_CH. We will look for "assets/lib/i18n/fr_CH.po",
|
||||
* "assets/lib/i18n/fr.po", and "assets/lib/i18n/en.po", stopping at the first file we
|
||||
* find.
|
||||
*
|
||||
* Translation files are not merged, meaning if some translations are missing in fr_CH.po
|
||||
* but are present in fr.po, the missing translations will not be picked up from fr.po,
|
||||
* and thus will show up in english.
|
||||
*/
|
||||
Locale('cs_CZ'),
|
||||
Locale('cy'),
|
||||
Locale('de'),
|
||||
Locale('en'),
|
||||
Locale('fr'),
|
||||
Locale('fr', 'CH'),
|
||||
Locale('gd'),
|
||||
Locale('it'),
|
||||
Locale('nl'),
|
||||
Locale('no'),
|
||||
Locale('oc'),
|
||||
Locale('ru'),
|
||||
],
|
||||
supportedLocales: supportedLocales.map((s) => s.contains("_")
|
||||
? Locale(s.split("_")[0], s.split("_")[1])
|
||||
: Locale(s)),
|
||||
localizationsDelegates: [
|
||||
GettextLocalizationsDelegate(),
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
],
|
||||
locale:
|
||||
Locale(appSettings.languageCode!, appSettings.countryCode),
|
||||
localeListResolutionCallback: (locales, supportedLocales) {
|
||||
if (locales != null) {
|
||||
for (var locale in locales) {
|
||||
|
|
@ -96,5 +77,56 @@ class _AppState extends State<App> with PreferencesMixin {
|
|||
}
|
||||
},
|
||||
);
|
||||
/*
|
||||
return FutureBuilder<bool?>(
|
||||
future: getPreference<bool>(prefThemeMode),
|
||||
builder: (context, AsyncSnapshot<bool?> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.data != null) {
|
||||
context.read<AppSettings>().useDarkModeSilently = snapshot.data!;
|
||||
}
|
||||
return Consumer<AppSettings>(
|
||||
builder: (context, appTheme, _) => MaterialApp(
|
||||
theme: ThemeData(primarySwatch: Colors.pink),
|
||||
darkTheme: ThemeData.dark(),
|
||||
themeMode: appTheme.themeMode,
|
||||
home: const MainPage(),
|
||||
supportedLocales: supportedLocales.map((s) => s.contains("_")
|
||||
? Locale(s.split("_")[0], s.split("_")[1])
|
||||
: Locale(s)),
|
||||
localizationsDelegates: [
|
||||
GettextLocalizationsDelegate(),
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
],
|
||||
locale: const Locale('ru'),
|
||||
localeListResolutionCallback: (locales, supportedLocales) {
|
||||
if (locales != null) {
|
||||
for (var locale in locales) {
|
||||
var supportedLocale = supportedLocales.where((element) =>
|
||||
element.languageCode == locale.languageCode &&
|
||||
element.countryCode == locale.countryCode);
|
||||
if (supportedLocale.isNotEmpty) {
|
||||
return supportedLocale.first;
|
||||
}
|
||||
supportedLocale = supportedLocales.where((element) =>
|
||||
element.languageCode == locale.languageCode);
|
||||
if (supportedLocale.isNotEmpty) {
|
||||
return supportedLocale.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@ import 'dart:io';
|
|||
var gIsSnap = Platform.environment['SNAP']?.isNotEmpty ?? false;
|
||||
const String prefWorkingDirectory = 'workingDirectory';
|
||||
const String prefThemeMode = 'themeMode';
|
||||
const String prefCurrentLocale = 'currentLocale';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:quickgui/src/supported_locales.dart';
|
||||
|
||||
class AppSettings extends ChangeNotifier {
|
||||
ThemeMode? _themeMode;
|
||||
String? _activeLocale;
|
||||
|
||||
ThemeMode get themeMode => _themeMode ?? ThemeMode.system;
|
||||
|
||||
String get activeLocale => _activeLocale ?? Platform.localeName;
|
||||
|
||||
String? get languageCode => _activeLocale?.split("_")[0];
|
||||
String? get countryCode =>
|
||||
((_activeLocale != null) && (_activeLocale!.contains("_")))
|
||||
? _activeLocale!.split("_")[1]
|
||||
: null;
|
||||
|
||||
set activeLocale(String locale) {
|
||||
_activeLocale = locale;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
setActiveLocaleSilently(String locale) {
|
||||
_activeLocale = locale;
|
||||
if (_activeLocale!.contains(".")) {
|
||||
_activeLocale = _activeLocale!.split(".")[0];
|
||||
}
|
||||
if (!supportedLocales.contains(_activeLocale)) {
|
||||
if (activeLocale.contains("_")) {
|
||||
_activeLocale = _activeLocale!.split("_")[0];
|
||||
}
|
||||
if (!supportedLocales.contains(_activeLocale)) {
|
||||
_activeLocale = "en";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set useDarkModeSilently(bool useDarkMode) {
|
||||
_themeMode = useDarkMode ? ThemeMode.dark : ThemeMode.light;
|
||||
}
|
||||
|
||||
set useDarkMode(bool useDarkMode) {
|
||||
useDarkModeSilently = useDarkMode;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppTheme extends ChangeNotifier {
|
||||
ThemeMode? _themeMode;
|
||||
|
||||
ThemeMode get themeMode => _themeMode ?? ThemeMode.system;
|
||||
|
||||
set useDarkModeSilently(bool useDarkMode) {
|
||||
_themeMode = useDarkMode ? ThemeMode.dark : ThemeMode.light;
|
||||
}
|
||||
|
||||
set useDarkMode(bool useDarkMode) {
|
||||
useDarkModeSilently = useDarkMode;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* List of locales (language + country) we have translations for.
|
||||
*
|
||||
* If there is a file for the tuple (langue, country) in assets/lib/i18n, then this
|
||||
* will be used for translation.
|
||||
*
|
||||
* If there is not, then we'll look for a file for the language only.
|
||||
*
|
||||
* If there is no file for the language code, we'll fallback to the english file.
|
||||
*
|
||||
* Example : let's say the locale is fr_CH. We will look for "assets/lib/i18n/fr_CH.po",
|
||||
* "assets/lib/i18n/fr.po", and "assets/lib/i18n/en.po", stopping at the first file we
|
||||
* find.
|
||||
*
|
||||
* Translation files are not merged, meaning if some translations are missing in fr_CH.po
|
||||
* but are present in fr.po, the missing translations will not be picked up from fr.po,
|
||||
* and thus will show up in english.
|
||||
*/
|
||||
final supportedLocales = [
|
||||
'cs_CZ',
|
||||
'cy',
|
||||
'de',
|
||||
'en',
|
||||
'fr',
|
||||
'gd',
|
||||
'it',
|
||||
'nl',
|
||||
'no',
|
||||
'oc',
|
||||
'ru',
|
||||
];
|
||||
|
|
@ -1,45 +1,102 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:gettext_i18n/gettext_i18n.dart';
|
||||
import 'package:quickgui/src/supported_locales.dart';
|
||||
|
||||
import '../globals.dart';
|
||||
import '../mixins/app_version.dart';
|
||||
import '../mixins/preferences_mixin.dart';
|
||||
import '../model/app_theme.dart';
|
||||
import '../model/app_settings.dart';
|
||||
|
||||
class LeftMenu extends StatelessWidget with PreferencesMixin {
|
||||
class LeftMenu extends StatefulWidget {
|
||||
const LeftMenu({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<LeftMenu> createState() => _LeftMenuState();
|
||||
}
|
||||
|
||||
class _LeftMenuState extends State<LeftMenu> with PreferencesMixin {
|
||||
late String currentLocale;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
var appSettings = context.read<AppSettings>();
|
||||
currentLocale = appSettings.activeLocale;
|
||||
if (!supportedLocales.contains(currentLocale)) {
|
||||
currentLocale = currentLocale.split("_")[0];
|
||||
if (!supportedLocales.contains(currentLocale)) {
|
||||
currentLocale = "en";
|
||||
}
|
||||
}
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var _version = AppVersion.packageInfo!.version;
|
||||
return Consumer<AppTheme>(
|
||||
builder: (context, appTheme, _) => Drawer(
|
||||
child: ListView(
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text("quickgui $_version", style: Theme.of(context).textTheme.headline6),
|
||||
),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(context.t('Use dark mode')),
|
||||
Switch(
|
||||
value: Theme.of(context).brightness == Brightness.dark,
|
||||
onChanged: (value) {
|
||||
appTheme.useDarkMode = value;
|
||||
savePreference(prefThemeMode, value);
|
||||
},
|
||||
),
|
||||
],
|
||||
return Consumer<AppSettings>(
|
||||
builder: (context, appSettings, _) {
|
||||
return Drawer(
|
||||
child: ListView(
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text("quickgui $_version",
|
||||
style: Theme.of(context).textTheme.headline6),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(context.t('Use dark mode')),
|
||||
Expanded(
|
||||
child: Container(),
|
||||
),
|
||||
Switch(
|
||||
value: Theme.of(context).brightness == Brightness.dark,
|
||||
onChanged: (value) {
|
||||
appSettings.useDarkMode = value;
|
||||
savePreference(prefThemeMode, value);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(context.t('Language')),
|
||||
Expanded(
|
||||
child: Container(),
|
||||
),
|
||||
DropdownButton<String>(
|
||||
value: currentLocale,
|
||||
items: supportedLocales
|
||||
.map(
|
||||
(e) => DropdownMenuItem(child: Text(e), value: e))
|
||||
.toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
currentLocale = value!;
|
||||
appSettings.activeLocale = currentLocale;
|
||||
savePreference(prefCurrentLocale, currentLocale);
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ static void my_application_activate(GApplication* application) {
|
|||
gtk_window_set_title(window, "quickgui");
|
||||
}
|
||||
|
||||
gtk_window_set_default_size(window, 640, 480);
|
||||
gtk_window_set_default_size(window, 692, 580);
|
||||
gtk_widget_show(GTK_WIDGET(window));
|
||||
|
||||
g_autoptr(FlDartProject) project = fl_dart_project_new();
|
||||
|
|
|
|||
Loading…
Reference in New Issue