Cleanup
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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(
|
||||||
|
animation: fc,
|
||||||
|
builder: (context, _) {
|
||||||
|
final baseTabs = _getMobileTabs(context);
|
||||||
|
|
||||||
|
// Erlaubte Tabs filtern
|
||||||
|
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,
|
selectedIndex: selected,
|
||||||
onDestinationSelected: (i) =>
|
onDestinationSelected: (i) => context.go(tabs[i].route),
|
||||||
_goForIndex(context, i, tabs, (it) => it.route),
|
|
||||||
destinations: [
|
destinations: [
|
||||||
for (final it in tabs)
|
for (final it in tabs)
|
||||||
NavigationDestination(icon: Icon(it.icon), label: it.label),
|
NavigationDestination(icon: Icon(it.icon), label: it.label),
|
||||||
],
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -194,6 +255,36 @@ 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>();
|
||||||
|
|
||||||
|
bool routeEnabled(String route) {
|
||||||
|
if (route.startsWith(AppRoute.home.path)) return true;
|
||||||
|
if (route.startsWith(AppRoute.settings.path)) return true;
|
||||||
|
|
||||||
|
if (route.startsWith(AppRoute.budget.path)) return fc.hasHousehold;
|
||||||
|
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;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnimatedBuilder(
|
||||||
|
animation: fc,
|
||||||
|
builder: (context, _) {
|
||||||
|
final visibleItems = [
|
||||||
|
for (final it in items)
|
||||||
|
if (routeEnabled(it.route)) it,
|
||||||
|
];
|
||||||
|
|
||||||
|
final currentPath = GoRouterState.of(context).matchedLocation;
|
||||||
|
int safeSelected = 0;
|
||||||
|
for (var i = 0; i < visibleItems.length; i++) {
|
||||||
|
if (currentPath.startsWith(visibleItems[i].route)) {
|
||||||
|
safeSelected = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
@@ -206,75 +297,32 @@ class _DesktopDrawer extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
const _LogoHeader(),
|
const _LogoHeader(),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
for (var i = 0; i < items.length; i++)
|
for (var i = 0; i < visibleItems.length; i++)
|
||||||
ListTile(
|
ListTile(
|
||||||
selected: i == selectedIndex,
|
selected: i == safeSelected,
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
i == selectedIndex
|
i == safeSelected
|
||||||
? (items[i].selectedIcon ?? items[i].icon)
|
? (visibleItems[i].selectedIcon ??
|
||||||
: items[i].icon,
|
visibleItems[i].icon)
|
||||||
|
: visibleItems[i].icon,
|
||||||
),
|
),
|
||||||
title: Text(items[i].label),
|
title: Text(visibleItems[i].label),
|
||||||
onTap: () => context.go(items[i].route),
|
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),
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AppDrawer extends StatelessWidget {
|
|
||||||
final List<
|
|
||||||
({IconData icon, IconData? selectedIcon, String label, String route})
|
|
||||||
>
|
|
||||||
items;
|
|
||||||
final int selectedIndex;
|
|
||||||
|
|
||||||
const _AppDrawer({required this.items, required this.selectedIndex});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final scheme = Theme.of(context).colorScheme;
|
|
||||||
|
|
||||||
return Drawer(
|
|
||||||
child: SafeArea(
|
|
||||||
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: () {
|
|
||||||
Navigator.of(context).maybePop();
|
|
||||||
context.go(items[i].route);
|
|
||||||
},
|
},
|
||||||
),
|
|
||||||
const Divider(),
|
|
||||||
ListTile(
|
|
||||||
leading: const Icon(Icons.settings_outlined),
|
|
||||||
title: Text(Translations.of(context).app.drawerSettings),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).maybePop();
|
|
||||||
context.go('/settings');
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
@@ -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(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
@@ -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,7 +52,8 @@ class _CategoryList extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(
|
return SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_SectionHeader(t.settings.sections.app),
|
_SectionHeader(t.settings.sections.app),
|
||||||
@@ -66,9 +64,9 @@ class _CategoryList extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
tile(
|
tile(
|
||||||
Icons.tune,
|
Icons.phone_iphone,
|
||||||
t.settings.featureSettings,
|
t.settings.items.designSettings,
|
||||||
() => const FeatureSettingsView(),
|
() => const DesignSettingsView(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
@@ -109,11 +107,14 @@ class _CategoryList extends StatelessWidget {
|
|||||||
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),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user