import 'package:flutter/material.dart'; import '../services/database_helper.dart'; import '../services/app_strings.dart'; import '../theme/theme_controller.dart'; import '../theme/locale_controller.dart'; import '../widgets/brand_mark.dart'; import 'analysis_screen.dart'; import 'live_analysis_screen.dart'; import 'static_capture_screen.dart'; import 'history_screen.dart'; import 'manual_screen.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { int? _totalScans; @override void initState() { super.initState(); _loadStats(); } Future _loadStats() async { final records = await DatabaseHelper().getAllRecords(); if (mounted) setState(() => _totalScans = records.length); } @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return ValueListenableBuilder( valueListenable: LocaleController.localeCode, builder: (context, _, _) { return Scaffold( body: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const BrandMark(size: 44), const SizedBox(width: 12), Expanded( child: Text( AppStrings.t('app_title'), style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: colorScheme.onSurface, ), ), ), IconButton( icon: Icon(Icons.help_outline, color: colorScheme.onSurface), tooltip: AppStrings.t('manual_title'), onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (context) => const ManualScreen()), ), ), IconButton( icon: Icon(Icons.settings_outlined, color: colorScheme.onSurface), tooltip: AppStrings.t('settings_label'), onPressed: () => _showSettingsSheet(context), ), ], ), const SizedBox(height: 20), _buildStatCard(context, colorScheme), const SizedBox(height: 24), GridView.count( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), crossAxisCount: 2, mainAxisSpacing: 16, crossAxisSpacing: 16, childAspectRatio: 0.95, children: [ _buildTile( context, title: AppStrings.t('analyze_gallery_title'), subtitle: AppStrings.t('analyze_gallery_subtitle'), icon: Icons.photo_library, background: colorScheme.primary, foreground: colorScheme.onPrimary, onTap: () => Navigator.push( context, MaterialPageRoute(builder: (context) => const AnalysisScreen()), ), ), _buildTile( context, title: AppStrings.t('snap_analyze_title'), subtitle: AppStrings.t('snap_analyze_subtitle'), icon: Icons.camera_alt, background: colorScheme.secondary, foreground: colorScheme.onSecondary, onTap: () => Navigator.push( context, MaterialPageRoute(builder: (context) => const StaticCaptureScreen()), ), ), _buildTile( context, title: AppStrings.t('live_inference_title'), subtitle: AppStrings.t('live_inference_subtitle'), icon: Icons.camera, background: colorScheme.primaryContainer, foreground: colorScheme.onPrimaryContainer, onTap: () => Navigator.push( context, MaterialPageRoute(builder: (context) => const LiveAnalysisScreen()), ), ), _buildTile( context, title: AppStrings.t('history_vault_title'), subtitle: AppStrings.t('history_vault_subtitle'), icon: Icons.history, background: colorScheme.surfaceContainerHighest, foreground: colorScheme.onSurface, bordered: true, onTap: () => Navigator.push( context, MaterialPageRoute(builder: (context) => const HistoryScreen()), ), ), ], ), ], ), ), ), ); }, ); } Future _showSettingsSheet(BuildContext context) async { await showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (sheetContext) { return SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.fromLTRB(20, 20, 20, 8), child: Align( alignment: Alignment.centerLeft, child: Text(AppStrings.t('settings_label'), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), ), ), ValueListenableBuilder( valueListenable: ThemeController.themeMode, builder: (context, mode, _) { return ListTile( leading: Icon(_themeModeIcon(mode)), title: Text(AppStrings.t('theme_label')), subtitle: Text(_themeModeLabel(mode)), trailing: const Icon(Icons.chevron_right), onTap: () { Navigator.pop(sheetContext); _showThemePicker(context, mode); }, ); }, ), ValueListenableBuilder( valueListenable: LocaleController.localeCode, builder: (context, code, _) { return ListTile( leading: const Icon(Icons.language), title: Text(AppStrings.t('language_label')), subtitle: Text(_languageLabel(code)), trailing: const Icon(Icons.chevron_right), onTap: () { Navigator.pop(sheetContext); _showLanguagePicker(context); }, ); }, ), const SizedBox(height: 8), ], ), ); }, ); } String _themeModeLabel(ThemeMode mode) { switch (mode) { case ThemeMode.light: return AppStrings.t('theme_light'); case ThemeMode.dark: return AppStrings.t('theme_dark'); case ThemeMode.system: return AppStrings.t('theme_system'); } } String _languageLabel(String code) { switch (code) { case 'ms': return "Bahasa Melayu"; case 'zh': return "中文"; default: return "English"; } } IconData _themeModeIcon(ThemeMode mode) { switch (mode) { case ThemeMode.light: return Icons.light_mode; case ThemeMode.dark: return Icons.dark_mode; case ThemeMode.system: return Icons.brightness_auto; } } Future _showThemePicker(BuildContext context, ThemeMode current) async { await showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (sheetContext) { return SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.fromLTRB(20, 20, 20, 8), child: Align( alignment: Alignment.centerLeft, child: Text(AppStrings.t('theme_label'), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), ), ), _themeOptionTile(sheetContext, AppStrings.t('theme_light'), Icons.light_mode, ThemeMode.light, current), _themeOptionTile(sheetContext, AppStrings.t('theme_dark'), Icons.dark_mode, ThemeMode.dark, current), _themeOptionTile(sheetContext, AppStrings.t('theme_system'), Icons.brightness_auto, ThemeMode.system, current), const SizedBox(height: 8), ], ), ); }, ); } Widget _themeOptionTile(BuildContext context, String label, IconData icon, ThemeMode mode, ThemeMode current) { final selected = mode == current; return ListTile( leading: Icon(icon), title: Text(label), trailing: selected ? const Icon(Icons.check) : null, onTap: () { ThemeController.setThemeMode(mode); Navigator.pop(context); }, ); } Future _showLanguagePicker(BuildContext context) async { final current = LocaleController.localeCode.value; await showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (sheetContext) { return SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.fromLTRB(20, 20, 20, 8), child: Align( alignment: Alignment.centerLeft, child: Text(AppStrings.t('language_label'), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), ), ), _languageOptionTile(sheetContext, "English", "en", current), _languageOptionTile(sheetContext, "Bahasa Melayu", "ms", current), _languageOptionTile(sheetContext, "中文", "zh", current), const SizedBox(height: 8), ], ), ); }, ); } Widget _languageOptionTile(BuildContext context, String label, String code, String current) { final selected = code == current; return ListTile( title: Text(label), trailing: selected ? const Icon(Icons.check) : null, onTap: () { LocaleController.setLocale(code); Navigator.pop(context); }, ); } Widget _buildStatCard(BuildContext context, ColorScheme colorScheme) { return InkWell( borderRadius: BorderRadius.circular(16), onTap: () => Navigator.push( context, MaterialPageRoute(builder: (context) => const HistoryScreen()), ), child: Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(16), border: Border.all(color: colorScheme.primary.withValues(alpha: 0.15)), ), child: Row( children: [ Icon(Icons.analytics_outlined, color: colorScheme.primary, size: 28), const SizedBox(width: 12), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _totalScans == null ? '—' : '$_totalScans', style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: colorScheme.onSurface), ), Text( AppStrings.t('total_scans'), style: TextStyle(fontSize: 13, color: colorScheme.onSurface.withValues(alpha: 0.6)), ), ], ), const Spacer(), Icon(Icons.chevron_right, color: colorScheme.onSurface.withValues(alpha: 0.4)), ], ), ), ); } Widget _buildTile( BuildContext context, { required String title, required String subtitle, required IconData icon, required Color background, required Color foreground, required VoidCallback onTap, bool bordered = false, }) { return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: background, borderRadius: BorderRadius.circular(20), border: bordered ? Border.all(color: foreground.withValues(alpha: 0.15)) : null, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon(icon, color: foreground, size: 32), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: foreground), ), const SizedBox(height: 4), Text( subtitle, style: TextStyle(fontSize: 12, color: foreground.withValues(alpha: 0.85)), ), ], ), ], ), ), ); } }