import 'package:flutter/material.dart'; import 'package:food_ai/l10n/app_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../home/home_provider.dart'; import '../scan/dish_result_screen.dart'; import 'recognition_service.dart'; /// Full-screen page showing all dish recognition jobs. class RecognitionHistoryScreen extends ConsumerWidget { const RecognitionHistoryScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context)!; final jobsState = ref.watch(allJobsProvider); return Scaffold( appBar: AppBar( title: Text(l10n.historyTitle), ), body: jobsState.when( loading: () => const Center(child: CircularProgressIndicator()), error: (recognitionError, _) => Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(l10n.historyLoadError), const SizedBox(height: 12), FilledButton( onPressed: () => ref.invalidate(allJobsProvider), child: Text(l10n.retry), ), ], ), ), data: (jobs) { if (jobs.isEmpty) { return Center(child: Text(l10n.noHistory)); } return ListView.separated( padding: const EdgeInsets.all(16), itemCount: jobs.length, separatorBuilder: (_, __) => const SizedBox(height: 8), itemBuilder: (context, index) => _HistoryJobTile(job: jobs[index]), ); }, ), ); } } class _HistoryJobTile extends ConsumerWidget { final DishJobSummary job; const _HistoryJobTile({required this.job}); @override Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context)!; final theme = Theme.of(context); final isDone = job.status == 'done'; final isFailed = job.status == 'failed'; final isProcessing = job.status == 'processing' || job.status == 'pending'; final IconData statusIcon; final Color statusColor; if (isDone) { statusIcon = Icons.check_circle_outline; statusColor = Colors.green; } else if (isFailed) { statusIcon = Icons.error_outline; statusColor = theme.colorScheme.error; } else { statusIcon = Icons.hourglass_top_outlined; statusColor = theme.colorScheme.primary; } final dishName = job.result?.candidates.isNotEmpty == true ? job.result!.best.dishName : null; final String titleText; if (isDone) { titleText = dishName ?? l10n.dishRecognized; } else if (isProcessing) { titleText = l10n.recognizing; } else { titleText = l10n.recognitionError; } final contextParts = [ if (job.targetMealType != null) job.targetMealType!, if (job.targetDate != null) job.targetDate!, ]; return Card( child: ListTile( leading: Icon(statusIcon, color: statusColor), title: Text(titleText, style: theme.textTheme.bodyMedium), subtitle: contextParts.isNotEmpty ? Text( contextParts.join(' ยท '), style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ) : null, onTap: isDone && job.result != null ? () { showModalBottomSheet( context: context, isScrollControlled: true, useSafeArea: true, builder: (sheetContext) => DishResultSheet( dish: job.result!, preselectedMealType: job.targetMealType, jobId: job.id, targetDate: job.targetDate, createdAt: job.createdAt, onAdded: () => Navigator.pop(sheetContext), ), ); } : null, ), ); } }