badge percentage support
This commit is contained in:
@@ -22,6 +22,14 @@ import 'package:provider/provider.dart';
|
||||
final GlobalKey<NavigatorState> _shellNavigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
const List<String> _contentPages = [
|
||||
"/dashboard",
|
||||
"/logbook",
|
||||
"/traction",
|
||||
"/add",
|
||||
"/more",
|
||||
];
|
||||
|
||||
const List<String> _defaultTabDestinations = [
|
||||
"/dashboard",
|
||||
"/logbook/entries",
|
||||
"/traction",
|
||||
@@ -29,7 +37,7 @@ const List<String> _contentPages = [
|
||||
"/more",
|
||||
];
|
||||
|
||||
const int _addTabIndex = 5;
|
||||
const int _addTabIndex = 3;
|
||||
|
||||
class _NavItem {
|
||||
final String label;
|
||||
@@ -53,10 +61,9 @@ int tabIndexForPath(String path) {
|
||||
matchPath = '/logbook/entries';
|
||||
} else if (matchPath.startsWith('/trips')) {
|
||||
matchPath = '/logbook/trips';
|
||||
} else if (matchPath == '/logbook') {
|
||||
matchPath = '/logbook/entries';
|
||||
} else if (matchPath.startsWith('/logbook/trips')) {
|
||||
matchPath = '/logbook/entries';
|
||||
}
|
||||
if (matchPath.startsWith('/logbook')) {
|
||||
matchPath = '/logbook';
|
||||
} else if (matchPath.startsWith('/profile') ||
|
||||
matchPath.startsWith('/settings') ||
|
||||
matchPath.startsWith('/more')) {
|
||||
@@ -107,7 +114,7 @@ class _MyAppState extends State<MyApp> {
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
redirect: (_, __) => '/dashboard',
|
||||
redirect: (context, state) => '/dashboard',
|
||||
),
|
||||
ShellRoute(
|
||||
navigatorKey: _shellNavigatorKey,
|
||||
@@ -119,7 +126,7 @@ class _MyAppState extends State<MyApp> {
|
||||
),
|
||||
GoRoute(
|
||||
path: '/logbook',
|
||||
builder: (context, state) => const LogbookPage(),
|
||||
redirect: (context, state) => '/logbook/entries',
|
||||
),
|
||||
GoRoute(
|
||||
path: '/logbook/entries',
|
||||
@@ -132,12 +139,11 @@ class _MyAppState extends State<MyApp> {
|
||||
),
|
||||
GoRoute(
|
||||
path: '/trips',
|
||||
builder: (context, state) =>
|
||||
const LogbookPage(initialTab: LogbookTab.trips),
|
||||
redirect: (context, state) => '/logbook/trips',
|
||||
),
|
||||
GoRoute(
|
||||
path: '/legs',
|
||||
builder: (context, state) => const LogbookPage(),
|
||||
redirect: (context, state) => '/logbook/entries',
|
||||
),
|
||||
GoRoute(
|
||||
path: '/traction',
|
||||
@@ -254,14 +260,14 @@ class MyHomePage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
List<String> get contentPages => _contentPages;
|
||||
List<String> get tabDestinations => _defaultTabDestinations;
|
||||
|
||||
Future<void> _onItemTapped(int index, int currentIndex) async {
|
||||
if (index < 0 || index >= contentPages.length) {
|
||||
if (index < 0 || index >= tabDestinations.length) {
|
||||
return;
|
||||
}
|
||||
final currentPath = GoRouterState.of(context).uri.path;
|
||||
final targetPath = contentPages[index];
|
||||
final targetPath = tabDestinations[index];
|
||||
final alreadyAtTarget =
|
||||
currentPath == targetPath || currentPath.startsWith('$targetPath/');
|
||||
if (index == currentIndex && alreadyAtTarget) return;
|
||||
@@ -272,9 +278,9 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
});
|
||||
}
|
||||
|
||||
final List<int> _history = [];
|
||||
final List<String> _history = [];
|
||||
int _historyPosition = -1;
|
||||
final List<int> _forwardHistory = [];
|
||||
final List<String> _forwardHistory = [];
|
||||
bool _suppressRecord = false;
|
||||
|
||||
bool _fetched = false;
|
||||
@@ -323,7 +329,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
Widget build(BuildContext context) {
|
||||
final uri = GoRouterState.of(context).uri;
|
||||
final pageIndex = tabIndexForPath(uri.path);
|
||||
_syncHistory(pageIndex);
|
||||
_syncHistory(uri.path);
|
||||
if (pageIndex != _addTabIndex) {
|
||||
NavigationGuard.unregister();
|
||||
}
|
||||
@@ -544,24 +550,21 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
|
||||
Future<void> _openNotificationsPanel(BuildContext context) async {
|
||||
final data = context.read<DataService>();
|
||||
final isWide = MediaQuery.sizeOf(context).width >= 900;
|
||||
final sheetHeight = MediaQuery.sizeOf(context).height * 0.9;
|
||||
try {
|
||||
await data.fetchNotifications();
|
||||
} catch (_) {
|
||||
// Already logged inside data service.
|
||||
}
|
||||
if (!mounted) return;
|
||||
final isWide = MediaQuery.of(context).size.width >= 900;
|
||||
|
||||
final panelBuilder = (BuildContext ctx) {
|
||||
return _buildNotificationsContent(ctx, isWide);
|
||||
};
|
||||
if (!context.mounted) return;
|
||||
|
||||
if (isWide) {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (dialogCtx) => Dialog(
|
||||
insetPadding: const EdgeInsets.all(16),
|
||||
child: panelBuilder(dialogCtx),
|
||||
child: _buildNotificationsContent(dialogCtx, isWide),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
@@ -569,11 +572,10 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (sheetCtx) {
|
||||
final height = MediaQuery.of(context).size.height * 0.9;
|
||||
return SizedBox(
|
||||
height: height,
|
||||
height: sheetHeight,
|
||||
child: SafeArea(
|
||||
child: panelBuilder(sheetCtx),
|
||||
child: _buildNotificationsContent(sheetCtx, isWide),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -606,7 +608,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
height: listHeight,
|
||||
child: ListView.separated(
|
||||
itemCount: notifications.length,
|
||||
separatorBuilder: (_, __) => const SizedBox(height: 8),
|
||||
separatorBuilder: (_, index) => const SizedBox(height: 8),
|
||||
itemBuilder: (ctx, index) {
|
||||
final item = notifications[index];
|
||||
return Card(
|
||||
@@ -644,11 +646,18 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.copyWith(
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.color
|
||||
?.withOpacity(0.7),
|
||||
color: () {
|
||||
final baseColor = Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.color;
|
||||
if (baseColor == null) return null;
|
||||
final newAlpha =
|
||||
(baseColor.a * 0.7).clamp(0.0, 1.0);
|
||||
return baseColor.withValues(
|
||||
alpha: newAlpha,
|
||||
);
|
||||
}(),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -757,31 +766,32 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
);
|
||||
}
|
||||
|
||||
int get _currentPageIndex => tabIndexForPath(GoRouterState.of(context).uri.path);
|
||||
|
||||
Future<bool> _handleBackNavigation({
|
||||
bool allowExit = false,
|
||||
bool recordForward = false,
|
||||
}) async {
|
||||
final pageIndex = _currentPageIndex;
|
||||
final currentPath = GoRouterState.of(context).uri.path;
|
||||
final shellNav = _shellNavigatorKey.currentState;
|
||||
if (shellNav != null && shellNav.canPop()) {
|
||||
if (recordForward) _pushForward(currentPath);
|
||||
_alignHistoryAfterPop(currentPath);
|
||||
shellNav.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_historyPosition > 0) {
|
||||
if (recordForward) _pushForward(pageIndex);
|
||||
if (recordForward) _pushForward(currentPath);
|
||||
_historyPosition -= 1;
|
||||
_suppressRecord = true;
|
||||
context.go(contentPages[_history[_historyPosition]]);
|
||||
context.go(_history[_historyPosition]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pageIndex != 0) {
|
||||
if (recordForward) _pushForward(pageIndex);
|
||||
final homePath = tabDestinations.first;
|
||||
if (currentPath != homePath) {
|
||||
if (recordForward) _pushForward(currentPath);
|
||||
_suppressRecord = true;
|
||||
context.go(contentPages[0]);
|
||||
context.go(homePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -795,35 +805,48 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
|
||||
Future<bool> _handleForwardNavigation() async {
|
||||
if (_forwardHistory.isEmpty) return false;
|
||||
final nextTab = _forwardHistory.removeLast();
|
||||
final nextPath = _forwardHistory.removeLast();
|
||||
|
||||
// Move cursor forward, keeping history in sync.
|
||||
if (_historyPosition < _history.length - 1) {
|
||||
_historyPosition += 1;
|
||||
_history[_historyPosition] = nextTab;
|
||||
_history[_historyPosition] = nextPath;
|
||||
if (_historyPosition < _history.length - 1) {
|
||||
_history.removeRange(_historyPosition + 1, _history.length);
|
||||
}
|
||||
} else {
|
||||
_history.add(nextTab);
|
||||
_history.add(nextPath);
|
||||
_historyPosition = _history.length - 1;
|
||||
}
|
||||
|
||||
_suppressRecord = true;
|
||||
if (!mounted) return false;
|
||||
context.go(contentPages[nextTab]);
|
||||
context.go(nextPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
void _pushForward(int pageIndex) {
|
||||
if (_forwardHistory.isEmpty || _forwardHistory.last != pageIndex) {
|
||||
_forwardHistory.add(pageIndex);
|
||||
void _pushForward(String path) {
|
||||
if (_forwardHistory.isEmpty || _forwardHistory.last != path) {
|
||||
_forwardHistory.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
void _syncHistory(int pageIndex) {
|
||||
void _alignHistoryAfterPop(String currentPath) {
|
||||
if (_history.isEmpty) return;
|
||||
if (_historyPosition >= 0 &&
|
||||
_historyPosition < _history.length &&
|
||||
_history[_historyPosition] == currentPath) {
|
||||
if (_historyPosition > 0) {
|
||||
_historyPosition -= 1;
|
||||
}
|
||||
_history.removeRange(_historyPosition + 1, _history.length);
|
||||
_suppressRecord = true;
|
||||
}
|
||||
}
|
||||
|
||||
void _syncHistory(String path) {
|
||||
if (_history.isEmpty) {
|
||||
_history.add(pageIndex);
|
||||
_history.add(path);
|
||||
_historyPosition = 0;
|
||||
return;
|
||||
}
|
||||
@@ -833,13 +856,13 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
}
|
||||
if (_historyPosition >= 0 &&
|
||||
_historyPosition < _history.length &&
|
||||
_history[_historyPosition] == pageIndex) {
|
||||
_history[_historyPosition] == path) {
|
||||
return;
|
||||
}
|
||||
if (_historyPosition < _history.length - 1) {
|
||||
_history.removeRange(_historyPosition + 1, _history.length);
|
||||
}
|
||||
_history.add(pageIndex);
|
||||
_history.add(path);
|
||||
_historyPosition = _history.length - 1;
|
||||
_forwardHistory.clear();
|
||||
}
|
||||
@@ -847,6 +870,6 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
void _navigateToIndex(int index) {
|
||||
_suppressRecord = false;
|
||||
_forwardHistory.clear();
|
||||
context.go(contentPages[index]);
|
||||
context.go(tabDestinations[index]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user