diff --git a/lib/features/radiology/radiology_repo.dart b/lib/features/radiology/radiology_repo.dart index 30b078ef..7374b247 100644 --- a/lib/features/radiology/radiology_repo.dart +++ b/lib/features/radiology/radiology_repo.dart @@ -42,7 +42,7 @@ class RadiologyRepoImp implements RadiologyRepo { failure = failureType; }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { - final radOrders; + List radOrders = []; try { if (response['FinalRadiologyList'] != null && response['FinalRadiologyList'].length != 0) { final list = response['FinalRadiologyList']; @@ -52,10 +52,18 @@ class RadiologyRepoImp implements RadiologyRepo { .cast(); } else { final list = response['FinalRadiologyListAPI']; - radOrders = list - .map((item) => PatientRadiologyResponseModel.fromJson(item as Map)) - .toList() - .cast(); + if(list != null && list.length != 0) { + radOrders = list + .map((item) => PatientRadiologyResponseModel.fromJson(item as Map)) + .toList() + .cast(); + } + } + + // Check if radOrders is empty and set failure + if (radOrders.isEmpty) { + failure = ServerFailure(errorMessage ?? "No radiology orders found"); + return; } apiResponse = GenericApiModel>( @@ -203,6 +211,12 @@ class RadiologyRepoImp implements RadiologyRepo { } } + // Check if radOrders is empty and set failure + if (radOrders.isEmpty) { + failure = ServerFailure(errorMessage ?? "No radiology orders found for this appointment"); + return; + } + apiResponse = GenericApiModel>( messageStatus: messageStatus, statusCode: statusCode, diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 66d2b151..dfdde83a 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -430,8 +430,8 @@ class _AppointmentDetailsPageState extends State { const Spacer(), BellAnimatedSwitch( key: _bellSwitchKey, - width: 48.w, - height: 30.h, + width: 56.w, + height: 38.h, initialValue: widget.patientAppointmentHistoryResponseModel.hasReminder ?? false, activeColor: AppColors.successColor.withOpacity(0.2), inactiveColor: AppColors.lightGrayBGColor, diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index fabb9043..505afcdf 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -717,35 +717,37 @@ class _AppointmentCardState extends State { // Countdown Timer - DD : HH : MM : SS format with labels - // Row( - // mainAxisAlignment: MainAxisAlignment.center, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // // Days - // _buildTimeUnit( - // _timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00', - // LocaleKeys.days.tr(context: context), - // ), - // _buildTimeSeparator(), - // // Hours - // _buildTimeUnit( - // _timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00', - // LocaleKeys.hours.tr(context: context), - // ), - // _buildTimeSeparator(), - // // Minutes - // _buildTimeUnit( - // _timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00', - // LocaleKeys.minutes.tr(context: context), - // ), - // _buildTimeSeparator(), - // // Seconds - // _buildTimeUnit( - // _timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00', - // LocaleKeys.seconds.tr(context: context), - // ), - // ], - // ), + Directionality( + textDirection: ui.TextDirection.ltr, + child:Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Days + _buildTimeUnit( + _timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00', + LocaleKeys.days.tr(context: context), + ), + _buildTimeSeparator(), + // Hours + _buildTimeUnit( + _timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00', + LocaleKeys.hours.tr(context: context), + ), + _buildTimeSeparator(), + // Minutes + _buildTimeUnit( + _timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00', + LocaleKeys.minutes.tr(context: context), + ), + _buildTimeSeparator(), + // Seconds + _buildTimeUnit( + _timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00', + LocaleKeys.seconds.tr(context: context), + ), + ], + )), SizedBox(height: 24.h), // Green Acknowledge button with checkmark icon CustomButton( diff --git a/lib/presentation/health_calculators_and_converts/health_calculators_page.dart b/lib/presentation/health_calculators_and_converts/health_calculators_page.dart index 877a5d9b..a7fe0ef5 100644 --- a/lib/presentation/health_calculators_and_converts/health_calculators_page.dart +++ b/lib/presentation/health_calculators_and_converts/health_calculators_page.dart @@ -135,8 +135,8 @@ class _HealthCalculatorsPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ - LocaleKeys.bloodSugar.tr().toText16(isBold: true), - LocaleKeys.trackYourGlucoseLevels.tr().toText12( + LocaleKeys.bloodSugar.tr(context: context).toText16(isBold: true), + LocaleKeys.trackYourGlucoseLevels.tr(context: context).toText12( isBold: true, color: Color(0xFF8F9AA3), ) @@ -168,7 +168,7 @@ class _HealthCalculatorsPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, - children: [LocaleKeys.bloodCholesterol.tr().toText16(isBold: true), LocaleKeys.monitorCholesterolLevels.tr().toText12(isBold: true, color: Color(0xFF8F9AA3))], + children: [LocaleKeys.bloodCholesterol.tr(context: context).toText16(isBold: true), LocaleKeys.monitorCholesterolLevels.tr(context: context).toText12(isBold: true, color: Color(0xFF8F9AA3))], ), ), SizedBox(width: 12.w), @@ -195,8 +195,8 @@ class _HealthCalculatorsPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ - LocaleKeys.triglyceridesFatBlood.tr().toText16(isBold: true), - LocaleKeys.understandTriglyceridesImpact.tr().toText12(isBold: true, color: Color(0xFF8F9AA3)) + LocaleKeys.triglyceridesFatBlood.tr(context: context).toText16(isBold: true), + LocaleKeys.understandTriglyceridesImpact.tr(context: context).toText12(isBold: true, color: Color(0xFF8F9AA3)) ], ), ), diff --git a/lib/presentation/health_trackers/add_health_tracker_entry_page.dart b/lib/presentation/health_trackers/add_health_tracker_entry_page.dart index 0305eebf..829c4a95 100644 --- a/lib/presentation/health_trackers/add_health_tracker_entry_page.dart +++ b/lib/presentation/health_trackers/add_health_tracker_entry_page.dart @@ -154,7 +154,8 @@ class _AddHealthTrackerEntryPageState extends State { } // Show success message and pop back - void _showSuccessAndPop() { + + void _showSuccessAndPop() async{ showCommonBottomSheetWithoutHeight( context, child: Utils.getSuccessWidget( @@ -164,7 +165,13 @@ class _AddHealthTrackerEntryPageState extends State { }, isCloseButtonVisible: false, isDismissible: true, - isFullScreen: false, isAutoDismiss: true); + isFullScreen: false, isAutoDismiss: false); + await Future.delayed(Duration(milliseconds: 2000)).then((value) { + if (mounted){ + Navigator.pop(context); + Navigator.pop(context); + } + }); } // Reusable method to build selection row widget @@ -366,7 +373,7 @@ class _AddHealthTrackerEntryPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - "Unit".toText12(isBold: true, color: AppColors.inputLabelTextColor), + LocaleKeys.unit.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor), unit.toText12(isBold: true, color: AppColors.textColor), ], ), @@ -473,7 +480,7 @@ class _AddHealthTrackerEntryPageState extends State { controller: dateController, isReadOnly: true, isArrowTrailing: true, - labelText: "Date", + labelText: LocaleKeys.date.tr(context: context), hintText: LocaleKeys.pickADate.tr(context: context), focusNode: FocusNode(), isEnable: true, @@ -503,7 +510,7 @@ class _AddHealthTrackerEntryPageState extends State { controller: timeController, isReadOnly: true, isArrowTrailing: true, - labelText: "Time", + labelText: LocaleKeys.time.tr(context: context), hintText: LocaleKeys.selectMeasureTime.tr(context: context), focusNode: FocusNode(), isEnable: true, diff --git a/lib/presentation/health_trackers/health_trackers_page.dart b/lib/presentation/health_trackers/health_trackers_page.dart index e974773c..e066b106 100644 --- a/lib/presentation/health_trackers/health_trackers_page.dart +++ b/lib/presentation/health_trackers/health_trackers_page.dart @@ -84,7 +84,7 @@ class _HealthTrackersPageState extends State { iconBgColor: AppColors.primaryRedColor, icon: AppAssets.bloodSugarOnlyIcon, title: LocaleKeys.bloodSugar.tr(context: context), - description: "Track your glucose levels, understand trends, and get personalized insights for better health.", + description: LocaleKeys.trackYourGlucoseLevels.tr(context: context), onTap: () { context.navigateWithName( AppRoutes.healthTrackerDetailPage, diff --git a/lib/presentation/hmg_services/services_page.dart b/lib/presentation/hmg_services/services_page.dart index 4f648c96..56923038 100644 --- a/lib/presentation/hmg_services/services_page.dart +++ b/lib/presentation/hmg_services/services_page.dart @@ -32,6 +32,7 @@ import 'package:hmg_patient_app_new/presentation/hmg_services/services_view.dart import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart'; import 'package:hmg_patient_app_new/presentation/home/service_info_page.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart'; +import 'package:hmg_patient_app_new/presentation/hmg_services/widgets/weather_widget.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; import 'package:hmg_patient_app_new/presentation/parking/paking_page.dart'; import 'package:hmg_patient_app_new/presentation/servicesPriceList/services_price_list_page.dart'; @@ -378,8 +379,8 @@ class _ServicesPageState extends State { void initState() { // TODO: implement initState super.initState(); - //weatherVM = getIt(); - // weatherVM.fetchCityInfoList(); + weatherVM = getIt(); + weatherVM.fetchCityInfoList(); } @@ -390,85 +391,18 @@ class _ServicesPageState extends State { medicalFileViewModel = Provider.of(context); hmgServices.removeWhere((element) => Utils.havePrivilege(element.action) == false); - return Scaffold( - backgroundColor: AppColors.bgScaffoldColor, - body: CollapsingListView( - title: LocaleKeys.exploreServices.tr(), - isLeading: widget.showBackIcon, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Row( - // children: [ - // Flexible( - // child: Container( - // padding: EdgeInsets.all(16.w), - // decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false), - // child: Column( - // children: [ - // Row( - // children: [ - // Utils.buildSvgWithAssets(icon: "assets/images/svg/cloudyweather.svg", width: 64.w, height: 64.w).onPress(() { - // // locationUtils?.getCurrentLocation(); - // print(getIt.get().userLat); - // print(getIt.get().userLong); - // }), - // SizedBox(width: 12.w), - // Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // "August 19, 2025 - Tuesday, 11:25 ".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), - // SizedBox( - // height: 4.w, - // ), - // "Cloudy 38oC".toText16(isBold: true, weight: FontWeight.w600), - // SizedBox( - // height: 4.w, - // ), - // "Health tips based on current weather".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500) - // ], - // ), - // ], - // ), - // SizedBox(height: 16.w), - // Container( - // padding: EdgeInsets.all(16.w), - // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - // color: AppColors.lightGrayBGColor, - // borderRadius: 10.r, - // hasShadow: false, - // ), - // child: Row( - // crossAxisAlignment: CrossAxisAlignment.center, - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // Row( - // children: [ - // Utils.buildSvgWithAssets(icon: "assets/images/svg/morning.svg", width: 24.w, height: 24.h), - // SizedBox(width: 4.w), - // DateTime.now().toLocal().toString().substring(11, 16).toText14(isBold: true), - // ], - // ), - // SizedBox(width: 25.w), - // DateTime.now().toLocal().toString().substring(11, 16).toText14(isBold: true), - // SizedBox(width: 25.w), - // Row( - // children: [ - // Utils.buildSvgWithAssets(icon: "assets/images/svg/evening.svg", width: 24.w, height: 24.h), - // SizedBox(width: 4.w), - // DateTime.now().toLocal().toString().substring(11, 16).toText14(isBold: true), - // ], - // ), - // ], - // ).expanded, - // ).paddingSymmetrical(0.w, 8.w) - // ], - // ), - // ), - // ) - // ], - // ).paddingSymmetrical(24.w, 0.w), - SizedBox(height: 16.h), + return ChangeNotifierProvider.value( + value: weatherVM, + child: Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: CollapsingListView( + title: LocaleKeys.exploreServices.tr(), + isLeading: widget.showBackIcon, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const WeatherWidget(), + SizedBox(height: 16.h), LocaleKeys.medicalAndCareServices.tr().toText18(isBold: true).paddingSymmetrical(24.w, 0), SizedBox(height: 16.h), GridView.builder( @@ -910,6 +844,7 @@ class _ServicesPageState extends State { ], ), ), + ), ); } } diff --git a/lib/presentation/hmg_services/widgets/weather_widget.dart b/lib/presentation/hmg_services/widgets/weather_widget.dart new file mode 100644 index 00000000..4c353763 --- /dev/null +++ b/lib/presentation/hmg_services/widgets/weather_widget.dart @@ -0,0 +1,194 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/weather/weather_view_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/weather/weather_details_page.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; +import 'package:provider/provider.dart'; + +class WeatherWidget extends StatelessWidget { + final bool showButton; + + const WeatherWidget({super.key, this.showButton = true}); + + String _getWeatherIcon(String? categoryValue) { + if (categoryValue == null) return "assets/images/svg/cloudyweather.svg"; + + final lowerValue = categoryValue.toLowerCase(); + if (lowerValue.contains('sunny') || lowerValue.contains('clear')) { + return "assets/images/svg/morning.svg"; + } else if (lowerValue.contains('cloudy') || lowerValue.contains('cloud')) { + return "assets/images/svg/cloudyweather.svg"; + } else if (lowerValue.contains('rain')) { + return "assets/images/svg/cloudyweather.svg"; + } + return "assets/images/svg/cloudyweather.svg"; + } + + String _formatDateTime(DateTime dateTime) { + final formatter = DateFormat('MMMM dd, yyyy - EEEE, HH:mm'); + return formatter.format(dateTime); + } + + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, weatherVM, child) { + final currentCity = weatherVM.cityInfoList.isNotEmpty + ? weatherVM.cityInfoList.first + : null; + + final now = DateTime.now(); + final temperature = currentCity?.temperature; + final healthTip = LocaleKeys.healthTipsBasedOnCurrentWeather.tr(); + + return Row( + children: [ + Flexible( + child: Container( + padding: EdgeInsets.all(16.w), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: false, + ), + child: weatherVM.isLoading + ? _buildLoadingState() + : Column( + children: [ + Row( + children: [ + Utils.buildSvgWithAssets( + icon: _getWeatherIcon(currentCity?.categoryValue), + width: 64.w, + height: 64.w, + ), + SizedBox(width: 12.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _formatDateTime(now).toText12( + fontWeight: FontWeight.w500, + color: AppColors.greyTextColor, + ), + SizedBox(height: 4.w), + "$temperature°C" + .toText16( + isBold: true, + weight: FontWeight.w600, + ), + SizedBox(height: 4.w), + healthTip.toText12( + color: AppColors.greyTextColor, + fontWeight: FontWeight.w500, + maxLine: 2, + ), + ], + ), + ), + ], + ), + if (showButton) ...[ + SizedBox(height: 16.w), + CustomButton( + text: LocaleKeys.viewDetails.tr(context: context), + onPressed: () { + Navigator.of(context).push( + CustomPageRoute( + page: ChangeNotifierProvider.value( + value: weatherVM, + child: const WeatherDetailsPage(), + ), + ), + ); + }, + padding: EdgeInsets.zero, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 14.f, + fontWeight: FontWeight.w600, + borderRadius: 10.r, + height: 40.h, + ), + ], + ], + ), + ), + ), + ], + ).paddingSymmetrical(24.w, 0.w); + }, + ); + } + + Widget _buildLoadingState() { + return Column( + children: [ + Row( + children: [ + Container( + width: 64.w, + height: 64.w, + decoration: BoxDecoration( + color: AppColors.lightGrayBGColor, + borderRadius: BorderRadius.circular(12.r), + ), + ), + SizedBox(width: 12.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: double.infinity, + height: 12.h, + decoration: BoxDecoration( + color: AppColors.lightGrayBGColor, + borderRadius: BorderRadius.circular(6.r), + ), + ), + SizedBox(height: 8.h), + Container( + width: 100.w, + height: 16.h, + decoration: BoxDecoration( + color: AppColors.lightGrayBGColor, + borderRadius: BorderRadius.circular(8.r), + ), + ), + SizedBox(height: 8.h), + Container( + width: double.infinity, + height: 12.h, + decoration: BoxDecoration( + color: AppColors.lightGrayBGColor, + borderRadius: BorderRadius.circular(6.r), + ), + ), + ], + ), + ), + ], + ), + SizedBox(height: 16.w), + Container( + height: 56.h, + decoration: BoxDecoration( + color: AppColors.lightGrayBGColor, + borderRadius: BorderRadius.circular(10.r), + ), + ), + ], + ); + } +} + diff --git a/lib/presentation/insurance/insurance_approval_details_page.dart b/lib/presentation/insurance/insurance_approval_details_page.dart index 6589bc4e..6d8e2524 100644 --- a/lib/presentation/insurance/insurance_approval_details_page.dart +++ b/lib/presentation/insurance/insurance_approval_details_page.dart @@ -53,8 +53,16 @@ class InsuranceApprovalDetailsPage extends StatelessWidget { children: [ AppCustomChipWidget( labelText: insuranceApprovalResponseModel.approvalStatusDescption, - backgroundColor: insuranceApprovalResponseModel.status == 9 ? AppColors.successColor.withOpacity(0.1) : AppColors.primaryRedColor.withOpacity(0.1), - textColor: insuranceApprovalResponseModel.status == 9 ? AppColors.successColor : AppColors.primaryRedColor, + backgroundColor: insuranceApprovalResponseModel.status == 9 + ? AppColors.successColor.withValues(alpha: 0.1) + : (insuranceApprovalResponseModel.approvalStatusDescption?.toLowerCase().contains('partial') == true || insuranceApprovalResponseModel.status == 8) + ? AppColors.warningColorYellow.withValues(alpha: 0.1) + : AppColors.primaryRedColor.withValues(alpha: 0.1), + textColor: insuranceApprovalResponseModel.status == 9 + ? AppColors.successColor + : (insuranceApprovalResponseModel.approvalStatusDescption?.toLowerCase().contains('partial') == true || insuranceApprovalResponseModel.status == 8) + ? AppColors.warningColorYellow + : AppColors.primaryRedColor, ), AppCustomChipWidget( icon: (!insuranceApprovalResponseModel.isLiveCareAppointment! ? AppAssets.walkin_appointment_icon : AppAssets.small_livecare_icon), @@ -65,7 +73,7 @@ class InsuranceApprovalDetailsPage extends StatelessWidget { ), AppCustomChipWidget( labelText: appState.isArabic() ? insuranceApprovalResponseModel.isInOutPatientDescriptionN! : insuranceApprovalResponseModel.isInOutPatientDescription!, - backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), + backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.1), textColor: AppColors.warningColorYellow, ), ], diff --git a/lib/presentation/insurance/widgets/insurance_approval_card.dart b/lib/presentation/insurance/widgets/insurance_approval_card.dart index b50e199f..a12a26b6 100644 --- a/lib/presentation/insurance/widgets/insurance_approval_card.dart +++ b/lib/presentation/insurance/widgets/insurance_approval_card.dart @@ -24,6 +24,34 @@ class InsuranceApprovalCard extends StatelessWidget { AppState appState; bool isLoading; + /// Helper method to determine if approval is partially approved + bool _isPartiallyApproved() { + final description = insuranceApprovalResponseModel.approvalStatusDescption?.toLowerCase() ?? ''; + return description.contains('partial') || insuranceApprovalResponseModel.status == 8; + } + + /// Helper method to get chip background color based on approval status + Color _getChipBackgroundColor() { + if (insuranceApprovalResponseModel.status == 9) { + return AppColors.successColor.withValues(alpha: 0.1); + } else if (_isPartiallyApproved()) { + return AppColors.warningColorYellow.withValues(alpha: 0.1); + } else { + return AppColors.primaryRedColor.withValues(alpha: 0.1); + } + } + + /// Helper method to get chip text color based on approval status + Color _getChipTextColor() { + if (insuranceApprovalResponseModel.status == 9) { + return AppColors.successColor; + } else if (_isPartiallyApproved()) { + return AppColors.warningColorYellow; + } else { + return AppColors.primaryRedColor; + } + } + @override Widget build(BuildContext context) { return Container( @@ -45,8 +73,8 @@ class InsuranceApprovalCard extends StatelessWidget { children: [ AppCustomChipWidget( labelText: isLoading ? "Approved" : insuranceApprovalResponseModel.approvalStatusDescption, - backgroundColor: insuranceApprovalResponseModel.status == 9 ? AppColors.successColor.withOpacity(0.1) : AppColors.primaryRedColor.withOpacity(0.1), - textColor: insuranceApprovalResponseModel.status == 9 ? AppColors.successColor : AppColors.primaryRedColor, + backgroundColor: isLoading ? AppColors.successColor.withValues(alpha: 0.1) : _getChipBackgroundColor(), + textColor: isLoading ? AppColors.successColor : _getChipTextColor(), ).toShimmer2(isShow: isLoading), AppCustomChipWidget( icon: isLoading ? AppAssets.walkin_appointment_icon : (!insuranceApprovalResponseModel.isLiveCareAppointment! ? AppAssets.walkin_appointment_icon : AppAssets.small_livecare_icon), @@ -69,7 +97,7 @@ class InsuranceApprovalCard extends StatelessWidget { : appState.isArabic() ? insuranceApprovalResponseModel.isInOutPatientDescriptionN! : insuranceApprovalResponseModel.isInOutPatientDescription!, - backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), + backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.1), textColor: AppColors.warningColorYellow, ).toShimmer2(isShow: isLoading), ], diff --git a/lib/presentation/weather/weather_details_page.dart b/lib/presentation/weather/weather_details_page.dart new file mode 100644 index 00000000..0057f9b6 --- /dev/null +++ b/lib/presentation/weather/weather_details_page.dart @@ -0,0 +1,185 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/weather/models/waether_cities_model.dart'; +import 'package:hmg_patient_app_new/features/weather/weather_view_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/hmg_services/widgets/weather_widget.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:provider/provider.dart'; + +class WeatherDetailsPage extends StatelessWidget { + const WeatherDetailsPage({super.key}); + + Color _getColorFromColorName(ColorName? colorName) { + if (colorName == null) return AppColors.successColor; + + switch (colorName) { + case ColorName.GREEN: + return AppColors.successColor; + case ColorName.ORANGE: + return AppColors.warningColor; + case ColorName.RED: + return AppColors.errorColor; + } + } + + Color _getBackgroundColorFromColorName(ColorName? colorName) { + if (colorName == null) return AppColors.successLightColor.withValues(alpha: 0.1); + + switch (colorName) { + case ColorName.GREEN: + return AppColors.successLightColor.withValues(alpha: 0.1); + case ColorName.ORANGE: + return AppColors.warningLightColor.withValues(alpha: 0.1); + case ColorName.RED: + return AppColors.errorLightColor.withValues(alpha: 0.1); + } + } + + IconData _getIconFromCategory(String? category) { + if (category == null) return Icons.wb_sunny_outlined; + + final lowerCategory = category.toLowerCase(); + if (lowerCategory.contains('walking') || lowerCategory.contains('activity')) { + return Icons.directions_walk; + } else if (lowerCategory.contains('weather') || lowerCategory.contains('temperature')) { + return Icons.thermostat_outlined; + } else if (lowerCategory.contains('elderly') || lowerCategory.contains('hiking')) { + return Icons.elderly; + } + return Icons.wb_sunny_outlined; + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, weatherVM, child) { + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: CollapsingListView( + title: LocaleKeys.healthWeatherIndicators.tr(), + isLeading: true, + child: weatherVM.isLoading + ? Center( + child: CircularProgressIndicator( + color: AppColors.primaryRedColor, + ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Reuse WeatherWidget at the top (without the button) + const WeatherWidget(showButton: false), + + SizedBox(height: 16.h), + + // Categories List (Sliders) + ...weatherVM.cityInfoList.map((cityInfo) { + return _buildCategoryCard( + description: cityInfo.name ?? '', + categoryLabel: cityInfo.category ?? '', + color: _getColorFromColorName(cityInfo.colorName), + backgroundColor: _getBackgroundColorFromColorName(cityInfo.colorName), + icon: _getIconFromCategory(cityInfo.category), + ); + }), + + SizedBox(height: 24.h), + ], + ), + ), + ); + }, + ); + } + + Widget _buildCategoryCard({ + required String description, + required String categoryLabel, + required Color color, + required Color backgroundColor, + required IconData icon, + }) { + return Container( + margin: EdgeInsets.only(bottom: 16.h), + padding: EdgeInsets.all(16.w), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 16.r, + hasShadow: false, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Icon + Container( + width: 40.w, + height: 40.w, + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(8.r), + ), + child: Icon( + icon, + color: color, + size: 24.w, + ), + ), + SizedBox(width: 12.w), + // Content + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + description.toText14( + isBold: true, + color: AppColors.textColor, + ), + SizedBox(height: 8.h), + // Progress bar + Container( + height: 4.h, + decoration: BoxDecoration( + color: AppColors.lightGrayBGColor, + borderRadius: BorderRadius.circular(2.r), + ), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: 0.7, + child: Container( + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(2.r), + ), + ), + ), + ), + ], + ), + ), + SizedBox(width: 12.w), + // Category Label + Container( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(8.r), + ), + child: categoryLabel.toText12( + color: color, + fontWeight: FontWeight.w600, + maxLine: 1 + ), + ), + ], + ), + ).paddingSymmetrical(24.w, 0.w); + } +} + diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index d8a74d17..b1a0883f 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -269,10 +269,10 @@ class TextInputWidget extends StatelessWidget { final picked = await TimePickerWidget.show( context, initialTime: initialTime, - use24HourFormat: false, // You can make this configurable if needed + use24HourFormat: true, onTimeSelected: (time) { if (onChange != null) { - final formattedTime = TimePickerWidget.formatTime(time); + final formattedTime = TimePickerWidget.formatTime(time, use24HourFormat: true); onChange!(formattedTime); } }, @@ -280,7 +280,7 @@ class TextInputWidget extends StatelessWidget { // Update controller if time was picked if (picked != null && controller != null) { - controller!.text = TimePickerWidget.formatTime(picked); + controller!.text = TimePickerWidget.formatTime(picked, use24HourFormat: true); } }, child: Utils.buildSvgWithAssets(icon: isArrowTrailing ? AppAssets.arrow_down : AppAssets.alarm_clock_icon), diff --git a/lib/widgets/time_picker_widget.dart b/lib/widgets/time_picker_widget.dart index fd5cb409..eadbf5f3 100644 --- a/lib/widgets/time_picker_widget.dart +++ b/lib/widgets/time_picker_widget.dart @@ -1,3 +1,5 @@ +import 'dart:ui' as ui; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -126,48 +128,50 @@ class _TimePickerBottomSheetState extends State<_TimePickerBottomSheet> { @override Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - color: AppColors.whiteColor, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20.r), - topRight: Radius.circular(20.r), + return Directionality( + textDirection: ui.TextDirection.ltr, + child: Container( + decoration: BoxDecoration( + color: AppColors.whiteColor, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20.r), + topRight: Radius.circular(20.r), + ), ), - ), - child: SafeArea( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - // Header - Container( - padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: AppColors.dividerColor, - width: 1, + child: SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Header + Container( + padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: AppColors.dividerColor, + width: 1, + ), ), ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - LocaleKeys.selectTime.tr(context: context).toText18( - weight: FontWeight.w600, - color: AppColors.textColor, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.selectTime.tr(context: context).toText18( + weight: FontWeight.w600, + color: AppColors.textColor, + ), + GestureDetector( + onTap: () => Navigator.pop(context), + child: Utils.buildSvgWithAssets( + icon: AppAssets.cancel, + width: 24.h, + height: 24.h, + iconColor: AppColors.textColor, ), - GestureDetector( - onTap: () => Navigator.pop(context), - child: Utils.buildSvgWithAssets( - icon: AppAssets.cancel, - width: 24.h, - height: 24.h, - iconColor: AppColors.textColor, ), - ), - ], + ], + ), ), - ), // Time Picker SizedBox( @@ -345,6 +349,7 @@ class _TimePickerBottomSheetState extends State<_TimePickerBottomSheet> { ], ), ), + ), ); } }