diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2c2d262..09f20e5 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -114,6 +114,6 @@ SPEC CHECKSUMS: wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 workmanager: 01be2de7f184bd15de93a1812936a2b7f42ef07e -PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e +PODFILE CHECKSUM: eacb6976ee55d09dd7976888367ed4eee5f3a1bd COCOAPODS: 1.16.2 diff --git a/lib/core/router/app_shell.dart b/lib/core/router/app_shell.dart index ce09770..10ae864 100644 --- a/lib/core/router/app_shell.dart +++ b/lib/core/router/app_shell.dart @@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:lazurite/features/auth/bloc/auth_bloc.dart'; import 'package:lazurite/features/notifications/cubit/unread_count_cubit.dart'; +import 'package:provider/provider.dart'; class AppShellScope extends InheritedWidget { const AppShellScope({super.key, required super.child, required this.openMenu}); @@ -53,9 +54,66 @@ class _AppShellState extends State { key: _scaffoldKey, drawer: _AppMenu(navigationShell: widget.navigationShell, rootContext: context), body: widget.navigationShell, + bottomNavigationBar: NavigationBar( + height: 50, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest, + selectedIndex: widget.navigationShell.currentIndex, + onDestinationSelected: (index) { + widget.navigationShell.goBranch(index, initialLocation: index == widget.navigationShell.currentIndex); + }, + indicatorShape: RoundedSuperellipseBorder(borderRadius: BorderRadius.circular(10)), + labelBehavior: NavigationDestinationLabelBehavior.alwaysHide, + destinations: _destinations, + ), ), ); } + + List get _destinations => [ + const NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: 'Home'), + const NavigationDestination(icon: Icon(Icons.search_outlined), selectedIcon: Icon(Icons.search), label: 'Search'), + const NavigationDestination( + icon: _NotificationDestinationIcon(selected: false), + selectedIcon: _NotificationDestinationIcon(selected: true), + label: 'Notifications', + ), + const NavigationDestination(icon: Icon(Icons.person_outline), selectedIcon: Icon(Icons.person), label: 'Profile'), + const NavigationDestination( + icon: Icon(Icons.chat_bubble_outline), + selectedIcon: Icon(Icons.chat_bubble), + label: 'Messages', + ), + const NavigationDestination( + icon: Icon(Icons.settings_outlined), + selectedIcon: Icon(Icons.settings), + label: 'Settings', + ), + ]; +} + +class _NotificationDestinationIcon extends StatelessWidget { + const _NotificationDestinationIcon({required this.selected}); + + final bool selected; + + @override + Widget build(BuildContext context) { + final unreadCountCubit = Provider.of(context, listen: false); + if (unreadCountCubit == null) { + return Icon(selected ? Icons.notifications : Icons.notifications_outlined); + } + + return BlocBuilder( + bloc: unreadCountCubit, + builder: (context, state) { + return Badge( + isLabelVisible: state.hasUnread, + label: Text(state.count > 99 ? '99+' : state.count.toString(), style: const TextStyle(fontSize: 10)), + child: Icon(selected ? Icons.notifications : Icons.notifications_outlined), + ); + }, + ); + } } class _AppMenu extends StatelessWidget { diff --git a/pubspec.lock b/pubspec.lock index d9795cf..b142b9e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1017,7 +1017,7 @@ packages: source: hosted version: "1.5.2" provider: - dependency: transitive + dependency: "direct main" description: name: provider sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" diff --git a/pubspec.yaml b/pubspec.yaml index 123b3b0..8bd2176 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,7 @@ dependencies: dio: ^5.9.2 gal: ^2.3.2 permission_handler: ^12.0.1 + provider: ^6.1.5+1 dev_dependencies: flutter_test: diff --git a/test/core/router/app_router_test.dart b/test/core/router/app_router_test.dart index 9afc80c..791d0f2 100644 --- a/test/core/router/app_router_test.dart +++ b/test/core/router/app_router_test.dart @@ -156,7 +156,7 @@ void main() { await tester.scrollUntilVisible(find.text('Log Out'), 200, scrollable: find.byType(Scrollable).last); expect(find.text('Log Out'), findsOneWidget); - await tester.tap(find.text('Profile')); + await tester.tap(find.text('Profile').last); await tester.pumpAndSettle(); expect(find.text('River Tam'), findsOneWidget); @@ -164,7 +164,7 @@ void main() { await tester.tap(find.byTooltip('Open menu')); await tester.pumpAndSettle(); - await tester.tap(find.text('Settings')); + await tester.tap(find.text('Settings').last); await tester.pumpAndSettle(); expect(find.text('APPEARANCE'), findsOneWidget);