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,
),