202 lines
6.2 KiB
Dart
202 lines
6.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import '../../features/auth/data/auth_providers.dart';
|
|
import '../../features/recipes/data/recipes_grid_provider.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
const _adminDestination = _AppDestination(
|
|
path: '/admin',
|
|
title: 'Admin',
|
|
icon: Icons.admin_panel_settings_outlined,
|
|
label: 'Admin',
|
|
);
|
|
|
|
class AppShell extends ConsumerWidget {
|
|
final String location;
|
|
final Widget child;
|
|
|
|
const AppShell({
|
|
super.key,
|
|
required this.location,
|
|
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',
|
|
),
|
|
_AppDestination(
|
|
path: '/profile',
|
|
title: 'Profil',
|
|
icon: Icons.person,
|
|
label: 'Profil',
|
|
),
|
|
];
|
|
|
|
List<_AppDestination> _destinations(bool isAdmin) => [
|
|
..._baseDestinations,
|
|
if (isAdmin) _adminDestination,
|
|
];
|
|
|
|
int _selectedIndex(List<_AppDestination> destinations) {
|
|
final index = destinations.indexWhere(
|
|
(destination) => location.startsWith(destination.path),
|
|
);
|
|
return index < 0 ? 0 : index;
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final isAdmin = ref.watch(isAdminProvider);
|
|
final dests = _destinations(isAdmin);
|
|
final selectedIndex = _selectedIndex(dests);
|
|
final selectedDestination = dests[selectedIndex];
|
|
final isWide = MediaQuery.of(context).size.width >= 900;
|
|
|
|
Future<void> logout() async {
|
|
await ref.read(authStateProvider.notifier).logout();
|
|
if (context.mounted) {
|
|
context.go('/login');
|
|
}
|
|
}
|
|
|
|
void navigateTo(int index) {
|
|
final target = dests[index].path;
|
|
if (target != location && context.mounted) {
|
|
context.go(target);
|
|
}
|
|
}
|
|
|
|
final isRecipesRoute = location.startsWith('/recipes') &&
|
|
!location.startsWith('/recipes/');
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(selectedDestination.title),
|
|
actions: [
|
|
if (isRecipesRoute) ...existing code...
|
|
Consumer(
|
|
builder: (context, ref, child) {
|
|
final view = ref.watch(recipesViewProvider).valueOrNull ??
|
|
(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<int>(
|
|
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')),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
IconButton(
|
|
tooltip: 'Logga ut',
|
|
icon: const Icon(Icons.logout),
|
|
onPressed: logout,
|
|
),
|
|
],
|
|
),
|
|
body: isWide
|
|
? Row(
|
|
children: [
|
|
NavigationRail(
|
|
selectedIndex: selectedIndex,
|
|
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,
|
|
onDestinationSelected: navigateTo,
|
|
destinations: dests
|
|
.map(
|
|
(destination) => NavigationDestination(
|
|
icon: Icon(destination.icon),
|
|
label: destination.label,
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
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,
|
|
});
|
|
}
|