Keyboard Shortcuts

j / kScroll down / up
ggScroll to top
GScroll to bottom
K / /Open search
?Show this help
EscClose search / help
n / NNext / previous section
hGo to landing
dGo to docs
:Command mode — type section name

Press ? or Esc to close

Architecture

Bottom Navigation

Five persistent tabs. Each tab is an independent navigation stack kept alive by StatefulShellRoute.indexedStack, so switching tabs preserves scroll position and local state.

The five tabs

TabBranch route
HomehomeRoute
FeedfeedRoute
DiscoverdiscoverRoute
ActivityactivityRoute
ProfileprofileRoute

Tab definition

Each tab is described by AppBottomNavItem — a route, a label key, and an icon pair. Adding a tab means adding an enum value and a branch; nothing else changes.

lib/config/ui/bottom_nav_item.dart
enum AppBottomNavItem {
  home(AppRoutes.home, TranslationKeys.navigationHome, AppIcons.home, AppIcons.homeFilled),
  feed(AppRoutes.feed, TranslationKeys.navigationFeed, AppIcons.compass, AppIcons.compassFilled),
  discover(AppRoutes.discover, TranslationKeys.navigationDiscover, AppIcons.sparkles, AppIcons.sparklesFilled),
  activity(AppRoutes.activity, TranslationKeys.navigationActivity, AppIcons.bell, AppIcons.bellFilled),
  profile(AppRoutes.profile, TranslationKeys.navigationProfile, AppIcons.user, AppIcons.userFilled);

  const AppBottomNavItem(this.route, this.label, this.icon, this.activeIcon);
  final String route;
  final TranslationKeys label;
  final Widget icon;
  final Widget activeIcon;
}

Unread badge

The notifications tab shows an unread count pulled from NotificationsCubit via context.select. The badge updates reactively without rebuilding the whole bar.

lib/config/ui/bottom_nav_bar.dart
final unread = context.select<NotificationsCubit, int>(
  (c) => c.state.unreadCount,
);

Tab switching

goBranch(index) is called on tap. Tapping the active tab is a no-op, so it does not reset the stack.

lib/app/app_router.dart
void _onTabTapped(int index) {
  if (index == widget.navigationShell.currentIndex) return;
  widget.navigationShell.goBranch(index);
}
sam's arch — A Pragmatic Flutter Architecture