import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../features/auth/data/auth_providers.dart'; import '../../features/admin/presentation/admin_screen.dart'; import '../../features/recipes/data/recipes_grid_provider.dart'; const _profileHeaderDestination = _AppDestination( path: '/profile', title: 'Profil', icon: Icons.person, label: 'Profil', ); const _adminHeaderDestination = _AppDestination( path: '/admin', title: 'Admin', icon: Icons.admin_panel_settings_outlined, label: 'Admin', ); class AppShell extends ConsumerWidget { final String location; final ValueChanged onNavigateToPath; final Widget child; const AppShell({ super.key, required this.location, required this.onNavigateToPath, required this.child, }); static const _baseDestinations = [ _AppDestination( path: '/recipes', title: 'Recept', icon: Icons.restaurant_menu, label: 'Recept', ), _AppDestination( path: '/inventory', title: 'Inventarie', icon: Icons.inventory_2_outlined, label: 'Inventarie', ), _AppDestination( path: '/matsedel', title: 'Matsedel', icon: Icons.calendar_month_outlined, label: 'Matsedel', ), _AppDestination( path: '/baslager', title: 'Baslager', icon: Icons.storefront_outlined, label: 'Baslager', ), _AppDestination( path: '/import', title: 'Importera', icon: Icons.upload_file_outlined, label: 'Importera', ), ]; List<_AppDestination> _destinations(bool isAdmin) => isAdmin ? [..._baseDestinations, _adminHeaderDestination] : _baseDestinations; int? _selectedIndex(List<_AppDestination> destinations) { final index = destinations.indexWhere( (destination) => location.startsWith(destination.path), ); return index < 0 ? null : index; } _AppDestination _selectedHeaderDestination( List<_AppDestination> destinations, bool isAdmin, ) { if (location.startsWith('/profile')) { return _profileHeaderDestination; } if (location.startsWith('/admin') && isAdmin) { return _adminHeaderDestination; } final selectedIndex = _selectedIndex(destinations); if (selectedIndex != null) { return destinations[selectedIndex]; } return destinations.first; } @override Widget build(BuildContext context, WidgetRef ref) { final locationUri = Uri.parse(location); final isAdmin = ref.watch(isAdminProvider); final dests = _destinations(isAdmin); final selectedIndex = _selectedIndex(dests); final selectedDestination = _selectedHeaderDestination(dests, isAdmin); final isWide = MediaQuery.of(context).size.width >= 900; void navigateTo(int index) { final target = dests[index].path; if (target != location && context.mounted) { onNavigateToPath(target); } } final isRecipesRoute = location.startsWith('/recipes') && !location.startsWith('/recipes/'); final isImportRoute = location == '/import'; final isAdminRoute = location.startsWith('/admin'); final adminTab = AdminViewTabX.fromQuery( locationUri.queryParameters['tab'], ); void navigateToAdminTab(AdminViewTab tab) { final target = '/admin?tab=${tab.queryValue}'; if (target != location && context.mounted) { onNavigateToPath(target); } } Widget buildAdminTitle() { return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( mainAxisSize: MainAxisSize.min, children: [ ChoiceChip( label: const Text('Användare'), selected: adminTab == AdminViewTab.users, onSelected: (_) => navigateToAdminTab(AdminViewTab.users), ), const SizedBox(width: 8), ChoiceChip( label: const Text('Databas'), selected: adminTab == AdminViewTab.database, onSelected: (_) => navigateToAdminTab(AdminViewTab.database), ), ], ), ); } Widget shell = Scaffold( appBar: AppBar( title: isAdminRoute ? buildAdminTitle() : Text(selectedDestination.title), bottom: isImportRoute ? const TabBar( tabs: [ Tab( icon: Icon(Icons.restaurant_menu_outlined), text: 'Recept', ), Tab( icon: Icon(Icons.receipt_long_outlined), text: 'Kvitto', ), ], ) : null, actions: [ if (isRecipesRoute) Consumer( builder: (context, ref, child) { final view = ref.watch(recipesViewProvider).maybeWhen( data: (v) => v, orElse: () => (mode: RecipesViewMode.grid, columns: 2), ); return Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( tooltip: view.mode == RecipesViewMode.grid ? 'Visa som lista' : 'Visa som grid', icon: Icon(view.mode == RecipesViewMode.grid ? Icons.view_list : Icons.grid_view), onPressed: () => ref.read(recipesViewProvider.notifier).toggleMode(), ), if (view.mode == RecipesViewMode.grid) PopupMenuButton( icon: const Icon(Icons.grid_view), tooltip: 'Välj antal kolumner', onSelected: (columns) => ref.read(recipesViewProvider.notifier).setColumns(columns), itemBuilder: (context) => const [ PopupMenuItem(value: 2, child: Text('2 kolumner')), PopupMenuItem(value: 4, child: Text('4 kolumner')), PopupMenuItem(value: 6, child: Text('6 kolumner')), PopupMenuItem(value: 8, child: Text('8 kolumner')), ], ), ], ); }, ), PopupMenuButton( tooltip: 'Profil och konto', icon: const Icon(Icons.account_circle_outlined), onSelected: (value) async { switch (value) { case 'profile': if (location != '/profile' && context.mounted) { onNavigateToPath('/profile'); } break; case 'logout': await ref.read(authStateProvider.notifier).logout(); if (context.mounted) { onNavigateToPath('/login'); } break; } }, itemBuilder: (context) => const [ PopupMenuItem( value: 'profile', child: ListTile( leading: Icon(Icons.person_outline), title: Text('Profil'), contentPadding: EdgeInsets.zero, ), ), PopupMenuDivider(), PopupMenuItem( value: 'logout', child: ListTile( leading: Icon(Icons.logout), title: Text('Logga ut'), contentPadding: EdgeInsets.zero, ), ), ], ), ], ), body: isWide ? Row( children: [ NavigationRail( selectedIndex: selectedIndex ?? 0, onDestinationSelected: navigateTo, labelType: NavigationRailLabelType.all, destinations: dests .map( (destination) => NavigationRailDestination( icon: Icon(destination.icon), label: Text(destination.label), ), ) .toList(), ), const VerticalDivider(width: 1), Expanded(child: child), ], ) : child, bottomNavigationBar: isWide ? null : NavigationBar( selectedIndex: selectedIndex ?? 0, onDestinationSelected: navigateTo, destinations: dests .map( (destination) => NavigationDestination( icon: Icon(destination.icon), label: destination.label, ), ) .toList(), ), ); if (isImportRoute) { shell = DefaultTabController(length: 2, child: shell); } return shell; } } class _AppDestination { final String path; final String title; final IconData icon; final String label; const _AppDestination({ required this.path, required this.title, required this.icon, required this.label, }); }