Skip to content

Commit 549c676

Browse files
committed
Add DetailsPage and integrate navigation from HomePage
1 parent 1d9dedc commit 549c676

File tree

2 files changed

+366
-42
lines changed

2 files changed

+366
-42
lines changed

lib/app/view/details_page.dart

Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
import 'package:flutter/material.dart';
2+
3+
class DetailsPage extends StatelessWidget {
4+
const DetailsPage({super.key});
5+
6+
@override
7+
Widget build(BuildContext context) {
8+
return Scaffold(
9+
backgroundColor: const Color(0xFFF9F3FF),
10+
body: SafeArea(
11+
child: SingleChildScrollView(
12+
child: Column(
13+
crossAxisAlignment: CrossAxisAlignment.start,
14+
children: [
15+
Stack(
16+
children: [
17+
Container(
18+
height: 320,
19+
width: double.infinity,
20+
decoration: const BoxDecoration(
21+
borderRadius: BorderRadius.only(
22+
bottomLeft: Radius.circular(32),
23+
bottomRight: Radius.circular(32),
24+
),
25+
image: DecorationImage(
26+
image: NetworkImage('https://image.tmdb.org/t/p/w500/ochi.jpg'),
27+
fit: BoxFit.cover,
28+
),
29+
),
30+
),
31+
Positioned(
32+
top: 16,
33+
left: 16,
34+
child: _CircleButton(
35+
icon: Icons.arrow_back,
36+
onTap: () => Navigator.of(context).pop(),
37+
),
38+
),
39+
Positioned(
40+
top: 16,
41+
right: 16,
42+
child: _CircleButton(
43+
icon: Icons.favorite_border,
44+
onTap: () {},
45+
),
46+
),
47+
Positioned(
48+
left: 24,
49+
bottom: 0,
50+
child: _RatingIndicator(percent: 0.58),
51+
),
52+
Positioned(
53+
left: 100,
54+
bottom: 32,
55+
right: 16,
56+
child: Column(
57+
crossAxisAlignment: CrossAxisAlignment.start,
58+
children: const [
59+
Text(
60+
'The Legend of Ochi',
61+
style: TextStyle(
62+
color: Colors.black,
63+
fontSize: 24,
64+
fontWeight: FontWeight.bold,
65+
),
66+
),
67+
SizedBox(height: 4),
68+
Text(
69+
'-',
70+
style: TextStyle(
71+
color: Colors.black54,
72+
fontSize: 16,
73+
),
74+
),
75+
],
76+
),
77+
),
78+
],
79+
),
80+
const SizedBox(height: 24),
81+
const Padding(
82+
padding: EdgeInsets.symmetric(horizontal: 16.0),
83+
child: Text(
84+
'In a remote village on the island of Carpathia, a shy farm girl named Yuri is raised to fear an elusive animal species known as ochi. But when Yuri discovers a wounded baby ochi has been left behind, she escapes on a quest to bring him home.',
85+
style: TextStyle(
86+
color: Colors.black87,
87+
fontSize: 16,
88+
),
89+
),
90+
),
91+
const SizedBox(height: 24),
92+
const Padding(
93+
padding: EdgeInsets.symmetric(horizontal: 16.0),
94+
child: Text(
95+
'Cast',
96+
style: TextStyle(
97+
color: Colors.black,
98+
fontSize: 18,
99+
fontWeight: FontWeight.bold,
100+
),
101+
),
102+
),
103+
const SizedBox(height: 12),
104+
SizedBox(
105+
height: 90,
106+
child: ListView(
107+
scrollDirection: Axis.horizontal,
108+
padding: const EdgeInsets.symmetric(horizontal: 16.0),
109+
children: const [
110+
_CastCard(name: 'Helena Zengel', image: 'https://randomuser.me/api/portraits/women/1.jpg'),
111+
_CastCard(name: 'Finn Wolfhard', image: 'https://randomuser.me/api/portraits/men/2.jpg'),
112+
_CastCard(name: 'Emily Watson', image: 'https://randomuser.me/api/portraits/women/3.jpg'),
113+
_CastCard(name: 'Willem Dafoe', image: 'https://randomuser.me/api/portraits/men/4.jpg'),
114+
_CastCard(name: 'Razvan Stoica', image: 'https://randomuser.me/api/portraits/men/5.jpg'),
115+
_CastCard(name: 'Carol B.', image: 'https://randomuser.me/api/portraits/women/6.jpg'),
116+
],
117+
),
118+
),
119+
const SizedBox(height: 24),
120+
const Padding(
121+
padding: EdgeInsets.symmetric(horizontal: 16.0),
122+
child: Text(
123+
'Categories',
124+
style: TextStyle(
125+
color: Colors.black,
126+
fontSize: 16,
127+
fontWeight: FontWeight.bold,
128+
),
129+
),
130+
),
131+
const SizedBox(height: 12),
132+
Padding(
133+
padding: const EdgeInsets.symmetric(horizontal: 16.0),
134+
child: Wrap(
135+
spacing: 8,
136+
children: const [
137+
_CategoryChip(label: 'Fantasy'),
138+
_CategoryChip(label: 'Adventure'),
139+
_CategoryChip(label: 'Family'),
140+
],
141+
),
142+
),
143+
const SizedBox(height: 24),
144+
const Padding(
145+
padding: EdgeInsets.symmetric(horizontal: 16.0),
146+
child: Text(
147+
'Recommendations',
148+
style: TextStyle(
149+
color: Colors.black,
150+
fontSize: 18,
151+
fontWeight: FontWeight.bold,
152+
),
153+
),
154+
),
155+
const SizedBox(height: 12),
156+
SizedBox(
157+
height: 180,
158+
child: ListView(
159+
scrollDirection: Axis.horizontal,
160+
padding: const EdgeInsets.symmetric(horizontal: 16.0),
161+
children: const [
162+
_RecommendationCard(image: 'https://image.tmdb.org/t/p/w500/rec1.jpg'),
163+
_RecommendationCard(image: 'https://image.tmdb.org/t/p/w500/rec2.jpg'),
164+
_RecommendationCard(image: 'https://image.tmdb.org/t/p/w500/rec3.jpg'),
165+
],
166+
),
167+
),
168+
const SizedBox(height: 32),
169+
],
170+
),
171+
),
172+
),
173+
);
174+
}
175+
}
176+
177+
class _CircleButton extends StatelessWidget {
178+
final IconData icon;
179+
final VoidCallback onTap;
180+
const _CircleButton({required this.icon, required this.onTap});
181+
182+
@override
183+
Widget build(BuildContext context) {
184+
return Material(
185+
color: Colors.white.withOpacity(0.7),
186+
shape: const CircleBorder(),
187+
child: InkWell(
188+
customBorder: const CircleBorder(),
189+
onTap: onTap,
190+
child: Padding(
191+
padding: const EdgeInsets.all(10.0),
192+
child: Icon(icon, color: Colors.black, size: 24),
193+
),
194+
),
195+
);
196+
}
197+
}
198+
199+
class _RatingIndicator extends StatelessWidget {
200+
final double percent;
201+
const _RatingIndicator({required this.percent});
202+
203+
@override
204+
Widget build(BuildContext context) {
205+
return Column(
206+
children: [
207+
SizedBox(
208+
width: 48,
209+
height: 48,
210+
child: Stack(
211+
fit: StackFit.expand,
212+
children: [
213+
CircularProgressIndicator(
214+
value: percent,
215+
strokeWidth: 5,
216+
backgroundColor: Colors.grey[300],
217+
valueColor: const AlwaysStoppedAnimation<Color>(Color(0xFFB388F6)),
218+
),
219+
Center(
220+
child: Text(
221+
'${(percent * 100).round()}%',
222+
style: const TextStyle(
223+
color: Color(0xFF7C4DFF),
224+
fontWeight: FontWeight.bold,
225+
),
226+
),
227+
),
228+
],
229+
),
230+
),
231+
],
232+
);
233+
}
234+
}
235+
236+
class _CastCard extends StatelessWidget {
237+
final String name;
238+
final String image;
239+
const _CastCard({required this.name, required this.image});
240+
241+
@override
242+
Widget build(BuildContext context) {
243+
return Container(
244+
width: 70,
245+
margin: const EdgeInsets.only(right: 12),
246+
child: Column(
247+
children: [
248+
CircleAvatar(
249+
radius: 28,
250+
backgroundImage: NetworkImage(image),
251+
),
252+
const SizedBox(height: 4),
253+
Text(
254+
name,
255+
style: const TextStyle(
256+
color: Colors.black87,
257+
fontSize: 12,
258+
fontWeight: FontWeight.w500,
259+
),
260+
maxLines: 1,
261+
overflow: TextOverflow.ellipsis,
262+
textAlign: TextAlign.center,
263+
),
264+
],
265+
),
266+
);
267+
}
268+
}
269+
270+
class _CategoryChip extends StatelessWidget {
271+
final String label;
272+
const _CategoryChip({required this.label});
273+
274+
@override
275+
Widget build(BuildContext context) {
276+
return Chip(
277+
label: Text(label),
278+
backgroundColor: Colors.white,
279+
labelStyle: const TextStyle(
280+
color: Colors.black87,
281+
fontWeight: FontWeight.bold,
282+
),
283+
side: const BorderSide(color: Colors.black12),
284+
shape: RoundedRectangleBorder(
285+
borderRadius: BorderRadius.circular(20),
286+
),
287+
);
288+
}
289+
}
290+
291+
class _RecommendationCard extends StatelessWidget {
292+
final String image;
293+
const _RecommendationCard({required this.image});
294+
295+
@override
296+
Widget build(BuildContext context) {
297+
return Container(
298+
width: 120,
299+
margin: const EdgeInsets.only(right: 16),
300+
decoration: BoxDecoration(
301+
borderRadius: BorderRadius.circular(16),
302+
image: DecorationImage(
303+
image: NetworkImage(image),
304+
fit: BoxFit.cover,
305+
),
306+
boxShadow: const [
307+
BoxShadow(
308+
color: Colors.black12,
309+
blurRadius: 6,
310+
offset: Offset(0, 2),
311+
),
312+
],
313+
),
314+
);
315+
}
316+
}

0 commit comments

Comments
 (0)