import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/theme/app_theme.dart'; import '../../core/constants/app_constants.dart'; import '../../models/recommendation_model.dart'; import '../../services/firebase_service.dart'; import '../recommendation/recommendation_screen.dart'; import '../../services/ocr_service.dart'; import '../../services/dialog_service.dart'; class HistoryScreen extends ConsumerStatefulWidget { final int initialIndex; const HistoryScreen({super.key, this.initialIndex = 0}); @override ConsumerState createState() => _HistoryScreenState(); } class _HistoryScreenState extends ConsumerState with SingleTickerProviderStateMixin { late TabController _tabController; List _allRecommendations = []; List _favoriteRecommendations = []; bool _isLoading = true; String? _error; @override void initState() { super.initState(); _tabController = TabController( length: 2, vsync: this, initialIndex: widget.initialIndex, ); _loadRecommendations(); } @override void dispose() { _tabController.dispose(); super.dispose(); } Future _loadRecommendations() async { setState(() { _isLoading = true; _error = null; }); try { final firebaseService = FirebaseService(); final currentUser = firebaseService.currentUser; if (currentUser == null) { // For now, show empty state instead of error for unauthenticated users if (mounted) { setState(() { _allRecommendations = []; _favoriteRecommendations = []; _isLoading = false; }); } return; } // Try to get recommendations with simpler query to avoid index issues final recommendations = await firebaseService.getUserRecommendations( currentUser.uid, limit: 20, // Reduce limit to avoid performance issues ); if (mounted) { setState(() { // Hanya tampilkan riwayat yang sudah dipilih menunya _allRecommendations = recommendations.where((r) => r.selectedMenuName != null).toList(); _favoriteRecommendations = _allRecommendations .where((rec) => rec.isFavorite) .toList(); _isLoading = false; }); } } catch (e) { if (mounted) { setState(() { // Show more user-friendly error message _error = 'Tidak dapat memuat riwayat. Pastikan Anda sudah login dan memiliki koneksi internet.'; _isLoading = false; }); } } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppTheme.warmWhite, appBar: AppBar( title: const Text( 'Riwayat Rekomendasi', style: TextStyle( color: AppTheme.primaryBrown, fontWeight: FontWeight.bold, ), ), backgroundColor: AppTheme.warmWhite, elevation: 0, iconTheme: const IconThemeData(color: AppTheme.primaryBrown), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: _loadRecommendations, ), PopupMenuButton( icon: const Icon(Icons.more_vert, color: AppTheme.primaryBrown), itemBuilder: (context) => [ const PopupMenuItem( value: 'clear_all', child: Row( children: [ Icon(Icons.clear_all, color: Colors.red), SizedBox(width: 8), Text('Hapus Semua'), ], ), ), const PopupMenuItem( value: 'export', child: Row( children: [ Icon(Icons.download), SizedBox(width: 8), Text('Export Data'), ], ), ), ], onSelected: (value) { if (value == 'clear_all') { _showClearAllDialog(); } else if (value == 'export') { _exportData(); } }, ), ], bottom: TabBar( controller: _tabController, labelColor: AppTheme.primaryBrown, unselectedLabelColor: AppTheme.grey500, indicatorColor: AppTheme.primaryBrown, tabs: [ Tab(text: 'Semua (${_allRecommendations.length})'), Tab(text: 'Favorit (${_favoriteRecommendations.length})'), ], ), ), body: _isLoading ? _buildLoadingState() : _error != null ? _buildErrorState() : TabBarView( controller: _tabController, children: [ _buildRecommendationsList(_allRecommendations), _buildRecommendationsList(_favoriteRecommendations), ], ), ); } Widget _buildLoadingState() { return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(), SizedBox(height: 16), Text('Memuat riwayat...'), ], ), ); } Widget _buildErrorState() { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.error_outline, size: 64, color: AppTheme.error), const SizedBox(height: 16), Text( 'Gagal memuat riwayat', style: Theme.of( context, ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Text( _error ?? 'Terjadi kesalahan', style: Theme.of( context, ).textTheme.bodyMedium?.copyWith(color: AppTheme.grey600), textAlign: TextAlign.center, ), const SizedBox(height: 24), ElevatedButton( onPressed: _loadRecommendations, child: const Text('Coba Lagi'), ), ], ), ); } Widget _buildRecommendationsList(List recommendations) { if (recommendations.isEmpty) { return _buildEmptyState(); } final bottomPadding = MediaQuery.of(context).padding.bottom + kBottomNavigationBarHeight + 16.0; return RefreshIndicator( onRefresh: _loadRecommendations, child: ListView.builder( padding: EdgeInsets.fromLTRB( AppConstants.defaultPadding, AppConstants.defaultPadding, AppConstants.defaultPadding, bottomPadding, ), itemCount: recommendations.length, itemBuilder: (context, index) { return _buildRecommendationCard(recommendations[index]); }, ), ); } Widget _buildEmptyState() { return Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.history, size: 64, color: AppTheme.grey400), const SizedBox(height: 16), Text( 'Belum ada riwayat', style: Theme.of(context).textTheme.titleLarge?.copyWith( fontWeight: FontWeight.bold, color: AppTheme.grey700, ), ), const SizedBox(height: 8), Text( 'Mulai ambil foto menu untuk mendapatkan rekomendasi personal dari AI', style: Theme.of( context, ).textTheme.bodyMedium?.copyWith(color: AppTheme.grey600), textAlign: TextAlign.center, ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: () { // Navigate to camera or home screen Navigator.of(context).popUntil((route) => route.isFirst); }, icon: const Icon(Icons.camera_alt), label: const Text('Ambil Foto Menu'), ), ], ), ), ); } Widget _buildRecommendationCard(RecommendationModel recommendation) { final topRecommendations = recommendation.topRecommendations; return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(AppConstants.borderRadius), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: InkWell( onTap: () => _openRecommendation(recommendation), borderRadius: BorderRadius.circular(AppConstants.borderRadius), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( recommendation.formattedDate, style: Theme.of(context).textTheme.titleMedium ?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 4), Text( '${recommendation.recommendations.length} rekomendasi', style: Theme.of(context).textTheme.bodySmall ?.copyWith(color: AppTheme.grey600), ), ], ), ), // Confidence Badge Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: _getConfidenceColor( recommendation.confidence, ).withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all( color: _getConfidenceColor( recommendation.confidence, ).withOpacity(0.3), ), ), child: Text( '${(recommendation.confidence * 100).toInt()}%', style: TextStyle( color: _getConfidenceColor(recommendation.confidence), fontSize: 12, fontWeight: FontWeight.bold, ), ), ), const SizedBox(width: 8), // Favorite Icon Icon( recommendation.isFavorite ? Icons.favorite : Icons.favorite_border, color: recommendation.isFavorite ? AppTheme.error : AppTheme.grey400, size: 20, ), ], ), const SizedBox(height: 12), // Top Recommendations Preview if (topRecommendations.isNotEmpty) ...[ Text( 'Rekomendasi Teratas:', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: AppTheme.grey600, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 8), ...topRecommendations .take(2) .map((rec) => _buildMiniRecommendationItem(rec)) .toList(), if (topRecommendations.length > 2) Padding( padding: const EdgeInsets.only(top: 4), child: Text( '+${topRecommendations.length - 2} lainnya', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: AppTheme.primaryBrown, fontWeight: FontWeight.w500, ), ), ), ], const SizedBox(height: 12), // Action Buttons Row( children: [ Expanded( child: OutlinedButton.icon( onPressed: () => _openRecommendation(recommendation), icon: const Icon(Icons.visibility, size: 16), label: const Text('Lihat Detail'), style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 8), ), ), ), const SizedBox(width: 8), IconButton( onPressed: () => _toggleFavorite(recommendation), icon: Icon( recommendation.isFavorite ? Icons.favorite : Icons.favorite_border, color: recommendation.isFavorite ? AppTheme.error : AppTheme.grey500, ), ), IconButton( onPressed: () => _showDeleteDialog(recommendation), icon: const Icon( Icons.delete_outline, color: AppTheme.error, ), ), ], ), ], ), ), ), ); } Widget _buildMiniRecommendationItem(MenuRecommendation recommendation) { return Padding( padding: const EdgeInsets.only(bottom: 4), child: Row( children: [ Container( width: 4, height: 4, decoration: BoxDecoration( color: AppTheme.primaryBrown, shape: BoxShape.circle, ), ), const SizedBox(width: 8), Expanded( child: Text( '${recommendation.menuName} - ${recommendation.formattedPrice}', style: Theme.of( context, ).textTheme.bodySmall?.copyWith(color: AppTheme.grey700), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), // Rating Stars Row( mainAxisSize: MainAxisSize.min, children: List.generate(recommendation.starRating, (index) { return Icon(Icons.star, color: AppTheme.accent, size: 12); }), ), ], ), ); } Color _getConfidenceColor(double confidence) { if (confidence >= 0.8) return AppTheme.success; if (confidence >= 0.6) return AppTheme.warning; return AppTheme.error; } Future _openRecommendation(RecommendationModel recommendation) async { // Create a mock OCR result for the recommendation screen final ocrResult = OCRResult( rawText: recommendation.originalMenuText, processedText: recommendation.originalMenuText, menuItems: recommendation.recommendations .map( (rec) => MenuItemOCR( name: rec.menuName, price: rec.price, description: rec.description, category: rec.category, ), ) .toList(), confidence: recommendation.confidence, isSuccess: true, ); Navigator.of(context).push( MaterialPageRoute( builder: (context) => RecommendationScreen( recommendation: recommendation, ocrResult: ocrResult, ), ), ); } Future _toggleFavorite(RecommendationModel recommendation) async { try { final newFavoriteStatus = !recommendation.isFavorite; await FirebaseService().toggleRecommendationFavorite( recommendation.id, newFavoriteStatus, ); setState(() { recommendation.copyWith(isFavorite: newFavoriteStatus); _favoriteRecommendations = _allRecommendations .where((rec) => rec.isFavorite) .toList(); }); DialogService().showSuccess( newFavoriteStatus ? 'Ditambahkan ke favorit' : 'Dihapus dari favorit', ); } catch (e) { DialogService().showError('Gagal mengupdate favorit: $e'); } } Future _showDeleteDialog(RecommendationModel recommendation) async { final confirm = await DialogService().showConfirmDialog( title: 'Hapus Rekomendasi', message: 'Apakah Anda yakin ingin menghapus rekomendasi ini?', isDanger: true, context: context, ); if (confirm) { await _deleteRecommendation(recommendation); } } Future _deleteRecommendation(RecommendationModel recommendation) async { try { await FirebaseService().deleteRecommendation(recommendation.id); setState(() { _allRecommendations.removeWhere((rec) => rec.id == recommendation.id); _favoriteRecommendations.removeWhere( (rec) => rec.id == recommendation.id, ); }); DialogService().showSuccess('Rekomendasi berhasil dihapus'); } catch (e) { DialogService().showError('Gagal menghapus rekomendasi: $e'); } } Future _showClearAllDialog() async { final confirm = await DialogService().showConfirmDialog( title: 'Hapus Semua Riwayat', message: 'Apakah Anda yakin ingin menghapus semua riwayat rekomendasi? Tindakan ini tidak dapat dibatalkan.', isDanger: true, context: context, ); if (confirm) { await _clearAllRecommendations(); } } Future _clearAllRecommendations() async { try { // Delete all recommendations for (final recommendation in _allRecommendations) { await FirebaseService().deleteRecommendation(recommendation.id); } setState(() { _allRecommendations.clear(); _favoriteRecommendations.clear(); }); DialogService().showSuccess('Semua riwayat berhasil dihapus'); } catch (e) { DialogService().showError('Gagal menghapus riwayat: $e'); } } void _exportData() { DialogService().showInfo('Fitur export akan segera hadir'); } }