diff --git a/assets/images/png/full_body_back.png b/assets/images/png/full_body_back.png new file mode 100644 index 00000000..2eda5e8f Binary files /dev/null and b/assets/images/png/full_body_back.png differ diff --git a/assets/images/png/full_body_front.png b/assets/images/png/full_body_front.png new file mode 100644 index 00000000..d1f34b4e Binary files /dev/null and b/assets/images/png/full_body_front.png differ diff --git a/assets/images/svg/body_icon.svg b/assets/images/svg/body_icon.svg new file mode 100644 index 00000000..03591eca --- /dev/null +++ b/assets/images/svg/body_icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/images/svg/rotate_icon.svg b/assets/images/svg/rotate_icon.svg new file mode 100644 index 00000000..cb52c310 --- /dev/null +++ b/assets/images/svg/rotate_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 5fccc6e7..eb6f74cb 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -176,7 +176,6 @@ class AppAssets { static const String all_payment_method = '$svgBasePath/all_payment_method.svg'; static const String ic_rrt_vehicle = '$svgBasePath/ic_rrt_vehicle.svg'; - //bottom navigation// static const String homeBottom = '$svgBasePath/home_bottom.svg'; static const String bookAppoBottom = '$svgBasePath/book_appo_bottom.svg'; @@ -190,22 +189,29 @@ class AppAssets { static const String alertSquare = '$svgBasePath/alert-square.svg'; static const String arrowRight = '$svgBasePath/arrow-right.svg'; + // Symptoms Checker + static const String bodyIcon = '$svgBasePath/body_icon.svg'; + static const String rotateIcon = '$svgBasePath/rotate_icon.svg'; + // PNGS // - static const String hmg_logo = '$pngBasePath/hmg_logo.png'; - static const String livecare_service = '$pngBasePath/livecare_service.png'; - static const String male_img = '$pngBasePath/male_img.png'; + static const String hmgLogo = '$pngBasePath/hmg_logo.png'; + static const String liveCareService = '$pngBasePath/livecare_service.png'; + static const String maleImg = '$pngBasePath/male_img.png'; static const String femaleImg = '$pngBasePath/female_img.png'; static const String babyGirlImg = '$pngBasePath/baby_girl_img.png'; static const String babyBoyImg = '$pngBasePath/baby_img.png'; - static const String apple_pay = '$pngBasePath/Apple_Pay.png'; + static const String applePay = '$pngBasePath/Apple_Pay.png'; static const String mada = '$pngBasePath/Mada.png'; - static const String Mastercard = '$pngBasePath/Mastercard.png'; - static const String tamara_en = '$pngBasePath/tamara_en.png'; + static const String mastercard = '$pngBasePath/Mastercard.png'; + static const String tamaraEng = '$pngBasePath/tamara_en.png'; static const String visa = '$pngBasePath/visa.png'; static const String lockIcon = '$pngBasePath/lock-icon.png'; - static const String dummy_user = '$pngBasePath/dummy_user.png'; + static const String dummyUser = '$pngBasePath/dummy_user.png'; static const String comprehensiveCheckupEn = '$pngBasePath/cc_en.png'; static const String comprehensiveCheckupAr = '$pngBasePath/cc_er.png'; + + static const String fullBodyFront = '$pngBasePath/full_body_front.png'; + static const String fullBodyBack = '$pngBasePath/full_body_back.png'; } class AppAnimations { diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 73a93c69..58c4a669 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -16,7 +16,6 @@ import 'package:hmg_patient_app_new/features/emergency_services/emergency_servic import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart'; -import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_repo.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart'; import 'package:hmg_patient_app_new/features/insurance/insurance_repo.dart'; @@ -39,6 +38,7 @@ import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart'; import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart'; import 'package:hmg_patient_app_new/features/todo_section/todo_section_repo.dart'; import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart'; +import 'package:hmg_patient_app_new/presentation/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; @@ -123,11 +123,7 @@ class AppDependencies { getIt.registerLazySingleton(() => LabViewModel(labRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt())); getIt.registerLazySingleton( - () => RadiologyViewModel( - radiologyRepo: getIt(), - errorHandlerService: getIt(), - navigationService: getIt() - ), + () => RadiologyViewModel(radiologyRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt()), ); getIt.registerLazySingleton(() => PrescriptionsViewModel(prescriptionsRepo: getIt(), errorHandlerService: getIt())); @@ -220,17 +216,6 @@ class AppDependencies { () => TodoSectionViewModel(todoSectionRepo: getIt(), errorHandlerService: getIt()), ); - getIt.registerLazySingleton( - () => HmgServicesViewModel(bookAppointmentsRepo: getIt(), hmgServicesRepo: getIt(), errorHandlerService: getIt()), - ); - - // Screen-specific VMs → Factory - // getIt.registerFactory( - // () => BookAppointmentsViewModel( - // bookAppointmentsRepo: getIt(), - // dialogService: getIt(), - // errorHandlerService: getIt(), - // ), - // ); + getIt.registerLazySingleton(() => SymptomsCheckerViewModel()); } } diff --git a/lib/core/enums.dart b/lib/core/enums.dart index 4151bed4..e318401b 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -32,6 +32,8 @@ enum AppEnvironmentTypeEnum { dev, uat, preProd, qa, staging, prod } enum FamilyFileEnum { active, inactive, blocked, deleted, pending, rejected } +enum BodyView { front, back } + extension CalenderExtension on CalenderEnum { int get toInt { switch (this) { @@ -172,7 +174,7 @@ extension FamilyFileEnumExtenshion on FamilyFileEnum { return isArabic ? 'محذوف' : 'Deleted'; case FamilyFileEnum.pending: return isArabic ? 'قيد الانتظار' : 'Pending'; - case FamilyFileEnum.rejected: + case FamilyFileEnum.rejected: return isArabic ? 'مرفوض' : 'Rejected'; } } diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index e3b108fc..9fdd9477 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -721,10 +721,10 @@ class Utils { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Image.asset(AppAssets.mada, width: 25.h, height: 25.h), - Image.asset(AppAssets.tamara_en, width: 25.h, height: 25.h), + Image.asset(AppAssets.tamaraEng, width: 25.h, height: 25.h), Image.asset(AppAssets.visa, width: 25.h, height: 25.h), - Image.asset(AppAssets.Mastercard, width: 25.h, height: 25.h), - Image.asset(AppAssets.apple_pay, width: 25.h, height: 25.h), + Image.asset(AppAssets.mastercard, width: 25.h, height: 25.h), + Image.asset(AppAssets.applePay, width: 25.h, height: 25.h), ], ); } diff --git a/lib/extensions/route_extensions.dart b/lib/extensions/route_extensions.dart index 0dcc54bd..b76acfac 100644 --- a/lib/extensions/route_extensions.dart +++ b/lib/extensions/route_extensions.dart @@ -17,7 +17,7 @@ extension NavigationExtensions on BuildContext { Navigator.of(this).pop(); } - void navigateTo(Widget page) { + void pushNavigateTo(Widget page) { Navigator.push(this, MaterialPageRoute(builder: (context) => page)); } diff --git a/lib/features/symptoms_checker/models/organ_model.dart b/lib/features/symptoms_checker/models/organ_model.dart new file mode 100644 index 00000000..984a290e --- /dev/null +++ b/lib/features/symptoms_checker/models/organ_model.dart @@ -0,0 +1,41 @@ +import 'package:hmg_patient_app_new/core/enums.dart'; + +class OrganModel { + final String id; + final String name; + final BodyView bodyView; + final OrganPosition position; + + const OrganModel({ + required this.id, + required this.name, + required this.bodyView, + required this.position, + }); + + OrganModel copyWith({ + String? id, + String? name, + BodyView? bodyView, + OrganPosition? position, + }) { + return OrganModel( + id: id ?? this.id, + name: name ?? this.name, + bodyView: bodyView ?? this.bodyView, + position: position ?? this.position, + ); + } +} + +class OrganPosition { + final double x; // Percentage from left (0.0 to 1.0) + final double y; // Percentage from top (0.0 to 1.0) + + const OrganPosition({ + required this.x, + required this.y, + }); +} + + diff --git a/lib/features/symptoms_checker/organ_mapping_data.dart b/lib/features/symptoms_checker/organ_mapping_data.dart new file mode 100644 index 00000000..a2395e4c --- /dev/null +++ b/lib/features/symptoms_checker/organ_mapping_data.dart @@ -0,0 +1,371 @@ +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/features/symptoms_checker/models/organ_model.dart'; + +class OrganData { + // ==================== FRONT VIEW ==================== + static const List frontViewOrgans = [ + // ========== HEAD & FACE ========== + OrganModel( + id: 'head', + name: 'Head', + bodyView: BodyView.front, + position: OrganPosition(x: 0.50, y: 0.03), + ), + OrganModel( + id: 'left_eye', + name: 'Left Eye', + bodyView: BodyView.front, + position: OrganPosition(x: 0.43, y: 0.07), + ), + OrganModel( + id: 'right_eye', + name: 'Right Eye', + bodyView: BodyView.front, + position: OrganPosition(x: 0.57, y: 0.07), + ), + OrganModel( + id: 'nose_mouth', + name: 'Nose/Mouth', + bodyView: BodyView.front, + position: OrganPosition(x: 0.50, y: 0.09), + ), + + // ========== NECK ========== + OrganModel( + id: 'throat', + name: 'Throat', + bodyView: BodyView.front, + position: OrganPosition(x: 0.50, y: 0.15), + ), + + // ========== SHOULDERS ========== + OrganModel( + id: 'left_shoulder', + name: 'Left Shoulder', + bodyView: BodyView.front, + position: OrganPosition(x: 0.22, y: 0.22), + ), + OrganModel( + id: 'right_shoulder', + name: 'Right Shoulder', + bodyView: BodyView.front, + position: OrganPosition(x: 0.8, y: 0.22), + ), + + // ========== CHEST ========== + OrganModel( + id: 'left_chest', + name: 'Left Chest', + bodyView: BodyView.front, + position: OrganPosition(x: 0.38, y: 0.22), + ), + OrganModel( + id: 'center_chest', + name: 'Center Chest', + bodyView: BodyView.front, + position: OrganPosition(x: 0.52, y: 0.25), + ), + OrganModel( + id: 'right_chest', + name: 'Right Chest', + bodyView: BodyView.front, + position: OrganPosition(x: 0.65, y: 0.22), + ), + + // ========== RIBS ========== + OrganModel( + id: 'left_ribs', + name: 'Left Ribs', + bodyView: BodyView.front, + position: OrganPosition(x: 0.38, y: 0.35), + ), + OrganModel( + id: 'right_ribs', + name: 'Right Ribs', + bodyView: BodyView.front, + position: OrganPosition(x: 0.64, y: 0.35), + ), + + // ========== ABDOMEN ========== + OrganModel( + id: 'upper_abdomen', + name: 'Upper Abdomen', + bodyView: BodyView.front, + position: OrganPosition(x: 0.51, y: 0.31), + ), + OrganModel( + id: 'navel', + name: 'Navel', + bodyView: BodyView.front, + position: OrganPosition(x: 0.51, y: 0.38), + ), + OrganModel( + id: 'lower_abdomen', + name: 'Lower Abdomen', + bodyView: BodyView.front, + position: OrganPosition(x: 0.51, y: 0.44), + ), + + // ========== PELVIS ========== + OrganModel( + id: 'left_groin', + name: 'Left Groin', + bodyView: BodyView.front, + position: OrganPosition(x: 0.42, y: 0.49), + ), + OrganModel( + id: 'right_groin', + name: 'Right Groin', + bodyView: BodyView.front, + position: OrganPosition(x: 0.59, y: 0.49), + ), + + // ========== LEFT ARM ========== + + OrganModel( + id: 'left_elbow', + name: 'Left Elbow', + bodyView: BodyView.front, + position: OrganPosition(x: 0.21, y: 0.35), + ), + OrganModel( + id: 'left_forearm', + name: 'Left Forearm', + bodyView: BodyView.front, + position: OrganPosition(x: 0.19, y: 0.43), + ), + OrganModel( + id: 'left_wrist', + name: 'Left Wrist', + bodyView: BodyView.front, + position: OrganPosition(x: 0.14, y: 0.5), + ), + + // ========== RIGHT ARM ========== + + OrganModel( + id: 'right_elbow', + name: 'Right Elbow', + bodyView: BodyView.front, + position: OrganPosition(x: 0.79, y: 0.35), + ), + OrganModel( + id: 'right_forearm', + name: 'Right Forearm', + bodyView: BodyView.front, + position: OrganPosition(x: 0.81, y: 0.43), + ), + OrganModel( + id: 'right_wrist', + name: 'Right Wrist', + bodyView: BodyView.front, + position: OrganPosition(x: 0.85, y: 0.5), + ), + + // ========== LEFT LEG ========== + OrganModel( + id: 'left_thigh', + name: 'Left Thigh', + bodyView: BodyView.front, + position: OrganPosition(x: 0.4, y: 0.60), + ), + OrganModel( + id: 'left_knee', + name: 'Left Knee', + bodyView: BodyView.front, + position: OrganPosition(x: 0.4, y: 0.72), + ), + OrganModel( + id: 'left_shin', + name: 'Left Shin', + bodyView: BodyView.front, + position: OrganPosition(x: 0.41, y: 0.82), + ), + OrganModel( + id: 'left_ankle', + name: 'Left Ankle', + bodyView: BodyView.front, + position: OrganPosition(x: 0.43, y: 0.91), + ), + + // ========== RIGHT LEG ========== + OrganModel( + id: 'right_thigh', + name: 'Right Thigh', + bodyView: BodyView.front, + position: OrganPosition(x: 0.65, y: 0.60), + ), + OrganModel( + id: 'right_knee', + name: 'Right Knee', + bodyView: BodyView.front, + position: OrganPosition(x: 0.6, y: 0.72), + ), + OrganModel( + id: 'right_shin', + name: 'Right Shin', + bodyView: BodyView.front, + position: OrganPosition(x: 0.57, y: 0.82), + ), + OrganModel( + id: 'right_ankle', + name: 'Right Ankle', + bodyView: BodyView.front, + position: OrganPosition(x: 0.57, y: 0.91), + ), + ]; + + // ==================== BACK VIEW ==================== + static const List backViewOrgans = [ + // ========== HEAD & NECK ========== + OrganModel( + id: 'back_of_head', + name: 'Back of Head', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.04), + ), + OrganModel( + id: 'neck_back', + name: 'Neck', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.14), + ), + + // ========== SHOULDERS ========== + OrganModel( + id: 'left_shoulder_back', + name: 'Left Shoulder', + bodyView: BodyView.back, + position: OrganPosition(x: 0.33, y: 0.19), + ), + OrganModel( + id: 'right_shoulder_back', + name: 'Right Shoulder', + bodyView: BodyView.back, + position: OrganPosition(x: 0.67, y: 0.19), + ), + + // ========== UPPER BACK ========== + OrganModel( + id: 'upper_spine', + name: 'Upper Spine', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.23), + ), + OrganModel( + id: 'left_upper_back', + name: 'Left Upper Back', + bodyView: BodyView.back, + position: OrganPosition(x: 0.38, y: 0.28), + ), + OrganModel( + id: 'right_upper_back', + name: 'Right Upper Back', + bodyView: BodyView.back, + position: OrganPosition(x: 0.62, y: 0.28), + ), + + // ========== MID BACK ========== + OrganModel( + id: 'mid_spine', + name: 'Mid Spine', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.35), + ), + OrganModel( + id: 'left_mid_back', + name: 'Left Mid Back', + bodyView: BodyView.back, + position: OrganPosition(x: 0.38, y: 0.35), + ), + OrganModel( + id: 'right_mid_back', + name: 'Right Mid Back', + bodyView: BodyView.back, + position: OrganPosition(x: 0.62, y: 0.35), + ), + + // ========== LOWER BACK ========== + OrganModel( + id: 'lower_spine', + name: 'Lower Back', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.43), + ), + OrganModel( + id: 'left_lower_back', + name: 'Left Lower Back', + bodyView: BodyView.back, + position: OrganPosition(x: 0.40, y: 0.43), + ), + OrganModel( + id: 'right_lower_back', + name: 'Right Lower Back', + bodyView: BodyView.back, + position: OrganPosition(x: 0.60, y: 0.43), + ), + + // ========== GLUTES ========== + OrganModel( + id: 'sacrum', + name: 'Sacrum', + bodyView: BodyView.back, + position: OrganPosition(x: 0.50, y: 0.52), + ), + OrganModel( + id: 'left_glute', + name: 'Left Glute', + bodyView: BodyView.back, + position: OrganPosition(x: 0.45, y: 0.56), + ), + OrganModel( + id: 'right_glute', + name: 'Right Glute', + bodyView: BodyView.back, + position: OrganPosition(x: 0.55, y: 0.56), + ), + + // ========== LEGS ========== + OrganModel( + id: 'left_hamstring', + name: 'Left Hamstring', + bodyView: BodyView.back, + position: OrganPosition(x: 0.43, y: 0.65), + ), + OrganModel( + id: 'right_hamstring', + name: 'Right Hamstring', + bodyView: BodyView.back, + position: OrganPosition(x: 0.57, y: 0.65), + ), + OrganModel( + id: 'left_calf', + name: 'Left Calf', + bodyView: BodyView.back, + position: OrganPosition(x: 0.43, y: 0.79), + ), + OrganModel( + id: 'right_calf', + name: 'Right Calf', + bodyView: BodyView.back, + position: OrganPosition(x: 0.57, y: 0.79), + ), + ]; + + // Helper methods + static List getOrgansForView(BodyView view) { + return view == BodyView.front ? frontViewOrgans : backViewOrgans; + } + + static List getAllOrgans() { + return [...frontViewOrgans, ...backViewOrgans]; + } + + static OrganModel? getOrganById(String id) { + try { + return getAllOrgans().firstWhere((organ) => organ.id == id); + } catch (e) { + return null; + } + } +} diff --git a/lib/main.dart b/lib/main.dart index 1af80b66..254a2ca6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,6 +28,7 @@ import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_mo import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart'; import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart'; +import 'package:hmg_patient_app_new/presentation/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; @@ -145,6 +146,9 @@ void main() async { ), ChangeNotifierProvider( create: (_) => getIt.get(), + ), + ChangeNotifierProvider( + create: (_) => getIt.get(), ) ], child: MyApp()), ), diff --git a/lib/presentation/appointments/appointment_payment_page.dart b/lib/presentation/appointments/appointment_payment_page.dart index faf1c2a8..ccd70180 100644 --- a/lib/presentation/appointments/appointment_payment_page.dart +++ b/lib/presentation/appointments/appointment_payment_page.dart @@ -149,7 +149,7 @@ class _AppointmentPaymentPageState extends State { children: [ Image.asset(AppAssets.visa, width: 50.h, height: 50.h), SizedBox(width: 8.h), - Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h), + Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h), ], ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), SizedBox(height: 16.h), @@ -191,7 +191,7 @@ class _AppointmentPaymentPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Image.asset(AppAssets.tamara_en, width: 72.h, height: 25.h) + Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h) .toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), SizedBox(height: 16.h), "Tamara" diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart index af7d053d..d16e4410 100644 --- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart +++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart @@ -61,7 +61,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget { child: Row( children: [ Image.asset( - appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, + appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, width: 52.h, height: 52.h, ), diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart index 914ac4a4..b0529694 100644 --- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart +++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart @@ -147,7 +147,7 @@ class _ImmediateLiveCarePaymentPageState extends State { child: Row( children: [ Image.asset( - appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, + appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, width: 52.h, height: 52.h, ), diff --git a/lib/presentation/emergency_services/RRT/rrt_request_type_select.dart b/lib/presentation/emergency_services/RRT/rrt_request_type_select.dart index d628c1db..66894b6f 100644 --- a/lib/presentation/emergency_services/RRT/rrt_request_type_select.dart +++ b/lib/presentation/emergency_services/RRT/rrt_request_type_select.dart @@ -131,8 +131,8 @@ class RrtRequestTypeSelect extends StatelessWidget { children: [ Image.asset(AppAssets.mada, width: 24.h, height: 24.h), Image.asset(AppAssets.visa, width: 24.h, height: 24.h), - Image.asset(AppAssets.Mastercard, width: 24.h, height: 24.h), - Image.asset(AppAssets.apple_pay, width: 24.h, height: 24.h), + Image.asset(AppAssets.mastercard, width: 24.h, height: 24.h), + Image.asset(AppAssets.applePay, width: 24.h, height: 24.h), ], ), Column( diff --git a/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_page.dart b/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_page.dart index a3524fd7..8de75184 100644 --- a/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_page.dart +++ b/lib/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_page.dart @@ -137,7 +137,7 @@ class _ErOnlineCheckinPaymentPageState extends State children: [ Image.asset(AppAssets.visa, width: 50.h, height: 50.h), SizedBox(width: 8.h), - Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h), + Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h), ], ), SizedBox(height: 16.h), @@ -176,7 +176,7 @@ class _ErOnlineCheckinPaymentPageState extends State Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Image.asset(AppAssets.tamara_en, width: 72.h, height: 25.h), + Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h), SizedBox(height: 16.h), "Tamara".needTranslation.toText16(isBold: true), ], diff --git a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart index 8be6ce29..1341af71 100644 --- a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart +++ b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart @@ -120,7 +120,7 @@ class _WalletPaymentConfirmPageState extends State { children: [ Image.asset(AppAssets.visa, width: 40.h, height: 40.h), SizedBox(width: 8.h), - Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h), + Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h), ], ).toShimmer2(isShow: false), SizedBox(height: 16.h), diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart index 31b4598b..0178720d 100644 --- a/lib/presentation/home/data/landing_page_data.dart +++ b/lib/presentation/home/data/landing_page_data.dart @@ -142,7 +142,7 @@ class LandingPageData { static List getServiceCardsList = [ ServiceCardData( - icon: AppAssets.livecare_service, + icon: AppAssets.liveCareService, title: "LiveCare", subtitle: "Explore our app, View our services and offers", largeCardIcon: AppAssets.livecare_icon, diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 10075474..454f1e7d 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -12,6 +12,7 @@ import 'package:hmg_patient_app_new/core/dependencies.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/int_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/route_extensions.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/authentication/authentication_view_model.dart'; @@ -39,6 +40,7 @@ import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card import 'package:hmg_patient_app_new/presentation/home/widgets/welcome_widget.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; import 'package:hmg_patient_app_new/presentation/profile_settings/profile_settings.dart'; +import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; @@ -104,6 +106,346 @@ class _LandingPageState extends State { super.initState(); } + Widget buildOptionsForAuthenticatedUser() { + return Column( + children: [ + SizedBox(height: 12.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Appointments & Visits".toText16(isBold: true), + Row( + children: [ + LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], + ), + ], + ).paddingSymmetrical(24.h, 0.h).onPress(() { + Navigator.of(context).push(CustomPageRoute(page: MyAppointmentsPage())); + }), + SizedBox(height: 16.h), + Consumer( + builder: (context, myAppointmentsVM, child) { + return myAppointmentsVM.isMyAppointmentsLoading + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), + child: AppointmentCard( + patientAppointmentHistoryResponseModel: PatientAppointmentHistoryResponseModel(), + myAppointmentsViewModel: myAppointmentsViewModel, + bookAppointmentsViewModel: bookAppointmentsViewModel, + isLoading: true, + isFromHomePage: true, + ), + ).paddingSymmetrical(24.h, 0.h) + : myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty + ? myAppointmentsVM.patientAppointmentsHistoryList.length == 1 + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), + child: AppointmentCard( + patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList.first, + myAppointmentsViewModel: myAppointmentsViewModel, + bookAppointmentsViewModel: bookAppointmentsViewModel, + isLoading: false, + isFromHomePage: true, + ), + ).paddingSymmetrical(24.h, 0.h) + : Swiper( + itemCount: myAppointmentsVM.isMyAppointmentsLoading + ? 3 + : myAppointmentsVM.patientAppointmentsHistoryList.length < 3 + ? myAppointmentsVM.patientAppointmentsHistoryList.length + : 3, + layout: SwiperLayout.STACK, + loop: true, + itemWidth: MediaQuery.of(context).size.width - 48.h, + indicatorLayout: PageIndicatorLayout.COLOR, + axisDirection: AxisDirection.right, + controller: _controller, + itemHeight: 200.h, + pagination: const SwiperPagination( + alignment: Alignment.bottomCenter, + margin: EdgeInsets.only(top: 210 + 8 + 24), + builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + ), + itemBuilder: (BuildContext context, int index) { + return Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), + child: AppointmentCard( + patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index], + myAppointmentsViewModel: myAppointmentsViewModel, + bookAppointmentsViewModel: bookAppointmentsViewModel, + isLoading: false, + isFromHomePage: true, + ), + ); + }, + ) + : Container( + width: double.infinity, + decoration: + RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), + child: Padding( + padding: EdgeInsets.all(12.h), + child: Column( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), + SizedBox(height: 12.h), + "You do not have any upcoming appointment. Please book an appointment".needTranslation.toText12(isCenter: true), + SizedBox(height: 12.h), + CustomButton( + text: LocaleKeys.bookAppo.tr(context: context), + onPressed: () { + Navigator.of(context).push(CustomPageRoute(page: BookAppointmentPage())); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 14.f, + fontWeight: FontWeight.w500, + padding: EdgeInsets.fromLTRB(10.h, 0, 10.h, 0), + icon: AppAssets.add_icon, + iconColor: AppColors.primaryRedColor, + height: 46.h, + ), + ], + ), + ), + ).paddingSymmetrical(24.h, 0.h); + }, + ), + + // Consumer for LiveCare pending request + Consumer( + builder: (context, immediateLiveCareVM, child) { + return immediateLiveCareVM.patientHasPendingLiveCareRequest + ? Column( + children: [ + SizedBox(height: 12.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.r, + hasShadow: true, + side: BorderSide(color: AppColors.ratingColorYellow, width: 3.h), + ), + width: double.infinity, + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + AppCustomChipWidget( + labelText: immediateLiveCareViewModel.patientLiveCareHistoryList[0].stringCallStatus, + backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.20), + textColor: AppColors.alertColor, + ), + Utils.buildSvgWithAssets(icon: AppAssets.waiting_icon, width: 24.h, height: 24.h), + // Lottie.asset(AppAnimations.pending_loading_animation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 40.h, height: 40.h, fit: BoxFit.contain), + ], + ), + SizedBox(height: 8.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "You have a pending LiveCare request".needTranslation.toText12(isBold: true), + Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon_small, + iconColor: AppColors.blackColor, + width: 20.h, + height: 15.h, + fit: BoxFit.contain, + ), + ], + ), + ], + ), + ), + ).paddingSymmetrical(24.h, 0.h).onPress(() { + Navigator.of(context).push(CustomPageRoute(page: ImmediateLiveCarePendingRequestPage())); + }), + SizedBox(height: 12.h), + ], + ) + : SizedBox(height: 12.h); + }, + ), + + // Consumer for ER Online Check-In pending request + Consumer( + builder: (context, emergencyServicesVM, child) { + return emergencyServicesVM.patientHasAdvanceERBalance + ? Column( + children: [ + SizedBox(height: 4.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.r, + hasShadow: true, + side: BorderSide(color: AppColors.primaryRedColor, width: 3.h), + ), + width: double.infinity, + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + AppCustomChipWidget( + labelText: "ER Online Check-In Request", + backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.10), + textColor: AppColors.primaryRedColor, + ), + Utils.buildSvgWithAssets( + icon: AppAssets.appointment_checkin_icon, width: 24.h, height: 24.h, iconColor: AppColors.primaryRedColor), + ], + ), + SizedBox(height: 8.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "You have ER Online Check-In Request".needTranslation.toText12(isBold: true), + Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon_small, + iconColor: AppColors.blackColor, + width: 20.h, + height: 15.h, + fit: BoxFit.contain, + ), + ], + ), + ], + ), + ), + ).paddingSymmetrical(24.h, 0.h).onPress(() { + Navigator.of(context).push(CustomPageRoute(page: ErOnlineCheckinHome())); + // context.read().navigateToEROnlineCheckIn(); + }), + SizedBox(height: 12.h), + ], + ) + : SizedBox(height: 12.h); + }, + ), + + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Quick Links".needTranslation.toText16(isBold: true), + Row( + children: [ + "View medical file".needTranslation.toText12(color: AppColors.primaryRedColor), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], + ), + ], + ).paddingSymmetrical(24.h, 0.h).onPress(() { + Navigator.of(context).push(CustomPageRoute(page: MedicalFilePage())); + }), + SizedBox(height: 16.h), + Container( + height: 121.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getLoggedInServiceCardsList.length, + shrinkWrap: true, + padding: EdgeInsets.only(left: 16.h, right: 16.h), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: SmallServiceCard( + icon: LandingPageData.getLoggedInServiceCardsList[index].icon, + title: LandingPageData.getLoggedInServiceCardsList[index].title, + subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, + iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor, + textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor, + backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor, + isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold, + serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName, + ), + ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 10.width, + ), + ), + ], + ), + ).paddingSymmetrical(24.h, 0.h), + ], + ); + } + + Widget buildOptionsForNotAuthenticatedUser() { + return Container( + height: 127.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, + shrinkWrap: true, + padding: EdgeInsets.only(left: 16.h, right: 16.h), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: SmallServiceCard( + serviceName: LandingPageData.getNotLoggedInServiceCardsList[index].serviceName, + icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon, + title: LandingPageData.getNotLoggedInServiceCardsList[index].title, + subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle, + iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor, + textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor, + backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor, + isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold, + ), + ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 0.width, + ), + ), + ], + ), + ).paddingSymmetrical(24.h, 0.h); + } + @override Widget build(BuildContext context) { bookAppointmentsViewModel = Provider.of(context, listen: false); @@ -132,7 +474,7 @@ class _LandingPageState extends State { Navigator.of(context).push(springPageRoute(ProfileSettings())); }, name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), - imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, + imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, ).expanded : CustomButton( text: LocaleKeys.loginOrRegister.tr(context: context), @@ -152,22 +494,9 @@ class _LandingPageState extends State { mainAxisSize: MainAxisSize.min, spacing: 12.h, children: [ - Utils.buildSvgWithAssets(icon: AppAssets.bell, height: 18.h, width: 18.h).onPress(() { - Navigator.of(context).push( - CustomPageRoute( - page: MedicalFilePage(), - // page: LoginScreen(), - ), - ); - }), - Utils.buildSvgWithAssets(icon: AppAssets.search_icon, height: 18.h, width: 18.h).onPress(() { - Navigator.of(context).push( - CustomPageRoute( - page: MedicalFilePage(), - // page: LoginScreen(), - ), - ); - }), + Utils.buildSvgWithAssets(icon: AppAssets.bell, height: 18.h, width: 18.h) + .onPress(() => context.navigateWithName(AppRoutes.organSelectorPage)), + Utils.buildSvgWithAssets(icon: AppAssets.search_icon, height: 18.h, width: 18.h).onPress(() {}), Utils.buildSvgWithAssets(icon: AppAssets.contact_icon, height: 18.h, width: 18.h).onPress(() { showCommonBottomSheetWithoutHeight( context, @@ -181,342 +510,7 @@ class _LandingPageState extends State { ), ], ).paddingSymmetrical(24.h, 0.h), - appState.isAuthenticated - ? Column( - children: [ - SizedBox(height: 12.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Appointments & Visits".toText16(isBold: true), - Row( - children: [ - LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), - ], - ), - ], - ).paddingSymmetrical(24.h, 0.h).onPress(() { - Navigator.of(context).push(CustomPageRoute(page: MyAppointmentsPage())); - }), - SizedBox(height: 16.h), - Consumer( - builder: (context, myAppointmentsVM, child) { - return myAppointmentsVM.isMyAppointmentsLoading - ? Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24.r, - hasShadow: true, - ), - child: AppointmentCard( - patientAppointmentHistoryResponseModel: PatientAppointmentHistoryResponseModel(), - myAppointmentsViewModel: myAppointmentsViewModel, - bookAppointmentsViewModel: bookAppointmentsViewModel, - isLoading: true, - isFromHomePage: true, - ), - ).paddingSymmetrical(24.h, 0.h) - : myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty - ? myAppointmentsVM.patientAppointmentsHistoryList.length == 1 - ? Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24.r, - hasShadow: true, - ), - child: AppointmentCard( - patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList.first, - myAppointmentsViewModel: myAppointmentsViewModel, - bookAppointmentsViewModel: bookAppointmentsViewModel, - isLoading: false, - isFromHomePage: true, - ), - ).paddingSymmetrical(24.h, 0.h) - : Swiper( - itemCount: myAppointmentsVM.isMyAppointmentsLoading - ? 3 - : myAppointmentsVM.patientAppointmentsHistoryList.length < 3 - ? myAppointmentsVM.patientAppointmentsHistoryList.length - : 3, - layout: SwiperLayout.STACK, - loop: true, - itemWidth: MediaQuery.of(context).size.width - 48.h, - indicatorLayout: PageIndicatorLayout.COLOR, - axisDirection: AxisDirection.right, - controller: _controller, - itemHeight: 200.h, - pagination: const SwiperPagination( - alignment: Alignment.bottomCenter, - margin: EdgeInsets.only(top: 210 + 8 + 24), - builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), - ), - itemBuilder: (BuildContext context, int index) { - return Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24.r, - hasShadow: true, - ), - child: AppointmentCard( - patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index], - myAppointmentsViewModel: myAppointmentsViewModel, - bookAppointmentsViewModel: bookAppointmentsViewModel, - isLoading: false, - isFromHomePage: true, - ), - ); - }, - ) - : Container( - width: double.infinity, - decoration: RoundedRectangleBorder() - .toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), - child: Padding( - padding: EdgeInsets.all(12.h), - child: Column( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), - SizedBox(height: 12.h), - "You do not have any upcoming appointment. Please book an appointment" - .needTranslation - .toText12(isCenter: true), - SizedBox(height: 12.h), - CustomButton( - text: LocaleKeys.bookAppo.tr(context: context), - onPressed: () { - Navigator.of(context).push(CustomPageRoute(page: BookAppointmentPage())); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 14.f, - fontWeight: FontWeight.w500, - padding: EdgeInsets.fromLTRB(10.h, 0, 10.h, 0), - icon: AppAssets.add_icon, - iconColor: AppColors.primaryRedColor, - height: 46.h, - ), - ], - ), - ), - ).paddingSymmetrical(24.h, 0.h); - }, - ), - - // Consumer for LiveCare pending request - Consumer( - builder: (context, immediateLiveCareVM, child) { - return immediateLiveCareVM.patientHasPendingLiveCareRequest - ? Column( - children: [ - SizedBox(height: 12.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.r, - hasShadow: true, - side: BorderSide(color: AppColors.ratingColorYellow, width: 3.h), - ), - width: double.infinity, - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - AppCustomChipWidget( - labelText: immediateLiveCareViewModel.patientLiveCareHistoryList[0].stringCallStatus, - backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.20), - textColor: AppColors.alertColor, - ), - Utils.buildSvgWithAssets(icon: AppAssets.waiting_icon, width: 24.h, height: 24.h), - // Lottie.asset(AppAnimations.pending_loading_animation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 40.h, height: 40.h, fit: BoxFit.contain), - ], - ), - SizedBox(height: 8.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "You have a pending LiveCare request".needTranslation.toText12(isBold: true), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon_small, - iconColor: AppColors.blackColor, - width: 20.h, - height: 15.h, - fit: BoxFit.contain, - ), - ], - ), - ], - ), - ), - ).paddingSymmetrical(24.h, 0.h).onPress(() { - Navigator.of(context).push(CustomPageRoute(page: ImmediateLiveCarePendingRequestPage())); - }), - SizedBox(height: 12.h), - ], - ) - : SizedBox(height: 12.h); - }, - ), - - // Consumer for ER Online Check-In pending request - Consumer( - builder: (context, emergencyServicesVM, child) { - return emergencyServicesVM.patientHasAdvanceERBalance - ? Column( - children: [ - SizedBox(height: 4.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.r, - hasShadow: true, - side: BorderSide(color: AppColors.primaryRedColor, width: 3.h), - ), - width: double.infinity, - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - AppCustomChipWidget( - labelText: "ER Online Check-In Request", - backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.10), - textColor: AppColors.primaryRedColor, - ), - Utils.buildSvgWithAssets(icon: AppAssets.appointment_checkin_icon, width: 24.h, height: 24.h, iconColor: AppColors.primaryRedColor), - ], - ), - SizedBox(height: 8.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "You have ER Online Check-In Request".needTranslation.toText12(isBold: true), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon_small, - iconColor: AppColors.blackColor, - width: 20.h, - height: 15.h, - fit: BoxFit.contain, - ), - ], - ), - ], - ), - ), - ).paddingSymmetrical(24.h, 0.h).onPress(() { - Navigator.of(context).push(CustomPageRoute(page: ErOnlineCheckinHome())); - // context.read().navigateToEROnlineCheckIn(); - }), - SizedBox(height: 12.h), - ], - ) - : SizedBox(height: 12.h); - }, - ), - - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Quick Links".needTranslation.toText16(isBold: true), - Row( - children: [ - "View medical file".needTranslation.toText12(color: AppColors.primaryRedColor), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), - ], - ), - ], - ).paddingSymmetrical(24.h, 0.h).onPress(() { - Navigator.of(context).push(CustomPageRoute(page: MedicalFilePage())); - }), - SizedBox(height: 16.h), - Container( - height: 121.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), - child: Column( - children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getLoggedInServiceCardsList.length, - shrinkWrap: true, - padding: EdgeInsets.only(left: 16.h, right: 16.h), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: SmallServiceCard( - icon: LandingPageData.getLoggedInServiceCardsList[index].icon, - title: LandingPageData.getLoggedInServiceCardsList[index].title, - subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, - iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor, - textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor, - backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor, - isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold, - serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName, - ), - ), - ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 10.width, - ), - ), - ], - ), - ).paddingSymmetrical(24.h, 0.h), - ], - ) - : Container( - height: 127.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), - child: Column( - children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, - shrinkWrap: true, - padding: EdgeInsets.only(left: 16.h, right: 16.h), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: SmallServiceCard( - serviceName: LandingPageData.getNotLoggedInServiceCardsList[index].serviceName, - icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon, - title: LandingPageData.getNotLoggedInServiceCardsList[index].title, - subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle, - iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor, - textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor, - backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor, - isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold, - ), - ), - ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 0.width, - ), - ), - ], - ), - ).paddingSymmetrical(24.h, 0.h), + if (appState.isAuthenticated) buildOptionsForAuthenticatedUser() else buildOptionsForNotAuthenticatedUser(), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/lib/presentation/home/widgets/large_service_card.dart b/lib/presentation/home/widgets/large_service_card.dart index 39895238..7a155dfc 100644 --- a/lib/presentation/home/widgets/large_service_card.dart +++ b/lib/presentation/home/widgets/large_service_card.dart @@ -34,7 +34,7 @@ class LargeServiceCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Image.asset(AppAssets.livecare_service, width: 220.w, fit: BoxFit.contain), + Image.asset(AppAssets.liveCareService, width: 220.w, fit: BoxFit.contain), SizedBox(height: 10.h), Row( children: [ diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 883ca370..05ae91a1 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -123,7 +123,7 @@ class _MedicalFilePageState extends State { fit: BoxFit.contain, ), Utils.buildImgWithAssets( - icon: AppAssets.male_img, + icon: AppAssets.maleImg, height: 32.h, border: 1.5, borderRadius: 50.r, @@ -174,7 +174,7 @@ class _MedicalFilePageState extends State { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Image.asset(appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, width: 56.w, height: 56.h), + Image.asset(appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, width: 56.w, height: 56.h), SizedBox(width: 8.w), Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart index 4db5470f..3621cc30 100644 --- a/lib/presentation/my_family/widget/family_cards.dart +++ b/lib/presentation/my_family/widget/family_cards.dart @@ -173,9 +173,9 @@ class _FamilyCardsState extends State { children: [ Utils.buildImgWithAssets( icon: profile.gender == null - ? AppAssets.dummy_user + ? AppAssets.dummyUser : profile.gender == 1 - ? ((profile.age ?? 0) < 7 ? AppAssets.babyBoyImg : AppAssets.male_img) + ? ((profile.age ?? 0) < 7 ? AppAssets.babyBoyImg : AppAssets.maleImg) : (profile.age! < 7 ? AppAssets.babyGirlImg : AppAssets.femaleImg), width: 72.h, height: 70.h, diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index ee7465d1..9e4c8088 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -29,18 +29,14 @@ import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; -import '../../core/dependencies.dart' show getIt; - class ProfileSettings extends StatefulWidget { - ProfileSettings({Key? key}) : super(key: key); + const ProfileSettings({super.key}); @override - _ProfileSettingsState createState() { - return _ProfileSettingsState(); - } + ProfileSettingsState createState() => ProfileSettingsState(); } -class _ProfileSettingsState extends State { +class ProfileSettingsState extends State { @override void initState() { super.initState(); @@ -184,7 +180,10 @@ class _ProfileSettingsState extends State { ), ], ), - "Quick Actions".needTranslation.toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w), + "Quick Actions" + .needTranslation + .toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1) + .paddingOnly(left: 24.w, right: 24.w), Container( margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h), padding: EdgeInsets.only(top: 4.h, bottom: 4.h), @@ -192,9 +191,12 @@ class _ProfileSettingsState extends State { child: Column( children: [ actionItem(AppAssets.language_change, "Language".needTranslation, () { - showCommonBottomSheetWithoutHeight(context, title: "Application Language".needTranslation, child: AppLanguageChange(), callBackFunc: () {}, isFullScreen: false); + showCommonBottomSheetWithoutHeight(context, + title: "Application Language".needTranslation, child: AppLanguageChange(), callBackFunc: () {}, isFullScreen: false); }, trailingLabel: Utils.appState.isArabic() ? "العربية".needTranslation : "English".needTranslation), 1.divider, + actionItem(AppAssets.accessibility, "Symptoms Checker".needTranslation, () {}), + 1.divider, actionItem(AppAssets.accessibility, "Accessibility".needTranslation, () {}), 1.divider, actionItem(AppAssets.bell, "Notifications Settings".needTranslation, () {}), @@ -203,7 +205,10 @@ class _ProfileSettingsState extends State { ], ), ), - "Personal Information".needTranslation.toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w), + "Personal Information" + .needTranslation + .toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1) + .paddingOnly(left: 24.w, right: 24.w), Container( margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h), padding: EdgeInsets.only(top: 4.h, bottom: 4.h), @@ -220,7 +225,10 @@ class _ProfileSettingsState extends State { ], ), ), - "Help & Support".needTranslation.toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1).paddingOnly(left: 24.w, right: 24.w), + "Help & Support" + .needTranslation + .toText18(weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1) + .paddingOnly(left: 24.w, right: 24.w), Container( margin: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h), padding: EdgeInsets.only(top: 4.h, bottom: 4.h), @@ -261,12 +269,13 @@ class _ProfileSettingsState extends State { children: [ Utils.buildSvgWithAssets(icon: icon, iconColor: AppColors.greyTextColor), label.toText14(weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1).expanded, - if (trailingLabel.isNotEmpty) trailingLabel.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1), + if (trailingLabel.isNotEmpty) + trailingLabel.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1), switchValue != null ? Switch( value: switchValue, onChanged: (value) {}, - activeColor: AppColors.successColor, + activeThumbColor: AppColors.successColor, activeTrackColor: AppColors.successColor.withValues(alpha: .15), ) : Transform.scale( @@ -295,8 +304,8 @@ class FamilyCardWidget extends StatelessWidget { Widget build(BuildContext context) { AppState appState = getIt.get(); final isActive = (profile.responseId == appState.getAuthenticatedUser()?.patientId); - final isParentUser = appState.getAuthenticatedUser()?.isParentUser ?? false; - final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID); + // final isParentUser = appState.getAuthenticatedUser()?.isParentUser ?? false; + // final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID); return Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, @@ -312,7 +321,7 @@ class FamilyCardWidget extends StatelessWidget { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Image.asset(profile.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, width: 56.w, height: 56.h), + Image.asset(profile.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, width: 56.w, height: 56.h), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, diff --git a/lib/presentation/profile_settings/widgets/family_card_widget.dart b/lib/presentation/profile_settings/widgets/family_card_widget.dart new file mode 100644 index 00000000..eaee4c02 --- /dev/null +++ b/lib/presentation/profile_settings/widgets/family_card_widget.dart @@ -0,0 +1,207 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.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/core/utils/date_util.dart'; +import 'package:hmg_patient_app_new/extensions/int_extensions.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/insurance/insurance_view_model.dart'; +import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.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/chip/app_custom_chip_widget.dart'; +import 'package:provider/provider.dart'; + +class FamilyCardWidget extends StatelessWidget { + final Function() onAddFamilyMemberPress; + final Function(FamilyFileResponseModelLists member) onFamilySwitchPress; + final FamilyFileResponseModelLists profile; + + const FamilyCardWidget({ + super.key, + required this.onAddFamilyMemberPress, + required this.profile, + required this.onFamilySwitchPress(FamilyFileResponseModelLists member), + }); + + @override + Widget build(BuildContext context) { + AppState appState = getIt.get(); + final isActive = (profile.responseId == appState.getAuthenticatedUser()?.patientId); + final isParentUser = appState.getAuthenticatedUser()?.isParentUser ?? false; + final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID); + return Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8.h, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset(profile.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, width: 56.w, height: 56.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + "${profile.patientName}".toText18(isBold: true, weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1), + AppCustomChipWidget( + icon: AppAssets.file_icon, + labelText: "${LocaleKeys.fileNo.tr(context: context)}: ${profile.responseId}", + iconSize: 12.w, + ), + ], + ).expanded, + Icon(Icons.qr_code, size: 56.h) + ], + ), + SizedBox(height: 4.h), + SizedBox( + child: Wrap( + alignment: WrapAlignment.start, + spacing: 4.w, + runSpacing: 4.h, + children: [ + AppCustomChipWidget( + labelText: "${profile.age} Years Old".needTranslation, + ), + isActive && appState.getAuthenticatedUser()!.bloodGroup != null + ? AppCustomChipWidget( + icon: AppAssets.blood_icon, + labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 8.w), + labelText: "Blood: ${appState.getAuthenticatedUser()!.bloodGroup ?? ""}", + iconColor: AppColors.primaryRedColor) + : SizedBox(), + Selector( + selector: (context, insuranceVM) => ( + isEmpty: insuranceVM.patientInsuranceList.isEmpty, + patientID: insuranceVM.patientInsuranceList.isNotEmpty ? insuranceVM.patientInsuranceList.first.patientID : null, + isLoading: insuranceVM.isInsuranceLoading, + cardValidTo: insuranceVM.patientInsuranceList.isNotEmpty ? insuranceVM.patientInsuranceList.first.cardValidTo : null + ), + builder: (context, data, child) { + if (data.isEmpty) { + return const SizedBox(); + } else if (profile.responseId != data.patientID) { + return SizedBox(); + } + + final isLoading = data.isLoading; + final isExpired = !isLoading && DateTime.now().isAfter(DateUtil.convertStringToDate(data.cardValidTo)); + + final String icon; + final String labelText; + final Color iconColor; + final Color backgroundColor; + + if (isLoading) { + icon = AppAssets.cancel_circle_icon; + labelText = "Insurance".needTranslation; + iconColor = AppColors.primaryRedColor; + backgroundColor = AppColors.primaryRedColor; + } else if (isExpired) { + icon = AppAssets.cancel_circle_icon; + labelText = "Insurance Expired".needTranslation; + iconColor = AppColors.primaryRedColor; + backgroundColor = AppColors.primaryRedColor.withValues(alpha: 0.15); + } else { + icon = AppAssets.insurance_active_icon; + labelText = "Insurance Active".needTranslation; + iconColor = AppColors.successColor; + backgroundColor = AppColors.successColor.withValues(alpha: 0.15); + } + + return AppCustomChipWidget( + icon: icon, + labelText: labelText, + iconColor: iconColor, + iconSize: 12.w, + backgroundColor: backgroundColor, + labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 8.w), + // padding: EdgeInsets.zero, + ).toShimmer2(isShow: isLoading); + }, + ) + ], + ), + ), + ], + ).paddingOnly(top: 16.h, right: 16.w, left: 16.w, bottom: 12.h), + 1.divider, + _buildActionButton(appState), + ], + ), + ); + } + + Widget _buildActionButton(AppState appState) { + final isParentUser = appState.getAuthenticatedUser()?.isParentUser ?? false; + final int? currentUserId = appState.getAuthenticatedUser()?.patientId; + final int? superUserId = appState.getSuperUserID; + + if (isParentUser) { + return _buildParentUserButton(currentUserId); + } else { + return _buildNonParentUserButton(superUserId); + } + } + + Widget _buildParentUserButton(int? currentUserId) { + final canSwitch = profile.responseId != currentUserId; + + return CustomButton( + icon: canSwitch ? AppAssets.switch_user : AppAssets.add_family, + text: canSwitch ? "Switch Family File".needTranslation : "Add a new family member".needTranslation, + onPressed: canSwitch ? () => onFamilySwitchPress(profile) : onAddFamilyMemberPress, + backgroundColor: canSwitch ? AppColors.secondaryLightRedColor : AppColors.primaryRedColor, + borderColor: canSwitch ? AppColors.secondaryLightRedColor : AppColors.primaryRedColor, + textColor: canSwitch ? AppColors.primaryRedColor : AppColors.whiteColor, + iconColor: canSwitch ? AppColors.primaryRedColor : AppColors.whiteColor, + height: isFoldable ? 50.h : 40.h, + fontSize: 14.f, + ).paddingOnly(top: 12.h, right: 16.w, left: 16.w, bottom: 16.h); + } + + Widget _buildNonParentUserButton(int? superUserId) { + final canSwitchBack = superUserId != null && superUserId == profile.responseId; + + return CustomButton( + icon: AppAssets.switch_user, + text: canSwitchBack ? "Switch Back To Family File".needTranslation : "Switch".needTranslation, + backgroundColor: canSwitchBack ? AppColors.primaryRedColor : Colors.grey.shade200, + borderColor: canSwitchBack ? AppColors.primaryRedColor : Colors.grey.shade200, + textColor: canSwitchBack ? AppColors.whiteColor : AppColors.greyTextColor, + iconColor: canSwitchBack ? AppColors.whiteColor : AppColors.greyTextColor, + onPressed: canSwitchBack ? () => onFamilySwitchPress(profile) : () {}, + height: isFoldable ? 50.h : 40.h, + fontSize: 14.f, + ).paddingOnly(top: 12.h, right: 16.w, left: 16.w, bottom: 16.h); + } + +// //TODO: Add family file switch logic here +// isRootUser +// ? CustomButton(icon: AppAssets.add_family, text: "Add a new family member".needTranslation, height: 40.h, fontSize: 14, onPressed: () {}) +// .paddingOnly(top: 12, right: 16, left: 16, bottom: 16) +// : CustomButton( +// icon: AppAssets.add_family, +// backgroundColor: AppColors.secondaryLightRedColor, +// borderColor: AppColors.secondaryLightRedColor, +// textColor: AppColors.primaryRedColor, +// iconColor: AppColors.primaryRedColor, +// text: "Switch to this medical file".needTranslation, +// height: 40.h, +// fontSize: 14, +// onPressed: () {}) +// .paddingOnly(top: 12, right: 16, left: 16, bottom: 16), +// +} diff --git a/lib/presentation/symptoms_checker/organ_selector_screen.dart b/lib/presentation/symptoms_checker/organ_selector_screen.dart new file mode 100644 index 00000000..6b9582cf --- /dev/null +++ b/lib/presentation/symptoms_checker/organ_selector_screen.dart @@ -0,0 +1,337 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.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/core/enums.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/presentation/symptoms_checker/symptoms_checker_view_model.dart'; +import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/interactive_body_widget.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/chip/app_custom_chip_widget.dart'; +import 'package:provider/provider.dart'; + +class OrganSelectorPage extends StatefulWidget { + const OrganSelectorPage({super.key}); + + @override + State createState() => _OrganSelectorPageState(); +} + +class _OrganSelectorPageState extends State { + late final AppState _appState; + + @override + void initState() { + super.initState(); + _appState = getIt.get(); + } + + void _onNextPressed(SymptomsCheckerViewModel viewModel) { + if (!viewModel.validateSelection()) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Please select at least one organ'.needTranslation), + backgroundColor: AppColors.errorColor, + ), + ); + return; + } + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Selected organs:\n\n ${viewModel.getSelectedOrganIds()}'), + backgroundColor: AppColors.successColor, + ), + ); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (_) => SymptomsCheckerViewModel(), + child: Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + appBar: _buildAppBar(), + body: Consumer( + builder: (context, viewModel, _) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitle(), + SizedBox(height: 8.h), + Expanded( + child: Stack( + children: [ + _buildBodyViewer(viewModel), + _buildViewToggleButtons(viewModel), + _buildBottomSheet(viewModel), + ], + ), + ), + ], + ); + }, + ), + ), + ); + } + + PreferredSizeWidget _buildAppBar() { + return AppBar( + backgroundColor: AppColors.bgScaffoldColor, + elevation: 0, + leading: Transform.flip( + flipX: _appState.isArabic(), + child: IconButton( + icon: Utils.buildSvgWithAssets( + icon: AppAssets.arrow_back, + width: 32.h, + height: 32.h, + ), + padding: const EdgeInsets.only(left: 12), + onPressed: () => Navigator.pop(context), + highlightColor: Colors.transparent, + ), + ), + ); + } + + Widget _buildTitle() { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: Text( + "Organ Selector".needTranslation, + style: TextStyle( + color: AppColors.textColor, + fontSize: 22.f, + fontWeight: FontWeight.w600, + ), + ), + ); + } + + Widget _buildBodyViewer(SymptomsCheckerViewModel viewModel) { + return Padding( + padding: EdgeInsets.fromLTRB(16.h, 16.h, 16.h, 45.h), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 600), + transitionBuilder: (child, animation) => _build3DFlipTransition(child, animation), + switchInCurve: Curves.easeInOut, + switchOutCurve: Curves.easeInOut, + child: InteractiveBodyWidget( + key: ValueKey(viewModel.currentView), + bodyImageAsset: viewModel.currentView == BodyView.front ? AppAssets.fullBodyFront : AppAssets.fullBodyBack, + organs: viewModel.currentOrgans, + selectedOrganIds: viewModel.selectedOrganIds, + onOrganTap: viewModel.toggleOrganSelection, + isBodyHidden: viewModel.isBodyHidden, + ), + ), + ); + } + + Widget _build3DFlipTransition(Widget child, Animation animation) { + final rotateAnimation = Tween(begin: 0.5, end: 0.0).animate( + CurvedAnimation(parent: animation, curve: Curves.easeInOut), + ); + + return AnimatedBuilder( + animation: rotateAnimation, + builder: (context, child) { + final angle = rotateAnimation.value * 3.14159; + final transform = Matrix4.identity() + ..setEntry(3, 2, 0.001) + ..rotateY(angle); + + return Transform( + transform: transform, + alignment: Alignment.center, + child: child, + ); + }, + child: child, + ); + } + + Widget _buildViewToggleButtons(SymptomsCheckerViewModel viewModel) { + return Positioned( + left: 16.w, + top: 36.h, + child: Column( + children: [ + _buildToggleButton( + icon: AppAssets.bodyIcon, + onTap: viewModel.toggleIsBodyHidden, + ), + SizedBox(height: 16.h), + _buildToggleButton( + icon: AppAssets.rotateIcon, + onTap: viewModel.toggleView, + ), + ], + ), + ); + } + + Widget _buildToggleButton({required String icon, required VoidCallback onTap}) { + return GestureDetector( + onTap: onTap, + child: Container( + width: 48.w, + height: 48.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 11.r, + ), + child: Center( + child: Utils.buildSvgWithAssets( + icon: icon, + width: 25.w, + height: 25.h, + ), + ), + ), + ); + } + + Widget _buildBottomSheet(SymptomsCheckerViewModel viewModel) { + return Positioned( + left: 0, + right: 0, + bottom: 0, + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), + child: SafeArea( + top: false, + child: Stack( + clipBehavior: Clip.none, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (viewModel.isBottomSheetExpanded) ...[ + SizedBox(height: 20.h), + _buildBottomSheetTitle(), + SizedBox(height: 12.h), + _buildSelectedOrgansContent(viewModel), + SizedBox(height: 16.h), + _buildNextButton(viewModel), + SizedBox(height: 16.h), + ] else + SizedBox(height: 20.h), + ], + ), + _buildExpandCollapseButton(viewModel), + ], + ), + ), + ), + ); + } + + Widget _buildBottomSheetTitle() { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: Text( + 'Selected Organs'.needTranslation, + style: TextStyle( + fontSize: 16.f, + fontWeight: FontWeight.w600, + color: AppColors.textColor, + ), + ), + ); + } + + Widget _buildSelectedOrgansContent(SymptomsCheckerViewModel viewModel) { + if (viewModel.selectedOrgans.isEmpty) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: Text( + 'No organs selected yet'.needTranslation, + style: TextStyle( + color: AppColors.greyTextColor, + fontSize: 14.f, + ), + ), + ); + } + + return ConstrainedBox( + constraints: BoxConstraints(maxHeight: 150.h), + child: SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: Wrap( + spacing: 8.w, + runSpacing: 8.h, + children: viewModel.selectedOrgans.map((organ) { + return AppCustomChipWidget( + labelText: organ.name, + backgroundColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + deleteIcon: AppAssets.cancel, + deleteIconColor: AppColors.primaryRedColor, + deleteIconHasColor: false, + onDeleteTap: () => viewModel.removeOrgan(organ.id), + ); + }).toList(), + ), + ), + ); + } + + Widget _buildNextButton(SymptomsCheckerViewModel viewModel) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: CustomButton( + text: 'Next'.needTranslation, + onPressed: () => _onNextPressed(viewModel), + isDisabled: viewModel.selectedOrgans.isEmpty, + backgroundColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + ), + ); + } + + Widget _buildExpandCollapseButton(SymptomsCheckerViewModel viewModel) { + return Positioned( + right: 24.w, + top: -24.h, + child: GestureDetector( + onTap: viewModel.toggleBottomSheet, + behavior: HitTestBehavior.opaque, + child: Container( + width: 70.w, + height: 70.h, + alignment: Alignment.center, + child: Container( + width: 48.w, + height: 48.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 11.r, + ), + child: Center( + child: AnimatedRotation( + duration: const Duration(milliseconds: 300), + turns: viewModel.isBottomSheetExpanded ? 0.25 : -0.25, + child: Utils.buildSvgWithAssets( + icon: AppAssets.arrowRight, + width: 25.w, + height: 25.h, + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/presentation/symptoms_checker/symptoms_checker_view_model.dart b/lib/presentation/symptoms_checker/symptoms_checker_view_model.dart new file mode 100644 index 00000000..35a23f18 --- /dev/null +++ b/lib/presentation/symptoms_checker/symptoms_checker_view_model.dart @@ -0,0 +1,108 @@ +import 'package:flutter/cupertino.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/features/symptoms_checker/models/organ_model.dart'; +import 'package:hmg_patient_app_new/features/symptoms_checker/organ_mapping_data.dart'; + +class SymptomsCheckerViewModel extends ChangeNotifier { + // State variables + bool isBodyHidden = false; + BodyView _currentView = BodyView.front; + final Set _selectedOrganIds = {}; + bool _isBottomSheetExpanded = false; + + // Getters + + BodyView get currentView => _currentView; + + Set get selectedOrganIds => _selectedOrganIds; + + bool get isBottomSheetExpanded => _isBottomSheetExpanded; + + /// Get organs for current view + List get currentOrgans => OrganData.getOrgansForView(_currentView); + + /// Get all selected organs from both views + List get selectedOrgans { + final allOrgans = [ + ...OrganData.frontViewOrgans, + ...OrganData.backViewOrgans, + ]; + return allOrgans.where((organ) => _selectedOrganIds.contains(organ.id)).toList(); + } + + /// Check if any organs are selected + bool get hasSelectedOrgans => _selectedOrganIds.isNotEmpty; + + /// Get count of selected organs + int get selectedOrgansCount => _selectedOrganIds.length; + + // Methods + + /// Toggle between front and back body view + void toggleView() { + _currentView = _currentView == BodyView.front ? BodyView.back : BodyView.front; + notifyListeners(); + } + + toggleIsBodyHidden() { + isBodyHidden = !isBodyHidden; + notifyListeners(); + } + + /// Toggle organ selection (add if not selected, remove if selected) + void toggleOrganSelection(String organId) { + if (_selectedOrganIds.contains(organId)) { + _selectedOrganIds.remove(organId); + } else { + _selectedOrganIds.add(organId); + } + notifyListeners(); + } + + /// Remove a specific organ from selection + void removeOrgan(String organId) { + _selectedOrganIds.remove(organId); + notifyListeners(); + } + + /// Clear all selected organs + void clearAllSelections() { + _selectedOrganIds.clear(); + notifyListeners(); + } + + /// Toggle bottom sheet expanded/collapsed state + void toggleBottomSheet() { + _isBottomSheetExpanded = !_isBottomSheetExpanded; + notifyListeners(); + } + + /// Set bottom sheet expanded state + void setBottomSheetExpanded(bool isExpanded) { + _isBottomSheetExpanded = isExpanded; + notifyListeners(); + } + + /// Validate if at least one organ is selected + bool validateSelection() { + return _selectedOrganIds.isNotEmpty; + } + + /// Get selected organ IDs as a list + List getSelectedOrganIds() { + return _selectedOrganIds.toList(); + } + + /// Get selected organ names as a list + List getSelectedOrganNames() { + return selectedOrgans.map((organ) => organ.name).toList(); + } + + /// Reset the view model to initial state + void reset() { + _currentView = BodyView.front; + _selectedOrganIds.clear(); + _isBottomSheetExpanded = false; + notifyListeners(); + } +} diff --git a/lib/presentation/symptoms_checker/widgets/interactive_body_widget.dart b/lib/presentation/symptoms_checker/widgets/interactive_body_widget.dart new file mode 100644 index 00000000..33663b57 --- /dev/null +++ b/lib/presentation/symptoms_checker/widgets/interactive_body_widget.dart @@ -0,0 +1,121 @@ +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:hmg_patient_app_new/features/symptoms_checker/models/organ_model.dart'; +import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/organ_dot_widget.dart'; + +class InteractiveBodyWidget extends StatefulWidget { + final String bodyImageAsset; + final List organs; + final Set selectedOrganIds; + final bool isBodyHidden; + final Function(String organId) onOrganTap; + + const InteractiveBodyWidget({ + super.key, + required this.bodyImageAsset, + required this.organs, + required this.selectedOrganIds, + required this.onOrganTap, + this.isBodyHidden = false, + }); + + @override + State createState() => _InteractiveBodyWidgetState(); +} + +class _InteractiveBodyWidgetState extends State { + double? _imageAspectRatio; + final TransformationController _transformationController = TransformationController(); + + @override + void initState() { + super.initState(); + _loadImageAspectRatio(); + } + + @override + void didUpdateWidget(InteractiveBodyWidget oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.bodyImageAsset != widget.bodyImageAsset) { + _loadImageAspectRatio(); + // Reset zoom when switching views + _transformationController.value = Matrix4.identity(); + } + } + + @override + void dispose() { + _transformationController.dispose(); + super.dispose(); + } + + Future _loadImageAspectRatio() async { + final ByteData data = await rootBundle.load(widget.bodyImageAsset); + final ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List()); + final ui.FrameInfo frameInfo = await codec.getNextFrame(); + final image = frameInfo.image; + + if (mounted) { + setState(() { + _imageAspectRatio = image.width / image.height; + }); + } + } + + @override + Widget build(BuildContext context) { + if (_imageAspectRatio == null) { + return const Center(child: CircularProgressIndicator()); + } + + return LayoutBuilder( + builder: (context, constraints) { + return Center( + child: InteractiveViewer( + transformationController: _transformationController, + minScale: 0.5, + maxScale: 4.0, + boundaryMargin: const EdgeInsets.all(20), + clipBehavior: Clip.none, + child: AspectRatio( + aspectRatio: _imageAspectRatio!, + child: LayoutBuilder( + builder: (context, imageConstraints) { + return Stack( + children: [ + // Body image + Positioned.fill( + child: Image.asset( + widget.bodyImageAsset, + fit: BoxFit.fill, + color: widget.isBodyHidden ? Colors.black.withValues(alpha: 0.5) : null, + ), + ), + + // Organ dots + ...widget.organs.map((organ) { + final isSelected = widget.selectedOrganIds.contains(organ.id); + final dotSize = 16.0; + + final leftPos = (organ.position.x * imageConstraints.maxWidth) - (dotSize / 2); + final topPos = (organ.position.y * imageConstraints.maxHeight) - (dotSize / 2); + + return Positioned( + left: leftPos, + top: topPos, + child: OrganDot(isSelected: isSelected, onTap: () => widget.onOrganTap(organ.id), size: dotSize), + ); + }), + ], + ); + }, + ), + ), + ), + ); + }, + ); + } +} diff --git a/lib/presentation/symptoms_checker/widgets/organ_dot_widget.dart b/lib/presentation/symptoms_checker/widgets/organ_dot_widget.dart new file mode 100644 index 00000000..0783dfb7 --- /dev/null +++ b/lib/presentation/symptoms_checker/widgets/organ_dot_widget.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; + +class OrganDot extends StatelessWidget { + final bool isSelected; + final VoidCallback onTap; + final double size; + + const OrganDot({super.key, required this.isSelected, required this.onTap, this.size = 50.0}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: AnimatedContainer( + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut, + width: size.w, + height: size.h, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: isSelected ? AppColors.whiteColor : AppColors.blackColor.withValues(alpha: 0.6), + ), + child: Padding( + padding: EdgeInsets.all(isSelected ? 2.w : 3.w), + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: isSelected ? AppColors.primaryRedColor : AppColors.whiteColor, + ), + child: isSelected + ? Center( + child: Container( + width: size.w * 0.25, + height: size.h * 0.25, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: AppColors.whiteColor, + ), + ), + ) + : null, + ), + ), + ), + ); + } +} diff --git a/lib/presentation/symptoms_checker/widgets/selected_organs_section.dart b/lib/presentation/symptoms_checker/widgets/selected_organs_section.dart new file mode 100644 index 00000000..dbb93ab3 --- /dev/null +++ b/lib/presentation/symptoms_checker/widgets/selected_organs_section.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/features/symptoms_checker/models/organ_model.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; + +class SelectedOrgansSection extends StatefulWidget { + final List selectedOrgans; + final Function(String organId) onRemoveOrgan; + + const SelectedOrgansSection({ + super.key, + required this.selectedOrgans, + required this.onRemoveOrgan, + }); + + @override + State createState() => _SelectedOrgansSectionState(); +} + +class _SelectedOrgansSectionState extends State { + bool _isExpanded = true; + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(16.h), + decoration: BoxDecoration( + color: AppColors.whiteColor, + borderRadius: BorderRadius.circular(12.r), + boxShadow: [ + BoxShadow( + color: AppColors.blackColor.withValues(alpha: 0.05), + blurRadius: 10, + offset: const Offset(0, -2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + GestureDetector( + onTap: () { + setState(() { + _isExpanded = !_isExpanded; + }); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Selected Organs'.needTranslation, + style: TextStyle( + fontSize: 16.f, + fontWeight: FontWeight.w600, + color: AppColors.textColor, + ), + ), + Row( + children: [ + if (widget.selectedOrgans.isNotEmpty) + Container( + padding: EdgeInsets.symmetric( + horizontal: 8.w, + vertical: 4.h, + ), + decoration: BoxDecoration( + color: AppColors.primaryRedColor, + borderRadius: BorderRadius.circular(12.r), + ), + child: Text( + '${widget.selectedOrgans.length}', + style: TextStyle( + color: AppColors.whiteColor, + fontSize: 12.f, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 8.w), + AnimatedRotation( + turns: _isExpanded ? 0.5 : 0.0, + duration: const Duration(milliseconds: 200), + child: Icon( + Icons.keyboard_arrow_down, + color: AppColors.textColorLight, + size: 24.h, + ), + ), + ], + ), + ], + ), + ), + if (_isExpanded) ...[ + SizedBox(height: 16.h), + if (widget.selectedOrgans.isEmpty) + Padding( + padding: EdgeInsets.symmetric(vertical: 8.h), + child: Text( + 'No organs selected yet'.needTranslation, + style: TextStyle( + color: AppColors.greyTextColor, + fontSize: 14.f, + ), + ), + ) + else + Wrap( + spacing: 8.w, + runSpacing: 8.h, + children: widget.selectedOrgans.map((organ) { + return AppCustomChipWidget( + labelText: organ.name, + backgroundColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + deleteIcon: AppAssets.cross_circle, + deleteIconColor: AppColors.primaryRedColor, + deleteIconHasColor: true, + onDeleteTap: () => widget.onRemoveOrgan(organ.id), + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), + ); + }).toList(), + ), + ], + ], + ), + ); + } +} diff --git a/lib/presentation/todo_section/ancillary_order_payment_page.dart b/lib/presentation/todo_section/ancillary_order_payment_page.dart index f9995dca..ad204fae 100644 --- a/lib/presentation/todo_section/ancillary_order_payment_page.dart +++ b/lib/presentation/todo_section/ancillary_order_payment_page.dart @@ -148,7 +148,7 @@ class _AncillaryOrderPaymentPageState extends State { children: [ Image.asset(AppAssets.visa, width: 50.h, height: 50.h), SizedBox(width: 8.h), - Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h), + Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h), ], ).toShimmer2(isShow: todoVM.isProcessingPayment), SizedBox(height: 16.h), diff --git a/lib/presentation/todo_section/ancillary_procedures_details_page.dart b/lib/presentation/todo_section/ancillary_procedures_details_page.dart index 449d21e1..940c8eb2 100644 --- a/lib/presentation/todo_section/ancillary_procedures_details_page.dart +++ b/lib/presentation/todo_section/ancillary_procedures_details_page.dart @@ -221,7 +221,7 @@ class _AncillaryOrderDetailsListState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.asset( - gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, + gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, width: 56.w, height: 56.h, ), diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index a0ee1e59..a144d19f 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_page_home import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_procedures_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; +import 'package:hmg_patient_app_new/presentation/symptoms_checker/organ_selector_screen.dart'; import 'package:hmg_patient_app_new/splashPage.dart'; class AppRoutes { @@ -20,6 +21,9 @@ class AppRoutes { static const String comprehensiveCheckupPage = '/comprehensiveCheckupPage'; static const String homeHealthCarePage = '/homeHealthCarePage'; + // Symptoms Checker + static const String organSelectorPage = '/organSelectorPage'; + static Map get routes => { initialRoute: (context) => SplashPage(), loginScreen: (context) => LoginScreen(), @@ -29,6 +33,7 @@ class AppRoutes { medicalFilePage: (context) => MedicalFilePage(), eReferralPage: (context) => EReferralPage(), comprehensiveCheckupPage: (context) => ComprehensiveCheckupPage(), - homeHealthCarePage: (context) => HhcProceduresPage() + homeHealthCarePage: (context) => HhcProceduresPage(), + organSelectorPage: (context) => OrganSelectorPage() }; } diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index b3abe6ab..ccdf0306 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -9,6 +9,7 @@ class AppColors { static const lightGreyEFColor = Color(0xffeaeaff); static const greyF7Color = Color(0xffF7F7F7); static const lightGrayColor = Color(0xff808080); + static const greyTextColorLight = Color(0xFFA2A2A2); // New UI Colors static const whiteColor = Color(0xFFffffff); diff --git a/lib/widgets/appbar/collapsing_list_view.dart b/lib/widgets/appbar/collapsing_list_view.dart index 8fa5f99b..e124f02f 100644 --- a/lib/widgets/appbar/collapsing_list_view.dart +++ b/lib/widgets/appbar/collapsing_list_view.dart @@ -92,7 +92,8 @@ class CollapsingListView extends StatelessWidget { t, )!, child: Padding( - padding: EdgeInsets.only(left: appState.isArabic() ? 0 : leftPadding, right: appState.isArabic() ? leftPadding : 0, bottom: bottomPadding), + padding: EdgeInsets.only( + left: appState.isArabic() ? 0 : leftPadding, right: appState.isArabic() ? leftPadding : 0, bottom: bottomPadding), child: Row( spacing: 4.h, children: [ @@ -109,11 +110,18 @@ class CollapsingListView extends StatelessWidget { color: AppColors.blackColor, letterSpacing: -0.5), ).expanded, - if (logout != null) actionButton(context, t, title: "Logout".needTranslation, icon: AppAssets.logout).onPress(logout!), - if (report != null) actionButton(context, t, title: "Report".needTranslation, icon: AppAssets.report_icon).onPress(report!), - if (history != null) actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon).onPress(history!), - if (instructions != null) actionButton(context, t, title: "Instructions".needTranslation, icon: AppAssets.requests).onPress(instructions!), - if (requests != null) actionButton(context, t, title: "Requests".needTranslation, icon: AppAssets.insurance_history_icon).onPress(requests!), + if (logout != null) + actionButton(context, t, title: "Logout".needTranslation, icon: AppAssets.logout).onPress(logout!), + if (report != null) + actionButton(context, t, title: "Report".needTranslation, icon: AppAssets.report_icon).onPress(report!), + if (history != null) + actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon) + .onPress(history!), + if (instructions != null) + actionButton(context, t, title: "Instructions".needTranslation, icon: AppAssets.requests).onPress(instructions!), + if (requests != null) + actionButton(context, t, title: "Requests".needTranslation, icon: AppAssets.insurance_history_icon) + .onPress(requests!), if (search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(search!).paddingOnly(right: 24), if (trailing != null) trailing!, ], diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index b823eae9..676f0bc1 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -3,6 +3,7 @@ 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/theme/colors.dart'; class CustomButton extends StatelessWidget { final String text; @@ -64,10 +65,10 @@ class CustomButton extends StatelessWidget { width: width, padding: padding, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: isDisabled ? backgroundColor.withValues(alpha: .5) : backgroundColor, + color: isDisabled ? AppColors.inputLabelTextColor.withValues(alpha: 0.3) : backgroundColor, borderRadius: radius, customBorder: BorderRadius.circular(radius), - side: borderSide ?? BorderSide(width: borderWidth.h, color: borderColor)), + side: borderSide ?? BorderSide(width: borderWidth.h, color: isDisabled ? Colors.transparent : borderColor)), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, @@ -86,7 +87,7 @@ class CustomButton extends StatelessWidget { overflow: textOverflow, style: context.dynamicTextStyle( fontSize: fontS, - color: isDisabled ? textColor.withValues(alpha: 0.5) : textColor, + color: isDisabled ? AppColors.greyTextColor : textColor, letterSpacing: 0, fontWeight: fontWeight, ),