1+ import 'package:flutter/material.dart' ;
2+ import 'package:flutter_movie_clean_architecture/core/config/app_constant.dart' ;
3+ import 'package:flutter_movie_clean_architecture/core/hive/favorite_model.dart' ;
4+ import 'package:flutter_movie_clean_architecture/core/hive/hive_helper.dart' ;
5+ import 'package:go_router/go_router.dart' ;
6+
7+ class FavoritesPage extends StatefulWidget {
8+ const FavoritesPage ({super .key});
9+
10+ @override
11+ State <FavoritesPage > createState () => _FavoritesPageState ();
12+ }
13+
14+ class _FavoritesPageState extends State <FavoritesPage > {
15+ int _currentIndex = 0 ;
16+ late Future <List <Favorite >> _favoritesFuture;
17+
18+ @override
19+ void initState () {
20+ super .initState ();
21+ _loadFavorites ();
22+ }
23+
24+ Future <void > _loadFavorites () async {
25+ setState (() {
26+ _favoritesFuture = _getFavoritesByType ();
27+ });
28+ }
29+
30+ Future <List <Favorite >> _getFavoritesByType () async {
31+ switch (_currentIndex) {
32+ case 0 :
33+ return await HiveHelper .getFavoritesByType ('movie' );
34+ case 1 :
35+ return await HiveHelper .getFavoritesByType ('tv' );
36+ case 2 :
37+ return await HiveHelper .getFavoritesByType ('celebrity' );
38+ default :
39+ return await HiveHelper .getAllFavorites ();
40+ }
41+ }
42+
43+ Future <void > _refreshFavorites () async {
44+ await _loadFavorites ();
45+ }
46+
47+ @override
48+ Widget build (BuildContext context) {
49+ return Scaffold (
50+ body: FutureBuilder <List <Favorite >>(
51+ future: _favoritesFuture,
52+ builder: (context, snapshot) {
53+ if (snapshot.connectionState == ConnectionState .waiting) {
54+ return const Center (child: CircularProgressIndicator ());
55+ }
56+
57+ if (snapshot.hasError) {
58+ return Center (
59+ child: Text ('Error loading favorites: ${snapshot .error }' ),
60+ );
61+ }
62+
63+ final favorites = snapshot.data ?? [];
64+
65+ if (favorites.isEmpty) {
66+ return const Center (
67+ child: Column (
68+ mainAxisAlignment: MainAxisAlignment .center,
69+ children: [
70+ Icon (Icons .favorite_border, size: 64 , color: Colors .grey),
71+ SizedBox (height: 16 ),
72+ Text (
73+ 'No favorites yet' ,
74+ style: TextStyle (fontSize: 18 , color: Colors .grey),
75+ ),
76+ SizedBox (height: 8 ),
77+ Text (
78+ 'Start adding favorites from movie, TV series, or artist details' ,
79+ textAlign: TextAlign .center,
80+ style: TextStyle (color: Colors .grey),
81+ ),
82+ ],
83+ ),
84+ );
85+ }
86+
87+ return RefreshIndicator (
88+ onRefresh: _refreshFavorites,
89+ child: GridView .builder (
90+ padding: const EdgeInsets .all (16 ),
91+ gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount (
92+ crossAxisCount: 2 ,
93+ crossAxisSpacing: 16 ,
94+ mainAxisSpacing: 16 ,
95+ childAspectRatio: 0.7 ,
96+ ),
97+ itemCount: favorites.length,
98+ itemBuilder: (context, index) {
99+ final favorite = favorites[index];
100+ return Card (
101+ elevation: 4 ,
102+ shape: RoundedRectangleBorder (
103+ borderRadius: BorderRadius .circular (12 ),
104+ ),
105+ child: InkWell (
106+ onTap: () {
107+ switch (favorite.type) {
108+ case 'movie' :
109+ context.push ('/movie/${favorite .itemId }' );
110+ break ;
111+ case 'tv' :
112+ context.push ('/tv/${favorite .itemId }' );
113+ break ;
114+ case 'celebrity' :
115+ context.push ('/artistId/${favorite .itemId }' );
116+ break ;
117+ }
118+ },
119+ borderRadius: BorderRadius .circular (12 ),
120+ child: Column (
121+ crossAxisAlignment: CrossAxisAlignment .start,
122+ children: [
123+ Expanded (
124+ child: ClipRRect (
125+ borderRadius: const BorderRadius .vertical (
126+ top: Radius .circular (12 ),
127+ ),
128+ child: favorite.posterPath.isNotEmpty
129+ ? Image .network (
130+ '$IMAGE_URL ${favorite .posterPath }' ,
131+ fit: BoxFit .cover,
132+ width: double .infinity,
133+ errorBuilder: (_, __, ___) =>
134+ _buildPlaceholderImage (),
135+ )
136+ : _buildPlaceholderImage (),
137+ ),
138+ ),
139+ Padding (
140+ padding: const EdgeInsets .all (8 ),
141+ child: Column (
142+ crossAxisAlignment: CrossAxisAlignment .start,
143+ children: [
144+ Text (
145+ favorite.title,
146+ maxLines: 2 ,
147+ overflow: TextOverflow .ellipsis,
148+ style: const TextStyle (
149+ fontWeight: FontWeight .bold,
150+ fontSize: 14 ,
151+ ),
152+ ),
153+ const SizedBox (height: 4 ),
154+ Row (
155+ mainAxisAlignment:
156+ MainAxisAlignment .spaceBetween,
157+ children: [
158+ Text (
159+ favorite.type.toUpperCase (),
160+ style: TextStyle (
161+ color: Colors .grey[600 ],
162+ fontSize: 10 ,
163+ ),
164+ ),
165+ IconButton (
166+ icon: const Icon (
167+ Icons .favorite,
168+ color: Colors .red,
169+ size: 18 ,
170+ ),
171+ padding: EdgeInsets .zero,
172+ onPressed: () async {
173+ await HiveHelper .deleteFavorite (
174+ favorite.itemId, favorite.type);
175+ _refreshFavorites ();
176+ },
177+ ),
178+ ],
179+ ),
180+ ],
181+ ),
182+ ),
183+ ],
184+ ),
185+ ),
186+ );
187+ },
188+ ),
189+ );
190+ },
191+ ),
192+ bottomNavigationBar: BottomNavigationBar (
193+ currentIndex: _currentIndex,
194+ onTap: (index) {
195+ setState (() {
196+ _currentIndex = index;
197+ _loadFavorites ();
198+ });
199+ },
200+ items: const [
201+ BottomNavigationBarItem (
202+ icon: Icon (Icons .movie),
203+ label: 'Movies' ,
204+ ),
205+ BottomNavigationBarItem (
206+ icon: Icon (Icons .tv),
207+ label: 'TV Series' ,
208+ ),
209+ BottomNavigationBarItem (
210+ icon: Icon (Icons .people),
211+ label: 'Celebrities' ,
212+ ),
213+ ],
214+ ),
215+ );
216+ }
217+
218+ Widget _buildPlaceholderImage () {
219+ return Container (
220+ width: double .infinity,
221+ height: double .infinity,
222+ color: Colors .grey[300 ],
223+ child: const Icon (Icons .image, color: Colors .grey),
224+ );
225+ }
226+ }
0 commit comments