This commit is contained in:
2025-09-27 14:21:48 +02:00
parent 8fa071e565
commit 465f7153a4
10 changed files with 258 additions and 202 deletions

View File

@@ -13,9 +13,11 @@
"title": "Budgets" "title": "Budgets"
}, },
"app": { "app": {
"navigationCar": "Auto",
"navigationSettings": "Einstellungen", "navigationSettings": "Einstellungen",
"navigationDashboard": "Dashboard", "navigationDashboard": "Dashboard",
"navigationBudgets": "Budgets", "navigationBudgets": "Budgets",
"navigationHousehold": "Haushalt",
"navigationInventory": "Inventar", "navigationInventory": "Inventar",
"navigationReports": "Berichte", "navigationReports": "Berichte",
"tooltipMenu": "Menü", "tooltipMenu": "Menü",
@@ -27,7 +29,6 @@
}, },
"settings": { "settings": {
"title": "Einstellungen", "title": "Einstellungen",
"featureSettings": "Funktionseinstellungen",
"sections": { "sections": {
"account": "Konto & Daten", "account": "Konto & Daten",
"app": "App", "app": "App",
@@ -35,6 +36,7 @@
}, },
"items": { "items": {
"appSettings": "App-Einstellungen", "appSettings": "App-Einstellungen",
"designSettings": "Design-Einstellungen",
"personalData": "Persönliche Daten", "personalData": "Persönliche Daten",
"accountManagement": "Kontoverwaltung", "accountManagement": "Kontoverwaltung",
"helpCenter": "Hilfe", "helpCenter": "Hilfe",

View File

@@ -13,8 +13,10 @@
"title": "Budgets" "title": "Budgets"
}, },
"app": { "app": {
"navigationCar": "Car",
"navigationSettings": "Settings", "navigationSettings": "Settings",
"navigationDashboard": "Dashboard", "navigationDashboard": "Dashboard",
"navigationHousehold": "Household",
"navigationBudgets": "Budgets", "navigationBudgets": "Budgets",
"navigationInventory": "Inventory", "navigationInventory": "Inventory",
"navigationReports": "Reports", "navigationReports": "Reports",
@@ -27,7 +29,6 @@
}, },
"settings": { "settings": {
"title": "Settings", "title": "Settings",
"featureSettings": "Feature Settings",
"sections": { "sections": {
"account": "Account & Data", "account": "Account & Data",
"app": "App", "app": "App",
@@ -35,6 +36,7 @@
}, },
"items": { "items": {
"appSettings": "App settings", "appSettings": "App settings",
"designSettings": "Design settings",
"personalData": "Personal data", "personalData": "Personal data",
"accountManagement": "Account management", "accountManagement": "Account management",
"helpCenter": "Help", "helpCenter": "Help",

View File

@@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang` /// To regenerate, run: `dart run slang`
/// ///
/// Locales: 2 /// Locales: 2
/// Strings: 122 (61 per locale) /// Strings: 126 (63 per locale)
/// ///
/// Built on 2025-09-27 at 11:35 UTC /// Built on 2025-09-27 at 12:19 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint, unused_import // ignore_for_file: type=lint, unused_import

View File

@@ -85,9 +85,11 @@ class _TranslationsAppDe implements TranslationsAppEn {
final TranslationsDe _root; // ignore: unused_field final TranslationsDe _root; // ignore: unused_field
// Translations // Translations
@override String get navigationCar => 'Auto';
@override String get navigationSettings => 'Einstellungen'; @override String get navigationSettings => 'Einstellungen';
@override String get navigationDashboard => 'Dashboard'; @override String get navigationDashboard => 'Dashboard';
@override String get navigationBudgets => 'Budgets'; @override String get navigationBudgets => 'Budgets';
@override String get navigationHousehold => 'Haushalt';
@override String get navigationInventory => 'Inventar'; @override String get navigationInventory => 'Inventar';
@override String get navigationReports => 'Berichte'; @override String get navigationReports => 'Berichte';
@override String get tooltipMenu => 'Menü'; @override String get tooltipMenu => 'Menü';
@@ -106,7 +108,6 @@ class _TranslationsSettingsDe implements TranslationsSettingsEn {
// Translations // Translations
@override String get title => 'Einstellungen'; @override String get title => 'Einstellungen';
@override String get featureSettings => 'Funktionseinstellungen';
@override late final _TranslationsSettingsSectionsDe sections = _TranslationsSettingsSectionsDe._(_root); @override late final _TranslationsSettingsSectionsDe sections = _TranslationsSettingsSectionsDe._(_root);
@override late final _TranslationsSettingsItemsDe items = _TranslationsSettingsItemsDe._(_root); @override late final _TranslationsSettingsItemsDe items = _TranslationsSettingsItemsDe._(_root);
@override late final _TranslationsSettingsMessagesDe messages = _TranslationsSettingsMessagesDe._(_root); @override late final _TranslationsSettingsMessagesDe messages = _TranslationsSettingsMessagesDe._(_root);
@@ -150,6 +151,7 @@ class _TranslationsSettingsItemsDe implements TranslationsSettingsItemsEn {
// Translations // Translations
@override String get appSettings => 'App-Einstellungen'; @override String get appSettings => 'App-Einstellungen';
@override String get designSettings => 'Design-Einstellungen';
@override String get personalData => 'Persönliche Daten'; @override String get personalData => 'Persönliche Daten';
@override String get accountManagement => 'Kontoverwaltung'; @override String get accountManagement => 'Kontoverwaltung';
@override String get helpCenter => 'Hilfe'; @override String get helpCenter => 'Hilfe';
@@ -291,9 +293,11 @@ extension on TranslationsDe {
case 'login.success': return 'Login erfolgreich'; case 'login.success': return 'Login erfolgreich';
case 'dashboard.welcome': return 'Dashboard Willkommen bei Finlog'; case 'dashboard.welcome': return 'Dashboard Willkommen bei Finlog';
case 'budget.title': return 'Budgets'; case 'budget.title': return 'Budgets';
case 'app.navigationCar': return 'Auto';
case 'app.navigationSettings': return 'Einstellungen'; case 'app.navigationSettings': return 'Einstellungen';
case 'app.navigationDashboard': return 'Dashboard'; case 'app.navigationDashboard': return 'Dashboard';
case 'app.navigationBudgets': return 'Budgets'; case 'app.navigationBudgets': return 'Budgets';
case 'app.navigationHousehold': return 'Haushalt';
case 'app.navigationInventory': return 'Inventar'; case 'app.navigationInventory': return 'Inventar';
case 'app.navigationReports': return 'Berichte'; case 'app.navigationReports': return 'Berichte';
case 'app.tooltipMenu': return 'Menü'; case 'app.tooltipMenu': return 'Menü';
@@ -303,11 +307,11 @@ extension on TranslationsDe {
case 'app.tooltipExpandRail': return 'Leiste erweitern'; case 'app.tooltipExpandRail': return 'Leiste erweitern';
case 'app.drawerSettings': return 'Einstellungen'; case 'app.drawerSettings': return 'Einstellungen';
case 'settings.title': return 'Einstellungen'; case 'settings.title': return 'Einstellungen';
case 'settings.featureSettings': return 'Funktionseinstellungen';
case 'settings.sections.account': return 'Konto & Daten'; case 'settings.sections.account': return 'Konto & Daten';
case 'settings.sections.app': return 'App'; case 'settings.sections.app': return 'App';
case 'settings.sections.help': return 'Hilfe & Rechtliches'; case 'settings.sections.help': return 'Hilfe & Rechtliches';
case 'settings.items.appSettings': return 'App-Einstellungen'; case 'settings.items.appSettings': return 'App-Einstellungen';
case 'settings.items.designSettings': return 'Design-Einstellungen';
case 'settings.items.personalData': return 'Persönliche Daten'; case 'settings.items.personalData': return 'Persönliche Daten';
case 'settings.items.accountManagement': return 'Kontoverwaltung'; case 'settings.items.accountManagement': return 'Kontoverwaltung';
case 'settings.items.helpCenter': return 'Hilfe'; case 'settings.items.helpCenter': return 'Hilfe';

View File

@@ -104,12 +104,18 @@ class TranslationsAppEn {
// Translations // Translations
/// en: 'Car'
String get navigationCar => 'Car';
/// en: 'Settings' /// en: 'Settings'
String get navigationSettings => 'Settings'; String get navigationSettings => 'Settings';
/// en: 'Dashboard' /// en: 'Dashboard'
String get navigationDashboard => 'Dashboard'; String get navigationDashboard => 'Dashboard';
/// en: 'Household'
String get navigationHousehold => 'Household';
/// en: 'Budgets' /// en: 'Budgets'
String get navigationBudgets => 'Budgets'; String get navigationBudgets => 'Budgets';
@@ -149,9 +155,6 @@ class TranslationsSettingsEn {
/// en: 'Settings' /// en: 'Settings'
String get title => 'Settings'; String get title => 'Settings';
/// en: 'Feature Settings'
String get featureSettings => 'Feature Settings';
late final TranslationsSettingsSectionsEn sections = TranslationsSettingsSectionsEn._(_root); late final TranslationsSettingsSectionsEn sections = TranslationsSettingsSectionsEn._(_root);
late final TranslationsSettingsItemsEn items = TranslationsSettingsItemsEn._(_root); late final TranslationsSettingsItemsEn items = TranslationsSettingsItemsEn._(_root);
late final TranslationsSettingsMessagesEn messages = TranslationsSettingsMessagesEn._(_root); late final TranslationsSettingsMessagesEn messages = TranslationsSettingsMessagesEn._(_root);
@@ -204,6 +207,9 @@ class TranslationsSettingsItemsEn {
/// en: 'App settings' /// en: 'App settings'
String get appSettings => 'App settings'; String get appSettings => 'App settings';
/// en: 'Design settings'
String get designSettings => 'Design settings';
/// en: 'Personal data' /// en: 'Personal data'
String get personalData => 'Personal data'; String get personalData => 'Personal data';
@@ -418,8 +424,10 @@ extension on Translations {
case 'login.success': return 'Logged in successfully'; case 'login.success': return 'Logged in successfully';
case 'dashboard.welcome': return 'Dashboard Welcome to Finlog'; case 'dashboard.welcome': return 'Dashboard Welcome to Finlog';
case 'budget.title': return 'Budgets'; case 'budget.title': return 'Budgets';
case 'app.navigationCar': return 'Car';
case 'app.navigationSettings': return 'Settings'; case 'app.navigationSettings': return 'Settings';
case 'app.navigationDashboard': return 'Dashboard'; case 'app.navigationDashboard': return 'Dashboard';
case 'app.navigationHousehold': return 'Household';
case 'app.navigationBudgets': return 'Budgets'; case 'app.navigationBudgets': return 'Budgets';
case 'app.navigationInventory': return 'Inventory'; case 'app.navigationInventory': return 'Inventory';
case 'app.navigationReports': return 'Reports'; case 'app.navigationReports': return 'Reports';
@@ -430,11 +438,11 @@ extension on Translations {
case 'app.tooltipExpandRail': return 'Expand Rail'; case 'app.tooltipExpandRail': return 'Expand Rail';
case 'app.drawerSettings': return 'Settings'; case 'app.drawerSettings': return 'Settings';
case 'settings.title': return 'Settings'; case 'settings.title': return 'Settings';
case 'settings.featureSettings': return 'Feature Settings';
case 'settings.sections.account': return 'Account & Data'; case 'settings.sections.account': return 'Account & Data';
case 'settings.sections.app': return 'App'; case 'settings.sections.app': return 'App';
case 'settings.sections.help': return 'Help & Legal'; case 'settings.sections.help': return 'Help & Legal';
case 'settings.items.appSettings': return 'App settings'; case 'settings.items.appSettings': return 'App settings';
case 'settings.items.designSettings': return 'Design settings';
case 'settings.items.personalData': return 'Personal data'; case 'settings.items.personalData': return 'Personal data';
case 'settings.items.accountManagement': return 'Account management'; case 'settings.items.accountManagement': return 'Account management';
case 'settings.items.helpCenter': return 'Help'; case 'settings.items.helpCenter': return 'Help';

View File

@@ -1,6 +1,9 @@
import 'package:app/core/app/router.dart';
import 'package:app/core/features/feature_controller.dart';
import 'package:app/core/i18n/translations.g.dart'; import 'package:app/core/i18n/translations.g.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
class AppShell extends StatefulWidget { class AppShell extends StatefulWidget {
final Widget child; final Widget child;
@@ -12,7 +15,7 @@ class AppShell extends StatefulWidget {
} }
class _AppShellState extends State<AppShell> { class _AppShellState extends State<AppShell> {
static const double _breakpoint = 800; // Tablet/Desktop threshold static const double _breakpoint = 800;
final FocusNode _contentFocus = FocusNode(debugLabel: 'contentFocus'); final FocusNode _contentFocus = FocusNode(debugLabel: 'contentFocus');
@override @override
@@ -23,7 +26,7 @@ class _AppShellState extends State<AppShell> {
// --- NAV ITEMS ------------------------------------------------------------- // --- NAV ITEMS -------------------------------------------------------------
// Desktop/Tablet drawer items (you can keep them rich/longer here) // Desktop/Tablet drawer items
List<({IconData icon, IconData? selectedIcon, String label, String route})> List<({IconData icon, IconData? selectedIcon, String label, String route})>
_getDesktopItems(BuildContext context) { _getDesktopItems(BuildContext context) {
final t = Translations.of(context); final t = Translations.of(context);
@@ -32,46 +35,61 @@ class _AppShellState extends State<AppShell> {
icon: Icons.dashboard_outlined, icon: Icons.dashboard_outlined,
selectedIcon: Icons.dashboard, selectedIcon: Icons.dashboard,
label: t.app.navigationDashboard, label: t.app.navigationDashboard,
route: '/', route: AppRoute.home.path,
), ),
( (
icon: Icons.account_balance_wallet_outlined, icon: Icons.account_balance_wallet_outlined,
selectedIcon: Icons.account_balance_wallet, selectedIcon: Icons.account_balance_wallet,
label: t.app.navigationBudgets, label: t.app.navigationBudgets, // Haushaltsbereich inkl. Budget
route: '/budget', route: AppRoute.budget.path,
), ),
( (
icon: Icons.inventory_2_outlined, icon: Icons.inventory_2_outlined,
selectedIcon: Icons.inventory_2, selectedIcon: Icons.inventory_2,
label: t.app.navigationInventory, label: t.app.navigationInventory,
route: '/inventory', route: AppRoute.inventory.path,
), ),
( (
icon: Icons.bar_chart_outlined, icon: Icons.bar_chart_outlined,
selectedIcon: Icons.bar_chart, selectedIcon: Icons.bar_chart,
label: t.app.navigationReports, label: t.app.navigationReports,
route: '/reports', route: AppRoute.reports.path,
), ),
( (
icon: Icons.settings_outlined, icon: Icons.settings_outlined,
selectedIcon: Icons.settings, selectedIcon: Icons.settings,
label: t.app.navigationSettings, label: t.app.navigationSettings,
route: '/settings', route: AppRoute.settings.path,
), ),
]; ];
} }
// Mobile bottom bar items (exactly the four you asked for) // Mobile bottom bar items (4 Tabs)
List<({IconData icon, String label, String route})> _getMobileTabs( List<({IconData icon, String label, String route})> _getMobileTabs(
BuildContext context, BuildContext context,
) { ) {
final t = Translations.of(context); final t = Translations.of(context);
return [ return [
(icon: Icons.dashboard, label: t.app.navigationDashboard, route: '/home'), (
// “Haushalt (inkl. Budget)” → map to /budget for now icon: Icons.dashboard,
(icon: Icons.home, label: 'Haushalt', route: '/budget'), label: t.app.navigationDashboard,
(icon: Icons.inventory_2, label: 'Inventar', route: '/inventory'), route: AppRoute.home.path,
(icon: Icons.directions_car, label: 'Auto', route: '/car'), ),
(
icon: Icons.home,
label: (t.app.navigationHousehold),
route: AppRoute.budget.path,
),
(
icon: Icons.inventory_2,
label: t.app.navigationInventory,
route: AppRoute.inventory.path,
),
(
icon: Icons.directions_car,
label: (t.app.navigationCar),
route: AppRoute.car.path,
),
]; ];
} }
@@ -82,13 +100,18 @@ class _AppShellState extends State<AppShell> {
return 0; return 0;
} }
void _goForIndex<T>( // Route→Feature-Guard
BuildContext ctx, bool _routeEnabled(String route, FeatureController fc) {
int i, if (route.startsWith(AppRoute.home.path)) return true;
List<T> items, if (route.startsWith(AppRoute.settings.path)) return true;
String Function(T) routeOf,
) { if (route.startsWith(AppRoute.budget.path)) return fc.hasHousehold;
ctx.go(routeOf(items[i])); if (route.startsWith(AppRoute.inventory.path)) return fc.hasInventory;
if (route.startsWith(AppRoute.car.path)) return fc.hasCar;
if (route.startsWith(AppRoute.reports.path)) return fc.hasReports;
// Default: sichtbar
return true;
} }
@override @override
@@ -107,16 +130,8 @@ class _AppShellState extends State<AppShell> {
final appBar = AppBar( final appBar = AppBar(
title: const _LogoHeader(), title: const _LogoHeader(),
// On desktop we use a persistent drawer, so no burger button. // Kein Burger-Button, da mobil ohne Drawer (BottomNav) und Desktop mit persistentem Drawer
leading: isDesktop leading: null,
? null
: Builder(
builder: (ctx) => IconButton(
icon: const Icon(Icons.menu),
onPressed: () => Scaffold.of(ctx).openDrawer(),
tooltip: t.app.tooltipMenu,
),
),
actions: [ actions: [
IconButton( IconButton(
tooltip: t.app.tooltipNotifications, tooltip: t.app.tooltipNotifications,
@@ -125,7 +140,7 @@ class _AppShellState extends State<AppShell> {
), ),
IconButton( IconButton(
tooltip: t.app.tooltipUserSettings, tooltip: t.app.tooltipUserSettings,
onPressed: () => context.push('/settings'), onPressed: () => context.push(AppRoute.settings.path),
icon: const Icon(Icons.account_circle_outlined), icon: const Icon(Icons.account_circle_outlined),
), ),
], ],
@@ -133,21 +148,67 @@ class _AppShellState extends State<AppShell> {
if (!isDesktop) { if (!isDesktop) {
// ------------------- MOBILE: Bottom Navigation ------------------- // ------------------- MOBILE: Bottom Navigation -------------------
final tabs = _getMobileTabs(context); final fc = context.read<FeatureController>();
final selected = _indexForPath(currentPath, tabs, (it) => it.route);
// Wenn aktuelle Route deaktiviert ist, sanft nach Home umleiten
WidgetsBinding.instance.addPostFrameCallback((_) {
final p = GoRouterState.of(context).matchedLocation;
if (!_routeEnabled(p, fc)) {
if (mounted) context.go(AppRoute.home.path);
}
});
return Scaffold( return Scaffold(
appBar: appBar, appBar: appBar,
// Keep drawer for mobile? You asked for bottom bar instead — remove drawer.
body: SafeArea(child: widget.child), body: SafeArea(child: widget.child),
bottomNavigationBar: NavigationBar( bottomNavigationBar: AnimatedBuilder(
selectedIndex: selected, animation: fc,
onDestinationSelected: (i) => builder: (context, _) {
_goForIndex(context, i, tabs, (it) => it.route), final baseTabs = _getMobileTabs(context);
destinations: [
for (final it in tabs) // Erlaubte Tabs filtern
NavigationDestination(icon: Icon(it.icon), label: it.label), var tabs = <({IconData icon, String label, String route})>[
], for (final it in baseTabs)
if (_routeEnabled(it.route, fc)) it,
];
// Fallback: min. 2 Ziele sicherstellen
if (tabs.length < 2) {
// Home ist immer erlaubt; „Einstellungen“ als zweites Ziel ergänzen
tabs = [
// Stelle sicher, dass Home als erstes drin ist
(
icon: Icons.dashboard,
label: Translations.of(context).app.navigationDashboard,
route: AppRoute.home.path,
),
(
icon: Icons.settings,
label: Translations.of(context).app.navigationSettings,
route: AppRoute.settings.path,
),
];
}
// aktuellen Index robust bestimmen
final currentPath = GoRouterState.of(context).matchedLocation;
int selected = 0;
for (var i = 0; i < tabs.length; i++) {
if (currentPath.startsWith(tabs[i].route)) {
selected = i;
break;
}
}
return NavigationBar(
selectedIndex: selected,
onDestinationSelected: (i) => context.go(tabs[i].route),
destinations: [
for (final it in tabs)
NavigationDestination(icon: Icon(it.icon), label: it.label),
],
);
},
), ),
); );
} }
@@ -194,87 +255,74 @@ class _DesktopDrawer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme; final scheme = Theme.of(context).colorScheme;
final fc = context.read<FeatureController>();
return Material( bool routeEnabled(String route) {
elevation: 0, if (route.startsWith(AppRoute.home.path)) return true;
child: SafeArea( if (route.startsWith(AppRoute.settings.path)) return true;
child: ListTileTheme(
selectedColor: scheme.onSecondaryContainer,
selectedTileColor: scheme.secondaryContainer,
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 8),
children: [
const _LogoHeader(),
const Divider(),
for (var i = 0; i < items.length; i++)
ListTile(
selected: i == selectedIndex,
leading: Icon(
i == selectedIndex
? (items[i].selectedIcon ?? items[i].icon)
: items[i].icon,
),
title: Text(items[i].label),
onTap: () => context.go(items[i].route),
),
],
),
),
),
);
}
}
class _AppDrawer extends StatelessWidget { if (route.startsWith(AppRoute.budget.path)) return fc.hasHousehold;
final List< if (route.startsWith(AppRoute.inventory.path)) return fc.hasInventory;
({IconData icon, IconData? selectedIcon, String label, String route}) if (route.startsWith(AppRoute.car.path)) return fc.hasCar;
> if (route.startsWith(AppRoute.reports.path)) return fc.hasReports;
items;
final int selectedIndex;
const _AppDrawer({required this.items, required this.selectedIndex}); return true;
}
@override return AnimatedBuilder(
Widget build(BuildContext context) { animation: fc,
final scheme = Theme.of(context).colorScheme; builder: (context, _) {
final visibleItems = [
for (final it in items)
if (routeEnabled(it.route)) it,
];
return Drawer( final currentPath = GoRouterState.of(context).matchedLocation;
child: SafeArea( int safeSelected = 0;
child: ListTileTheme( for (var i = 0; i < visibleItems.length; i++) {
selectedColor: scheme.onSecondaryContainer, if (currentPath.startsWith(visibleItems[i].route)) {
selectedTileColor: scheme.secondaryContainer, safeSelected = i;
child: ListView( break;
padding: const EdgeInsets.symmetric(vertical: 8), }
children: [ }
const _LogoHeader(),
const Divider(), return Material(
for (var i = 0; i < items.length; i++) elevation: 0,
ListTile( child: SafeArea(
selected: i == selectedIndex, child: ListTileTheme(
leading: Icon( selectedColor: scheme.onSecondaryContainer,
i == selectedIndex selectedTileColor: scheme.secondaryContainer,
? (items[i].selectedIcon ?? items[i].icon) child: ListView(
: items[i].icon, padding: const EdgeInsets.symmetric(vertical: 8),
), children: [
title: Text(items[i].label), const _LogoHeader(),
onTap: () { const Divider(),
Navigator.of(context).maybePop(); for (var i = 0; i < visibleItems.length; i++)
context.go(items[i].route); ListTile(
}, selected: i == safeSelected,
), leading: Icon(
const Divider(), i == safeSelected
ListTile( ? (visibleItems[i].selectedIcon ??
leading: const Icon(Icons.settings_outlined), visibleItems[i].icon)
title: Text(Translations.of(context).app.drawerSettings), : visibleItems[i].icon,
onTap: () { ),
Navigator.of(context).maybePop(); title: Text(visibleItems[i].label),
context.go('/settings'); onTap: () => context.go(visibleItems[i].route),
}, ),
// Optional: Settings als fixer Eintrag,
// falls du ihn unabhängig von items immer unten haben willst:
// const Divider(),
// ListTile(
// leading: const Icon(Icons.settings_outlined),
// title: Text(t.app.navigationSettings),
// onTap: () => context.go(AppRoute.settings.path),
// ),
],
), ),
], ),
), ),
), );
), },
); );
} }
} }

View File

@@ -2,12 +2,12 @@ import 'package:app/core/i18n/translations.g.dart';
import 'package:app/core/ui/controller/locale_controller.dart'; import 'package:app/core/ui/controller/locale_controller.dart';
import 'package:app/core/ui/controller/scale_controller.dart'; import 'package:app/core/ui/controller/scale_controller.dart';
import 'package:app/core/ui/controller/theme.dart'; import 'package:app/core/ui/controller/theme.dart';
import 'package:app/modules/settings/modules/app/model/app_settings_view_model.dart'; import 'package:app/modules/settings/modules/app/model/design_settings_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class AppSettingsView extends StatelessWidget { class DesignSettingsView extends StatelessWidget {
const AppSettingsView({super.key}); const DesignSettingsView({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@@ -3,26 +3,20 @@ import 'package:app/modules/settings/modules/app/model/feature_settings_view_mod
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:app/core/i18n/translations.g.dart';
/// A dedicated section under "Einstellungen" to enable/disable features. /// A dedicated section under "Einstellungen" to enable/disable features.
/// You can link this screen from your existing Settings list. /// You can link this screen from your existing Settings list.
/// If you keep a single Settings page, render _FeatureSettingsSection in-place. /// If you keep a single Settings page, render _FeatureSettingsSection in-place.
class FeatureSettingsView extends StatelessWidget { class AppSettingsView extends StatelessWidget {
const FeatureSettingsView({super.key}); const AppSettingsView({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final t = Translations.of(context);
final featureController = context.read<FeatureController>(); final featureController = context.read<FeatureController>();
final model = FeatureSettingsViewModel(featureController); final model = FeatureSettingsViewModel(featureController);
return ChangeNotifierProvider( return ChangeNotifierProvider(
create: (BuildContext context) => model, create: (BuildContext context) => model,
child: Scaffold( child: Scaffold(body: const _FeatureSettingsSection()),
appBar: AppBar(title: Text(t.settings.featureSettings)),
body: const _FeatureSettingsSection(),
),
); );
} }
} }

View File

@@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
class AppSettingsViewModel extends ChangeNotifier { class AppSettingsViewModel extends ChangeNotifier {
bool _isLoading = false; bool _isLoading = false;
bool _isSaving = false;
final ThemeController _theme; final ThemeController _theme;
final ScaleController _scale; final ScaleController _scale;
@@ -53,6 +52,4 @@ class AppSettingsViewModel extends ChangeNotifier {
TextScalePref get textScale => _scale.scale; TextScalePref get textScale => _scale.scale;
bool get isLoading => _isLoading; bool get isLoading => _isLoading;
bool get isSaving => _isSaving;
} }

View File

@@ -1,6 +1,6 @@
import 'package:app/core/i18n/translations.g.dart'; import 'package:app/core/i18n/translations.g.dart';
import 'package:app/core/ui/panel.dart'; import 'package:app/core/ui/panel.dart';
import 'package:app/modules/settings/modules/app/app_settings_view.dart'; import 'package:app/modules/settings/modules/app/design_settings_view.dart';
import 'package:app/modules/settings/modules/app/features_settings_view.dart'; import 'package:app/modules/settings/modules/app/features_settings_view.dart';
import 'package:app/modules/settings/modules/help/feedback_view.dart'; import 'package:app/modules/settings/modules/help/feedback_view.dart';
import 'package:app/modules/settings/modules/help/help_view.dart'; import 'package:app/modules/settings/modules/help/help_view.dart';
@@ -14,10 +14,7 @@ class SettingsView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final t = Translations.of(context);
return Scaffold( return Scaffold(
// appBar: AppBar(title: Text(t.settings.title)),
body: PanelNavigator(rootBuilder: (ctx) => _CategoryList()), body: PanelNavigator(rootBuilder: (ctx) => _CategoryList()),
); );
} }
@@ -55,65 +52,69 @@ class _CategoryList extends StatelessWidget {
); );
} }
return Column( return SingleChildScrollView(
crossAxisAlignment: CrossAxisAlignment.start, child: Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
_SectionHeader(t.settings.sections.app), children: [
tile( _SectionHeader(t.settings.sections.app),
Icons.tune, tile(
t.settings.items.appSettings, Icons.tune,
() => const AppSettingsView(), t.settings.items.appSettings,
), () => const AppSettingsView(),
const SizedBox(height: 12), ),
tile( const SizedBox(height: 12),
Icons.tune, tile(
t.settings.featureSettings, Icons.phone_iphone,
() => const FeatureSettingsView(), t.settings.items.designSettings,
), () => const DesignSettingsView(),
const SizedBox(height: 12), ),
const SizedBox(height: 12),
_SectionHeader(t.settings.sections.account), _SectionHeader(t.settings.sections.account),
tile( tile(
Icons.badge_outlined, Icons.badge_outlined,
t.settings.items.personalData, t.settings.items.personalData,
() => const PersonalPanel(), () => const PersonalPanel(),
), ),
tile( tile(
Icons.manage_accounts_outlined, Icons.manage_accounts_outlined,
t.settings.items.accountManagement, t.settings.items.accountManagement,
() => const AccountPanel(), () => const AccountPanel(),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
_SectionHeader(t.settings.sections.help), _SectionHeader(t.settings.sections.help),
tile( tile(
Icons.help_outline, Icons.help_outline,
t.settings.items.helpCenter, t.settings.items.helpCenter,
() => const HelpPanel(), () => const HelpPanel(),
), ),
tile( tile(
Icons.feedback_outlined, Icons.feedback_outlined,
t.settings.items.feedback, t.settings.items.feedback,
() => const FeedbackPanel(), () => const FeedbackPanel(),
), ),
tile( tile(
Icons.gavel_outlined, Icons.gavel_outlined,
t.settings.items.legalPrivacy, // "Rechtliches & Datenschutz" t.settings.items.legalPrivacy, // "Rechtliches & Datenschutz"
() => const LegalPanel(), () => const LegalPanel(),
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
const Divider(), const Divider(),
ListTile( ListTile(
leading: const Icon(Icons.logout), leading: const Icon(Icons.logout),
title: Text(t.settings.items.logout), title: Text(t.settings.items.logout),
onTap: () { onTap: () {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(t.settings.messages.logoutNotImplemented)), SnackBar(
); content: Text(t.settings.messages.logoutNotImplemented),
}, ),
), );
], },
),
],
),
); );
} }
} }