Aidra Driver 1.3.5+68
Aidra Driver - Your path to green energy
Loading...
Searching...
No Matches
course_detail_screen.dart
Go to the documentation of this file.
1import 'package:fluentui_system_icons/fluentui_system_icons.dart';
2import 'package:flutter/material.dart';
3import 'package:flutter_bloc/flutter_bloc.dart';
4import 'package:flutter_screenutil/flutter_screenutil.dart';
5import 'package:go_router/go_router.dart';
6
7import '../../../../core/router/routes.dart';
8import '../../../../core/ui/theme/color_palette.dart';
9import '../../../../core/ui/widgets/custom_scaffold.dart';
10import '../../../../core/ui/widgets/faild_to_fetch_data_view.dart';
11import '../../domain/entities/course_entity.dart';
12import '../logic/cubit/elearning_v2_cubit.dart';
13import 'qcm_screen.dart';
14
16 final int courseId;
17
19 super.key,
20 required this.courseId,
21 });
22
23 @override
24 State<CourseDetailScreen> createState() => _CourseDetailScreenState();
25}
26
27class _CourseDetailScreenState extends State<CourseDetailScreen> {
28 @override
29 void initState() {
30 super.initState();
32 }
33
35 context.read<ElearningV2Cubit>().loadCourseDetails(widget.courseId);
36 }
37
38 @override
39 Widget build(BuildContext context) {
40 return BlocBuilder<ElearningV2Cubit, ElearningV2State>(
41 builder: (context, state) {
42 return CustomScaffold(
44 ? state.course.title ?? 'Course Details'
45 : 'Course Details',
46 isLoading: state is LoadingCourseDetailsState,
47 isLeadingVisible: true,
48 body: SafeArea(
49 child: _buildBody(state),
50 ),
51 );
52 },
53 );
54 }
55
57 if (state is CourseDetailsLoadedState) {
59 state.course,
60 state.pdfPath,
61 state.qcmList.isNotEmpty,
62 );
63 } else if (state is CourseDetailsLoadingFailureState) {
64 return FailedToFetchDataView(
65 onRetry: _loadCourseDetails,
66 );
67 } else {
68 return const SizedBox();
69 }
70 }
71
73 Color mainColor = _parseColor(course.iconColor ?? '#4CAF50', context);
74 return SingleChildScrollView(
75 padding: EdgeInsets.all(16.r),
77 crossAxisAlignment: CrossAxisAlignment.start,
78 children: [
79 // Course title and description
80 Text(
81 course.title ?? 'Untitled Course',
82 style: Theme.of(context).textTheme.displayMedium,
83 ),
84 SizedBox(height: 8.r),
85 Text(
86 course.description ?? '',
87 style: Theme.of(context).textTheme.bodyMedium?.copyWith(
88 color: Theme.of(context).hintColor,
89 ),
90 ),
91
92 // Progress indicator
93 Container(
94 decoration: BoxDecoration(
95 color: Theme.of(context).colorScheme.surface,
96 borderRadius: BorderRadius.circular(16),
97 ),
98 margin: EdgeInsets.symmetric(vertical: 16.sp),
99 padding: EdgeInsets.all(15.sp),
100 child: Column(
101 crossAxisAlignment: CrossAxisAlignment.start,
102 children: [
103 Row(
104 children: [
105 Icon(FluentIcons.arrow_flow_diagonal_up_right_12_filled, size: 20),
106 SizedBox(width: 7.sp),
107 Text(
108 'Your Progress',
109 style: Theme.of(context).textTheme.bodyLarge?.copyWith(
110 fontWeight: FontWeight.bold,
111 ),
112 ),
113 ],
114 ),
115 SizedBox(height: 12.r),
116 LinearProgressIndicator(
117 value: course.progress,
118 color: mainColor,
119 backgroundColor: mainColor.withValues(alpha: 0.11),
120 valueColor: AlwaysStoppedAnimation<Color>(
121 mainColor,
122 ),
123 borderRadius: BorderRadius.circular(4.r),
124 minHeight: 3.r,
125 ),
126 SizedBox(height: 8.r),
127 Align(
128 alignment: Alignment.centerRight,
129 child: Text('${(course.progress! * 100).toInt()}%',
130 style: Theme.of(context).textTheme.displaySmall?.copyWith(
131 color: mainColor,
132 )),
133 ),
134 ],
135 ),
136 ),
137
138 // Learning steps
139
140 Text(
141 'Learning Steps',
142 style: Theme.of(context).textTheme.bodyLarge,
143 ),
144 SizedBox(height: 16.r),
145
146 // PDF Reading step
148 color: mainColor,
149 title: 'Step 1: Read the Material',
150 description:
151 'Read through the PDF material to understand the concepts',
152 progress: course.progress! >= 0.5 ? 1.0 : course.progress! * 2,
153 onTap: () {
154 context.push(
155 Routes.pdfViewerScreen.route,
156 extra: {
157 'pdfPath': course.pdfPath,
158 'courseId': course.id,
159 'onComplete': (double progress) {
160 if (course.progress! < 0.5) {
161 context.read<ElearningV2Cubit>().updateProgress(
162 course.id!,
163 0.5,
164 );
165 }
166 },
167 },
168 );
169 },
170 ),
171 SizedBox(height: 16.r),
172 // QCM Quiz step
174 color: mainColor,
175 title: 'Step 2: Test Your Knowledge',
176 description: 'Complete the quiz to test your understanding',
177 progress:
178 course.progress! <= 0.5 ? 0.0 : (course.progress! - 0.5) * 2,
179 isDisabled: course.progress! < 0.5,
180 onTap: () {
181 if (course.progress! >= 0.5) {
182 Navigator.push(
183 context,
184 MaterialPageRoute(
185 builder: (context) => QcmScreen(
186 courseId: course.id!,
187 currentProgress: course.progress!,
188 onComplete: (double quizScore) {
189 // Calculate new progress (50% from PDF + 50% from quiz)
190 final newProgress = 0.5 + (quizScore * 0.5);
191 context.read<ElearningV2Cubit>().updateProgress(
192 course.id!,
193 newProgress,
194 );
195 },
196 ),
197 ),
198 );
199 }
200 },
201 ),
202 ],
203 ),
204 );
205 }
206
208 required String title,
209 required String description,
210 required double progress,
211 required VoidCallback onTap,
212 required Color color,
213 bool isDisabled = false,
214 }) {
215 return GestureDetector(
216 onTap: isDisabled ? null : onTap,
217 child: Container(
218 decoration: BoxDecoration(
219 color: Theme.of(context).colorScheme.surface,
220 borderRadius: BorderRadius.circular(16.r),
221 border: Border.all(
222 color: isDisabled
223 ? Theme.of(context).dividerColor
224 : color.withValues(alpha: 0.3),
225 width: 1.5,
226 ),
227 ),
228 padding: EdgeInsets.all(16.r),
229 child: Row(
230 children: [
231 Container(
232 width: 40.r,
233 height: 40.r,
234 decoration: BoxDecoration(
235 color: isDisabled
236 ? Theme.of(context).disabledColor.withValues(alpha: 0.1)
237 : color.withValues(alpha: 0.1),
238 shape: BoxShape.circle,
239 ),
240 child: Icon(
241 FluentIcons.document_100_16_regular,
242 color: isDisabled ? Theme.of(context).disabledColor : color,
243 size: 20.r,
244 ),
245 ),
246 SizedBox(width: 12.r),
247 Expanded(
248 child: Column(
249 crossAxisAlignment: CrossAxisAlignment.start,
250 children: [
251 Text(
252 title,
253 style: Theme.of(context).textTheme.titleMedium?.copyWith(
254 fontWeight: FontWeight.bold,
255 color: isDisabled
256 ? Theme.of(context).disabledColor
257 : Theme.of(context).textTheme.titleMedium?.color,
258 ),
259 ),
260 SizedBox(height: 4.r),
261 Text(
262 description,
263 style: Theme.of(context).textTheme.bodyMedium?.copyWith(
264 color: isDisabled
265 ? Theme.of(context).hintColor.withValues(alpha: 0.3)
267 ),
268 maxLines: 2,
269 overflow: TextOverflow.ellipsis,
270 ),
271 ],
272 ),
273 ),
274 ],
275 ),
276 ),
277 );
278 }
279
280 // Widget _buildLearningStep({
281 // required String title,
282 // required String description,
283 // required double progress,
284 // required VoidCallback onTap,
285 // required Color color,
286 // bool isDisabled = false,
287 // }) {
288 // return GestureDetector(
289 // onTap: isDisabled ? null : onTap,
290 // child: Container(
291 // padding: EdgeInsets.all(16.r),
292 // decoration: BoxDecoration(
293 // color: isDisabled
294 // ? Theme.of(context).colorScheme.surface.withOpacity(.5)
295 // : Theme.of(context).colorScheme.onPrimaryContainer,
296 // borderRadius: BorderRadius.circular(10.r),
297 // ),
298 // child: Column(
299 // crossAxisAlignment: CrossAxisAlignment.start,
300 // children: [
301 // Row(
302 // children: [
303 // Container(
304 // width: 40.r,
305 // height: 40.r,
306 // decoration: BoxDecoration(
307 // color: isDisabled
308 // ? Theme.of(context)
309 // .colorScheme
310 // .onSurface
311 // .withOpacity(0.11)
312 // : Theme.of(context).primaryColor.withOpacity(0.1),
313 // shape: BoxShape.circle,
314 // ),
315 // child: Icon(
316 // isDisabled
317 // ? HugeIcons.strokeRoundedSquareLock01
318 // : HugeIcons.strokeRoundedCursorPointer01,
319 // color: isDisabled
320 // ? Theme.of(context).hintColor.withOpacity(0.3)
321 // : Theme.of(context).primaryColor,
322 // size: 24.r,
323 // ),
324 // ),
325 // SizedBox(width: 12.r),
326 // Expanded(
327 // child: Column(
328 // crossAxisAlignment: CrossAxisAlignment.start,
329 // children: [
330 // Text(
331 // title,
332 // style: Theme.of(context)
333 // .textTheme
334 // .displaySmall
335 // ?.copyWith(
336 // color: isDisabled
337 // ? Theme.of(context).hintColor.withOpacity(0.3)
338 // : Theme.of(context).primaryColor,
339 // ),
340 // ),
341 // SizedBox(height: 4.r),
342 // Text(
343 // description,
344 // style: Theme.of(context).textTheme.bodyMedium?.copyWith(
345 // color: isDisabled
346 // ? Theme.of(context).hintColor.withOpacity(0.3)
347 // : ColorPaletteV2.textSecondaryLight,
348 // ),
349 // maxLines: 2,
350 // overflow: TextOverflow.ellipsis,
351 // ),
352 // ],
353 // ),
354 // ),
355 // ],
356 // ),
357 // SizedBox(height: 16.r),
358 // LinearProgressIndicator(
359 // value: progress,
360 // backgroundColor: isDisabled
361 // ? Theme.of(context).highlightColor.withOpacity(0.11)
362 // : Theme.of(context).colorScheme.primary.withOpacity(0.11),
363 // valueColor: AlwaysStoppedAnimation<Color>(
364 // Theme.of(context).colorScheme.primary,
365 // ),
366 // borderRadius: BorderRadius.circular(4.r),
367 // minHeight: 3.r,
368 // ),
369 // SizedBox(height: 10.r),
370 // Align(
371 // alignment: Alignment.centerRight,
372 // child: Text(
373 // '${(progress * 100).toInt()}%',
374 // style: TextStyle(
375 // fontSize: 12.sp,
376 // fontWeight: FontWeight.bold,
377 // color: isDisabled
378 // ? Theme.of(context).hintColor.withOpacity(0.3)
379 // : Theme.of(context).primaryColor,
380 // ),
381 // ),
382 // ),
383 // ],
384 // ),
385 // ),
386 // );
387 // }
388
389 // Helper method to parse hex color string to Color
390 Color _parseColor(String hexColor, BuildContext context) {
391 try {
392 hexColor = hexColor.replaceAll('#', '');
393 if (hexColor.length == 6) {
394 hexColor = 'FF$hexColor';
395 }
396 return Color(int.parse(hexColor, radix: 16));
397 } catch (e) {
398 return Theme.of(context).colorScheme.primary;
399 }
400 }
401}
override void initState()
class App extends StatefulWidget build(BuildContext context)
Definition app.dart:31
bool isLoading
static const black
const CourseDetailScreen({ super.key, required this.courseId, })
override State< CourseDetailScreen > createState()
Widget _buildLearningStep({ required String title, required String description, required double progress, required VoidCallback onTap, required Color color, bool isDisabled=false, })
void _loadCourseDetails()
Widget _buildCourseDetails(CourseEntity course, String pdfPath, bool hasQcm)
Color _parseColor(String hexColor, BuildContext context)
const CourseDetailScreen({ super.key, required this.courseId, })
final Widget child
final EdgeInsets padding
class Partner String
Widget _buildBody()
final String pdfPath
class CoursesLoadingFailureState extends ElearningV2State course
const CourseDetailsLoadedState(this.course, this.pdfPath, this.qcmList)
final Color color
Definition failures.dart:1
final VoidCallback onTap
final String title
final double progress
style Text( '${ 'scheduling.reference'.tr()}:${collection.internalCode}', style:Theme.of(context).textTheme.bodySmall,)
style SizedBox(height:2.h)
style Column(crossAxisAlignment:CrossAxisAlignment.end, children:[Container(padding:EdgeInsets.symmetric(horizontal:8.w, vertical:4.h), decoration:BoxDecoration(color:ColorPalette.tiffanyBlue.withValues(alpha:0.1), borderRadius:BorderRadius.circular(12),), child:Text(collection.type ?? '', style:Theme.of(context).textTheme.bodySmall?.copyWith(color:ColorPalette.tiffanyBlue, fontWeight:FontWeight.bold,),),),],)