Use width-based adaptive layout (768px breakpoint) so tablets get a NavigationRail sidebar instead of the bottom bar, and grid columns scale from 2 to 5 based on available width. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
124 lines
4.1 KiB
Dart
124 lines
4.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:worldhopper/config/router.dart';
|
|
import 'package:worldhopper/l10n/app_localizations.dart';
|
|
import 'package:worldhopper/helpers/responsive_helper.dart';
|
|
import 'package:worldhopper/providers/navigation_provider.dart';
|
|
|
|
/// Shell widget that provides the bottom navigation bar
|
|
/// and handles tab switching for the main app sections
|
|
class MainShellScreen extends ConsumerStatefulWidget {
|
|
final StatefulNavigationShell navigationShell;
|
|
|
|
const MainShellScreen({
|
|
super.key,
|
|
required this.navigationShell,
|
|
});
|
|
|
|
@override
|
|
ConsumerState<MainShellScreen> createState() => _MainShellScreenState();
|
|
}
|
|
|
|
class _MainShellScreenState extends ConsumerState<MainShellScreen> {
|
|
bool _initialized = false;
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
super.didChangeDependencies();
|
|
|
|
if (!_initialized) {
|
|
_initialized = true;
|
|
// Load saved tab index and navigate to it
|
|
final savedIndex = ref.read(navigationStateProvider);
|
|
if (savedIndex != widget.navigationShell.currentIndex) {
|
|
// Delay navigation to allow widget tree to build
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
widget.navigationShell.goBranch(savedIndex, initialLocation: true);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
void _onDestinationSelected(int index) {
|
|
// Persist the tab change
|
|
ref.read(navigationStateProvider.notifier).setTabIndex(index);
|
|
|
|
// If re-tapping the same tab, pop any Navigator-pushed routes
|
|
// (e.g. sub-settings screens) back to the branch root
|
|
if (index == widget.navigationShell.currentIndex) {
|
|
final navigatorKey = AppRouter.branchNavigatorKeys[index];
|
|
navigatorKey.currentState?.popUntil((route) => route.isFirst);
|
|
}
|
|
|
|
// Navigate to the selected tab
|
|
widget.navigationShell.goBranch(
|
|
index,
|
|
initialLocation: index == widget.navigationShell.currentIndex,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context);
|
|
final wide = isWideScreen(MediaQuery.of(context).size.width);
|
|
|
|
if (wide) {
|
|
return Scaffold(
|
|
body: Row(
|
|
children: [
|
|
NavigationRail(
|
|
labelType: NavigationRailLabelType.all,
|
|
selectedIndex: widget.navigationShell.currentIndex,
|
|
onDestinationSelected: _onDestinationSelected,
|
|
destinations: [
|
|
NavigationRailDestination(
|
|
icon: const Icon(Icons.auto_stories_outlined),
|
|
selectedIcon: const Icon(Icons.auto_stories),
|
|
label: Text(l10n.navLibrary),
|
|
),
|
|
NavigationRailDestination(
|
|
icon: const Icon(Icons.dns_outlined),
|
|
selectedIcon: const Icon(Icons.dns),
|
|
label: Text(l10n.navServers),
|
|
),
|
|
NavigationRailDestination(
|
|
icon: const Icon(Icons.settings_outlined),
|
|
selectedIcon: const Icon(Icons.settings),
|
|
label: Text(l10n.navSettings),
|
|
),
|
|
],
|
|
),
|
|
const VerticalDivider(thickness: 1, width: 1),
|
|
Expanded(child: widget.navigationShell),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
return Scaffold(
|
|
body: widget.navigationShell,
|
|
bottomNavigationBar: NavigationBar(
|
|
selectedIndex: widget.navigationShell.currentIndex,
|
|
onDestinationSelected: _onDestinationSelected,
|
|
destinations: [
|
|
NavigationDestination(
|
|
icon: const Icon(Icons.auto_stories_outlined),
|
|
selectedIcon: const Icon(Icons.auto_stories),
|
|
label: l10n.navLibrary,
|
|
),
|
|
NavigationDestination(
|
|
icon: const Icon(Icons.dns_outlined),
|
|
selectedIcon: const Icon(Icons.dns),
|
|
label: l10n.navServers,
|
|
),
|
|
NavigationDestination(
|
|
icon: const Icon(Icons.settings_outlined),
|
|
selectedIcon: const Icon(Icons.settings),
|
|
label: l10n.navSettings,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|