import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:inou_app/design/inou_theme.dart'; import 'package:inou_app/design/inou_text.dart'; import 'package:inou_app/main.dart'; import 'package:inou_app/core/locale_provider.dart'; /// Navigation item for header class NavItem { final String label; final String route; final bool isExternal; const NavItem({ required this.label, required this.route, this.isExternal = false, }); } /// inou Header - responsive, matches web design with language switcher class InouHeader extends StatelessWidget { final VoidCallback? onLogoTap; final List navItems; final String? currentRoute; final VoidCallback? onLoginTap; final VoidCallback? onSignupTap; final bool isLoggedIn; final String? userName; final VoidCallback? onProfileTap; final VoidCallback? onLogoutTap; const InouHeader({ super.key, this.onLogoTap, this.navItems = const [], this.currentRoute, this.onLoginTap, this.onSignupTap, this.isLoggedIn = false, this.userName, this.onProfileTap, this.onLogoutTap, }); static const defaultNavItems = [ NavItem(label: 'Dossiers', route: '/dossiers'), NavItem(label: 'Privacy', route: '/privacy'), NavItem(label: 'Connect', route: '/connect'), NavItem(label: 'Invite a friend', route: '/invite'), NavItem(label: 'Demo', route: '/demo'), ]; @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; final isMobile = screenWidth < 768; return Container( width: double.infinity, decoration: BoxDecoration( color: InouTheme.bg, border: Border( bottom: BorderSide(color: InouTheme.border, width: 1), ), ), child: SafeArea( bottom: false, child: Center( child: Container( constraints: const BoxConstraints(maxWidth: InouTheme.maxWidth), padding: EdgeInsets.symmetric( horizontal: isMobile ? 16 : 24, vertical: 12, ), child: isMobile ? _buildMobileHeader(context) : _buildDesktopHeader(context), ), ), ), ); } Widget _buildDesktopHeader(BuildContext context) { return Row( children: [ // Logo _buildLogo(context), const SizedBox(width: 48), // Navigation Expanded( child: Row( children: [ for (final item in navItems.isEmpty ? defaultNavItems : navItems) _buildNavItem(context, item), ], ), ), // Language switcher _LanguageSwitcher(), const SizedBox(width: 16), // Auth buttons _buildAuthSection(context), ], ); } Widget _buildMobileHeader(BuildContext context) { return Row( children: [ _buildLogo(context), const Spacer(), _LanguageSwitcher(), const SizedBox(width: 8), _buildMobileMenuButton(context), ], ); } Widget _buildLogo(BuildContext context) { final l10n = AppLocalizations.of(context); return GestureDetector( onTap: onLogoTap, child: Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, children: [ Text( 'inou', style: InouText.logo.copyWith( color: InouTheme.accent, ), ), Text( 'health', style: InouText.logoLight.copyWith( color: InouTheme.textMuted, ), ), const SizedBox(width: 12), Text( l10n?.appTagline ?? 'ai answers for you', style: InouText.logoTagline, ), ], ), ); } Widget _buildNavItem(BuildContext context, NavItem item) { final isActive = currentRoute == item.route; return Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: InkWell( onTap: () => _navigateTo(context, item), borderRadius: BorderRadius.circular(4), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), child: Text( item.label, style: isActive ? InouText.navActive : InouText.nav, ), ), ), ); } Widget _buildAuthSection(BuildContext context) { final l10n = AppLocalizations.of(context); if (isLoggedIn) { return Row( mainAxisSize: MainAxisSize.min, children: [ InkWell( onTap: onProfileTap, borderRadius: BorderRadius.circular(4), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Row( children: [ CircleAvatar( radius: 14, backgroundColor: InouTheme.accentLight, child: Text( (userName ?? 'U')[0].toUpperCase(), style: InouText.bodySmall.copyWith( color: InouTheme.accent, fontWeight: FontWeight.w600, ), ), ), const SizedBox(width: 8), Text( userName ?? 'Account', style: InouText.body, ), ], ), ), ), ], ); } return Row( mainAxisSize: MainAxisSize.min, children: [ TextButton( onPressed: onLoginTap, child: Text( l10n?.signIn ?? 'Log in', style: InouText.nav, ), ), const SizedBox(width: 8), ElevatedButton( onPressed: onSignupTap, style: ElevatedButton.styleFrom( backgroundColor: InouTheme.accent, foregroundColor: Colors.white, elevation: 0, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), shape: RoundedRectangleBorder( borderRadius: InouTheme.borderRadiusMd, ), ), child: Text(l10n?.getStarted ?? 'Get started', style: InouText.button.copyWith(color: Colors.white)), ), ], ); } Widget _buildMobileMenuButton(BuildContext context) { return IconButton( icon: const Icon(Icons.menu, color: InouTheme.text), onPressed: () => _showMobileMenu(context), ); } void _showMobileMenu(BuildContext context) { final l10n = AppLocalizations.of(context); showModalBottomSheet( context: context, backgroundColor: InouTheme.bgCard, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) => SafeArea( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ for (final item in navItems.isEmpty ? defaultNavItems : navItems) ListTile( title: Text(item.label, style: InouText.body), trailing: item.isExternal ? Icon(Icons.open_in_new, size: 18, color: InouTheme.textMuted) : null, onTap: () { Navigator.pop(context); _navigateTo(context, item); }, ), const Divider(height: 32), if (!isLoggedIn) ...[ OutlinedButton( onPressed: () { Navigator.pop(context); onLoginTap?.call(); }, style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), ), child: Text(l10n?.signIn ?? 'Log in', style: InouText.button), ), const SizedBox(height: 12), ElevatedButton( onPressed: () { Navigator.pop(context); onSignupTap?.call(); }, style: ElevatedButton.styleFrom( backgroundColor: InouTheme.accent, padding: const EdgeInsets.symmetric(vertical: 16), ), child: Text(l10n?.getStarted ?? 'Get started', style: InouText.button.copyWith(color: Colors.white)), ), ] else ...[ ListTile( leading: CircleAvatar( backgroundColor: InouTheme.accentLight, child: Text( (userName ?? 'U')[0].toUpperCase(), style: InouText.bodySmall.copyWith(color: InouTheme.accent), ), ), title: Text(userName ?? 'Account', style: InouText.body), onTap: () { Navigator.pop(context); onProfileTap?.call(); }, ), ListTile( leading: const Icon(Icons.logout), title: Text('Log out', style: InouText.body), onTap: () { Navigator.pop(context); onLogoutTap?.call(); }, ), ], ], ), ), ), ); } void _navigateTo(BuildContext context, NavItem item) { if (item.isExternal) { // Handle external links (url_launcher would be needed) return; } Navigator.pushNamed(context, item.route); } } /// Language switcher dropdown matching Go version .lang-menu class _LanguageSwitcher extends StatelessWidget { @override Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: localeNotifier, builder: (context, locale, _) { final currentCode = LocaleProvider.localeCodes[locale.languageCode] ?? 'EN'; return PopupMenuButton( offset: const Offset(0, 40), tooltip: 'Change language', shape: RoundedRectangleBorder( borderRadius: InouTheme.borderRadiusMd, ), color: InouTheme.bgCard, child: Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( border: Border.all(color: InouTheme.border), borderRadius: InouTheme.borderRadiusSm, ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Text( currentCode, style: InouText.bodySmall.copyWith( color: InouTheme.textMuted, fontWeight: FontWeight.w500, ), ), const SizedBox(width: 4), Icon( Icons.keyboard_arrow_down, size: 16, color: InouTheme.textMuted, ), ], ), ), onSelected: (selectedLocale) { InouApp.setLocale(context, selectedLocale); }, itemBuilder: (context) => [ for (final supportedLocale in LocaleProvider.supportedLocales) PopupMenuItem( value: supportedLocale, child: Row( children: [ Text( LocaleProvider.localeNames[supportedLocale.languageCode] ?? '', style: InouText.bodySmall.copyWith( color: locale.languageCode == supportedLocale.languageCode ? InouTheme.accent : InouTheme.text, fontWeight: locale.languageCode == supportedLocale.languageCode ? FontWeight.w600 : FontWeight.w400, ), ), if (locale.languageCode == supportedLocale.languageCode) ...[ const SizedBox(width: 8), Icon(Icons.check, size: 16, color: InouTheme.accent), ], ], ), ), ], ); }, ); } }