Line data Source code
1 : import 'package:flutter/foundation.dart'; 2 : 3 : import '../../domain/entities/models/mdl_the_movie.dart'; 4 : import '../../data/datasources/local/favorites_service.dart'; 5 : 6 : /// Manages the state and logic for the user's favorite movies. 7 : /// 8 : /// The `FavoritesProvider` is responsible for: 9 : /// - Storing and updating the list of favorite movies. 10 : /// - Adding, removing, toggling, and checking favorite status for movies. 11 : /// - Persisting favorites using [FavoritesService]. 12 : /// - Notifying listeners when the state changes, enabling reactive UI updates. 13 : /// - Handling loading, error, and empty states for favorites. 14 : /// 15 : /// ### State 16 : /// - `_favoriteMovies`: Internal list of favorite movies. 17 : /// - `_favoriteIds`: Set of favorite movie IDs for quick lookup. 18 : /// - `_isLoading`: Indicates if favorites are being loaded. 19 : /// - `_error`: Stores error messages for UI feedback. 20 : /// 21 : /// ### Getters 22 : /// - `favoriteMovies`: List of favorite movies. 23 : /// - `favoriteIds`: Set of favorite movie IDs. 24 : /// - `isLoading`: Loading state. 25 : /// - `error`: Error message, if any. 26 : /// - `favoritesCount`: Number of favorite movies. 27 : /// - `isEmpty` / `isNotEmpty`: Whether the favorites list is empty or not. 28 : /// 29 : /// ### Methods 30 : /// - [init]: Loads favorites from persistent storage. 31 : /// - [addToFavorites]: Adds a movie to favorites. 32 : /// - [removeFromFavorites]: Removes a movie from favorites. 33 : /// - [toggleFavorite]: Toggles the favorite status of a movie. 34 : /// - [clearAllFavorites]: Removes all favorites. 35 : /// - [refreshFavorites]: Reloads favorites from storage. 36 : /// - [getFavoriteById]: Retrieves a favorite movie by its ID. 37 : /// - [clearError]: Clears any error message. 38 : /// 39 : /// ### Usage 40 : /// Use this provider in your app to manage and reactively update the user's favorite movies. 41 : class FavoritesProvider with ChangeNotifier { 42 : /// Creates a `FavoritesProvider` instance. 43 : /// 44 : /// **Parameters:** 45 : /// - `_favoritesService` (FavoritesService): The service used to manage favorite movies. 46 2 : FavoritesProvider(this._favoritesService); 47 : 48 : /// The service used to manage favorite movies. 49 : final FavoritesService _favoritesService; 50 : 51 : // Favorites State 52 : List<TheMovie> _favoriteMovies = []; 53 : Set<int> _favoriteIds = <int>{}; 54 : bool _isLoading = false; 55 : String? _error; 56 : 57 : // Getters 58 2 : List<TheMovie> get favoriteMovies => _favoriteMovies; 59 2 : Set<int> get favoriteIds => _favoriteIds; 60 2 : bool get isLoading => _isLoading; 61 2 : String? get error => _error; 62 3 : int get favoritesCount => _favoriteMovies.length; 63 : 64 : /// Initializes the provider by loading favorites from storage. 65 1 : Future<void> init() async { 66 1 : await _loadFavorites(); 67 : } 68 : 69 : /// Load favorites from storage 70 1 : Future<void> _loadFavorites() async { 71 1 : _isLoading = true; 72 1 : _error = null; 73 1 : notifyListeners(); 74 : 75 : try { 76 3 : _favoriteMovies = await _favoritesService.getFavoriteMovies(); 77 3 : _favoriteIds = await _favoritesService.getFavoriteIds(); 78 1 : _isLoading = false; 79 1 : notifyListeners(); 80 : } catch (e) { 81 1 : _isLoading = false; 82 3 : _error = 'Error al cargar favoritos: ${e.toString()}'; 83 1 : notifyListeners(); 84 : } 85 : } 86 : 87 : /// Checks if a movie is marked as a favorite. 88 : /// 89 : /// **Parameters:** 90 : /// - `movieId` (int): The ID of the movie to check. 91 : /// 92 : /// **Returns:** 93 : /// - `true` if the movie is a favorite, `false` otherwise. 94 1 : bool isFavorite(int movieId) { 95 2 : return _favoriteIds.contains(movieId); 96 : } 97 : 98 : /// Adds a movie to the list of favorites. 99 : /// 100 : /// **Parameters:** 101 : /// - `movie` (TheMovie): The movie to add to favorites. 102 : /// 103 : /// **Returns:** 104 : /// - A `Future` that resolves to `true` if the movie was added successfully, or `false` otherwise. 105 1 : Future<bool> addToFavorites(TheMovie movie) async { 106 : try { 107 2 : final success = await _favoritesService.addToFavorites(movie); 108 : if (success) { 109 2 : _favoriteMovies.add(movie); 110 3 : _favoriteIds.add(movie.id); 111 1 : notifyListeners(); 112 : } 113 : return success; 114 : } catch (e) { 115 3 : _error = 'Error al agregar a favoritos: ${e.toString()}'; 116 1 : notifyListeners(); 117 : return false; 118 : } 119 : } 120 : 121 : /// Remove movie from favorites 122 1 : Future<bool> removeFromFavorites(int movieId) async { 123 : try { 124 2 : final success = await _favoritesService.removeFromFavorites(movieId); 125 : if (success) { 126 5 : _favoriteMovies.removeWhere((movie) => movie.id == movieId); 127 2 : _favoriteIds.remove(movieId); 128 1 : notifyListeners(); 129 : } 130 : return success; 131 : } catch (e) { 132 3 : _error = 'Error al remover de favoritos: ${e.toString()}'; 133 1 : notifyListeners(); 134 : return false; 135 : } 136 : } 137 : 138 : /// Toggle favorite status 139 1 : Future<bool> toggleFavorite(TheMovie movie) async { 140 2 : if (isFavorite(movie.id)) { 141 2 : return await removeFromFavorites(movie.id); 142 : } else { 143 1 : return await addToFavorites(movie); 144 : } 145 : } 146 : 147 : /// Clear all favorites 148 1 : Future<bool> clearAllFavorites() async { 149 : try { 150 2 : final success = await _favoritesService.clearAllFavorites(); 151 : if (success) { 152 2 : _favoriteMovies.clear(); 153 2 : _favoriteIds.clear(); 154 1 : notifyListeners(); 155 : } 156 : return success; 157 : } catch (e) { 158 3 : _error = 'Error al limpiar favoritos: ${e.toString()}'; 159 1 : notifyListeners(); 160 : return false; 161 : } 162 : } 163 : 164 : /// Refresh favorites from storage 165 1 : Future<void> refreshFavorites() async { 166 1 : await _loadFavorites(); 167 : } 168 : 169 : /// Get favorite movie by ID 170 1 : TheMovie? getFavoriteById(int id) { 171 : try { 172 5 : return _favoriteMovies.firstWhere((movie) => movie.id == id); 173 : } catch (e) { 174 : return null; 175 : } 176 : } 177 : 178 : /// Check if favorites list is empty 179 3 : bool get isEmpty => _favoriteMovies.isEmpty; 180 3 : bool get isNotEmpty => _favoriteMovies.isNotEmpty; 181 : 182 : /// Clear any error 183 1 : void clearError() { 184 1 : _error = null; 185 1 : notifyListeners(); 186 : } 187 : }