From 1376802f76e359902688db624f059830fd86751b Mon Sep 17 00:00:00 2001 From: Patrick Britton Date: Fri, 6 Feb 2026 15:49:46 -0600 Subject: [PATCH] Threads-style nav: move Search and Activity into bottom nav tabs, remove duplicate nav from NotificationsScreen --- sojorn_app/lib/routes/app_routes.dart | 16 +- sojorn_app/lib/screens/home/home_shell.dart | 74 ++++--- .../notifications/notifications_screen.dart | 181 +++++------------- 3 files changed, 90 insertions(+), 181 deletions(-) diff --git a/sojorn_app/lib/routes/app_routes.dart b/sojorn_app/lib/routes/app_routes.dart index 7c2837d..3aff63e 100644 --- a/sojorn_app/lib/routes/app_routes.dart +++ b/sojorn_app/lib/routes/app_routes.dart @@ -21,6 +21,7 @@ import '../screens/discover/discover_screen.dart'; import '../screens/secure_chat/secure_chat_full_screen.dart'; import '../screens/secure_chat/secure_chat_loader_screen.dart'; import '../screens/post/threaded_conversation_screen.dart'; +import '../screens/notifications/notifications_screen.dart'; /// App routing config (GoRouter). class AppRoutes { @@ -88,6 +89,7 @@ class AppRoutes { authenticatedChild: HomeShell(navigationShell: navigationShell), ), branches: [ + // Tab 0: Home StatefulShellBranch( routes: [ GoRoute( @@ -96,25 +98,25 @@ class AppRoutes { ), ], ), + // Tab 1: Search / Discover StatefulShellBranch( routes: [ GoRoute( - path: quips, - builder: (_, state) => QuipsFeedScreen( - initialPostId: state.uri.queryParameters['postId'], - ), + path: '/discover', + builder: (_, __) => const DiscoverScreen(), ), - ], ), + // Tab 2: Activity / Notifications StatefulShellBranch( routes: [ GoRoute( - path: '/beacon', - builder: (_, __) => const BeaconScreen(), + path: '/activity', + builder: (_, __) => const NotificationsScreen(), ), ], ), + // Tab 3: Profile StatefulShellBranch( routes: [ GoRoute( diff --git a/sojorn_app/lib/screens/home/home_shell.dart b/sojorn_app/lib/screens/home/home_shell.dart index e7030f4..baf107f 100644 --- a/sojorn_app/lib/screens/home/home_shell.dart +++ b/sojorn_app/lib/screens/home/home_shell.dart @@ -206,17 +206,14 @@ class _HomeShellState extends ConsumerState with WidgetsBindingObserv label: 'Home', ), _buildNavBarItem( - icon: Icons.play_circle_outline, - activeIcon: Icons.play_circle, + icon: Icons.search_outlined, + activeIcon: Icons.search, index: 1, - label: 'Quips', + label: 'Search', ), const SizedBox(width: 48), - _buildNavBarItem( - icon: Icons.sensors_outlined, - activeIcon: Icons.sensors, + _buildActivityNavItem( index: 2, - label: 'Beacon', ), _buildNavBarItem( icon: Icons.person_outline, @@ -253,17 +250,6 @@ class _HomeShellState extends ConsumerState with WidgetsBindingObserv ), ), actions: [ - IconButton( - icon: Icon(Icons.search, color: AppTheme.navyBlue), - tooltip: 'Discover', - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => const DiscoverScreen(), - ), - ); - }, - ), IconButton( icon: Consumer( builder: (context, ref, child) { @@ -286,27 +272,6 @@ class _HomeShellState extends ConsumerState with WidgetsBindingObserv ); }, ), - IconButton( - icon: Consumer( - builder: (context, ref, child) { - final badge = ref.watch(currentBadgeProvider); - return Badge( - label: Text(badge.notificationCount.toString()), - isLabelVisible: badge.notificationCount > 0, - backgroundColor: Colors.redAccent, - child: Icon(Icons.notifications_none, color: AppTheme.navyBlue), - ); - }, - ), - tooltip: 'Notifications', - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => const NotificationsScreen(), - ), - ); - }, - ), const SizedBox(width: 4), ], ); @@ -337,6 +302,37 @@ class _HomeShellState extends ConsumerState with WidgetsBindingObserv ), ); } + + Widget _buildActivityNavItem({required int index}) { + final isActive = widget.navigationShell.currentIndex == index; + return Expanded( + child: InkWell( + onTap: () => widget.navigationShell.goBranch( + index, + initialLocation: index == widget.navigationShell.currentIndex, + ), + child: Container( + height: double.infinity, + alignment: Alignment.center, + child: Consumer( + builder: (context, ref, child) { + final badge = ref.watch(currentBadgeProvider); + return Badge( + label: Text(badge.notificationCount.toString()), + isLabelVisible: badge.notificationCount > 0, + backgroundColor: Colors.redAccent, + child: Icon( + isActive ? Icons.favorite : Icons.favorite_border, + color: isActive ? AppTheme.navyBlue : Colors.grey, + size: 26, + ), + ); + }, + ), + ), + ), + ); + } } class _VerticalBorderProgressPainter extends CustomPainter { diff --git a/sojorn_app/lib/screens/notifications/notifications_screen.dart b/sojorn_app/lib/screens/notifications/notifications_screen.dart index 9fe45bd..f1c17d7 100644 --- a/sojorn_app/lib/screens/notifications/notifications_screen.dart +++ b/sojorn_app/lib/screens/notifications/notifications_screen.dart @@ -6,13 +6,9 @@ import 'package:timeago/timeago.dart' as timeago; import '../../models/notification.dart'; import '../../providers/api_provider.dart'; import '../../theme/app_theme.dart'; -import '../../widgets/app_scaffold.dart'; import '../../widgets/media/signed_media_image.dart'; import '../profile/viewable_profile_screen.dart'; import '../post/post_detail_screen.dart'; -import '../search/search_screen.dart'; -import '../discover/discover_screen.dart'; -import '../secure_chat/secure_chat_full_screen.dart'; import 'package:go_router/go_router.dart'; import '../../services/notification_service.dart'; @@ -352,66 +348,59 @@ class _NotificationsScreenState extends ConsumerState { } } - void _navigateHome() { - Navigator.of(context).pop(); - } - - void _navigateSearch() { - Navigator.of(context).pushReplacement( - MaterialPageRoute(builder: (_) => const DiscoverScreen()), - ); - } - - void _navigateChat() { - Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: (_) => const SecureChatFullScreen(), - fullscreenDialog: true, - ), - ); - } - @override Widget build(BuildContext context) { final canArchiveAll = _activeTabIndex == 0 && _notifications.isNotEmpty; return DefaultTabController( length: 2, - child: AppScaffold( - title: 'Activity', - leading: const SizedBox.shrink(), - actions: [ - if (canArchiveAll) - TextButton( - onPressed: _archiveAllNotifications, - child: Text( - 'Archive All', - style: AppTheme.textTheme.labelMedium?.copyWith( - color: AppTheme.egyptianBlue, - fontWeight: FontWeight.w600, + child: Column( + children: [ + // Tab bar + Archive All button + Material( + color: AppTheme.scaffoldBg, + child: Column( + children: [ + if (canArchiveAll) + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.only(right: 8, top: 4), + child: TextButton( + onPressed: _archiveAllNotifications, + child: Text( + 'Archive All', + style: AppTheme.textTheme.labelMedium?.copyWith( + color: AppTheme.egyptianBlue, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ), + TabBar( + onTap: (index) { + if (index != _activeTabIndex) { + setState(() { + _activeTabIndex = index; + }); + _loadNotifications(refresh: true); + } + }, + indicatorColor: AppTheme.egyptianBlue, + labelColor: AppTheme.egyptianBlue, + unselectedLabelColor: AppTheme.egyptianBlue.withOpacity(0.5), + tabs: const [ + Tab(text: 'Active'), + Tab(text: 'Archived'), + ], ), - ), + ], ), - ], - bottom: TabBar( - onTap: (index) { - if (index != _activeTabIndex) { - setState(() { - _activeTabIndex = index; - }); - _loadNotifications(refresh: true); - } - }, - indicatorColor: AppTheme.egyptianBlue, - labelColor: AppTheme.egyptianBlue, - unselectedLabelColor: AppTheme.egyptianBlue.withOpacity(0.5), - tabs: const [ - Tab(text: 'Active'), - Tab(text: 'Archived'), - ], - ), - bottomNavigationBar: _buildBottomNav(), - body: _error != null + ), + // Content + Expanded( + child: _error != null ? _ErrorState( message: _error!, onRetry: () => _loadNotifications(refresh: true), @@ -485,86 +474,8 @@ class _NotificationsScreenState extends ConsumerState { }, ), ), - ), - ); - } - - Widget _buildBottomNav() { - return Container( - decoration: BoxDecoration( - color: AppTheme.scaffoldBg, - border: Border( - top: BorderSide( - color: AppTheme.egyptianBlue.withOpacity(0.1), - width: 0.5, ), - ), - ), - child: SafeArea( - top: false, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildNavItem( - icon: Icons.home_outlined, - label: 'Home', - onTap: _navigateHome, - ), - _buildNavItem( - icon: Icons.search, - label: 'Discover', - onTap: _navigateSearch, - ), - _buildNavItem( - icon: Icons.notifications, - label: 'Activity', - isActive: true, - onTap: () {}, - ), - _buildNavItem( - icon: Icons.chat_bubble_outline, - label: 'Chat', - onTap: _navigateChat, - ), - ], - ), - ), - ), - ); - } - - Widget _buildNavItem({ - required IconData icon, - required String label, - required VoidCallback onTap, - bool isActive = false, - }) { - return InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(12), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - icon, - color: isActive ? AppTheme.navyBlue : Colors.grey, - size: 26, - ), - const SizedBox(height: 2), - Text( - label, - style: TextStyle( - fontSize: 10, - color: isActive ? AppTheme.navyBlue : Colors.grey, - fontWeight: isActive ? FontWeight.w600 : FontWeight.normal, - ), - ), - ], - ), + ], ), ); }