Line data Source code
1 : import 'dart:convert'; 2 : 3 : import 'dts_user_pref.dart'; 4 : 5 : import '../../../domain/entities/models/mdl_the_movie.dart'; 6 : 7 : /// Service for managing favorite movies using [SharedPreferences]. 8 : /// 9 : /// The [FavoritesService] class provides methods to store, retrieve, and manage favorite movies locally. 10 : /// Movies are persisted as JSON strings in [SharedPreferences] via [UserPref]. 11 : /// 12 : /// ### Usage 13 : /// Create an instance by passing a [UserPref] object, then use the provided methods to manage favorites. 14 : /// 15 : /// ### Methods 16 : /// - [getFavoriteMovies]: Returns all favorite movies as a list of [TheMovie]. 17 : /// - [addToFavorites]: Adds a movie to favorites. 18 : /// - [removeFromFavorites]: Removes a movie from favorites by ID. 19 : /// - [isFavorite]: Checks if a movie is in favorites. 20 : /// - [toggleFavorite]: Adds or removes a movie depending on its current state. 21 : /// - [getFavoritesCount]: Returns the count of favorite movies. 22 : /// - [clearAllFavorites]: Removes all favorites. 23 : /// - [getFavoriteIds]: Returns a set of favorite movie IDs. 24 : /// 25 : /// ### Example 26 : /// ```dart 27 : /// final service = FavoritesService(UserPref()); 28 : /// await service.addToFavorites(movie); 29 : /// final favorites = await service.getFavoriteMovies(); 30 : /// print(favorites.length); 31 : /// ``` 32 : class FavoritesService { 33 2 : FavoritesService(this._userPref); 34 : 35 : /// SharedPreferences instance 36 : final UserPref _userPref; 37 : 38 : /// Key for storing favorite movies in SharedPreferences 39 : static const String _favoritesKey = 'favorite_movies'; 40 : 41 : /// Get all favorite movies. 42 : /// 43 : /// **Returns:** 44 : /// - A `Future` that resolves to a list of `TheMovie` objects. 45 1 : Future<List<TheMovie>> getFavoriteMovies() async { 46 : try { 47 2 : final List<String> favoritesJson = _userPref.favorites; 48 : 49 : return favoritesJson 50 3 : .map((movieJson) => TheMovie.fromRaw(movieJson)) 51 1 : .toList(); 52 : } catch (e) { 53 : // If there's an error parsing, return empty list 54 1 : return []; 55 : } 56 : } 57 : 58 : /// Add a movie to favorites. 59 : /// 60 : /// **Parameters:** 61 : /// - `movie` (TheMovie): The movie to add to favorites. 62 : /// 63 : /// **Returns:** 64 : /// - A `Future` that resolves to `true` if the movie was added successfully, or `false` if it was already in favorites. 65 1 : Future<bool> addToFavorites(TheMovie movie) async { 66 : try { 67 1 : final List<TheMovie> favorites = await getFavoriteMovies(); 68 : 69 : /// Check if movie is already in favorites 70 5 : if (favorites.any((favMovie) => favMovie.id == movie.id)) { 71 : return false; // Already in favorites 72 : } 73 : 74 : /// Add movie to favorites 75 1 : favorites.add(movie); 76 1 : await _saveFavorites(favorites); 77 : return true; 78 : } catch (e) { 79 : return false; 80 : } 81 : } 82 : 83 : /// Remove a movie from favorites. 84 : /// 85 : /// **Parameters:** 86 : /// - `movieId` (int): The ID of the movie to remove. 87 : /// 88 : /// **Returns:** 89 : /// - A `Future` that resolves to `true` if the movie was removed successfully, or `false` otherwise. 90 1 : Future<bool> removeFromFavorites(int movieId) async { 91 : try { 92 1 : final List<TheMovie> favorites = await getFavoriteMovies(); 93 : 94 : /// Remove movie with matching ID 95 4 : favorites.removeWhere((movie) => movie.id == movieId); 96 1 : await _saveFavorites(favorites); 97 : return true; 98 : } catch (e) { 99 : return false; 100 : } 101 : } 102 : 103 : /// Check if a movie is in favorites. 104 : /// 105 : /// **Parameters:** 106 : /// - `movieId` (int): The ID of the movie to check. 107 : /// 108 : /// **Returns:** 109 : /// - A `Future` that resolves to `true` if the movie is in favorites, or `false` otherwise. 110 1 : Future<bool> isFavorite(int movieId) async { 111 : try { 112 1 : final List<TheMovie> favorites = await getFavoriteMovies(); 113 4 : return favorites.any((movie) => movie.id == movieId); 114 : } catch (e) { 115 : return false; 116 : } 117 : } 118 : 119 : /// Toggle favorite status of a movie. 120 : /// 121 : /// **Parameters:** 122 : /// - `movie` (TheMovie): The movie to toggle. 123 : /// 124 : /// **Returns:** 125 : /// - A `Future` that resolves to `true` if the movie was added to favorites, or `false` if it was removed. 126 1 : Future<bool> toggleFavorite(TheMovie movie) async { 127 2 : final bool isCurrentlyFavorite = await isFavorite(movie.id); 128 : 129 : if (isCurrentlyFavorite) { 130 2 : return await removeFromFavorites(movie.id); 131 : } else { 132 1 : return await addToFavorites(movie); 133 : } 134 : } 135 : 136 : /// Get count of favorite movies. 137 : /// 138 : /// **Returns:** 139 : /// - A `Future` that resolves to the count of favorite movies. 140 1 : Future<int> getFavoritesCount() async { 141 1 : final List<TheMovie> favorites = await getFavoriteMovies(); 142 1 : return favorites.length; 143 : } 144 : 145 : /// Clear all favorites. 146 : /// 147 : /// **Returns:** 148 : /// - A `Future` that resolves to `true` if all favorites were cleared successfully, or `false` otherwise. 149 1 : Future<bool> clearAllFavorites() async { 150 : try { 151 3 : _userPref.favorites.remove(_favoritesKey); 152 : return true; 153 : } catch (e) { 154 : return false; 155 : } 156 : } 157 : 158 : /// Private method to save favorites list to SharedPreferences. 159 : /// 160 : /// **Parameters:** 161 : /// - `favorites` (List<TheMovie>): The list of favorite movies to save. 162 1 : Future<void> _saveFavorites(List<TheMovie> favorites) async { 163 : final List<String> favoritesJson = favorites 164 4 : .map((movie) => json.encode(movie.toMap())) 165 1 : .toList(); 166 : 167 2 : _userPref.favorites = favoritesJson; 168 : } 169 : 170 : /// Get favorite movie IDs only (for quick checks). 171 : /// 172 : /// **Returns:** 173 : /// - A `Future` that resolves to a `Set` of movie IDs. 174 1 : Future<Set<int>> getFavoriteIds() async { 175 : try { 176 1 : final List<TheMovie> favorites = await getFavoriteMovies(); 177 4 : return favorites.map((movie) => movie.id).toSet(); 178 : } catch (e) { 179 : return <int>{}; 180 : } 181 : } 182 : }