feat: simplify AdminScreen and refactor ImportScreen to use TabBarView directly

This commit is contained in:
Nils-Johan Gynther
2026-04-25 08:31:42 +02:00
parent 8ea2b97c27
commit e2b7b884aa
3 changed files with 60 additions and 57 deletions
+53 -17
View File
@@ -5,7 +5,14 @@ import 'package:go_router/go_router.dart';
import '../../features/auth/data/auth_providers.dart'; import '../../features/auth/data/auth_providers.dart';
import '../../features/recipes/data/recipes_grid_provider.dart'; import '../../features/recipes/data/recipes_grid_provider.dart';
const _adminDestination = _AppDestination( const _profileHeaderDestination = _AppDestination(
path: '/profile',
title: 'Profil',
icon: Icons.person,
label: 'Profil',
);
const _adminHeaderDestination = _AppDestination(
path: '/admin', path: '/admin',
title: 'Admin', title: 'Admin',
icon: Icons.admin_panel_settings_outlined, icon: Icons.admin_panel_settings_outlined,
@@ -53,24 +60,32 @@ class AppShell extends ConsumerWidget {
icon: Icons.upload_file_outlined, icon: Icons.upload_file_outlined,
label: 'Importera', label: 'Importera',
), ),
_AppDestination(
path: '/profile',
title: 'Profil',
icon: Icons.person,
label: 'Profil',
),
]; ];
List<_AppDestination> _destinations(bool isAdmin) => [ List<_AppDestination> _destinations(bool isAdmin) => _baseDestinations;
..._baseDestinations,
if (isAdmin) _adminDestination,
];
int _selectedIndex(List<_AppDestination> destinations) { int? _selectedIndex(List<_AppDestination> destinations) {
final index = destinations.indexWhere( final index = destinations.indexWhere(
(destination) => location.startsWith(destination.path), (destination) => location.startsWith(destination.path),
); );
return index < 0 ? 0 : index; 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 @override
@@ -78,7 +93,7 @@ class AppShell extends ConsumerWidget {
final isAdmin = ref.watch(isAdminProvider); final isAdmin = ref.watch(isAdminProvider);
final dests = _destinations(isAdmin); final dests = _destinations(isAdmin);
final selectedIndex = _selectedIndex(dests); final selectedIndex = _selectedIndex(dests);
final selectedDestination = dests[selectedIndex]; final selectedDestination = _selectedHeaderDestination(dests, isAdmin);
final isWide = MediaQuery.of(context).size.width >= 900; final isWide = MediaQuery.of(context).size.width >= 900;
void navigateTo(int index) { void navigateTo(int index) {
@@ -90,6 +105,7 @@ class AppShell extends ConsumerWidget {
final isRecipesRoute = location.startsWith('/recipes') && final isRecipesRoute = location.startsWith('/recipes') &&
!location.startsWith('/recipes/'); !location.startsWith('/recipes/');
final isImportRoute = location == '/import';
Future<void> logout() async { Future<void> logout() async {
await ref.read(authStateProvider.notifier).logout(); await ref.read(authStateProvider.notifier).logout();
@@ -98,9 +114,23 @@ class AppShell extends ConsumerWidget {
} }
} }
return Scaffold( Widget shell = Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(selectedDestination.title), title: 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: [ actions: [
if (isRecipesRoute) if (isRecipesRoute)
Consumer( Consumer(
@@ -177,7 +207,7 @@ class AppShell extends ConsumerWidget {
? Row( ? Row(
children: [ children: [
NavigationRail( NavigationRail(
selectedIndex: selectedIndex, selectedIndex: selectedIndex ?? 0,
onDestinationSelected: navigateTo, onDestinationSelected: navigateTo,
labelType: NavigationRailLabelType.all, labelType: NavigationRailLabelType.all,
destinations: dests destinations: dests
@@ -197,7 +227,7 @@ class AppShell extends ConsumerWidget {
bottomNavigationBar: isWide bottomNavigationBar: isWide
? null ? null
: NavigationBar( : NavigationBar(
selectedIndex: selectedIndex, selectedIndex: selectedIndex ?? 0,
onDestinationSelected: navigateTo, onDestinationSelected: navigateTo,
destinations: dests destinations: dests
.map( .map(
@@ -209,6 +239,12 @@ class AppShell extends ConsumerWidget {
.toList(), .toList(),
), ),
); );
if (isImportRoute) {
shell = DefaultTabController(length: 2, child: shell);
}
return shell;
} }
} }
@@ -12,12 +12,7 @@ class AdminScreen extends ConsumerStatefulWidget {
class _AdminScreenState extends ConsumerState<AdminScreen> { class _AdminScreenState extends ConsumerState<AdminScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return const AdminUsersPanel();
appBar: AppBar(
title: const Text('Admin Användare'),
),
body: const AdminUsersPanel(),
);
} }
} }
@@ -14,42 +14,14 @@ class ImportScreen extends StatefulWidget {
State<ImportScreen> createState() => _ImportScreenState(); State<ImportScreen> createState() => _ImportScreenState();
} }
class _ImportScreenState extends State<ImportScreen> class _ImportScreenState extends State<ImportScreen> {
with SingleTickerProviderStateMixin {
late final TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return const TabBarView(
appBar: AppBar( children: [
title: const Text('Importera'), RecipeImportTab(),
bottom: TabBar( ReceiptImportTab(),
controller: _tabController, ],
tabs: const [
Tab(icon: Icon(Icons.restaurant_menu_outlined), text: 'Recept'),
Tab(icon: Icon(Icons.receipt_long_outlined), text: 'Kvitto'),
],
),
),
body: TabBarView(
controller: _tabController,
children: const [
RecipeImportTab(),
ReceiptImportTab(),
],
),
); );
} }
} }