import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:go_router/go_router.dart'; import 'providers/app_state.dart'; import 'screens/home_screen.dart'; import 'screens/beans_screen.dart'; import 'screens/machines_screen.dart'; import 'screens/recipes_screen.dart'; import 'screens/journal_screen.dart'; import 'screens/settings_screen.dart'; import 'components/global_search.dart'; void main() { runApp(const CoffeeAtHomeApp()); } class CoffeeAtHomeApp extends StatelessWidget { const CoffeeAtHomeApp({super.key}); @override Widget build(BuildContext context) { return MultiProvider( providers: [ChangeNotifierProvider(create: (_) => AppState())], child: MaterialApp.router( title: 'Coffee at Home', theme: _buildTheme(), routerConfig: _router, ), ); } ThemeData _buildTheme() { return ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: const Color(0xFFD4A574), // Warm coffee brown brightness: Brightness.dark, ).copyWith( primary: const Color(0xFFD4A574), secondary: const Color(0xFF6F4E37), surface: const Color(0xFF2D2D2D), onPrimary: const Color(0xFF1A1A1A), onSecondary: const Color(0xFFFFFFFF), onSurface: const Color(0xFFF5F5DC), ), scaffoldBackgroundColor: const Color(0xFF1A1A1A), cardTheme: CardThemeData( color: const Color(0xFF2D2D2D), elevation: 4, shape: RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(12)), side: const BorderSide(color: Color(0xFF3A3A3A)), ), shadowColor: Colors.black.withValues(alpha: 0.4), ), appBarTheme: const AppBarTheme( backgroundColor: Color(0xFF2D2D2D), foregroundColor: Color(0xFFF5F5DC), elevation: 0, titleTextStyle: TextStyle( color: Color(0xFFF5F5DC), fontSize: 20, fontWeight: FontWeight.w500, ), surfaceTintColor: Colors.transparent, ), bottomNavigationBarTheme: const BottomNavigationBarThemeData( backgroundColor: Color(0xFF2D2D2D), selectedItemColor: Color(0xFFD4A574), unselectedItemColor: Color(0xFFD2B48C), type: BottomNavigationBarType.fixed, elevation: 3, ), floatingActionButtonTheme: const FloatingActionButtonThemeData( backgroundColor: Color(0xFFD4A574), foregroundColor: Color(0xFF1A1A1A), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFD4A574), foregroundColor: const Color(0xFF1A1A1A), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), textStyle: const TextStyle(fontWeight: FontWeight.w600), ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFFD4A574), side: const BorderSide(color: Color(0xFFD4A574)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ), textTheme: const TextTheme( headlineLarge: TextStyle( color: Color(0xFFF5F5DC), fontWeight: FontWeight.w600, ), headlineMedium: TextStyle( color: Color(0xFFF5F5DC), fontWeight: FontWeight.w600, ), headlineSmall: TextStyle( color: Color(0xFFF5F5DC), fontWeight: FontWeight.w500, ), titleLarge: TextStyle( color: Color(0xFFF5F5DC), fontWeight: FontWeight.w500, ), titleMedium: TextStyle( color: Color(0xFFF5F5DC), fontWeight: FontWeight.w500, ), titleSmall: TextStyle( color: Color(0xFFF5F5DC), fontWeight: FontWeight.w500, ), bodyLarge: TextStyle(color: Color(0xFFD2B48C)), bodyMedium: TextStyle(color: Color(0xFFD2B48C)), bodySmall: TextStyle(color: Color(0xFFD2B48C)), ), ); } } final GoRouter _router = GoRouter( routes: [ ShellRoute( builder: (context, state, child) { return MainScaffold(child: child); }, routes: [ GoRoute(path: '/', redirect: (_, __) => '/home'), GoRoute(path: '/home', builder: (context, state) => const HomeScreen()), GoRoute( path: '/beans', builder: (context, state) => const BeansScreen(), ), GoRoute( path: '/machines', builder: (context, state) => const MachinesScreen(), ), GoRoute( path: '/recipes', builder: (context, state) => const RecipesScreen(), ), GoRoute( path: '/journal', builder: (context, state) => const JournalScreen(), ), GoRoute( path: '/settings', builder: (context, state) => const SettingsScreen(), ), ], ), ], ); class MainScaffold extends StatefulWidget { final Widget child; const MainScaffold({super.key, required this.child}); @override State createState() => _MainScaffoldState(); } class _MainScaffoldState extends State { int _currentIndex = 0; bool _isSearchOpen = false; final List _routes = [ '/home', '/beans', '/machines', '/recipes', '/journal', '/settings', ]; void _onItemTapped(int index) { setState(() { _currentIndex = index; }); context.go(_routes[index]); } void _openSearch() { setState(() { _isSearchOpen = true; }); } void _closeSearch() { setState(() { _isSearchOpen = false; }); } void _onSearchResultSelected(SearchResult result) { switch (result.type) { case 'Bean': context.go('/beans'); break; case 'Machine': context.go('/machines'); break; case 'Recipe': context.go('/recipes'); break; case 'Journal': context.go('/journal'); break; } } @override Widget build(BuildContext context) { // Update current index based on current route final currentRoute = GoRouterState.of(context).uri.path; final routeIndex = _routes.indexOf(currentRoute); if (routeIndex != -1 && routeIndex != _currentIndex) { WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { _currentIndex = routeIndex; }); }); } return Scaffold( body: _isSearchOpen ? Stack( children: [ Column( children: [ // AppBar Container( decoration: const BoxDecoration( color: Color(0xFF2D2D2D), border: Border( bottom: BorderSide( color: Color(0xFF3A3A3A), width: 1, ), ), ), child: SafeArea( child: Container( height: 56, padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ const Expanded( child: Text( 'Coffee at Home', style: TextStyle( color: Color(0xFFF5F5DC), fontSize: 20, fontWeight: FontWeight.w500, ), ), ), IconButton( icon: const Icon( Icons.search, color: Color(0xFFF5F5DC), ), onPressed: _openSearch, ), ], ), ), ), ), // Body Expanded( child: LayoutBuilder( builder: (context, constraints) { return Container( width: double.infinity, constraints: BoxConstraints( maxWidth: constraints.maxWidth > 1200 ? 1200 : constraints.maxWidth, ), margin: EdgeInsets.symmetric( horizontal: constraints.maxWidth > 1200 ? (constraints.maxWidth - 1200) / 2 : 0, ), padding: const EdgeInsets.symmetric(vertical: 16), child: widget.child, ); }, ), ), // Bottom Navigation Container( decoration: const BoxDecoration( color: Color(0xFF2D2D2D), border: Border( top: BorderSide(color: Color(0xFF3A3A3A), width: 1), ), boxShadow: [ BoxShadow( color: Colors.black26, blurRadius: 8, offset: Offset(0, -2), ), ], ), child: SafeArea( child: SizedBox( height: 56, child: Row( children: [ _buildBottomNavItem(0, Icons.home, 'Home'), _buildBottomNavItem(1, Icons.coffee, 'Beans'), _buildBottomNavItem( 2, Icons.kitchen, 'Equipment', ), _buildBottomNavItem( 3, Icons.menu_book, 'Recipes', ), _buildBottomNavItem(4, Icons.book, 'Journal'), _buildBottomNavItem( 5, Icons.settings, 'Settings', ), ], ), ), ), ), ], ), GlobalSearchWidget( isOpen: _isSearchOpen, onClose: _closeSearch, onResultSelected: _onSearchResultSelected, ), ], ) : Column( children: [ // AppBar Container( decoration: const BoxDecoration( color: Color(0xFF2D2D2D), border: Border( bottom: BorderSide(color: Color(0xFF3A3A3A), width: 1), ), ), child: SafeArea( child: Container( height: 56, padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ const Expanded( child: Text( 'Coffee at Home', style: TextStyle( color: Color(0xFFF5F5DC), fontSize: 20, fontWeight: FontWeight.w500, ), ), ), IconButton( icon: const Icon( Icons.search, color: Color(0xFFF5F5DC), ), onPressed: _openSearch, ), ], ), ), ), ), // Body Expanded( child: LayoutBuilder( builder: (context, constraints) { return Container( width: double.infinity, constraints: BoxConstraints( maxWidth: constraints.maxWidth > 1200 ? 1200 : constraints.maxWidth, ), margin: EdgeInsets.symmetric( horizontal: constraints.maxWidth > 1200 ? (constraints.maxWidth - 1200) / 2 : 0, ), padding: const EdgeInsets.symmetric(vertical: 16), child: widget.child, ); }, ), ), // Bottom Navigation Container( decoration: const BoxDecoration( color: Color(0xFF2D2D2D), border: Border( top: BorderSide(color: Color(0xFF3A3A3A), width: 1), ), boxShadow: [ BoxShadow( color: Colors.black26, blurRadius: 8, offset: Offset(0, -2), ), ], ), child: SafeArea( child: SizedBox( height: 56, child: Row( children: [ _buildBottomNavItem(0, Icons.home, 'Home'), _buildBottomNavItem(1, Icons.coffee, 'Beans'), _buildBottomNavItem(2, Icons.kitchen, 'Equipment'), _buildBottomNavItem(3, Icons.menu_book, 'Recipes'), _buildBottomNavItem(4, Icons.book, 'Journal'), _buildBottomNavItem(5, Icons.settings, 'Settings'), ], ), ), ), ), ], ), ); } Widget _buildBottomNavItem(int index, IconData icon, String label) { final isSelected = _currentIndex == index; return Expanded( child: Material( color: Colors.transparent, child: InkWell( onTap: () => _onItemTapped(index), child: Container( padding: const EdgeInsets.symmetric(vertical: 6), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon( icon, color: isSelected ? const Color(0xFFD4A574) : const Color(0xFFD2B48C), size: 22, ), const SizedBox(height: 2), Text( label, style: TextStyle( color: isSelected ? const Color(0xFFD4A574) : const Color(0xFFD2B48C), fontSize: 11, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), ), ), ); } }