91 lines
2.8 KiB
Dart
91 lines
2.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'home_screen.dart';
|
|
import 'receipts_screen.dart';
|
|
import 'report_screen.dart';
|
|
import 'settings_screen.dart';
|
|
|
|
/// App root once loaded: a persistent bottom nav bar over the four main
|
|
/// sections — Receipts (all vehicles), Vehicles (the vehicle list),
|
|
/// Reports, and Settings. Each tab keeps its own [Scaffold]/[AppBar]; this
|
|
/// shell only owns the [PageView]/[NavigationBar] and which tab is
|
|
/// selected.
|
|
///
|
|
/// A right-to-left swipe on the body advances to the next tab (and
|
|
/// left-to-right goes back) with the same sliding animation tapping a
|
|
/// [NavigationDestination] uses — both go through [_goToTab], which is the
|
|
/// only thing that moves [_pageController]. [AutomaticKeepAliveClientMixin]
|
|
/// on the three stateful tab screens (Receipts/Report/Settings) is what
|
|
/// keeps each tab's state — scroll position, toggles, in-progress form
|
|
/// fields — alive when [PageView] builds/tears down pages outside its
|
|
/// cache extent, the same guarantee the previous [IndexedStack]-based
|
|
/// version gave "for free".
|
|
class MainShell extends StatefulWidget {
|
|
const MainShell({super.key});
|
|
|
|
@override
|
|
State<MainShell> createState() => _MainShellState();
|
|
}
|
|
|
|
class _MainShellState extends State<MainShell> {
|
|
int _index = 0;
|
|
final _pageController = PageController();
|
|
|
|
static const _tabs = [
|
|
ReceiptsScreen(),
|
|
HomeScreen(),
|
|
ReportScreen(),
|
|
SettingsScreen(),
|
|
];
|
|
|
|
@override
|
|
void dispose() {
|
|
_pageController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _goToTab(int index) {
|
|
_pageController.animateToPage(
|
|
index,
|
|
duration: const Duration(milliseconds: 280),
|
|
curve: Curves.easeOutCubic,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: PageView(
|
|
controller: _pageController,
|
|
onPageChanged: (index) => setState(() => _index = index),
|
|
children: _tabs,
|
|
),
|
|
bottomNavigationBar: NavigationBar(
|
|
selectedIndex: _index,
|
|
onDestinationSelected: _goToTab,
|
|
destinations: const [
|
|
NavigationDestination(
|
|
icon: Icon(Icons.receipt_long_outlined),
|
|
selectedIcon: Icon(Icons.receipt_long),
|
|
label: 'Receipts',
|
|
),
|
|
NavigationDestination(
|
|
icon: Icon(Icons.directions_car_outlined),
|
|
selectedIcon: Icon(Icons.directions_car),
|
|
label: 'Vehicles',
|
|
),
|
|
NavigationDestination(
|
|
icon: Icon(Icons.summarize_outlined),
|
|
selectedIcon: Icon(Icons.summarize),
|
|
label: 'Reports',
|
|
),
|
|
NavigationDestination(
|
|
icon: Icon(Icons.settings_outlined),
|
|
selectedIcon: Icon(Icons.settings),
|
|
label: 'Settings',
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|