A shared three-dot menu providing access to global app features.
import 'package:cambridge_beer_festival/widgets/widgets.dart';
// Add to AppBar actions
AppBar(
title: Text('Screen Title'),
actions: [
buildOverflowMenu(context),
],
)The overflow menu provides access to:
- Browse Festivals - Opens festival selector bottom sheet
- Settings - Opens app settings bottom sheet
- About - Navigates to
/aboutscreen
✅ Include overflow menu on:
- Drinks screen (
DrinksScreen) - Favorites screen (
FavoritesScreen) - Any screen where users need access to festival switching or settings
❌ Do NOT include on:
- About screen (already in the app menu)
- Festival info screen (festival-specific, not global)
- Detail screens (drink/brewery/style) - use back navigation only
- Modal bottom sheets (use sheet close instead)
Pattern: Shared function (not a widget) that returns a PopupMenuButton
Widget buildOverflowMenu(BuildContext context)Accessibility:
- Main button has
Semanticslabel: "Menu" - Main button has tooltip: "Menu"
- Icons are decorative: wrapped in
ExcludeSemantics - Screen readers announce: "Browse Festivals", "Settings", "About" (icon is skipped)
Navigation:
- Festival browser and Settings open as modal bottom sheets
- About navigates to
/aboutroute usingcontext.go()
The overflow menu triggers these modal sheets:
showFestivalBrowser(context)- ShowsFestivalSelectorSheetshowSettingsSheet(context)- ShowsSettingsSheet
Both sheets are defined in lib/widgets/festival_menu_sheets.dart.
A navigation breadcrumb bar for detail screens.
import 'package:cambridge_beer_festival/widgets/widgets.dart';
import 'package:cambridge_beer_festival/utils/utils.dart';
// Breadcrumb for detail screens (back to festival home)
BreadcrumbBar(
backLabel: provider.currentFestival.id, // e.g., 'cbf2025'
contextLabel: 'Oakham Ales',
onBack: () {
if (context.canPop()) {
context.pop();
} else {
context.go(buildFestivalHome(festivalId));
}
},
onBackLabelTap: () => context.go(buildFestivalHome(festivalId)),
)Current pattern (festival-scoped routing):
backLabel: Festival ID (e.g.,cbf2025,cbf2024)contextLabel: Parent context (brewery name, style name, etc.)onBack: Pop if possible, otherwise navigate to festival homeonBackLabelTap: Always navigate to festival home when clicking the festival ID
- Large touch target: IconButton with 28px icon size (48x48 touch target)
- Semantic labels: Only the IconButton has
Semantics(not the entire row)- Label: "Back to {backLabel}"
- Marked as button for screen readers
- Tooltip: "Back to {backLabel}" on hover
- Text overflow handling: Single line with ellipsis for long text
- Supports text scaling: No overflow at 200% scale
- Semantics structure: Only the interactive IconButton is wrapped in
Semantics - Text widget: Non-interactive text is NOT marked as a button
- Single-line constraint:
maxLines: 1withTextOverflow.ellipsis - No variable shadowing: Uses
contextLabelproperty (notcontext) to avoid Flutter BuildContext confusion
- Material Design back arrow icon
- Context text with separator (/)
- Ellipsis for long text
- Consistent padding (8px)
Use BreadcrumbBar on:
- Drink detail screens (back to drinks list)
- Brewery detail screens (back to drinks list)
- Style detail screens (back to drinks list)
Do NOT use on:
- Home screen (no parent)
- Modal dialogs (use dialog close button)
- Settings screens (use AppBar back button)