import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/inAppWebView.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/theme/colors.dart' as theme_colors; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:provider/provider.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; class CoursesScreen extends StatefulWidget { const CoursesScreen({Key? key}) : super(key: key); @override _CoursesScreenState createState() => _CoursesScreenState(); } class _CoursesScreenState extends State { late DashboardProviderModel data; final RefreshController _refreshController = RefreshController(initialRefresh: false); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { data = Provider.of(context, listen: false); _onRefresh(); }); } void _onRefresh() async { await data.fetchCourses(context); _refreshController.refreshCompleted(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBarWidget( context, title: LocaleKeys.courses.tr(), ), body: Consumer( builder: (context, provider, child) { return SmartRefresher( enablePullDown: true, enablePullUp: false, controller: _refreshController, onRefresh: _onRefresh, child: provider.isCoursesLoading ? _buildShimmerLoading() : provider.coursesList.isEmpty ? _buildEmptyState() : _buildCoursesList(provider.coursesList), ); }, ), ); } Widget _buildShimmerLoading() { return ListView.builder( padding: const EdgeInsets.all(21), itemCount: 5, itemBuilder: (context, index) { return Container( margin: const EdgeInsets.only(bottom: 12), height: 150, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: 20, width: 200, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(4), ), ).toShimmer(), 12.height, Container( height: 14, width: 100, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(4), ), ).toShimmer(), const Spacer(), Container( height: 40, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(6), ), ).toShimmer(), ], ).paddingAll(14), ); }, ); } Widget _buildEmptyState() { return Utils.getNoDataWidget(context); } Widget _buildCoursesList(List courses) { return ListView.separated( physics: const BouncingScrollPhysics(), shrinkWrap: true, padding: const EdgeInsets.all(21), itemBuilder: (BuildContext context, int index) { return _buildCourseCard(courses[index]); }, separatorBuilder: (BuildContext context, int index) => 12.height, itemCount: courses.length, ); } Widget _buildCourseCard(CourseStatus course) { bool isArabic = AppState().isArabic(context); String courseName = isArabic && course.cNameAr != null && course.cNameAr!.isNotEmpty ? course.cNameAr! : course.cFullname ?? ''; String status = course.cStatus ?? 'Unknown'; Color statusColor = _getStatusColor(status); return InkWell( onTap: () => _openCourse(course.cUrl ?? ''), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Course Title Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: MyColors.lightGreyEFColor, borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.school_rounded, color: MyColors.gradiantStartColor, size: 20, ), ), 12.width, Expanded( child: courseName.toText14(isBold: true, color: MyColors.darkTextColor), ), ], ), 12.height, // Status Badge Row( children: [ Icon( _getStatusIcon(status), size: 16, color: statusColor, ), 6.width, LocaleKeys.status.tr().toText11(color: MyColors.grey98Color), 8.width, Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: statusColor.withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all( color: statusColor.withOpacity(0.3), width: 1, ), ), child: status.toText10(color: statusColor, isBold: true), ), ], ), 10.height, // Start Date if (course.cStartdate != null && course.cStartdate!.isNotEmpty) Row( children: [ const Icon( Icons.calendar_month_rounded, size: 16, color: MyColors.darkIconColor, ), 6.width, LocaleKeys.startDateT.tr().toText11(color: MyColors.grey98Color), 8.width, Expanded( child: _formatDate(course.cStartdate!).toText11( color: MyColors.darkTextColor, isBold: true, ), ), ], ), if (course.cStartdate != null && course.cStartdate!.isNotEmpty) 14.height, // Open Button Row( mainAxisAlignment: MainAxisAlignment.end, children: [ LocaleKeys.open.tr().toText12(color: MyColors.gradiantStartColor, isUnderLine: true), 6.width, RotatedBox( quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset( "assets/images/arrow_next.svg", color: MyColors.gradiantStartColor, width: 16, height: 16, ), ), ], ), ], ).objectContainerView(), ); } IconData _getStatusIcon(String status) { if (status.toLowerCase().contains('passed')) { return Icons.check_circle_rounded; } else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) { return Icons.cancel_rounded; } else if (status.toLowerCase().contains('in progress')) { return Icons.pending_rounded; } else { return Icons.info_rounded; } } Color _getStatusColor(String status) { if (status.toLowerCase().contains('passed') && !status.toLowerCase().contains('not passed')) { return Colors.green; } else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) { return Colors.red; } else if (status.toLowerCase().contains('in progress')) { return Colors.yellow[700]!; } else { return MyColors.grey98Color; } } DateTime? _parseDate(String? date) { if (date == null || date.isEmpty) return null; try { return DateTime.parse(date.replaceAll(' ', 'T')); } catch (e) { try { DateFormat format = DateFormat('yyyy-MM-dd HH:mm:ss'); return format.parse(date); } catch (e) { return null; } } } String _formatDate(String date) { DateTime? dateTime = _parseDate(date); if (dateTime == null) return date; bool isArabic = AppState().isArabic(context); DateFormat format = DateFormat('dd MMM yyyy, hh:mm a', isArabic ? 'ar' : 'en'); return format.format(dateTime); } void _openCourse(String url) { if (url.isEmpty) { Utils.showToast(LocaleKeys.courseUrlNotAvailable.tr()); return; } MyInAppBrowser browser = MyInAppBrowser( onExitCallback: () {}, onLoadStartCallback: (String url) {}, ); var settings = InAppBrowserClassSettings( webViewSettings: InAppWebViewSettings( useShouldOverrideUrlLoading: false, transparentBackground: false, ), browserSettings: InAppBrowserSettings( hideUrlBar: true, hideTitleBar: false, toolbarTopBackgroundColor: theme_colors.primaryColor, ), ); browser.openUrlRequest( urlRequest: URLRequest(url: WebUri(url)), settings: settings, ); } @override void dispose() { _refreshController.dispose(); super.dispose(); } }