diff --git a/frontend/assets/l10n/app_de.json b/frontend/assets/l10n/app_de.json index 44ad09c9e..07f4dc13d 100644 --- a/frontend/assets/l10n/app_de.json +++ b/frontend/assets/l10n/app_de.json @@ -3,18 +3,22 @@ "dependencies": "Software-Bibliotheken", "developmentOptions": "Entwickleroptionen", "disclaimer": "Haftung, Haftungsausschluss und Impressum", + "infoTitle": "Info", + "languageChange": "Sprache wechseln", + "languageChangeSuccessful": "Ihre Sprache wurde erfolgreich geändert!", "licenses": { "one": "Lizenz", "other": "Lizenzen" }, "moreInformation": "Mehr Informationen", "numberLicenses": { - "zero": "Keine Lizenzen", "one": "1 Lizenz", - "other": "$n Lizenzen" + "other": "$n Lizenzen", + "zero": "Keine Lizenzen" }, "privacyDeclaration": "Datenschutzerklärung", "publisher": "Herausgeber", + "settingsTitle": "Einstellungen", "sourceCode": "Quellcode der App", "title": "Über" }, diff --git a/frontend/assets/l10n/app_en.json b/frontend/assets/l10n/app_en.json index 12d154821..c2d7aaa4d 100644 --- a/frontend/assets/l10n/app_en.json +++ b/frontend/assets/l10n/app_en.json @@ -3,18 +3,22 @@ "dependencies": "Libraries", "developmentOptions": "Developer options", "disclaimer": "Liability, disclaimer and imprint", + "infoTitle": "Info", + "languageChange": "Change language", + "languageChangeSuccessful": "Your language was changed successfully!", "licenses": { "one": "License", "other": "Licenses" }, "moreInformation": "More information", "numberLicenses": { - "zero": "No licenses", "one": "1 license", - "other": "$n licenses" + "other": "$n licenses", + "zero": "No licenses" }, "privacyDeclaration": "Privacy policy", "publisher": "Publisher", + "settingsTitle": "Settings", "sourceCode": "Source code", "title": "About" }, diff --git a/frontend/assets/nuernberg/l10n/override_de.json b/frontend/assets/nuernberg/l10n/override_de.json index 76c38c031..a63359282 100644 --- a/frontend/assets/nuernberg/l10n/override_de.json +++ b/frontend/assets/nuernberg/l10n/override_de.json @@ -30,5 +30,8 @@ "usageDescription": "Auf der Karte von Nürnberg können Sie alle Akzeptanzstellen finden. Tippen Sie auf einen Standort, um mehr Informationen sehen zu können.", "usageTitle": "Wo kann ich den Nürnberg-Pass nutzen?", "welcomeDescription": "Vielen Dank, dass Sie sich die App zum Nürnberg-Pass heruntergeladen haben!" + }, + "about": { + "title": "Mehr" } } diff --git a/frontend/assets/nuernberg/l10n/override_en.json b/frontend/assets/nuernberg/l10n/override_en.json index 159272b6a..ca52269e8 100644 --- a/frontend/assets/nuernberg/l10n/override_en.json +++ b/frontend/assets/nuernberg/l10n/override_en.json @@ -30,5 +30,8 @@ "usageDescription": "On the map of Nürnberg you can find all acceptance points. Tap on a location to be able to see more information.", "usageTitle": "Where can I use my Nürnberg-Pass?", "welcomeDescription": "Thank you for downloading the app for the Nürnberg-Pass!" + }, + "about": { + "title": "More" } } diff --git a/frontend/build-configs/bayern/index.ts b/frontend/build-configs/bayern/index.ts index d5c55ddf9..79f0f6e30 100644 --- a/frontend/build-configs/bayern/index.ts +++ b/frontend/build-configs/bayern/index.ts @@ -62,7 +62,7 @@ export const bayernCommon: CommonBuildConfigType = { "assets/bayern/intro_slides/search_with_location.png", ], featureFlags: { - verification: true + verification: true, }, applicationUrl: "https://bayern.ehrenamtskarte.app/beantragen", dataPrivacyPolicyUrl: "https://bayern.ehrenamtskarte.app/data-privacy-policy", diff --git a/frontend/build-configs/nuernberg/index.ts b/frontend/build-configs/nuernberg/index.ts index c24ca1b16..6dd7f404e 100644 --- a/frontend/build-configs/nuernberg/index.ts +++ b/frontend/build-configs/nuernberg/index.ts @@ -62,7 +62,7 @@ export const nuernbergCommon: CommonBuildConfigType = { "assets/nuernberg/intro_slides/search_with_location.png", ], featureFlags: { - verification: true + verification: true, }, applicationUrl: "https://beantragen.nuernberg.sozialpass.app", publisherAddress: diff --git a/frontend/lib/about/about_page.dart b/frontend/lib/about/about_page.dart index 10e942cdb..4e41af45f 100644 --- a/frontend/lib/about/about_page.dart +++ b/frontend/lib/about/about_page.dart @@ -1,7 +1,9 @@ import 'package:ehrenamtskarte/about/backend_switch_dialog.dart'; import 'package:ehrenamtskarte/about/content_tile.dart'; import 'package:ehrenamtskarte/about/dev_settings_view.dart'; +import 'package:ehrenamtskarte/about/language_change.dart'; import 'package:ehrenamtskarte/about/license_page.dart'; +import 'package:ehrenamtskarte/about/section.dart'; import 'package:ehrenamtskarte/about/texts.dart'; import 'package:ehrenamtskarte/build_config/build_config.dart' show buildConfig; import 'package:ehrenamtskarte/configuration/configuration.dart'; @@ -27,7 +29,6 @@ class AboutPageState extends State { @override Widget build(BuildContext context) { final config = Configuration.of(context); - return FutureBuilder( future: PackageInfo.fromPlatform(), builder: (context, snapshot) { @@ -95,53 +96,75 @@ class AboutPageState extends State { ); }, ), + if (buildConfig.appLocales.length > 1) + Column(children: [ + const Divider( + height: 1, + thickness: 1, + ), + Section( + headline: t.about.settingsTitle, + children: [ + ContentTile(icon: Icons.language, title: t.about.languageChange, children: [LanguageChange()]), + ], + ), + ]), const Divider( height: 1, thickness: 1, ), - const SizedBox(height: 20), - ContentTile(icon: Icons.copyright, title: t.about.licenses(n: 1), children: getCopyrightText(context)), - ListTile( - leading: const Icon(Icons.privacy_tip_outlined), - title: Text(t.about.privacyDeclaration), - onTap: () => launchUrlString(buildConfig.dataPrivacyPolicyUrl, mode: LaunchMode.externalApplication), - ), - ContentTile( - icon: Icons.info_outline, - title: t.about.disclaimer, - children: getDisclaimerText(context), - ), - ListTile( - leading: const Icon(Icons.book_outlined), - title: Text(t.about.dependencies), - onTap: () { - Navigator.push( - context, - AppRoute( - builder: (context) => const CustomLicensePage(), - ), - ); - }, - ), - ListTile( - leading: const Icon(Icons.code_outlined), - title: Text(t.about.sourceCode), - onTap: () { - launchUrlString( - 'https://github.com/digitalfabrik/entitlementcard', - mode: LaunchMode.externalApplication, - ); - }, - ), - if (config.showDevSettings) + Section(headline: t.about.infoTitle, children: [ + ContentTile(icon: Icons.copyright, title: t.about.licenses(n: 1), children: getCopyrightText(context)), ListTile( - leading: const Icon(Icons.build), - title: Text(t.about.developmentOptions), - onTap: () => showDialog( - context: context, - builder: (context) => - SimpleDialog(title: Text(t.about.developmentOptions), children: [DevSettingsView()]), - ), + leading: const Icon(Icons.privacy_tip_outlined), + title: Text(t.about.privacyDeclaration), + onTap: () => launchUrlString(buildConfig.dataPrivacyPolicyUrl, mode: LaunchMode.externalApplication), + ), + ContentTile( + icon: Icons.info_outline, + title: t.about.disclaimer, + children: getDisclaimerText(context), + ), + ListTile( + leading: const Icon(Icons.book_outlined), + title: Text(t.about.dependencies), + onTap: () { + Navigator.push( + context, + AppRoute( + builder: (context) => const CustomLicensePage(), + ), + ); + }, + ), + ListTile( + leading: const Icon(Icons.code_outlined), + title: Text(t.about.sourceCode), + onTap: () { + launchUrlString( + 'https://github.com/digitalfabrik/entitlementcard', + mode: LaunchMode.externalApplication, + ); + }, + ), + ]), + if (config.showDevSettings) + Column( + children: [ + const Divider( + height: 1, + thickness: 1, + ), + ListTile( + leading: const Icon(Icons.build), + title: Text(t.about.developmentOptions), + onTap: () => showDialog( + context: context, + builder: (context) => + SimpleDialog(title: Text(t.about.developmentOptions), children: [DevSettingsView()]), + ), + ) + ], ) ]; } else { diff --git a/frontend/lib/about/language_change.dart b/frontend/lib/about/language_change.dart new file mode 100644 index 000000000..eb5eb2b13 --- /dev/null +++ b/frontend/lib/about/language_change.dart @@ -0,0 +1,40 @@ +import 'package:ehrenamtskarte/build_config/build_config.dart' show buildConfig; +import 'package:ehrenamtskarte/l10n/translations.g.dart'; +import 'package:flutter/material.dart'; + +Map languages = {'en': 'Englisch', 'de': 'Deutsch'}; + +class LanguageChange extends StatelessWidget { + const LanguageChange({super.key}); + + @override + Widget build(BuildContext context) { + return Column(children: [ + ...buildConfig.appLocales.map((item) => DecoratedBox( + decoration: BoxDecoration( + color: LocaleSettings.currentLocale.languageCode == item + ? Theme.of(context).colorScheme.surfaceVariant + : null), + child: ListTile( + title: Text( + languages[item]!, + textAlign: TextAlign.center, + style: TextStyle(fontWeight: FontWeight.bold), + ), + onTap: () => switchLanguage(context, item)))) + ]); + } + + switchLanguage(BuildContext context, String language) { + final messengerState = ScaffoldMessenger.of(context); + LocaleSettings.setLocaleRaw(language); + messengerState.showSnackBar( + SnackBar( + backgroundColor: Theme.of(context).colorScheme.primary, + content: + Text(t.about.languageChangeSuccessful, style: TextStyle(color: Theme.of(context).colorScheme.background)), + ), + ); + Navigator.pop(context); + } +} diff --git a/frontend/lib/about/section.dart b/frontend/lib/about/section.dart new file mode 100644 index 000000000..652727715 --- /dev/null +++ b/frontend/lib/about/section.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +class Section extends StatelessWidget { + final String headline; + final List children; + + const Section({super.key, required this.headline, required this.children}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 16, left: 16, right: 16), + child: Text(headline, + style: Theme.of(context) + .textTheme + .bodySmall + ?.merge(TextStyle(color: Theme.of(context).colorScheme.secondary))), + ), + Column(children: children), + const SizedBox(height: 10), + ], + ); + } +} diff --git a/frontend/lib/home/home_page.dart b/frontend/lib/home/home_page.dart index aec036628..c306cf0be 100644 --- a/frontend/lib/home/home_page.dart +++ b/frontend/lib/home/home_page.dart @@ -51,12 +51,12 @@ class HomePageState extends State { if (buildConfig.featureFlags.verification) AppFlow( IdentificationPage(), - Icons.remove_red_eye_outlined, + Icons.credit_card, (BuildContext context) => t.identification.title, GlobalKey(debugLabel: 'Auth tab key'), ), - AppFlow(const AboutPage(), Icons.info_outline, (BuildContext context) => t.about.title, - GlobalKey(debugLabel: 'About tab key')), + AppFlow(const AboutPage(), buildConfig.appLocales.length > 1 ? Icons.menu : Icons.info_outline, + (BuildContext context) => t.about.title, GlobalKey(debugLabel: 'About tab key')), ]; } diff --git a/frontend/lib/themes.dart b/frontend/lib/themes.dart index 71cebd3eb..7c925b8d3 100644 --- a/frontend/lib/themes.dart +++ b/frontend/lib/themes.dart @@ -16,7 +16,7 @@ ThemeData get lightTheme { ), textTheme: defaultTypography.copyWith( headlineMedium: defaultTypography.headlineMedium?.apply(color: Colors.black87), - headlineSmall: defaultTypography.headlineMedium?.apply(color: Colors.black87), + headlineSmall: defaultTypography.headlineSmall?.apply(color: Colors.black87), titleLarge: const TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold), bodyLarge: const TextStyle(fontSize: 15.0, fontWeight: FontWeight.normal), bodyMedium: const TextStyle(fontSize: 15.0, color: Color(0xFF505050)), @@ -59,7 +59,7 @@ ThemeData get darkTheme { ), textTheme: defaultTypography.copyWith( headlineMedium: defaultTypography.headlineMedium?.apply(color: Colors.white), - headlineSmall: defaultTypography.headlineMedium?.apply(color: Colors.white), + headlineSmall: defaultTypography.headlineSmall?.apply(color: Colors.white), titleLarge: const TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold), bodyLarge: const TextStyle(fontSize: 15.0, fontWeight: FontWeight.normal), bodyMedium: const TextStyle(fontSize: 15.0, color: Color(0xFFC6C4C4)),