From 089fe1f8df036aef2a65c1636b5fa9b3406ed6b6 Mon Sep 17 00:00:00 2001 From: Flummi Date: Mon, 16 Jun 2025 19:10:00 +0200 Subject: [PATCH] v1.3.2+58 --- assets/i18n/de_DE.json | 11 ++++ assets/i18n/en_US.json | 11 ++++ assets/i18n/fr_FR.json | 11 ++++ assets/i18n/nl_NL.json | 11 ++++ lib/controller/localization_controller.dart | 61 +++++++++++++++++++ lib/controller/media_controller.dart | 4 +- lib/main.dart | 9 +++ lib/screens/detail_view.dart | 10 +++- lib/screens/settings_screen.dart | 65 ++++++++++++++++----- lib/utils/animatedtransition.dart | 3 +- lib/widgets/end_drawer.dart | 2 +- pubspec.yaml | 3 +- 12 files changed, 179 insertions(+), 22 deletions(-) create mode 100644 assets/i18n/de_DE.json create mode 100644 assets/i18n/en_US.json create mode 100644 assets/i18n/fr_FR.json create mode 100644 assets/i18n/nl_NL.json create mode 100644 lib/controller/localization_controller.dart diff --git a/assets/i18n/de_DE.json b/assets/i18n/de_DE.json new file mode 100644 index 0000000..afed18f --- /dev/null +++ b/assets/i18n/de_DE.json @@ -0,0 +1,11 @@ +{ + "settings_title": "Einstellungen", + "settings_language": "Sprache", + "settings_drawer_title": "Drawer per Geste öffnen", + "settings_drawer_subtitle": "Wähle, ob der Drawer mit einer Wischgeste geschlossen/geöffnet werden kann.", + "settings_numberofcolumns_title": "Spaltenanzahl", + "settings_numberofcolumns_columns": "@count Spalten", + "settings_pageanimation_title": "Seitenwechselanimation", + "settings_cache_title": "Cache leeren", + "settings_cache_clear_button": "Leeren" +} diff --git a/assets/i18n/en_US.json b/assets/i18n/en_US.json new file mode 100644 index 0000000..57b16fa --- /dev/null +++ b/assets/i18n/en_US.json @@ -0,0 +1,11 @@ +{ + "settings_title": "Settings", + "settings_language": "Language", + "settings_drawer_title": "Open drawer with gesture", + "settings_drawer_subtitle": "Choose whether the drawer can be closed/opened with a swipe gesture.", + "settings_numberofcolumns_title": "Number of columns", + "settings_numberofcolumns_columns": "@count columns", + "settings_pageanimation_title": "Page change animation", + "settings_cache_title": "Clear Cache", + "settings_cache_clear_button": "Clear" +} diff --git a/assets/i18n/fr_FR.json b/assets/i18n/fr_FR.json new file mode 100644 index 0000000..ab40d3c --- /dev/null +++ b/assets/i18n/fr_FR.json @@ -0,0 +1,11 @@ +{ + "settings_title": "Paramètres", + "settings_language": "Langue", + "settings_drawer_title": "Ouvrir le tiroir avec un geste", + "settings_drawer_subtitle": "Choisissez si le tiroir peut être ouvert/fermé avec un geste de balayage.", + "settings_numberofcolumns_title": "Nombre de colonnes", + "settings_numberofcolumns_columns": "@count colonnes", + "settings_pageanimation_title": "Animation de changement de page", + "settings_cache_title": "Vider le cache", + "settings_cache_clear_button": "Vider" +} diff --git a/assets/i18n/nl_NL.json b/assets/i18n/nl_NL.json new file mode 100644 index 0000000..0a26c5d --- /dev/null +++ b/assets/i18n/nl_NL.json @@ -0,0 +1,11 @@ +{ + "settings_title": "Instellingen", + "settings_language": "Taal", + "settings_drawer_title": "Lade openen met een gebaar", + "settings_drawer_subtitle": "Kies of de lade geopend/gesloten kan worden met een veeggebaar.", + "settings_numberofcolumns_title": "Aantal kolommen", + "settings_numberofcolumns_columns": "@count kolommen", + "settings_pageanimation_title": "Pagina-overgangsanimatie", + "settings_cache_title": "Cache wissen", + "settings_cache_clear_button": "Wissen" +} diff --git a/lib/controller/localization_controller.dart b/lib/controller/localization_controller.dart new file mode 100644 index 0000000..1ac40b9 --- /dev/null +++ b/lib/controller/localization_controller.dart @@ -0,0 +1,61 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'package:get/get.dart'; +import 'package:encrypt_shared_preferences/provider.dart'; + +class MyTranslations extends Translations { + static final MyTranslations instance = MyTranslations._internal(); + MyTranslations._internal(); + + static final Map> _translations = {}; + + static Future loadTranslations() async { + final locales = ['en_US', 'de_DE', 'fr_FR', 'nl_NL']; + for (final locale in locales) { + final String jsonString = await rootBundle.loadString('assets/i18n/$locale.json'); + final Map jsonMap = json.decode(jsonString); + _translations[locale] = jsonMap.map((key, value) => MapEntry(key, value.toString())); + } + } + + @override + Map> get keys => _translations; +} + +class LocalizationController extends GetxController { + final EncryptedSharedPreferencesAsync storage = + EncryptedSharedPreferencesAsync.getInstance(); + Rx currentLocale = const Locale('en', 'US').obs; + + @override + void onInit() { + super.onInit(); + loadLocale(); + } + + Future loadLocale() async { + String? savedLocale = await storage.getString( + 'locale', + defaultValue: 'en_US', + ); + if (savedLocale != null && savedLocale.isNotEmpty) { + final List parts = savedLocale.split('_'); + currentLocale.value = parts.length == 2 + ? Locale(parts[0], parts[1]) + : Locale(parts[0]); + Get.locale = currentLocale.value; + } + } + + Future changeLocale(Locale newLocale) async { + currentLocale.value = newLocale; + Get.updateLocale(newLocale); + await storage.setString( + 'locale', + '${newLocale.languageCode}_${newLocale.countryCode}', + ); + } +} diff --git a/lib/controller/media_controller.dart b/lib/controller/media_controller.dart index 3eae3e3..016cd23 100644 --- a/lib/controller/media_controller.dart +++ b/lib/controller/media_controller.dart @@ -1,7 +1,7 @@ import 'package:encrypt_shared_preferences/provider.dart'; -import 'package:f0ckapp/utils/animatedtransition.dart'; import 'package:get/get.dart'; +import 'package:f0ckapp/utils/animatedtransition.dart'; import 'package:f0ckapp/service/media_service.dart'; import 'package:f0ckapp/models/media_item.dart'; @@ -98,7 +98,7 @@ class MediaController extends GetxController { ); append ? mediaItems.addAll(items) : mediaItems.assignAll(items); - + errorMessage.value = ''; } catch (e) { errorMessage.value = 'Fehler beim Laden der Daten: ${e.toString()}'; diff --git a/lib/main.dart b/lib/main.dart index 5006bf1..ebcb5df 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:encrypt_shared_preferences/provider.dart'; +import 'package:f0ckapp/controller/localization_controller.dart'; import 'package:f0ckapp/utils/appversion.dart'; import 'package:f0ckapp/controller/theme_controller.dart'; import 'package:f0ckapp/controller/media_controller.dart'; @@ -14,13 +15,21 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); await EncryptedSharedPreferencesAsync.initialize('VokTnbAbemBUa2j9'); + await MyTranslations.loadTranslations(); await AppVersion.init(); Get.put(MediaController()); + LocalizationController localizationController = Get.put(LocalizationController()); final ThemeController themeController = Get.put(ThemeController()); + Get.addTranslations(MyTranslations.instance.keys); + Get.locale = localizationController.currentLocale.value; + + //Locale systemLocale = WidgetsBinding.instance.platformDispatcher.locale; + runApp( Obx( () => MaterialApp( + locale: Get.locale, navigatorKey: Get.key, theme: themeController.currentTheme.value, debugShowCheckedModeBanner: false, diff --git a/lib/screens/detail_view.dart b/lib/screens/detail_view.dart index a53b54a..6a6fd56 100644 --- a/lib/screens/detail_view.dart +++ b/lib/screens/detail_view.dart @@ -1,7 +1,5 @@ import 'dart:io'; -import 'package:f0ckapp/utils/animatedtransition.dart'; -import 'package:f0ckapp/utils/smartrefreshindicator.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -10,6 +8,8 @@ import 'package:get/get.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:f0ckapp/utils/animatedtransition.dart'; +import 'package:f0ckapp/utils/smartrefreshindicator.dart'; import 'package:f0ckapp/controller/media_controller.dart'; import 'package:f0ckapp/models/media_item.dart'; import 'package:f0ckapp/screens/media_grid.dart'; @@ -151,7 +151,11 @@ class _DetailViewState extends State { title: Text('f0ck #${currentItem.id.toString()}'), leading: IconButton( icon: const Icon(Icons.arrow_back), - onPressed: () => Get.back(), + onPressed: () { + Navigator.canPop(context) + ? Get.back() + : Get.offAllNamed('/'); + } ), actions: [ IconButton( diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 8ed0750..9a6a507 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -1,10 +1,11 @@ -import 'package:f0ckapp/utils/animatedtransition.dart'; import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:get/get.dart'; import 'package:f0ckapp/controller/media_controller.dart'; +import 'package:f0ckapp/controller/localization_controller.dart'; +import 'package:f0ckapp/utils/animatedtransition.dart'; class SettingsPage extends StatefulWidget { const SettingsPage({super.key}); @@ -14,7 +15,8 @@ class SettingsPage extends StatefulWidget { } class _SettingsPageState extends State { - final MediaController controller = Get.find(); + final MediaController controller = Get.find(); + final LocalizationController localizationController = Get.find(); @override Widget build(BuildContext context) { @@ -24,12 +26,12 @@ class _SettingsPageState extends State { SliverAppBar( floating: false, pinned: true, - title: const Text('Settings'), + title: Text('settings_title'.tr), ), SliverList( delegate: SliverChildListDelegate([ ListTile( - title: const Text("Spaltenanzahl"), + title: Text('settings_numberofcolumns_title'.tr), trailing: Obx( () => DropdownButton( value: controller.crossAxisCount.value, @@ -38,7 +40,13 @@ class _SettingsPageState extends State { items: [0, 3, 4, 5].map((int value) { return DropdownMenuItem( value: value, - child: Text(value == 0 ? 'auto' : '$value Spalten'), + child: Text( + value == 0 + ? 'auto' + : 'settings_numberofcolumns_columns'.trParams({ + 'count': value.toString(), + }), + ), ); }).toList(), onChanged: (int? newValue) async { @@ -52,7 +60,7 @@ class _SettingsPageState extends State { ), const Divider(), ListTile( - title: const Text("Seitenwechselanimation"), + title: Text('settings_pageanimation_title'.tr), trailing: Obx( () => DropdownButton( value: controller.transitionType.value, @@ -94,10 +102,8 @@ class _SettingsPageState extends State { const Divider(), SwitchListTile( - title: const Text("Drawer per Geste öffnen"), - subtitle: const Text( - "Wähle, ob der Drawer mit einer Wischgeste geschlossen/ geöffnet werden kann.", - ), + title: Text('settings_drawer_title'.tr), + subtitle: Text('settings_drawer_subtitle'.tr), value: controller.drawerSwipeEnabled.value, onChanged: (bool value) async { await controller.setDrawerSwipeEnabled(value); @@ -106,17 +112,50 @@ class _SettingsPageState extends State { ), const Divider(), ListTile( - title: Text("Cache löschen"), + title: Text('settings_language'.tr), + trailing: Obx( + () => DropdownButton( + value: localizationController.currentLocale.value, + dropdownColor: const Color.fromARGB(255, 43, 43, 43), + iconEnabledColor: Colors.white, + items: const [ + DropdownMenuItem( + value: Locale('en', 'US'), + child: Text('English'), + ), + DropdownMenuItem( + value: Locale('de', 'DE'), + child: Text('Deutsch'), + ), + DropdownMenuItem( + value: Locale('fr', 'FR'), + child: Text('Français'), + ), + DropdownMenuItem( + value: Locale('nl', 'NL'), + child: Text('Nederlands'), + ), + ], + onChanged: (Locale? newLocale) async { + if (newLocale != null) { + await localizationController.changeLocale(newLocale); + } + }, + ), + ), + ), + const Divider(), + ListTile( + title: Text('settings_cache_title'.tr), trailing: ElevatedButton( onPressed: () async { await DefaultCacheManager().emptyCache(); if (!mounted) return; Get.snackbar('', 'der Cache wurde geleert.'); }, - child: const Text("Löschen"), + child: Text('settings_cache_clear_button'.tr), ), ), - const SizedBox(height: 20), ]), ), ], diff --git a/lib/utils/animatedtransition.dart b/lib/utils/animatedtransition.dart index b79a11c..b3f1072 100644 --- a/lib/utils/animatedtransition.dart +++ b/lib/utils/animatedtransition.dart @@ -18,7 +18,7 @@ Widget buildAnimatedTransition({ switch (controller.transitionType.value) { case PageTransition.opacity: return Opacity( - opacity: Curves.easeOut.transform(1 - value.abs().clamp(0.0, 40.0)), + opacity: Curves.easeOut.transform(1 - value.abs().clamp(0.0, 1.0)), child: Transform(transform: Matrix4.identity(), child: child), ); case PageTransition.scale: @@ -48,4 +48,3 @@ Widget buildAnimatedTransition({ ); } } - \ No newline at end of file diff --git a/lib/widgets/end_drawer.dart b/lib/widgets/end_drawer.dart index 07b7a49..ea82c6c 100644 --- a/lib/widgets/end_drawer.dart +++ b/lib/widgets/end_drawer.dart @@ -1,8 +1,8 @@ -import 'package:f0ckapp/screens/settings_screen.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:f0ckapp/screens/settings_screen.dart'; import 'package:f0ckapp/controller/theme_controller.dart'; import 'package:f0ckapp/utils/appversion.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 585c351..5ddc61a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.3.1+57 +version: 1.3.2+58 environment: sdk: ^3.9.0-100.2.beta @@ -63,6 +63,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/images/ + - assets/i18n/ - pubspec.yaml # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg