From 803d74ccebc0576df9ec6ee564645864ecf5b4f0 Mon Sep 17 00:00:00 2001 From: FaizHashmi Date: Tue, 22 Sep 2026 16:50:37 +0300 Subject: [PATCH] Dynamic theming has been implemented --- lib/core/api/api_client.dart | 97 +++++----- lib/core/api_consts.dart | 3 +- .../appointment_details_page.dart | 4 +- .../appointments/my_appointments_page.dart | 10 +- .../widgets/appointment_doctor_card.dart | 33 ++-- .../widgets/appointment_rating_widget.dart | 6 +- .../authentication/quick_login.dart | 4 +- .../book_appointment_page.dart | 10 +- .../book_appointment/doctor_profile_page.dart | 44 ++--- .../laser/laser_appointment.dart | 4 +- .../book_appointment/widgets/doctor_card.dart | 6 +- lib/presentation/home/landing_page.dart | 25 ++- lib/presentation/lab/alphabeticScroll.dart | 165 ++++++++---------- lib/presentation/lab/lab_order_by_test.dart | 115 ++++++------ lib/presentation/lab/lab_orders_page.dart | 2 +- .../my_invoices/my_invoices_list.dart | 57 +++--- .../onboarding/onboarding_screen.dart | 2 +- .../onboarding/splash_animation_screen.dart | 6 +- .../rate_appointment_clinic.dart | 6 +- .../rate_appointment_doctor.dart | 6 +- .../smartwatches/activity_detail.dart | 4 +- .../health_dashboard/health_dashboard.dart | 4 +- .../widgets/ancillary_orders_list.dart | 6 +- .../widgets/ancillary_procedures_list.dart | 6 +- lib/theme/colors.dart | 2 +- lib/widgets/buttons/custom_button.dart | 14 +- 26 files changed, 289 insertions(+), 352 deletions(-) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 4c961843..5454c2f4 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -138,8 +138,7 @@ class ApiClientImp implements ApiClient { } else {} if (body.containsKey('isDentalAllowedBackend')) { - body['isDentalAllowedBackend'] = - body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND; + body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND; } if (!body.containsKey('IsPublicRequest')) { @@ -271,11 +270,11 @@ class ApiClientImp implements ApiClient { Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim())); Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint)); Clarity.setCustomTag('api_err_method', 'POST'); - + if (_appState.isAuthenticated) { Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString()); } - + Clarity.sendCustomEvent('api_socket_exception'); return; @@ -283,19 +282,19 @@ class ApiClientImp implements ApiClient { final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr(); onFailure(message, -1, failureType: ConnectivityFailure(message)); _analytics.errorTracking.log(endPoint, error: "ClientException: $e"); - + // Enhanced Clarity logging Clarity.setCustomTag('api_err_type', 'client_exception'); Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim())); Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint)); Clarity.setCustomTag('api_err_method', 'POST'); - + if (_appState.isAuthenticated) { Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString()); } - + Clarity.sendCustomEvent('api_client_exception'); - + return; } on TimeoutException catch (_) { final message = LocaleKeys.networkTimeout.tr(); @@ -307,36 +306,36 @@ class ApiClientImp implements ApiClient { Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim())); Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint)); Clarity.setCustomTag('api_err_method', 'POST'); - + if (_appState.isAuthenticated) { Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString()); } - + Clarity.sendCustomEvent('api_timeout'); - + return; } catch (e) { final message = LocaleKeys.networkUnknownError.tr(); onFailure(message, -1, failureType: ConnectivityFailure(message)); _analytics.errorTracking.log(endPoint, error: "UnknownException: $e"); - + // Enhanced Clarity logging for unknown errors Clarity.setCustomTag('api_err_type', 'unknown_exception'); Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim())); Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint)); Clarity.setCustomTag('api_err_method', 'POST'); - + // Truncate exception message for Clarity final exceptionMsg = e.toString(); final truncatedMsg = exceptionMsg.length > 252 ? '...${exceptionMsg.substring(exceptionMsg.length - 252)}' : exceptionMsg; Clarity.setCustomTag('api_err_exception', truncatedMsg); - + if (_appState.isAuthenticated) { Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString()); } - + Clarity.sendCustomEvent('api_unknown_exception'); - + return; } @@ -384,24 +383,19 @@ class ApiClientImp implements ApiClient { onFailure( parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode, - failureType: - UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url), + failureType: UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url), ); // logApiEndpointError(endPoint, "session logged out", statusCode); } if (isAllowAny) { - onSuccess(parsed, statusCode, - messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else if (parsed['IsAuthenticated'] == null) { if (parsed['isSMSSent'] == true) { - onSuccess(parsed, statusCode, - messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else if (parsed['MessageStatus'] == 1) { - onSuccess(parsed, statusCode, - messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else if (parsed['Result'] == 'OK') { - onSuccess(parsed, statusCode, - messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else { onFailure( parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], @@ -411,8 +405,7 @@ class ApiClientImp implements ApiClient { logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { - onSuccess(parsed, statusCode, - messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } // else if (parsed['IsAuthenticated'] == false) { // onFailure( @@ -424,8 +417,7 @@ class ApiClientImp implements ApiClient { // } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode, - messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else { if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['ErrorSearchMsg'] == null) { @@ -459,8 +451,7 @@ class ApiClientImp implements ApiClient { } } else { if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode, - messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else { if (parsed['message'] != null) { onFailure( @@ -537,74 +528,74 @@ class ApiClientImp implements ApiClient { final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr(); onFailure(message, -1); _analytics.errorTracking.log(endPoint, error: "SocketException: $e"); - + // Clarity logging for GET requests Clarity.setCustomTag('api_err_type', 'socket_exception'); Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim())); Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint)); Clarity.setCustomTag('api_err_method', 'GET'); - + if (_appState.isAuthenticated) { Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString()); } - + Clarity.sendCustomEvent('api_get_socket_exception'); - + return; } on http.ClientException catch (e) { final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr(); onFailure(message, -1); _analytics.errorTracking.log(endPoint, error: "ClientException: $e"); - + Clarity.setCustomTag('api_err_type', 'client_exception'); Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim())); Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint)); Clarity.setCustomTag('api_err_method', 'GET'); - + if (_appState.isAuthenticated) { Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString()); } - + Clarity.sendCustomEvent('api_get_client_exception'); - + return; } on TimeoutException catch (_) { final message = LocaleKeys.networkTimeout.tr(); onFailure(message, -1); _analytics.errorTracking.log(endPoint, error: "TimeoutException"); - + Clarity.setCustomTag('api_err_type', 'timeout'); Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim())); Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint)); Clarity.setCustomTag('api_err_method', 'GET'); - + if (_appState.isAuthenticated) { Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString()); } - + Clarity.sendCustomEvent('api_get_timeout'); - + return; } catch (e) { final message = LocaleKeys.networkUnknownError.tr(); onFailure(message, -1); _analytics.errorTracking.log(endPoint, error: "UnknownException: $e"); - + Clarity.setCustomTag('api_err_type', 'unknown_exception'); Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim())); Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint)); Clarity.setCustomTag('api_err_method', 'GET'); - + final exceptionMsg = e.toString(); final truncatedMsg = exceptionMsg.length > 252 ? '...${exceptionMsg.substring(exceptionMsg.length - 252)}' : exceptionMsg; Clarity.setCustomTag('api_err_exception', truncatedMsg); - + if (_appState.isAuthenticated) { Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString()); } - + Clarity.sendCustomEvent('api_get_unknown_exception'); - + return; } @@ -614,18 +605,18 @@ class ApiClientImp implements ApiClient { if (statusCode < 200 || statusCode >= 400) { onFailure(LocaleKeys.networkErrorWhileFetching.tr(), statusCode); logApiEndpointError(endPoint, LocaleKeys.networkErrorWhileFetching.tr(), statusCode); - + // Clarity logging for GET status code errors Clarity.setCustomTag('api_err_type', 'status_code_error'); Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim())); Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint)); Clarity.setCustomTag('api_err_method', 'GET'); Clarity.setCustomTag('api_err_status', statusCode.toString()); - + if (_appState.isAuthenticated) { Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString()); } - + Clarity.sendCustomEvent('api_get_status_error'); } else { var parsed = json.decode(utf8.decode(response.bodyBytes)); @@ -813,7 +804,7 @@ class ApiClientImp implements ApiClient { // Extract the last part of the endpoint path for cleaner tracking const int clarityLimit = 100; final cleanEndpoint = endpoint.split('/').last; - + if (cleanEndpoint.length <= clarityLimit) return cleanEndpoint; return '...${cleanEndpoint.substring(cleanEndpoint.length - (clarityLimit - 3))}'; } diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 45d6f48c..39e4a677 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -864,8 +864,7 @@ var GET_CUSTOMER_INFO = "VerifyCustomer"; //Pharmacy -var GET_PHARMACY_CATEGORISE = - 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0'; +var GET_PHARMACY_CATEGORISE = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0'; var GET_OFFERS_CATEGORISE = 'discountcategories'; var GET_OFFERS_PRODUCTS = 'offerproducts/'; var GET_CATEGORISE_PARENT = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id='; diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index dc147981..7d1d3f91 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -989,7 +989,7 @@ class _AppointmentDetailsPageState extends State { openDoctorScheduleCalendar(); }, backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, + borderColor: Colors.transparent, textColor: Colors.white, fontSize: 16.f, fontWeight: FontWeight.w600, @@ -1097,7 +1097,7 @@ class _AppointmentDetailsPageState extends State { openDoctorScheduleCalendar(); }, backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, + borderColor: Colors.transparent, textColor: Colors.white, fontSize: 16.f, fontWeight: FontWeight.w600, diff --git a/lib/presentation/appointments/my_appointments_page.dart b/lib/presentation/appointments/my_appointments_page.dart index da20e183..e15edb47 100644 --- a/lib/presentation/appointments/my_appointments_page.dart +++ b/lib/presentation/appointments/my_appointments_page.dart @@ -67,8 +67,8 @@ class _MyAppointmentsPageState extends State { SizedBox(height: 16.h), CustomTabBar( initialIndex: myAppointmentsVM.selectedTabIndex, - activeTextColor: Color(0xffED1C2B), - activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), + activeTextColor: AppColors.primaryRedColor, + activeBackgroundColor: AppColors.secondaryLightRedColor, tabs: [ // CustomTabBarModel(null, LocaleKeys.allAppt.tr(context: context)), CustomTabBarModel(null, LocaleKeys.upcoming.tr(context: context)), @@ -269,9 +269,9 @@ class _MyAppointmentsPageState extends State { ), ); }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, fontSize: 14.f, isBold: true, borderRadius: 12.r, diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index 4dd838ea..a3b13259 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -84,8 +84,7 @@ class AppointmentDoctorCard extends StatelessWidget { children: [ Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.h, height: 15.h, iconColor: AppColors.ratingColorYellow), SizedBox(height: 2.h), - "${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? 0.0}" - .toText11(isBold: true, color: AppColors.textColor, isEnglishOnly: true), + "${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? 0.0}".toText11(isBold: true, color: AppColors.textColor, isEnglishOnly: true), ], ), ).circle(100), @@ -102,11 +101,7 @@ class AppointmentDoctorCard extends StatelessWidget { children: [ Expanded( child: (patientAppointmentHistoryResponseModel.doctorNameObj ?? "").toText16( - isBold: true, - isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? ""), - textOverflow: TextOverflow.ellipsis, - maxlines: 2 - ), + isBold: true, isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? ""), textOverflow: TextOverflow.ellipsis, maxlines: 2), ), SizedBox(width: 12.w), // (patientAppointmentHistoryResponseModel.doctorNationalityFlagURL != null && @@ -142,18 +137,17 @@ class AppointmentDoctorCard extends StatelessWidget { child: AppCustomChipWidget( labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), icon: AppAssets.doctor_calendar_icon, - richText: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${(patientAppointmentHistoryResponseModel.startTime != null && patientAppointmentHistoryResponseModel.startTime!.isNotEmpty) ? patientAppointmentHistoryResponseModel.startTime!.substring(0, 5) : DateUtil.formatDateToTimeLang(DateUtil.convertStringToDateSaudiTimezone(patientAppointmentHistoryResponseModel.appointmentDate!, patientAppointmentHistoryResponseModel.projectID), false)}" - .toText10(isBold: true), + richText: + "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${(patientAppointmentHistoryResponseModel.startTime != null && patientAppointmentHistoryResponseModel.startTime!.isNotEmpty) ? patientAppointmentHistoryResponseModel.startTime!.substring(0, 5) : DateUtil.formatDateToTimeLang(DateUtil.convertStringToDateSaudiTimezone(patientAppointmentHistoryResponseModel.appointmentDate!, patientAppointmentHistoryResponseModel.projectID), false)}" + .toText10(isBold: true), ), ), ), AppCustomChipWidget( labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), - icon: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppAssets.walkin_appointment_icon - : AppAssets.small_livecare_icon, + icon: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppAssets.walkin_appointment_icon : AppAssets.small_livecare_icon, iconColor: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppColors.textColor : Colors.white, - labelText: (patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? LocaleKeys.livecare.tr(context: context) - : LocaleKeys.walkin.tr(context: context), + labelText: (patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? LocaleKeys.livecare.tr(context: context) : LocaleKeys.walkin.tr(context: context), backgroundColor: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppColors.greyColor : AppColors.successColor, textColor: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppColors.textColor : Colors.white, ), @@ -163,13 +157,12 @@ class AppointmentDoctorCard extends StatelessWidget { ), ), (patientAppointmentHistoryResponseModel.isLiveCareAppointment! || - patientAppointmentHistoryResponseModel.isExecludeDoctor! || + patientAppointmentHistoryResponseModel.isExecludeDoctor! || patientAppointmentHistoryResponseModel.isClinicReBookingAllowed! == false || patientAppointmentHistoryResponseModel.isActiveDoctor! == false || - !Utils.isClinicAllowedForRebook(patientAppointmentHistoryResponseModel.clinicID)) + !Utils.isClinicAllowedForRebook(patientAppointmentHistoryResponseModel.clinicID)) ? SizedBox.shrink() - : Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown) - .onPress(() async { + : Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).onPress(() async { // DoctorsListResponseModel selectedDoctor = DoctorsListResponseModel(); // selectedDoctor.doctorID = patientAppointmentHistoryResponseModel.doctorID; // selectedDoctor.doctorImageURL = patientAppointmentHistoryResponseModel.doctorImageURL; @@ -270,7 +263,7 @@ class AppointmentDoctorCard extends StatelessWidget { onAskDoctorTap(); }, backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, + borderColor: Colors.transparent, textColor: AppColors.primaryRedColor, fontSize: 14.f, isBold: true, @@ -310,7 +303,7 @@ class AppointmentDoctorCard extends StatelessWidget { onCancelTap(); }, backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, + borderColor: Colors.transparent, textColor: AppColors.whiteColor, fontSize: 14.f, isBold: true, @@ -329,7 +322,7 @@ class AppointmentDoctorCard extends StatelessWidget { onRescheduleTap(); }, backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, + borderColor: Colors.transparent, textColor: AppColors.primaryRedColor, fontSize: 14.f, isBold: true, diff --git a/lib/presentation/appointments/widgets/appointment_rating_widget.dart b/lib/presentation/appointments/widgets/appointment_rating_widget.dart index 9b13c6cd..ae70da1d 100644 --- a/lib/presentation/appointments/widgets/appointment_rating_widget.dart +++ b/lib/presentation/appointments/widgets/appointment_rating_widget.dart @@ -142,9 +142,9 @@ class _AppointmentRatingWidgetState extends State { Expanded( child: CustomButton( text: LocaleKeys.later.tr(context: context), - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, onPressed: () { Navigator.pop(context); }, diff --git a/lib/presentation/authentication/quick_login.dart b/lib/presentation/authentication/quick_login.dart index 0830b23e..00e872a3 100644 --- a/lib/presentation/authentication/quick_login.dart +++ b/lib/presentation/authentication/quick_login.dart @@ -114,7 +114,7 @@ class QuickLoginState extends State { Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - Expanded( + Expanded( child: CustomButton( text: LocaleKeys.notNow.tr(context: context), onPressed: () { @@ -122,7 +122,7 @@ class QuickLoginState extends State { Navigator.pop(context, "true"); }, backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, + borderColor: Colors.transparent, textColor: AppColors.primaryRedColor, height: 56.h, // icon: "assets/images/svg/apple-finder.svg", diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index c2560ecd..57b3d541 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -106,8 +106,8 @@ class _BookAppointmentPageState extends State { children: [ SizedBox(height: 16.h), CustomTabBar( - activeTextColor: Color(0xffED1C2B), - activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), + activeTextColor: AppColors.primaryRedColor, + activeBackgroundColor: AppColors.secondaryLightRedColor, initialIndex: bookAppointmentsVM.selectedTabIndex, tabs: [ CustomTabBarModel(null, LocaleKeys.general.tr(context: context)), @@ -326,9 +326,9 @@ class _BookAppointmentPageState extends State { onPressed: () { Navigator.of(context).push(CustomPageRoute(page: SearchDoctorByName())); }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, fontSize: 14.f, isBold: true, padding: EdgeInsets.fromLTRB(10.h, 0, 10.h, 0), diff --git a/lib/presentation/book_appointment/doctor_profile_page.dart b/lib/presentation/book_appointment/doctor_profile_page.dart index 5b6ad09d..ee4d859b 100644 --- a/lib/presentation/book_appointment/doctor_profile_page.dart +++ b/lib/presentation/book_appointment/doctor_profile_page.dart @@ -60,9 +60,7 @@ class DoctorProfilePage extends StatelessWidget { doctorID: viewModel.doctorsProfileResponseModel.doctorID ?? 0, isActive: viewModel.isFavouriteDoctor, onSuccess: (response) { - Utils.showToast(viewModel.isFavouriteDoctor - ? LocaleKeys.doctorAddedToFavourite.tr(context: context) - : LocaleKeys.doctorRemovedFromFavourite.tr(context: context)); + Utils.showToast(viewModel.isFavouriteDoctor ? LocaleKeys.doctorAddedToFavourite.tr(context: context) : LocaleKeys.doctorRemovedFromFavourite.tr(context: context)); // Successfully added/removed favorite - refresh the favorites list getIt.get().refreshFavouriteDoctors(); }, @@ -101,14 +99,11 @@ class DoctorProfilePage extends StatelessWidget { children: [ SizedBox( width: isFoldable ? 250.w : 220.w, - child: - ("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}") - .toString() - .toText24(isBold: true), + child: ("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}") + .toString() + .toText24(isBold: true), ), - (bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty - ? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first - : "") + (bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty ? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first : "") .toString() .toText18(isBold: true, color: AppColors.primaryRedColor), ], @@ -148,16 +143,12 @@ class DoctorProfilePage extends StatelessWidget { children: [ Column( children: [ - Utils.buildSvgWithAssets( - icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), + Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), SizedBox(height: 16.h), LocaleKeys.ratings.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor), - bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate.toString().toText16( - isBold: true, - color: AppColors.textColor, - isUnderLine: true, - decorationColor: AppColors.textColor, - fontFamily: "Poppins"), + bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate + .toString() + .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), ], ).onPress(() { bookAppointmentsViewModel.getDoctorRatingDetails(); @@ -173,18 +164,12 @@ class DoctorProfilePage extends StatelessWidget { SizedBox(width: 36.w), Column( children: [ - Utils.buildSvgWithAssets( - icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), + Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), SizedBox(height: 16.h), LocaleKeys.reviews.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor), NumberFormat.decimalPattern("en_US") .format(bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate ?? 0) - .toText16( - isBold: true, - color: AppColors.textColor, - isUnderLine: true, - decorationColor: AppColors.textColor, - fontFamily: "Poppins"), + .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), ], ).onPress(() { bookAppointmentsViewModel.getDoctorRatingDetails(); @@ -215,9 +200,7 @@ class DoctorProfilePage extends StatelessWidget { SizedBox(height: 16.h), LocaleKeys.information.tr(context: context).toText14(isBold: true, color: AppColors.textColor), SizedBox(height: 6.h), - (bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo ?? "") - .trim() - .toText12(isBold: true, color: AppColors.greyTextColor), + (bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo ?? "").trim().toText12(isBold: true, color: AppColors.greyTextColor), SizedBox(height: 24.h), ], ).paddingSymmetrical(24.h, 0.h), @@ -238,8 +221,7 @@ class DoctorProfilePage extends StatelessWidget { bookAppointmentsViewModel.selectedDoctor.specialityN = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty; bookAppointmentsViewModel.selectedDoctor.name = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName; bookAppointmentsViewModel.selectedDoctor.doctorImageURL = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL; - bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL = - bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL; + bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL = bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL; bookAppointmentsViewModel.selectedDoctor.clinicName = bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription; bookAppointmentsViewModel.selectedDoctor.projectName = bookAppointmentsViewModel.doctorsProfileResponseModel.projectName; diff --git a/lib/presentation/book_appointment/laser/laser_appointment.dart b/lib/presentation/book_appointment/laser/laser_appointment.dart index c8773933..affd5423 100644 --- a/lib/presentation/book_appointment/laser/laser_appointment.dart +++ b/lib/presentation/book_appointment/laser/laser_appointment.dart @@ -80,8 +80,8 @@ class LaserAppointment extends StatelessWidget { child: Column( children: [ CustomTabBar( - activeTextColor: Color(0xffED1C2B), - activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), + activeTextColor: AppColors.primaryRedColor, + activeBackgroundColor: AppColors.secondaryLightRedColor, tabs: [ CustomTabBarModel(null, LocaleKeys.malE.tr()), CustomTabBarModel(null, LocaleKeys.femaleGender.tr()), diff --git a/lib/presentation/book_appointment/widgets/doctor_card.dart b/lib/presentation/book_appointment/widgets/doctor_card.dart index 23a9cbcd..70f99303 100644 --- a/lib/presentation/book_appointment/widgets/doctor_card.dart +++ b/lib/presentation/book_appointment/widgets/doctor_card.dart @@ -308,9 +308,9 @@ class DoctorCard extends StatelessWidget { }); } }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, fontSize: 14.f, isBold: true, borderRadius: 10.r, diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index b7e537f1..a4f194bf 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -291,7 +291,6 @@ class _LandingPageState extends State { child: Column( children: [ const OccasionBannerWidget(), - Row( spacing: 8.h, mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -358,11 +357,11 @@ class _LandingPageState extends State { // ...existing commented code... }, backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, + borderColor: Colors.transparent, textColor: AppColors.primaryRedColor, fontSize: 14.f, fontWeight: FontWeight.w700, - borderRadius: 12.r, + borderRadius: 10.r, padding: EdgeInsets.fromLTRB(12.h, 0, 12.h, 0), height: 40.h, ), @@ -685,9 +684,9 @@ class _LandingPageState extends State { getIt.get().onTabChanged(0); Navigator.of(context).push(CustomPageRoute(page: BookAppointmentPage())); }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, fontSize: 14.f, fontWeight: FontWeight.w600, padding: EdgeInsets.fromLTRB(10.h, 0, 10.h, 0), @@ -1009,13 +1008,13 @@ class _LandingPageState extends State { ), ), ), - (appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown) + (appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown) ? Container( height: MediaQuery.paddingOf(context).top + 50.h, decoration: ShapeDecoration( - color: AppColors.secondaryLightRedBorderColor, + color: AppColors.secondaryLightRedColorBase, shape: SmoothRectangleBorder( - side: BorderSide(width: 1, color: AppColors.primaryRedColor.withAlpha(20)), + side: BorderSide(width: 1, color: AppColors.primaryRedColorBase.withAlpha(20)), // borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), smoothness: 1, ), @@ -1026,7 +1025,7 @@ class _LandingPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, isBold: true).paddingSymmetrical(0.h, 0.h), + LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColorBase, isBold: true).paddingSymmetrical(0.h, 0.h), Row( children: [ CustomButton( @@ -1038,8 +1037,8 @@ class _LandingPageState extends State { showCommonBottomSheetWithoutHeight(context, child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); }, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.secondaryLightRedBorderColor, + backgroundColor: AppColors.primaryRedColorBase, + borderColor: AppColors.primaryRedColorBase, textColor: Colors.white, fontSize: 12.f, fontWeight: FontWeight.bold, @@ -1047,7 +1046,7 @@ class _LandingPageState extends State { padding: EdgeInsets.fromLTRB(15, 0, 15, 0), height: 36.h, ).paddingSymmetrical(12.h, 0.h), - Icon(Icons.close, color: AppColors.primaryRedColor).onPress(() { + Icon(Icons.close, color: AppColors.primaryRedColorBase).onPress(() { insuranceVM.setIsInsuranceExpiryBannerShown(false); }), ], diff --git a/lib/presentation/lab/alphabeticScroll.dart b/lib/presentation/lab/alphabeticScroll.dart index ff0efbf4..a1a9add8 100644 --- a/lib/presentation/lab/alphabeticScroll.dart +++ b/lib/presentation/lab/alphabeticScroll.dart @@ -14,8 +14,8 @@ import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'lab_order_by_test.dart'; -class AlphabeticScroll extends StatefulWidget{ - final List alpahbetsAvailable; +class AlphabeticScroll extends StatefulWidget { + final List alpahbetsAvailable; final List details; final AppState appState; final LabViewModel labViewModel; @@ -38,13 +38,13 @@ class _AlphabetScrollPageState extends State { Map density = {}; Map _offsetMap = {}; - Map _offsetKeys = {}; + Map _offsetKeys = {}; int _activeIndex = 0; // <-- Highlighted letter @override void initState() { super.initState(); - scheduleMicrotask((){ + scheduleMicrotask(() { _rebuildData(); }); itemPositionsListener.itemPositions.addListener(_onPositionChanged); @@ -61,9 +61,7 @@ class _AlphabetScrollPageState extends State { void _rebuildData() { data.clear(); for (var char in widget.alpahbetsAvailable) { - data[char] = widget.details - .where((element) => element.description?.toLowerCase().startsWith(char.toLowerCase()) == true) - .toList(); + data[char] = widget.details.where((element) => element.description?.toLowerCase().startsWith(char.toLowerCase()) == true).toList(); } if (_activeIndex >= widget.alpahbetsAvailable.length) { _activeIndex = 0; @@ -79,15 +77,12 @@ class _AlphabetScrollPageState extends State { // Get FIRST visible item (top-most) final firstVisible = positions .where((p) => p.itemTrailingEdge > 0) // visible - .reduce((min, p) => - p.itemLeadingEdge < min.itemLeadingEdge ? p : min); + .reduce((min, p) => p.itemLeadingEdge < min.itemLeadingEdge ? p : min); - if(_activeIndex == firstVisible.index) return ; + if (_activeIndex == firstVisible.index) return; setState(() { _activeIndex = firstVisible.index; }); - - print("Active index = $_activeIndex"); } @override @@ -97,12 +92,8 @@ class _AlphabetScrollPageState extends State { } void _scrollToLetter(String letter) async { - // itemScrollController.jumpTo(index:density[letter]?.toInt()??0, ); - itemScrollController.scrollTo( - index: data.keys.toList().indexOf(letter).toInt()??0, - duration: Duration(seconds: 2), - curve: Curves.easeInOutCubic); + itemScrollController.scrollTo(index: data.keys.toList().indexOf(letter).toInt() ?? 0, duration: Duration(seconds: 2), curve: Curves.easeInOutCubic); // final key = _offsetKeys[letter]; // if (key == null) return; // @@ -134,58 +125,52 @@ class _AlphabetScrollPageState extends State { @override Widget build(BuildContext context) { return SizedBox( - width: MediaQuery.sizeOf(context).width, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, // Add this - children: [ - Expanded( - child: Column( - children: [ - SizedBox( - height: (MediaQuery.sizeOf(context).height), - child: _buildList(widget.alpahbetsAvailable) - ), - ], - ), + width: MediaQuery.sizeOf(context).width, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, // Add this + children: [ + Expanded( + child: Column( + children: [ + SizedBox(height: (MediaQuery.sizeOf(context).height), child: _buildList(widget.alpahbetsAvailable)), + ], ), - SizedBox( - width: 24.w, - height: MediaQuery.sizeOf(context).height-(70.h+ kToolbarHeight+100.h), - child: Column( - mainAxisSize: MainAxisSize.max, // Add this - mainAxisAlignment: MainAxisAlignment.center, // Changed from center to start - crossAxisAlignment: CrossAxisAlignment.center, - children:List.generate(widget.alpahbetsAvailable.length, (i) { - final isActive = (i == _activeIndex); - return GestureDetector( - onTap: () { - setState(() => _activeIndex = i); - _scrollToLetter(widget.alpahbetsAvailable[i]); - }, - child: TweenAnimationBuilder( - tween: Tween(begin: 1.0, end: isActive ? 1.8 : 1.0), - duration: Duration(milliseconds: 120), - curve: Curves.easeOut, - builder: (_, scale, child) { - return Transform.scale( - scale: scale, - child: Opacity( - opacity: isActive ? 1.0 : 0.5, - child: widget.alpahbetsAvailable[i].toUpperCase().toText14( - color: !isActive ? AppColors.greyTextColor : AppColors.primaryRedColor, isEnglishOnly: true - ), - ), - ); - }, - ), - ); - } + ), + SizedBox( + width: 24.w, + height: MediaQuery.sizeOf(context).height - (70.h + kToolbarHeight + 100.h), + child: Column( + mainAxisSize: MainAxisSize.max, // Add this + mainAxisAlignment: MainAxisAlignment.center, // Changed from center to start + crossAxisAlignment: CrossAxisAlignment.center, + children: List.generate(widget.alpahbetsAvailable.length, (i) { + final isActive = (i == _activeIndex); + return GestureDetector( + onTap: () { + setState(() => _activeIndex = i); + _scrollToLetter(widget.alpahbetsAvailable[i]); + }, + child: TweenAnimationBuilder( + tween: Tween(begin: 1.0, end: isActive ? 1.8 : 1.0), + duration: Duration(milliseconds: 120), + curve: Curves.easeOut, + builder: (_, scale, child) { + return Transform.scale( + scale: scale, + child: Opacity( + opacity: isActive ? 1.0 : 0.5, + child: widget.alpahbetsAvailable[i].toUpperCase().toText14(color: !isActive ? AppColors.greyTextColor : AppColors.primaryRedColor, isEnglishOnly: true), + ), + ); + }, ), - ), - ), - ], - ), - ); + ); + }), + ), + ), + ], + ), + ); // ); } @@ -205,35 +190,35 @@ class _AlphabetScrollPageState extends State { key: _offsetKeys[letter], child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: - List.generate(items.length,(itemIndex)=> - AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 500), - child: SlideAnimation( - verticalOffset: 100.0, - child: FadeInAnimation( - child: LabOrderByTest( - appState: getIt(), - onTap: () { - if (items[itemIndex].model != null) { - widget.rangeViewModel.flush(); - widget.labViewModel.getPatientLabResult(items[itemIndex].model!, items[itemIndex].description!, - (widget.appState.isArabic() ? items[itemIndex].testDescriptionAr! : items[itemIndex].testDescriptionEn!),""); - } - }, - tests: items[itemIndex], - index: itemIndex, - isExpanded: true)), - ), - )) + children: List.generate( + items.length, + (itemIndex) => AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 500), + child: SlideAnimation( + verticalOffset: 100.0, + child: FadeInAnimation( + child: LabOrderByTest( + appState: getIt(), + onTap: () { + if (items[itemIndex].model != null) { + widget.rangeViewModel.flush(); + widget.labViewModel.getPatientLabResult(items[itemIndex].model!, items[itemIndex].description!, + (widget.appState.isArabic() ? items[itemIndex].testDescriptionAr! : items[itemIndex].testDescriptionEn!), ""); + } + }, + tests: items[itemIndex], + index: itemIndex, + isExpanded: true)), + ), + )) // ...items.indexed((item) => // // // // ) - ), + ), ); }, ); diff --git a/lib/presentation/lab/lab_order_by_test.dart b/lib/presentation/lab/lab_order_by_test.dart index 7740a596..733fb792 100644 --- a/lib/presentation/lab/lab_order_by_test.dart +++ b/lib/presentation/lab/lab_order_by_test.dart @@ -26,64 +26,65 @@ class LabOrderByTest extends StatelessWidget { @override build(BuildContext context) { return AnimatedContainer( - key:key, - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - margin: EdgeInsets.symmetric(vertical: 8.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), - child: Container( - key: ValueKey(index), - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - '${tests!.description}'.toText16(isBold: true, isEnglishOnly: true), - SizedBox(height: 4.h), - (appState.isArabic() ? tests!.testDescriptionAr : tests!.testDescriptionEn)!.toText12(isBold: true), - SizedBox(height: 8.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - AppCustomChipWidget( - richText: Row( - children: [ - "${LocaleKeys.lastTested.tr(context: context)}: ".toText12(isBold: true), - Directionality( - textDirection: ui.TextDirection.ltr,child: DateUtil.formatDateToDate(DateUtil.convertStringToDate(tests!.createdOn), false).toText12(isBold: true, isEnglishOnly: true)) - ], - ), - backgroundColor: AppColors.greyLightColor, - textColor: AppColors.textColor, + key: key, + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + margin: EdgeInsets.symmetric(vertical: 8.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), + child: Container( + key: ValueKey(index), + padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + '${tests!.description}'.toText16(isBold: true, isEnglishOnly: true), + SizedBox(height: 4.h), + (appState.isArabic() ? tests!.testDescriptionAr : tests!.testDescriptionEn)!.toText12(isBold: true), + SizedBox(height: 8.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + AppCustomChipWidget( + richText: Row( + children: [ + "${LocaleKeys.lastTested.tr(context: context)}: ".toText12(isBold: true), + Directionality( + textDirection: ui.TextDirection.ltr, child: DateUtil.formatDateToDate(DateUtil.convertStringToDate(tests!.createdOn), false).toText12(isBold: true, isEnglishOnly: true)) + ], ), - ], - ), - SizedBox(height: 16.h), - Row( - children: [ - Expanded(child: Container()), - Expanded( - child: CustomButton( - icon: AppAssets.view_report_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 16.h, - text: LocaleKeys.viewResults.tr(context: context), - onPressed: () { - onTap(); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 14.f, - fontWeight: FontWeight.w600, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - ), + backgroundColor: AppColors.greyLightColor, + textColor: AppColors.textColor, + ), + ], + ), + SizedBox(height: 16.h), + Row( + children: [ + Expanded(child: Container()), + Expanded( + child: CustomButton( + icon: AppAssets.view_report_icon, + iconColor: AppColors.primaryRedColor, + iconSize: 16.h, + text: LocaleKeys.viewResults.tr(context: context), + onPressed: () { + onTap(); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: Colors.transparent, + textColor: AppColors.primaryRedColor, + fontSize: 14.f, + fontWeight: FontWeight.w600, + borderRadius: 10.r, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, ), - ], - ), - ], - ), - )); + ), + ], + ), + ], + ), + ), + ); } } diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index 0e8890ba..332a89da 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -1 +1 @@ -import 'dart:async'; import 'dart:ui' as ui; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_assets.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/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.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/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), physics: activeIndex == 1 ? NeverScrollableScrollPhysics() : ScrollPhysics(), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ // CustomButton( // text: LocaleKeys.byClinic.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(true); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, // borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), // textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, // fontSize: 12.f, // isBold: true, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: LocaleKeys.byHospital.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(false); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, // borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, // textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, // fontSize: 12, // isBold: true, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, isEnglishOnly: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrders.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.filteredLabOrders.length, itemBuilder: (context, index) { final group = labViewModel.filteredLabOrders[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder() .toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( richText: Row( children: [ "${group.testDetails!.length} ".toText10( color: AppColors.successColor, isEnglishOnly: true, weight: FontWeight.w600), LocaleKeys.tests .tr(context: context) .toText10(color: AppColors.successColor, weight: FontWeight.w600), ], ), labelText: "${group.testDetails!.length} ${LocaleKeys.tests.tr(context: context)}", backgroundColor: AppColors.successColor.withOpacity(0.1), textColor: AppColors.successColor, ), AppCustomChipWidget( labelText: "${_appState.isArabic() ? group.isInOutPatientDescriptionN : group.isInOutPatientDescription}", backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), textColor: AppColors.warningColorYellow, ) ], ), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded( child: (group.doctorName ?? group.doctorNameEnglish ?? "") .toString() .toText14(isBold: true)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ Directionality( textDirection: ui.TextDirection.ltr, child: AppCustomChipWidget( labelText: DateUtil.formatDateToDate( DateUtil.convertStringToDate(group.orderDate ?? ""), false), isEnglishOnly: true, )), AppCustomChipWidget( labelText: (group.projectName ?? ""), ), AppCustomChipWidget( labelText: (group.clinicDescription ?? ""), ), ], ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: Column( children: [ ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "• ${order.testDetails![index].description!}" .toText14(isBold: true, isEnglishOnly: true), SizedBox(height: 4.h), (_appState.isArabic() ? order.testDetails![index].testDescriptionAr! : order.testDetails![index].testDescriptionEn!).toText12( isBold: true, color: AppColors.textColorLight, isEnglishOnly: true), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider( color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.testDetails!.length > 3 ? 3 : group.testDetails!.length), SizedBox(height: 16.h), CustomButton( text: "${LocaleKeys.viewResults.tr()} (${group.testDetails!.length})", onPressed: () { labProvider.currentlySelectedPatientOrder = group; labProvider.getPatientLabResultByHospital(group); labProvider.getPatientSpecialResult(group); Navigator.of(context).push( CustomPageRoute( page: LabResultByClinic(labOrder: group), ), ); }, backgroundColor: AppColors.infoColor.withAlpha(20), borderColor: AppColors.infoColor.withAlpha(0), textColor: AppColors.infoColor, fontSize: (isFoldable || isTablet) ? 12.f : 14.f, isBold: true, borderRadius: 12.r, padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), height: 40.h, iconSize: 14.h, icon: AppAssets.view_report_icon, iconColor: AppColors.infoColor, ), SizedBox(height: 16.h), ], ), ) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.filteredIndexedCharacterForUniqueTest, details: labViewModel.filteredUniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file +import 'dart:async'; import 'dart:ui' as ui; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_assets.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/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.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/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), physics: activeIndex == 1 ? NeverScrollableScrollPhysics() : ScrollPhysics(), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: AppColors.primaryRedColor, activeBackgroundColor: AppColors.secondaryLightRedColor, tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ // CustomButton( // text: LocaleKeys.byClinic.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(true); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, // borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), // textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, // fontSize: 12.f, // isBold: true, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: LocaleKeys.byHospital.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(false); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, // borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, // textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, // fontSize: 12, // isBold: true, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, isEnglishOnly: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrders.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.filteredLabOrders.length, itemBuilder: (context, index) { final group = labViewModel.filteredLabOrders[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( richText: Row( children: [ "${group.testDetails!.length} ".toText10(color: AppColors.successColor, isEnglishOnly: true, weight: FontWeight.w600), LocaleKeys.tests.tr(context: context).toText10(color: AppColors.successColor, weight: FontWeight.w600), ], ), labelText: "${group.testDetails!.length} ${LocaleKeys.tests.tr(context: context)}", backgroundColor: AppColors.successColor.withOpacity(0.1), textColor: AppColors.successColor, ), AppCustomChipWidget( labelText: "${_appState.isArabic() ? group.isInOutPatientDescriptionN : group.isInOutPatientDescription}", backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), textColor: AppColors.warningColorYellow, ) ], ), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (group.doctorName ?? group.doctorNameEnglish ?? "").toString().toText14(isBold: true)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ Directionality( textDirection: ui.TextDirection.ltr, child: AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(group.orderDate ?? ""), false), isEnglishOnly: true, )), AppCustomChipWidget( labelText: (group.projectName ?? ""), ), AppCustomChipWidget( labelText: (group.clinicDescription ?? ""), ), ], ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: Column( children: [ ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "• ${order.testDetails![index].description!}".toText14(isBold: true, isEnglishOnly: true), SizedBox(height: 4.h), (_appState.isArabic() ? order.testDetails![index].testDescriptionAr! : order.testDetails![index].testDescriptionEn!) .toText12(isBold: true, color: AppColors.textColorLight, isEnglishOnly: true), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.testDetails!.length > 3 ? 3 : group.testDetails!.length), SizedBox(height: 16.h), CustomButton( text: "${LocaleKeys.viewResults.tr()} (${group.testDetails!.length})", onPressed: () { labProvider.currentlySelectedPatientOrder = group; labProvider.getPatientLabResultByHospital(group); labProvider.getPatientSpecialResult(group); Navigator.of(context).push( CustomPageRoute( page: LabResultByClinic(labOrder: group), ), ); }, backgroundColor: AppColors.infoColor.withAlpha(20), borderColor: AppColors.infoColor.withAlpha(0), textColor: AppColors.infoColor, fontSize: (isFoldable || isTablet) ? 12.f : 14.f, isBold: true, borderRadius: 12.r, padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), height: 40.h, iconSize: 14.h, icon: AppAssets.view_report_icon, iconColor: AppColors.infoColor, ), SizedBox(height: 16.h), ], ), ) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.filteredIndexedCharacterForUniqueTest, details: labViewModel.filteredUniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file diff --git a/lib/presentation/my_invoices/my_invoices_list.dart b/lib/presentation/my_invoices/my_invoices_list.dart index 67ee05a6..95ff3e16 100644 --- a/lib/presentation/my_invoices/my_invoices_list.dart +++ b/lib/presentation/my_invoices/my_invoices_list.dart @@ -122,8 +122,8 @@ class _MyInvoicesListState extends State { children: [ SizedBox(height: 16.h), CustomTabBar( - activeTextColor: Color(0xffED1C2B), - activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), + activeTextColor: AppColors.primaryRedColor, + activeBackgroundColor: AppColors.secondaryLightRedColor, initialIndex: 0, tabs: [ CustomTabBarModel(null, LocaleKeys.visitsOrders.tr(context: context)), @@ -149,13 +149,11 @@ class _MyInvoicesListState extends State { myInvoicesViewModel.filterInvoices(InvoiceFilterType.all); }, backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all - ? AppColors.primaryRedColor - : AppColors.textColor.withValues(alpha: 0.2), + borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.blackColor, - fontSize: 12, + fontSize: 12.f, fontWeight: FontWeight.w600, - borderRadius: 10, + borderRadius: 10.r, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), @@ -166,15 +164,12 @@ class _MyInvoicesListState extends State { if (myInvoicesVM.getOriginalInvoicesList().isEmpty) return; _showHospitalFilterBottomSheet(context); }, - backgroundColor: - myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital - ? AppColors.primaryRedColor - : AppColors.textColor.withValues(alpha: 0.2), + backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.blackColor, - fontSize: 12, + fontSize: 12.f, fontWeight: FontWeight.w600, - borderRadius: 10, + borderRadius: 10.r, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), @@ -185,15 +180,12 @@ class _MyInvoicesListState extends State { if (myInvoicesVM.getOriginalInvoicesList().isEmpty) return; _showClinicFilterBottomSheet(context); }, - backgroundColor: - myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic - ? AppColors.primaryRedColor - : AppColors.textColor.withValues(alpha: 0.2), + backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.blackColor, - fontSize: 12, + fontSize: 12.f, fontWeight: FontWeight.w600, - borderRadius: 10, + borderRadius: 10.r, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), @@ -204,15 +196,12 @@ class _MyInvoicesListState extends State { if (myInvoicesVM.getOriginalInvoicesList().isEmpty) return; _showDoctorFilterBottomSheet(context); }, - backgroundColor: - myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor - ? AppColors.primaryRedColor - : AppColors.textColor.withValues(alpha: 0.2), + backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.blackColor, - fontSize: 12, + fontSize: 12.f, fontWeight: FontWeight.w600, - borderRadius: 10, + borderRadius: 10.r, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), @@ -245,16 +234,14 @@ class _MyInvoicesListState extends State { getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index], onTap: () async { if (Utils.isVidaPlusProject(myInvoicesVM.allInvoicesList[index].projectId ?? 0)) { - LoaderBottomSheet.showLoader( - loadingText: LocaleKeys.sendingEmailPleaseWait.tr(context: context)); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.sendingEmailPleaseWait.tr(context: context)); await myInvoicesViewModel.sendInvoiceEmail( appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!, projectID: myInvoicesVM.allInvoicesList[index].projectId!, onSuccess: (val) { LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight(context, - child: Utils.getSuccessWidget( - loadingText: LocaleKeys.emailSentSuccessfullyMessage.tr(context: context)), + child: Utils.getSuccessWidget(loadingText: LocaleKeys.emailSentSuccessfullyMessage.tr(context: context)), callBackFunc: () {}, isFullScreen: false, isCloseButtonVisible: true, @@ -289,8 +276,7 @@ class _MyInvoicesListState extends State { onSuccess: (value) async { LoaderBottomSheet.hideLoader(); if (myInvoicesViewModel.downloadInvoicePDFBase64!.isNotEmpty) { - String path = await Utils.createFileFromString( - myInvoicesViewModel.downloadInvoicePDFBase64!, "pdf"); + String path = await Utils.createFileFromString(myInvoicesViewModel.downloadInvoicePDFBase64!, "pdf"); try { OpenFilex.open(path); } catch (ex) { @@ -377,8 +363,7 @@ class _MyInvoicesListState extends State { onSuccess: (value) async { LoaderBottomSheet.hideLoader(); if (myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!.isNotEmpty) { - String path = await Utils.createFileFromString( - myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!, "pdf"); + String path = await Utils.createFileFromString(myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!, "pdf"); try { OpenFilex.open(path); } catch (ex) { diff --git a/lib/presentation/onboarding/onboarding_screen.dart b/lib/presentation/onboarding/onboarding_screen.dart index 0af63b40..1c5b64d8 100644 --- a/lib/presentation/onboarding/onboarding_screen.dart +++ b/lib/presentation/onboarding/onboarding_screen.dart @@ -111,7 +111,7 @@ class _OnboardingScreenState extends State { onPressed: () => goToHomePage(), width: 86.w, height: 56.h, - backgroundColor: Color(0xffFEE9EA), + backgroundColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, borderColor: Colors.transparent, ).paddingOnly(left: 24.w) diff --git a/lib/presentation/onboarding/splash_animation_screen.dart b/lib/presentation/onboarding/splash_animation_screen.dart index 105922bb..0fdd86a8 100644 --- a/lib/presentation/onboarding/splash_animation_screen.dart +++ b/lib/presentation/onboarding/splash_animation_screen.dart @@ -164,7 +164,7 @@ class _AnimatedScreenState extends State with TickerProviderStat width: 400.h, height: 653.h, decoration: BoxDecoration( - color: Color(0xffED1C2B), + color: AppColors.primaryRedColor, borderRadius: BorderRadius.circular(330.h), ), ), @@ -273,7 +273,7 @@ class _MoveObjectDemoState extends State with SingleTickerProvid width: 200, height: 375, decoration: BoxDecoration( - color: const Color(0xffED1C2B), + color: AppColors.primaryRedColor, borderRadius: BorderRadius.circular(330), ), ), @@ -367,7 +367,7 @@ class _MoveOnClickDemoState extends State with TickerProviderSt width: 100, height: 150, decoration: BoxDecoration( - color: const Color(0xffED1C2B), + color: AppColors.primaryRedColor, borderRadius: BorderRadius.circular(330), ), ), diff --git a/lib/presentation/rate_appointment/rate_appointment_clinic.dart b/lib/presentation/rate_appointment/rate_appointment_clinic.dart index c8aedea8..e285a7c1 100644 --- a/lib/presentation/rate_appointment/rate_appointment_clinic.dart +++ b/lib/presentation/rate_appointment/rate_appointment_clinic.dart @@ -159,9 +159,9 @@ class _RateAppointmentClinicState extends State { Expanded( child: CustomButton( text: LocaleKeys.back.tr(context: context), - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, onPressed: () { appointmentRatingViewModel!.setTitle(LocaleKeys.rateDoctor.tr(context: context)); appointmentRatingViewModel!.setSubTitle(LocaleKeys.howWasYourLastVisitWithDoctor.tr(context: context)); diff --git a/lib/presentation/rate_appointment/rate_appointment_doctor.dart b/lib/presentation/rate_appointment/rate_appointment_doctor.dart index d78dc59e..b54b5741 100644 --- a/lib/presentation/rate_appointment/rate_appointment_doctor.dart +++ b/lib/presentation/rate_appointment/rate_appointment_doctor.dart @@ -181,9 +181,9 @@ class _RateAppointmentDoctorState extends State { Expanded( child: CustomButton( text: LocaleKeys.later.tr(context: context), - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, onPressed: () { Navigator.pop(context); }, diff --git a/lib/presentation/smartwatches/activity_detail.dart b/lib/presentation/smartwatches/activity_detail.dart index 7911baf6..c246d5a0 100644 --- a/lib/presentation/smartwatches/activity_detail.dart +++ b/lib/presentation/smartwatches/activity_detail.dart @@ -66,8 +66,8 @@ class _ActivityDetailsState extends State { children: [ Expanded( child: CustomTabBar( - activeTextColor: Color(0xffED1C2B), - activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), + activeTextColor: AppColors.primaryRedColor, + activeBackgroundColor: AppColors.secondaryLightRedColor, tabs: [ CustomTabBarModel(null, "D"), CustomTabBarModel(null, "W"), diff --git a/lib/presentation/smartwatches/health_dashboard/health_dashboard.dart b/lib/presentation/smartwatches/health_dashboard/health_dashboard.dart index f30d87a9..84ec64e9 100644 --- a/lib/presentation/smartwatches/health_dashboard/health_dashboard.dart +++ b/lib/presentation/smartwatches/health_dashboard/health_dashboard.dart @@ -56,8 +56,8 @@ class _HealthDashboardState extends State with SingleTickerProv children: [ SizedBox(height: 96.h), CustomTabBar( - activeTextColor: Color(0xffED1C2B), - activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), + activeTextColor: AppColors.primaryRedColor, + activeBackgroundColor: AppColors.secondaryLightRedColor, tabs: [ CustomTabBarModel(null, "Overview".needTranslation), CustomTabBarModel(null, "Details".needTranslation), diff --git a/lib/presentation/todo_section/widgets/ancillary_orders_list.dart b/lib/presentation/todo_section/widgets/ancillary_orders_list.dart index cc5bbbb6..da75dd7b 100644 --- a/lib/presentation/todo_section/widgets/ancillary_orders_list.dart +++ b/lib/presentation/todo_section/widgets/ancillary_orders_list.dart @@ -257,9 +257,9 @@ class AncillaryOrderCard extends StatelessWidget { onViewDetails!(); } }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontWeight: FontWeight.w600, borderRadius: 10.r, diff --git a/lib/presentation/todo_section/widgets/ancillary_procedures_list.dart b/lib/presentation/todo_section/widgets/ancillary_procedures_list.dart index 54c92789..b7f0f28a 100644 --- a/lib/presentation/todo_section/widgets/ancillary_procedures_list.dart +++ b/lib/presentation/todo_section/widgets/ancillary_procedures_list.dart @@ -252,9 +252,9 @@ class AncillaryOrderCard extends StatelessWidget { onViewDetails!(); } }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, fontSize: 14.f, isBold: true, borderRadius: 10.r, diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index 24c8bd25..3b9cbdae 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -54,7 +54,7 @@ class AppColors { /// The original, non-themed brand red (or its dark-mode variant). Always /// stable regardless of any active occasion theme — intended for opacity /// derived usages (e.g. `AppColors.primaryRedColorBase.withOpacity(0.1)`). - static Color get primaryRedColorBase => isDarkMode ? const Color(0xFFED1C2B) : const Color(0xFFED1C2B); + static Color get primaryRedColorBase => isDarkMode ? dark.primaryRedColor : const Color(0xFFED1C2B); /// Semantic color for critical/negative actions (delete/deactivate account, /// cancel appointment, clear/reset, emergency, etc.). Same light/dark diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index 82b62507..8b8e599a 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -10,8 +10,8 @@ class CustomButton extends StatefulWidget { final String text; final String? icon; final VoidCallback? onPressed; - final Color backgroundColor; - final Color borderColor; + final Color? backgroundColor; + final Color? borderColor; final Color textColor; final double? borderRadius; final double borderWidth; @@ -33,8 +33,8 @@ class CustomButton extends StatefulWidget { super.key, required this.text, required this.onPressed, - this.backgroundColor = const Color(0xFFED1C2B), - this.borderColor = const Color(0xFFED1C2B), + this.backgroundColor, + this.borderColor, this.textColor = Colors.white, this.borderRadius, this.borderWidth = 2, @@ -93,6 +93,8 @@ class _CustomButtonState extends State with SingleTickerProviderSt final iconS = widget.iconSize ?? (24.h); final fontS = widget.fontSize ?? (16.f); final isButtonDisabled = widget.isDisabled || widget.onPressed == null; + final resolvedBackgroundColor = widget.backgroundColor ?? AppColors.primaryRedColor; + final resolvedBorderColor = widget.borderColor ?? AppColors.primaryRedColor; return Semantics( button: true, @@ -134,10 +136,10 @@ class _CustomButtonState extends State with SingleTickerProviderSt width: widget.width, padding: widget.padding, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: isButtonDisabled ? AppColors.inputLabelTextColor.withValues(alpha: 0.3) : widget.backgroundColor, + color: isButtonDisabled ? AppColors.inputLabelTextColor.withValues(alpha: 0.3) : resolvedBackgroundColor, borderRadius: radius, customBorder: BorderRadius.circular(radius), - side: widget.borderSide ?? BorderSide(width: widget.borderWidth.h, color: isButtonDisabled ? Colors.transparent : widget.borderColor)), + side: widget.borderSide ?? BorderSide(width: widget.borderWidth.h, color: isButtonDisabled ? Colors.transparent : resolvedBorderColor)), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,