From d137e1166d2d6b0fdc4bce201ccdd5c486728609 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Mon, 9 Feb 2026 12:14:17 +0300 Subject: [PATCH 01/33] watch integration ui added. --- assets/images/svg/bluetooth.svg | 6 + assets/images/svg/watch_activity.svg | 3 + assets/images/svg/watch_activity_trailing.svg | 4 + assets/images/svg/watch_bmi.svg | 6 + assets/images/svg/watch_bmi_trailing.svg | 3 + assets/images/svg/watch_height.svg | 3 + assets/images/svg/watch_sleep.svg | 3 + assets/images/svg/watch_sleep_trailing.svg | 5 + assets/images/svg/watch_steps.svg | 5 + assets/images/svg/watch_steps_trailing.svg | 9 + assets/images/svg/watch_weight.svg | 3 + assets/images/svg/watch_weight_trailing.svg | 9 + assets/langs/ar-SA.json | 17 +- assets/langs/en-US.json | 17 +- ios/Runner.xcodeproj/project.pbxproj | 58 ---- ios/Runner/AppDelegate.swift | 10 +- lib/core/app_assets.dart | 15 ++ lib/core/common_models/smart_watch.dart | 18 ++ lib/generated/locale_keys.g.dart | 14 + .../smartwatches/activity_detail.dart | 247 ++++++++++++++++++ .../smartwatches/smart_watch_activity.dart | 147 +++++++++++ .../smartwatches/smartwatch_home_page.dart | 37 ++- .../smartwatch_instructions_page.dart | 61 ++++- lib/routes/app_routes.dart | 1 + lib/theme/colors.dart | 1 + lib/widgets/custom_tab_bar.dart | 7 + lib/widgets/graph/CustomBarGraph.dart | 240 +++++++++++++++++ 27 files changed, 881 insertions(+), 68 deletions(-) create mode 100644 assets/images/svg/bluetooth.svg create mode 100644 assets/images/svg/watch_activity.svg create mode 100644 assets/images/svg/watch_activity_trailing.svg create mode 100644 assets/images/svg/watch_bmi.svg create mode 100644 assets/images/svg/watch_bmi_trailing.svg create mode 100644 assets/images/svg/watch_height.svg create mode 100644 assets/images/svg/watch_sleep.svg create mode 100644 assets/images/svg/watch_sleep_trailing.svg create mode 100644 assets/images/svg/watch_steps.svg create mode 100644 assets/images/svg/watch_steps_trailing.svg create mode 100644 assets/images/svg/watch_weight.svg create mode 100644 assets/images/svg/watch_weight_trailing.svg create mode 100644 lib/core/common_models/smart_watch.dart create mode 100644 lib/presentation/smartwatches/activity_detail.dart create mode 100644 lib/presentation/smartwatches/smart_watch_activity.dart create mode 100644 lib/widgets/graph/CustomBarGraph.dart diff --git a/assets/images/svg/bluetooth.svg b/assets/images/svg/bluetooth.svg new file mode 100644 index 00000000..5fe2cf0c --- /dev/null +++ b/assets/images/svg/bluetooth.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/images/svg/watch_activity.svg b/assets/images/svg/watch_activity.svg new file mode 100644 index 00000000..8da915fa --- /dev/null +++ b/assets/images/svg/watch_activity.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/watch_activity_trailing.svg b/assets/images/svg/watch_activity_trailing.svg new file mode 100644 index 00000000..dc09c058 --- /dev/null +++ b/assets/images/svg/watch_activity_trailing.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/svg/watch_bmi.svg b/assets/images/svg/watch_bmi.svg new file mode 100644 index 00000000..4d34d5d0 --- /dev/null +++ b/assets/images/svg/watch_bmi.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/images/svg/watch_bmi_trailing.svg b/assets/images/svg/watch_bmi_trailing.svg new file mode 100644 index 00000000..772d18a4 --- /dev/null +++ b/assets/images/svg/watch_bmi_trailing.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/watch_height.svg b/assets/images/svg/watch_height.svg new file mode 100644 index 00000000..e70b4b89 --- /dev/null +++ b/assets/images/svg/watch_height.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/watch_sleep.svg b/assets/images/svg/watch_sleep.svg new file mode 100644 index 00000000..dd21f628 --- /dev/null +++ b/assets/images/svg/watch_sleep.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/watch_sleep_trailing.svg b/assets/images/svg/watch_sleep_trailing.svg new file mode 100644 index 00000000..dff5ab36 --- /dev/null +++ b/assets/images/svg/watch_sleep_trailing.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/svg/watch_steps.svg b/assets/images/svg/watch_steps.svg new file mode 100644 index 00000000..730c1892 --- /dev/null +++ b/assets/images/svg/watch_steps.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/svg/watch_steps_trailing.svg b/assets/images/svg/watch_steps_trailing.svg new file mode 100644 index 00000000..2c1b2f20 --- /dev/null +++ b/assets/images/svg/watch_steps_trailing.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/images/svg/watch_weight.svg b/assets/images/svg/watch_weight.svg new file mode 100644 index 00000000..3acddca5 --- /dev/null +++ b/assets/images/svg/watch_weight.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/watch_weight_trailing.svg b/assets/images/svg/watch_weight_trailing.svg new file mode 100644 index 00000000..3e2b3dd8 --- /dev/null +++ b/assets/images/svg/watch_weight_trailing.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index cb2b71ab..dd576900 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1523,5 +1523,20 @@ "bmi": "مؤشر كتلة الجسم", "yesPleaseINeedHelp": "نعم، من فضلك أريد المساعدة", "noThanksIKnowTheClinic": "لا شكراً، أعرف العيادة", - "unableToSendOTP": "تعذر إرسال رمز التحقق لمرة واحدة" + "unableToSendOTP": "تعذر إرسال رمز التحقق لمرة واحدة", + "applewatch": "ساعة آبل", + "applehealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Apple Health على هاتفك", + "unabletodetectapplicationinstalledpleasecomebackonceinstalled": "لا يمكننا اكتشاف التطبيق المثبت على جهازك. يرجى العودة إلى هنا بمجرد تثبيت هذا التطبيق.", + "applewatchshouldbeconnected": "يجب توصيل ساعة آبل", + "samsungwatch": "ساعة سامسونج", + "samsunghealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Samsung Health على هاتفك", + "samsungwatchshouldbeconnected": "يجب توصيل ساعة سامسونج", + "huaweiwatch": "ساعة هواوي", + "huaweihealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Huawei Health على هاتفك", + "huaweiwatchshouldbeconnected": "يجب توصيل ساعة هواوي", + "whoopwatch": "ساعة Whoop", + "whoophealthapplicationshouldbeinstalledinyourphone": "يجب تثبيت تطبيق Whoop Health على هاتفك", + "whoopwatchshouldbeconnected": "يجب توصيل ساعة Whoop", + "updatetheinformation": "سيتيح ذلك جمع أحدث المعلومات من ساعة آبل الخاصة بك" + } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index d937f6bc..ef7fcb9f 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1516,5 +1516,20 @@ "bmi": "BMI", "yesPleaseINeedHelp": "Yes, Please I need help", "noThanksIKnowTheClinic": "No, Thanks. I Know the clinic", - "unableToSendOTP": "Unable to send Verification OTP" + "unableToSendOTP": "Unable to send Verification OTP", + "applewatch": "Apple Watch", + "applehealthapplicationshouldbeinstalledinyourphone": "Apple Health application should be installed in your phone", + "unabletodetectapplicationinstalledpleasecomebackonceinstalled": "We are unable to detect the application installed in your device. Please come back here once you have installed this application.", + "applewatchshouldbeconnected": "Apple Watch should be connected", + "samsungwatch": "Samsung Watch", + "samsunghealthapplicationshouldbeinstalledinyourphone": "Samsung Health application should be installed in your phone", + "samsungwatchshouldbeconnected": "Samsung Watch should be connected", + "huaweiwatch": "Huawei Watch", + "huaweihealthapplicationshouldbeinstalledinyourphone": "Huawei Health application should be installed in your phone", + "huaweiwatchshouldbeconnected": "Huawei Watch should be connected", + "whoopwatch": "Whoop Watch", + "whoophealthapplicationshouldbeinstalledinyourphone": "Whoop Health application should be installed in your phone", + "whoopwatchshouldbeconnected": "Whoop Watch should be connected", + "updatetheinformation": "This will allow to gather the most up to date information from your apple watch" + } diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7a41ae2c..2a0fec9a 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -11,19 +11,7 @@ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 478CFA942E638C8E0064F3D7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */; }; - 61243B492EC5FA3700D46FA0 /* PenguinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */; }; - 61243B4C2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */; }; - 61243B502EC5FA3700D46FA0 /* PenguinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B452EC5FA3700D46FA0 /* PenguinView.swift */; }; - 61243B542EC5FA3700D46FA0 /* PenguinPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */; }; - 61243B562EC5FA3700D46FA0 /* PenguinNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */; }; - 61243B572EC5FA3700D46FA0 /* PenguinViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 766D8CB62EC60BE600D05E07 /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB32EC60BE600D05E07 /* Penguin.xcframework */; }; - 766D8CB72EC60BE600D05E07 /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB32EC60BE600D05E07 /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 766D8CB82EC60BE600D05E07 /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB42EC60BE600D05E07 /* PenNavUI.xcframework */; }; - 766D8CB92EC60BE600D05E07 /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB42EC60BE600D05E07 /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 766D8CBA2EC60BE600D05E07 /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB52EC60BE600D05E07 /* PenguinINRenderer.xcframework */; }; - 766D8CBB2EC60BE600D05E07 /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 766D8CB52EC60BE600D05E07 /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -47,9 +35,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 766D8CB72EC60BE600D05E07 /* Penguin.xcframework in Embed Frameworks */, - 766D8CBB2EC60BE600D05E07 /* PenguinINRenderer.xcframework in Embed Frameworks */, - 766D8CB92EC60BE600D05E07 /* PenNavUI.xcframework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -64,18 +49,9 @@ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 478CFA952E6E20A60064F3D7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; - 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = ""; }; - 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = ""; }; - 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = ""; }; - 61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = ""; }; - 61243B452EC5FA3700D46FA0 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = ""; }; - 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7595037DD52211B91157B0F3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 766D8CB32EC60BE600D05E07 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = ""; }; - 766D8CB42EC60BE600D05E07 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = ""; }; - 766D8CB52EC60BE600D05E07 /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenguinINRenderer.xcframework; path = Frameworks/PenguinINRenderer.xcframework; sourceTree = ""; }; 769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 8E12CEEB8E334EE22D5259D7 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; @@ -95,9 +71,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 766D8CB62EC60BE600D05E07 /* Penguin.xcframework in Frameworks */, - 766D8CBA2EC60BE600D05E07 /* PenguinINRenderer.xcframework in Frameworks */, - 766D8CB82EC60BE600D05E07 /* PenNavUI.xcframework in Frameworks */, DE1EF78253E64BE86845D2CC /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -113,32 +86,9 @@ path = RunnerTests; sourceTree = ""; }; - 61243B412EC5FA3700D46FA0 /* Helper */ = { - isa = PBXGroup; - children = ( - 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */, - ); - path = Helper; - sourceTree = ""; - }; - 61243B472EC5FA3700D46FA0 /* Penguin */ = { - isa = PBXGroup; - children = ( - 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */, - 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */, - 61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */, - 61243B452EC5FA3700D46FA0 /* PenguinView.swift */, - 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */, - ); - path = Penguin; - sourceTree = ""; - }; 766D8CB22EC60BE600D05E07 /* Frameworks */ = { isa = PBXGroup; children = ( - 766D8CB32EC60BE600D05E07 /* Penguin.xcframework */, - 766D8CB52EC60BE600D05E07 /* PenguinINRenderer.xcframework */, - 766D8CB42EC60BE600D05E07 /* PenNavUI.xcframework */, D562310E31D1DDEFA02A6C12 /* Pods_Runner.framework */, ); name = Frameworks; @@ -189,8 +139,6 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - 61243B412EC5FA3700D46FA0 /* Helper */, - 61243B472EC5FA3700D46FA0 /* Penguin */, 769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */, 478CFA952E6E20A60064F3D7 /* Runner.entitlements */, 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */, @@ -414,12 +362,6 @@ buildActionMask = 2147483647; files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 61243B492EC5FA3700D46FA0 /* PenguinModel.swift in Sources */, - 61243B4C2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift in Sources */, - 61243B502EC5FA3700D46FA0 /* PenguinView.swift in Sources */, - 61243B542EC5FA3700D46FA0 /* PenguinPlugin.swift in Sources */, - 61243B562EC5FA3700D46FA0 /* PenguinNavigator.swift in Sources */, - 61243B572EC5FA3700D46FA0 /* PenguinViewFactory.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 64d7428e..308891a7 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -16,11 +16,11 @@ import GoogleMaps return super.application(application, didFinishLaunchingWithOptions: launchOptions) } func initializePlatformChannels(){ - if let mainViewController = window?.rootViewController as? FlutterViewController{ // platform initialization suppose to be in foreground - - HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController) - - } +// if let mainViewController = window?.rootViewController as? FlutterViewController{ // platform initialization suppose to be in foreground +// +//// HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController) +// +// } } override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken:Data){ // Messaging.messaging().apnsToken = deviceToken diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 5b8d2ed5..019bd144 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -230,6 +230,21 @@ class AppAssets { static const String forward_top_nav_icon = '$svgBasePath/forward_top_nav_icon.svg'; static const String back_top_nav_icon = '$svgBasePath/back_top_nav_icon.svg'; + static const String bluetooth = '$svgBasePath/bluetooth.svg'; + + //smartwatch + static const String watchActivity = '$svgBasePath/watch_activity.svg'; + static const String watchActivityTrailing = '$svgBasePath/watch_activity_trailing.svg'; + static const String watchSteps= '$svgBasePath/watch_steps.svg'; + static const String watchStepsTrailing= '$svgBasePath/watch_steps_trailing.svg'; + static const String watchSleep= '$svgBasePath/watch_sleep.svg'; + static const String watchSleepTrailing= '$svgBasePath/watch_sleep_trailing.svg'; + static const String watchBmi= '$svgBasePath/watch_bmi.svg'; + static const String watchBmiTrailing= '$svgBasePath/watch_bmi_trailing.svg'; + static const String watchWeight= '$svgBasePath/watch_weight.svg'; + static const String watchWeightTrailing= '$svgBasePath/watch_weight_trailing.svg'; + static const String watchHeight= '$svgBasePath/watch_height.svg'; + //bottom navigation// static const String homeBottom = '$svgBasePath/home_bottom.svg'; diff --git a/lib/core/common_models/smart_watch.dart b/lib/core/common_models/smart_watch.dart new file mode 100644 index 00000000..b9259f5a --- /dev/null +++ b/lib/core/common_models/smart_watch.dart @@ -0,0 +1,18 @@ +enum SmartWatchTypes{ + apple, + samsung, + huawei, + whoop +} + + +class SmartwatchDetails { + final SmartWatchTypes watchType; + final String watchIcon; + final String smallIcon; + final String detailsTitle; + final String details; + final String secondTitle; + + SmartwatchDetails(this.watchType, this.watchIcon, this.smallIcon, this.detailsTitle, this.details, this.secondTitle); +} \ No newline at end of file diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 416d2a47..1ff22113 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1515,5 +1515,19 @@ abstract class LocaleKeys { static const yesPleaseINeedHelp = 'yesPleaseINeedHelp'; static const noThanksIKnowTheClinic = 'noThanksIKnowTheClinic'; static const unableToSendOTP = 'unableToSendOTP'; + static const applewatch = 'applewatch'; + static const applehealthapplicationshouldbeinstalledinyourphone = 'applehealthapplicationshouldbeinstalledinyourphone'; + static const unabletodetectapplicationinstalledpleasecomebackonceinstalled = 'unabletodetectapplicationinstalledpleasecomebackonceinstalled'; + static const applewatchshouldbeconnected = 'applewatchshouldbeconnected'; + static const samsungwatch = 'samsungwatch'; + static const samsunghealthapplicationshouldbeinstalledinyourphone = 'samsunghealthapplicationshouldbeinstalledinyourphone'; + static const samsungwatchshouldbeconnected = 'samsungwatchshouldbeconnected'; + static const huaweiwatch = 'huaweiwatch'; + static const huaweihealthapplicationshouldbeinstalledinyourphone = 'huaweihealthapplicationshouldbeinstalledinyourphone'; + static const huaweiwatchshouldbeconnected = 'huaweiwatchshouldbeconnected'; + static const whoopwatch = 'whoopwatch'; + static const whoophealthapplicationshouldbeinstalledinyourphone = 'whoophealthapplicationshouldbeinstalledinyourphone'; + static const whoopwatchshouldbeconnected = 'whoopwatchshouldbeconnected'; + static const updatetheinformation = 'updatetheinformation'; } diff --git a/lib/presentation/smartwatches/activity_detail.dart b/lib/presentation/smartwatches/activity_detail.dart new file mode 100644 index 00000000..cc006a61 --- /dev/null +++ b/lib/presentation/smartwatches/activity_detail.dart @@ -0,0 +1,247 @@ +import 'dart:math'; + +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/common_models/data_points.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/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; +import 'package:hmg_patient_app_new/widgets/graph/CustomBarGraph.dart'; +import 'package:intl/intl.dart' show DateFormat; + +class ActivityDetails extends StatefulWidget { + final String selectedActivity; + + const ActivityDetails({super.key, required this.selectedActivity}); + + @override + State createState() => _ActivityDetailsState(); +} + +class _ActivityDetailsState extends State { + int index = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: CollapsingListView( + title: "All Health Data".needTranslation, + child: Column( + spacing: 16.h, + children: [ + periodSelectorView((index) {}), + activityDetails(), + DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h), + child: + activityGraph().paddingOnly(left: 16.w, right: 16.w, top: 32.h, bottom: 16.h),) + ], + ).paddingSymmetrical(24.w, 24.h), + ), + ); + } + + Widget periodSelectorView(Function(int) onItemSelected) { + return DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h), + child: Row( + children: [ + Expanded( + child: CustomTabBar( + activeTextColor: Color(0xffED1C2B), + activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), + tabs: [ + CustomTabBarModel(null, "D"), + CustomTabBarModel(null, "W"), + CustomTabBarModel(null, "M"), + CustomTabBarModel(null, "6M"), + CustomTabBarModel(null, "Y"), + // CustomTabBarModel(null, "Completed".needTranslation), + ], + shouldTabExpanded: true, + onTabChange: (index) { + //todo handle the selection from viewmodel + setState(() { + this.index = index; + }); + }, + ), + ), + ], + ).paddingSymmetrical(4.w, 4.h)); + } + + Widget activityDetails() { + return DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h, hasShadow: true), + child: Column( + spacing: 8.h, + children: [ + Column( + children: [widget.selectedActivity.toText32(weight: FontWeight.w600, color: AppColors.textColor), "Average".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)], + ), + Row( + children: ["3232".toText24(color: AppColors.textGreenColor, fontWeight: FontWeight.w600), "(20-21)".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500)], + ) + ], + ).paddingSymmetrical(16.w, 16.h)); + } + + + Widget activityGraph() { + final _random = Random(); + + int randomBP() => 100 + _random.nextInt(51); // 100–150 + final List data6Months = List.generate(6, (index) { + final date = DateTime.now().subtract(Duration(days: 30 * (5 - index))); + + final value = randomBP(); + + return DataPoint( + value: value.toDouble(), + label: value.toString(), + actualValue: value.toString(), + displayTime: DateFormat('MMM').format(date), + unitOfMeasurement: 'mmHg', + time: date, + ); + }); + final List data12Months = List.generate(12, (index) { + final date = DateTime.now().subtract(Duration(days: 30 * (11 - index))); + + final value = randomBP(); + + return DataPoint( + value: value.toDouble(), + label: value.toString(), + actualValue: value.toString(), + displayTime: DateFormat('MMM').format(date), + unitOfMeasurement: 'mmHg', + time: date, + ); + }); + + List data =[]; + if(index == 0){ + data = data6Months; + } else if(index == 1){ + data = data12Months; + } else + data = [ + DataPoint( + value: 128, + label: "128", + actualValue: '128', + displayTime: 'Sun', + unitOfMeasurement: 'mmHg', + time: DateTime.now().subtract(const Duration(days: 6)), + ), + DataPoint( + value: 135, + label: "135", + actualValue: '135', + displayTime: 'Mon', + unitOfMeasurement: 'mmHg', + time: DateTime.now().subtract(const Duration(days: 5)), + ), + DataPoint( + value: 122, + label: "122", + actualValue: '122', + displayTime: 'Tue', + unitOfMeasurement: 'mmHg', + time: DateTime.now().subtract(const Duration(days: 4)), + ), + DataPoint( + value: 140, + label: "140", + actualValue: '140', + displayTime: 'Wed', + unitOfMeasurement: 'mmHg', + time: DateTime.now().subtract(const Duration(days: 3)), + ), + DataPoint( + value: 118, + label: "118", + actualValue: '118', + displayTime: 'Thu', + unitOfMeasurement: 'mmHg', + time: DateTime.now().subtract(const Duration(days: 2)), + ), + DataPoint( + value: 125, + label: "125", + actualValue: '125', + displayTime: 'Fri', + unitOfMeasurement: 'mmHg', + time: DateTime.now().subtract(const Duration(days: 1)), + ), + DataPoint( + value: 130, + label: "130", + actualValue: '130', + displayTime: 'Sat', + unitOfMeasurement: 'mmHg', + time: DateTime.now(), + ), + ]; + + return CustomBarChart( + dataPoints: data, + height: 300.h, + maxY: 150, + barColor: AppColors.bgGreenColor, + barWidth: 26.w, + barRadius: BorderRadius.circular(8), + bottomLabelColor: Colors.black, + bottomLabelSize: 12, + leftLabelInterval: .1, + leftLabelReservedSize: 40, + // Left axis label formatter (Y-axis) + leftLabelFormatter: (value) { + var labelValue = double.tryParse(value.toStringAsFixed(0)); + + if (labelValue == null) return SizedBox.shrink(); + if (labelValue == 0 || labelValue == 150 / 2 || labelValue == 150) { + return Text( + labelValue.toStringAsFixed(0), + style: const TextStyle( + color: Colors.black26, + fontSize: 11, + ), + ); + } + + return SizedBox.shrink(); + }, + + // Bottom axis label formatter (X-axis - Days) + bottomLabelFormatter: (value, dataPoints) { + final index = value.toInt(); + if (index >= 0 && index < dataPoints.length) { + return Text( + dataPoints[index].displayTime, + style: const TextStyle( + color: Colors.grey, + fontSize: 11, + ), + ); + } + return const Text(''); + }, + verticalInterval: 1/data.length, + getDrawingVerticalLine: (value) { + return FlLine( + color: AppColors.greyColor, + strokeWidth: 1, + ); + }, + showGridLines: true, + ); + } +} diff --git a/lib/presentation/smartwatches/smart_watch_activity.dart b/lib/presentation/smartwatches/smart_watch_activity.dart new file mode 100644 index 00000000..531139b8 --- /dev/null +++ b/lib/presentation/smartwatches/smart_watch_activity.dart @@ -0,0 +1,147 @@ +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/dependencies.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/smartwatches/activity_detail.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; + +class SmartWatchActivity extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: CollapsingListView( + title: "All Health Data".needTranslation, + child: Column( + spacing: 16.h, + children: [ + resultItem( + leadingIcon: AppAssets.watchActivity, + title: "Activity".needTranslation, + description: "Activity rings give you a quick visual reference of how active you are each day. ".needTranslation, + trailingIcon: AppAssets.watchActivityTrailing, + result: "21", + unitsOfMeasure: "Cal" + ).onPress((){ + getIt.get().pushPage(page: ActivityDetails( selectedActivity: "Steps")); + }), + resultItem( + leadingIcon: AppAssets.watchSteps, + title: "Steps".needTranslation, + description: "Step count is the number of steps you take throughout the day.".needTranslation, + trailingIcon: AppAssets.watchStepsTrailing, + result: "21", + unitsOfMeasure: "Steps" + ), + resultItem( + leadingIcon: AppAssets.watchSteps, + title: "Walking + Running Distance".needTranslation, + description: "This will show you the total distance you covered in a day".needTranslation, + trailingIcon: AppAssets.watchStepsTrailing, + result: "21", + unitsOfMeasure: "km" + ), + resultItem( + leadingIcon: AppAssets.watchSleep, + title: "Sleep Score".needTranslation, + description: "This will keep track of how much hours you sleep in a day".needTranslation, + trailingIcon: AppAssets.watchSleepTrailing, + result: "21", + unitsOfMeasure: "hr", + resultSecondValue: "2", + unitOfSecondMeasure: "min" + ), + resultItem( + leadingIcon: AppAssets.watchBmi, + title: "Body Mass Index".needTranslation, + description: "This will calculate your weight and height ratio to analyze the ".needTranslation, + trailingIcon: AppAssets.watchBmiTrailing, + result: "21", + unitsOfMeasure: "BMI" + ), + resultItem( + leadingIcon: AppAssets.watchWeight, + title: "Weight".needTranslation, + description: "This will calculate your weight to keep track and update history".needTranslation, + trailingIcon: AppAssets.watchWeightTrailing, + result: "21", + unitsOfMeasure: "Kg" + ), + resultItem( + leadingIcon: AppAssets.watchWeight, + title: "Height".needTranslation, + description: "This will calculate your height to keep track and update history".needTranslation, + trailingIcon: AppAssets.watchWeightTrailing, + result: "21", + unitsOfMeasure: "ft" + ) + ], + ).paddingSymmetrical(24.w, 24.h), + )); + } + + Widget resultItem({ + required String leadingIcon, + required String title, + required String description, + required String trailingIcon, + required String result, + required String unitsOfMeasure, + String? resultSecondValue, + String? unitOfSecondMeasure + }) { + return DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h), + child: Row( + spacing: 16.w, + children: [ + Expanded( + child:Column( + spacing: 8.h, + children: [ + Row( + spacing: 8.w, + children: [ + Utils.buildSvgWithAssets(icon: leadingIcon, height: 16.h, width: 14.w), + title.toText16( weight: FontWeight.w600, color: AppColors.textColor), + ], + ), + description.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + Row( + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + spacing: 2.h, + children: [ + result.toText21(weight: FontWeight.w600, color: AppColors.textColor), + unitsOfMeasure.toText10(weight: FontWeight.w500, color:AppColors.greyTextColor ), + if(resultSecondValue != null) + Visibility( + visible: resultSecondValue != null , + child: Row( + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + spacing: 2.h, + children: [ + SizedBox(width: 2.w,), + resultSecondValue.toText21(weight: FontWeight.w600, color: AppColors.textColor), + unitOfSecondMeasure!.toText10(weight: FontWeight.w500, color:AppColors.greyTextColor ) + ], + ), + ) + ], + ), + + ], + ) , + ), + Utils.buildSvgWithAssets(icon: trailingIcon, width: 72.w, height: 72.h), + ], + ).paddingSymmetrical(16.w, 16.h) + ); + } +} diff --git a/lib/presentation/smartwatches/smartwatch_home_page.dart b/lib/presentation/smartwatches/smartwatch_home_page.dart index 8fd79098..050cbf7d 100644 --- a/lib/presentation/smartwatches/smartwatch_home_page.dart +++ b/lib/presentation/smartwatches/smartwatch_home_page.dart @@ -3,12 +3,16 @@ import 'dart:io'; 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/common_models/smart_watch.dart'; +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/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/smartwatches/smartwatch_instructions_page.dart'; import 'package:hmg_patient_app_new/presentation/smartwatches/widgets/supported_watches_list.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; @@ -81,6 +85,14 @@ class SmartwatchHomePage extends StatelessWidget { text: LocaleKeys.select.tr(context: context), onPressed: () { context.read().setSelectedWatchType("apple", "assets/images/png/smartwatches/apple-watch-5.jpg"); + getIt.get().pushPage(page: SmartwatchInstructionsPage( + smartwatchDetails: SmartwatchDetails(SmartWatchTypes.apple, + "assets/images/png/smartwatches/apple-watch-5.jpg", + AppAssets.bluetooth, + LocaleKeys.applehealthapplicationshouldbeinstalledinyourphone.tr(context: context), + LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context), + LocaleKeys.applewatchshouldbeconnected.tr(context: context)), + )); }, backgroundColor: AppColors.primaryRedColor.withAlpha(40), borderColor: AppColors.primaryRedColor.withAlpha(0), @@ -106,7 +118,14 @@ class SmartwatchHomePage extends StatelessWidget { text: LocaleKeys.select.tr(context: context), onPressed: () { context.read().setSelectedWatchType("samsung", "assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg"); - }, + getIt.get().pushPage(page: SmartwatchInstructionsPage( + smartwatchDetails: SmartwatchDetails(SmartWatchTypes.samsung, + "assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg", + AppAssets.bluetooth, + LocaleKeys.samsunghealthapplicationshouldbeinstalledinyourphone.tr(context: context), + LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context), + LocaleKeys.samsungwatchshouldbeconnected.tr(context: context)), + )); }, backgroundColor: AppColors.primaryRedColor.withAlpha(40), borderColor: AppColors.primaryRedColor.withAlpha(0), textColor: AppColors.primaryRedColor, @@ -131,6 +150,14 @@ class SmartwatchHomePage extends StatelessWidget { text: LocaleKeys.select.tr(context: context), onPressed: () { context.read().setSelectedWatchType("huawei", "assets/images/png/smartwatches/Huawei_Watch.png"); + getIt.get().pushPage(page: SmartwatchInstructionsPage( + smartwatchDetails: SmartwatchDetails(SmartWatchTypes.huawei, + "assets/images/png/smartwatches/Huawei_Watch.png", + AppAssets.bluetooth, + LocaleKeys.huaweihealthapplicationshouldbeinstalledinyourphone.tr(context: context), + LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context), + LocaleKeys.huaweiwatchshouldbeconnected.tr(context: context)), + )); }, backgroundColor: AppColors.primaryRedColor.withAlpha(40), borderColor: AppColors.primaryRedColor.withAlpha(0), @@ -156,6 +183,14 @@ class SmartwatchHomePage extends StatelessWidget { text: LocaleKeys.select.tr(context: context), onPressed: () { context.read().setSelectedWatchType("whoop", "assets/images/png/smartwatches/Whoop_Watch.png"); + getIt.get().pushPage(page: SmartwatchInstructionsPage( + smartwatchDetails: SmartwatchDetails(SmartWatchTypes.whoop, + "assets/images/png/smartwatches/Whoop_Watch.png", + AppAssets.bluetooth, + LocaleKeys.whoophealthapplicationshouldbeinstalledinyourphone.tr(context: context), + LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context), + LocaleKeys.whoopwatchshouldbeconnected.tr(context: context)), + )); }, backgroundColor: AppColors.primaryRedColor.withAlpha(40), borderColor: AppColors.primaryRedColor.withAlpha(0), diff --git a/lib/presentation/smartwatches/smartwatch_instructions_page.dart b/lib/presentation/smartwatches/smartwatch_instructions_page.dart index 48683d50..949b460f 100644 --- a/lib/presentation/smartwatches/smartwatch_instructions_page.dart +++ b/lib/presentation/smartwatches/smartwatch_instructions_page.dart @@ -1,15 +1,24 @@ 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/common_models/smart_watch.dart'; +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/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/smartwatches/smart_watch_activity.dart' show SmartWatchActivity; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import '../../core/utils/utils.dart'; + class SmartwatchInstructionsPage extends StatelessWidget { - const SmartwatchInstructionsPage({super.key}); + final SmartwatchDetails smartwatchDetails; + + const SmartwatchInstructionsPage({super.key, required this.smartwatchDetails}); @override Widget build(BuildContext context) { @@ -25,6 +34,7 @@ class SmartwatchInstructionsPage extends StatelessWidget { child: CustomButton( text: LocaleKeys.getStarted.tr(context: context), onPressed: () { + getIt.get().pushPage(page: SmartWatchActivity()); }, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, @@ -35,8 +45,55 @@ class SmartwatchInstructionsPage extends StatelessWidget { height: 50.h, ).paddingSymmetrical(24.w, 30.h), ), - child: SingleChildScrollView(), + child: Column( + mainAxisSize: MainAxisSize.max, + spacing: 18.h, + children: [ + Image.asset(smartwatchDetails.watchIcon, fit: BoxFit.contain, height: 280.h,width: 280.w,), + DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h), + child: Column( + children: [ + watchContentDetails( + title: smartwatchDetails.detailsTitle, + description: smartwatchDetails.details, + icon: smartwatchDetails.smallIcon, + descriptionTextColor: AppColors.primaryRedColor + ), + Divider( + color: AppColors.dividerColor, + thickness: 1.h, + ).paddingOnly(top: 16.h, bottom: 16.h), + watchContentDetails( + title: smartwatchDetails.secondTitle, + description: LocaleKeys.updatetheinformation.tr(), + icon: AppAssets.bluetooth, + descriptionTextColor: AppColors.greyTextColor + ), + ], + ).paddingSymmetrical(16.w, 16.h), + ) + ], + ).paddingSymmetrical(24.w, 16.h), ), ); } + + + Widget watchContentDetails({required String title, required String description, required String icon, required Color descriptionTextColor}) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8.h, + children: [ + DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h), + child: Utils.buildSvgWithAssets(icon: icon, width: 40.w, height: 40.h), + + ), + + title.toText16(weight: FontWeight.w600, color: AppColors.textColor), + description.toText12(fontWeight: FontWeight.w500, color: descriptionTextColor) + ], + ); + } } diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index 9cf0ed91..8af9789d 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -39,6 +39,7 @@ import '../features/monthly_reports/monthly_reports_repo.dart'; import '../features/monthly_reports/monthly_reports_view_model.dart'; import '../features/qr_parking/qr_parking_view_model.dart'; import '../presentation/parking/paking_page.dart'; +import '../presentation/smartwatches/smartwatch_instructions_page.dart'; import '../services/error_handler_service.dart'; class AppRoutes { diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index d56178b7..f450aebb 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -113,4 +113,5 @@ class AppColors { static const Color covid29Color = Color(0xff2563EB); // #2563EB static const Color lightGreyTextColor = Color(0xFF959595); static const Color labelColorYellow = Color(0xFFFBCB6E); + static const Color tooltipColor = Color(0xFF1AACACAC); } diff --git a/lib/widgets/custom_tab_bar.dart b/lib/widgets/custom_tab_bar.dart index c30c0700..03f1b25a 100644 --- a/lib/widgets/custom_tab_bar.dart +++ b/lib/widgets/custom_tab_bar.dart @@ -21,6 +21,7 @@ class CustomTabBar extends StatefulWidget { final Color inActiveTextColor; final Color inActiveBackgroundColor; final Function(int)? onTabChange; + final bool shouldTabExpanded; const CustomTabBar({ super.key, @@ -31,6 +32,7 @@ class CustomTabBar extends StatefulWidget { this.activeBackgroundColor = const Color(0x142E3039), this.inActiveBackgroundColor = Colors.white, this.onTabChange, + this.shouldTabExpanded = false }); @override @@ -58,6 +60,11 @@ class CustomTabBarState extends State { @override Widget build(BuildContext context) { late Widget parentWidget; + if(widget.shouldTabExpanded){ + return Row( + children:List.generate(widget.tabs.length, (index)=>myTab(widget.tabs[index], index).expanded), + ); + } if (widget.tabs.length > 3) { parentWidget = ListView.separated( diff --git a/lib/widgets/graph/CustomBarGraph.dart b/lib/widgets/graph/CustomBarGraph.dart new file mode 100644 index 00000000..b90ddb00 --- /dev/null +++ b/lib/widgets/graph/CustomBarGraph.dart @@ -0,0 +1,240 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/common_models/data_points.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; + +/// A customizable bar chart widget using `fl_chart`. +/// +/// Displays a bar chart with configurable axis labels, colors, and data points. +/// Useful for visualizing comparative data, categories, or grouped values. +/// +/// **Parameters:** +/// - [dataPoints]: List of `DataPoint` objects to plot. +/// - [secondaryDataPoints]: Optional list for grouped bars (e.g., comparison data). +/// - [leftLabelFormatter]: Function to build left axis labels. +/// - [bottomLabelFormatter]: Function to build bottom axis labels. +/// - [width]: Optional width of the chart. +/// - [height]: Required height of the chart. +/// - [maxY], [maxX], [minX]: Axis bounds. +/// - [barColor]: Color of the bars. +/// - [secondaryBarColor]: Color of the secondary bars. +/// - [barRadius]: Border radius for bar corners. +/// - [barWidth]: Width of each bar. +/// - [bottomLabelColor]: Color of bottom axis labels. +/// - [bottomLabelSize]: Font size for bottom axis labels. +/// - [bottomLabelFontWeight]: Font weight for bottom axis labels. +/// - [leftLabelInterval]: Interval between left axis labels. +/// - [leftLabelReservedSize]: Reserved space for left axis labels. +/// - [showBottomTitleDates]: Whether to show bottom axis labels. +/// - [isFullScreeGraph]: Whether the graph is fullscreen. +/// - [makeGraphBasedOnActualValue]: Use `actualValue` for plotting. +/// +/// Example usage: +/// ```dart +/// CustomBarChart( +/// dataPoints: sampleData, +/// leftLabelFormatter: (value) => ..., +/// bottomLabelFormatter: (value, dataPoints) => ..., +/// height: 300, +/// maxY: 100, +/// ) +class CustomBarChart extends StatelessWidget { + final List dataPoints; + final List? secondaryDataPoints; // For grouped bar charts + final double? width; + final double height; + final double? maxY; + final double? maxX; + final double? minX; + final Color barColor; + final Color? secondaryBarColor; + final Color barGridColor; + final Color bottomLabelColor; + final double? bottomLabelSize; + final FontWeight? bottomLabelFontWeight; + final double? leftLabelInterval; + final double? leftLabelReservedSize; + final double? bottomLabelReservedSize; + final bool? showGridLines; + final GetDrawingGridLine? getDrawingVerticalLine; + final double? verticalInterval; + final double? minY; + final BorderRadius? barRadius; + final double barWidth; + + /// Creates the left label and provides it to the chart + final Widget Function(double) leftLabelFormatter; + final Widget Function(double, List) bottomLabelFormatter; + + final bool showBottomTitleDates; + final bool isFullScreeGraph; + final bool makeGraphBasedOnActualValue; + + const CustomBarChart( + {super.key, + required this.dataPoints, + this.secondaryDataPoints, + required this.leftLabelFormatter, + this.width, + required this.height, + this.maxY, + this.maxX, + this.showBottomTitleDates = true, + this.isFullScreeGraph = false, + this.barColor = AppColors.bgGreenColor, + this.secondaryBarColor, + this.barGridColor = AppColors.graphGridColor, + this.bottomLabelColor = AppColors.textColor, + this.bottomLabelFontWeight = FontWeight.w500, + this.bottomLabelSize, + this.leftLabelInterval, + this.leftLabelReservedSize, + this.bottomLabelReservedSize, + this.makeGraphBasedOnActualValue = false, + required this.bottomLabelFormatter, + this.minX, + this.showGridLines = false, + this.getDrawingVerticalLine, + this.verticalInterval, + this.minY, + this.barRadius, + this.barWidth = 16}); + + @override + Widget build(BuildContext context) { + return Material( + color: Colors.white, + child: SizedBox( + width: width, + height: height, + child: BarChart( + BarChartData( + minY: minY ?? 0, + maxY: maxY, + + barTouchData: BarTouchData( + handleBuiltInTouches: true, + touchCallback: (FlTouchEvent event, BarTouchResponse? touchResponse) { + // Let fl_chart handle the touch + }, + + touchTooltipData: BarTouchTooltipData( + getTooltipColor: (_)=>AppColors.tooltipColor, + getTooltipItem: (group, groupIndex, rod, rodIndex) { + final dataPoint = dataPoints[groupIndex]; + return BarTooltipItem( + '${dataPoint.actualValue} ${dataPoint.unitOfMeasurement ?? ""}\n${DateFormat('dd MMM, yyyy').format(dataPoint.time)}', + TextStyle( + color: Colors.black, + fontSize: 12.f, + fontWeight: FontWeight.w500, + ), + ); + }, + ), + enabled: true, + ), + titlesData: FlTitlesData( + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: leftLabelReservedSize ?? 80, + interval: leftLabelInterval ?? .1, + getTitlesWidget: (value, _) { + return leftLabelFormatter(value); + }, + ), + ), + bottomTitles: AxisTitles( + axisNameSize: 20, + sideTitles: SideTitles( + showTitles: showBottomTitleDates, + reservedSize: bottomLabelReservedSize ?? 30, + getTitlesWidget: (value, _) { + return bottomLabelFormatter(value, dataPoints); + }, + interval: 1, + ), + ), + topTitles: AxisTitles(), + rightTitles: AxisTitles(), + ), + borderData: FlBorderData( + show: true, + border: const Border( + bottom: BorderSide.none, + left: BorderSide(color: Colors.grey, width: .5), + right: BorderSide.none, + top: BorderSide.none, + ), + ), + barGroups: _buildBarGroups(dataPoints), + + gridData: FlGridData( + show: showGridLines ?? true, + drawHorizontalLine: false, + verticalInterval: verticalInterval, + getDrawingVerticalLine: getDrawingVerticalLine ?? + (value) { + return FlLine( + color: barGridColor, + strokeWidth: 1, + dashArray: [5, 5], + ); + }, + )), + ), + ), + ); + } + + /// Builds bar chart groups from data points + List _buildBarGroups(List dataPoints) { + return dataPoints.asMap().entries.map((entry) { + final index = entry.key; + final dataPoint = entry.value; + double value = (makeGraphBasedOnActualValue) + ? double.tryParse(dataPoint.actualValue) ?? 0.0 + : dataPoint.value; + + final barRods = [ + BarChartRodData( + toY: value, + color: barColor, + width: barWidth, + borderRadius: barRadius ?? BorderRadius.circular(6), + // backDrawRodData: BackgroundBarChartRodData( + // show: true, + // toY: maxY, + // color: Colors.grey[100], + // ), + ), + ]; + + // Add secondary bar if provided (for grouped bar charts) + if (secondaryDataPoints != null && index < secondaryDataPoints!.length) { + final secondaryDataPoint = secondaryDataPoints![index]; + double secondaryValue = (makeGraphBasedOnActualValue) + ? double.tryParse(secondaryDataPoint.actualValue) ?? 0.0 + : secondaryDataPoint.value; + + barRods.add( + BarChartRodData( + toY: secondaryValue, + color: secondaryBarColor ?? AppColors.blueColor, + width: barWidth, + borderRadius: barRadius ?? BorderRadius.circular(6), + ), + ); + } + + return BarChartGroupData( + x: index, + barRods: barRods, + barsSpace: 8.w + ); + }).toList(); + } +} \ No newline at end of file From 183bcce003e19ca249afc4620e02691bbba18941 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Mon, 9 Feb 2026 12:18:56 +0300 Subject: [PATCH 02/33] merge issue resolution --- assets/langs/ar-SA.json | 5 +---- assets/langs/en-US.json | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 5742fc6c..ba7c12fc 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1559,10 +1559,7 @@ "dietZoneDietDescription": "Zone Diet (~40% carbs / 30% protein / 30% fat): emphasizes hormonal balance and portion control. May improve body composition and energy for some, but requires planning; personalize with a nutrition professional.", "contextDependent": "يعتمد السياق", "calculatedValue": "القيمة المحسوبة", - "calculationFormula": "صيغة الحساب" - - - + "calculationFormula": "صيغة الحساب", "confirmYourLocation": "قم بتأكيد موقعك", "confirmYourLocationDesc": "يرجى تأكيد موقعك الحالي لعرض الاتجاهات المناسبة.", "insideHospital": "أنا داخل المستشفى", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 3ffe74fa..0652be09 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1522,7 +1522,7 @@ "servicePriceListDesc": "Below is the services price list outline the healthcare services fees for cash payments, where the insurance coverage, eligibility, and co-payment deductions will be processed in accordance with the insurance policy terms and the table of benefits of each insurance providers:", "servicePriceListRights": "The patient has the right to a free follow-up within 14 days of initial visit", "serviceName": "Service Name", - "noFreeSlot": "No free slot available for the selected date. Please select another date or check back later." + "noFreeSlot": "No free slot available for the selected date. Please select another date or check back later.", "noThanksIKnowTheClinic": "No, Thanks. I Know the clinic", "unableToSendOTP": "Unable to send Verification OTP", "aiOverView": "AI Overview", From 4912f686f910d7615a62af4114b8780a0d638a74 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Tue, 10 Feb 2026 10:55:51 +0300 Subject: [PATCH 03/33] platform channel added. --- android/app/build.gradle.kts | 4 +- .../main/kotlin/com/ejada/hmg/MainActivity.kt | 2 + .../ejada/hmg/samsung_watch/SamsungWatch.kt | 125 ++++++++++++++++++ lib/core/api_consts.dart | 2 +- .../health_provider.dart | 35 ++++- .../health_service.dart | 26 ++++ .../samsung_platform_channel.dart | 31 +++++ .../watch_connectors/create_watch_helper.dart | 14 ++ .../watch_connectors/samsung_health.dart | 25 ++++ .../watch_connectors/watch_helper.dart | 7 + .../smartwatches/smartwatch_home_page.dart | 8 +- .../smartwatch_instructions_page.dart | 4 +- 12 files changed, 274 insertions(+), 9 deletions(-) create mode 100644 android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt create mode 100644 lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart create mode 100644 lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart create mode 100644 lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart create mode 100644 lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 5d74c4d0..523a9f8e 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -7,6 +7,7 @@ plugins { id("com.google.gms.google-services") version "4.4.1" // Add the version here id("dev.flutter.flutter-gradle-plugin") id("com.huawei.agconnect") + id("kotlin-parcelize") // id("com.mapbox.gradle.application") // id("com.mapbox.gradle.plugins.ndk") } @@ -25,7 +26,7 @@ android { defaultConfig { applicationId = "com.ejada.hmg" // minSdk = 24 - minSdk = 26 + minSdk = 29 targetSdk = 36 compileSdk = 36 // targetSdk = flutter.targetSdkVersion @@ -167,6 +168,7 @@ dependencies { implementation(files("libs/PenNavUI.aar")) implementation(files("libs/Penguin.aar")) implementation(files("libs/PenguinRenderer.aar")) + api(files("libs/samsung-health-data-api.aar")) implementation("com.github.kittinunf.fuel:fuel:2.3.1") implementation("com.github.kittinunf.fuel:fuel-android:2.3.1") diff --git a/android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt b/android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt index b81a6fb0..8aac0a9d 100644 --- a/android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt +++ b/android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt @@ -9,6 +9,7 @@ import android.view.WindowManager import androidx.annotation.NonNull; import androidx.annotation.RequiresApi import com.ejada.hmg.penguin.PenguinInPlatformBridge +import com.ejada.hmg.samsung_watch.SamsungWatch import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugins.GeneratedPluginRegistrant @@ -23,6 +24,7 @@ class MainActivity: FlutterFragmentActivity() { this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) PenguinInPlatformBridge(flutterEngine, this).create() + SamsungWatch(flutterEngine, this) } override fun onRequestPermissionsResult( diff --git a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt new file mode 100644 index 00000000..e0bd2bac --- /dev/null +++ b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt @@ -0,0 +1,125 @@ +package com.ejada.hmg.samsung_watch + + + +import com.ejada.hmg.MainActivity +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import com.ejada.hmg.penguin.PenguinView +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodCall +import com.ejada.hmg.PermissionManager.HostNotificationPermissionManager +import com.ejada.hmg.PermissionManager.HostBgLocationManager +import com.ejada.hmg.PermissionManager.HostGpsStateManager +import com.samsung.android.sdk.health.data.HealthDataService +import com.samsung.android.sdk.health.data.HealthDataStore +import com.samsung.android.sdk.health.data.permission.AccessType +import com.samsung.android.sdk.health.data.permission.Permission +import com.samsung.android.sdk.health.data.request.DataTypes +import com.samsung.android.sdk.health.data.request.LocalTimeFilter +import com.samsung.android.sdk.health.data.request.Ordering +import io.flutter.plugin.common.MethodChannel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import java.time.LocalDateTime +import java.time.LocalTime + +class SamsungWatch( + private var flutterEngine: FlutterEngine, + private var mainActivity: MainActivity +) { + + private lateinit var channel: MethodChannel + private lateinit var dataStore: HealthDataStore + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + private val TAG = "SamsungWatch" + companion object { + private const val CHANNEL = "samsung_watch" + + } + init{ + create() + } + + @RequiresApi(Build.VERSION_CODES.O) + fun create() { + Log.d(TAG, "create: is called") +// openTok = OpenTok(mainActivity, flutterEngine) + channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) + channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result -> + when (call.method) { + "init" -> { + Log.d(TAG, "onMethodCall: init called") + dataStore = HealthDataService.getStore(mainActivity) + result.success("initialized") + } + + "getPermission"->{ + if(!this::dataStore.isInitialized) + result.error("DataStoreNotInitialized", "Please call init before requesting permissions", null) + val permSet = setOf( + Permission.of(DataTypes.HEART_RATE, AccessType.READ), + Permission.of(DataTypes.STEPS, AccessType.READ), + Permission.of(DataTypes.BLOOD_OXYGEN, AccessType.READ), + Permission.of(DataTypes.ACTIVITY_SUMMARY, AccessType.READ), + Permission.of(DataTypes.SLEEP, AccessType.READ), +// Permission.of(DataTypes.SKIN_TEMPERATURE, AccessType.READ), +// Permission.of(DataTypes.NUTRITION, AccessType.READ), + + ) + scope.launch { + try { + var granted = dataStore.getGrantedPermissions(permSet) + + if(granted.containsAll(granted)) + result.success("Permission Granted") // adapt result as needed + + granted = dataStore.requestPermissions(permSet, mainActivity) + + if(granted.containsAll(granted)) + result.success("Permission Granted") // adapt result as needed + result.error("PermissionError", "Permission Not Granted", null) // adapt result as needed + } catch (e: Exception) { + Log.e(TAG, "create: getPermission failed", e) + result.error("PermissionError", e.message, null) + } + } + } + + "getHeartRate"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT) + val localTimeFilter = LocalTimeFilter.of(dateTime, dateTime.minusDays(365)) + val readRequest = DataTypes.HEART_RATE.readDataRequestBuilder + .setLocalTimeFilter(localTimeFilter) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val heartRateList = dataStore.readData(readRequest).dataList + Log.d(TAG, "create: heart rate data count: ${heartRateList}") + + } + } + + + "closeCoroutineScope"->{ + destroy() + result.success("Coroutine Scope Cancelled") + } + + else -> { + result.notImplemented() + } + } + } + } + + fun destroy() { + scope.cancel() + } + +} diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index c08cdda9..df6fdf7c 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -683,7 +683,7 @@ const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard'; class ApiConsts { static const maxSmallScreen = 660; - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT diff --git a/lib/features/smartwatch_health_data/health_provider.dart b/lib/features/smartwatch_health_data/health_provider.dart index 0acb25bb..662b8141 100644 --- a/lib/features/smartwatch_health_data/health_provider.dart +++ b/lib/features/smartwatch_health_data/health_provider.dart @@ -1,6 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:health/health.dart'; +import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart'; +import 'package:hmg_patient_app_new/core/utils/loading_utils.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_service.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; + +import '../../core/dependencies.dart'; +import '../../presentation/smartwatches/smart_watch_activity.dart' show SmartWatchActivity; +import '../../services/navigation_service.dart' show NavigationService; class HealthProvider with ChangeNotifier { final HealthService _healthService = HealthService(); @@ -10,13 +17,14 @@ class HealthProvider with ChangeNotifier { String selectedTimeRange = '7D'; int selectedTabIndex = 0; - String selectedWatchType = 'apple'; + SmartWatchTypes? selectedWatchType ; String selectedWatchURL = 'assets/images/png/smartwatches/apple-watch-5.jpg'; - setSelectedWatchType(String type, String imageURL) { + setSelectedWatchType(SmartWatchTypes type, String imageURL) { selectedWatchType = type; selectedWatchURL = imageURL; notifyListeners(); + _healthService.addWatchHelper(type); } void onTabChanged(int index) { @@ -91,4 +99,27 @@ class HealthProvider with ChangeNotifier { return DateTime.now().subtract(const Duration(days: 7)); } } + + void initDevice() async { + LoaderBottomSheet.showLoader(); + notifyListeners(); + final result = await _healthService.initDevice(); + isLoading = false; + LoaderBottomSheet.hideLoader(); + if (result.isError) { + error = 'Error initializing device: ${result.asError}'; + } else { + getIt.get().pushPage(page: SmartWatchActivity()); + print('Device initialized successfully'); + } + notifyListeners(); + } + + void getHeartRate() async{ + isLoading = true; + notifyListeners(); + final result = await _healthService.getHeartRate(); + isLoading = false; + notifyListeners(); + } } diff --git a/lib/features/smartwatch_health_data/health_service.dart b/lib/features/smartwatch_health_data/health_service.dart index d3815b3b..b8ffbc99 100644 --- a/lib/features/smartwatch_health_data/health_service.dart +++ b/lib/features/smartwatch_health_data/health_service.dart @@ -1,9 +1,14 @@ +import 'dart:async'; import 'dart:io'; import 'package:health/health.dart'; +import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart'; import 'package:permission_handler/permission_handler.dart'; import 'health_utils.dart'; +import 'package:async/async.dart'; class HealthService { static final HealthService _instance = HealthService._internal(); @@ -14,6 +19,8 @@ class HealthService { final Health health = Health(); + WatchHelper? watchHelper; + final List _healthMetrics = [ HealthDataType.HEART_RATE, // HealthDataType.STEPS, @@ -161,4 +168,23 @@ class HealthService { return []; } } + + void addWatchHelper(SmartWatchTypes watchType){ + watchHelper = CreateWatchHelper.getWatchName(watchType) ; + } + + Future> initDevice() async { + if(watchHelper == null){ + return Result.error('No watch helper found'); + } + return await watchHelper!.initDevice(); + } + + FutureOr getHeartRate() async { + if (watchHelper == null) { + print('No watch helper found'); + return; + } + await watchHelper!.getHeartRate(); + } } diff --git a/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart new file mode 100644 index 00000000..ee3a3e83 --- /dev/null +++ b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart @@ -0,0 +1,31 @@ + +import 'package:async/async.dart'; +import 'package:flutter/services.dart'; +class SamsungPlatformChannel { + final MethodChannel _channel = MethodChannel('samsung_watch'); + Future> initDevice() async { + try{ + await _channel.invokeMethod('init'); + return Result.value(true); + }catch(e){ + return Result.error(e); + } + } + + Future> getRequestedPermission() async { + try{ + await _channel.invokeMethod('getPermission'); + return Result.value(true); + }catch(e){ + return Result.error(e); + } + } + Future> getHeartRate() async { + try{ + await _channel.invokeMethod('getHeartRate'); + return Result.value(true); + }catch(e){ + return Result.error(e); + } + } +} \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart new file mode 100644 index 00000000..9bc6d84d --- /dev/null +++ b/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart @@ -0,0 +1,14 @@ +import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/samsung_health.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart'; + +class CreateWatchHelper { + static WatchHelper getWatchName(SmartWatchTypes watchType) { + switch(watchType){ + case SmartWatchTypes.samsung: + return SamsungHealth(); + default: + return SamsungHealth(); + } + } +} \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart new file mode 100644 index 00000000..69d0b88a --- /dev/null +++ b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart @@ -0,0 +1,25 @@ +import 'dart:async'; + +import 'package:async/src/result/result.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart' show WatchHelper; + +class SamsungHealth extends WatchHelper { + + final SamsungPlatformChannel platformChannel = SamsungPlatformChannel(); + + @override + FutureOr getHeartRate() async { + await platformChannel.getHeartRate(); + } + + @override + Future> initDevice() async { + var result = await platformChannel.initDevice(); + if(result.isError){ + return result; + } + return await platformChannel.getRequestedPermission(); + } + +} \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart new file mode 100644 index 00000000..faa98d39 --- /dev/null +++ b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart @@ -0,0 +1,7 @@ +import 'dart:async'; +import 'package:async/async.dart'; +abstract class WatchHelper { + Future> initDevice(); + FutureOr getHeartRate(); + +} \ No newline at end of file diff --git a/lib/presentation/smartwatches/smartwatch_home_page.dart b/lib/presentation/smartwatches/smartwatch_home_page.dart index 050cbf7d..70cab3d9 100644 --- a/lib/presentation/smartwatches/smartwatch_home_page.dart +++ b/lib/presentation/smartwatches/smartwatch_home_page.dart @@ -84,7 +84,7 @@ class SmartwatchHomePage extends StatelessWidget { CustomButton( text: LocaleKeys.select.tr(context: context), onPressed: () { - context.read().setSelectedWatchType("apple", "assets/images/png/smartwatches/apple-watch-5.jpg"); + context.read().setSelectedWatchType(SmartWatchTypes.apple, "assets/images/png/smartwatches/apple-watch-5.jpg"); getIt.get().pushPage(page: SmartwatchInstructionsPage( smartwatchDetails: SmartwatchDetails(SmartWatchTypes.apple, "assets/images/png/smartwatches/apple-watch-5.jpg", @@ -117,7 +117,7 @@ class SmartwatchHomePage extends StatelessWidget { CustomButton( text: LocaleKeys.select.tr(context: context), onPressed: () { - context.read().setSelectedWatchType("samsung", "assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg"); + context.read().setSelectedWatchType(SmartWatchTypes.samsung, "assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg"); getIt.get().pushPage(page: SmartwatchInstructionsPage( smartwatchDetails: SmartwatchDetails(SmartWatchTypes.samsung, "assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg", @@ -149,7 +149,7 @@ class SmartwatchHomePage extends StatelessWidget { CustomButton( text: LocaleKeys.select.tr(context: context), onPressed: () { - context.read().setSelectedWatchType("huawei", "assets/images/png/smartwatches/Huawei_Watch.png"); + context.read().setSelectedWatchType(SmartWatchTypes.huawei, "assets/images/png/smartwatches/Huawei_Watch.png"); getIt.get().pushPage(page: SmartwatchInstructionsPage( smartwatchDetails: SmartwatchDetails(SmartWatchTypes.huawei, "assets/images/png/smartwatches/Huawei_Watch.png", @@ -182,7 +182,7 @@ class SmartwatchHomePage extends StatelessWidget { CustomButton( text: LocaleKeys.select.tr(context: context), onPressed: () { - context.read().setSelectedWatchType("whoop", "assets/images/png/smartwatches/Whoop_Watch.png"); + context.read().setSelectedWatchType(SmartWatchTypes.whoop, "assets/images/png/smartwatches/Whoop_Watch.png"); getIt.get().pushPage(page: SmartwatchInstructionsPage( smartwatchDetails: SmartwatchDetails(SmartWatchTypes.whoop, "assets/images/png/smartwatches/Whoop_Watch.png", diff --git a/lib/presentation/smartwatches/smartwatch_instructions_page.dart b/lib/presentation/smartwatches/smartwatch_instructions_page.dart index 949b460f..fa5f3135 100644 --- a/lib/presentation/smartwatches/smartwatch_instructions_page.dart +++ b/lib/presentation/smartwatches/smartwatch_instructions_page.dart @@ -12,8 +12,10 @@ import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:provider/provider.dart'; import '../../core/utils/utils.dart'; +import '../../features/smartwatch_health_data/health_provider.dart' show HealthProvider; class SmartwatchInstructionsPage extends StatelessWidget { final SmartwatchDetails smartwatchDetails; @@ -34,7 +36,7 @@ class SmartwatchInstructionsPage extends StatelessWidget { child: CustomButton( text: LocaleKeys.getStarted.tr(context: context), onPressed: () { - getIt.get().pushPage(page: SmartWatchActivity()); + context.read().initDevice(); }, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, From df0b926e59ad2c7ccd8d7c8cc59e99e0e300254a Mon Sep 17 00:00:00 2001 From: tahaalam Date: Wed, 11 Feb 2026 10:43:48 +0300 Subject: [PATCH 04/33] heart rate sleep data and steps count obtained --- .../ejada/hmg/samsung_watch/SamsungWatch.kt | 114 ++++++++++++++++-- .../ejada/hmg/samsung_watch/model/Vitals.kt | 6 + .../health_provider.dart | 1 + .../health_service.dart | 9 +- .../samsung_platform_channel.dart | 16 +++ .../watch_connectors/samsung_health.dart | 29 ++++- .../watch_connectors/watch_helper.dart | 2 + 7 files changed, 165 insertions(+), 12 deletions(-) create mode 100644 android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt diff --git a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt index e0bd2bac..11778578 100644 --- a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt +++ b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt @@ -6,25 +6,29 @@ import com.ejada.hmg.MainActivity import android.os.Build import android.util.Log import androidx.annotation.RequiresApi -import com.ejada.hmg.penguin.PenguinView import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall -import com.ejada.hmg.PermissionManager.HostNotificationPermissionManager -import com.ejada.hmg.PermissionManager.HostBgLocationManager -import com.ejada.hmg.PermissionManager.HostGpsStateManager +import com.ejada.hmg.samsung_watch.model.Vitals import com.samsung.android.sdk.health.data.HealthDataService import com.samsung.android.sdk.health.data.HealthDataStore +import com.samsung.android.sdk.health.data.data.AggregatedData +import com.samsung.android.sdk.health.data.data.HealthDataPoint import com.samsung.android.sdk.health.data.permission.AccessType import com.samsung.android.sdk.health.data.permission.Permission +import com.samsung.android.sdk.health.data.request.DataType import com.samsung.android.sdk.health.data.request.DataTypes import com.samsung.android.sdk.health.data.request.LocalTimeFilter +import com.samsung.android.sdk.health.data.request.LocalTimeGroup +import com.samsung.android.sdk.health.data.request.LocalTimeGroupUnit import com.samsung.android.sdk.health.data.request.Ordering +import com.samsung.android.sdk.health.data.response.DataResponse import io.flutter.plugin.common.MethodChannel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.launch +import java.time.Duration import java.time.LocalDateTime import java.time.LocalTime @@ -37,6 +41,9 @@ class SamsungWatch( private lateinit var dataStore: HealthDataStore private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) private val TAG = "SamsungWatch" + + + private lateinit var vitals: MutableMap> companion object { private const val CHANNEL = "samsung_watch" @@ -55,6 +62,7 @@ class SamsungWatch( "init" -> { Log.d(TAG, "onMethodCall: init called") dataStore = HealthDataService.getStore(mainActivity) + vitals = mutableMapOf() result.success("initialized") } @@ -75,13 +83,17 @@ class SamsungWatch( try { var granted = dataStore.getGrantedPermissions(permSet) - if(granted.containsAll(granted)) - result.success("Permission Granted") // adapt result as needed + if (granted.containsAll(permSet)) { + result.success("Permission Granted") + return@launch + } granted = dataStore.requestPermissions(permSet, mainActivity) - if(granted.containsAll(granted)) + if (granted.containsAll(permSet)) { result.success("Permission Granted") // adapt result as needed + return@launch + } result.error("PermissionError", "Permission Not Granted", null) // adapt result as needed } catch (e: Exception) { Log.e(TAG, "create: getPermission failed", e) @@ -91,8 +103,8 @@ class SamsungWatch( } "getHeartRate"->{ - val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT) - val localTimeFilter = LocalTimeFilter.of(dateTime, dateTime.minusDays(365)) + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) val readRequest = DataTypes.HEART_RATE.readDataRequestBuilder .setLocalTimeFilter(localTimeFilter) .setOrdering(Ordering.DESC) @@ -100,8 +112,46 @@ class SamsungWatch( scope.launch { val heartRateList = dataStore.readData(readRequest).dataList - Log.d(TAG, "create: heart rate data count: ${heartRateList}") + processHeartVital(heartRateList) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals}") + result.success("Permission Granted") + } + } + + + "getSleepData" -> { + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val readRequest = DataTypes.SLEEP.readDataRequestBuilder + .setLocalTimeFilter(localTimeFilter) + .setOrdering(Ordering.ASC) + .build() + scope.launch { + val sleepData = dataStore.readData(readRequest).dataList + processSleepVital(sleepData) + print("the data is $vitals") + Log.d(TAG, "the data is $vitals") + result.success("Permission Granted") + } + + } + + "steps"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1) + val aggregateRequest = DataType.StepsType.TOTAL.requestBuilder + .setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup) + .setOrdering(Ordering.ASC) + .build() + scope.launch { + val steps = dataStore.aggregateData(aggregateRequest) + processStepsCount(steps) + print("the data is $vitals") + Log.d(TAG, "the data is $vitals") + result.success("Permission Granted") } } @@ -118,6 +168,50 @@ class SamsungWatch( } } + private fun CoroutineScope.processStepsCount(result: DataResponse>) { + val stepCount = ArrayList>() + var totalSteps: Long = 0 + vitals["steps"] = emptyList() + result.dataList.forEach { stepData -> + val vitalData = Vitals().apply { + value = (stepData.value as Long).toString() + timeStamp = stepData.startTime.toString() + } + (vitals["sleep"] as MutableList).add(vitalData) + } + + } + + private fun CoroutineScope.processSleepVital(sleepData: List) { + vitals["sleep"] = mutableListOf() + sleepData.forEach { + (vitals["sleep"] as MutableList).add( + Vitals().apply { + timeStamp = it.startTime.toString() + value = (it.getValue(DataType.SleepType.DURATION)?.toString().toString()) + } + ) + } + } + + private suspend fun CoroutineScope.processHeartVital( + heartRateList: List, + ) { + vitals["heartRate"] = mutableListOf() + heartRateList.forEach { + (vitals["heartRate"] as MutableList).add(processHeartRateData(it)) + } + } + + private fun processHeartRateData(heartRateData: HealthDataPoint) = + Vitals().apply { + heartRateData.getValue(DataType.HeartRateType.MAX_HEART_RATE)?.let { + value = it.toString() + } + timeStamp = heartRateData.startTime.toString() + } + + fun destroy() { scope.cancel() } diff --git a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt new file mode 100644 index 00000000..c3a0c672 --- /dev/null +++ b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt @@ -0,0 +1,6 @@ +package com.ejada.hmg.samsung_watch.model + +data class Vitals( + var value : String = "", + var timeStamp : String = "" +) \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/health_provider.dart b/lib/features/smartwatch_health_data/health_provider.dart index 662b8141..23d73114 100644 --- a/lib/features/smartwatch_health_data/health_provider.dart +++ b/lib/features/smartwatch_health_data/health_provider.dart @@ -109,6 +109,7 @@ class HealthProvider with ChangeNotifier { if (result.isError) { error = 'Error initializing device: ${result.asError}'; } else { + getHeartRate(); getIt.get().pushPage(page: SmartWatchActivity()); print('Device initialized successfully'); } diff --git a/lib/features/smartwatch_health_data/health_service.dart b/lib/features/smartwatch_health_data/health_service.dart index b8ffbc99..198648a6 100644 --- a/lib/features/smartwatch_health_data/health_service.dart +++ b/lib/features/smartwatch_health_data/health_service.dart @@ -185,6 +185,13 @@ class HealthService { print('No watch helper found'); return; } - await watchHelper!.getHeartRate(); + try { + await watchHelper!.getHeartRate(); + await watchHelper!.getSleep(); + await watchHelper!.getSteps(); + }catch(e){ + print('Error getting heart rate: $e'); + } + } } diff --git a/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart index ee3a3e83..efc3e39f 100644 --- a/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart +++ b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart @@ -28,4 +28,20 @@ class SamsungPlatformChannel { return Result.error(e); } } + Future> getSleep() async { + try{ + await _channel.invokeMethod('getSleepData'); + return Result.value(true); + }catch(e){ + return Result.error(e); + } + } + Future> getSteps() async { + try{ + await _channel.invokeMethod('steps'); + return Result.value(true); + }catch(e){ + return Result.error(e); + } + } } \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart index 69d0b88a..fd1c257b 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart @@ -10,7 +10,14 @@ class SamsungHealth extends WatchHelper { @override FutureOr getHeartRate() async { - await platformChannel.getHeartRate(); + try { + await platformChannel.getHeartRate(); + + }catch(e){ + print('Error getting heart rate: $e'); + } + + } @override @@ -22,4 +29,24 @@ class SamsungHealth extends WatchHelper { return await platformChannel.getRequestedPermission(); } + @override + FutureOr getSleep() async { + try { + await platformChannel.getSleep(); + + }catch(e){ + print('Error getting heart rate: $e'); + } + } + + @override + FutureOr getSteps() async{ + try { + await platformChannel.getSteps(); + + }catch(e){ + print('Error getting heart rate: $e'); + } + } + } \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart index faa98d39..0ce360fe 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart @@ -3,5 +3,7 @@ import 'package:async/async.dart'; abstract class WatchHelper { Future> initDevice(); FutureOr getHeartRate(); + FutureOr getSleep(); + FutureOr getSteps(); } \ No newline at end of file From 5ea70397e2fc376d9ce6e7e74eb1c096aaebaa20 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Sun, 15 Feb 2026 12:13:50 +0300 Subject: [PATCH 05/33] samsung integration addded --- .../ejada/hmg/samsung_watch/SamsungWatch.kt | 118 +++++++++++++++++- .../ejada/hmg/samsung_watch/model/Vitals.kt | 11 +- .../reports/problems/problems-report.html | 2 +- .../health_provider.dart | 6 +- .../health_service.dart | 18 ++- .../smartwatch_health_data/model/Vitals.dart | 56 +++++++++ .../samsung_platform_channel.dart | 33 +++++ .../watch_connectors/samsung_health.dart | 37 ++++++ .../watch_connectors/watch_helper.dart | 4 + 9 files changed, 272 insertions(+), 13 deletions(-) create mode 100644 lib/features/smartwatch_health_data/model/Vitals.dart diff --git a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt index 11778578..09efa394 100644 --- a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt +++ b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt @@ -28,7 +28,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.launch -import java.time.Duration import java.time.LocalDateTime import java.time.LocalTime @@ -75,6 +74,8 @@ class SamsungWatch( Permission.of(DataTypes.BLOOD_OXYGEN, AccessType.READ), Permission.of(DataTypes.ACTIVITY_SUMMARY, AccessType.READ), Permission.of(DataTypes.SLEEP, AccessType.READ), + Permission.of(DataTypes.BLOOD_OXYGEN, AccessType.READ), + Permission.of(DataTypes.BODY_TEMPERATURE, AccessType.READ), // Permission.of(DataTypes.SKIN_TEMPERATURE, AccessType.READ), // Permission.of(DataTypes.NUTRITION, AccessType.READ), @@ -115,7 +116,7 @@ class SamsungWatch( processHeartVital(heartRateList) Log.d("TAG"," the data is ${vitals}") print("the data is ${vitals}") - result.success("Permission Granted") + result.success("Data is obtained") } } @@ -132,7 +133,7 @@ class SamsungWatch( processSleepVital(sleepData) print("the data is $vitals") Log.d(TAG, "the data is $vitals") - result.success("Permission Granted") + result.success("Data is obtained") } } @@ -151,10 +152,80 @@ class SamsungWatch( processStepsCount(steps) print("the data is $vitals") Log.d(TAG, "the data is $vitals") - result.success("Permission Granted") + result.success("Data is obtained") + } + } + + "activitySummary"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1) + val readRequest = DataType.ActivitySummaryType.TOTAL_CALORIES_BURNED.requestBuilder + .setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val activityResult = dataStore.aggregateData(readRequest).dataList + processActivity(activityResult) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals}") + result.success("Data is obtained") + } + } + + "bloodOxygen"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val readRequest = DataTypes.BLOOD_OXYGEN.readDataRequestBuilder + .setLocalTimeFilter(localTimeFilter) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val bloodOxygenList = dataStore.readData(readRequest).dataList + processBloodOxygen(bloodOxygenList) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals["bloodOxygen"]}") + result.success("Data is obtained") + } + } + + + "bodyTemperature"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val readRequest = DataTypes.BODY_TEMPERATURE.readDataRequestBuilder + .setLocalTimeFilter(localTimeFilter) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val bodyTemperatureList = dataStore.readData(readRequest).dataList + processBodyTemperature(bodyTemperatureList) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals["bodyTemperature"]}") + result.success("Data is obtained") } } + "retrieveData"->{ + if(vitals.isEmpty()){ + result.error("NoDataFound", "No Data was obtained", null) + return@setMethodCallHandler + } + result.success(""" + { + "heartRate": ${vitals["heartRate"]}, + "steps": ${vitals["steps"]}, + "sleep": ${vitals["sleep"]}, + "activity": ${vitals["activity"]}, + "bloodOxygen": ${vitals["bloodOxygen"]}, + "bodyTemperature": ${vitals["bodyTemperature"]} + } + """.trimIndent()) + } + "closeCoroutineScope"->{ destroy() @@ -168,16 +239,51 @@ class SamsungWatch( } } + private fun CoroutineScope.processBodyTemperature( bodyTemperatureList :List) { + vitals["bodyTemperature"] = mutableListOf() + bodyTemperatureList.forEach { stepData -> + val vitalData = Vitals().apply { + value = stepData.getValue(DataType.BodyTemperatureType.BODY_TEMPERATURE).toString() + timeStamp = stepData.endTime.toString() + } + (vitals["bodyTemperature"] as MutableList).add(vitalData) + } + } + + private fun CoroutineScope.processBloodOxygen( bloodOxygenList :List) { + vitals["bloodOxygen"] = mutableListOf() + bloodOxygenList.forEach { stepData -> + val vitalData = Vitals().apply { + value = stepData.getValue(DataType.BloodOxygenType.OXYGEN_SATURATION).toString() + timeStamp = stepData.endTime.toString() + } + (vitals["bloodOxygen"] as MutableList).add(vitalData) + } + } + + + private fun CoroutineScope.processActivity(activityResult: List>) { + + vitals["activity"] = mutableListOf() + activityResult.forEach { stepData -> + val vitalData = Vitals().apply { + value = stepData.value.toString() + timeStamp = stepData.endTime.toString() + } + (vitals["activity"] as MutableList).add(vitalData) + } + } + private fun CoroutineScope.processStepsCount(result: DataResponse>) { val stepCount = ArrayList>() var totalSteps: Long = 0 - vitals["steps"] = emptyList() + vitals["steps"] = mutableListOf() result.dataList.forEach { stepData -> val vitalData = Vitals().apply { value = (stepData.value as Long).toString() timeStamp = stepData.startTime.toString() } - (vitals["sleep"] as MutableList).add(vitalData) + (vitals["steps"] as MutableList).add(vitalData) } } diff --git a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt index c3a0c672..6ab7d37c 100644 --- a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt +++ b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt @@ -2,5 +2,12 @@ package com.ejada.hmg.samsung_watch.model data class Vitals( var value : String = "", - var timeStamp : String = "" -) \ No newline at end of file + var timeStamp :String = "" +){ + override fun toString(): String { + return """{ + "value": "$value", + "timeStamp": "$timeStamp"} + """.trimIndent() + } +} \ No newline at end of file diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html index 9b679bc9..a4239f0d 100644 --- a/android/build/reports/problems/problems-report.html +++ b/android/build/reports/problems/problems-report.html @@ -650,7 +650,7 @@ code + .copy-button { diff --git a/lib/features/smartwatch_health_data/health_provider.dart b/lib/features/smartwatch_health_data/health_provider.dart index 23d73114..7a175d8e 100644 --- a/lib/features/smartwatch_health_data/health_provider.dart +++ b/lib/features/smartwatch_health_data/health_provider.dart @@ -109,17 +109,17 @@ class HealthProvider with ChangeNotifier { if (result.isError) { error = 'Error initializing device: ${result.asError}'; } else { - getHeartRate(); + getVitals(); getIt.get().pushPage(page: SmartWatchActivity()); print('Device initialized successfully'); } notifyListeners(); } - void getHeartRate() async{ + void getVitals() async{ isLoading = true; notifyListeners(); - final result = await _healthService.getHeartRate(); + final result = await _healthService.getVitals(); isLoading = false; notifyListeners(); } diff --git a/lib/features/smartwatch_health_data/health_service.dart b/lib/features/smartwatch_health_data/health_service.dart index 198648a6..4d532a5a 100644 --- a/lib/features/smartwatch_health_data/health_service.dart +++ b/lib/features/smartwatch_health_data/health_service.dart @@ -1,8 +1,11 @@ import 'dart:async'; +import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:health/health.dart'; import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/model/Vitals.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -180,7 +183,7 @@ class HealthService { return await watchHelper!.initDevice(); } - FutureOr getHeartRate() async { + FutureOr getVitals() async { if (watchHelper == null) { print('No watch helper found'); return; @@ -189,6 +192,19 @@ class HealthService { await watchHelper!.getHeartRate(); await watchHelper!.getSleep(); await watchHelper!.getSteps(); + await watchHelper!.getActivity(); + await watchHelper!.getBodyTemperature(); + await watchHelper!.getBloodOxygen(); + Result data = await watchHelper!.retrieveData(); + + if(data.isError) { + print('Unable to get the data'); + } + + + var response = jsonDecode(data.asValue?.value?.toString()?.trim().replaceAll("\n", "")??""); + VitalsWRTType vitals = VitalsWRTType.fromMap(response); + log("the data is ${vitals}"); }catch(e){ print('Error getting heart rate: $e'); } diff --git a/lib/features/smartwatch_health_data/model/Vitals.dart b/lib/features/smartwatch_health_data/model/Vitals.dart new file mode 100644 index 00000000..bbcf1035 --- /dev/null +++ b/lib/features/smartwatch_health_data/model/Vitals.dart @@ -0,0 +1,56 @@ +class Vitals { + final String value; + final String timestamp; + + Vitals({ + required this.value, + required this.timestamp, + }); + + factory Vitals.fromMap(Map map) { + return Vitals( + value: map['value'] ?? "", + timestamp: map['timestamp'] ?? "", + ); + } +} + +class VitalsWRTType { + final List heartRate; + final List sleep; + final List step; + final List activity; + final List bodyOxygen; + final List bodyTemperature; + + VitalsWRTType({required this.bodyOxygen, required this.bodyTemperature, required this.heartRate, required this.sleep, required this.step, required this.activity}); + + factory VitalsWRTType.fromMap(Map map) { + List activity = []; + List steps = []; + List sleeps = []; + List heartRate = []; + List bodyOxygen = []; + List bodyTemperature = []; + map["activity"].forEach((element) { + activity.add(Vitals.fromMap(element)); + }); + map["steps"].forEach((element) { + steps.add(Vitals.fromMap(element)); + }); + map["sleep"].forEach((element) { + sleeps.add(Vitals.fromMap(element)); + }); + map["heartRate"].forEach((element) { + heartRate.add(Vitals.fromMap(element)); + }); + map["bloodOxygen"].forEach((element) { + bodyOxygen.add(Vitals.fromMap(element)); + }); + map["bodyTemperature"].forEach((element) { + bodyTemperature.add(Vitals.fromMap(element)); + }); + + return VitalsWRTType(bodyTemperature: bodyTemperature, bodyOxygen: bodyOxygen, heartRate: heartRate, sleep: sleeps, step: steps, activity: activity); + } +} diff --git a/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart index efc3e39f..1e3ef6df 100644 --- a/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart +++ b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart @@ -44,4 +44,37 @@ class SamsungPlatformChannel { return Result.error(e); } } + + Future> getActivity() async { + try{ + await _channel.invokeMethod('activitySummary'); + return Result.value(true); + }catch(e){ + return Result.error(e); + } + } + + Future> retrieveData() async { + try{ + return Result.value(await _channel.invokeMethod('retrieveData')); + }catch(e){ + return Result.error(e); + } + } + + Future> getBloodOxygen() async { + try{ + return Result.value(await _channel.invokeMethod('bloodOxygen')); + }catch(e){ + return Result.error(e); + } + } + + Future> getBodyTemperature() async { + try{ + return Result.value(await _channel.invokeMethod('bodyTemperature')); + }catch(e){ + return Result.error(e); + } + } } \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart index fd1c257b..c2e8fd3e 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart @@ -48,5 +48,42 @@ class SamsungHealth extends WatchHelper { print('Error getting heart rate: $e'); } } + @override + Future getActivity() async{ + try { + await platformChannel.getActivity(); + }catch(e){ + print('Error getting heart rate: $e'); + } + } + + @override + Future retrieveData() async{ + try { + return await platformChannel.retrieveData(); + }catch(e){ + print('Error getting heart rate: $e'); + } + } + + @override + Future getBloodOxygen() async{ + try { + return await platformChannel.getBloodOxygen(); + }catch(e){ + print('Error getting heart rate: $e'); + } + } + + @override + Future getBodyTemperature() async { + try { + return await platformChannel.getBodyTemperature(); + }catch(e){ + print('Error getting heart rate: $e'); + } + } + + } \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart index 0ce360fe..fe62fdc0 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart @@ -5,5 +5,9 @@ abstract class WatchHelper { FutureOr getHeartRate(); FutureOr getSleep(); FutureOr getSteps(); + Future getActivity(); + Future retrieveData(); + Future getBodyTemperature(); + Future getBloodOxygen(); } \ No newline at end of file From bfeb3dce4ef1b419c855b013fc1c4f25de50d55e Mon Sep 17 00:00:00 2001 From: tahaalam Date: Tue, 17 Feb 2026 17:01:04 +0300 Subject: [PATCH 06/33] data integration along with the data representation --- android/app/build.gradle.kts | 2 + android/app/src/main/AndroidManifest.xml | 3 + .../main/kotlin/com/ejada/hmg/MainActivity.kt | 41 +- .../{ => watch}/samsung_watch/SamsungWatch.kt | 91 +++- .../{ => watch}/samsung_watch/model/Vitals.kt | 2 +- lib/core/utils/date_util.dart | 19 + lib/extensions/string_extensions.dart | 1 + .../HealthDataTransformation.dart | 128 ++++++ .../health_provider.dart | 177 +++++++- .../health_service.dart | 12 +- .../smartwatch_health_data/model/Vitals.dart | 58 ++- .../samsung_platform_channel.dart | 10 + .../watch_connectors/create_watch_helper.dart | 3 + .../huawei_watch_connecter.dart | 86 ++++ .../watch_connectors/samsung_health.dart | 9 + .../watch_connectors/watch_helper.dart | 1 + .../hmg_services/services_page.dart | 8 +- .../smartwatches/activity_detail.dart | 399 +++++++++++------- .../smartwatches/smart_watch_activity.dart | 167 ++++++-- lib/widgets/graph/CustomBarGraph.dart | 9 +- pubspec.yaml | 2 +- 21 files changed, 1010 insertions(+), 218 deletions(-) rename android/app/src/main/kotlin/com/ejada/hmg/{ => watch}/samsung_watch/SamsungWatch.kt (79%) rename android/app/src/main/kotlin/com/ejada/hmg/{ => watch}/samsung_watch/model/Vitals.kt (81%) create mode 100644 lib/features/smartwatch_health_data/HealthDataTransformation.dart create mode 100644 lib/features/smartwatch_health_data/watch_connectors/huawei_watch_connecter.dart diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 523a9f8e..6d1321f6 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -169,6 +169,8 @@ dependencies { implementation(files("libs/Penguin.aar")) implementation(files("libs/PenguinRenderer.aar")) api(files("libs/samsung-health-data-api.aar")) + implementation("com.huawei.hms:health:6.11.0.300") + implementation("com.huawei.hms:hmscoreinstaller:6.6.0.300") implementation("com.github.kittinunf.fuel:fuel:2.3.1") implementation("com.github.kittinunf.fuel:fuel-android:2.3.1") diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8c1388b5..6ad5e539 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -134,6 +134,9 @@ android:showOnLockScreen="true" android:usesCleartextTraffic="true" tools:replace="android:label"> + = result.authAccount.authorizedScopes +// if(authorizedScopes.isNotEmpty()) { +// huaweiWatch?.getHealthAppAuthorization() +// } +// } +// } else { +// Log.w("MainActivty", "authorization fail, errorCode:" + result.getErrorCode()) +// } +// } +// } } diff --git a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt b/android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/SamsungWatch.kt similarity index 79% rename from android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt rename to android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/SamsungWatch.kt index 09efa394..09aafff2 100644 --- a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt +++ b/android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/SamsungWatch.kt @@ -1,4 +1,4 @@ -package com.ejada.hmg.samsung_watch +package com.ejada.hmg.watch.huawei.samsung_watch @@ -8,7 +8,7 @@ import android.util.Log import androidx.annotation.RequiresApi import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall -import com.ejada.hmg.samsung_watch.model.Vitals +import com.ejada.hmg.watch.huawei.samsung_watch.model.Vitals import com.samsung.android.sdk.health.data.HealthDataService import com.samsung.android.sdk.health.data.HealthDataStore import com.samsung.android.sdk.health.data.data.AggregatedData @@ -74,8 +74,8 @@ class SamsungWatch( Permission.of(DataTypes.BLOOD_OXYGEN, AccessType.READ), Permission.of(DataTypes.ACTIVITY_SUMMARY, AccessType.READ), Permission.of(DataTypes.SLEEP, AccessType.READ), - Permission.of(DataTypes.BLOOD_OXYGEN, AccessType.READ), Permission.of(DataTypes.BODY_TEMPERATURE, AccessType.READ), + Permission.of(DataTypes.EXERCISE, AccessType.READ), // Permission.of(DataTypes.SKIN_TEMPERATURE, AccessType.READ), // Permission.of(DataTypes.NUTRITION, AccessType.READ), @@ -160,7 +160,8 @@ class SamsungWatch( val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1) - val readRequest = DataType.ActivitySummaryType.TOTAL_CALORIES_BURNED.requestBuilder + val readRequest = DataType.ActivitySummaryType.TOTAL_ACTIVE_CALORIES_BURNED + .requestBuilder .setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup) .setOrdering(Ordering.DESC) .build() @@ -172,6 +173,24 @@ class SamsungWatch( print("the data is ${vitals}") result.success("Data is obtained") } + +// val readRequest = DataTypes.EXERCISE.readDataRequestBuilder +// .setLocalTimeFilter(localTimeFilter) +// .build() +// +// scope.launch{ +// try { +// val readResult = dataStore.readData(readRequest) +// val dataPoints = readResult.dataList +// +// processActivity(dataPoints) +// +// +// } catch (e: Exception) { +// e.printStackTrace() +// } +// result.success("Data is obtained") +// } } "bloodOxygen"->{ @@ -209,6 +228,24 @@ class SamsungWatch( } } + "distance"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1) + val readRequest = DataType.ActivitySummaryType.TOTAL_DISTANCE.requestBuilder + .setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val activityResult = dataStore.aggregateData(readRequest).dataList + processDistance(activityResult) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals}") + result.success("Data is obtained") + } + } + "retrieveData"->{ if(vitals.isEmpty()){ result.error("NoDataFound", "No Data was obtained", null) @@ -221,7 +258,8 @@ class SamsungWatch( "sleep": ${vitals["sleep"]}, "activity": ${vitals["activity"]}, "bloodOxygen": ${vitals["bloodOxygen"]}, - "bodyTemperature": ${vitals["bodyTemperature"]} + "bodyTemperature": ${vitals["bodyTemperature"]}, + "distance": ${vitals["distance"]} } """.trimIndent()) } @@ -239,6 +277,18 @@ class SamsungWatch( } } + private fun CoroutineScope.processDistance(activityResult: List>) { + vitals["distance"] = mutableListOf() + activityResult.forEach { stepData -> + val vitalData = Vitals().apply { + + value = stepData.value.toString() + timeStamp = stepData.startTime.toString() + } + (vitals["distance"] as MutableList).add(vitalData) + } + } + private fun CoroutineScope.processBodyTemperature( bodyTemperatureList :List) { vitals["bodyTemperature"] = mutableListOf() bodyTemperatureList.forEach { stepData -> @@ -262,16 +312,43 @@ class SamsungWatch( } +// private fun CoroutineScope.processActivity(activityResult: List>) { +// +// vitals["activity"] = mutableListOf() +// activityResult.forEach { stepData -> +// val vitalData = Vitals().apply { +// +// value = stepData.value.toString() +// timeStamp = stepData.startTime.toString() +// } +// (vitals["activity"] as MutableList).add(vitalData) +// } +// } private fun CoroutineScope.processActivity(activityResult: List>) { vitals["activity"] = mutableListOf() activityResult.forEach { stepData -> val vitalData = Vitals().apply { + value = stepData.value.toString() - timeStamp = stepData.endTime.toString() + timeStamp = stepData.startTime.toString() } (vitals["activity"] as MutableList).add(vitalData) } + +// dataPoints.forEach { dataPoint -> +// val sessions = dataPoint.getValue(DataType.ExerciseType.SESSIONS) +// +// sessions?.forEach { session -> +// +// val exerciseSessionCalories = session.calories +// val vitalData = Vitals().apply { +// value = exerciseSessionCalories.toString() +// timeStamp = session.startTime.toString() +// } +// (vitals["activity"] as MutableList).add(vitalData) +// } +// } } private fun CoroutineScope.processStepsCount(result: DataResponse>) { @@ -294,7 +371,7 @@ class SamsungWatch( (vitals["sleep"] as MutableList).add( Vitals().apply { timeStamp = it.startTime.toString() - value = (it.getValue(DataType.SleepType.DURATION)?.toString().toString()) + value = (it.getValue(DataType.SleepType.DURATION)?.toMillis().toString()) } ) } diff --git a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt b/android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/model/Vitals.kt similarity index 81% rename from android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt rename to android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/model/Vitals.kt index 6ab7d37c..3b5cdfe4 100644 --- a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt +++ b/android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/model/Vitals.kt @@ -1,4 +1,4 @@ -package com.ejada.hmg.samsung_watch.model +package com.ejada.hmg.watch.huawei.samsung_watch.model data class Vitals( var value : String = "", diff --git a/lib/core/utils/date_util.dart b/lib/core/utils/date_util.dart index 2b134735..f15214a1 100644 --- a/lib/core/utils/date_util.dart +++ b/lib/core/utils/date_util.dart @@ -1,7 +1,10 @@ import 'package:device_calendar/device_calendar.dart'; import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:intl/intl.dart'; +import '../app_state.dart' show AppState; + class DateUtil { /// convert String To Date function /// [date] String we want to convert @@ -198,6 +201,10 @@ class DateUtil { } } + static getMonthDayAsOfLang(int month){ + return getIt.get().isArabic()?getMonthArabic(month):getMonth(month); + } + /// get month by /// [month] convert month number in to month name in Arabic static getMonthArabic(int month) { @@ -268,6 +275,10 @@ class DateUtil { return date ?? DateTime.now(); } + static getWeekDayAsOfLang(int weekDay){ + return getIt.get().isArabic()?getWeekDayArabic(weekDay):getWeekDayEnglish(weekDay); + } + /// get month by /// [weekDay] convert week day in int to week day name static getWeekDay(int weekDay) { @@ -580,6 +591,14 @@ class DateUtil { return weekDayName; // Return as-is if not recognized } } + + static String millisToHourMin(int milliseconds) { + int totalMinutes = (milliseconds / 60000).floor(); // convert ms → min + int hours = totalMinutes ~/ 60; // integer division + int minutes = totalMinutes % 60; // remaining minutes + + return '${hours} hr ${minutes} min'; + } } extension OnlyDate on DateTime { diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 6a009428..2deefa78 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -18,6 +18,7 @@ extension CapExtension on String { String get needTranslation => this; String get capitalizeFirstofEach => trim().isNotEmpty ? trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : ""; + } extension EmailValidator on String { diff --git a/lib/features/smartwatch_health_data/HealthDataTransformation.dart b/lib/features/smartwatch_health_data/HealthDataTransformation.dart new file mode 100644 index 00000000..d389135d --- /dev/null +++ b/lib/features/smartwatch_health_data/HealthDataTransformation.dart @@ -0,0 +1,128 @@ +import 'dart:math'; + +import 'package:hmg_patient_app_new/core/common_models/data_points.dart'; +import 'package:intl/intl.dart'; + +import 'model/Vitals.dart'; + +enum Durations { + daily("daily"), + weekly("weekly"), + monthly("weekly"), + halfYearly("halfYearly"), + yearly("yearly"); + + final String value; + const Durations(this.value); +} + +class HealthDataTransformation { + Map> transformVitalsToDataPoints(VitalsWRTType vitals, String filterType, String selectedSection,) { + final Map> dataPointMap = {}; + Map> data = vitals.getVitals(); + // Group data based on the filter type + Map> groupedData = {}; + // List > items = data.values.toList(); + List keys = data.keys.toList(); + var count = 0; + List item = data[selectedSection] ?? []; + // for(var item in items) { + List dataPoints = []; + + for (var vital in item) { + String key = ""; + if (vital.value == "" || vital.timestamp == "") continue; + var parseDate = DateTime.parse(vital.timestamp); + var currentDate = normalizeToStartOfDay(DateTime.now()); + if (filterType == Durations.daily.value) { + if(isBetweenInclusive(parseDate, currentDate, DateTime.now())) { + key = DateFormat('yyyy-MM-dd HH').format(DateTime.parse(vital.timestamp)); + groupedData.putIfAbsent(key, () => []).add(vital); + }// Group by hour + } else if (filterType == Durations.weekly.value) { + if(isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 7)), DateTime.now())) { + key = DateFormat('yyyy-MM-dd').format(DateTime.parse(vital.timestamp)); + groupedData.putIfAbsent(key, () => []).add(vital); + + } // Group by day + } else if (filterType == Durations.monthly.value) { + if(isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 30)), DateTime.now())) { + key = DateFormat('yyyy-MM-dd').format(DateTime.parse(vital.timestamp)); + groupedData.putIfAbsent(key, () => []).add(vital); + + } // Group by day + } else if (filterType == Durations.halfYearly.value || filterType == Durations.yearly.value) { + if(isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: filterType == Durations.halfYearly.value?180: 365)), DateTime.now())) { + key = DateFormat('yyyy-MM').format(DateTime.parse(vital.timestamp)); + groupedData.putIfAbsent(key, () => []).add(vital); + + } // Group by month + } else { + throw ArgumentError('Invalid filter type'); + } + } + print("the size of groupData is ${groupedData.values.length}"); + + // Process grouped data + groupedData.forEach((key, values) { + double sum = values.fold(0, (acc, v) => acc + num.parse(v.value)); + double mean = sum / values.length; + + double finalValue = filterType == 'weekly' ? mean : sum; + print("the final value is $finalValue for the key $key with the original values ${values.map((v) => v.value).toList()} and uom is ${values.first.unitOfMeasure}"); + dataPoints.add(DataPoint( + value: smartScale(finalValue), + label: key, + actualValue: finalValue.toStringAsFixed(2), + displayTime: key, + unitOfMeasurement:values.first.unitOfMeasure , + time: DateTime.parse(values.first.timestamp), + )); + }); + + dataPointMap[filterType] = dataPoints; + // } + return dataPointMap; + } + + double smartScale(double number) { + // if (number <= 0) return 0; + // final _random = Random(); + // double ratio = number / 100; + // + // double scalingFactor = ratio > 1 ? 100 / number : 100; + // + // double result = (number / 100) * scalingFactor; + // print("the ratio is ${ratio.toInt()+1}"); + // double max = (100+_random.nextInt(ratio.toInt()+10)).toDouble(); + // + // return result.clamp(0, max); + + if (number <= 0) return 0; + + final random = Random(); + + // Smooth compression scaling + double baseScaled = number <20 ? number:100 * (number / (number + 100)); + + // Random factor between 0.9 and 1.1 (±10%) + double randomFactor = number <20 ? random.nextDouble() * 1.5: 0.9 + random.nextDouble() * 0.2; + + double result = baseScaled * randomFactor; + + return result.clamp(0, 100); + } + + DateTime normalizeToStartOfDay(DateTime date) { + return DateTime(date.year, date.month, date.day); + } + bool isBetweenInclusive( + DateTime target, + DateTime start, + DateTime end, + ) { + return !normalizeToStartOfDay(target).isBefore(start) && !normalizeToStartOfDay(target).isAfter(end); + } + + +} \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/health_provider.dart b/lib/features/smartwatch_health_data/health_provider.dart index 7a175d8e..905c8d5a 100644 --- a/lib/features/smartwatch_health_data/health_provider.dart +++ b/lib/features/smartwatch_health_data/health_provider.dart @@ -1,13 +1,18 @@ import 'package:flutter/foundation.dart'; import 'package:health/health.dart'; import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart'; +import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/loading_utils.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_service.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import '../../core/common_models/data_points.dart'; import '../../core/dependencies.dart'; +import '../../presentation/smartwatches/activity_detail.dart' show ActivityDetails; import '../../presentation/smartwatches/smart_watch_activity.dart' show SmartWatchActivity; import '../../services/navigation_service.dart' show NavigationService; +import 'HealthDataTransformation.dart'; +import 'model/Vitals.dart'; class HealthProvider with ChangeNotifier { final HealthService _healthService = HealthService(); @@ -19,6 +24,19 @@ class HealthProvider with ChangeNotifier { SmartWatchTypes? selectedWatchType ; String selectedWatchURL = 'assets/images/png/smartwatches/apple-watch-5.jpg'; + HealthDataTransformation healthDataTransformation = HealthDataTransformation(); + + String selectedSection = ""; + Map> daily = {}; + Map> weekly = {}; + Map> monthly = {}; + Map> halgyearly = {}; + Map> yearly = {}; + Map> selectedData = {}; + Durations selectedDuration = Durations.daily; + VitalsWRTType? vitals; + double? averageValue; + String? averageValueString; setSelectedWatchType(SmartWatchTypes type, String imageURL) { selectedWatchType = type; @@ -109,18 +127,167 @@ class HealthProvider with ChangeNotifier { if (result.isError) { error = 'Error initializing device: ${result.asError}'; } else { - getVitals(); + LoaderBottomSheet.hideLoader(); + + LoaderBottomSheet.showLoader(); + await getVitals(); + LoaderBottomSheet.hideLoader(); + await Future.delayed(Duration(seconds: 5)); getIt.get().pushPage(page: SmartWatchActivity()); print('Device initialized successfully'); } notifyListeners(); } - void getVitals() async{ - isLoading = true; - notifyListeners(); + Future getVitals() async { + final result = await _healthService.getVitals(); - isLoading = false; + vitals = result; + LoaderBottomSheet.hideLoader(); + notifyListeners(); } + + mapValuesForFilters( + Durations filter, + String selectedSection, + ) { + if (vitals == null) return {}; + + switch (filter) { + case Durations.daily: + if (daily.isNotEmpty) { + selectedData = daily; + break; + } + selectedData = daily = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.daily.value, selectedSection); + break; + case Durations.weekly: + if (weekly.isNotEmpty) { + selectedData = daily; + break; + } + selectedData = weekly = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.weekly.value, selectedSection); + break; + case Durations.monthly: + if (monthly.isNotEmpty) { + selectedData = monthly; + break; + } + selectedData = monthly = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.monthly.value, selectedSection); + break; + case Durations.halfYearly: + if (halgyearly.isNotEmpty) { + selectedData = halgyearly; + break; + } + selectedData = halgyearly = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.halfYearly.value, selectedSection); + break; + case Durations.yearly: + if (yearly.isNotEmpty) { + selectedData = yearly; + break; + } + selectedData = yearly = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.yearly.value, selectedSection); + break; + default: + {} + ; + } + notifyListeners(); + } + + void navigateToDetails(String value, {required String sectionName, required String uom}) { + getIt.get().pushPage(page: ActivityDetails(selectedActivity: value, sectionName:sectionName, uom: uom,)); + } + + void saveSelectedSection(String value) { + // if(selectedSection == value) return; + selectedSection = value; + } + + void deleteDataIfSectionIsDifferent(String value) { + // if(selectedSection == value){ + // return; + // } + daily.clear(); + weekly.clear(); + halgyearly.clear(); + monthly.clear(); + yearly.clear(); + selectedSection = ""; + selectedSection = ""; + averageValue = null; + averageValueString = null; + selectedDuration = Durations.daily; + } + + void fetchData() { + // if(selectedSection == value) return; + mapValuesForFilters(selectedDuration, selectedSection); + getAverageForData(); + transformValueIfSleepIsSelected(); + } + + void setDurations(Durations duration) { + selectedDuration = duration; + } + + void getAverageForData() { + if (selectedData.isEmpty) { + averageValue = 0.0; + notifyListeners(); + return; + } + double total = 0; + int count = 0; + selectedData.forEach((key, dataPoints) { + for (var dataPoint in dataPoints) { + total += num.parse(dataPoint.actualValue).toInt(); + count++; + } + }); + averageValue = count > 0 ? total / count : null; + notifyListeners(); + } + + void transformValueIfSleepIsSelected() { + if (selectedSection != "sleep") return; + if (averageValue == null) { + averageValueString = null; + return; + } + averageValueString = DateUtil.millisToHourMin(averageValue?.toInt() ?? 0); + averageValue = null; + notifyListeners(); + } + + String firstNonEmptyValue(List dataPoints) { + try { + return dataPoints.firstWhere((dp) => dp.value != null && dp.value!.trim().isNotEmpty).value; + } catch (e) { + return "0"; // no non-empty value found + } + } + + String sumOfNonEmptyData(List list) { + final now = DateTime.now().toLocal(); + final today = DateTime(now.year, now.month, now.day); + + var data = double.parse(list + .where((dp) { + final localDate = DateTime.parse(dp.timestamp); + final normalized = DateTime(localDate.year, localDate.month, localDate.day); + + return normalized.isAtSameMomentAs(today); + }) + .fold("0", (sum, dp) => (double.parse(sum) + double.parse(dp.value)).toString()) + .toString()); + var formattedString = data.toStringAsFixed(2); + + if (formattedString.endsWith('.00')) { + return formattedString.substring(0, formattedString.length - 3); + } + return formattedString; + } } diff --git a/lib/features/smartwatch_health_data/health_service.dart b/lib/features/smartwatch_health_data/health_service.dart index 4d532a5a..1cc42014 100644 --- a/lib/features/smartwatch_health_data/health_service.dart +++ b/lib/features/smartwatch_health_data/health_service.dart @@ -183,31 +183,31 @@ class HealthService { return await watchHelper!.initDevice(); } - FutureOr getVitals() async { + Future getVitals() async { if (watchHelper == null) { print('No watch helper found'); - return; + return null; } try { + await watchHelper!.getActivity(); await watchHelper!.getHeartRate(); await watchHelper!.getSleep(); await watchHelper!.getSteps(); await watchHelper!.getActivity(); await watchHelper!.getBodyTemperature(); + await watchHelper!.getDistance(); await watchHelper!.getBloodOxygen(); Result data = await watchHelper!.retrieveData(); - if(data.isError) { print('Unable to get the data'); } - - var response = jsonDecode(data.asValue?.value?.toString()?.trim().replaceAll("\n", "")??""); VitalsWRTType vitals = VitalsWRTType.fromMap(response); log("the data is ${vitals}"); + return vitals; }catch(e){ print('Error getting heart rate: $e'); } - + return null; } } diff --git a/lib/features/smartwatch_health_data/model/Vitals.dart b/lib/features/smartwatch_health_data/model/Vitals.dart index bbcf1035..cea1df4f 100644 --- a/lib/features/smartwatch_health_data/model/Vitals.dart +++ b/lib/features/smartwatch_health_data/model/Vitals.dart @@ -1,16 +1,19 @@ class Vitals { - final String value; + String value; final String timestamp; + final String unitOfMeasure; Vitals({ required this.value, required this.timestamp, + this.unitOfMeasure = "", }); factory Vitals.fromMap(Map map) { return Vitals( value: map['value'] ?? "", - timestamp: map['timestamp'] ?? "", + timestamp: map['timeStamp'] ?? "", + unitOfMeasure: map['uom'] ?? "", ); } } @@ -19,11 +22,19 @@ class VitalsWRTType { final List heartRate; final List sleep; final List step; + final List distance; final List activity; final List bodyOxygen; final List bodyTemperature; + double maxHeartRate = double.negativeInfinity; + double maxSleep = double.negativeInfinity; + double maxStep= double.negativeInfinity; + double maxActivity = double.negativeInfinity; + double maxBloodOxygen = double.negativeInfinity; + double maxBodyTemperature = double.negativeInfinity; - VitalsWRTType({required this.bodyOxygen, required this.bodyTemperature, required this.heartRate, required this.sleep, required this.step, required this.activity}); + + VitalsWRTType({required this.distance, required this.bodyOxygen, required this.bodyTemperature, required this.heartRate, required this.sleep, required this.step, required this.activity}); factory VitalsWRTType.fromMap(Map map) { List activity = []; @@ -31,26 +42,63 @@ class VitalsWRTType { List sleeps = []; List heartRate = []; List bodyOxygen = []; + List distance = []; List bodyTemperature = []; map["activity"].forEach((element) { - activity.add(Vitals.fromMap(element)); + element["uom"] = "Kcal"; + var data = Vitals.fromMap(element); + // data.value = (double.parse(data.value)/1000).toStringAsFixed(2); + activity.add(data); }); map["steps"].forEach((element) { + element["uom"] = ""; + steps.add(Vitals.fromMap(element)); }); map["sleep"].forEach((element) { + element["uom"] = "hr"; sleeps.add(Vitals.fromMap(element)); }); map["heartRate"].forEach((element) { + element["uom"] = "bpm"; + heartRate.add(Vitals.fromMap(element)); }); map["bloodOxygen"].forEach((element) { + element["uom"] = ""; + + bodyOxygen.add(Vitals.fromMap(element)); + }); + + map["distance"].forEach((element) { + element["uom"] = "m"; + bodyOxygen.add(Vitals.fromMap(element)); }); map["bodyTemperature"].forEach((element) { + element["uom"] = "C"; bodyTemperature.add(Vitals.fromMap(element)); }); - return VitalsWRTType(bodyTemperature: bodyTemperature, bodyOxygen: bodyOxygen, heartRate: heartRate, sleep: sleeps, step: steps, activity: activity); + map["distance"].forEach((element) { + element["uom"] = "km"; + var data = Vitals.fromMap(element); + data.value = (double.parse(data.value)/1000).toStringAsFixed(2); + distance.add(data); + }); + + return VitalsWRTType(bodyTemperature: bodyTemperature, bodyOxygen: bodyOxygen, heartRate: heartRate, sleep: sleeps, step: steps, activity: activity, distance: distance); + } + + Map> getVitals() { + return { + "heartRate": heartRate , + "sleep": sleep, + "steps": step, + "activity": activity, + "bodyOxygen": bodyOxygen, + "bodyTemperature": bodyTemperature, + "distance": distance, + }; } } diff --git a/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart index 1e3ef6df..a36cda39 100644 --- a/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart +++ b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart @@ -1,4 +1,6 @@ +import 'dart:async'; + import 'package:async/async.dart'; import 'package:flutter/services.dart'; class SamsungPlatformChannel { @@ -77,4 +79,12 @@ class SamsungPlatformChannel { return Result.error(e); } } + + Future> getDistance() async { + try{ + return Result.value(await _channel.invokeMethod('distance')); + }catch(e){ + return Result.error(e); + } + } } \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart index 9bc6d84d..72f97b69 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart @@ -1,4 +1,5 @@ import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/huawei_watch_connecter.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/samsung_health.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart'; @@ -7,6 +8,8 @@ class CreateWatchHelper { switch(watchType){ case SmartWatchTypes.samsung: return SamsungHealth(); + case SmartWatchTypes.huawei: + return HuaweiHealthDataConnector(); default: return SamsungHealth(); } diff --git a/lib/features/smartwatch_health_data/watch_connectors/huawei_watch_connecter.dart b/lib/features/smartwatch_health_data/watch_connectors/huawei_watch_connecter.dart new file mode 100644 index 00000000..a8300e2d --- /dev/null +++ b/lib/features/smartwatch_health_data/watch_connectors/huawei_watch_connecter.dart @@ -0,0 +1,86 @@ +import 'dart:async'; + +import 'package:async/src/result/result.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart'; +import 'package:huawei_health/huawei_health.dart'; + +class HuaweiHealthDataConnector extends WatchHelper{ + final MethodChannel _channel = MethodChannel('huawei_watch'); + @override + Future> initDevice() async{ + try{ + await _channel.invokeMethod('init'); + + }catch(e){ + + } + // List of scopes to ask for authorization. + // Note: These scopes should also be authorized on the Huawei Developer Console. + List scopes = [ + Scope.HEALTHKIT_STEP_READ, Scope.HEALTHKIT_OXYGEN_SATURATION_READ, // View and store height and weight data in Health Service Kit. + Scope.HEALTHKIT_HEARTRATE_READ, Scope.HEALTHKIT_SLEEP_READ, + Scope.HEALTHKIT_BODYTEMPERATURE_READ, Scope.HEALTHKIT_CALORIES_READ + ]; + try { + bool? result = await SettingController.getHealthAppAuthorization(); + debugPrint( + 'Granted Scopes for result == is $result}', + ); + return Result.value(true); + } catch (e) { + debugPrint('Error on authorization, Error:${e.toString()}'); + return Result.error(false); + } + } + + @override + Future getActivity() async { + DataType dataTypeResult = await SettingController.readDataType( + DataType.DT_CONTINUOUS_STEPS_DELTA.name + ); + + + } + + @override + Future getBloodOxygen() { + throw UnimplementedError(); + + } + + @override + Future getBodyTemperature() { + + throw UnimplementedError(); + } + + @override + FutureOr getHeartRate() { + throw UnimplementedError(); + } + + @override + FutureOr getSleep() { + throw UnimplementedError(); + } + + @override + FutureOr getSteps() { + throw UnimplementedError(); + } + + + @override + Future retrieveData() { + throw UnimplementedError(); + } + + @override + FutureOr getDistance() { + // TODO: implement getDistance + throw UnimplementedError(); + } + +} \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart index c2e8fd3e..d3cbcfc9 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart @@ -84,6 +84,15 @@ class SamsungHealth extends WatchHelper { } } + @override + FutureOr getDistance() async{ + try { + return await platformChannel.getDistance(); + }catch(e){ + print('Error getting heart rate: $e'); + } + } + } \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart index fe62fdc0..a09064d8 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart @@ -5,6 +5,7 @@ abstract class WatchHelper { FutureOr getHeartRate(); FutureOr getSleep(); FutureOr getSteps(); + FutureOr getDistance(); Future getActivity(); Future retrieveData(); Future getBodyTemperature(); diff --git a/lib/presentation/hmg_services/services_page.dart b/lib/presentation/hmg_services/services_page.dart index 9aaf1591..00c78721 100644 --- a/lib/presentation/hmg_services/services_page.dart +++ b/lib/presentation/hmg_services/services_page.dart @@ -303,11 +303,11 @@ class ServicesPage extends StatelessWidget { true, route: null, onTap: () async { - if (getIt.get().isAuthenticated) { + // if (getIt.get().isAuthenticated) { getIt.get().pushPageRoute(AppRoutes.smartWatches); - } else { - await getIt.get().onLoginPressed(); - } + // } else { + // await getIt.get().onLoginPressed(); + // } }, // route: AppRoutes.huaweiHealthExample, ), diff --git a/lib/presentation/smartwatches/activity_detail.dart b/lib/presentation/smartwatches/activity_detail.dart index cc006a61..21d168ad 100644 --- a/lib/presentation/smartwatches/activity_detail.dart +++ b/lib/presentation/smartwatches/activity_detail.dart @@ -6,17 +6,25 @@ import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/common_models/data_points.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/smartwatch_health_data/health_provider.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/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/graph/CustomBarGraph.dart'; import 'package:intl/intl.dart' show DateFormat; +import 'package:provider/provider.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/HealthDataTransformation.dart' as durations; +import 'package:dartz/dartz.dart' show Tuple2; + +import '../../core/utils/date_util.dart'; class ActivityDetails extends StatefulWidget { final String selectedActivity; + final String sectionName; + final String uom; - const ActivityDetails({super.key, required this.selectedActivity}); + const ActivityDetails({super.key, required this.selectedActivity, required this.sectionName, required this.uom}); @override State createState() => _ActivityDetailsState(); @@ -25,6 +33,11 @@ class ActivityDetails extends StatefulWidget { class _ActivityDetailsState extends State { int index = 0; + @override + void initState() { + super.initState(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -65,10 +78,24 @@ class _ActivityDetailsState extends State { ], shouldTabExpanded: true, onTabChange: (index) { - //todo handle the selection from viewmodel - setState(() { - this.index = index; - }); + switch (index) { + case 0: + context.read().setDurations(durations.Durations.daily); + break; + case 1: + context.read().setDurations(durations.Durations.weekly); + break; + case 2: + context.read().setDurations(durations.Durations.monthly); + break; + case 3: + context.read().setDurations(durations.Durations.halfYearly); + break; + case 4: + context.read().setDurations(durations.Durations.yearly); + break; + } + context.read().fetchData(); }, ), ), @@ -81,167 +108,235 @@ class _ActivityDetailsState extends State { decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h, hasShadow: true), child: Column( spacing: 8.h, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( - children: [widget.selectedActivity.toText32(weight: FontWeight.w600, color: AppColors.textColor), "Average".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)], + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + widget.sectionName.capitalizeFirstofEach.toText32(weight: FontWeight.w600, color: AppColors.textColor), + "Average".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor) + ], ), - Row( - children: ["3232".toText24(color: AppColors.textGreenColor, fontWeight: FontWeight.w600), "(20-21)".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500)], - ) + Selector>( + selector: (_, model) => Tuple2(model.averageValue, model.averageValueString), + builder: (_, data, __) { + var averageAsDouble = data.value1; + var averageAsString = data.value2; + return Row( + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + children: [ + (averageAsDouble?.toStringAsFixed(2) ?? averageAsString ?? "N/A").toText24(color: AppColors.textGreenColor, fontWeight: FontWeight.w600), + Visibility( + visible: averageAsDouble != null || averageAsString != null, + child: widget.uom.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500) + ) + ], + ); + }) ], ).paddingSymmetrical(16.w, 16.h)); } Widget activityGraph() { - final _random = Random(); - - int randomBP() => 100 + _random.nextInt(51); // 100–150 - final List data6Months = List.generate(6, (index) { - final date = DateTime.now().subtract(Duration(days: 30 * (5 - index))); - - final value = randomBP(); - - return DataPoint( - value: value.toDouble(), - label: value.toString(), - actualValue: value.toString(), - displayTime: DateFormat('MMM').format(date), - unitOfMeasurement: 'mmHg', - time: date, - ); - }); - final List data12Months = List.generate(12, (index) { - final date = DateTime.now().subtract(Duration(days: 30 * (11 - index))); - - final value = randomBP(); - - return DataPoint( - value: value.toDouble(), - label: value.toString(), - actualValue: value.toString(), - displayTime: DateFormat('MMM').format(date), - unitOfMeasurement: 'mmHg', - time: date, - ); - }); - - List data =[]; - if(index == 0){ - data = data6Months; - } else if(index == 1){ - data = data12Months; - } else - data = [ - DataPoint( - value: 128, - label: "128", - actualValue: '128', - displayTime: 'Sun', - unitOfMeasurement: 'mmHg', - time: DateTime.now().subtract(const Duration(days: 6)), - ), - DataPoint( - value: 135, - label: "135", - actualValue: '135', - displayTime: 'Mon', - unitOfMeasurement: 'mmHg', - time: DateTime.now().subtract(const Duration(days: 5)), - ), - DataPoint( - value: 122, - label: "122", - actualValue: '122', - displayTime: 'Tue', - unitOfMeasurement: 'mmHg', - time: DateTime.now().subtract(const Duration(days: 4)), - ), - DataPoint( - value: 140, - label: "140", - actualValue: '140', - displayTime: 'Wed', - unitOfMeasurement: 'mmHg', - time: DateTime.now().subtract(const Duration(days: 3)), - ), - DataPoint( - value: 118, - label: "118", - actualValue: '118', - displayTime: 'Thu', - unitOfMeasurement: 'mmHg', - time: DateTime.now().subtract(const Duration(days: 2)), - ), - DataPoint( - value: 125, - label: "125", - actualValue: '125', - displayTime: 'Fri', - unitOfMeasurement: 'mmHg', - time: DateTime.now().subtract(const Duration(days: 1)), - ), - DataPoint( - value: 130, - label: "130", - actualValue: '130', - displayTime: 'Sat', - unitOfMeasurement: 'mmHg', - time: DateTime.now(), - ), - ]; - - return CustomBarChart( - dataPoints: data, - height: 300.h, - maxY: 150, - barColor: AppColors.bgGreenColor, - barWidth: 26.w, - barRadius: BorderRadius.circular(8), - bottomLabelColor: Colors.black, - bottomLabelSize: 12, - leftLabelInterval: .1, - leftLabelReservedSize: 40, - // Left axis label formatter (Y-axis) - leftLabelFormatter: (value) { - var labelValue = double.tryParse(value.toStringAsFixed(0)); - - if (labelValue == null) return SizedBox.shrink(); - if (labelValue == 0 || labelValue == 150 / 2 || labelValue == 150) { - return Text( - labelValue.toStringAsFixed(0), - style: const TextStyle( - color: Colors.black26, - fontSize: 11, - ), - ); - } + // final _random = Random(); + // + // int randomBP() => 100 + _random.nextInt(51); // 100–150 + // final List data6Months = List.generate(6, (index) { + // final date = DateTime.now().subtract(Duration(days: 30 * (5 - index))); + // + // final value = randomBP(); + // + // return DataPoint( + // value: value.toDouble(), + // label: value.toString(), + // actualValue: value.toString(), + // displayTime: DateFormat('MMM').format(date), + // unitOfMeasurement: 'mmHg', + // time: date, + // ); + // }); + // final List data12Months = List.generate(12, (index) { + // final date = DateTime.now().subtract(Duration(days: 30 * (11 - index))); + // + // final value = randomBP(); + // + // return DataPoint( + // value: value.toDouble(), + // label: value.toString(), + // actualValue: value.toString(), + // displayTime: DateFormat('MMM').format(date), + // unitOfMeasurement: 'mmHg', + // time: date, + // ); + // }); + // + // List data =[]; + // if(index == 0){ + // data = data6Months; + // } else if(index == 1){ + // data = data12Months; + // } else + // data = [ + // DataPoint( + // value: 128, + // label: "128", + // actualValue: '128', + // displayTime: 'Sun', + // unitOfMeasurement: 'mmHg', + // time: DateTime.now().subtract(const Duration(days: 6)), + // ), + // DataPoint( + // value: 135, + // label: "135", + // actualValue: '135', + // displayTime: 'Mon', + // unitOfMeasurement: 'mmHg', + // time: DateTime.now().subtract(const Duration(days: 5)), + // ), + // DataPoint( + // value: 122, + // label: "122", + // actualValue: '122', + // displayTime: 'Tue', + // unitOfMeasurement: 'mmHg', + // time: DateTime.now().subtract(const Duration(days: 4)), + // ), + // DataPoint( + // value: 140, + // label: "140", + // actualValue: '140', + // displayTime: 'Wed', + // unitOfMeasurement: 'mmHg', + // time: DateTime.now().subtract(const Duration(days: 3)), + // ), + // DataPoint( + // value: 118, + // label: "118", + // actualValue: '118', + // displayTime: 'Thu', + // unitOfMeasurement: 'mmHg', + // time: DateTime.now().subtract(const Duration(days: 2)), + // ), + // DataPoint( + // value: 125, + // label: "125", + // actualValue: '125', + // displayTime: 'Fri', + // unitOfMeasurement: 'mmHg', + // time: DateTime.now().subtract(const Duration(days: 1)), + // ), + // DataPoint( + // value: 130, + // label: "130", + // actualValue: '130', + // displayTime: 'Sat', + // unitOfMeasurement: 'mmHg', + // time: DateTime.now(), + // ),23 + // ]; + return Selector>?>( + selector: (_, model) => model.selectedData, + builder: (_, data, __) { + if (context.read().selectedData.values.toList().first?.isEmpty == true) return SizedBox(); - return SizedBox.shrink(); - }, + return CustomBarChart( + dataPoints: context.read().selectedData.values.toList().first, + height: 300.h, + maxY: 150, + barColor: AppColors.bgGreenColor, + barWidth: context.read().selectedData.values.toList().first.length < 10 ? 26.w : 20.w, + barRadius: BorderRadius.circular(8), + bottomLabelColor: Colors.black, + bottomLabelSize: 12, + leftLabelInterval: .1, + leftLabelReservedSize: 20, + // Left axis label formatter (Y-axis) + leftLabelFormatter: (value) { + var labelValue = double.tryParse(value.toStringAsFixed(0)); + + if (labelValue == null) return SizedBox.shrink(); + // if (labelValue == 0 || labelValue == 150 / 2 || labelValue == 150) { + // return Text( + // labelValue.toStringAsFixed(0), + // style: const TextStyle( + // color: Colors.black26, + // fontSize: 11, + // ), + // ); + // } - // Bottom axis label formatter (X-axis - Days) + return SizedBox.shrink(); + }, + + /// for the handling of the sleep time + getTooltipItem: (widget.selectedActivity == "sleep") + ? (data) { + return BarTooltipItem( + '${DateUtil. millisToHourMin(num.parse(data.actualValue).toInt())}\n${DateFormat('dd MMM, yyyy').format(data.time)}', + TextStyle( + color: Colors.black, + fontSize: 12.f, + fontWeight: FontWeight.w500, + ), + ); + } + : null, + + // Bottom axis label formatter (X-axis - Days) bottomLabelFormatter: (value, dataPoints) { final index = value.toInt(); - if (index >= 0 && index < dataPoints.length) { - return Text( - dataPoints[index].displayTime, - style: const TextStyle( - color: Colors.grey, - fontSize: 11, - ), - ); - } - return const Text(''); - }, - verticalInterval: 1/data.length, - getDrawingVerticalLine: (value) { - return FlLine( - color: AppColors.greyColor, - strokeWidth: 1, + print("value is $value"); + print("the index is $index"); + print("the dataPoints.length is ${dataPoints.length}"); + + var bottomText = ""; + var date = dataPoints[index].time; + print("the time is ${date}"); + switch (context.read().selectedDuration) { + case durations.Durations.daily: + bottomText = getHour(date).toString(); + break; + case durations.Durations.weekly: + bottomText = getDayName(date)[0]; + break; + case durations.Durations.monthly: + case durations.Durations.halfYearly: + case durations.Durations.yearly: + bottomText = getMonthName(date)[0]; + } + + return Text( + bottomText, + style: const TextStyle( + color: Colors.grey, + fontSize: 11, + ), + ); + return const Text(''); + }, + verticalInterval: 1 / context.read().selectedData.values.toList().first.length, + getDrawingVerticalLine: (value) { + return FlLine( + color: AppColors.greyColor, + strokeWidth: 1, ); }, - showGridLines: true, - ); + showGridLines: true); + }); + } + + //todo remove these from here + String getDayName(DateTime date) { + return DateUtil.getWeekDayAsOfLang(date.weekday); + } + + String getHour(DateTime date) { + return date.hour.toString().padLeft(2, '0').toString(); + } + + static String getMonthName(DateTime date) { + return DateUtil.getMonthDayAsOfLang(date.month); } } diff --git a/lib/presentation/smartwatches/smart_watch_activity.dart b/lib/presentation/smartwatches/smart_watch_activity.dart index 531139b8..cffb802d 100644 --- a/lib/presentation/smartwatches/smart_watch_activity.dart +++ b/lib/presentation/smartwatches/smart_watch_activity.dart @@ -5,10 +5,15 @@ import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart'; import 'package:hmg_patient_app_new/presentation/smartwatches/activity_detail.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:provider/provider.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/HealthDataTransformation.dart' as durations; + +import '../../core/utils/date_util.dart' show DateUtil; class SmartWatchActivity extends StatelessWidget { @override @@ -22,64 +27,164 @@ class SmartWatchActivity extends StatelessWidget { children: [ resultItem( leadingIcon: AppAssets.watchActivity, - title: "Activity".needTranslation, + title: "Activity Calories".needTranslation, description: "Activity rings give you a quick visual reference of how active you are each day. ".needTranslation, trailingIcon: AppAssets.watchActivityTrailing, - result: "21", + result: context.read().sumOfNonEmptyData(context.read().vitals?.activity??[]), unitsOfMeasure: "Cal" ).onPress((){ - getIt.get().pushPage(page: ActivityDetails( selectedActivity: "Steps")); + // Map> getVitals() { + // return { + // "heartRate": heartRate , + // "sleep": sleep, + // "steps": step, + // "activity": activity, + // "bodyOxygen": bodyOxygen, + // "bodyTemperature": bodyTemperature, + // }; + // } + context.read().setDurations(durations.Durations.daily); + + context.read().deleteDataIfSectionIsDifferent("activity"); + context.read().saveSelectedSection("activity"); + context.read().fetchData(); + context.read().navigateToDetails("activity", sectionName:"Activity Calories", uom: "cal"); + }), resultItem( leadingIcon: AppAssets.watchSteps, title: "Steps".needTranslation, description: "Step count is the number of steps you take throughout the day.".needTranslation, trailingIcon: AppAssets.watchStepsTrailing, - result: "21", + result: context.read().sumOfNonEmptyData(context.read().vitals?.step??[]), unitsOfMeasure: "Steps" - ), + ).onPress((){ + // Map> getVitals() { + // return { + // "heartRate": heartRate , + // "sleep": sleep, + // "steps": step, + // "activity": activity, + // "bodyOxygen": bodyOxygen, + // "bodyTemperature": bodyTemperature, + // }; + // } + context.read().setDurations(durations.Durations.daily); + + context.read().deleteDataIfSectionIsDifferent("steps"); + context.read().saveSelectedSection("steps"); + context.read().fetchData(); + context.read().navigateToDetails("steps", sectionName: "Steps", uom: "Steps"); + + }), resultItem( leadingIcon: AppAssets.watchSteps, - title: "Walking + Running Distance".needTranslation, - description: "This will show you the total distance you covered in a day".needTranslation, + title: "Distance Covered".needTranslation, + description: "Step count is the distance you take throughout the day.".needTranslation, trailingIcon: AppAssets.watchStepsTrailing, - result: "21", - unitsOfMeasure: "km" - ), + result: context.read().sumOfNonEmptyData(context.read().vitals?.distance??[]), + unitsOfMeasure: "Km" + ).onPress((){ + // Map> getVitals() { + // return { + // "heartRate": heartRate , + // "sleep": sleep, + // "steps": step, + // "activity": activity, + // "bodyOxygen": bodyOxygen, + // "bodyTemperature": bodyTemperature, + // }; + // } + context.read().setDurations(durations.Durations.daily); + + context.read().deleteDataIfSectionIsDifferent("distance"); + context.read().saveSelectedSection("distance"); + context.read().fetchData(); + context.read().navigateToDetails("distance", sectionName: "Distance Covered", uom: "km"); + + }), + resultItem( leadingIcon: AppAssets.watchSleep, title: "Sleep Score".needTranslation, description: "This will keep track of how much hours you sleep in a day".needTranslation, trailingIcon: AppAssets.watchSleepTrailing, - result: "21", + result: DateUtil.millisToHourMin(int.parse(context.read().firstNonEmptyValue(context.read().vitals?.sleep??[]))).split(" ")[0], unitsOfMeasure: "hr", - resultSecondValue: "2", + resultSecondValue: DateUtil.millisToHourMin(int.parse(context.read().firstNonEmptyValue(context.read().vitals?.sleep??[]))).split(" ")[2], unitOfSecondMeasure: "min" - ), - resultItem( - leadingIcon: AppAssets.watchBmi, - title: "Body Mass Index".needTranslation, - description: "This will calculate your weight and height ratio to analyze the ".needTranslation, - trailingIcon: AppAssets.watchBmiTrailing, - result: "21", - unitsOfMeasure: "BMI" - ), + ).onPress((){ + // Map> getVitals() { + // return { + // "heartRate": heartRate , + // "sleep": sleep, + // "steps": step, + // "activity": activity, + // "bodyOxygen": bodyOxygen, + // "bodyTemperature": bodyTemperature, + // }; + // } + context.read().setDurations(durations.Durations.daily); + + context.read().deleteDataIfSectionIsDifferent("sleep"); + context.read().saveSelectedSection("sleep"); + context.read().fetchData(); + context.read().navigateToDetails("sleep", sectionName:"Sleep Score",uom:""); + + }), + resultItem( leadingIcon: AppAssets.watchWeight, - title: "Weight".needTranslation, - description: "This will calculate your weight to keep track and update history".needTranslation, + title: "Blood Oxygen".needTranslation, + description: "This will calculate your Blood Oxygen to keep track and update history".needTranslation, trailingIcon: AppAssets.watchWeightTrailing, - result: "21", - unitsOfMeasure: "Kg" - ), + result: context.read().firstNonEmptyValue(context.read().vitals?.bodyOxygen??[], ), + unitsOfMeasure: "%" + ).onPress((){ + // Map> getVitals() { + // return { + // "heartRate": heartRate , + // "sleep": sleep, + // "steps": step, + // "activity": activity, + // "bodyOxygen": bodyOxygen, + // "bodyTemperature": bodyTemperature, + // }; + // } + context.read().setDurations(durations.Durations.daily); + + context.read().deleteDataIfSectionIsDifferent("bodyOxygen"); + context.read().saveSelectedSection("bodyOxygen"); + context.read().fetchData(); + context.read().navigateToDetails("bodyOxygen", uom: "%", sectionName:"Blood Oxygen" ); + + }), resultItem( leadingIcon: AppAssets.watchWeight, - title: "Height".needTranslation, - description: "This will calculate your height to keep track and update history".needTranslation, + title: "Body temperature".needTranslation, + description: "This will calculate your Body temprerature to keep track and update history".needTranslation, trailingIcon: AppAssets.watchWeightTrailing, - result: "21", - unitsOfMeasure: "ft" - ) + result: context.read().firstNonEmptyValue(context.read().vitals?.bodyTemperature??[]), + unitsOfMeasure: "C" + ).onPress((){ + // Map> getVitals() { + // return { + // "heartRate": heartRate , + // "sleep": sleep, + // "steps": step, + // "activity": activity, + // "bodyOxygen": bodyOxygen, + // "bodyTemperature": bodyTemperature, + // }; + // } + context.read().setDurations(durations.Durations.daily); + + context.read().deleteDataIfSectionIsDifferent("bodyTemperature"); + context.read().saveSelectedSection("bodyTemperature"); + context.read().fetchData(); + context.read().navigateToDetails("bodyTemperature" , sectionName: "Body temperature".capitalizeFirstofEach, uom: "C"); + + }), ], ).paddingSymmetrical(24.w, 24.h), )); diff --git a/lib/widgets/graph/CustomBarGraph.dart b/lib/widgets/graph/CustomBarGraph.dart index b90ddb00..bacdf0c7 100644 --- a/lib/widgets/graph/CustomBarGraph.dart +++ b/lib/widgets/graph/CustomBarGraph.dart @@ -63,6 +63,7 @@ class CustomBarChart extends StatelessWidget { final double? minY; final BorderRadius? barRadius; final double barWidth; + final BarTooltipItem Function(DataPoint)? getTooltipItem; /// Creates the left label and provides it to the chart final Widget Function(double) leftLabelFormatter; @@ -100,7 +101,9 @@ class CustomBarChart extends StatelessWidget { this.verticalInterval, this.minY, this.barRadius, - this.barWidth = 16}); + this.barWidth = 16, + this.getTooltipItem + }); @override Widget build(BuildContext context) { @@ -124,6 +127,10 @@ class CustomBarChart extends StatelessWidget { getTooltipColor: (_)=>AppColors.tooltipColor, getTooltipItem: (group, groupIndex, rod, rodIndex) { final dataPoint = dataPoints[groupIndex]; + if(getTooltipItem != null) { + return getTooltipItem!(dataPoint); + } + return BarTooltipItem( '${dataPoint.actualValue} ${dataPoint.unitOfMeasurement ?? ""}\n${DateFormat('dd MMM, yyyy').format(dataPoint.time)}', TextStyle( diff --git a/pubspec.yaml b/pubspec.yaml index 19acdf31..17860c67 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -88,7 +88,7 @@ dependencies: location: ^8.0.1 gms_check: ^1.0.4 huawei_location: ^6.14.2+301 - huawei_health: ^6.16.0+300 + huawei_health: ^6.15.0+300 intl: ^0.20.2 flutter_widget_from_html: ^0.17.1 huawei_map: From a395d9b93aeb30750df9f1a3db292b283bcdf46a Mon Sep 17 00:00:00 2001 From: tahaalam Date: Wed, 18 Feb 2026 11:59:32 +0300 Subject: [PATCH 07/33] ios health connect added --- .../health_provider.dart | 2 - .../watch_connectors/create_watch_helper.dart | 5 + .../health_connect_helper.dart | 164 ++++++++++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 lib/features/smartwatch_health_data/watch_connectors/health_connect_helper.dart diff --git a/lib/features/smartwatch_health_data/health_provider.dart b/lib/features/smartwatch_health_data/health_provider.dart index 905c8d5a..80a79bb3 100644 --- a/lib/features/smartwatch_health_data/health_provider.dart +++ b/lib/features/smartwatch_health_data/health_provider.dart @@ -66,9 +66,7 @@ class HealthProvider with ChangeNotifier { final startTime = _getStartDate(); final endTime = DateTime.now(); - healthData = await _healthService.getAllHealthData(startTime, endTime); - isLoading = false; notifyListeners(); } catch (e) { diff --git a/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart index 72f97b69..8abb2136 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/create_watch_helper.dart @@ -1,10 +1,15 @@ +import 'dart:io'; + import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/health_connect_helper.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/huawei_watch_connecter.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/samsung_health.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart'; class CreateWatchHelper { static WatchHelper getWatchName(SmartWatchTypes watchType) { + /// if running device is ios + if(Platform.isIOS) return HealthConnectHelper(); switch(watchType){ case SmartWatchTypes.samsung: return SamsungHealth(); diff --git a/lib/features/smartwatch_health_data/watch_connectors/health_connect_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/health_connect_helper.dart new file mode 100644 index 00000000..e7ec35b7 --- /dev/null +++ b/lib/features/smartwatch_health_data/watch_connectors/health_connect_helper.dart @@ -0,0 +1,164 @@ +import 'dart:async'; +import 'dart:io'; +import 'package:async/src/result/result.dart'; +import 'package:health/health.dart'; +import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart' show WatchHelper; +import 'package:permission_handler/permission_handler.dart'; + +import '../model/Vitals.dart'; + +class HealthConnectHelper extends WatchHelper { + final Health health = Health(); + + final List _healthPermissions = [ + HealthDataType.HEART_RATE, + HealthDataType.STEPS, + HealthDataType.BLOOD_OXYGEN, + HealthDataType.BODY_TEMPERATURE, + HealthDataType.DISTANCE_WALKING_RUNNING, + HealthDataType.TOTAL_CALORIES_BURNED + ]; + + Map> mappedData = {}; + + @override + FutureOr getHeartRate() async { + try { + final types = [HealthDataType.HEART_RATE]; + final endDate = DateTime.now(); + final startDate = endDate.subtract(Duration(days: 365)); + final data = await getData(startDate, endDate, types); + addDataToMap("heartRate",data ); + } catch (e) { + print('Error getting heart rate: $e'); + } + } + + @override + FutureOr getSleep() async { + try { + final types = [HealthDataType.SLEEP_IN_BED]; + final endDate = DateTime.now(); + final startDate = endDate.subtract(Duration(days: 365)); + final data = await getData(startDate, endDate, types); + addDataToMap("sleep",data ); + } catch (e) { + print('Error getting sleep data: $e'); + } + } + + @override + FutureOr getSteps() async { + try { + final types = [HealthDataType.STEPS]; + final endDate = DateTime.now(); + final startDate = endDate.subtract(Duration(days: 365)); + final data = await getData(startDate, endDate, types); + addDataToMap("steps",data ); + print('Steps Data: $data'); + } catch (e) { + print('Error getting steps: $e'); + } + } + + @override + Future getActivity() async { + try { + final types = [HealthDataType.ACTIVE_ENERGY_BURNED]; + final endDate = DateTime.now(); + final startDate = endDate.subtract(Duration(days: 365)); + final data = await getData(startDate, endDate, types); + addDataToMap("activity",data ); + print('Activity Data: $data'); + } catch (e) { + print('Error getting activity: $e'); + } + } + + @override + Future retrieveData() async { + return mappedData; + } + + @override + Future getBloodOxygen() async { + try { + final types = [HealthDataType.BLOOD_OXYGEN]; + final endDate = DateTime.now(); + final startDate = endDate.subtract(Duration(days: 365)); + final data = await getData(startDate, endDate, types); + addDataToMap("bloodOxygen",data ); + } catch (e) { + print('Error getting blood oxygen: $e'); + } + } + + @override + Future getBodyTemperature() async { + try { + final types = [HealthDataType.BODY_TEMPERATURE]; + final endDate = DateTime.now(); + final startDate = endDate.subtract(Duration(days: 365)); + final data = await getData(startDate, endDate, types); + addDataToMap("bodyTemperature",data ); + } catch (e) { + print('Error getting body temp erature: $e'); + } + } + + @override + FutureOr getDistance() async { + try { + final types = [HealthDataType.DISTANCE_WALKING_RUNNING]; + final endDate = DateTime.now(); + final startDate = endDate.subtract(Duration(days: 365)); + final data = await getData(startDate, endDate, types); + addDataToMap("distance",data ); + } catch (e) { + print('Error getting distance: $e'); + } + } + + @override + Future> initDevice() async { + try { + final types = _healthPermissions; + final granted = await health.requestAuthorization(types); + await Permission.activityRecognition.request(); + await Permission.location.request(); + // request access to read historic data + await Health().requestHealthDataHistoryAuthorization(); + // await authorize(); + return Result.value(granted); + } catch (e) { + print('Authorization error: $e'); + return Result.error(false); + } + } + + getData(startTime, endTime,type) async { + return await health.getHealthIntervalDataFromTypes( + startDate: startTime, + endDate: endTime, + types: [type], + interval: 86400, + ); + } + + void addDataToMap(String s, data) { + mappedData[s] = []; + for (var point in data) { + if (point.value is NumericHealthValue) { + final numericValue = (point.value as NumericHealthValue).numericValue; + point.value = NumericHealthValue( + numericValue: numericValue * 100, + ); + Vitals vitals = Vitals( + value: (point.value as NumericHealthValue).numericValue.toStringAsFixed(2), + timestamp: point.dateFrom.toString() + ); + mappedData[s]?.add(vitals); + } + } + } +} From b334f631bd8b070b82013f9f24e0b1b7822b51cb Mon Sep 17 00:00:00 2001 From: tahaalam Date: Wed, 18 Feb 2026 12:02:55 +0300 Subject: [PATCH 08/33] samsung sdk health aar --- android/app/libs/samsung-health-data-api.aar | Bin 0 -> 533729 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 android/app/libs/samsung-health-data-api.aar diff --git a/android/app/libs/samsung-health-data-api.aar b/android/app/libs/samsung-health-data-api.aar new file mode 100644 index 0000000000000000000000000000000000000000..1fd240340efde4c8f36d576c8accc374acc5dec8 GIT binary patch literal 533729 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 EVaBNW*wP5thJ~`;9sgE*0QS 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
KOk*$Xs~;?QF3;nmr2HgWgvCExSXN6}5vV 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

hVTG(PFD$AoRQMQTed&)juau{ElPZzRVecjPsy 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 literal 0 HcmV?d00001 From 7100283a9d179624cd89ac85ab90a160017e28de Mon Sep 17 00:00:00 2001 From: tahaalam Date: Wed, 18 Feb 2026 13:00:34 +0300 Subject: [PATCH 09/33] package change activity --- android/app/src/main/AndroidManifest.xml | 3 - .../HMGPatientApp/Application.kt | 27 + .../HMGPatientApp/MainActivity.kt | 78 + .../HMGPatientApp/PenguinInPlatformBridge.kt | 60 + .../PermissionManager/AppPreferences.java | 139 ++ .../HostBgLocationManager.java | 136 ++ .../HostGpsStateManager.java | 68 + .../HostNotificationPermissionManager.java | 73 + .../PermissionManager/PermissionHelper.kt | 27 + .../PermissionManager/PermissionManager.kt | 50 + .../PermissionResultReceiver.kt | 15 + .../HMGPatientApp/penguin/PenguinMethod.kt | 13 + .../HMGPatientApp/penguin/PenguinNavigator.kt | 97 + .../HMGPatientApp/penguin/PenguinView.kt | 376 +++ .../watch/samsung_watch/SamsungWatch.kt | 402 ++++ .../watch/samsung_watch/model/Vitals.kt | 13 + .../main/kotlin/com/ejada/hmg/MainActivity.kt | 0 .../res/mipmap-hdpi/ic_launcher_local.png | Bin 2350 -> 4895 bytes .../res/mipmap-mdpi/ic_launcher_local.png | Bin 1742 -> 3233 bytes .../res/mipmap-xhdpi/ic_launcher_local.png | Bin 3028 -> 6692 bytes .../res/mipmap-xxhdpi/ic_launcher_local.png | Bin 4339 -> 10212 bytes .../res/mipmap-xxxhdpi/ic_launcher_local.png | Bin 5703 -> 13821 bytes android/app/src/main2/AndroidManifest.xml | 274 +++ .../kotlin/com/ejada/hmg/MainActivity.kt | 84 + .../hmg/watch/samsung_watch/SamsungWatch.kt | 0 .../hmg/watch/samsung_watch/model/Vitals.kt | 0 .../res/drawable-v21/launch_background.xml | 12 + .../app/src/main2/res/drawable/app_icon.png | Bin 0 -> 2555 bytes android/app/src/main2/res/drawable/food.png | Bin 0 -> 1789 bytes .../main2/res/drawable/launch_background.xml | 12 + android/app/src/main2/res/drawable/me.png | Bin 0 -> 1021 bytes .../main2/res/drawable/sample_large_icon.png | Bin 0 -> 180 bytes .../src/main2/res/drawable/secondary_icon.png | Bin 0 -> 1073 bytes .../res/layout/activity_whats_app_code.xml | 10 + .../app/src/main2/res/layout/local_video.xml | 14 + .../app/src/main2/res/layout/remote_video.xml | 20 + .../res/mipmap-hdpi/ic_launcher.png | Bin .../res/mipmap-hdpi/ic_launcher_local.png | Bin 0 -> 2350 bytes .../res/mipmap-mdpi/ic_launcher.png | Bin .../res/mipmap-mdpi/ic_launcher_local.png | Bin 0 -> 1742 bytes .../res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xhdpi/ic_launcher_local.png | Bin 0 -> 3028 bytes .../res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher_local.png | Bin 0 -> 4339 bytes .../res/mipmap-xxxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher_local.png | Bin 0 -> 5703 bytes android/app/src/main2/res/raw/keep.xml | 3 + .../src/main2/res/raw/slow_spring_board.mp3 | Bin 0 -> 37616 bytes .../app/src/main2/res/values-night/styles.xml | 18 + .../main2/res/values/mapbox_access_token.xml | 3 + android/app/src/main2/res/values/strings.xml | 23 + android/app/src/main2/res/values/styles.xml | 18 + ios/Podfile.lock | 543 +++++ pubspec.lock | 2097 +++++++++++++++++ 54 files changed, 4705 insertions(+), 3 deletions(-) create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/Application.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/MainActivity.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PenguinInPlatformBridge.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/AppPreferences.java create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostBgLocationManager.java create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostGpsStateManager.java create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostNotificationPermissionManager.java create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionHelper.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionManager.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionResultReceiver.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinMethod.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinNavigator.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinView.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/watch/samsung_watch/SamsungWatch.kt create mode 100644 android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/watch/samsung_watch/model/Vitals.kt delete mode 100644 android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt create mode 100644 android/app/src/main2/AndroidManifest.xml create mode 100644 android/app/src/main2/kotlin/com/ejada/hmg/MainActivity.kt rename android/app/src/{main => main2}/kotlin/com/ejada/hmg/watch/samsung_watch/SamsungWatch.kt (100%) rename android/app/src/{main => main2}/kotlin/com/ejada/hmg/watch/samsung_watch/model/Vitals.kt (100%) create mode 100644 android/app/src/main2/res/drawable-v21/launch_background.xml create mode 100755 android/app/src/main2/res/drawable/app_icon.png create mode 100644 android/app/src/main2/res/drawable/food.png create mode 100644 android/app/src/main2/res/drawable/launch_background.xml create mode 100644 android/app/src/main2/res/drawable/me.png create mode 100644 android/app/src/main2/res/drawable/sample_large_icon.png create mode 100644 android/app/src/main2/res/drawable/secondary_icon.png create mode 100644 android/app/src/main2/res/layout/activity_whats_app_code.xml create mode 100644 android/app/src/main2/res/layout/local_video.xml create mode 100644 android/app/src/main2/res/layout/remote_video.xml rename android/app/src/{main => main2}/res/mipmap-hdpi/ic_launcher.png (100%) create mode 100644 android/app/src/main2/res/mipmap-hdpi/ic_launcher_local.png rename android/app/src/{main => main2}/res/mipmap-mdpi/ic_launcher.png (100%) create mode 100644 android/app/src/main2/res/mipmap-mdpi/ic_launcher_local.png rename android/app/src/{main => main2}/res/mipmap-xhdpi/ic_launcher.png (100%) create mode 100644 android/app/src/main2/res/mipmap-xhdpi/ic_launcher_local.png rename android/app/src/{main => main2}/res/mipmap-xxhdpi/ic_launcher.png (100%) create mode 100644 android/app/src/main2/res/mipmap-xxhdpi/ic_launcher_local.png rename android/app/src/{main => main2}/res/mipmap-xxxhdpi/ic_launcher.png (100%) create mode 100644 android/app/src/main2/res/mipmap-xxxhdpi/ic_launcher_local.png create mode 100644 android/app/src/main2/res/raw/keep.xml create mode 100644 android/app/src/main2/res/raw/slow_spring_board.mp3 create mode 100644 android/app/src/main2/res/values-night/styles.xml create mode 100644 android/app/src/main2/res/values/mapbox_access_token.xml create mode 100644 android/app/src/main2/res/values/strings.xml create mode 100644 android/app/src/main2/res/values/styles.xml create mode 100644 ios/Podfile.lock create mode 100644 pubspec.lock diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e07739b9..54e1a5ee 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -134,9 +134,6 @@ android:showOnLockScreen="true" android:usesCleartextTraffic="true" tools:replace="android:label"> - diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/Application.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/Application.kt new file mode 100644 index 00000000..2520d186 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/Application.kt @@ -0,0 +1,27 @@ +//package com.cloud.diplomaticquarterapp +package com.cloudsolutions.HMGPatientApp + + +import io.flutter.app.FlutterApplication + +class Application : FlutterApplication() { + override fun onCreate() { + super.onCreate() + } +} + +//import io.flutter.app.FlutterApplication +//import io.flutter.plugin.common.PluginRegistry +//import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback +//import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService +// +//class Application : FlutterApplication(), PluginRegistrantCallback { +// override fun onCreate() { +// super.onCreate() +// FlutterFirebaseMessagingService.setPluginRegistrant(this) +// } +// +// override fun registerWith(registry: PluginRegistry?) { +// FirebaseCloudMessagingPluginRegistrant.registerWith(registry) +// } +//} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/MainActivity.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/MainActivity.kt new file mode 100644 index 00000000..fdb4d7ad --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/MainActivity.kt @@ -0,0 +1,78 @@ +package com.cloudsolutions.HMGPatientApp + +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.util.Log +import android.view.WindowManager +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi +import com.cloudsolutions.HMGPatientApp.watch.samsung_watch.SamsungWatch +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugins.GeneratedPluginRegistrant + +import io.flutter.embedding.android.FlutterFragmentActivity + + +class MainActivity: FlutterFragmentActivity() { + + @RequiresApi(Build.VERSION_CODES.O) + override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + GeneratedPluginRegistrant.registerWith(flutterEngine); + // Create Flutter Platform Bridge + this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) + + PenguinInPlatformBridge(flutterEngine, this).create() + SamsungWatch(flutterEngine, this) + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + + val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } + val intent = Intent("PERMISSION_RESULT_ACTION").apply { + putExtra("PERMISSION_GRANTED", granted) + } + sendBroadcast(intent) + + // Log the request code and permission results + Log.d("PermissionsResult", "Request Code: $requestCode") + Log.d("PermissionsResult", "Permissions: ${permissions.joinToString()}") + Log.d("PermissionsResult", "Grant Results: ${grantResults.joinToString()}") + + } + + override fun onResume() { + super.onResume() + } + +// override fun onActivityResult(requestCode: Int, resultCode: Int, @Nullable data: Intent?) { +// super.onActivityResult(requestCode, resultCode, data) +// +// // Process only the response result of the authorization process. +// if (requestCode == 1002) { +// // Obtain the authorization response result from the intent. +// val result: HealthKitAuthResult? = huaweiWatch?.mSettingController?.parseHealthKitAuthResultFromIntent(data) +// if (result == null) { +// Log.w(huaweiWatch?.TAG, "authorization fail") +// return +// } +// +// if (result.isSuccess) { +// Log.i(huaweiWatch?.TAG, "authorization success") +// if (result.getAuthAccount() != null && result.authAccount.authorizedScopes != null) { +// val authorizedScopes: MutableSet = result.authAccount.authorizedScopes +// if(authorizedScopes.isNotEmpty()) { +// huaweiWatch?.getHealthAppAuthorization() +// } +// } +// } else { +// Log.w("MainActivty", "authorization fail, errorCode:" + result.getErrorCode()) +// } +// } +// } +} diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PenguinInPlatformBridge.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PenguinInPlatformBridge.kt new file mode 100644 index 00000000..5fae68ca --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PenguinInPlatformBridge.kt @@ -0,0 +1,60 @@ +package com.cloudsolutions.HMGPatientApp + +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import com.cloudsolutions.HMGPatientApp.penguin.PenguinView +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodCall +import com.cloudsolutions.HMGPatientApp.PermissionManager.HostNotificationPermissionManager +import com.cloudsolutions.HMGPatientApp.PermissionManager.HostBgLocationManager +import com.cloudsolutions.HMGPatientApp.PermissionManager.HostGpsStateManager +import io.flutter.plugin.common.MethodChannel + +class PenguinInPlatformBridge( + private var flutterEngine: FlutterEngine, + private var mainActivity: MainActivity +) { + + private lateinit var channel: MethodChannel + + companion object { + private const val CHANNEL = "launch_penguin_ui" + } + + @RequiresApi(Build.VERSION_CODES.O) + fun create() { +// openTok = OpenTok(mainActivity, flutterEngine) + channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) + channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result -> + when (call.method) { + "launchPenguin" -> { + print("the platform channel is being called") + + if (HostNotificationPermissionManager.isNotificationPermissionGranted(mainActivity)) + else HostNotificationPermissionManager.requestNotificationPermission(mainActivity) + HostBgLocationManager.requestLocationBackgroundPermission(mainActivity) + HostGpsStateManager.requestLocationPermission(mainActivity) + val args = call.arguments as Map? + Log.d("TAG", "configureFlutterEngine: $args") + println("args") + args?.let { + PenguinView( + mainActivity, + 100, + args, + flutterEngine.dartExecutor.binaryMessenger, + activity = mainActivity, + channel + ) + } + } + + else -> { + result.notImplemented() + } + } + } + } + +} diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/AppPreferences.java b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/AppPreferences.java new file mode 100644 index 00000000..2f6c9722 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/AppPreferences.java @@ -0,0 +1,139 @@ +package com.cloudsolutions.HMGPatientApp.PermissionManager; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Handler; +import android.os.HandlerThread; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; + + +/** + * This preferences for app level + */ + +public class AppPreferences { + + public static final String PREF_NAME = "PenguinINUI_AppPreferences"; + public static final int MODE = Context.MODE_PRIVATE; + + public static final String campusIdKey = "campusId"; + + public static final String LANG = "Lang"; + + public static final String settingINFO = "SETTING-INFO"; + + public static final String userName = "userName"; + public static final String passWord = "passWord"; + + private static HandlerThread handlerThread; + private static Handler handler; + + static { + handlerThread = new HandlerThread("PreferencesHandlerThread"); + handlerThread.start(); + handler = new Handler(handlerThread.getLooper()); + } + + + + public static SharedPreferences getPreferences(final Context context) { + return context.getSharedPreferences(AppPreferences.PREF_NAME, AppPreferences.MODE); + } + + public static SharedPreferences.Editor getEditor(final Context context) { + return getPreferences(context).edit(); + } + + + public static void writeInt(final Context context, final String key, final int value) { + handler.post(() -> { + SharedPreferences.Editor editor = getEditor(context); + editor.putInt(key, value); + editor.apply(); + }); + } + + + public static int readInt(final Context context, final String key, final int defValue) { + Callable callable = () -> { + SharedPreferences preferences = getPreferences(context); + return preferences.getInt(key, -1); + }; + + Future future = new FutureTask<>(callable); + handler.post((Runnable) future); + + try { + return future.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); // Handle the exception appropriately + } + + return -1; // Return the default value in case of an error + } + + public static int getCampusId(final Context context) { + return readInt(context,campusIdKey,-1); + } + + + + public static void writeString(final Context context, final String key, final String value) { + handler.post(() -> { + SharedPreferences.Editor editor = getEditor(context); + editor.putString(key, value); + editor.apply(); + }); + } + + + public static String readString(final Context context, final String key, final String defValue) { + Callable callable = () -> { + SharedPreferences preferences = getPreferences(context); + return preferences.getString(key, defValue); + }; + + Future future = new FutureTask<>(callable); + handler.post((Runnable) future); + + try { + return future.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); // Handle the exception appropriately + } + + return defValue; // Return the default value in case of an error + } + + + public static void writeBoolean(final Context context, final String key, final boolean value) { + handler.post(() -> { + SharedPreferences.Editor editor = getEditor(context); + editor.putBoolean(key, value); + editor.apply(); + }); + } + + public static boolean readBoolean(final Context context, final String key, final boolean defValue) { + Callable callable = () -> { + SharedPreferences preferences = getPreferences(context); + return preferences.getBoolean(key, defValue); + }; + + Future future = new FutureTask<>(callable); + handler.post((Runnable) future); + + try { + return future.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); // Handle the exception appropriately + } + + return defValue; // Return the default value in case of an error + } + +} diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostBgLocationManager.java b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostBgLocationManager.java new file mode 100644 index 00000000..da0d8138 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostBgLocationManager.java @@ -0,0 +1,136 @@ +package com.cloudsolutions.HMGPatientApp.PermissionManager; + +import android.Manifest; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.provider.Settings; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import com.peng.pennavmap.PlugAndPlaySDK; +import com.peng.pennavmap.R; +import com.peng.pennavmap.enums.InitializationErrorType; + +/** + * Manages background location permission requests and handling for the application. + */ +public class HostBgLocationManager { + /** + * Request code for background location permission + */ + public static final int REQUEST_ACCESS_BACKGROUND_LOCATION_CODE = 301; + + /** + * Request code for navigating to app settings + */ + private static final int REQUEST_CODE_SETTINGS = 11234; + + /** + * Alert dialog for denied permissions + */ + private static AlertDialog deniedAlertDialog; + + /** + * Checks if the background location permission has been granted. + * + * @param context the context of the application or activity + * @return true if the permission is granted, false otherwise + */ + + public static boolean isLocationBackgroundGranted(Context context) { + return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) + == PackageManager.PERMISSION_GRANTED; + } + + /** + * Requests the background location permission from the user. + * + * @param activity the activity from which the request is made + */ + public static void requestLocationBackgroundPermission(Activity activity) { + // Check if the ACCESS_BACKGROUND_LOCATION permission is already granted + if (!isLocationBackgroundGranted(activity)) { + // Permission is not granted, so request it + ActivityCompat.requestPermissions(activity, + new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, + REQUEST_ACCESS_BACKGROUND_LOCATION_CODE); + } + } + + /** + * Displays a dialog prompting the user to grant the background location permission. + * + * @param activity the activity where the dialog is displayed + */ + public static void showLocationBackgroundPermission(Activity activity) { + AlertDialog alertDialog = new AlertDialog.Builder(activity) + .setCancelable(false) + .setMessage(activity.getString(R.string.com_penguin_nav_ui_geofence_alert_msg)) + .setPositiveButton(activity.getString(R.string.com_penguin_nav_ui_go_to_settings), (dialog, which) -> { + if (activity.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) { + HostBgLocationManager.requestLocationBackgroundPermission(activity); + } else { + openAppSettings(activity); + } + if (dialog != null) { + dialog.dismiss(); + } + }) + .setNegativeButton(activity.getString(R.string.com_penguin_nav_ui_later), (dialog, which) -> { + dialog.cancel(); + }) + .create(); + + alertDialog.show(); + } + + /** + * Handles the scenario where permissions are denied by the user. + * Displays a dialog to guide the user to app settings or exit the activity. + * + * @param activity the activity where the dialog is displayed + */ + public static synchronized void handlePermissionsDenied(Activity activity) { + if (deniedAlertDialog != null && deniedAlertDialog.isShowing()) { + deniedAlertDialog.dismiss(); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setCancelable(false) + .setMessage(activity.getString(R.string.com_penguin_nav_ui_permission_denied_dialog_msg)) + .setNegativeButton(activity.getString(R.string.com_penguin_nav_ui_cancel), (dialogInterface, i) -> { + if (PlugAndPlaySDK.externalPenNavUIDelegate != null) { + PlugAndPlaySDK.externalPenNavUIDelegate.onPenNavInitializationError( + InitializationErrorType.permissions.getTypeKey(), + InitializationErrorType.permissions); + } + activity.finish(); + }) + .setPositiveButton(activity.getString(R.string.com_penguin_nav_ui_go_settings), (dialogInterface, i) -> { + dialogInterface.dismiss(); + openAppSettings(activity); + }); + deniedAlertDialog = builder.create(); + deniedAlertDialog.show(); + } + + /** + * Opens the application's settings screen to allow the user to modify permissions. + * + * @param activity the activity from which the settings screen is launched + */ + private static void openAppSettings(Activity activity) { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", activity.getPackageName(), null); + intent.setData(uri); + + if (intent.resolveActivity(activity.getPackageManager()) != null) { + activity.startActivityForResult(intent, REQUEST_CODE_SETTINGS); + } + } +} diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostGpsStateManager.java b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostGpsStateManager.java new file mode 100644 index 00000000..f7f39c97 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostGpsStateManager.java @@ -0,0 +1,68 @@ +package com.cloudsolutions.HMGPatientApp.PermissionManager; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.location.LocationManager; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import com.peng.pennavmap.managers.permissions.managers.BgLocationManager; + +public class HostGpsStateManager { + private static final int LOCATION_PERMISSION_REQUEST_CODE = 1; + + + public boolean checkGPSEnabled(Activity activity) { + LocationManager gpsStateManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE); + return gpsStateManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + } + + public static boolean isGpsGranted(Activity activity) { + return BgLocationManager.isLocationBackgroundGranted(activity) + || ContextCompat.checkSelfPermission( + activity, + Manifest.permission.ACCESS_FINE_LOCATION + ) == PackageManager.PERMISSION_GRANTED + && ContextCompat.checkSelfPermission( + activity, + Manifest.permission.ACCESS_COARSE_LOCATION + ) == PackageManager.PERMISSION_GRANTED; + } + + + /** + * Checks if the location permission is granted. + * + * @param activity the Activity context + * @return true if permission is granted, false otherwise + */ + public static boolean isLocationPermissionGranted(Activity activity) { + return ContextCompat.checkSelfPermission( + activity, + Manifest.permission.ACCESS_FINE_LOCATION + ) == PackageManager.PERMISSION_GRANTED && + ContextCompat.checkSelfPermission( + activity, + Manifest.permission.ACCESS_COARSE_LOCATION + ) == PackageManager.PERMISSION_GRANTED; + } + + /** + * Requests the location permission. + * + * @param activity the Activity context + */ + public static void requestLocationPermission(Activity activity) { + ActivityCompat.requestPermissions( + activity, + new String[]{ + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION, + }, + LOCATION_PERMISSION_REQUEST_CODE + ); + } +} diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostNotificationPermissionManager.java b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostNotificationPermissionManager.java new file mode 100644 index 00000000..2dac16ca --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/HostNotificationPermissionManager.java @@ -0,0 +1,73 @@ +package com.cloudsolutions.HMGPatientApp.PermissionManager; + +import android.app.Activity; +import android.content.pm.PackageManager; +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.app.NotificationManagerCompat; + +public class HostNotificationPermissionManager { + private static final int REQUEST_NOTIFICATION_PERMISSION = 100; + + + /** + * Checks if the notification permission is granted. + * + * @return true if the notification permission is granted, false otherwise. + */ + public static boolean isNotificationPermissionGranted(Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + try { + return ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.POST_NOTIFICATIONS) + == PackageManager.PERMISSION_GRANTED; + } catch (Exception e) { + // Handle cases where the API is unavailable + e.printStackTrace(); + return NotificationManagerCompat.from(activity).areNotificationsEnabled(); + } + } else { + // Permissions were not required below Android 13 for notifications + return NotificationManagerCompat.from(activity).areNotificationsEnabled(); + } + } + + /** + * Requests the notification permission. + */ + public static void requestNotificationPermission(Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (!isNotificationPermissionGranted(activity)) { + ActivityCompat.requestPermissions(activity, + new String[]{android.Manifest.permission.POST_NOTIFICATIONS}, + REQUEST_NOTIFICATION_PERMISSION); + } + } + } + + /** + * Handles the result of the permission request. + * + * @param requestCode The request code passed in requestPermissions(). + * @param permissions The requested permissions. + * @param grantResults The grant results for the corresponding permissions. + */ + public static boolean handlePermissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (permissions.length > 0 && + permissions[0].equals(android.Manifest.permission.POST_NOTIFICATIONS) && + grantResults.length > 0 && + grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // Permission granted + System.out.println("Notification permission granted."); + return true; + } else { + // Permission denied + System.out.println("Notification permission denied."); + return false; + } + + } + + +} diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionHelper.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionHelper.kt new file mode 100644 index 00000000..9a033f36 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionHelper.kt @@ -0,0 +1,27 @@ +package com.cloudsolutions.HMGPatientApp.PermissionManager + +import android.Manifest + +object PermissionHelper { + + fun getRequiredPermissions(): Array { + val permissions = mutableListOf( + Manifest.permission.INTERNET, + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_NETWORK_STATE, + Manifest.permission.BLUETOOTH, + Manifest.permission.BLUETOOTH_ADMIN, +// Manifest.permission.ACTIVITY_RECOGNITION + ) + + // For Android 12 (API level 31) and above, add specific permissions +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12 (API 31) and above + permissions.add(Manifest.permission.BLUETOOTH_SCAN) + permissions.add(Manifest.permission.BLUETOOTH_CONNECT) + permissions.add(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS) +// } + + return permissions.toTypedArray() + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionManager.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionManager.kt new file mode 100644 index 00000000..6dadddb1 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionManager.kt @@ -0,0 +1,50 @@ +package com.cloudsolutions.HMGPatientApp.PermissionManager + +import android.app.Activity +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat + +class PermissionManager( + private val context: Context, + val listener: PermissionListener, + private val requestCode: Int, + vararg permissions: String +) { + + private val permissionsArray = permissions + + interface PermissionListener { + fun onPermissionGranted() + fun onPermissionDenied() + } + + fun arePermissionsGranted(): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + permissionsArray.all { + ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED + } + } else { + true + } + } + + fun requestPermissions(activity: Activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + ActivityCompat.requestPermissions(activity, permissionsArray, requestCode) + } + } + + fun handlePermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + if (this.requestCode == requestCode) { + val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } + if (allGranted) { + listener.onPermissionGranted() + } else { + listener.onPermissionDenied() + } + } + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionResultReceiver.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionResultReceiver.kt new file mode 100644 index 00000000..7c2df4cb --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/PermissionManager/PermissionResultReceiver.kt @@ -0,0 +1,15 @@ +package com.cloudsolutions.HMGPatientApp.PermissionManager + +// PermissionResultReceiver.kt +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent + +class PermissionResultReceiver( + private val callback: (Boolean) -> Unit +) : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + val granted = intent?.getBooleanExtra("PERMISSION_GRANTED", false) ?: false + callback(granted) + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinMethod.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinMethod.kt new file mode 100644 index 00000000..4807bcc7 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinMethod.kt @@ -0,0 +1,13 @@ +package com.cloudsolutions.HMGPatientApp.penguin + +enum class PenguinMethod { + // initializePenguin("initializePenguin"), + // configurePenguin("configurePenguin"), + // showPenguinUI("showPenguinUI"), + // onPenNavUIDismiss("onPenNavUIDismiss"), + // onReportIssue("onReportIssue"), + // onPenNavSuccess("onPenNavSuccess"), + onPenNavInitializationError // onLocationOffCampus("onLocationOffCampus"), + // navigateToPOI("navigateToPOI"), + // openSharedLocation("openSharedLocation"); +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinNavigator.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinNavigator.kt new file mode 100644 index 00000000..29cc82df --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinNavigator.kt @@ -0,0 +1,97 @@ +package com.cloudsolutions.HMGPatientApp.penguin + +import android.content.Context +import com.google.gson.Gson +import com.peng.pennavmap.PlugAndPlaySDK +import com.peng.pennavmap.connections.ApiController +import com.peng.pennavmap.interfaces.RefIdDelegate +import com.peng.pennavmap.models.TokenModel +import com.peng.pennavmap.models.postmodels.PostToken +import com.peng.pennavmap.utils.AppSharedData +import okhttp3.ResponseBody +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import android.util.Log + + +class PenguinNavigator() { + + fun navigateTo(mContext: Context, refID: String, delegate: RefIdDelegate,clientID : String,clientKey : String ) { + val postToken = PostToken(clientID, clientKey) + getToken(mContext, postToken, object : RefIdDelegate { + override fun onRefByIDSuccess(PoiId: String?) { + Log.e("navigateTo", "PoiId is+++++++ $refID") + + PlugAndPlaySDK.navigateTo(mContext, refID, object : RefIdDelegate { + override fun onRefByIDSuccess(PoiId: String?) { + Log.e("navigateTo", "PoiId 2is+++++++ $PoiId") + + delegate.onRefByIDSuccess(refID) + + } + + override fun onGetByRefIDError(error: String?) { + delegate.onRefByIDSuccess(error) + } + + }) + + + } + + override fun onGetByRefIDError(error: String?) { + delegate.onRefByIDSuccess(error) + } + + }) + + } + + fun getToken(mContext: Context, postToken: PostToken?, apiTokenCallBack: RefIdDelegate) { + try { + // Create the API call + val purposesCall: Call = ApiController.getInstance(mContext) + .apiMethods + .getToken(postToken) + + // Enqueue the call for asynchronous execution + purposesCall.enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful() && response.body() != null) { + try { + response.body()?.use { responseBody -> + val responseBodyString: String = responseBody.string() // Use `string()` to get the actual response content + if (responseBodyString.isNotEmpty()) { + val tokenModel = Gson().fromJson(responseBodyString, TokenModel::class.java) + if (tokenModel != null && tokenModel.token != null) { + AppSharedData.apiToken = tokenModel.token + apiTokenCallBack.onRefByIDSuccess(tokenModel.token) + } else { + apiTokenCallBack.onGetByRefIDError("Failed to parse token model") + } + } else { + apiTokenCallBack.onGetByRefIDError("Response body is empty") + } + } + } catch (e: Exception) { + apiTokenCallBack.onGetByRefIDError("An error occurred: ${e.message}") + } + } else { + apiTokenCallBack.onGetByRefIDError("Unsuccessful response: " + response.code()) + } + } + + override fun onFailure(call: Call, t: Throwable) { + apiTokenCallBack.onGetByRefIDError(t.message) + } + }) + } catch (error: Exception) { + apiTokenCallBack.onGetByRefIDError("Exception during API call: $error") + } + } + +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinView.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinView.kt new file mode 100644 index 00000000..2122e01c --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/penguin/PenguinView.kt @@ -0,0 +1,376 @@ +package com.cloudsolutions.HMGPatientApp.penguin + +import android.app.Activity +import android.content.Context +import android.content.Context.RECEIVER_EXPORTED +import android.content.IntentFilter +import android.graphics.Color +import android.os.Build +import android.util.Log +import android.view.View +import android.view.ViewGroup +import android.widget.RelativeLayout +import android.widget.Toast +import androidx.annotation.RequiresApi +import com.cloudsolutions.HMGPatientApp.PermissionManager.PermissionManager +import com.cloudsolutions.HMGPatientApp.PermissionManager.PermissionResultReceiver +import com.cloudsolutions.HMGPatientApp.MainActivity +import com.cloudsolutions.HMGPatientApp.PermissionManager.PermissionHelper +import com.peng.pennavmap.PlugAndPlayConfiguration +import com.peng.pennavmap.PlugAndPlaySDK +import com.peng.pennavmap.enums.InitializationErrorType +import com.peng.pennavmap.interfaces.PenNavUIDelegate +import com.peng.pennavmap.utils.Languages +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.platform.PlatformView +import com.peng.pennavmap.interfaces.PIEventsDelegate +import com.peng.pennavmap.interfaces.PILocationDelegate +import com.peng.pennavmap.interfaces.RefIdDelegate +import com.peng.pennavmap.models.LocationMessage +import com.peng.pennavmap.models.PIReportIssue +import java.util.ArrayList +import penguin.com.pennav.renderer.PIRendererSettings + +/** + * Custom PlatformView for displaying Penguin UI components within a Flutter app. + * Implements `PlatformView` for rendering the view, `MethodChannel.MethodCallHandler` for handling method calls, + * and `PenNavUIDelegate` for handling SDK events. + */ +@RequiresApi(Build.VERSION_CODES.O) +internal class PenguinView( + context: Context, + id: Int, + val creationParams: Map, + messenger: BinaryMessenger, + activity: MainActivity, + val channel: MethodChannel +) : PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate, PIEventsDelegate, + PILocationDelegate { + // The layout for displaying the Penguin UI + private val mapLayout: RelativeLayout = RelativeLayout(context) + private val _context: Context = context + + private val permissionResultReceiver: PermissionResultReceiver + private val permissionIntentFilter = IntentFilter("PERMISSION_RESULT_ACTION") + + private companion object { + const val PERMISSIONS_REQUEST_CODE = 1 + } + + private lateinit var permissionManager: PermissionManager + + // Reference to the main activity + private var _activity: Activity = activity + + private lateinit var mContext: Context + + lateinit var navigator: PenguinNavigator + + init { + // Set layout parameters for the mapLayout + mapLayout.layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT + ) + + mContext = context + + + permissionResultReceiver = PermissionResultReceiver { granted -> + if (granted) { + onPermissionsGranted() + } else { + onPermissionsDenied() + } + } + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + mContext.registerReceiver( + permissionResultReceiver, + permissionIntentFilter, + RECEIVER_EXPORTED + ) + } else { + mContext.registerReceiver( + permissionResultReceiver, + permissionIntentFilter, + ) + } + + // Set the background color of the layout + mapLayout.setBackgroundColor(Color.RED) + + permissionManager = PermissionManager( + context = mContext, + listener = object : PermissionManager.PermissionListener { + override fun onPermissionGranted() { + // Handle permissions granted + onPermissionsGranted() + } + + override fun onPermissionDenied() { + // Handle permissions denied + onPermissionsDenied() + } + }, + requestCode = PERMISSIONS_REQUEST_CODE, + PermissionHelper.getRequiredPermissions().get(0) + ) + + if (!permissionManager.arePermissionsGranted()) { + permissionManager.requestPermissions(_activity) + } else { + // Permissions already granted + permissionManager.listener.onPermissionGranted() + } + + + } + + private fun onPermissionsGranted() { + // Handle the actions when permissions are granted + Log.d("PermissionsResult", "onPermissionsGranted") + // Register the platform view factory for creating custom views + + // Initialize the Penguin SDK + initPenguin() + + + } + + private fun onPermissionsDenied() { + // Handle the actions when permissions are denied + Log.d("PermissionsResult", "onPermissionsDenied") + + } + + /** + * Returns the view associated with this PlatformView. + * + * @return The main view for this PlatformView. + */ + override fun getView(): View { + return mapLayout + } + + /** + * Cleans up resources associated with this PlatformView. + */ + override fun dispose() { + // Cleanup code if needed + } + + /** + * Handles method calls from Dart code. + * + * @param call The method call from Dart. + * @param result The result callback to send responses back to Dart. + */ + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + // Handle method calls from Dart code here + } + + /** + * Initializes the Penguin SDK with custom configuration and delegates. + */ + private fun initPenguin() { + navigator = PenguinNavigator() + // Configure the PlugAndPlaySDK + val language = when (creationParams["languageCode"] as String) { + "ar" -> Languages.ar + "en" -> Languages.en + else -> { + Languages.en + } + } + + +// PlugAndPlaySDK.configuration = Builder() +// .setClientData(MConstantsDemo.CLIENT_ID, MConstantsDemo.CLIENT_KEY) +// .setLanguageID(selectedLanguage) +// .setBaseUrl(MConstantsDemo.DATA_URL, MConstantsDemo.POSITION_URL) +// .setServiceName(MConstantsDemo.DATA_SERVICE_NAME, MConstantsDemo.POSITION_SERVICE_NAME) +// .setUserName(name) +// .setSimulationModeEnabled(isSimulation) +// .setCustomizeColor(if (MConstantsDemo.APP_COLOR != null) MConstantsDemo.APP_COLOR else "#2CA0AF") +// .setEnableBackButton(MConstantsDemo.SHOW_BACK_BUTTON) +// .setCampusId(MConstantsDemo.selectedCampusId) +// +// .setShowUILoader(true) +// .build() + + PIRendererSettings.styleUri = "mapbox://styles/rwaid/cm3h30b36007v01qz7ik8a0sk" + + PlugAndPlaySDK.configuration = PlugAndPlayConfiguration.Builder() + .setBaseUrl( + creationParams["dataURL"] as String, + creationParams["positionURL"] as String + ) + .setServiceName( + creationParams["dataServiceName"] as String, + creationParams["positionServiceName"] as String + ) + .setClientData( + creationParams["clientID"] as String, + creationParams["clientKey"] as String + ) + .setUserName(creationParams["username"] as String) +// .setLanguageID(Languages.en) + .setLanguageID(language) + .setSimulationModeEnabled(creationParams["isSimulationModeEnabled"] as Boolean) + .setEnableBackButton(true) +// .setDeepLinkData("deeplink") + .setCustomizeColor("#2CA0AF") + .setDeepLinkSchema("", "") + .setIsEnableReportIssue(true) + .setDeepLinkData("") + .setEnableSharedLocationCallBack(false) + .setShowUILoader(true) + .setCampusId(creationParams["projectID"] as Int) + .build() + + + Log.d( + "TAG", + "initPenguin: ${creationParams["projectID"]}" + ) + + Log.d( + "TAG", + "initPenguin: creation param are ${creationParams}" + ) + + // Set location delegate to handle location updates +// PlugAndPlaySDK.setPiLocationDelegate { + // Example code to handle location updates + // Uncomment and modify as needed + // if (location.size() > 0) + // Toast.makeText(_context, "Location Info Latitude: ${location[0]}, Longitude: ${location[1]}", Toast.LENGTH_SHORT).show() +// } + + // Set events delegate for reporting issues +// PlugAndPlaySDK.setPiEventsDelegate(new PIEventsDelegate() { +// @Override +// public void onReportIssue(PIReportIssue issue) { +// Log.e("Issue Reported: ", issue.getReportType()); +// } +// // Implement issue reporting logic here } +// @Override +// public void onSharedLocation(String link) { +// // Implement Shared location logic here +// } +// }) + + // Start the Penguin SDK + PlugAndPlaySDK.setPiEventsDelegate(this) + PlugAndPlaySDK.setPiLocationDelegate(this) + PlugAndPlaySDK.start(mContext, this) + } + + + /** + * Navigates to the specified reference ID. + * + * @param refID The reference ID to navigate to. + */ + fun navigateTo(refID: String) { + try { + if (refID.isBlank()) { + Log.e("navigateTo", "Invalid refID: The reference ID is blank.") + } +// referenceId = refID + navigator.navigateTo(mContext, refID,object : RefIdDelegate { + override fun onRefByIDSuccess(PoiId: String?) { + Log.e("navigateTo", "PoiId is penguin view+++++++ $PoiId") + +// channelFlutter.invokeMethod( +// PenguinMethod.navigateToPOI.name, +// "navigateTo Success" +// ) + } + + override fun onGetByRefIDError(error: String?) { + Log.e("navigateTo", "error is penguin view+++++++ $error") + +// channelFlutter.invokeMethod( +// PenguinMethod.navigateToPOI.name, +// "navigateTo Failed: Invalid refID" +// ) + } + } , creationParams["clientID"] as String, creationParams["clientKey"] as String ) + + } catch (e: Exception) { + Log.e("navigateTo", "Exception occurred during navigation: ${e.message}", e) +// channelFlutter.invokeMethod( +// PenguinMethod.navigateToPOI.name, +// "Failed: Exception - ${e.message}" +// ) + } + } + + /** + * Called when Penguin UI setup is successful. + * + * @param warningCode Optional warning code received from the SDK. + */ + override fun onPenNavSuccess(warningCode: String?) { + val clinicId = creationParams["clinicID"] as String + + if(clinicId.isEmpty()) return + + navigateTo(clinicId) +// navigateTo("3-1") + } + + /** + * Called when there is an initialization error with Penguin UI. + * + * @param description Description of the error. + * @param errorType Type of initialization error. + */ + override fun onPenNavInitializationError( + description: String?, + errorType: InitializationErrorType? + ) { + val arguments: Map = mapOf( + "description" to description, + "type" to errorType?.name + ) + Log.d( + "description", + "description : ${description}" + ) + + channel.invokeMethod(PenguinMethod.onPenNavInitializationError.name, arguments) + Toast.makeText(mContext, "Navigation Error: $description", Toast.LENGTH_SHORT).show() + } + + /** + * Called when Penguin UI is dismissed. + */ + override fun onPenNavUIDismiss() { + // Handle UI dismissal if needed + try { + mContext.unregisterReceiver(permissionResultReceiver) + dispose(); + } catch (e: IllegalArgumentException) { + Log.e("PenguinView", "Receiver not registered: $e") + } + } + + override fun onReportIssue(issue: PIReportIssue?) { + TODO("Not yet implemented") + } + + override fun onSharedLocation(link: String?) { + TODO("Not yet implemented") + } + + override fun onLocationOffCampus(location: ArrayList?) { + TODO("Not yet implemented") + } + + override fun onLocationMessage(locationMessage: LocationMessage?) { + TODO("Not yet implemented") + } +} diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/watch/samsung_watch/SamsungWatch.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/watch/samsung_watch/SamsungWatch.kt new file mode 100644 index 00000000..336651e4 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/watch/samsung_watch/SamsungWatch.kt @@ -0,0 +1,402 @@ +package com.cloudsolutions.HMGPatientApp.watch.samsung_watch + + + +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import com.cloudsolutions.HMGPatientApp.MainActivity +import com.cloudsolutions.HMGPatientApp.watch.samsung_watch.model.Vitals +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodCall +import com.samsung.android.sdk.health.data.HealthDataService +import com.samsung.android.sdk.health.data.HealthDataStore +import com.samsung.android.sdk.health.data.data.AggregatedData +import com.samsung.android.sdk.health.data.data.HealthDataPoint +import com.samsung.android.sdk.health.data.permission.AccessType +import com.samsung.android.sdk.health.data.permission.Permission +import com.samsung.android.sdk.health.data.request.DataType +import com.samsung.android.sdk.health.data.request.DataTypes +import com.samsung.android.sdk.health.data.request.LocalTimeFilter +import com.samsung.android.sdk.health.data.request.LocalTimeGroup +import com.samsung.android.sdk.health.data.request.LocalTimeGroupUnit +import com.samsung.android.sdk.health.data.request.Ordering +import com.samsung.android.sdk.health.data.response.DataResponse +import io.flutter.plugin.common.MethodChannel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import java.time.LocalDateTime +import java.time.LocalTime + +class SamsungWatch( + private var flutterEngine: FlutterEngine, + private var mainActivity: MainActivity +) { + + private lateinit var channel: MethodChannel + private lateinit var dataStore: HealthDataStore + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + private val TAG = "SamsungWatch" + + + private lateinit var vitals: MutableMap> + companion object { + private const val CHANNEL = "samsung_watch" + + } + init{ + create() + } + + @RequiresApi(Build.VERSION_CODES.O) + fun create() { + Log.d(TAG, "create: is called") +// openTok = OpenTok(mainActivity, flutterEngine) + channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) + channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result -> + when (call.method) { + "init" -> { + Log.d(TAG, "onMethodCall: init called") + dataStore = HealthDataService.getStore(mainActivity) + vitals = mutableMapOf() + result.success("initialized") + } + + "getPermission"->{ + if(!this::dataStore.isInitialized) + result.error("DataStoreNotInitialized", "Please call init before requesting permissions", null) + val permSet = setOf( + Permission.of(DataTypes.HEART_RATE, AccessType.READ), + Permission.of(DataTypes.STEPS, AccessType.READ), + Permission.of(DataTypes.BLOOD_OXYGEN, AccessType.READ), + Permission.of(DataTypes.ACTIVITY_SUMMARY, AccessType.READ), + Permission.of(DataTypes.SLEEP, AccessType.READ), + Permission.of(DataTypes.BODY_TEMPERATURE, AccessType.READ), + Permission.of(DataTypes.EXERCISE, AccessType.READ), +// Permission.of(DataTypes.SKIN_TEMPERATURE, AccessType.READ), +// Permission.of(DataTypes.NUTRITION, AccessType.READ), + + ) + scope.launch { + try { + var granted = dataStore.getGrantedPermissions(permSet) + + if (granted.containsAll(permSet)) { + result.success("Permission Granted") + return@launch + } + + granted = dataStore.requestPermissions(permSet, mainActivity) + + if (granted.containsAll(permSet)) { + result.success("Permission Granted") // adapt result as needed + return@launch + } + result.error("PermissionError", "Permission Not Granted", null) // adapt result as needed + } catch (e: Exception) { + Log.e(TAG, "create: getPermission failed", e) + result.error("PermissionError", e.message, null) + } + } + } + + "getHeartRate"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val readRequest = DataTypes.HEART_RATE.readDataRequestBuilder + .setLocalTimeFilter(localTimeFilter) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val heartRateList = dataStore.readData(readRequest).dataList + processHeartVital(heartRateList) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals}") + result.success("Data is obtained") + } + } + + + "getSleepData" -> { + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val readRequest = DataTypes.SLEEP.readDataRequestBuilder + .setLocalTimeFilter(localTimeFilter) + .setOrdering(Ordering.ASC) + .build() + scope.launch { + val sleepData = dataStore.readData(readRequest).dataList + processSleepVital(sleepData) + print("the data is $vitals") + Log.d(TAG, "the data is $vitals") + result.success("Data is obtained") + } + + } + + "steps"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1) + val aggregateRequest = DataType.StepsType.TOTAL.requestBuilder + .setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup) + .setOrdering(Ordering.ASC) + .build() + + scope.launch { + val steps = dataStore.aggregateData(aggregateRequest) + processStepsCount(steps) + print("the data is $vitals") + Log.d(TAG, "the data is $vitals") + result.success("Data is obtained") + } + } + + "activitySummary"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1) + val readRequest = DataType.ActivitySummaryType.TOTAL_ACTIVE_CALORIES_BURNED + .requestBuilder + .setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val activityResult = dataStore.aggregateData(readRequest).dataList + processActivity(activityResult) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals}") + result.success("Data is obtained") + } + +// val readRequest = DataTypes.EXERCISE.readDataRequestBuilder +// .setLocalTimeFilter(localTimeFilter) +// .build() +// +// scope.launch{ +// try { +// val readResult = dataStore.readData(readRequest) +// val dataPoints = readResult.dataList +// +// processActivity(dataPoints) +// +// +// } catch (e: Exception) { +// e.printStackTrace() +// } +// result.success("Data is obtained") +// } + } + + "bloodOxygen"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val readRequest = DataTypes.BLOOD_OXYGEN.readDataRequestBuilder + .setLocalTimeFilter(localTimeFilter) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val bloodOxygenList = dataStore.readData(readRequest).dataList + processBloodOxygen(bloodOxygenList) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals["bloodOxygen"]}") + result.success("Data is obtained") + } + } + + + "bodyTemperature"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val readRequest = DataTypes.BODY_TEMPERATURE.readDataRequestBuilder + .setLocalTimeFilter(localTimeFilter) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val bodyTemperatureList = dataStore.readData(readRequest).dataList + processBodyTemperature(bodyTemperatureList) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals["bodyTemperature"]}") + result.success("Data is obtained") + } + } + + "distance"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1) + val readRequest = DataType.ActivitySummaryType.TOTAL_DISTANCE.requestBuilder + .setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup) + .setOrdering(Ordering.DESC) + .build() + + scope.launch { + val activityResult = dataStore.aggregateData(readRequest).dataList + processDistance(activityResult) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals}") + result.success("Data is obtained") + } + } + + "retrieveData"->{ + if(vitals.isEmpty()){ + result.error("NoDataFound", "No Data was obtained", null) + return@setMethodCallHandler + } + result.success(""" + { + "heartRate": ${vitals["heartRate"]}, + "steps": ${vitals["steps"]}, + "sleep": ${vitals["sleep"]}, + "activity": ${vitals["activity"]}, + "bloodOxygen": ${vitals["bloodOxygen"]}, + "bodyTemperature": ${vitals["bodyTemperature"]}, + "distance": ${vitals["distance"]} + } + """.trimIndent()) + } + + + "closeCoroutineScope"->{ + destroy() + result.success("Coroutine Scope Cancelled") + } + + else -> { + result.notImplemented() + } + } + } + } + + private fun CoroutineScope.processDistance(activityResult: List>) { + vitals["distance"] = mutableListOf() + activityResult.forEach { stepData -> + val vitalData = Vitals().apply { + + value = stepData.value.toString() + timeStamp = stepData.startTime.toString() + } + (vitals["distance"] as MutableList).add(vitalData) + } + } + + private fun CoroutineScope.processBodyTemperature( bodyTemperatureList :List) { + vitals["bodyTemperature"] = mutableListOf() + bodyTemperatureList.forEach { stepData -> + val vitalData = Vitals().apply { + value = stepData.getValue(DataType.BodyTemperatureType.BODY_TEMPERATURE).toString() + timeStamp = stepData.endTime.toString() + } + (vitals["bodyTemperature"] as MutableList).add(vitalData) + } + } + + private fun CoroutineScope.processBloodOxygen( bloodOxygenList :List) { + vitals["bloodOxygen"] = mutableListOf() + bloodOxygenList.forEach { stepData -> + val vitalData = Vitals().apply { + value = stepData.getValue(DataType.BloodOxygenType.OXYGEN_SATURATION).toString() + timeStamp = stepData.endTime.toString() + } + (vitals["bloodOxygen"] as MutableList).add(vitalData) + } + } + + +// private fun CoroutineScope.processActivity(activityResult: List>) { +// +// vitals["activity"] = mutableListOf() +// activityResult.forEach { stepData -> +// val vitalData = Vitals().apply { +// +// value = stepData.value.toString() +// timeStamp = stepData.startTime.toString() +// } +// (vitals["activity"] as MutableList).add(vitalData) +// } +// } + private fun CoroutineScope.processActivity(activityResult: List>) { + + vitals["activity"] = mutableListOf() + activityResult.forEach { stepData -> + val vitalData = Vitals().apply { + + value = stepData.value.toString() + timeStamp = stepData.startTime.toString() + } + (vitals["activity"] as MutableList).add(vitalData) + } + +// dataPoints.forEach { dataPoint -> +// val sessions = dataPoint.getValue(DataType.ExerciseType.SESSIONS) +// +// sessions?.forEach { session -> +// +// val exerciseSessionCalories = session.calories +// val vitalData = Vitals().apply { +// value = exerciseSessionCalories.toString() +// timeStamp = session.startTime.toString() +// } +// (vitals["activity"] as MutableList).add(vitalData) +// } +// } + } + + private fun CoroutineScope.processStepsCount(result: DataResponse>) { + val stepCount = ArrayList>() + var totalSteps: Long = 0 + vitals["steps"] = mutableListOf() + result.dataList.forEach { stepData -> + val vitalData = Vitals().apply { + value = (stepData.value as Long).toString() + timeStamp = stepData.startTime.toString() + } + (vitals["steps"] as MutableList).add(vitalData) + } + + } + + private fun CoroutineScope.processSleepVital(sleepData: List) { + vitals["sleep"] = mutableListOf() + sleepData.forEach { + (vitals["sleep"] as MutableList).add( + Vitals().apply { + timeStamp = it.startTime.toString() + value = (it.getValue(DataType.SleepType.DURATION)?.toMillis().toString()) + } + ) + } + } + + private suspend fun CoroutineScope.processHeartVital( + heartRateList: List, + ) { + vitals["heartRate"] = mutableListOf() + heartRateList.forEach { + (vitals["heartRate"] as MutableList).add(processHeartRateData(it)) + } + } + + private fun processHeartRateData(heartRateData: HealthDataPoint) = + Vitals().apply { + heartRateData.getValue(DataType.HeartRateType.MAX_HEART_RATE)?.let { + value = it.toString() + } + timeStamp = heartRateData.startTime.toString() + } + + + fun destroy() { + scope.cancel() + } + +} diff --git a/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/watch/samsung_watch/model/Vitals.kt b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/watch/samsung_watch/model/Vitals.kt new file mode 100644 index 00000000..577ab283 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloudsolutions/HMGPatientApp/watch/samsung_watch/model/Vitals.kt @@ -0,0 +1,13 @@ +package com.cloudsolutions.HMGPatientApp.watch.samsung_watch.model + +data class Vitals( + var value : String = "", + var timeStamp :String = "" +){ + override fun toString(): String { + return """{ + "value": "$value", + "timeStamp": "$timeStamp"} + """.trimIndent() + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt b/android/app/src/main/kotlin/com/ejada/hmg/MainActivity.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png index 348b511670c0e98f244aa2c8337fa3cf0b0ce167..06095ae42ce39d1fcd9ba811f1fc6e195869c51c 100644 GIT binary patch literal 4895 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 KMNUMnLSTZ?!$!~m diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png index 410b1b1e59ec6f502163a727e67ceea9a9b48d5a..cb15fb647369d50bbf9117d2f8b1be9e0d244bf0 100644 GIT binary patch delta 3230 zcmV;P3}N%m4WSv3BYzB5NklUQx9qa) z?99&W%**fB@4aQ1Wns7~UGIC{ulqZGU-#GjzBjuTdx~MR=YP4ev2np=~5cx)6VO`7z*6)RS}&9dy?d+(h&apJ@)MvNFSx}l+AaR2`O>nkfOYhtlj z1$kp6$xD{aLw~v?D;-oBtB`KlkS*Dy?a9I*EX$THdt2COr9cu^$wIZn|S6=P`9I^(>_k}wfkPJbAMm3>+XEAaUV6DE9@1D7ih zwU!i)kfHbGapgiPuw9^zBSO>_>Q&v_GK5Lkgi%<9nQVDEU~jnLh8yXjM`wEjm%?r? zh=3YSen^&W`F})+x1Gr*d`j9#Qhg{C$V%7N?eKQB1Kr)=bc68=$hI(GPZ37La>^;E z3=wuacI?-e)^~#hET3n*(x(Nzy@G0_*Mgj5gLG`^UxTxNbUjo!5jsR~ah8q`HU* z{d7BM(4YqO85Y$(8Gtd^aqTqZKlljt3-vHH)iB8f5aS6JVMvJ-R!4%QOO!~!#N*DE zY=3sY_Yb75zsZMGbSG2-1o*yau=Vxz$7w9=6mW2Z=2omiZs|&x0sVolEFI#B1Im>H zSPB(_#iYIi$a=dw{0S0oCJQsLKe8?FpnLTPaQh-yg%In&fdh}TH7w%qAsOXEHyv={ z0UmLDhB5FuJK?pq?VonG!fizIORR_T1%G%P+oyaRbuu*LV@9It)@kqcLlg+F2$_bF8TU;?V=JdEn*hx~fZBSFnR z_Sca5&Abbyt`jnH?_(jJhoDx2(W*EhWpMk_h=Oc0Hg?@d}c|pxS_Qy#T zlP4m1^$+2~fsX4q)Jaw`aXgaOT!r|zDRc1!NQ6Y0#3kbpJ9{)_&+AOXg$r1OpSHDX zd;$!@;#$Hk2cluGt0|z`%TQ6!)_*hD)=A;^2%T{?H~L<6Hp}VCBhoMk4uk+mm@5!D z`9wG7?| z%JU&i1WS3S&jqjeM4?U{5Iy_vz|hKbK)HW1iLPf~WEQ#!UOLV90$*w!DY*0AZ6z8L z5LWi9U*VnGe;YH*?K|P|bbpE*-{AV(3ra2V(g_`#9$!`-PZ}MUnWvut#v*{Yb>gzDM%q56^gk^IqQK>Z@ECVL^K9dT?Ma$dAr7o&jjrQo!=t0H7*Ly zJg=jJvi$&MpVG%n)PH5VvLU`Q>EIlYQq5vW%vv?G0Va-e1$cLtoKY-`v`0#3RpX#! zs4J|UaQU}`bAU$NreoTxT*u=k_IB)qIc|V&u^6PBGh7!=OOln0h~Wkv5Q*{M2^h+&Y@~Pkuhyb zJ&V*1!h&4>r9Odk6aZD9KkDB@S=Av)w`N{%Ws3QX`+vWe??9+W#=`cIuBBT}l=&8x zc{xy~uVOz861c+riu z65PPykYZYyVxQE_9EP8ZGFS>&`t(NDX6;j+vZXnY^l)?g5QN8X1^0sGPu8>=JgSla zYg56$VSfZ|KDtxGC0SBd5r2%sE-^pOBhy2U54* z<<~QAN9yKZIbZ^pn)V9+gV(1c#|=DXg{KnIEo`wYi=e~)&4`5A?>;oN(fZnmoN4LXCx2 z3!Anea?*+Xn!BBoYH7=#Up9KMu3x`?oqeB0oqLfyr4!Mw4My$amrylhDzn8iVShhg z&-^Ayg%O{fJdokTA?c7do>0o2^s~BVz3R5GZ#j+E*5! z@@GGRIi?PrZXXNw6he&%b4yFh5`VjL<;vA-)~s2jxYFNc_pq@gujResmbEsq<)0H2 zR!X5GgO5jK@CjV%5<02OXUU#O9Zbii)7B4!sjBor2R7YA5=wXpqp+@Cy?T|fE4T`G zv(PK6!H}`1=INmqj8jA>+>CH#4m))Ar6bf|Y_kW5-w;M(HTT?e&)w`P$bW&zf&~kn zU$kh^yf_PA4mm9k2YX*qEYivx4U%qAZ_AvoLSEPiF)pmaOty#|;MoN`e*E~!9GJ_W ztYg+%w@dRup+owo46U4w0ug18%H?e6CYyozyewI3Bf=((!pc5}T{i&|OV|Nrv~8G!%*00v1!K^Ig50B$K^k)i2t Q1poj507*qoM6N<$f^+FhD*ylh delta 1727 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 Rvwr{p002ovPDHLkV1lRs%8dX3 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png index 0b9d9359e3dbcedc1337fce588f4c35b2ea84b33..3774c262317e5d546e6b695fca8c646805efbf24 100644 GIT binary patch literal 10212 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 Z091+02zk3etIsC@83{%4DpBKr{{t0&xI+K{ literal 4339 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 KG-}lBqyGn)&?Wo; diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png index aaa9808d6995beb1a391a35dd8ba72fc5a922ef9..a211290c5d41c4533fa78ae0927249e21902d2a4 100644 GIT binary patch literal 13821 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 UZ+=VB!XXY&SJqOhQm_vFKNIGqH~;_u diff --git a/android/app/src/main2/AndroidManifest.xml b/android/app/src/main2/AndroidManifest.xml new file mode 100644 index 00000000..e07739b9 --- /dev/null +++ b/android/app/src/main2/AndroidManifest.xml @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main2/kotlin/com/ejada/hmg/MainActivity.kt b/android/app/src/main2/kotlin/com/ejada/hmg/MainActivity.kt new file mode 100644 index 00000000..ece584b2 --- /dev/null +++ b/android/app/src/main2/kotlin/com/ejada/hmg/MainActivity.kt @@ -0,0 +1,84 @@ +package com.ejada.hmg + +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.util.Log +import android.view.WindowManager +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.annotation.RequiresApi +import com.ejada.hmg.penguin.PenguinInPlatformBridge +import com.ejada.hmg.watch.huawei.HuaweiWatch +import com.ejada.hmg.watch.huawei.samsung_watch.SamsungWatch +import com.huawei.hms.hihealth.result.HealthKitAuthResult +import com.huawei.hms.support.api.entity.auth.Scope +import io.flutter.embedding.android.FlutterFragmentActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugins.GeneratedPluginRegistrant + + +class MainActivity: FlutterFragmentActivity() { + + private var huaweiWatch : HuaweiWatch? = null + @RequiresApi(Build.VERSION_CODES.O) + override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + GeneratedPluginRegistrant.registerWith(flutterEngine); + // Create Flutter Platform Bridge + this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) + + PenguinInPlatformBridge(flutterEngine, this).create() + SamsungWatch(flutterEngine, this) + huaweiWatch = HuaweiWatch(flutterEngine, this) + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + + val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } + val intent = Intent("PERMISSION_RESULT_ACTION").apply { + putExtra("PERMISSION_GRANTED", granted) + } + sendBroadcast(intent) + + // Log the request code and permission results + Log.d("PermissionsResult", "Request Code: $requestCode") + Log.d("PermissionsResult", "Permissions: ${permissions.joinToString()}") + Log.d("PermissionsResult", "Grant Results: ${grantResults.joinToString()}") + + } + + override fun onResume() { + super.onResume() + } + +// override fun onActivityResult(requestCode: Int, resultCode: Int, @Nullable data: Intent?) { +// super.onActivityResult(requestCode, resultCode, data) +// +// // Process only the response result of the authorization process. +// if (requestCode == 1002) { +// // Obtain the authorization response result from the intent. +// val result: HealthKitAuthResult? = huaweiWatch?.mSettingController?.parseHealthKitAuthResultFromIntent(data) +// if (result == null) { +// Log.w(huaweiWatch?.TAG, "authorization fail") +// return +// } +// +// if (result.isSuccess) { +// Log.i(huaweiWatch?.TAG, "authorization success") +// if (result.getAuthAccount() != null && result.authAccount.authorizedScopes != null) { +// val authorizedScopes: MutableSet = result.authAccount.authorizedScopes +// if(authorizedScopes.isNotEmpty()) { +// huaweiWatch?.getHealthAppAuthorization() +// } +// } +// } else { +// Log.w("MainActivty", "authorization fail, errorCode:" + result.getErrorCode()) +// } +// } +// } +} diff --git a/android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/SamsungWatch.kt b/android/app/src/main2/kotlin/com/ejada/hmg/watch/samsung_watch/SamsungWatch.kt similarity index 100% rename from android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/SamsungWatch.kt rename to android/app/src/main2/kotlin/com/ejada/hmg/watch/samsung_watch/SamsungWatch.kt diff --git a/android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/model/Vitals.kt b/android/app/src/main2/kotlin/com/ejada/hmg/watch/samsung_watch/model/Vitals.kt similarity index 100% rename from android/app/src/main/kotlin/com/ejada/hmg/watch/samsung_watch/model/Vitals.kt rename to android/app/src/main2/kotlin/com/ejada/hmg/watch/samsung_watch/model/Vitals.kt diff --git a/android/app/src/main2/res/drawable-v21/launch_background.xml b/android/app/src/main2/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/android/app/src/main2/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main2/res/drawable/app_icon.png b/android/app/src/main2/res/drawable/app_icon.png new file mode 100755 index 0000000000000000000000000000000000000000..2d394f839a64801254fb2952e2955aa9fea2e81e GIT binary patch literal 2555 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main2/res/drawable/launch_background.xml b/android/app/src/main2/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/android/app/src/main2/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main2/res/drawable/me.png b/android/app/src/main2/res/drawable/me.png new file mode 100644 index 0000000000000000000000000000000000000000..ba75bc55bf4433d4fc364089c7556b6e119da94d GIT binary patch literal 1021 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1CmKZK~!i%?U-Lk zQ&AkpXF^dv^io7%^ks%)nGl7N;X^{GU_t+< zXp}kA{yjw`6(Q+^z9f;lQReyeJ9odq_4-rX+Rhg23m2y{gcaaf?!!d)u5GFrA-%eALPjTV$(F-0@j1 zv=KuSZ^>4jumSCxA4zB$)Pg;?4GUOr*AT9I)1-v*!GJH ztVhm~bGMxBd+qL@*-bX;V=nov-2w#g{-OmH#(+x*#22vafuRcoO)0 z9$*#4h+cSJ^Z5et$2}NyP>kq>J8_LOR{?&Nu2PKX<@N_(a^{K{q!`f)kI*DztcnSW r5xwvT1sP*S1cDSJrIb=)WitH*z#@M?8?WqE00000NkvXXu0mjfQ^nfk literal 0 HcmV?d00001 diff --git a/android/app/src/main2/res/drawable/sample_large_icon.png b/android/app/src/main2/res/drawable/sample_large_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f354ca234d31b0d663336c154933042eb1513bdb GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDB3?!H8JlO)ID|0t=hP86DQPxDme>0B8wRq_>O=u<5X=vX`rBur;B5VMQ?I~ z1nc64qys8qix`vx88%lWJG(G-xJ)(>5=#wWpPX?ZaMQ+xv5YQ@PIt5#v8Xnj2sB7y ZWQg9zdAz9V#xviX literal 0 HcmV?d00001 diff --git a/android/app/src/main2/res/drawable/secondary_icon.png b/android/app/src/main2/res/drawable/secondary_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9de9ff41bdae5d1b3a2bfceb45861d035b8ec7fc GIT binary patch literal 1073 zcmV-11kU@3P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGw)c^n-)dAs~2Fw5e02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;2FkAZe8V00W^(L_t(oN7dI`$WB=p!12!vGfaa-j-!!s zm_mk>V{(i^j-`plG(|3^apzQW;gCe4kPDHBa)DwbB3y8T$eEF2&So5PX8iy4J@xk5 z-@Es_eQD;YUwysbT5GSp*0T<~B1e3Q`S>@*1bmkG&vobv%)reQV^AD5&;>m!|E{*E zg9a(SLSfW|qjn2_VHBz@9Hk#H35&4~YvELm$9E_mffhK8n9}{V&q{m`qdP9Z|386KmpPw&Gb=dn zg&lbghkOqfVtS=zIE;sQiNcN@gD>WE4~1>cMRBfG87AQrJU}$;-#rwk=_P z?S!3=`Zq8VcFNBAj7(vLX>drRF^9PyzCqTgkBM-^q8+z{z9=iY!MCx2w>W@iC=NUB zs#;ztDM1}ESL8{=v>%15E>pOg4#J8yup3F8G0d?wh_@eyqy+UhH^j?`vRhFLsqs5v zN&k(ms4B8{$nf`Ja7(bPNpC)tjK(+*D>yncQ7X#mP{e9Pc}J;aPMQx-Vc}D#Y9&SF z=}<@9hUKrKEfT{exD?U&Z1})Zk*7m-VP0C^Ss0GQIu_go3qHd@q(z<%`TqrQ^;*ZX z(AD};G=fXhLhcoATxpS~Lx!h*Y?yx{aVDDL8Z6}D*$Qcqw?l5Qk*g<=xMRE5M6!7b zyZxs{-VS-{$0^{dPV7(V}v|(6Fbxp-eD}{Nd1Vk$lIac@B-G^ zj>H`L7CT@echR4a7Czkb%PWeSBQ31sxfiFwJS46%d+BnFf{T#(dQe8V*?L&}43CjP zs4|AY^UK06eecHA9lh}wKI1InCYcyco6FF`T7ks*%^8mPHrTei^m?S8_@nU}R&phb zK$b*J3p?YbKT^WBdm%NfxDhc*XW*B^r-U!$i+K-^c0DpOkA6G2TSsL#N-tP>lDsxd zTyxU4oT`1Ohs@zJ^fGl1(J8+YX2E-M)^N99g?|w3IN}{pb{g2JKDdKu>=pdbn~L~c zcGMht`M1BhI{l#ZCE`?fWc)_+ew{lft>`j!--w2T`LGv$LYoguumOiq__ZQ8+AYX( zU}p-iwv!QGB3U^qo>lJR + + + \ No newline at end of file diff --git a/android/app/src/main2/res/layout/local_video.xml b/android/app/src/main2/res/layout/local_video.xml new file mode 100644 index 00000000..f47c48cd --- /dev/null +++ b/android/app/src/main2/res/layout/local_video.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main2/res/layout/remote_video.xml b/android/app/src/main2/res/layout/remote_video.xml new file mode 100644 index 00000000..cfdbeb0d --- /dev/null +++ b/android/app/src/main2/res/layout/remote_video.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main2/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to android/app/src/main2/res/mipmap-hdpi/ic_launcher.png diff --git a/android/app/src/main2/res/mipmap-hdpi/ic_launcher_local.png b/android/app/src/main2/res/mipmap-hdpi/ic_launcher_local.png new file mode 100644 index 0000000000000000000000000000000000000000..348b511670c0e98f244aa2c8337fa3cf0b0ce167 GIT binary patch literal 2350 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 UoY!dqQvd(}07*qoM6N<$f~7q{L;wH) literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main2/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to android/app/src/main2/res/mipmap-mdpi/ic_launcher.png diff --git a/android/app/src/main2/res/mipmap-mdpi/ic_launcher_local.png b/android/app/src/main2/res/mipmap-mdpi/ic_launcher_local.png new file mode 100644 index 0000000000000000000000000000000000000000..410b1b1e59ec6f502163a727e67ceea9a9b48d5a GIT binary patch literal 1742 zcmV;<1~K`GP)JQU@`UB+$CWrw|)I>DV7&Pf0gF)mCLc6oGJKMExcjs|D z=iWQdo!On)7T8X5a<|hv=brD}bI)VW#A4z~*2kYgIw94y6>tP3LyR|@3{w`VF0SG@ zh}0W%Udg)ndul@m{9E779+K+YszrF4>f(lkK(Z*K*4Rn+1}x2!@HlEnDxx&1We3n2 zTsy$2O~d;t$&9l0$MBC6qrOVu;GPnb_&5KD;HNrPA#e!73(7tEN zh?YViVjgobT*w-3g8iv>0#URaC0Li8SWG_?uG zCO!s{`TrU7Ev*G=bXKeVOichUTsLt?14z?bVC?Ww7}>QK61UfLU`|;DfWXC+_1i$% z^c*M~dqH`+1Z~^_%I2MrTKO<8I`8;HLb}>!TVr&;p;b$%YxpOtBr%p%W$pP$+3ZNB| z^Oo8Gbe%02L~M?#va#^%@7#99c`$9B1Q>nyBiGzgJPl1_3K<80WuPa*0pJVjY_4|h z0wfo9a~=&g0O_u|Fm~i?0YEFyj|k_D4}fC_N}3KWrkemR1_Su&8$MstLYa^S0L}8c z0&vdJ&W8gK>P-0o@OZe%2Vm0dfb$GYMgXou-1Fl20hBv*P5>0FZmtQ04#D&Yk~at$IEElD0ZV)hd^Gm zf=A#voqSPL2JJxpyB~_&sPkFhHAY84Ubdz9rd`J$VZBYeS%2xytGC zKcHQ@;<8n*Aj+2KVfdEmObIM8yRD9a(i4))+?-}f=Bi!2#@6CAjQ3>7?tj~rnuIeU zEBTto9+W#*fgHb&Q~OFt&R@o&qmj$GK{(DqX6MVGJoPM3^fqiq?H?D~*NXs;zViVy zJ4&17j#Zqx?&mv+iY%3)$3hhpn21q6ZV}!~Oql_>PY+tTjTc0zgYHZ{)IUx#At_U3 zylE|ys0JugW5hz0bi~9-SZvUt%D%eaWz$X&&U~iFlH++-5piI+cZo)<84ji&=x||>N=%svxz7&y z9AYu%#+YlQnnF)2#co%CRR8>o^GA=z>Sd?1pvth4Lu|(abfYaxA=SMWQW#9+r4O*6 zLT+wk_iI=&6@1Mi|Krb)y7wVSEnkE5Ae;Z+z$eA$#dM?Zf6QDaccCjmZWHbrt3qj7 zb2I>KVk3{l=|?w%cJVUPpf0C4C5dF;KxU5VHR~a9>uj#knG2Z^#8*3eJ~)sOUrb%} zp#%?{7||*4u|QVC&q(M%W@^>xq44Bclc<;WUerAHF4;48qLHP0PVn+$D-8( zVqT`N{{|K`48U@K0F@RreS0bZ(6Yq!TIEIqa1}I>cfdRYp7eL}05D%IRs!Jfvn<`7 zSO9yjF94@2R8NNk5b4EMbT1?T3`-GSEouV5nP33ct3@^Bt3`F3021ZjPJ0)lG=ieI z@5|i}2O^k|F#$VZ1~Sr^rn`2+@6t!Itc2vD-}8DM6Sh?MI?yg$vS09eczStTaiF&p z0H3a;xoG;4O`tr!71EDw0fh*ED^G0Wgmtd6p$C*FdwA`;sgH;J=`E!j99UOVcOZF_q&fi1-TOMU&4~ zcAec~3TX1RM{e?!Dn2-f3Yv%hEmz*;6YYD$^N%VfTXReF8al~h_L<*H4A8d+a&>*B5(ETDcpMM7zgVe{_akNGs{HH# k1s9(dklEla>@(&5AG+f);Av%%d;kCd07*qoM6N<$f-3Vd?*IS* literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main2/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to android/app/src/main2/res/mipmap-xhdpi/ic_launcher.png diff --git a/android/app/src/main2/res/mipmap-xhdpi/ic_launcher_local.png b/android/app/src/main2/res/mipmap-xhdpi/ic_launcher_local.png new file mode 100644 index 0000000000000000000000000000000000000000..bb9943afca7ae877ef9598bcad6e039d5d154378 GIT binary patch literal 3028 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 KG-}lBqyGn)&?Wo; literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main2/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to android/app/src/main2/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/android/app/src/main2/res/mipmap-xxxhdpi/ic_launcher_local.png b/android/app/src/main2/res/mipmap-xxxhdpi/ic_launcher_local.png new file mode 100644 index 0000000000000000000000000000000000000000..aaa9808d6995beb1a391a35dd8ba72fc5a922ef9 GIT binary patch literal 5703 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 UZ+=VB!XXY&SJqOhQm_vFKNIGqH~;_u literal 0 HcmV?d00001 diff --git a/android/app/src/main2/res/raw/keep.xml b/android/app/src/main2/res/raw/keep.xml new file mode 100644 index 00000000..944a7ace --- /dev/null +++ b/android/app/src/main2/res/raw/keep.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/android/app/src/main2/res/raw/slow_spring_board.mp3 b/android/app/src/main2/res/raw/slow_spring_board.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..60dbf9794d2d1270b43308ab84425261ba2f5b19 GIT binary patch literal 37616 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main2/res/values-night/styles.xml b/android/app/src/main2/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/android/app/src/main2/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/main2/res/values/mapbox_access_token.xml b/android/app/src/main2/res/values/mapbox_access_token.xml new file mode 100644 index 00000000..65bc4b37 --- /dev/null +++ b/android/app/src/main2/res/values/mapbox_access_token.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/android/app/src/main2/res/values/strings.xml b/android/app/src/main2/res/values/strings.xml new file mode 100644 index 00000000..2d103337 --- /dev/null +++ b/android/app/src/main2/res/values/strings.xml @@ -0,0 +1,23 @@ + + HMG Patient App + + + Unknown error: the Geofence service is not available now. + + + Geofence service is not available now. Go to Settings>Location>Mode and choose High accuracy. + + + Your app has registered too many geofences. + + + You have provided too many PendingIntents to the addGeofences() call. + + + App do not have permission to access location service. + + + Geofence requests happened too frequently. + + pk.eyJ1IjoicndhaWQiLCJhIjoiY2x5cGo4aHNjMGNsbTJyc2djempobGQxaSJ9.RCaC6WrUt4A4YnZNfxnONQ + diff --git a/android/app/src/main2/res/values/styles.xml b/android/app/src/main2/res/values/styles.xml new file mode 100644 index 00000000..1f83a33f --- /dev/null +++ b/android/app/src/main2/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 00000000..02c8b5da --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,543 @@ +PODS: + - amazon_payfort (1.1.4): + - Flutter + - PayFortSDK + - audio_session (0.0.1): + - Flutter + - barcode_scan2 (0.0.1): + - Flutter + - SwiftProtobuf (~> 1.33) + - connectivity_plus (0.0.1): + - Flutter + - CryptoSwift (1.8.4) + - device_calendar (0.0.1): + - Flutter + - device_calendar_plus_ios (0.0.1): + - Flutter + - device_info_plus (0.0.1): + - Flutter + - DKImagePickerController/Core (4.3.9): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.9) + - DKImagePickerController/PhotoGallery (4.3.9): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.9) + - DKPhotoGallery (0.0.19): + - DKPhotoGallery/Core (= 0.0.19) + - DKPhotoGallery/Model (= 0.0.19) + - DKPhotoGallery/Preview (= 0.0.19) + - DKPhotoGallery/Resource (= 0.0.19) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.19): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.19): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - Firebase/Analytics (11.15.0): + - Firebase/Core + - Firebase/Core (11.15.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 11.15.0) + - Firebase/CoreOnly (11.15.0): + - FirebaseCore (~> 11.15.0) + - Firebase/Messaging (11.15.0): + - Firebase/CoreOnly + - FirebaseMessaging (~> 11.15.0) + - firebase_analytics (11.6.0): + - Firebase/Analytics (= 11.15.0) + - firebase_core + - Flutter + - firebase_core (3.15.2): + - Firebase/CoreOnly (= 11.15.0) + - Flutter + - firebase_messaging (15.2.10): + - Firebase/Messaging (= 11.15.0) + - firebase_core + - Flutter + - FirebaseAnalytics (11.15.0): + - FirebaseAnalytics/Default (= 11.15.0) + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - FirebaseAnalytics/Default (11.15.0): + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleAppMeasurement/Default (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - FirebaseCore (11.15.0): + - FirebaseCoreInternal (~> 11.15.0) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/Logger (~> 8.1) + - FirebaseCoreInternal (11.15.0): + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - FirebaseInstallations (11.15.0): + - FirebaseCore (~> 11.15.0) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/UserDefaults (~> 8.1) + - PromisesObjC (~> 2.4) + - FirebaseMessaging (11.15.0): + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleDataTransport (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/Reachability (~> 8.1) + - GoogleUtilities/UserDefaults (~> 8.1) + - nanopb (~> 3.30910.0) + - FLAnimatedImage (1.0.17) + - Flutter (1.0.0) + - flutter_callkit_incoming (0.0.1): + - CryptoSwift + - Flutter + - flutter_inappwebview_ios (0.0.1): + - Flutter + - flutter_inappwebview_ios/Core (= 0.0.1) + - OrderedSet (~> 6.0.3) + - flutter_inappwebview_ios/Core (0.0.1): + - Flutter + - OrderedSet (~> 6.0.3) + - flutter_ios_voip_kit_karmm (0.8.0): + - Flutter + - flutter_local_notifications (0.0.1): + - Flutter + - flutter_nfc_kit (3.6.0): + - Flutter + - flutter_zoom_videosdk (0.0.1): + - Flutter + - ZoomVideoSDK/CptShare (= 2.1.10) + - ZoomVideoSDK/zm_annoter_dynamic (= 2.1.10) + - ZoomVideoSDK/zoomcml (= 2.1.10) + - ZoomVideoSDK/ZoomVideoSDK (= 2.1.10) + - fluttertoast (0.0.2): + - Flutter + - geolocator_apple (1.2.0): + - Flutter + - FlutterMacOS + - Google-Maps-iOS-Utils (5.0.0): + - GoogleMaps (~> 8.0) + - google_maps_flutter_ios (0.0.1): + - Flutter + - Google-Maps-iOS-Utils (< 7.0, >= 5.0) + - GoogleMaps (< 11.0, >= 8.4) + - GoogleAdsOnDeviceConversion (2.1.0): + - GoogleUtilities/Logger (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/Core (11.15.0): + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/Default (11.15.0): + - GoogleAdsOnDeviceConversion (= 2.1.0) + - GoogleAppMeasurement/Core (= 11.15.0) + - GoogleAppMeasurement/IdentitySupport (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/IdentitySupport (11.15.0): + - GoogleAppMeasurement/Core (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - GoogleDataTransport (10.1.0): + - nanopb (~> 3.30910.0) + - PromisesObjC (~> 2.4) + - GoogleMaps (8.4.0): + - GoogleMaps/Maps (= 8.4.0) + - GoogleMaps/Base (8.4.0) + - GoogleMaps/Maps (8.4.0): + - GoogleMaps/Base + - GoogleUtilities/AppDelegateSwizzler (8.1.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Privacy + - GoogleUtilities/Environment (8.1.0): + - GoogleUtilities/Privacy + - GoogleUtilities/Logger (8.1.0): + - GoogleUtilities/Environment + - GoogleUtilities/Privacy + - GoogleUtilities/MethodSwizzler (8.1.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GoogleUtilities/Network (8.1.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Privacy + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (8.1.0)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (8.1.0) + - GoogleUtilities/Reachability (8.1.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GoogleUtilities/UserDefaults (8.1.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - health (13.1.4): + - Flutter + - image_picker_ios (0.0.1): + - Flutter + - just_audio (0.0.1): + - Flutter + - FlutterMacOS + - local_auth_darwin (0.0.1): + - Flutter + - FlutterMacOS + - location (0.0.1): + - Flutter + - manage_calendar_events (0.0.1): + - Flutter + - map_launcher (0.0.1): + - Flutter + - MapboxCommon (23.11.0) + - MapboxCoreMaps (10.19.1): + - MapboxCommon (~> 23.11) + - MapboxCoreNavigation (2.19.0): + - MapboxDirections (~> 2.14) + - MapboxNavigationNative (< 207.0.0, >= 206.0.1) + - MapboxDirections (2.14.3): + - Polyline (~> 5.0) + - Turf (~> 2.8.0) + - MapboxMaps (10.19.0): + - MapboxCommon (= 23.11.0) + - MapboxCoreMaps (= 10.19.1) + - MapboxMobileEvents (= 2.0.0) + - Turf (= 2.8.0) + - MapboxMobileEvents (2.0.0) + - MapboxNavigation (2.19.0): + - MapboxCoreNavigation (= 2.19.0) + - MapboxMaps (~> 10.18) + - MapboxSpeech (~> 2.0) + - Solar-dev (~> 3.0) + - MapboxNavigationNative (206.2.2): + - MapboxCommon (~> 23.10) + - MapboxSpeech (2.1.1) + - nanopb (3.30910.0): + - nanopb/decode (= 3.30910.0) + - nanopb/encode (= 3.30910.0) + - nanopb/decode (3.30910.0) + - nanopb/encode (3.30910.0) + - network_info_plus (0.0.1): + - Flutter + - open_filex (0.0.2): + - Flutter + - OrderedSet (6.0.3) + - package_info_plus (0.4.5): + - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - PayFortSDK (3.2.1) + - permission_handler_apple (9.3.0): + - Flutter + - Polyline (5.1.0) + - PromisesObjC (2.4.0) + - SDWebImage (5.21.5): + - SDWebImage/Core (= 5.21.5) + - SDWebImage/Core (5.21.5) + - share_plus (0.0.1): + - Flutter + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - Solar-dev (3.0.1) + - sqflite_darwin (0.0.4): + - Flutter + - FlutterMacOS + - SwiftProtobuf (1.33.3) + - SwiftyGif (5.4.5) + - Turf (2.8.0) + - url_launcher_ios (0.0.1): + - Flutter + - video_player_avfoundation (0.0.1): + - Flutter + - FlutterMacOS + - wakelock_plus (0.0.1): + - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter + - FlutterMacOS + - ZoomVideoSDK/CptShare (2.1.10) + - ZoomVideoSDK/zm_annoter_dynamic (2.1.10) + - ZoomVideoSDK/zoomcml (2.1.10) + - ZoomVideoSDK/ZoomVideoSDK (2.1.10) + +DEPENDENCIES: + - amazon_payfort (from `.symlinks/plugins/amazon_payfort/ios`) + - audio_session (from `.symlinks/plugins/audio_session/ios`) + - barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`) + - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) + - device_calendar (from `.symlinks/plugins/device_calendar/ios`) + - device_calendar_plus_ios (from `.symlinks/plugins/device_calendar_plus_ios/ios`) + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) + - FLAnimatedImage + - Flutter (from `Flutter`) + - flutter_callkit_incoming (from `.symlinks/plugins/flutter_callkit_incoming/ios`) + - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) + - flutter_ios_voip_kit_karmm (from `.symlinks/plugins/flutter_ios_voip_kit_karmm/ios`) + - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) + - flutter_nfc_kit (from `.symlinks/plugins/flutter_nfc_kit/ios`) + - flutter_zoom_videosdk (from `.symlinks/plugins/flutter_zoom_videosdk/ios`) + - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) + - google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`) + - health (from `.symlinks/plugins/health/ios`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - just_audio (from `.symlinks/plugins/just_audio/darwin`) + - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`) + - location (from `.symlinks/plugins/location/ios`) + - manage_calendar_events (from `.symlinks/plugins/manage_calendar_events/ios`) + - map_launcher (from `.symlinks/plugins/map_launcher/ios`) + - MapboxMaps (= 10.19.0) + - MapboxNavigation (= 2.19.0) + - network_info_plus (from `.symlinks/plugins/network_info_plus/ios`) + - open_filex (from `.symlinks/plugins/open_filex/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + - share_plus (from `.symlinks/plugins/share_plus/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) + - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) + +SPEC REPOS: + trunk: + - CryptoSwift + - DKImagePickerController + - DKPhotoGallery + - Firebase + - FirebaseAnalytics + - FirebaseCore + - FirebaseCoreInternal + - FirebaseInstallations + - FirebaseMessaging + - FLAnimatedImage + - Google-Maps-iOS-Utils + - GoogleAdsOnDeviceConversion + - GoogleAppMeasurement + - GoogleDataTransport + - GoogleMaps + - GoogleUtilities + - MapboxCommon + - MapboxCoreMaps + - MapboxCoreNavigation + - MapboxDirections + - MapboxMaps + - MapboxMobileEvents + - MapboxNavigation + - MapboxNavigationNative + - MapboxSpeech + - nanopb + - OrderedSet + - PayFortSDK + - Polyline + - PromisesObjC + - SDWebImage + - Solar-dev + - SwiftProtobuf + - SwiftyGif + - Turf + - ZoomVideoSDK + +EXTERNAL SOURCES: + amazon_payfort: + :path: ".symlinks/plugins/amazon_payfort/ios" + audio_session: + :path: ".symlinks/plugins/audio_session/ios" + barcode_scan2: + :path: ".symlinks/plugins/barcode_scan2/ios" + connectivity_plus: + :path: ".symlinks/plugins/connectivity_plus/ios" + device_calendar: + :path: ".symlinks/plugins/device_calendar/ios" + device_calendar_plus_ios: + :path: ".symlinks/plugins/device_calendar_plus_ios/ios" + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + firebase_analytics: + :path: ".symlinks/plugins/firebase_analytics/ios" + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_messaging: + :path: ".symlinks/plugins/firebase_messaging/ios" + Flutter: + :path: Flutter + flutter_callkit_incoming: + :path: ".symlinks/plugins/flutter_callkit_incoming/ios" + flutter_inappwebview_ios: + :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" + flutter_ios_voip_kit_karmm: + :path: ".symlinks/plugins/flutter_ios_voip_kit_karmm/ios" + flutter_local_notifications: + :path: ".symlinks/plugins/flutter_local_notifications/ios" + flutter_nfc_kit: + :path: ".symlinks/plugins/flutter_nfc_kit/ios" + flutter_zoom_videosdk: + :path: ".symlinks/plugins/flutter_zoom_videosdk/ios" + fluttertoast: + :path: ".symlinks/plugins/fluttertoast/ios" + geolocator_apple: + :path: ".symlinks/plugins/geolocator_apple/darwin" + google_maps_flutter_ios: + :path: ".symlinks/plugins/google_maps_flutter_ios/ios" + health: + :path: ".symlinks/plugins/health/ios" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" + just_audio: + :path: ".symlinks/plugins/just_audio/darwin" + local_auth_darwin: + :path: ".symlinks/plugins/local_auth_darwin/darwin" + location: + :path: ".symlinks/plugins/location/ios" + manage_calendar_events: + :path: ".symlinks/plugins/manage_calendar_events/ios" + map_launcher: + :path: ".symlinks/plugins/map_launcher/ios" + network_info_plus: + :path: ".symlinks/plugins/network_info_plus/ios" + open_filex: + :path: ".symlinks/plugins/open_filex/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + permission_handler_apple: + :path: ".symlinks/plugins/permission_handler_apple/ios" + share_plus: + :path: ".symlinks/plugins/share_plus/ios" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + sqflite_darwin: + :path: ".symlinks/plugins/sqflite_darwin/darwin" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + video_player_avfoundation: + :path: ".symlinks/plugins/video_player_avfoundation/darwin" + wakelock_plus: + :path: ".symlinks/plugins/wakelock_plus/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" + +SPEC CHECKSUMS: + amazon_payfort: 4ad7a3413acc1c4c4022117a80d18fee23c572d3 + audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0 + barcode_scan2: 4e4b850b112f4e29017833e4715f36161f987966 + connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd + CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90 + device_calendar: b55b2c5406cfba45c95a59f9059156daee1f74ed + device_calendar_plus_ios: 2c04ad7643c6e697438216e33693b84e8ca45ded + device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe + DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c + DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 + file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be + Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e + firebase_analytics: 0e25ca1d4001ccedd40b4e5b74c0ec34e18f6425 + firebase_core: 995454a784ff288be5689b796deb9e9fa3601818 + firebase_messaging: f4a41dd102ac18b840eba3f39d67e77922d3f707 + FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae + FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e + FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 + FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 + FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 + FLAnimatedImage: bbf914596368867157cc71b38a8ec834b3eeb32b + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + flutter_callkit_incoming: cb8138af67cda6dd981f7101a5d709003af21502 + flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 + flutter_ios_voip_kit_karmm: 371663476722afb631d5a13a39dee74c56c1abd0 + flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb + flutter_nfc_kit: e1b71583eafd2c9650bc86844a7f2d185fb414f6 + flutter_zoom_videosdk: 0f59e71685a03ddb0783ecc43bf3155b8599a7f5 + fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1 + geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e + Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321 + google_maps_flutter_ios: 3213e1e5f5588b6134935cb8fc59acb4e6d88377 + GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64 + GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539 + GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 + GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d + GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 + health: 32d2fbc7f26f9a2388d1a514ce168adbfa5bda65 + image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 + just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed + local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb + location: 155caecf9da4f280ab5fe4a55f94ceccfab838f8 + manage_calendar_events: fe1541069431af035ced925ebd9def8b4b271254 + map_launcher: 8051ad5783913cafce93f2414c6858f2904fd8df + MapboxCommon: 119f3759f7dc9457f0695848108ab323eb643cb4 + MapboxCoreMaps: ca17f67baced23f8c952166ac6314c35bad3f66c + MapboxCoreNavigation: 3be9990fae3ed732a101001746d0e3b4234ec023 + MapboxDirections: d9ad8452e8927d95ed21e35f733834dbca7e0eb1 + MapboxMaps: b7f29ec7c33f7dc6d2947c1148edce6db81db9a7 + MapboxMobileEvents: d044b9edbe0ec7df60f6c2c9634fe9a7f449266b + MapboxNavigation: da9cf3d773ed5b0fa0fb388fccdaa117ee681f31 + MapboxNavigationNative: 629e359f3d2590acd1ebbacaaf99e1a80ee57e42 + MapboxSpeech: cd25ef99c3a3d2e0da72620ff558276ea5991a77 + nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 + network_info_plus: cf61925ab5205dce05a4f0895989afdb6aade5fc + open_filex: 432f3cd11432da3e39f47fcc0df2b1603854eff1 + OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 + PayFortSDK: 233eabe9a45601fdbeac67fa6e5aae46ed8faf82 + permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d + Polyline: 2a1f29f87f8d9b7de868940f4f76deb8c678a5b1 + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838 + share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a + shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb + Solar-dev: 4612dc9878b9fed2667d23b327f1d4e54e16e8d0 + sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 + SwiftProtobuf: e1b437c8e31a4c5577b643249a0bb62ed4f02153 + SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 + Turf: aa2ede4298009639d10db36aba1a7ebaad072a5e + url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b + video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a + wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 + webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d + ZoomVideoSDK: 94e939820e57a075c5e712559f927017da0de06a + +PODFILE CHECKSUM: 8235407385ddd5904afc2563d65406117a51993e + +COCOAPODS: 1.16.2 diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 00000000..8395a120 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,2097 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 + url: "https://pub.dev" + source: hosted + version: "1.3.59" + adaptive_number: + dependency: transitive + description: + name: adaptive_number + sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + amazon_payfort: + dependency: "direct main" + description: + name: amazon_payfort + sha256: "7732df0764aecbb814f910db36d0dca2f696e7e5ea380b49aa3ec62965768b33" + url: "https://pub.dev" + source: hosted + version: "1.1.4" + archive: + dependency: transitive + description: + name: archive + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + url: "https://pub.dev" + source: hosted + version: "4.0.7" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + audio_session: + dependency: transitive + description: + name: audio_session + sha256: "8f96a7fecbb718cb093070f868b4cdcb8a9b1053dce342ff8ab2fde10eb9afb7" + url: "https://pub.dev" + source: hosted + version: "0.2.2" + auto_size_text: + dependency: "direct main" + description: + name: auto_size_text + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + barcode_scan2: + dependency: "direct main" + description: + name: barcode_scan2 + sha256: "9b539b0ce419005c451de66374c79f39801986f1fd7a213e63d948f21487cd69" + url: "https://pub.dev" + source: hosted + version: "4.7.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + carp_serializable: + dependency: transitive + description: + name: carp_serializable + sha256: f039f8ea22e9437aef13fe7e9743c3761c76d401288dcb702eadd273c3e4dcef + url: "https://pub.dev" + source: hosted + version: "2.0.1" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + chewie: + dependency: transitive + description: + name: chewie + sha256: "44bcfc5f0dfd1de290c87c9d86a61308b3282a70b63435d5557cfd60f54a69ca" + url: "https://pub.dev" + source: hosted + version: "1.13.0" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + connectivity_plus: + dependency: "direct main" + description: + name: connectivity_plus + sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec + url: "https://pub.dev" + source: hosted + version: "6.1.5" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "701dcfc06da0882883a2657c445103380e53e647060ad8d9dfb710c100996608" + url: "https://pub.dev" + source: hosted + version: "0.3.5+1" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + dart_jsonwebtoken: + dependency: "direct main" + description: + name: dart_jsonwebtoken + sha256: "0de65691c1d736e9459f22f654ddd6fd8368a271d4e41aa07e53e6301eff5075" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + dartz: + dependency: "direct main" + description: + name: dartz + sha256: e6acf34ad2e31b1eb00948692468c30ab48ac8250e0f0df661e29f12dd252168 + url: "https://pub.dev" + source: hosted + version: "0.10.1" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" + device_calendar: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: "5ea5ed9e2bb499c0633383b53103f2920b634755" + url: "https://github.com/bardram/device_calendar" + source: git + version: "4.3.1" + device_calendar_plus: + dependency: "direct main" + description: + name: device_calendar_plus + sha256: d11a70d98eb123e8eb09fdcfaf220ca4f1aa65a1512e12092f176f4b54983507 + url: "https://pub.dev" + source: hosted + version: "0.3.3" + device_calendar_plus_android: + dependency: transitive + description: + name: device_calendar_plus_android + sha256: a341ef29fa0251251287d63c1d009dfd35c1459dc6a129fd5e03f5ac92d8d7ff + url: "https://pub.dev" + source: hosted + version: "0.3.3" + device_calendar_plus_ios: + dependency: transitive + description: + name: device_calendar_plus_ios + sha256: "3b2f84ce1ed002be8460e214a3229e66748bbaad4077603f2c734d67c42033ff" + url: "https://pub.dev" + source: hosted + version: "0.3.3" + device_calendar_plus_platform_interface: + dependency: transitive + description: + name: device_calendar_plus_platform_interface + sha256: "0ce7511c094ca256831a48e16efe8f1e97e7bd00a5ff3936296ffd650a1d76b5" + url: "https://pub.dev" + source: hosted + version: "0.3.3" + device_info_plus: + dependency: "direct main" + description: + name: device_info_plus + sha256: "98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a" + url: "https://pub.dev" + source: hosted + version: "11.5.0" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f + url: "https://pub.dev" + source: hosted + version: "7.0.3" + dropdown_search: + dependency: "direct main" + description: + name: dropdown_search + sha256: c29b3e5147a82a06a4a08b3b574c51cb48cc17ad89893d53ee72a6f86643622e + url: "https://pub.dev" + source: hosted + version: "6.0.2" + easy_localization: + dependency: "direct main" + description: + name: easy_localization + sha256: "2ccdf9db8fe4d9c5a75c122e6275674508fd0f0d49c827354967b8afcc56bbed" + url: "https://pub.dev" + source: hosted + version: "3.0.8" + easy_logger: + dependency: transitive + description: + name: easy_logger + sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7 + url: "https://pub.dev" + source: hosted + version: "0.0.2" + ed25519_edwards: + dependency: transitive + description: + name: ed25519_edwards + sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + equatable: + dependency: "direct main" + description: + name: equatable + sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" + url: "https://pub.dev" + source: hosted + version: "2.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c + url: "https://pub.dev" + source: hosted + version: "2.1.5" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: d974b6ba2606371ac71dd94254beefb6fa81185bde0b59bdc1df09885da85fde + url: "https://pub.dev" + source: hosted + version: "10.3.8" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" + url: "https://pub.dev" + source: hosted + version: "0.9.4" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" + url: "https://pub.dev" + source: hosted + version: "0.9.5" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" + url: "https://pub.dev" + source: hosted + version: "2.7.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" + url: "https://pub.dev" + source: hosted + version: "0.9.3+5" + firebase_analytics: + dependency: "direct main" + description: + name: firebase_analytics + sha256: "4f85b161772e1d54a66893ef131c0a44bd9e552efa78b33d5f4f60d2caa5c8a3" + url: "https://pub.dev" + source: hosted + version: "11.6.0" + firebase_analytics_platform_interface: + dependency: transitive + description: + name: firebase_analytics_platform_interface + sha256: a44b6d1155ed5cae7641e3de7163111cfd9f6f6c954ca916dc6a3bdfa86bf845 + url: "https://pub.dev" + source: hosted + version: "4.4.3" + firebase_analytics_web: + dependency: transitive + description: + name: firebase_analytics_web + sha256: c7d1ed1f86ae64215757518af5576ff88341c8ce5741988c05cc3b2e07b0b273 + url: "https://pub.dev" + source: hosted + version: "0.5.10+16" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" + url: "https://pub.dev" + source: hosted + version: "3.15.2" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: cccb4f572325dc14904c02fcc7db6323ad62ba02536833dddb5c02cac7341c64 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" + url: "https://pub.dev" + source: hosted + version: "2.24.1" + firebase_crashlytics: + dependency: "direct main" + description: + name: firebase_crashlytics + sha256: "662ae6443da91bca1fb0be8aeeac026fa2975e8b7ddfca36e4d90ebafa35dde1" + url: "https://pub.dev" + source: hosted + version: "4.3.10" + firebase_crashlytics_platform_interface: + dependency: transitive + description: + name: firebase_crashlytics_platform_interface + sha256: "7222a8a40077c79f6b8b3f3439241c9f2b34e9ddfde8381ffc512f7b2e61f7eb" + url: "https://pub.dev" + source: hosted + version: "3.8.10" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "60be38574f8b5658e2f22b7e311ff2064bea835c248424a383783464e8e02fcc" + url: "https://pub.dev" + source: hosted + version: "15.2.10" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: "685e1771b3d1f9c8502771ccc9f91485b376ffe16d553533f335b9183ea99754" + url: "https://pub.dev" + source: hosted + version: "4.6.10" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: "0d1be17bc89ed3ff5001789c92df678b2e963a51b6fa2bdb467532cc9dbed390" + url: "https://pub.dev" + source: hosted + version: "3.10.10" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + fl_chart: + dependency: "direct main" + description: + name: fl_chart + sha256: "577aeac8ca414c25333334d7c4bb246775234c0e44b38b10a82b559dd4d764e7" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + flutter_callkit_incoming: + dependency: "direct main" + description: + name: flutter_callkit_incoming + sha256: "3589deb8b71e43f2d520a9c8a5240243f611062a8b246cdca4b1fda01fbbf9b8" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + flutter_hooks: + dependency: transitive + description: + name: flutter_hooks + sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70 + url: "https://pub.dev" + source: hosted + version: "0.20.5" + flutter_inappwebview: + dependency: "direct main" + description: + name: flutter_inappwebview + sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" + url: "https://pub.dev" + source: hosted + version: "6.1.5" + flutter_inappwebview_android: + dependency: transitive + description: + name: flutter_inappwebview_android + sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + flutter_inappwebview_internal_annotations: + dependency: transitive + description: + name: flutter_inappwebview_internal_annotations + sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + flutter_inappwebview_ios: + dependency: transitive + description: + name: flutter_inappwebview_ios + sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_macos: + dependency: transitive + description: + name: flutter_inappwebview_macos + sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + name: flutter_inappwebview_platform_interface + sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 + url: "https://pub.dev" + source: hosted + version: "1.3.0+1" + flutter_inappwebview_web: + dependency: transitive + description: + name: flutter_inappwebview_web + sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_windows: + dependency: transitive + description: + name: flutter_inappwebview_windows + sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + flutter_ios_voip_kit_karmm: + dependency: "direct main" + description: + name: flutter_ios_voip_kit_karmm + sha256: "31a445d78aacacdf128a0354efb9f4e424285dfe4c0af3ea872e64f03e6f6bfc" + url: "https://pub.dev" + source: hosted + version: "0.8.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: "19ffb0a8bb7407875555e5e98d7343a633bb73707bae6c6a5f37c90014077875" + url: "https://pub.dev" + source: hosted + version: "19.5.0" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: e3c277b2daab8e36ac5a6820536668d07e83851aeeb79c446e525a70710770a5 + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe" + url: "https://pub.dev" + source: hosted + version: "9.1.0" + flutter_local_notifications_windows: + dependency: transitive + description: + name: flutter_local_notifications_windows + sha256: "8d658f0d367c48bd420e7cf2d26655e2d1130147bca1eea917e576ca76668aaf" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_nfc_kit: + dependency: "direct main" + description: + name: flutter_nfc_kit + sha256: "3cf589592373f1d0b0bd9583532368bb85e7cd76ae014a2b67a5ab2d68ae9450" + url: "https://pub.dev" + source: hosted + version: "3.6.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1 + url: "https://pub.dev" + source: hosted + version: "2.0.33" + flutter_rating_bar: + dependency: "direct main" + description: + name: flutter_rating_bar + sha256: d2af03469eac832c591a1eba47c91ecc871fe5708e69967073c043b2d775ed93 + url: "https://pub.dev" + source: hosted + version: "4.0.1" + flutter_staggered_animations: + dependency: "direct main" + description: + name: flutter_staggered_animations + sha256: "81d3c816c9bb0dca9e8a5d5454610e21ffb068aedb2bde49d2f8d04f75538351" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + flutter_swiper_view: + dependency: "direct main" + description: + name: flutter_swiper_view + sha256: "2a165b259e8a4c49d4da5626b967ed42a73dac2d075bd9e266ad8d23b9f01879" + url: "https://pub.dev" + source: hosted + version: "1.1.8" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_widget_from_html: + dependency: "direct main" + description: + name: flutter_widget_from_html + sha256: "7f1daefcd3009c43c7e7fb37501e6bb752d79aa7bfad0085fb0444da14e89bd0" + url: "https://pub.dev" + source: hosted + version: "0.17.1" + flutter_widget_from_html_core: + dependency: transitive + description: + name: flutter_widget_from_html_core + sha256: "1120ee6ed3509ceff2d55aa6c6cbc7b6b1291434422de2411b5a59364dd6ff03" + url: "https://pub.dev" + source: hosted + version: "0.17.0" + flutter_zoom_videosdk: + dependency: "direct main" + description: + name: flutter_zoom_videosdk + sha256: "46a4dea664b1c969099328a499c198a1755adf9ac333dea28bea5187910b3bf9" + url: "https://pub.dev" + source: hosted + version: "2.1.10" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: "90778fe0497fe3a09166e8cf2e0867310ff434b794526589e77ec03cf08ba8e8" + url: "https://pub.dev" + source: hosted + version: "8.2.14" + fwfh_cached_network_image: + dependency: transitive + description: + name: fwfh_cached_network_image + sha256: "484cb5f8047f02cfac0654fca5832bfa91bb715fd7fc651c04eb7454187c4af8" + url: "https://pub.dev" + source: hosted + version: "0.16.1" + fwfh_chewie: + dependency: transitive + description: + name: fwfh_chewie + sha256: ae74fc26798b0e74f3983f7b851e74c63b9eeb2d3015ecd4b829096b2c3f8818 + url: "https://pub.dev" + source: hosted + version: "0.16.1" + fwfh_just_audio: + dependency: transitive + description: + name: fwfh_just_audio + sha256: dfd622a0dfe049ac647423a2a8afa7f057d9b2b93d92710b624e3d370b1ac69a + url: "https://pub.dev" + source: hosted + version: "0.17.0" + fwfh_svg: + dependency: transitive + description: + name: fwfh_svg + sha256: "2e6bb241179eeeb1a7941e05c8c923b05d332d36a9085233e7bf110ea7deb915" + url: "https://pub.dev" + source: hosted + version: "0.16.1" + fwfh_url_launcher: + dependency: transitive + description: + name: fwfh_url_launcher + sha256: c38aa8fb373fda3a89b951fa260b539f623f6edb45eee7874cb8b492471af881 + url: "https://pub.dev" + source: hosted + version: "0.16.1" + fwfh_webview: + dependency: transitive + description: + name: fwfh_webview + sha256: f71b0aa16e15d82f3c017f33560201ff5ae04e91e970cab5d12d3bcf970b870c + url: "https://pub.dev" + source: hosted + version: "0.15.6" + geoclue: + dependency: transitive + description: + name: geoclue + sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f + url: "https://pub.dev" + source: hosted + version: "0.1.1" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "79939537046c9025be47ec645f35c8090ecadb6fe98eba146a0d25e8c1357516" + url: "https://pub.dev" + source: hosted + version: "14.0.2" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: "179c3cb66dfa674fc9ccbf2be872a02658724d1c067634e2c427cf6df7df901a" + url: "https://pub.dev" + source: hosted + version: "5.0.2" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 + url: "https://pub.dev" + source: hosted + version: "2.3.13" + geolocator_linux: + dependency: transitive + description: + name: geolocator_linux + sha256: d64112a205931926f4363bb6bd48f14cb38e7326833041d170615586cd143797 + url: "https://pub.dev" + source: hosted + version: "0.2.4" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" + url: "https://pub.dev" + source: hosted + version: "4.2.6" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 + url: "https://pub.dev" + source: hosted + version: "4.1.3" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" + url: "https://pub.dev" + source: hosted + version: "0.2.5" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: ae78de7c3f2304b8d81f2bb6e320833e5e81de942188542328f074978cc0efa9 + url: "https://pub.dev" + source: hosted + version: "8.3.0" + gms_check: + dependency: "direct main" + description: + name: gms_check + sha256: b3fc08fd41da233f9761f9981303346aa9778b4802e90ce9bd8122674fcca6f0 + url: "https://pub.dev" + source: hosted + version: "1.0.4" + google_api_availability: + dependency: "direct main" + description: + name: google_api_availability + sha256: "2ffdc91e1e0cf4e7974fef6c2988a24cefa81f03526ff04b694df6dc0fcbca03" + url: "https://pub.dev" + source: hosted + version: "5.0.1" + google_api_availability_android: + dependency: transitive + description: + name: google_api_availability_android + sha256: "4794147f43a8f3eee6b514d3ae30dbe6f7b9048cae8cd2a74cb4055cd28d74a8" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + google_api_availability_platform_interface: + dependency: transitive + description: + name: google_api_availability_platform_interface + sha256: "65b7da62fe5b582bb3d508628ad827d36d890710ea274766a992a56fa5420da6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + google_maps: + dependency: transitive + description: + name: google_maps + sha256: "5d410c32112d7c6eb7858d359275b2aa04778eed3e36c745aeae905fb2fa6468" + url: "https://pub.dev" + source: hosted + version: "8.2.0" + google_maps_flutter: + dependency: "direct main" + description: + name: google_maps_flutter + sha256: "819985697596a42e1054b5feb2f407ba1ac92262e02844a40168e742b9f36dca" + url: "https://pub.dev" + source: hosted + version: "2.14.0" + google_maps_flutter_android: + dependency: transitive + description: + name: google_maps_flutter_android + sha256: "6dbbfc697eedd29c3634affb2d6b3e5ecfc4e6e50c8345f4b975cc969c74b582" + url: "https://pub.dev" + source: hosted + version: "2.18.9" + google_maps_flutter_ios: + dependency: transitive + description: + name: google_maps_flutter_ios + sha256: b3f9aa62f65f7f266651e156a910ce88b8158de6546c6b145c9ba8080eb861b3 + url: "https://pub.dev" + source: hosted + version: "2.16.1" + google_maps_flutter_platform_interface: + dependency: transitive + description: + name: google_maps_flutter_platform_interface + sha256: e8b1232419fcdd35c1fdafff96843f5a40238480365599d8ca661dde96d283dd + url: "https://pub.dev" + source: hosted + version: "2.14.1" + google_maps_flutter_web: + dependency: transitive + description: + name: google_maps_flutter_web + sha256: d416602944e1859f3cbbaa53e34785c223fa0a11eddb34a913c964c5cbb5d8cf + url: "https://pub.dev" + source: hosted + version: "0.5.14+3" + gsettings: + dependency: transitive + description: + name: gsettings + sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" + url: "https://pub.dev" + source: hosted + version: "0.2.8" + health: + dependency: "direct main" + description: + name: health + sha256: "320633022fb2423178baa66508001c4ca5aee5806ffa2c913e66488081e9fd47" + url: "https://pub.dev" + source: hosted + version: "13.1.4" + hijri_gregorian_calendar: + dependency: "direct main" + description: + name: hijri_gregorian_calendar + sha256: aecdbe3c9365fac55f17b5e1f24086a81999b1e5c9372cb08888bfbe61e07fa1 + url: "https://pub.dev" + source: hosted + version: "0.1.1" + html: + dependency: transitive + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" + http: + dependency: "direct main" + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + huawei_health: + dependency: "direct main" + description: + name: huawei_health + sha256: "52fb9990e1fc857e2fa1b1251dde63b2146086a13b2d9c50bdfc3c4f715c8a12" + url: "https://pub.dev" + source: hosted + version: "6.16.0+300" + huawei_location: + dependency: "direct main" + description: + name: huawei_location + sha256: dd939b0add3e228865cb7da230d7723551e55677d7d59de7dbfd466229847b9f + url: "https://pub.dev" + source: hosted + version: "6.16.0+300" + huawei_map: + dependency: "direct main" + description: + path: flutter-hms-map + ref: HEAD + resolved-ref: "9a16541e4016e3bf58a2571e6aa658a4751af399" + url: "https://github.com/fleoparra/hms-flutter-plugin.git" + source: git + version: "6.11.2+303" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "5e9bf126c37c117cf8094215373c6d561117a3cfb50ebc5add1a61dc6e224677" + url: "https://pub.dev" + source: hosted + version: "0.8.13+10" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "956c16a42c0c708f914021666ffcd8265dde36e673c9fa68c81f7d085d9774ad" + url: "https://pub.dev" + source: hosted + version: "0.8.13+3" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" + url: "https://pub.dev" + source: hosted + version: "0.2.2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" + url: "https://pub.dev" + source: hosted + version: "0.2.2+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" + url: "https://pub.dev" + source: hosted + version: "2.11.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae + url: "https://pub.dev" + source: hosted + version: "0.2.2" + in_app_update: + dependency: "direct main" + description: + name: in_app_update + sha256: "9924a3efe592e1c0ec89dda3683b3cfec3d4cd02d908e6de00c24b759038ddb1" + url: "https://pub.dev" + source: hosted + version: "4.2.5" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + jiffy: + dependency: "direct main" + description: + name: jiffy + sha256: e6f3b2aaec032f95ae917268edcbf007a5b834b57a602d39eb0ab17995a9c64a + url: "https://pub.dev" + source: hosted + version: "6.4.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + just_audio: + dependency: "direct main" + description: + name: just_audio + sha256: "9694e4734f515f2a052493d1d7e0d6de219ee0427c7c29492e246ff32a219908" + url: "https://pub.dev" + source: hosted + version: "0.10.5" + just_audio_platform_interface: + dependency: transitive + description: + name: just_audio_platform_interface + sha256: "2532c8d6702528824445921c5ff10548b518b13f808c2e34c2fd54793b999a6a" + url: "https://pub.dev" + source: hosted + version: "4.6.0" + just_audio_web: + dependency: transitive + description: + name: just_audio_web + sha256: "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663" + url: "https://pub.dev" + source: hosted + version: "0.4.16" + keyboard_actions: + dependency: "direct main" + description: + name: keyboard_actions + sha256: "5155a158c0d22c3a2f4a2192040445fe84977620cf0eeb29f6148a1dcb5835fa" + url: "https://pub.dev" + source: hosted + version: "4.2.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + lints: + dependency: transitive + description: + name: lints + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + url: "https://pub.dev" + source: hosted + version: "5.1.1" + local_auth: + dependency: "direct main" + description: + name: local_auth + sha256: "434d854cf478f17f12ab29a76a02b3067f86a63a6d6c4eb8fbfdcfe4879c1b7b" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + local_auth_android: + dependency: transitive + description: + name: local_auth_android + sha256: a0bdfcc0607050a26ef5b31d6b4b254581c3d3ce3c1816ab4d4f4a9173e84467 + url: "https://pub.dev" + source: hosted + version: "1.0.56" + local_auth_darwin: + dependency: transitive + description: + name: local_auth_darwin + sha256: "699873970067a40ef2f2c09b4c72eb1cfef64224ef041b3df9fdc5c4c1f91f49" + url: "https://pub.dev" + source: hosted + version: "1.6.1" + local_auth_platform_interface: + dependency: transitive + description: + name: local_auth_platform_interface + sha256: f98b8e388588583d3f781f6806e4f4c9f9e189d898d27f0c249b93a1973dd122 + url: "https://pub.dev" + source: hosted + version: "1.1.0" + local_auth_windows: + dependency: transitive + description: + name: local_auth_windows + sha256: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5 + url: "https://pub.dev" + source: hosted + version: "1.0.11" + location: + dependency: "direct main" + description: + name: location + sha256: b080053c181c7d152c43dd576eec6436c40e25f326933051c330da563ddd5333 + url: "https://pub.dev" + source: hosted + version: "8.0.1" + location_platform_interface: + dependency: transitive + description: + name: location_platform_interface + sha256: ca8700bb3f6b1e8b2afbd86bd78b2280d116c613ca7bfa1d4d7b64eba357d749 + url: "https://pub.dev" + source: hosted + version: "6.0.1" + location_web: + dependency: transitive + description: + name: location_web + sha256: b8e3add5efe0d65c5e692b7a135d80a4015c580d3ea646fa71973e97668dd868 + url: "https://pub.dev" + source: hosted + version: "6.0.1" + logger: + dependency: "direct main" + description: + name: logger + sha256: a7967e31b703831a893bbc3c3dd11db08126fe5f369b5c648a36f821979f5be3 + url: "https://pub.dev" + source: hosted + version: "2.6.2" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + lottie: + dependency: "direct main" + description: + name: lottie + sha256: "8ae0be46dbd9e19641791dc12ee480d34e1fd3f84c749adc05f3ad9342b71b95" + url: "https://pub.dev" + source: hosted + version: "3.3.2" + manage_calendar_events: + dependency: "direct main" + description: + name: manage_calendar_events + sha256: f17600fcb7dc7047120c185993045e493d686930237b4e3c2689c26a64513d66 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + map_launcher: + dependency: "direct main" + description: + name: map_launcher + sha256: "85ae218777b79c830477ed59d97f5ee9d6025b00c47b05d0b901f4dd7d2297cc" + url: "https://pub.dev" + source: hosted + version: "4.4.3" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + ndef: + dependency: transitive + description: + name: ndef + sha256: "198ba3798e80cea381648569d84059dbba64cd140079fb7b0d9c3f1e0f5973f3" + url: "https://pub.dev" + source: hosted + version: "0.4.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + network_info_plus: + dependency: "direct main" + description: + name: network_info_plus + sha256: f926b2ba86aa0086a0dfbb9e5072089bc213d854135c1712f1d29fc89ba3c877 + url: "https://pub.dev" + source: hosted + version: "6.1.4" + network_info_plus_platform_interface: + dependency: transitive + description: + name: network_info_plus_platform_interface + sha256: "7e7496a8a9d8136859b8881affc613c4a21304afeb6c324bcefc4bd0aff6b94b" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + open_filex: + dependency: "direct main" + description: + name: open_filex + sha256: "9976da61b6a72302cf3b1efbce259200cd40232643a467aac7370addf94d6900" + url: "https://pub.dev" + source: hosted + version: "4.7.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d + url: "https://pub.dev" + source: hosted + version: "9.0.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e + url: "https://pub.dev" + source: hosted + version: "2.2.22" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" + url: "https://pub.dev" + source: hosted + version: "2.5.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1 + url: "https://pub.dev" + source: hosted + version: "12.0.1" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: "1e3bc410ca1bf84662104b100eb126e066cb55791b7451307f9708d4007350e6" + url: "https://pub.dev" + source: hosted + version: "13.0.1" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + url: "https://pub.dev" + source: hosted + version: "9.4.7" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" + url: "https://pub.dev" + source: hosted + version: "0.1.3+5" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 + url: "https://pub.dev" + source: hosted + version: "4.3.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + url: "https://pub.dev" + source: hosted + version: "7.0.1" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + posix: + dependency: transitive + description: + name: posix + sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + url: "https://pub.dev" + source: hosted + version: "6.0.3" + protobuf: + dependency: transitive + description: + name: protobuf + sha256: "75ec242d22e950bdcc79ee38dd520ce4ee0bc491d7fadc4ea47694604d22bf06" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + provider: + dependency: "direct main" + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" + quiver: + dependency: transitive + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + rrule: + dependency: transitive + description: + name: rrule + sha256: f6f6ad5bf7b19d218d4c985d6055d3c9717f1d6efd5d1c0127b1146f1eb3640c + url: "https://pub.dev" + source: hosted + version: "0.2.18" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + sanitize_html: + dependency: transitive + description: + name: sanitize_html + sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + scrollable_positioned_list: + dependency: "direct main" + description: + name: scrollable_positioned_list + sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287" + url: "https://pub.dev" + source: hosted + version: "0.3.8" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: d7dc0630a923883c6328ca31b89aa682bacbf2f8304162d29f7c6aaff03a27a1 + url: "https://pub.dev" + source: hosted + version: "11.1.0" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "83af5c682796c0f7719c2bbf74792d113e40ae97981b8f266fa84574573556bc" + url: "https://pub.dev" + source: hosted + version: "2.4.18" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shimmer: + dependency: "direct main" + description: + name: shimmer + sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + sizer: + dependency: "direct main" + description: + name: sizer + sha256: "9963c89e4d30d7c2108de3eafc0a7e6a4a8009799376ea6be5ef0a9ad87cfbad" + url: "https://pub.dev" + source: hosted + version: "3.1.3" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + smooth_corner: + dependency: "direct main" + description: + name: smooth_corner + sha256: "112d7331f82ead81ec870c5d1eb0624f2e7e367eccd166c2fffe4c11d4f87c4f" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + sms_otp_auto_verify: + dependency: "direct main" + description: + name: sms_otp_auto_verify + sha256: ee02af0d6b81d386ef70d7d0317a1929bc0b4a3a30a451284450bbcf6901ba1a + url: "https://pub.dev" + source: hosted + version: "2.2.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88 + url: "https://pub.dev" + source: hosted + version: "2.4.2+2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + syncfusion_flutter_calendar: + dependency: "direct main" + description: + name: syncfusion_flutter_calendar + sha256: "8e8a4eef01d6a82ae2c17e76d497ff289ded274de014c9f471ffabc12d1e2e71" + url: "https://pub.dev" + source: hosted + version: "30.2.7" + syncfusion_flutter_core: + dependency: transitive + description: + name: syncfusion_flutter_core + sha256: bfd026c0f9822b49ff26fed11cd3334519acb6a6ad4b0c81d9cd18df6af1c4c0 + url: "https://pub.dev" + source: hosted + version: "30.2.7" + syncfusion_flutter_datepicker: + dependency: transitive + description: + name: syncfusion_flutter_datepicker + sha256: b5f35cc808e91b229d41613efe71dadab1549a35bfd493f922fc06ccc2fe908c + url: "https://pub.dev" + source: hosted + version: "30.2.7" + syncfusion_localizations: + dependency: transitive + description: + name: syncfusion_localizations + sha256: bb32b07879b4c1dee5d4c8ad1c57343a4fdae55d65a87f492727c11b68f23164 + url: "https://pub.dev" + source: hosted + version: "30.2.7" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + url: "https://pub.dev" + source: hosted + version: "3.4.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + time: + dependency: transitive + description: + name: time + sha256: "46187cf30bffdab28c56be9a63861b36e4ab7347bf403297595d6a97e10c789f" + url: "https://pub.dev" + source: hosted + version: "2.1.6" + timezone: + dependency: "direct main" + description: + name: timezone + sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 + url: "https://pub.dev" + source: hosted + version: "0.10.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + universal_platform: + dependency: transitive + description: + name: universal_platform + sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 + url: "https://pub.dev" + source: hosted + version: "6.3.2" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" + url: "https://pub.dev" + source: hosted + version: "6.3.28" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad + url: "https://pub.dev" + source: hosted + version: "6.3.6" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" + url: "https://pub.dev" + source: hosted + version: "3.2.5" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" + url: "https://pub.dev" + source: hosted + version: "3.1.5" + uuid: + dependency: "direct main" + description: + name: uuid + sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 + url: "https://pub.dev" + source: hosted + version: "4.5.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 + url: "https://pub.dev" + source: hosted + version: "1.1.19" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc + url: "https://pub.dev" + source: hosted + version: "1.1.19" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + video_player: + dependency: transitive + description: + name: video_player + sha256: "096bc28ce10d131be80dfb00c223024eb0fba301315a406728ab43dd99c45bdf" + url: "https://pub.dev" + source: hosted + version: "2.10.1" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: ee4fd520b0cafa02e4a867a0f882092e727cdaa1a2d24762171e787f8a502b0a + url: "https://pub.dev" + source: hosted + version: "2.9.1" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: d1eb970495a76abb35e5fa93ee3c58bd76fb6839e2ddf2fbb636674f2b971dd4 + url: "https://pub.dev" + source: hosted + version: "2.8.9" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + sha256: "57c5d73173f76d801129d0531c2774052c5a7c11ccb962f1830630decd9f24ec" + url: "https://pub.dev" + source: hosted + version: "6.6.0" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + wakelock_plus: + dependency: transitive + description: + name: wakelock_plus + sha256: "9296d40c9adbedaba95d1e704f4e0b434be446e2792948d0e4aa977048104228" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: "036deb14cd62f558ca3b73006d52ce049fabcdcb2eddfe0bf0fe4e8a943b5cf2" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + web: + dependency: "direct main" + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + webview_flutter: + dependency: transitive + description: + name: webview_flutter + sha256: a3da219916aba44947d3a5478b1927876a09781174b5a2b67fa5be0555154bf9 + url: "https://pub.dev" + source: hosted + version: "4.13.1" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: eeeb3fcd5f0ff9f8446c9f4bbc18a99b809e40297528a3395597d03aafb9f510 + url: "https://pub.dev" + source: hosted + version: "4.10.11" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: "63d26ee3aca7256a83ccb576a50272edd7cfc80573a4305caa98985feb493ee0" + url: "https://pub.dev" + source: hosted + version: "2.14.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: e49f378ed066efb13fc36186bbe0bd2425630d4ea0dbc71a18fdd0e4d8ed8ebc + url: "https://pub.dev" + source: hosted + version: "3.23.5" + win32: + dependency: transitive + description: + name: win32 + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e + url: "https://pub.dev" + source: hosted + version: "5.15.0" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" +sdks: + dart: ">=3.9.0 <4.0.0" + flutter: ">=3.35.0" From fbe9cd9dff9d746367f3e36bfb7381a654983884 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Wed, 18 Feb 2026 13:17:15 +0300 Subject: [PATCH 10/33] package change activity --- lib/features/smartwatch_health_data/health_provider.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/features/smartwatch_health_data/health_provider.dart b/lib/features/smartwatch_health_data/health_provider.dart index 80a79bb3..4d47ccb8 100644 --- a/lib/features/smartwatch_health_data/health_provider.dart +++ b/lib/features/smartwatch_health_data/health_provider.dart @@ -241,10 +241,11 @@ class HealthProvider with ChangeNotifier { int count = 0; selectedData.forEach((key, dataPoints) { for (var dataPoint in dataPoints) { - total += num.parse(dataPoint.actualValue).toInt(); + total += num.parse(dataPoint.actualValue); count++; } }); + print("total count is $count and total is $total"); averageValue = count > 0 ? total / count : null; notifyListeners(); } From a25df34f422b07f2430ff464f4cfbe692dddb4b1 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 18 Feb 2026 16:52:59 +0300 Subject: [PATCH 11/33] updates --- .../HealthDataTransformation.dart | 10 +++- .../health_provider.dart | 8 +-- .../health_service.dart | 1 - .../smartwatch_health_data/model/Vitals.dart | 11 ++-- .../health_connect_helper.dart | 57 ++++++++++++++----- .../smartwatches/activity_detail.dart | 19 ++++++- .../smartwatches/smart_watch_activity.dart | 4 +- lib/splashPage.dart | 2 +- 8 files changed, 80 insertions(+), 32 deletions(-) diff --git a/lib/features/smartwatch_health_data/HealthDataTransformation.dart b/lib/features/smartwatch_health_data/HealthDataTransformation.dart index d389135d..ffda4f4f 100644 --- a/lib/features/smartwatch_health_data/HealthDataTransformation.dart +++ b/lib/features/smartwatch_health_data/HealthDataTransformation.dart @@ -8,7 +8,7 @@ import 'model/Vitals.dart'; enum Durations { daily("daily"), weekly("weekly"), - monthly("weekly"), + monthly("monthly"), halfYearly("halfYearly"), yearly("yearly"); @@ -47,6 +47,7 @@ class HealthDataTransformation { } // Group by day } else if (filterType == Durations.monthly.value) { if(isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 30)), DateTime.now())) { + print("the value for the monthly filter is ${vital.value} with the timestamp ${vital.timestamp} and the current date is $currentDate and the parse date is $parseDate"); key = DateFormat('yyyy-MM-dd').format(DateTime.parse(vital.timestamp)); groupedData.putIfAbsent(key, () => []).add(vital); @@ -67,8 +68,13 @@ class HealthDataTransformation { groupedData.forEach((key, values) { double sum = values.fold(0, (acc, v) => acc + num.parse(v.value)); double mean = sum / values.length; + if(selectedSection == "bodyOxygen" || selectedSection == "bodyTemperature") { + mean = sum / values.length; + }else { + mean = sum; + } - double finalValue = filterType == 'weekly' ? mean : sum; + double finalValue = mean; print("the final value is $finalValue for the key $key with the original values ${values.map((v) => v.value).toList()} and uom is ${values.first.unitOfMeasure}"); dataPoints.add(DataPoint( value: smartScale(finalValue), diff --git a/lib/features/smartwatch_health_data/health_provider.dart b/lib/features/smartwatch_health_data/health_provider.dart index 4d47ccb8..963c0352 100644 --- a/lib/features/smartwatch_health_data/health_provider.dart +++ b/lib/features/smartwatch_health_data/health_provider.dart @@ -125,12 +125,10 @@ class HealthProvider with ChangeNotifier { if (result.isError) { error = 'Error initializing device: ${result.asError}'; } else { - LoaderBottomSheet.hideLoader(); - LoaderBottomSheet.showLoader(); await getVitals(); - LoaderBottomSheet.hideLoader(); - await Future.delayed(Duration(seconds: 5)); + // LoaderBottomSheet.hideLoader(); + // await Future.delayed(Duration(seconds: 5)); getIt.get().pushPage(page: SmartWatchActivity()); print('Device initialized successfully'); } @@ -162,7 +160,7 @@ class HealthProvider with ChangeNotifier { break; case Durations.weekly: if (weekly.isNotEmpty) { - selectedData = daily; + selectedData = weekly; break; } selectedData = weekly = healthDataTransformation.transformVitalsToDataPoints(vitals!, Durations.weekly.value, selectedSection); diff --git a/lib/features/smartwatch_health_data/health_service.dart b/lib/features/smartwatch_health_data/health_service.dart index 1cc42014..7d42092d 100644 --- a/lib/features/smartwatch_health_data/health_service.dart +++ b/lib/features/smartwatch_health_data/health_service.dart @@ -189,7 +189,6 @@ class HealthService { return null; } try { - await watchHelper!.getActivity(); await watchHelper!.getHeartRate(); await watchHelper!.getSleep(); await watchHelper!.getSteps(); diff --git a/lib/features/smartwatch_health_data/model/Vitals.dart b/lib/features/smartwatch_health_data/model/Vitals.dart index cea1df4f..96386f2d 100644 --- a/lib/features/smartwatch_health_data/model/Vitals.dart +++ b/lib/features/smartwatch_health_data/model/Vitals.dart @@ -16,6 +16,11 @@ class Vitals { unitOfMeasure: map['uom'] ?? "", ); } + + + toString(){ + return "{\"value\": \"$value\", \"timeStamp\": \"$timestamp\", \"uom\": \"$unitOfMeasure\"}"; + } } class VitalsWRTType { @@ -47,7 +52,6 @@ class VitalsWRTType { map["activity"].forEach((element) { element["uom"] = "Kcal"; var data = Vitals.fromMap(element); - // data.value = (double.parse(data.value)/1000).toStringAsFixed(2); activity.add(data); }); map["steps"].forEach((element) { @@ -70,11 +74,6 @@ class VitalsWRTType { bodyOxygen.add(Vitals.fromMap(element)); }); - map["distance"].forEach((element) { - element["uom"] = "m"; - - bodyOxygen.add(Vitals.fromMap(element)); - }); map["bodyTemperature"].forEach((element) { element["uom"] = "C"; bodyTemperature.add(Vitals.fromMap(element)); diff --git a/lib/features/smartwatch_health_data/watch_connectors/health_connect_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/health_connect_helper.dart index e7ec35b7..ac0170c8 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/health_connect_helper.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/health_connect_helper.dart @@ -11,6 +11,7 @@ class HealthConnectHelper extends WatchHelper { final Health health = Health(); final List _healthPermissions = [ + HealthDataType.ACTIVE_ENERGY_BURNED, HealthDataType.HEART_RATE, HealthDataType.STEPS, HealthDataType.BLOOD_OXYGEN, @@ -24,10 +25,11 @@ class HealthConnectHelper extends WatchHelper { @override FutureOr getHeartRate() async { try { - final types = [HealthDataType.HEART_RATE]; + final types = HealthDataType.HEART_RATE; final endDate = DateTime.now(); + // final startDate = endDate.subtract(Duration(days: 365)); final startDate = endDate.subtract(Duration(days: 365)); - final data = await getData(startDate, endDate, types); + final data = await getHeartData(startDate, endDate, types); addDataToMap("heartRate",data ); } catch (e) { print('Error getting heart rate: $e'); @@ -37,7 +39,7 @@ class HealthConnectHelper extends WatchHelper { @override FutureOr getSleep() async { try { - final types = [HealthDataType.SLEEP_IN_BED]; + final types = HealthDataType.SLEEP_IN_BED; final endDate = DateTime.now(); final startDate = endDate.subtract(Duration(days: 365)); final data = await getData(startDate, endDate, types); @@ -50,7 +52,7 @@ class HealthConnectHelper extends WatchHelper { @override FutureOr getSteps() async { try { - final types = [HealthDataType.STEPS]; + final types = HealthDataType.STEPS; final endDate = DateTime.now(); final startDate = endDate.subtract(Duration(days: 365)); final data = await getData(startDate, endDate, types); @@ -64,7 +66,7 @@ class HealthConnectHelper extends WatchHelper { @override Future getActivity() async { try { - final types = [HealthDataType.ACTIVE_ENERGY_BURNED]; + final types = HealthDataType.ACTIVE_ENERGY_BURNED; final endDate = DateTime.now(); final startDate = endDate.subtract(Duration(days: 365)); final data = await getData(startDate, endDate, types); @@ -77,17 +79,17 @@ class HealthConnectHelper extends WatchHelper { @override Future retrieveData() async { - return mappedData; + return Result.value(getMappedData()); } @override Future getBloodOxygen() async { try { - final types = [HealthDataType.BLOOD_OXYGEN]; + final types = HealthDataType.BLOOD_OXYGEN; final endDate = DateTime.now(); final startDate = endDate.subtract(Duration(days: 365)); final data = await getData(startDate, endDate, types); - addDataToMap("bloodOxygen",data ); + addDataToMapBloodOxygen("bloodOxygen", data); } catch (e) { print('Error getting blood oxygen: $e'); } @@ -96,7 +98,7 @@ class HealthConnectHelper extends WatchHelper { @override Future getBodyTemperature() async { try { - final types = [HealthDataType.BODY_TEMPERATURE]; + final types = HealthDataType.BODY_TEMPERATURE; final endDate = DateTime.now(); final startDate = endDate.subtract(Duration(days: 365)); final data = await getData(startDate, endDate, types); @@ -109,7 +111,7 @@ class HealthConnectHelper extends WatchHelper { @override FutureOr getDistance() async { try { - final types = [HealthDataType.DISTANCE_WALKING_RUNNING]; + final types = HealthDataType.DISTANCE_WALKING_RUNNING; final endDate = DateTime.now(); final startDate = endDate.subtract(Duration(days: 365)); final data = await getData(startDate, endDate, types); @@ -141,7 +143,8 @@ class HealthConnectHelper extends WatchHelper { startDate: startTime, endDate: endTime, types: [type], - interval: 86400, + // interval: 86400, + interval: 3600, ); } @@ -150,9 +153,9 @@ class HealthConnectHelper extends WatchHelper { for (var point in data) { if (point.value is NumericHealthValue) { final numericValue = (point.value as NumericHealthValue).numericValue; - point.value = NumericHealthValue( - numericValue: numericValue * 100, - ); + // point.value = NumericHealthValue( + // numericValue: numericValue * 100, + // ); Vitals vitals = Vitals( value: (point.value as NumericHealthValue).numericValue.toStringAsFixed(2), timestamp: point.dateFrom.toString() @@ -161,4 +164,30 @@ class HealthConnectHelper extends WatchHelper { } } } + + void addDataToMapBloodOxygen(String s, data) { + mappedData[s] = []; + for (var point in data) { + if (point.value is NumericHealthValue) { + final numericValue = (point.value as NumericHealthValue).numericValue; + point.value = NumericHealthValue( + numericValue: numericValue * 100, + ); + Vitals vitals = Vitals(value: (point.value as NumericHealthValue).numericValue.toStringAsFixed(2), timestamp: point.dateFrom.toString()); + mappedData[s]?.add(vitals); + } + } + } + + getMappedData() { + return " { \"heartRate\": ${mappedData["heartRate"] ?? []}, \"sleep\": ${mappedData["sleep"] ?? []}, \"steps\": ${mappedData["steps"] ?? []}, \"activity\": ${mappedData["activity"] ?? []}, \"bloodOxygen\": ${mappedData["bloodOxygen"] ?? []}, \"bodyTemperature\": ${mappedData["bodyTemperature"] ?? []}, \"distance\": ${mappedData["distance"] ?? []} }"; + } + + getHeartData(DateTime startDate, DateTime endDate, HealthDataType types) async { + return await health.getHealthDataFromTypes( + startTime: startDate, + endTime: endDate, + types: [types], + ); + } } diff --git a/lib/presentation/smartwatches/activity_detail.dart b/lib/presentation/smartwatches/activity_detail.dart index 21d168ad..78527140 100644 --- a/lib/presentation/smartwatches/activity_detail.dart +++ b/lib/presentation/smartwatches/activity_detail.dart @@ -125,6 +125,7 @@ class _ActivityDetailsState extends State { return Row( crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, + spacing: 4.w, children: [ (averageAsDouble?.toStringAsFixed(2) ?? averageAsString ?? "N/A").toText24(color: AppColors.textGreenColor, fontWeight: FontWeight.w600), Visibility( @@ -246,7 +247,7 @@ class _ActivityDetailsState extends State { height: 300.h, maxY: 150, barColor: AppColors.bgGreenColor, - barWidth: context.read().selectedData.values.toList().first.length < 10 ? 26.w : 20.w, + barWidth: getBarWidth(), barRadius: BorderRadius.circular(8), bottomLabelColor: Colors.black, bottomLabelSize: 12, @@ -339,4 +340,20 @@ class _ActivityDetailsState extends State { static String getMonthName(DateTime date) { return DateUtil.getMonthDayAsOfLang(date.month); } + + double getBarWidth() { + var duration = context.read().selectedDuration; + switch(duration){ + case durations.Durations.daily: + return 26.w; + case durations.Durations.weekly: + return 26.w; + case durations.Durations.monthly: + return 6.w; + case durations.Durations.halfYearly: + return 26.w; + case durations.Durations.yearly: + return 18.w; + } + } } diff --git a/lib/presentation/smartwatches/smart_watch_activity.dart b/lib/presentation/smartwatches/smart_watch_activity.dart index cffb802d..678fd715 100644 --- a/lib/presentation/smartwatches/smart_watch_activity.dart +++ b/lib/presentation/smartwatches/smart_watch_activity.dart @@ -31,7 +31,7 @@ class SmartWatchActivity extends StatelessWidget { description: "Activity rings give you a quick visual reference of how active you are each day. ".needTranslation, trailingIcon: AppAssets.watchActivityTrailing, result: context.read().sumOfNonEmptyData(context.read().vitals?.activity??[]), - unitsOfMeasure: "Cal" + unitsOfMeasure: "Kcal" ).onPress((){ // Map> getVitals() { // return { @@ -48,7 +48,7 @@ class SmartWatchActivity extends StatelessWidget { context.read().deleteDataIfSectionIsDifferent("activity"); context.read().saveSelectedSection("activity"); context.read().fetchData(); - context.read().navigateToDetails("activity", sectionName:"Activity Calories", uom: "cal"); + context.read().navigateToDetails("activity", sectionName:"Activity Calories", uom: "Kcal"); }), resultItem( diff --git a/lib/splashPage.dart b/lib/splashPage.dart index dc7a7c98..326665e9 100644 --- a/lib/splashPage.dart +++ b/lib/splashPage.dart @@ -57,7 +57,7 @@ class _SplashScreenState extends State { await notificationService.initialize(onNotificationClick: (payload) { // Handle notification click here }); - ZoomService().initializeZoomSDK(); + // ZoomService().initializeZoomSDK(); if (isAppOpenedFromCall) { navigateToTeleConsult(); } else { From dda4dbeba9715a1460ffe6c64b9334c56a48689e Mon Sep 17 00:00:00 2001 From: tahaalam Date: Thu, 12 Mar 2026 14:40:39 +0300 Subject: [PATCH 12/33] merge issue resolution some import were missing from master. --- android/app/src/main/AndroidManifest.xml | 1 + android/gradle.properties | 11 +++++++-- assets/langs/en-US.json | 1 - .../health_connect_helper.dart | 23 ++++++++----------- lib/widgets/custom_tab_bar.dart | 2 +- lib/widgets/datepicker_widget.dart | 3 ++- lib/widgets/graph/CustomBarGraph.dart | 21 +++++++++-------- lib/widgets/phone_number_input.dart | 3 ++- 8 files changed, 36 insertions(+), 29 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 0e77b6b6..ffa3a908 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -124,6 +124,7 @@ { late Widget parentWidget; if(widget.shouldTabExpanded){ return Row( - children:List.generate(widget.tabs.length, (index)=>myTab(widget.tabs[index], index).expanded), + children:List.generate(widget.tabs.length, (index)=>myTab(widget.tabs[index], index, resolvedActiveTextColor, resolvedInActiveTextColor, resolvedActiveBgColor, resolvedInActiveBgColor).expanded), ); } diff --git a/lib/widgets/datepicker_widget.dart b/lib/widgets/datepicker_widget.dart index f9d8ff73..bac05512 100644 --- a/lib/widgets/datepicker_widget.dart +++ b/lib/widgets/datepicker_widget.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; @@ -52,7 +53,7 @@ class DatePickerWidget extends StatelessWidget { Widget _buildLabelText() { return Text( labelText, - style: const TextStyle( + style: TextStyle( fontSize: 12.f, fontWeight: FontWeight.w500, color: Color(0xff898A8D), diff --git a/lib/widgets/graph/CustomBarGraph.dart b/lib/widgets/graph/CustomBarGraph.dart index bacdf0c7..2f50f20d 100644 --- a/lib/widgets/graph/CustomBarGraph.dart +++ b/lib/widgets/graph/CustomBarGraph.dart @@ -48,10 +48,10 @@ class CustomBarChart extends StatelessWidget { final double? maxY; final double? maxX; final double? minX; - final Color barColor; + Color? barColor; final Color? secondaryBarColor; - final Color barGridColor; - final Color bottomLabelColor; + Color? barGridColor; + Color? bottomLabelColor; final double? bottomLabelSize; final FontWeight? bottomLabelFontWeight; final double? leftLabelInterval; @@ -73,7 +73,7 @@ class CustomBarChart extends StatelessWidget { final bool isFullScreeGraph; final bool makeGraphBasedOnActualValue; - const CustomBarChart( + CustomBarChart( {super.key, required this.dataPoints, this.secondaryDataPoints, @@ -84,10 +84,7 @@ class CustomBarChart extends StatelessWidget { this.maxX, this.showBottomTitleDates = true, this.isFullScreeGraph = false, - this.barColor = AppColors.bgGreenColor, this.secondaryBarColor, - this.barGridColor = AppColors.graphGridColor, - this.bottomLabelColor = AppColors.textColor, this.bottomLabelFontWeight = FontWeight.w500, this.bottomLabelSize, this.leftLabelInterval, @@ -102,11 +99,17 @@ class CustomBarChart extends StatelessWidget { this.minY, this.barRadius, this.barWidth = 16, - this.getTooltipItem + this.getTooltipItem, + this.barColor , + this.barGridColor , + this.bottomLabelColor, }); @override Widget build(BuildContext context) { + barColor ??= AppColors.bgGreenColor; + barGridColor ??= AppColors.graphGridColor; + bottomLabelColor ??= AppColors.textColor; return Material( color: Colors.white, child: SizedBox( @@ -124,7 +127,7 @@ class CustomBarChart extends StatelessWidget { }, touchTooltipData: BarTouchTooltipData( - getTooltipColor: (_)=>AppColors.tooltipColor, + getTooltipColor: (_)=>AppColorsContext.tooltipColor, getTooltipItem: (group, groupIndex, rod, rodIndex) { final dataPoint = dataPoints[groupIndex]; if(getTooltipItem != null) { diff --git a/lib/widgets/phone_number_input.dart b/lib/widgets/phone_number_input.dart index 6ea07141..2055969f 100644 --- a/lib/widgets/phone_number_input.dart +++ b/lib/widgets/phone_number_input.dart @@ -1,3 +1,4 @@ +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:flutter/material.dart'; @@ -99,7 +100,7 @@ class _PhoneNumberInputState extends State { letterSpacing: 2, ), ), - style: const TextStyle( + style: TextStyle( fontSize: 18.f, fontWeight: FontWeight.bold, letterSpacing: 2, From 2c0d010bac14eadd9b85a349fba7e52f57c2d8c3 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 12 Mar 2026 15:30:36 +0300 Subject: [PATCH 13/33] updates --- assets/images/svg/biometric_lock_icon.svg | 3 +++ lib/core/api/api_client.dart | 5 +++++ lib/core/app_assets.dart | 1 + lib/presentation/authentication/quick_login.dart | 3 ++- 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 assets/images/svg/biometric_lock_icon.svg diff --git a/assets/images/svg/biometric_lock_icon.svg b/assets/images/svg/biometric_lock_icon.svg new file mode 100644 index 00000000..dd123157 --- /dev/null +++ b/assets/images/svg/biometric_lock_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 921e274b..4c252e8f 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -194,6 +194,11 @@ class ApiClientImp implements ApiClient { body['TokenID'] = "@dm!n"; } + if (url == 'https://uat.hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo') { + url = "https://hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo"; + body['TokenID'] = "@dm!n"; + } + // body['TokenID'] = "@dm!n"; // body['PatientID'] = 809289; // body['PatientTypeID'] = 1; diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index efe62775..4f7a0863 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -332,6 +332,7 @@ class AppAssets { static const String changeLanguageHomePageIcon = '$svgBasePath/change_language_home_page.svg'; static const String aiOverView = '$svgBasePath/ai_overview.svg'; static const String darkModeIcon = '$svgBasePath/dark_mode_icon.svg'; + static const String biometricLockIcon = '$svgBasePath/biometric_lock_icon.svg'; // PNGS // static const String hmgLogo = '$pngBasePath/hmg_logo.png'; diff --git a/lib/presentation/authentication/quick_login.dart b/lib/presentation/authentication/quick_login.dart index fbcb17d8..19e90d64 100644 --- a/lib/presentation/authentication/quick_login.dart +++ b/lib/presentation/authentication/quick_login.dart @@ -65,7 +65,8 @@ class QuickLoginState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Image.asset(AppAssets.lockIcon, height: 100), + // Image.asset(AppAssets.lockIcon, height: 100), + Utils.buildSvgWithAssets(icon: AppAssets.biometricLockIcon, iconColor: AppColors.textColor, width: 100.h, height: 100.h), SizedBox(height: 10.h), LocaleKeys.enableQuickLogin.tr(context: context).toText26(isBold: true), // Text( From 50d78551c2e8a064442414295d97832db113a973 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Thu, 12 Mar 2026 15:39:37 +0300 Subject: [PATCH 14/33] warning dialog displayed to user if the watch intented is not currently implemented --- assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 3 +- lib/core/utils/utils.dart | 22 ++++++- lib/generated/locale_keys.g.dart | 1 + .../smartwatches/smartwatch_home_page.dart | 61 +++++++++++++------ 5 files changed, 69 insertions(+), 21 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 51e27019..16ccf1af 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1597,5 +1597,6 @@ "continueCash": "متابعة الدفع نقدًا", "timeFor": "الوقت", "hmgPolicies": "سياسات مجموعة الحبيب الطبية", - "darkMode": "المظهر الداكن" + "darkMode": "المظهر الداكن", + "featureComingSoonDescription": "هذه الميزة ستتوفر قريباً. نحن نعمل جاهدين لإضافة ميزات أكثر تميزاً إلى التطبيق. انتظرونا لمتابعة التحديثات." } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 1498479f..55ed0dd4 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1589,5 +1589,6 @@ "updatetheinformation": "This will allow to gather the most up to date information from your apple watch", "timeFor": "Time For", "hmgPolicies": "HMG Policies", - "darkMode": "Dark Mode" + "darkMode": "Dark Mode", + "featureComingSoonDescription": "Feature is coming soon. We are actively working to bring more exciting features into the app. Stay tuned for updates." } diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 0d600bd7..ac8c152a 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -405,6 +405,7 @@ class Utils { static Widget getWarningWidget({ String? loadingText, bool isShowActionButtons = false, + bool showOkButton = false, Widget? bodyWidget, Function? onConfirmTap, Function? onCancelTap, @@ -457,7 +458,26 @@ class Utils { ), ], ) - : SizedBox.shrink(), + : showOkButton? + Row( + children: [ + Expanded( + child: CustomButton( + text: LocaleKeys.ok.tr(), + onPressed: () async { + if (onConfirmTap != null) { + onConfirmTap(); + } + }, + backgroundColor: AppColors.bgGreenColor, + borderColor: AppColors.bgGreenColor, + textColor: Colors.white, + // icon: AppAssets.confirm, + ), + ), + ], + ) + :SizedBox.shrink(), ], ).center; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 62451a3f..8250ec0f 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1590,5 +1590,6 @@ abstract class LocaleKeys { static const timeFor = 'timeFor'; static const hmgPolicies = 'hmgPolicies'; static const darkMode = 'darkMode'; + static const featureComingSoonDescription = 'featureComingSoonDescription'; } diff --git a/lib/presentation/smartwatches/smartwatch_home_page.dart b/lib/presentation/smartwatches/smartwatch_home_page.dart index 70cab3d9..800ff030 100644 --- a/lib/presentation/smartwatches/smartwatch_home_page.dart +++ b/lib/presentation/smartwatches/smartwatch_home_page.dart @@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/common_models/smart_watch.dart'; 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/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/smartwatch_health_data/health_provider.dart'; @@ -19,6 +20,8 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:provider/provider.dart'; +import '../../core/utils/utils.dart'; + class SmartwatchHomePage extends StatelessWidget { const SmartwatchHomePage({super.key}); @@ -149,15 +152,16 @@ class SmartwatchHomePage extends StatelessWidget { CustomButton( text: LocaleKeys.select.tr(context: context), onPressed: () { - context.read().setSelectedWatchType(SmartWatchTypes.huawei, "assets/images/png/smartwatches/Huawei_Watch.png"); - getIt.get().pushPage(page: SmartwatchInstructionsPage( - smartwatchDetails: SmartwatchDetails(SmartWatchTypes.huawei, - "assets/images/png/smartwatches/Huawei_Watch.png", - AppAssets.bluetooth, - LocaleKeys.huaweihealthapplicationshouldbeinstalledinyourphone.tr(context: context), - LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context), - LocaleKeys.huaweiwatchshouldbeconnected.tr(context: context)), - )); + // context.read().setSelectedWatchType(SmartWatchTypes.huawei, "assets/images/png/smartwatches/Huawei_Watch.png"); + // getIt.get().pushPage(page: SmartwatchInstructionsPage( + // smartwatchDetails: SmartwatchDetails(SmartWatchTypes.huawei, + // "assets/images/png/smartwatches/Huawei_Watch.png", + // AppAssets.bluetooth, + // LocaleKeys.huaweihealthapplicationshouldbeinstalledinyourphone.tr(context: context), + // LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context), + // LocaleKeys.huaweiwatchshouldbeconnected.tr(context: context)), + // )); + showUnavailableDialog(context); }, backgroundColor: AppColors.primaryRedColor.withAlpha(40), borderColor: AppColors.primaryRedColor.withAlpha(0), @@ -182,15 +186,17 @@ class SmartwatchHomePage extends StatelessWidget { CustomButton( text: LocaleKeys.select.tr(context: context), onPressed: () { - context.read().setSelectedWatchType(SmartWatchTypes.whoop, "assets/images/png/smartwatches/Whoop_Watch.png"); - getIt.get().pushPage(page: SmartwatchInstructionsPage( - smartwatchDetails: SmartwatchDetails(SmartWatchTypes.whoop, - "assets/images/png/smartwatches/Whoop_Watch.png", - AppAssets.bluetooth, - LocaleKeys.whoophealthapplicationshouldbeinstalledinyourphone.tr(context: context), - LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context), - LocaleKeys.whoopwatchshouldbeconnected.tr(context: context)), - )); + + showUnavailableDialog(context); + // context.read().setSelectedWatchType(SmartWatchTypes.whoop, "assets/images/png/smartwatches/Whoop_Watch.png"); + // getIt.get().pushPage(page: SmartwatchInstructionsPage( + // smartwatchDetails: SmartwatchDetails(SmartWatchTypes.whoop, + // "assets/images/png/smartwatches/Whoop_Watch.png", + // AppAssets.bluetooth, + // LocaleKeys.whoophealthapplicationshouldbeinstalledinyourphone.tr(context: context), + // LocaleKeys.unabletodetectapplicationinstalledpleasecomebackonceinstalled.tr(context: context), + // LocaleKeys.whoopwatchshouldbeconnected.tr(context: context)), + // )); }, backgroundColor: AppColors.primaryRedColor.withAlpha(40), borderColor: AppColors.primaryRedColor.withAlpha(0), @@ -212,4 +218,23 @@ class SmartwatchHomePage extends StatelessWidget { ), ); } + + void showUnavailableDialog(BuildContext context) { + + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.featureComingSoonDescription.tr(context: context), + isShowActionButtons: false, + showOkButton: true, + onConfirmTap: () async { + context.pop(); + } + ), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } } From 1a68ffd500d0f743bc3814323f76598e868642ac Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 12 Mar 2026 17:54:02 +0300 Subject: [PATCH 15/33] Updates --- assets/images/svg/globe_other.svg | 4 ++++ assets/langs/ar-SA.json | 3 ++- assets/langs/en-US.json | 3 ++- lib/core/api_consts.dart | 2 +- lib/core/app_assets.dart | 2 ++ lib/generated/locale_keys.g.dart | 1 + lib/presentation/authentication/saved_login_screen.dart | 3 ++- lib/presentation/lab/lab_results/lab_result_details.dart | 2 +- pubspec.yaml | 3 ++- 9 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 assets/images/svg/globe_other.svg diff --git a/assets/images/svg/globe_other.svg b/assets/images/svg/globe_other.svg new file mode 100644 index 00000000..1b9734b3 --- /dev/null +++ b/assets/images/svg/globe_other.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index f929b1ae..76736da7 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1583,5 +1583,6 @@ "continueCash": "متابعة الدفع نقدًا", "timeFor": "الوقت", "hmgPolicies": "سياسات مجموعة الحبيب الطبية", - "darkMode": "المظهر الداكن" + "darkMode": "المظهر الداكن", + "generateAiAnalysisResult": "قم بإجراء تحليل لهذا المختبر AI" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index b1cc5b08..b7c8def0 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1576,5 +1576,6 @@ "continueCash": "Continue as cash", "timeFor": "Time For", "hmgPolicies": "HMG Policies", - "darkMode": "Dark Mode" + "darkMode": "Dark Mode", + "generateAiAnalysisResult": "Generate AI analysis for this result" } diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index a529c740..99f62aad 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -233,7 +233,7 @@ class ApiConsts { static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API"; // ************ static values for Api **************** - static final double appVersionID = 20.2; + static final double appVersionID = 20.3; // static final double appVersionID = 50.7; static final int appChannelId = 3; static final String appIpAddress = "10.20.10.20"; diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 7e5e9e9b..9d5f28c8 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -17,6 +17,8 @@ class AppAssets { static const String email = '$svgBasePath/email.svg'; static const String globe = '$svgBasePath/globe.svg'; static const String globeOther = '$svgBasePath/globe_other.svg'; + + // static const String globeOther = '$svgBasePath/globe_other.svg'; static const String cancel = '$svgBasePath/cancel.svg'; static const String bell = '$svgBasePath/bell.svg'; static const String login1 = '$svgBasePath/login1.svg'; diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 1a33df93..2ba5dbc4 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1577,5 +1577,6 @@ abstract class LocaleKeys { static const timeFor = 'timeFor'; static const hmgPolicies = 'hmgPolicies'; static const darkMode = 'darkMode'; + static const generateAiAnalysisResult = 'generateAiAnalysisResult'; } diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart index e9f201ad..96db5187 100644 --- a/lib/presentation/authentication/saved_login_screen.dart +++ b/lib/presentation/authentication/saved_login_screen.dart @@ -206,7 +206,7 @@ class _SavedLogin extends State { }, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, - textColor: AppColors.whiteColor, + textColor: AppColors.textColor, icon: AppAssets.sms), ), Row( @@ -232,6 +232,7 @@ class _SavedLogin extends State { textColor: AppColors.textColor, icon: AppAssets.whatsapp, iconColor: null, + applyThemeColor: false, ), ), ], diff --git a/lib/presentation/lab/lab_results/lab_result_details.dart b/lib/presentation/lab/lab_results/lab_result_details.dart index d2c1b524..8d5d0042 100644 --- a/lib/presentation/lab/lab_results/lab_result_details.dart +++ b/lib/presentation/lab/lab_results/lab_result_details.dart @@ -104,7 +104,7 @@ class LabResultDetails extends StatelessWidget { padding: EdgeInsets.only(right: 4.w, left: 4.w), child: Utils.buildSvgWithAssets(icon: AppAssets.aiOverView, width: 16.h, height: 16.h, iconColor: Colors.white), ), - LocaleKeys.generateAiAnalysis.tr(context: context).toText16(isBold: true) + LocaleKeys.generateAiAnalysisResult.tr(context: context).toText16(isBold: true) ], ), ).paddingSymmetrical(24.h, 24.h).onPress(() async { diff --git a/pubspec.yaml b/pubspec.yaml index 43969000..27a81c7e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,8 @@ name: hmg_patient_app_new description: "New HMG Patient App" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 0.0.11+8 +#version: 0.0.11+8 +version: 0.0.1+9 environment: sdk: ">=3.6.0 <4.0.0" From d194b5a45bbe8d032aad13f722c3c97764b7bb3f Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Thu, 12 Mar 2026 22:15:35 +0300 Subject: [PATCH 16/33] updates --- lib/core/api/api_client.dart | 4 +- .../habib_wallet/habib_wallet_repo.dart | 11 ++-- .../habib_wallet/habib_wallet_view_model.dart | 10 +++- ...atient_advance_balance_response_model.dart | 27 ++++++++++ .../habib_wallet/habib_wallet_page.dart | 54 ++++++++++++++++--- 5 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 lib/features/habib_wallet/models/patient_advance_balance_response_model.dart diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 116e0733..f1a0ed0c 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -199,8 +199,8 @@ class ApiClientImp implements ApiClient { body['TokenID'] = "@dm!n"; } - // body['TokenID'] = "@dm!n"; - // body['PatientID'] = 809289; + body['TokenID'] = "@dm!n"; + body['PatientID'] = 2007395; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; // body['SessionID'] = "45786230487560q"; diff --git a/lib/features/habib_wallet/habib_wallet_repo.dart b/lib/features/habib_wallet/habib_wallet_repo.dart index 659510de..c89a85be 100644 --- a/lib/features/habib_wallet/habib_wallet_repo.dart +++ b/lib/features/habib_wallet/habib_wallet_repo.dart @@ -3,6 +3,7 @@ import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/features/habib_wallet/models/patient_advance_balance_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; @@ -40,18 +41,22 @@ class HabibWalletRepoImp implements HabibWalletRepo { }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { - // final list = response['ListPLO']; + final list = response['List_PatientAdvanceBalanceAmount']; // if (list == null || list.isEmpty) { // throw Exception("lab list is empty"); // } - // final labOrders = list.map((item) => PatientLabOrdersResponseModel.fromJson(item as Map)).toList().cast(); + final List balanceAmountList = list.map((item) => PatientAdvanceBalanceResponseModel.fromJson(item as Map)).toList().cast(); + + for (var element in balanceAmountList) { + element.totalAmount = response['TotalAdvanceBalanceAmount']; + } apiResponse = GenericApiModel( messageStatus: messageStatus, statusCode: statusCode, errorMessage: null, - data: response["TotalAdvanceBalanceAmount"], + data: balanceAmountList, ); } catch (e) { failure = DataParsingFailure(e.toString()); diff --git a/lib/features/habib_wallet/habib_wallet_view_model.dart b/lib/features/habib_wallet/habib_wallet_view_model.dart index 2f338957..65e8e276 100644 --- a/lib/features/habib_wallet/habib_wallet_view_model.dart +++ b/lib/features/habib_wallet/habib_wallet_view_model.dart @@ -1,6 +1,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.dart'; +import 'package:hmg_patient_app_new/features/habib_wallet/models/patient_advance_balance_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; @@ -30,6 +31,8 @@ class HabibWalletViewModel extends ChangeNotifier { num selectedRechargeType = 1; + List habibWalletBalanceList = []; + HabibWalletViewModel({required this.habibWalletRepo, required this.errorHandlerService}); initHabibWalletProvider() { @@ -39,6 +42,7 @@ class HabibWalletViewModel extends ChangeNotifier { walletRechargeAmount = 0; selectedRechargeType = 1; advancePaymentHospitals.clear(); + habibWalletBalanceList.clear(); selectedHospital = null; fileNumber = ''; depositorName = ''; @@ -103,7 +107,11 @@ class HabibWalletViewModel extends ChangeNotifier { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { - habibWalletAmount = apiResponse.data!; + habibWalletBalanceList = apiResponse.data; + habibWalletAmount = habibWalletBalanceList.first.totalAmount ?? 0.0; + + habibWalletBalanceList.sort((a, b) => b.patientAdvanceBalanceAmount!.compareTo(a.patientAdvanceBalanceAmount!)); + isWalletAmountLoading = false; notifyListeners(); if (onSuccess != null) { diff --git a/lib/features/habib_wallet/models/patient_advance_balance_response_model.dart b/lib/features/habib_wallet/models/patient_advance_balance_response_model.dart new file mode 100644 index 00000000..55594555 --- /dev/null +++ b/lib/features/habib_wallet/models/patient_advance_balance_response_model.dart @@ -0,0 +1,27 @@ +class PatientAdvanceBalanceResponseModel { + num? distanceInKilometers; + num? patientAdvanceBalanceAmount; + String? projectDescription; + int? projectID; + num? totalAmount; + + PatientAdvanceBalanceResponseModel({this.distanceInKilometers, this.patientAdvanceBalanceAmount, this.projectDescription, this.projectID, this.totalAmount}); + + PatientAdvanceBalanceResponseModel.fromJson(Map json) { + distanceInKilometers = json['DistanceInKilometers']; + patientAdvanceBalanceAmount = json['PatientAdvanceBalanceAmount']; + projectDescription = json['ProjectDescription']; + projectID = json['ProjectID']; + totalAmount = json['TotalAmount']; + } + + Map toJson() { + final Map data = Map(); + data['DistanceInKilometers'] = distanceInKilometers; + data['PatientAdvanceBalanceAmount'] = patientAdvanceBalanceAmount; + data['ProjectDescription'] = projectDescription; + data['ProjectID'] = projectID; + data['TotalAmount'] = totalAmount; + return data; + } +} diff --git a/lib/presentation/habib_wallet/habib_wallet_page.dart b/lib/presentation/habib_wallet/habib_wallet_page.dart index c90003a8..780c3d64 100644 --- a/lib/presentation/habib_wallet/habib_wallet_page.dart +++ b/lib/presentation/habib_wallet/habib_wallet_page.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; @@ -26,6 +28,16 @@ class HabibWalletPage extends StatefulWidget { class _HabibWalletState extends State { late HabibWalletViewModel habibWalletVM; + @override + void initState() { + scheduleMicrotask(() async { + habibWalletVM.initHabibWalletProvider(); + habibWalletVM.getPatientBalanceAmount(); + }); + + super.initState(); + } + @override Widget build(BuildContext context) { habibWalletVM = Provider.of(context, listen: false); @@ -44,7 +56,7 @@ class _HabibWalletState extends State { width: double.infinity, height: 180.h, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.blackBgColor, + color: AppColors.whiteColor, borderRadius: 24, ), child: Padding( @@ -59,18 +71,18 @@ class _HabibWalletState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - "${_appState.getAuthenticatedUser()!.firstName!} ${_appState.getAuthenticatedUser()!.lastName!}".toText19(isBold: true, color: AppColors.whiteColor), + "${_appState.getAuthenticatedUser()!.firstName!} ${_appState.getAuthenticatedUser()!.lastName!}".toText19(isBold: true, color: AppColors.textColor), "MRN: ${_appState.getAuthenticatedUser()!.patientId!}".toText14(weight: FontWeight.w500, color: AppColors.greyTextColor), ], ).expanded, - Utils.buildSvgWithAssets(icon: AppAssets.habiblogo, width: 24.h, height: 24.h), + Utils.buildSvgWithAssets(icon: AppAssets.habiblogo, width: 24.h, height: 24.h, applyThemeColor: false), ], ), Spacer(), - LocaleKeys.balanceAmount.tr(context: context).toText14(weight: FontWeight.w500, color: AppColors.whiteColor), + LocaleKeys.balanceAmount.tr(context: context).toText14(weight: FontWeight.w500, color: AppColors.textColor), SizedBox(height: 4.h), Consumer(builder: (context, habibWalletVM, child) { - return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, textColor: AppColors.whiteColor, iconColor: AppColors.whiteColor, iconSize: 13, isExpanded: false) + return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, textColor: AppColors.textColor, iconColor: AppColors.textColor, iconSize: 16, isExpanded: false) .toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 24.h); }), ], @@ -86,7 +98,7 @@ class _HabibWalletState extends State { icon: AppAssets.recharge_icon, iconSize: 24.w, backgroundColor: AppColors.infoColor, - textColor: AppColors.whiteColor, + textColor: Colors.white, text: LocaleKeys.recharge.tr(context: context), borderWidth: 0.w, fontWeight: FontWeight.w500, @@ -99,12 +111,42 @@ class _HabibWalletState extends State { page: RechargeWalletPage(), )) .then((val) { + habibWalletVM.initHabibWalletProvider(); habibWalletVM.getPatientBalanceAmount(); }); }, ), ], ), + SizedBox(height: 16.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: false, + ), + child: Consumer(builder: (context, habibWalletVM, child) { + return ListView.separated( + itemCount: habibWalletVM.habibWalletBalanceList.length, + physics: NeverScrollableScrollPhysics(), + padding: EdgeInsets.only(top: 8, bottom: 8), + shrinkWrap: true, + itemBuilder: (context, index) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded(child: habibWalletVM.habibWalletBalanceList[index].projectDescription!.toText16(weight: FontWeight.w500, color: AppColors.textColor)), + Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletBalanceList[index].patientAdvanceBalanceAmount!, textColor: AppColors.textColor, iconColor: AppColors.textColor, iconSize: 18.h, isExpanded: false, fontSize: 28.f, fontWeight: FontWeight.w500), + ], + ).paddingSymmetrical(0, 12.h); + }, + separatorBuilder: (BuildContext context, int index) { + return Divider(height: 1, color: AppColors.textColor.withAlpha(20)); + }, + ).paddingSymmetrical(16.h, 24.h).toShimmer2(isShow: habibWalletVM.isWalletAmountLoading); + }), + ), + SizedBox(height: 24.h), ], ), ), From 30bdfac44296ae24162d317d2f6c113f92d72185 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Fri, 13 Mar 2026 14:24:15 +0300 Subject: [PATCH 17/33] App update page updates --- ios/Runner.xcodeproj/project.pbxproj | 42 +++--- .../AppIcon.appiconset/Contents.json | 129 +----------------- lib/presentation/home/app_update_page.dart | 6 +- 3 files changed, 26 insertions(+), 151 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index e031a976..8ed9d257 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -11,6 +11,12 @@ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 478CFA942E638C8E0064F3D7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */; }; + 47C1AAC72F425ACF00DA1231 /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47C1AAC12F425AC800DA1231 /* Penguin.xcframework */; }; + 47C1AAC82F425ACF00DA1231 /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 47C1AAC12F425AC800DA1231 /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 47C1AAC92F425AD000DA1231 /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47C1AAC22F425AC800DA1231 /* PenguinINRenderer.xcframework */; }; + 47C1AACA2F425AD000DA1231 /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 47C1AAC22F425AC800DA1231 /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 47C1AACB2F425AD100DA1231 /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47C1AAC32F425AC800DA1231 /* PenNavUI.xcframework */; }; + 47C1AACC2F425AD100DA1231 /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 47C1AAC32F425AC800DA1231 /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 61243B492EC5FA3700D46FA0 /* PenguinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */; }; 61243B4C2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */; }; 61243B502EC5FA3700D46FA0 /* PenguinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B452EC5FA3700D46FA0 /* PenguinView.swift */; }; @@ -18,12 +24,6 @@ 61243B562EC5FA3700D46FA0 /* PenguinNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */; }; 61243B572EC5FA3700D46FA0 /* PenguinViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 765A5A8C2F35CD8B0003FF7D /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A802F35CD730003FF7D /* Penguin.xcframework */; }; - 765A5A8D2F35CD8B0003FF7D /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A802F35CD730003FF7D /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 765A5A8E2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */; }; - 765A5A8F2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 765A5A902F35CD8B0003FF7D /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */; }; - 765A5A912F35CD8B0003FF7D /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 76AA18AE2F3B2A4D00DC8DFC /* ring_30Sec.caf in Resources */ = {isa = PBXBuildFile; fileRef = 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */; }; 76AA18AF2F3B2A4D00DC8DFC /* ring_30Sec.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 76AA18AD2F3B2A4D00DC8DFC /* ring_30Sec.mp3 */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -49,9 +49,9 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 765A5A8F2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Embed Frameworks */, - 765A5A8D2F35CD8B0003FF7D /* Penguin.xcframework in Embed Frameworks */, - 765A5A912F35CD8B0003FF7D /* PenNavUI.xcframework in Embed Frameworks */, + 47C1AACA2F425AD000DA1231 /* PenguinINRenderer.xcframework in Embed Frameworks */, + 47C1AAC82F425ACF00DA1231 /* Penguin.xcframework in Embed Frameworks */, + 47C1AACC2F425AD100DA1231 /* PenNavUI.xcframework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -66,6 +66,9 @@ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 478CFA952E6E20A60064F3D7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + 47C1AAC12F425AC800DA1231 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Penguin.xcframework; sourceTree = ""; }; + 47C1AAC22F425AC800DA1231 /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenguinINRenderer.xcframework; sourceTree = ""; }; + 47C1AAC32F425AC800DA1231 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenNavUI.xcframework; sourceTree = ""; }; 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = ""; }; 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = ""; }; 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = ""; }; @@ -75,9 +78,6 @@ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7595037DD52211B91157B0F3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 765A5A802F35CD730003FF7D /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Penguin.xcframework; sourceTree = ""; }; - 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenguinINRenderer.xcframework; sourceTree = ""; }; - 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenNavUI.xcframework; sourceTree = ""; }; 769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = ""; }; 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = ring_30Sec.caf; sourceTree = ""; }; 76AA18AD2F3B2A4D00DC8DFC /* ring_30Sec.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = ring_30Sec.mp3; sourceTree = ""; }; @@ -99,9 +99,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 765A5A8C2F35CD8B0003FF7D /* Penguin.xcframework in Frameworks */, - 765A5A902F35CD8B0003FF7D /* PenNavUI.xcframework in Frameworks */, - 765A5A8E2F35CD8B0003FF7D /* PenguinINRenderer.xcframework in Frameworks */, + 47C1AAC92F425AD000DA1231 /* PenguinINRenderer.xcframework in Frameworks */, + 47C1AACB2F425AD100DA1231 /* PenNavUI.xcframework in Frameworks */, + 47C1AAC72F425ACF00DA1231 /* Penguin.xcframework in Frameworks */, DE1EF78253E64BE86845D2CC /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -140,9 +140,9 @@ 766D8CB22EC60BE600D05E07 /* Frameworks */ = { isa = PBXGroup; children = ( - 765A5A802F35CD730003FF7D /* Penguin.xcframework */, - 765A5A812F35CD730003FF7D /* PenguinINRenderer.xcframework */, - 765A5A822F35CD730003FF7D /* PenNavUI.xcframework */, + 47C1AAC12F425AC800DA1231 /* Penguin.xcframework */, + 47C1AAC22F425AC800DA1231 /* PenguinINRenderer.xcframework */, + 47C1AAC32F425AC800DA1231 /* PenNavUI.xcframework */, D562310E31D1DDEFA02A6C12 /* Pods_Runner.framework */, ); name = Frameworks; @@ -523,7 +523,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -709,7 +709,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -738,7 +738,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index 1eb27a20..65b74d7e 100644 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,128 +1 @@ -{ - "images" : [ - { - "filename" : "Icon-App-20x20@2x.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "Icon-App-20x20@3x.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "filename" : "Icon-App-29x29@1x.png", - "idiom" : "iphone", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "Icon-App-29x29@2x.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "Icon-App-29x29@3x.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "filename" : "Icon-App-40x40@2x.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "Icon-App-40x40@3x.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "filename" : "Icon-App-60x60@2x.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "filename" : "Icon-App-60x60@3x.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "filename" : "Icon-App-20x20@1x.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "filename" : "Icon-App-20x20@2x.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "Icon-App-29x29@1x.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "Icon-App-29x29@2x.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "Icon-App-40x40@1x.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "filename" : "Icon-App-40x40@2x.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "Icon-App-76x76@1x.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "filename" : "Icon-App-76x76@2x.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "filename" : "Icon-App-83.5x83.5@2x.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "filename" : "icon.jpg", - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - }, - { - "filename" : "Icon-App-76x76@2x.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "76x76" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} +{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]} \ No newline at end of file diff --git a/lib/presentation/home/app_update_page.dart b/lib/presentation/home/app_update_page.dart index 5e6481bd..18382838 100644 --- a/lib/presentation/home/app_update_page.dart +++ b/lib/presentation/home/app_update_page.dart @@ -83,13 +83,15 @@ class AppUpdatePage extends StatelessWidget { }).catchError((e) { print(e.toString()); Utils.openWebView( - url: "https://play.google.com/store/apps/details?id=com.ejada.hmg", + // url: "https://play.google.com/store/apps/details?id=com.ejada.hmg", + url: "https://play.google.com/store/apps/details?id=com.cloudsolutions.HMGPatientApp", ); }); } if (Platform.isIOS) { Utils.openWebView( - url: "https://itunes.apple.com/app/id733503978", + // url: "https://itunes.apple.com/app/id733503978", + url: "https://itunes.apple.com/app/id6758851027", ); } } From 657f88639131d2b7055e62c4dd52238f7a8e1c64 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Sat, 14 Mar 2026 15:06:50 +0300 Subject: [PATCH 18/33] Changes for AI Lab analysis --- PROJECT_ARCHITECTURE.md | 1768 +++++++++++++++++ lib/core/api/api_client.dart | 4 +- lib/features/lab/lab_view_model.dart | 5 + .../book_appointment/doctor_profile_page.dart | 21 +- .../LabResultByClinic.dart | 2 +- .../ai_analysis_widget.dart | 11 + .../lab/lab_results/lab_result_details.dart | 176 +- 7 files changed, 1880 insertions(+), 107 deletions(-) create mode 100644 PROJECT_ARCHITECTURE.md diff --git a/PROJECT_ARCHITECTURE.md b/PROJECT_ARCHITECTURE.md new file mode 100644 index 00000000..00ee9672 --- /dev/null +++ b/PROJECT_ARCHITECTURE.md @@ -0,0 +1,1768 @@ + +You are a senior Flutter developer. You will be given this entire document as your specification. +Your task: generate a complete, compilable Flutter project from scratch following every instruction below. +Do NOT skip any file. Do NOT summarize. Generate FULL, working Dart code for every file listed. +When you see placeholder names like `{{APP_NAME}}`, `{{PACKAGE_NAME}}`, `{{BASE_URL}}`, replace them with the values the user provides. If no values are provided, use the defaults in Section 1. + + +# Flutter Project Generator — Architecture Specification + +> **What this document is:** A precise, machine-readable specification for an AI to generate a greenfield Flutter project. Every file path, every class, every method signature, and every pattern is defined below with copy-ready code. Follow it top-to-bottom. + +--- + +## 1. DEFAULTS — Replace These for Your Project + +``` +APP_NAME = "My App" +DART_PACKAGE = "my_app" +ORG_IDENTIFIER = "com.example.myapp" +BASE_URL = "https://api.example.com/" +PRIMARY_COLOR = 0xFFED1C2B (Red) +FIGMA_WIDTH = 430 +FIGMA_HEIGHT = 927 +SUPPORTED_LOCALES = [en-US, ar-SA] +PRIMARY_FONT = "Poppins" +SECONDARY_FONT = "GESSTwo" (Arabic font) +``` + +When the user asks you to generate this project, first ask them for these values. If they say "use defaults," use the values above. + +--- + +## 2. COMMAND — Create the Flutter Project + +Run this first: +```bash +flutter create --org {{ORG_IDENTIFIER}} --project-name {{DART_PACKAGE}} {{DART_PACKAGE}} +cd {{DART_PACKAGE}} +``` + +--- + +## 3. FILE: `pubspec.yaml` + +Generate this file EXACTLY. Do not add or remove packages. + +```yaml +name: {{DART_PACKAGE}} +description: "{{APP_NAME}}" +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: ">=3.6.0 <4.0.0" + +dependencies: + flutter: + sdk: flutter + flutter_localizations: + sdk: flutter + + # === Core Architecture === + provider: ^6.1.5+1 + get_it: ^8.2.0 + dartz: ^0.10.1 + equatable: ^2.0.7 + + # === Networking === + http: ^1.5.0 + connectivity_plus: ^6.1.5 + + # === Firebase === + firebase_core: any + firebase_messaging: ^15.2.10 + firebase_analytics: ^11.5.1 + firebase_crashlytics: ^4.3.8 + + # === UI === + cupertino_icons: ^1.0.8 + flutter_svg: ^2.2.0 + cached_network_image: ^3.4.1 + auto_size_text: ^3.0.0 + shimmer: ^3.0.0 + sizer: ^3.1.3 + lottie: ^3.3.1 + smooth_corner: ^1.1.1 + flutter_staggered_animations: ^1.1.1 + fl_chart: 1.0.0 + flutter_rating_bar: ^4.0.1 + + # === Localization === + easy_localization: ^3.0.8 + intl: ^0.20.2 + + # === Storage === + shared_preferences: ^2.5.3 + path_provider: ^2.0.8 + + # === Device === + permission_handler: ^12.0.1 + local_auth: ^2.3.0 + device_info_plus: ^11.5.0 + image_picker: ^1.2.0 + url_launcher: ^6.3.2 + share_plus: ^11.1.0 + + # === Notifications === + flutter_local_notifications: ^19.4.1 + timezone: ^0.10.0 + fluttertoast: ^8.2.12 + + # === Logging === + logger: ^2.6.1 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^5.0.0 + +flutter: + uses-material-design: true + assets: + - assets/ + - assets/json/ + - assets/fonts/ + - assets/langs/ + - assets/images/ + - assets/images/svg/ + - assets/images/png/ + - assets/animations/ + - assets/animations/lottie/ + + fonts: + - family: Poppins + fonts: + - asset: assets/fonts/poppins/Poppins-SemiBold.ttf + weight: 600 + - asset: assets/fonts/poppins/Poppins-Medium.ttf + weight: 500 + - asset: assets/fonts/poppins/Poppins-Regular.ttf + weight: 400 + - asset: assets/fonts/poppins/Poppins-Light.ttf + weight: 300 +``` + +> **Note:** If the user provides a SECONDARY_FONT, add its font family block here too. + +--- + +## 4. FILE: `analysis_options.yaml` + +```yaml +include: package:flutter_lints/flutter.yaml + +linter: + rules: + # prefer_single_quotes: true +``` + +--- + +## 5. FOLDER STRUCTURE — Create ALL These Directories + +```bash +mkdir -p lib/core/api +mkdir -p lib/core/common_models +mkdir -p lib/core/exceptions +mkdir -p lib/core/utils +mkdir -p lib/services/analytics +mkdir -p lib/features +mkdir -p lib/presentation/home/widgets +mkdir -p lib/presentation/authentication +mkdir -p lib/presentation/onboarding +mkdir -p lib/routes +mkdir -p lib/theme +mkdir -p lib/extensions +mkdir -p lib/widgets/buttons +mkdir -p lib/widgets/loader +mkdir -p lib/widgets/bottomsheet +mkdir -p lib/widgets/bottom_navigation +mkdir -p lib/widgets/shimmer +mkdir -p lib/widgets/routes +mkdir -p lib/generated +mkdir -p assets/fonts/poppins +mkdir -p assets/images/svg +mkdir -p assets/images/png +mkdir -p assets/animations/lottie +mkdir -p assets/json +mkdir -p assets/langs +mkdir -p assets/sounds +``` + +--- + +## 6. CORE LAYER — Generate Each File Exactly + +### 6.1 FILE: `lib/core/enums.dart` + +```dart +enum ViewStateEnum { hide, idle, busy, error, busyLocal, errorLocal } + +enum AppEnvironmentTypeEnum { dev, uat, preProd, qa, staging, prod } + +enum GenderTypeEnum { male, female } + +enum ChipTypeEnum { success, error, alert, info, warning, lightBg, primaryRed } + +enum LoginTypeEnum { sms, whatsapp, face, fingerprint } + +enum OTPTypeEnum { sms, whatsapp, faceIDFingerprint } +``` + +### 6.2 FILE: `lib/core/exceptions/api_failure.dart` + +```dart +import 'package:equatable/equatable.dart'; + +abstract class Failure extends Equatable implements Exception { + final String message; + const Failure(this.message); +} + +class ServerFailure extends Failure { + final String url; + const ServerFailure(super.message, {this.url = ""}); + @override + List get props => [message]; +} + +class DataParsingFailure extends Failure { + const DataParsingFailure(super.message); + @override + List get props => [message]; +} + +class ConnectivityFailure extends Failure { + const ConnectivityFailure(super.message); + @override + List get props => [message]; +} + +class UnAuthenticatedUserFailure extends Failure { + final String url; + const UnAuthenticatedUserFailure(super.message, {this.url = ""}); + @override + List get props => [message]; +} + +class AppUpdateFailure extends Failure { + const AppUpdateFailure(super.message); + @override + List get props => [message]; +} + +class StatusCodeFailure extends Failure { + const StatusCodeFailure(super.message); + @override + List get props => [message]; +} + +class UnknownFailure extends Failure { + final String url; + const UnknownFailure(super.message, {this.url = ""}); + @override + List get props => [message]; +} + +class UserIntimationFailure extends Failure { + const UserIntimationFailure(super.message); + @override + List get props => [message]; +} + +class MessageStatusFailure extends Failure { + const MessageStatusFailure(super.message); + @override + List get props => [message]; +} + +class InvalidCredentials extends Failure { + const InvalidCredentials(String? message) : super(message ?? ''); + @override + List get props => [message]; +} + +class LocalStorageFailure extends Failure { + const LocalStorageFailure(super.message); + @override + List get props => [message]; +} +``` + +### 6.3 FILE: `lib/core/common_models/generic_api_model.dart` + +```dart +class GenericApiModel { + final int? messageStatus; + final String? errorMessage; + final int? statusCode; + final T? data; + + GenericApiModel({this.messageStatus, this.errorMessage, this.statusCode, this.data}); + + factory GenericApiModel.fromJson( + Map json, + T Function(Object? json)? fromJsonT, + ) { + return GenericApiModel( + messageStatus: json['messageStatus'] as int?, + errorMessage: json['errorMessage'] as String?, + statusCode: json['statusCode'] as int?, + data: fromJsonT != null ? fromJsonT(json['data']) : json['data'] as T?, + ); + } + + Map toJson(Object Function(T value)? toJsonT) { + return { + 'messageStatus': messageStatus, + 'errorMessage': errorMessage, + 'statusCode': statusCode, + 'data': toJsonT != null && data != null ? toJsonT(data as T) : data, + }; + } +} +``` + +### 6.4 FILE: `lib/core/api_consts.dart` + +```dart +import 'package:{{DART_PACKAGE}}/core/enums.dart'; + +const int VERSION_ID = 1; +const int CHANNEL = 3; +const String IP_ADDRESS = "10.20.10.20"; +const String GENERAL_ID = "Aborkan"; +const int PATIENT_TYPE = 1; +const int PATIENT_TYPE_ID = 1; +const String SETUP_ID = "010266"; +const bool IS_DENTAL_ALLOWED_BACKEND = false; + +class ApiConsts { + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; + static String baseUrl = '{{BASE_URL}}'; + + static int appVersionID = VERSION_ID; + static int appChannelId = CHANNEL; + static String appIpAddress = IP_ADDRESS; + static String appGeneralId = GENERAL_ID; + static String sessionID = ""; + + static void setBackendURLs() { + switch (appEnvironmentType) { + case AppEnvironmentTypeEnum.prod: + baseUrl = '{{BASE_URL}}'; + break; + case AppEnvironmentTypeEnum.dev: + case AppEnvironmentTypeEnum.uat: + case AppEnvironmentTypeEnum.preProd: + case AppEnvironmentTypeEnum.qa: + case AppEnvironmentTypeEnum.staging: + baseUrl = '{{BASE_URL}}'; + break; + } + } + + // ── Add endpoint paths here as you build features ── + // static const String login = "api/auth/login"; +} +``` + +### 6.5 FILE: `lib/core/cache_consts.dart` + +```dart +class CacheConst { + static const String firstLaunch = "firstLaunch"; + static const String appAuthToken = "app_auth_token"; + static const String loggedInUserObj = "logged_in_user_obj"; + static const String pushToken = "push_token"; + static const String appLanguage = 'language'; + static const String isDarkMode = 'is_dark_mode'; + + // Add more cache keys as features are built +} +``` + +### 6.6 FILE: `lib/core/app_state.dart` + +```dart +import 'dart:io'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:{{DART_PACKAGE}}/services/navigation_service.dart'; + +class AppState { + final NavigationService navigationService; + + AppState({required this.navigationService}); + + double userLat = 0.0; + double userLong = 0.0; + + bool isArabic() { + final ctx = navigationService.navigatorKey.currentContext; + if (ctx == null) return false; + return EasyLocalization.of(ctx)?.locale.languageCode == "ar"; + } + + int getLanguageID() => isArabic() ? 1 : 2; + String? getLanguageCode() { + final ctx = navigationService.navigatorKey.currentContext; + if (ctx == null) return "en"; + return EasyLocalization.of(ctx)?.locale.languageCode; + } + int getDeviceTypeID() => Platform.isIOS ? 1 : 2; + + bool isAuthenticated = false; + String appAuthToken = ""; + String deviceToken = ""; + String voipToken = ""; + String sessionId = ""; + String deviceTypeID = ""; + + Map? authenticatedUser; + + void setAuthenticatedUser(Map? user) { + authenticatedUser = user; + isAuthenticated = user != null; + } + + void resetLocation() { + userLat = 0.0; + userLong = 0.0; + } +} +``` + +### 6.7 FILE: `lib/core/app_assets.dart` + +```dart +class AppAssets { + static const String svgBasePath = 'assets/images/svg'; + static const String pngBasePath = 'assets/images/png'; + static const String lottieBasePath = 'assets/animations/lottie'; + + // Add asset constants here as you add files. Examples: + // static const String logo = '$svgBasePath/logo.svg'; + // static const String placeholder = '$pngBasePath/placeholder.png'; +} +``` + +### 6.8 FILE: `lib/core/app_export.dart` + +```dart +export '../routes/app_routes.dart'; +export 'utils/size_utils.dart'; +``` + +### 6.9 FILE: `lib/core/utils/size_utils.dart` + +```dart +import 'package:flutter/material.dart'; + +const num figmaDesignWidth = {{FIGMA_WIDTH}}; +const num figmaDesignHeight = {{FIGMA_HEIGHT}}; + +class SizeUtils { + static late double width; + static late double height; + static late DeviceType deviceType; + + static void init(BoxConstraints constraints, Orientation orientation) { + width = constraints.maxWidth; + height = constraints.maxHeight; + deviceType = width > 600 ? DeviceType.tablet : DeviceType.phone; + } +} + +enum DeviceType { phone, tablet } + +bool get isTablet => SizeUtils.deviceType == DeviceType.tablet; + +extension ResponsiveExtension on num { + double get _width => SizeUtils.width; + double get _height => SizeUtils.height; + + double get f { + double scale = (_width < _height ? _width : _height) / figmaDesignWidth; + double clamp = isTablet ? 1.4 : 1.2; + if (scale > clamp) scale = clamp; + return this * scale; + } + + double get w => (this * _width) / figmaDesignWidth; + double get h => (this * _height) / figmaDesignHeight; + double get r => (this * _width) / figmaDesignWidth; +} +``` + +### 6.10 FILE: `lib/core/utils/loading_utils.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:{{DART_PACKAGE}}/core/dependencies.dart'; +import 'package:{{DART_PACKAGE}}/services/navigation_service.dart'; + +class LoadingUtils { + static bool isLoading = false; + static OverlayEntry? _overlayEntry; + + static void showFullScreenLoader() { + final context = getIt.get().navigatorKey.currentContext; + if (context == null || isLoading) return; + isLoading = true; + _overlayEntry = OverlayEntry( + builder: (_) => Container( + color: Colors.black38, + child: const Center(child: CircularProgressIndicator()), + ), + ); + Overlay.of(context).insert(_overlayEntry!); + } + + static void hideFullScreenLoader() { + _overlayEntry?.remove(); + _overlayEntry = null; + isLoading = false; + } +} +``` + +### 6.11 FILE: `lib/core/api/api_client.dart` + +```dart +import 'dart:convert'; +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart' as http; +import 'package:{{DART_PACKAGE}}/core/api_consts.dart'; +import 'package:{{DART_PACKAGE}}/core/app_state.dart'; +import 'package:{{DART_PACKAGE}}/core/exceptions/api_failure.dart'; + +abstract class ApiClient { + Future post( + String endPoint, { + required Map body, + required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess, + required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, + bool isExternal = false, + Map? apiHeaders, + }); + + Future get( + String endPoint, { + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + Map? queryParams, + Map? apiHeaders, + bool isExternal = false, + }); +} + +class ApiClientImp implements ApiClient { + final AppState _appState; + + ApiClientImp({required AppState appState}) : _appState = appState; + + Map _defaultHeaders() => {'Content-Type': 'application/json', 'Accept': 'application/json'}; + + void _injectCommonFields(Map body) { + body['VersionID'] = ApiConsts.appVersionID.toString(); + body['Channel'] = ApiConsts.appChannelId.toString(); + body['IPAdress'] = ApiConsts.appIpAddress; + body['generalid'] = ApiConsts.appGeneralId; + body['LanguageID'] = _appState.getLanguageID().toString(); + body['Latitude'] = _appState.userLat.toString(); + body['Longitude'] = _appState.userLong.toString(); + body['DeviceTypeID'] = _appState.deviceTypeID; + if (_appState.appAuthToken.isNotEmpty) { + body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken; + } + } + + @override + Future post( + String endPoint, { + required Map body, + required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess, + required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, + bool isExternal = false, + Map? apiHeaders, + }) async { + final url = isExternal ? endPoint : ApiConsts.baseUrl + endPoint; + final headers = apiHeaders ?? _defaultHeaders(); + if (!isExternal) _injectCommonFields(body); + + try { + final response = await http.post(Uri.parse(url), headers: headers, body: jsonEncode(body)); + final statusCode = response.statusCode; + + if (statusCode == 401) { + onFailure('Unauthenticated', statusCode, failureType: UnAuthenticatedUserFailure('Session expired', url: url)); + return; + } + if (statusCode == 426) { + onFailure('App update required', statusCode, failureType: const AppUpdateFailure('Please update the app')); + return; + } + + if (statusCode >= 200 && statusCode < 300) { + final decoded = jsonDecode(response.body); + final int? messageStatus = decoded['MessageStatus']; + final String? errorMessage = decoded['ErrorEndUserMessage'] ?? decoded['ErrorMessage']; + + if (messageStatus == 1 || messageStatus == null) { + onSuccess(decoded, statusCode, messageStatus: messageStatus, errorMessage: errorMessage); + } else { + onFailure(errorMessage ?? 'Request failed', statusCode, + messageStatus: messageStatus, + failureType: MessageStatusFailure(errorMessage ?? 'Request failed with status $messageStatus')); + } + } else { + onFailure('Server error: $statusCode', statusCode, failureType: ServerFailure('Server error: $statusCode', url: url)); + } + } catch (e) { + if (kDebugMode) print('API POST error ($url): $e'); + onFailure(e.toString(), 0, failureType: UnknownFailure(e.toString(), url: url)); + } + } + + @override + Future get( + String endPoint, { + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + Map? queryParams, + Map? apiHeaders, + bool isExternal = false, + }) async { + final baseUrl = isExternal ? endPoint : ApiConsts.baseUrl + endPoint; + final uri = Uri.parse(baseUrl).replace(queryParameters: queryParams?.map((k, v) => MapEntry(k, v.toString()))); + final headers = apiHeaders ?? _defaultHeaders(); + + try { + final response = await http.get(uri, headers: headers); + if (response.statusCode >= 200 && response.statusCode < 300) { + onSuccess(jsonDecode(response.body), response.statusCode); + } else { + onFailure('GET failed: ${response.statusCode}', response.statusCode); + } + } catch (e) { + onFailure(e.toString(), 0); + } + } +} +``` + +--- + +## 7. SERVICES LAYER — Generate Each File Exactly + +### 7.1 FILE: `lib/services/logger_service.dart` + +```dart +import 'package:logger/logger.dart'; + +abstract class LoggerService { + void logError(String message); + void logInfo(String message); +} + +class LoggerServiceImp implements LoggerService { + final Logger logger; + LoggerServiceImp({required this.logger}); + + @override + void logError(String message) => logger.e(message); + @override + void logInfo(String message) => logger.d(message); +} +``` + +### 7.2 FILE: `lib/services/navigation_service.dart` + +```dart +import 'package:flutter/material.dart'; + +class NavigationService { + final GlobalKey navigatorKey = GlobalKey(); + + BuildContext? get context => navigatorKey.currentContext; + + Future push(Route route) => navigatorKey.currentState!.push(route); + + Future pushAndRemoveUntil(Route route, RoutePredicate predicate) => + navigatorKey.currentState!.pushAndRemoveUntil(route, predicate); + + void pop([T? result]) => navigatorKey.currentState!.pop(result); + + void popUntilNamed(String routeName) => + navigatorKey.currentState?.popUntil(ModalRoute.withName(routeName)); + + void replaceAllRoutesAndNavigateTo(String routeName) { + navigatorKey.currentState?.pushNamedAndRemoveUntil(routeName, (route) => false); + } + + void pushAndReplace(String routeName) => + navigatorKey.currentState?.pushReplacementNamed(routeName); + + void pushNamed(String routeName, {Object? arguments}) => + navigatorKey.currentState?.pushNamed(routeName, arguments: arguments); + + Future pushPage({required Widget page, bool fullscreenDialog = false}) => + navigatorKey.currentState!.push( + MaterialPageRoute(builder: (_) => page, fullscreenDialog: fullscreenDialog), + ); +} +``` + +### 7.3 FILE: `lib/services/cache_service.dart` + +```dart +import 'dart:convert'; +import 'package:{{DART_PACKAGE}}/services/logger_service.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +abstract class CacheService { + Future saveString({required String key, required String value}); + Future saveInt({required String key, required int value}); + Future saveBool({required String key, required bool value}); + String? getString({required String key}); + int? getInt({required String key}); + bool? getBool({required String key}); + Future getObject({required String key}); + Future saveObject({required String key, required dynamic value}); + Future remove({required String key}); + Future clear(); +} + +class CacheServiceImp implements CacheService { + final SharedPreferences sharedPreferences; + final LoggerService loggerService; + + CacheServiceImp({required this.sharedPreferences, required this.loggerService}); + + @override + Future saveString({required String key, required String value}) async => await sharedPreferences.setString(key, value); + @override + Future saveInt({required String key, required int value}) async => await sharedPreferences.setInt(key, value); + @override + Future saveBool({required String key, required bool value}) async => await sharedPreferences.setBool(key, value); + @override + String? getString({required String key}) => sharedPreferences.getString(key); + @override + int? getInt({required String key}) => sharedPreferences.getInt(key); + @override + bool? getBool({required String key}) => sharedPreferences.getBool(key); + + @override + Future getObject({required String key}) async { + try { + await sharedPreferences.reload(); + final s = sharedPreferences.getString(key); + return s == null ? null : json.decode(s); + } catch (e) { + loggerService.logError(e.toString()); + return null; + } + } + + @override + Future saveObject({required String key, required dynamic value}) async => + await sharedPreferences.setString(key, json.encode(value)); + @override + Future remove({required String key}) async => await sharedPreferences.remove(key); + @override + Future clear() async => await sharedPreferences.clear(); +} +``` + +### 7.4 FILE: `lib/services/dialog_service.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:{{DART_PACKAGE}}/services/navigation_service.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; + +abstract class DialogService { + Future showErrorBottomSheet({String title, required String message, Function()? onOkPressed}); + Future showConfirmBottomSheet({required String message, required Function() onOkPressed, Function()? onCancelPressed}); +} + +class DialogServiceImp implements DialogService { + final NavigationService navigationService; + bool _isSheetShowing = false; + + DialogServiceImp({required this.navigationService}); + + @override + Future showErrorBottomSheet({String title = "", required String message, Function()? onOkPressed}) async { + if (_isSheetShowing) return; + final context = navigationService.navigatorKey.currentContext; + if (context == null) return; + _isSheetShowing = true; + await showModalBottomSheet( + context: context, + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))), + builder: (_) => Padding( + padding: const EdgeInsets.all(24), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + if (title.isNotEmpty) ...[Text(title, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600)), const SizedBox(height: 12)], + Text(message, textAlign: TextAlign.center), + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom(backgroundColor: AppColors.primaryRedColor), + onPressed: () { Navigator.pop(context); onOkPressed?.call(); }, + child: const Text('OK', style: TextStyle(color: Colors.white)), + ), + ), + ]), + ), + ); + _isSheetShowing = false; + } + + @override + Future showConfirmBottomSheet({required String message, required Function() onOkPressed, Function()? onCancelPressed}) async { + final context = navigationService.navigatorKey.currentContext; + if (context == null) return; + await showModalBottomSheet( + context: context, + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))), + builder: (_) => Padding( + padding: const EdgeInsets.all(24), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + Text(message, textAlign: TextAlign.center), + const SizedBox(height: 24), + Row(children: [ + Expanded(child: OutlinedButton(onPressed: () { Navigator.pop(context); onCancelPressed?.call(); }, child: const Text('Cancel'))), + const SizedBox(width: 12), + Expanded(child: ElevatedButton( + style: ElevatedButton.styleFrom(backgroundColor: AppColors.primaryRedColor), + onPressed: () { Navigator.pop(context); onOkPressed(); }, + child: const Text('OK', style: TextStyle(color: Colors.white)), + )), + ]), + ]), + ), + ); + } +} +``` + +### 7.5 FILE: `lib/services/error_handler_service.dart` + +```dart +import 'package:{{DART_PACKAGE}}/core/exceptions/api_failure.dart'; +import 'package:{{DART_PACKAGE}}/core/utils/loading_utils.dart'; +import 'package:{{DART_PACKAGE}}/services/dialog_service.dart'; +import 'package:{{DART_PACKAGE}}/services/logger_service.dart'; +import 'package:{{DART_PACKAGE}}/services/navigation_service.dart'; +import 'package:{{DART_PACKAGE}}/routes/app_routes.dart'; + +abstract class ErrorHandlerService { + Future handleError({required Failure failure, Function()? onOkPressed, Function(Failure)? onUnHandledFailure, Function(Failure)? onMessageStatusFailure}); +} + +class ErrorHandlerServiceImp implements ErrorHandlerService { + final DialogService dialogService; + final LoggerService loggerService; + final NavigationService navigationService; + + ErrorHandlerServiceImp({required this.dialogService, required this.loggerService, required this.navigationService}); + + @override + Future handleError({required Failure failure, Function()? onOkPressed, Function(Failure)? onUnHandledFailure, Function(Failure)? onMessageStatusFailure}) async { + if (LoadingUtils.isLoading) LoadingUtils.hideFullScreenLoader(); + + if (failure is ServerFailure) { + loggerService.logError("Server: ${failure.message}"); + await _show(failure); + } else if (failure is ConnectivityFailure) { + loggerService.logError("Connectivity: ${failure.message}"); + await _show(failure, title: "No Internet"); + } else if (failure is UnAuthenticatedUserFailure) { + loggerService.logError("Unauth: ${failure.message}"); + await _show(failure, title: "Session Expired", onOk: () => navigationService.replaceAllRoutesAndNavigateTo(AppRoutes.landingScreen)); + } else if (failure is AppUpdateFailure) { + await _show(failure, title: "Update Required"); + } else if (failure is DataParsingFailure) { + loggerService.logError("Parse: ${failure.message}"); + await _show(failure, title: "Data Error"); + } else if (failure is UserIntimationFailure) { + onUnHandledFailure != null ? onUnHandledFailure(failure) : await _show(failure, onOk: onOkPressed); + } else if (failure is MessageStatusFailure) { + onMessageStatusFailure != null ? onMessageStatusFailure(failure) : await _show(failure, onOk: onOkPressed); + } else { + loggerService.logError("Unhandled: $failure"); + await _show(failure, onOk: onOkPressed); + } + } + + Future _show(Failure f, {String? title, Function()? onOk}) async => + await dialogService.showErrorBottomSheet(title: title ?? "", message: f.message, onOkPressed: onOk); +} +``` + +### 7.6 FILE: `lib/services/firebase_service.dart` + +```dart +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:{{DART_PACKAGE}}/core/app_state.dart'; +import 'package:{{DART_PACKAGE}}/services/logger_service.dart'; + +abstract class FirebaseService { + Future getDeviceToken(); +} + +class FirebaseServiceImpl implements FirebaseService { + final FirebaseMessaging firebaseMessaging; + final LoggerService loggerService; + final AppState appState; + + FirebaseServiceImpl({required this.firebaseMessaging, required this.loggerService, required this.appState}); + + @override + Future getDeviceToken() async { + try { + final token = await firebaseMessaging.getToken(); + appState.deviceToken = token ?? ""; + return appState.deviceToken; + } catch (e) { + loggerService.logError(e.toString()); + return ""; + } + } +} +``` + +### 7.7 FILE: `lib/services/notification_service.dart` + +```dart +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:{{DART_PACKAGE}}/services/logger_service.dart'; +import 'package:timezone/data/latest_all.dart' as tz; + +abstract class NotificationService { + Future initialize({Function(String payload)? onNotificationClick}); + Future showNotification({required String title, required String body, String? payload}); + Future cancelAllNotifications(); +} + +class NotificationServiceImp implements NotificationService { + final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin; + final LoggerService loggerService; + + NotificationServiceImp({required this.flutterLocalNotificationsPlugin, required this.loggerService}); + + @override + Future initialize({Function(String payload)? onNotificationClick}) async { + tz.initializeTimeZones(); + const android = AndroidInitializationSettings('app_icon'); + const ios = DarwinInitializationSettings(requestAlertPermission: true, requestBadgePermission: true, requestSoundPermission: true); + await flutterLocalNotificationsPlugin.initialize( + const InitializationSettings(android: android, iOS: ios), + onDidReceiveNotificationResponse: (r) => onNotificationClick?.call(r.payload ?? ''), + ); + } + + @override + Future showNotification({required String title, required String body, String? payload}) async { + const details = NotificationDetails( + android: AndroidNotificationDetails('general', 'General', importance: Importance.high, priority: Priority.high), + iOS: DarwinNotificationDetails(), + ); + await flutterLocalNotificationsPlugin.show(DateTime.now().millisecondsSinceEpoch ~/ 1000, title, body, details, payload: payload); + } + + @override + Future cancelAllNotifications() async => await flutterLocalNotificationsPlugin.cancelAll(); +} +``` + +### 7.8 FILE: `lib/services/analytics/analytics_service.dart` + +```dart +import 'package:firebase_analytics/firebase_analytics.dart'; + +class GAnalytics { + final _analytics = FirebaseAnalytics.instance; + + Future logEvent(String name, {Map? parameters}) async { + try { + await _analytics.logEvent(name: name.trim().toLowerCase(), parameters: parameters?.map((k, v) => MapEntry(k, v as Object))); + } catch (_) {} + } + + Future setUser({String? userId, String? language}) async { + if (userId != null) _analytics.setUserProperty(name: 'userid', value: userId); + if (language != null) _analytics.setUserProperty(name: 'user_language', value: language); + } +} +``` + +--- + +## 8. THEME LAYER + +### 8.1 FILE: `lib/theme/colors.dart` + +```dart +import 'package:flutter/material.dart'; + +class AppColors { + static bool isDarkMode = false; + static const transparent = Colors.transparent; + + static Color get scaffoldBgColor => isDarkMode ? dark.scaffoldBgColor : const Color(0xFFF8F8F8); + static Color get whiteColor => isDarkMode ? dark.whiteColor : const Color(0xFFFFFFFF); + static Color get primaryRedColor => isDarkMode ? dark.primaryRedColor : const Color({{PRIMARY_COLOR}}); + static Color get secondaryLightRedColor => isDarkMode ? dark.secondaryLightRedColor : const Color(0xFFFEE9EA); + static const Color successColor = Color(0xFF18C273); + static Color get textColor => isDarkMode ? dark.textColor : const Color(0xFF2E3039); + static Color get iconColor => isDarkMode ? dark.iconColor : const Color(0xFF2E3039); + static Color get greyColor => isDarkMode ? dark.greyColor : const Color(0xFFEFEFF0); + static Color get textColorLight => isDarkMode ? dark.textColorLight : const Color(0xFF5E5E5E); + static Color get dividerColor => isDarkMode ? dark.dividerColor : const Color(0x40D2D2D2); + static Color get borderGrayColor => isDarkMode ? dark.borderGrayColor : const Color(0x332E3039); + static Color get greyTextColor => isDarkMode ? dark.greyTextColor : const Color(0xFF8F9AA3); + static Color get inputLabelTextColor => isDarkMode ? dark.inputLabelTextColor : const Color(0xFF898A8D); + static Color get errorColor => isDarkMode ? dark.errorColor : const Color(0xFFED1C2B); + static Color get warningColor => isDarkMode ? dark.warningColor : const Color(0xFFFFCC00); + static Color get infoColor => isDarkMode ? dark.infoColor : const Color(0xFF0B85F7); + static Color get shimmerBaseColor => isDarkMode ? dark.shimmerBaseColor : const Color(0xFFE0E0E0); + static Color get shimmerHighlightColor => isDarkMode ? dark.shimmerHighlightColor : const Color(0xFFF5F5F5); + + static Color get blackColor => textColor; + static Color get bgScaffoldColor => scaffoldBgColor; + + static const AppColorsDark dark = AppColorsDark(); +} + +class AppColorsDark { + const AppColorsDark(); + Color get scaffoldBgColor => const Color(0xFF191919); + Color get whiteColor => const Color(0xFF1E1E1E); + Color get primaryRedColor => const Color(0xFFDE5C5D); + Color get secondaryLightRedColor => const Color(0xFF3A1015); + Color get textColor => const Color(0xFFFFFFFF); + Color get iconColor => const Color(0xFFFFFFFF); + Color get greyColor => const Color(0xFF2C2C2E); + Color get textColorLight => const Color(0xFFB0B0B0); + Color get dividerColor => const Color(0x33FFFFFF); + Color get borderGrayColor => const Color(0x55ECECEC); + Color get greyTextColor => const Color(0xFF8F9AA3); + Color get inputLabelTextColor => const Color(0xFF9E9E9E); + Color get errorColor => const Color(0xFFD63D48); + Color get warningColor => const Color(0xFFFFCC00); + Color get infoColor => const Color(0xFF4DA6FF); + Color get shimmerBaseColor => const Color(0xFF2C2C2E); + Color get shimmerHighlightColor => const Color(0xFF3A3A3C); +} +``` + +### 8.2 FILE: `lib/theme/app_theme.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; + +class AppTheme { + static ThemeData getTheme(bool isArabic) => ThemeData( + fontFamily: isArabic ? '{{SECONDARY_FONT}}' : '{{PRIMARY_FONT}}', + primarySwatch: Colors.red, + brightness: Brightness.light, + visualDensity: VisualDensity.adaptivePlatformDensity, + pageTransitionsTheme: const PageTransitionsTheme(builders: { + TargetPlatform.android: ZoomPageTransitionsBuilder(), + TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), + }), + canvasColor: Colors.white, + splashColor: Colors.transparent, + appBarTheme: const AppBarTheme(elevation: 0, systemOverlayStyle: SystemUiOverlayStyle.light, surfaceTintColor: Colors.transparent), + ); + + static ThemeData getDarkTheme(bool isArabic) => ThemeData( + fontFamily: isArabic ? '{{SECONDARY_FONT}}' : '{{PRIMARY_FONT}}', + primarySwatch: Colors.red, + brightness: Brightness.dark, + visualDensity: VisualDensity.adaptivePlatformDensity, + pageTransitionsTheme: const PageTransitionsTheme(builders: { + TargetPlatform.android: ZoomPageTransitionsBuilder(), + TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), + }), + canvasColor: AppColors.dark.scaffoldBgColor, + scaffoldBackgroundColor: AppColors.dark.scaffoldBgColor, + splashColor: Colors.transparent, + appBarTheme: AppBarTheme(color: AppColors.dark.scaffoldBgColor, elevation: 0, systemOverlayStyle: SystemUiOverlayStyle.light, surfaceTintColor: Colors.transparent), + ); +} +``` + +--- + +## 9. EXTENSIONS + +### 9.1 FILE: `lib/extensions/int_extensions.dart` + +```dart +import 'package:flutter/material.dart'; + +extension IntExtensions on int { + Widget get height => SizedBox(height: toDouble()); + Widget get width => SizedBox(width: toDouble()); + Widget get divider => Divider(height: toDouble(), thickness: toDouble(), color: const Color(0x30D2D2D2)); +} +``` + +### 9.2 FILE: `lib/extensions/string_extensions.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:{{DART_PACKAGE}}/core/utils/size_utils.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; + +extension CapExtension on String { + String get inCaps => isEmpty ? '' : '${this[0].toUpperCase()}${substring(1)}'; + String get capitalizeFirstOfEach => trim().isEmpty ? '' : trim().toLowerCase().split(' ').map((s) => s.inCaps).join(' '); +} + +extension StringToWidget on String { + Widget _text(double size, {Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false, bool isUnderLine = false, int? maxLines, TextOverflow? overflow, double letterSpacing = 0}) { + return Text(this, + textAlign: isCenter ? TextAlign.center : null, + maxLines: maxLines, + overflow: overflow, + style: TextStyle(fontSize: size.f, fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: letterSpacing, decoration: isUnderLine ? TextDecoration.underline : null, decorationColor: color ?? AppColors.blackColor), + ); + } + + Widget toText8({Color? color, FontWeight? fontWeight, bool isBold = false, int? maxLines, TextOverflow? overflow}) => _text(8, color: color, fontWeight: fontWeight, isBold: isBold, maxLines: maxLines, overflow: overflow); + Widget toText10({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false, int? maxLines, TextOverflow? overflow}) => _text(10, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter, maxLines: maxLines, overflow: overflow); + Widget toText11({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false, int? maxLines}) => _text(11, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter, maxLines: maxLines); + Widget toText12({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false, int? maxLines, TextOverflow? overflow}) => _text(12, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter, maxLines: maxLines, overflow: overflow); + Widget toText13({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false, int? maxLines, TextOverflow? overflow}) => _text(13, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter, maxLines: maxLines, overflow: overflow); + Widget toText14({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false, int? maxLines, TextOverflow? overflow}) => _text(14, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter, maxLines: maxLines, overflow: overflow); + Widget toText16({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false, int? maxLines, TextOverflow? overflow}) => _text(16, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter, maxLines: maxLines, overflow: overflow); + Widget toText18({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false, int? maxLines}) => _text(18, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter, maxLines: maxLines); + Widget toText20({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false}) => _text(20, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter); + Widget toText24({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false}) => _text(24, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter); + Widget toText30({Color? color, FontWeight? fontWeight, bool isBold = false, bool isCenter = false}) => _text(30, color: color, fontWeight: fontWeight, isBold: isBold, isCenter: isCenter); +} +``` + +### 9.3 FILE: `lib/extensions/widget_extensions.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:shimmer/shimmer.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; + +extension WidgetExtensions on Widget { + Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this); + Widget get expanded => Expanded(child: this); + Widget get center => Center(child: this); + Widget circle(double v) => ClipRRect(borderRadius: BorderRadius.circular(v), child: this); + Widget paddingAll(double v) => Padding(padding: EdgeInsets.all(v), child: this); + Widget paddingSymmetrical(double h, double v) => Padding(padding: EdgeInsets.symmetric(horizontal: h, vertical: v), child: this); + Widget paddingOnly({double left = 0, double right = 0, double top = 0, double bottom = 0}) => Padding(padding: EdgeInsetsDirectional.only(start: left, end: right, top: top, bottom: bottom), child: this); + Widget toShimmer({bool isShow = true}) => isShow ? Shimmer.fromColors(baseColor: AppColors.shimmerBaseColor, highlightColor: AppColors.shimmerHighlightColor, child: this) : this; + Widget objectContainerView({double radius = 15}) => Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration(color: AppColors.whiteColor, borderRadius: BorderRadius.circular(radius), boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.15), blurRadius: 26, offset: const Offset(0, -3))]), + child: this, + ); +} +``` + +### 9.4 FILE: `lib/extensions/context_extensions.dart` + +```dart +import 'package:flutter/material.dart'; + +extension ContextUtils on BuildContext { + double get screenHeight => MediaQuery.of(this).size.height; + double get screenWidth => MediaQuery.of(this).size.width; + ThemeData get theme => Theme.of(this); + TextTheme get textTheme => theme.textTheme; +} + +extension ShowBottomSheetExt on BuildContext { + Future showSheet({required Widget child, bool isScrollControlled = true, bool isDismissible = true}) { + return showModalBottomSheet(context: this, isScrollControlled: isScrollControlled, isDismissible: isDismissible, backgroundColor: Colors.transparent, builder: (_) => child); + } +} +``` + +### 9.5 FILE: `lib/extensions/route_extensions.dart` + +```dart +import 'package:flutter/material.dart'; + +extension NavigationExtensions on BuildContext { + void navigateWithName(String routeName, {Object? arguments}) => Navigator.pushNamed(this, routeName, arguments: arguments); + Future navigateReplaceWithName(String routeName, {Object? arguments}) async => await Navigator.pushReplacementNamed(this, routeName, arguments: arguments); + void navigateAndRemoveAll(String routeName) => Navigator.pushNamedAndRemoveUntil(this, routeName, (route) => false); + void pop() => Navigator.of(this).pop(); + void pushTo(Widget page) => Navigator.push(this, MaterialPageRoute(builder: (_) => page)); +} +``` + +--- + +## 10. WIDGETS — Starter Widgets + +### 10.1 FILE: `lib/widgets/buttons/custom_button.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:{{DART_PACKAGE}}/core/utils/size_utils.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; + +class CustomButton extends StatelessWidget { + final String label; + final VoidCallback? onPressed; + final Color? color; + final Color? textColor; + final double? width; + final bool isOutlined; + final bool isLoading; + + const CustomButton({super.key, required this.label, this.onPressed, this.color, this.textColor, this.width, this.isOutlined = false, this.isLoading = false}); + + @override + Widget build(BuildContext context) { + final bg = color ?? AppColors.primaryRedColor; + return SizedBox( + width: width ?? double.infinity, + height: 48.h, + child: isOutlined + ? OutlinedButton(onPressed: isLoading ? null : onPressed, style: OutlinedButton.styleFrom(side: BorderSide(color: bg), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r))), child: _child(bg)) + : ElevatedButton(onPressed: isLoading ? null : onPressed, style: ElevatedButton.styleFrom(backgroundColor: bg, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r))), child: _child(textColor ?? Colors.white)), + ); + } + + Widget _child(Color c) => isLoading ? SizedBox(height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2, color: c)) : Text(label, style: TextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, color: c)); +} +``` + +### 10.2 FILE: `lib/widgets/routes/fade_page.dart` + +```dart +import 'package:flutter/material.dart'; + +class FadePage extends PageRouteBuilder { + final Widget page; + FadePage({required this.page}) : super( + pageBuilder: (_, __, ___) => page, + transitionsBuilder: (_, a, __, child) => FadeTransition(opacity: a, child: child), + transitionDuration: const Duration(milliseconds: 300), + ); +} +``` + +--- + +## 11. DEPENDENCY INJECTION — `lib/core/dependencies.dart` + +```dart +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:get_it/get_it.dart'; +import 'package:logger/logger.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'package:{{DART_PACKAGE}}/core/api/api_client.dart'; +import 'package:{{DART_PACKAGE}}/core/app_state.dart'; +import 'package:{{DART_PACKAGE}}/services/analytics/analytics_service.dart'; +import 'package:{{DART_PACKAGE}}/services/cache_service.dart'; +import 'package:{{DART_PACKAGE}}/services/dialog_service.dart'; +import 'package:{{DART_PACKAGE}}/services/error_handler_service.dart'; +import 'package:{{DART_PACKAGE}}/services/firebase_service.dart'; +import 'package:{{DART_PACKAGE}}/services/logger_service.dart'; +import 'package:{{DART_PACKAGE}}/services/navigation_service.dart'; +import 'package:{{DART_PACKAGE}}/services/notification_service.dart'; + +final GetIt getIt = GetIt.instance; + +class AppDependencies { + static Future addDependencies() async { + final logger = Logger(printer: PrettyPrinter(methodCount: 2, errorMethodCount: 5, lineLength: 1000, colors: true, printEmojis: true)); + + getIt.registerLazySingleton(() => LoggerServiceImp(logger: logger)); + getIt.registerLazySingleton(() => NavigationService()); + getIt.registerLazySingleton(() => AppState(navigationService: getIt())); + getIt.registerLazySingleton(() => GAnalytics()); + getIt.registerLazySingleton(() => DialogServiceImp(navigationService: getIt())); + getIt.registerLazySingleton(() => ErrorHandlerServiceImp(dialogService: getIt(), loggerService: getIt(), navigationService: getIt())); + + final sp = await SharedPreferences.getInstance(); + getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sp, loggerService: getIt())); + getIt.registerLazySingleton(() => ApiClientImp(appState: getIt())); + getIt.registerLazySingleton(() => FirebaseServiceImpl(firebaseMessaging: FirebaseMessaging.instance, loggerService: getIt(), appState: getIt())); + + final flnp = FlutterLocalNotificationsPlugin(); + getIt.registerLazySingleton(() => NotificationServiceImp(flutterLocalNotificationsPlugin: flnp, loggerService: getIt())); + + // ═══ Register feature repos & ViewModels below as you add them ═══ + } +} +``` + +--- + +## 12. ROUTING — `lib/routes/app_routes.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:{{DART_PACKAGE}}/presentation/home/navigation_screen.dart'; +import 'package:{{DART_PACKAGE}}/splash_page.dart'; + +class AppRoutes { + static const String initialRoute = '/'; + static const String landingScreen = '/landingScreen'; + + // Add route names as you build features: + // static const String loginScreen = '/loginScreen'; + + static Map get routes => { + initialRoute: (_) => const SplashPage(), + landingScreen: (_) => const LandingNavigation(), + }; +} +``` + +--- + +## 13. LOCALIZATION FILES + +### FILE: `assets/langs/en-US.json` + +```json +{ + "appName": "{{APP_NAME}}", + "home": "Home", + "services": "Services", + "medicalFile": "Medical File", + "bookAppointment": "Book Appointment", + "login": "Login", + "register": "Register", + "cancel": "Cancel", + "confirm": "Confirm", + "done": "Done", + "ok": "OK", + "loading": "Loading...", + "noDataAvailable": "No data available", + "noInternetConnection": "No internet connection", + "settings": "Settings", + "language": "Language", + "darkMode": "Dark Mode", + "logout": "Logout", + "search": "Search" +} +``` + +### FILE: `assets/langs/ar-SA.json` + +```json +{ + "appName": "{{APP_NAME}}", + "home": "الرئيسية", + "services": "الخدمات", + "medicalFile": "الملف الطبي", + "bookAppointment": "حجز موعد", + "login": "تسجيل الدخول", + "register": "التسجيل", + "cancel": "إلغاء", + "confirm": "تأكيد", + "done": "تم", + "ok": "حسنا", + "loading": "جاري التحميل...", + "noDataAvailable": "لا توجد بيانات", + "noInternetConnection": "لا يوجد اتصال بالإنترنت", + "settings": "الإعدادات", + "language": "اللغة", + "darkMode": "الوضع الداكن", + "logout": "تسجيل الخروج", + "search": "بحث" +} +``` + +--- + +## 14. PRESENTATION — Starter Screens + +### FILE: `lib/splash_page.dart` + +```dart +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:{{DART_PACKAGE}}/core/api_consts.dart'; +import 'package:{{DART_PACKAGE}}/core/dependencies.dart'; +import 'package:{{DART_PACKAGE}}/presentation/home/navigation_screen.dart'; +import 'package:{{DART_PACKAGE}}/services/notification_service.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; +import 'package:{{DART_PACKAGE}}/widgets/routes/fade_page.dart'; + +class SplashPage extends StatefulWidget { + const SplashPage({super.key}); + @override + State createState() => _SplashPageState(); +} + +class _SplashPageState extends State { + @override + void initState() { + super.initState(); + _init(); + } + + Future _init() async { + ApiConsts.setBackendURLs(); + await getIt.get().initialize(); + Timer(const Duration(seconds: 2), () { + Navigator.of(context).pushReplacement(FadePage(page: const LandingNavigation())); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.whiteColor, + body: Center(child: Text('{{APP_NAME}}', style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: AppColors.primaryRedColor))), + ); + } +} +``` + +### FILE: `lib/presentation/home/navigation_screen.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:{{DART_PACKAGE}}/presentation/home/landing_page.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; + +class LandingNavigation extends StatefulWidget { + const LandingNavigation({super.key}); + @override + State createState() => _LandingNavigationState(); +} + +class _LandingNavigationState extends State { + int _idx = 0; + final _pc = PageController(); + + final _pages = const [ + LandingPage(), + Center(child: Text('Medical File')), + Center(child: Text('Book Appointment')), + Center(child: Text('Services')), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: PageView(controller: _pc, physics: const NeverScrollableScrollPhysics(), children: _pages), + bottomNavigationBar: BottomNavigationBar( + currentIndex: _idx, + type: BottomNavigationBarType.fixed, + selectedItemColor: AppColors.primaryRedColor, + unselectedItemColor: AppColors.greyTextColor, + onTap: (i) { setState(() => _idx = i); _pc.jumpToPage(i); }, + items: const [ + BottomNavigationBarItem(icon: Icon(Icons.home_outlined), activeIcon: Icon(Icons.home), label: 'Home'), + BottomNavigationBarItem(icon: Icon(Icons.folder_outlined), activeIcon: Icon(Icons.folder), label: 'File'), + BottomNavigationBarItem(icon: Icon(Icons.calendar_today_outlined), activeIcon: Icon(Icons.calendar_today), label: 'Book'), + BottomNavigationBarItem(icon: Icon(Icons.grid_view_outlined), activeIcon: Icon(Icons.grid_view), label: 'Services'), + ], + ), + ); + } +} +``` + +### FILE: `lib/presentation/home/landing_page.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:{{DART_PACKAGE}}/extensions/int_extensions.dart'; +import 'package:{{DART_PACKAGE}}/extensions/string_extensions.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; + +class LandingPage extends StatelessWidget { + const LandingPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.scaffoldBgColor, + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + 24.height, + 'Welcome'.toText24(isBold: true), + 8.height, + 'What would you like to do today?'.toText14(color: AppColors.greyTextColor), + 24.height, + Expanded(child: Center(child: 'Home content goes here'.toText16(color: AppColors.textColorLight, isCenter: true))), + ]), + ), + ), + ); + } +} +``` + +--- + +## 15. ENTRY POINT — `lib/main.dart` + +```dart +import 'dart:io'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import 'package:sizer/sizer.dart'; +import 'package:{{DART_PACKAGE}}/core/dependencies.dart'; +import 'package:{{DART_PACKAGE}}/routes/app_routes.dart'; +import 'package:{{DART_PACKAGE}}/services/navigation_service.dart'; +import 'package:{{DART_PACKAGE}}/theme/app_theme.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; + +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) => + super.createHttpClient(context)..badCertificateCallback = (cert, host, port) => true; +} + +Future _init() async { + WidgetsFlutterBinding.ensureInitialized(); + await EasyLocalization.ensureInitialized(); + // Uncomment when Firebase is configured: + // await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + await AppDependencies.addDependencies(); + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + HttpOverrides.global = MyHttpOverrides(); +} + +void main() async { + await _init(); + runApp( + EasyLocalization( + supportedLocales: const [Locale('en', 'US'), Locale('ar', 'SA')], + path: 'assets/langs', + fallbackLocale: const Locale('en', 'US'), + child: MultiProvider( + providers: [ + // ═══ Add ChangeNotifierProviders as you build features ═══ + ], + child: const MyApp(), + ), + ), + ); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return SafeArea( + top: false, + bottom: !Platform.isIOS, + child: LayoutBuilder(builder: (context, constraints) { + return Sizer(builder: (context, orientation, deviceType) { + final isArabic = EasyLocalization.of(context)?.locale.languageCode == "ar"; + return MaterialApp( + title: '{{APP_NAME}}', + debugShowCheckedModeBanner: false, + localizationsDelegates: context.localizationDelegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + initialRoute: AppRoutes.initialRoute, + routes: AppRoutes.routes, + theme: AppTheme.getTheme(isArabic), + darkTheme: AppTheme.getDarkTheme(isArabic), + themeMode: AppColors.isDarkMode ? ThemeMode.dark : ThemeMode.light, + navigatorKey: getIt.get().navigatorKey, + builder: (context, child) => MediaQuery( + data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling, alwaysUse24HourFormat: true), + child: child!, + ), + ); + }); + }), + ); + } +} +``` + +--- + +## 16. FEATURE MODULE TEMPLATE + +When asked to **add a new feature**, create these four files. Replace `{{feature}}` (snake_case) and `{{Feature}}` (PascalCase). + +### `lib/features/{{feature}}/{{feature}}_repo.dart` + +```dart +import 'package:dartz/dartz.dart'; +import 'package:{{DART_PACKAGE}}/core/api/api_client.dart'; +import 'package:{{DART_PACKAGE}}/core/common_models/generic_api_model.dart'; +import 'package:{{DART_PACKAGE}}/core/exceptions/api_failure.dart'; +import 'package:{{DART_PACKAGE}}/services/logger_service.dart'; + +abstract class {{Feature}}Repo { + // Future>>> getItems(); +} + +class {{Feature}}RepoImp implements {{Feature}}Repo { + final ApiClient apiClient; + final LoggerService loggerService; + {{Feature}}RepoImp({required this.loggerService, required this.apiClient}); + + // @override + // Future>>> getItems() async { + // Map body = {}; + // try { + // GenericApiModel>? result; + // Failure? failure; + // await apiClient.post('endpoint', body: body, + // onFailure: (e, s, {messageStatus, failureType}) => failure = failureType, + // onSuccess: (r, s, {messageStatus, errorMessage}) { + // try { result = GenericApiModel(data: (r['Key'] as List).map((e) => YourModel.fromJson(e)).toList()); } + // catch (e) { failure = DataParsingFailure(e.toString()); } + // }); + // if (failure != null) return Left(failure!); + // return Right(result!); + // } catch (e) { return Left(UnknownFailure(e.toString())); } + // } +} +``` + +### `lib/features/{{feature}}/{{feature}}_view_model.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:{{DART_PACKAGE}}/features/{{feature}}/{{feature}}_repo.dart'; +import 'package:{{DART_PACKAGE}}/services/error_handler_service.dart'; +import 'package:{{DART_PACKAGE}}/services/navigation_service.dart'; + +class {{Feature}}ViewModel extends ChangeNotifier { + final {{Feature}}Repo _repo; + final ErrorHandlerService _errorHandler; + final NavigationService _nav; + + {{Feature}}ViewModel({required {{Feature}}Repo repo, required ErrorHandlerService errorHandler, required NavigationService nav}) + : _repo = repo, _errorHandler = errorHandler, _nav = nav; + + bool isLoading = false; + + // void init() { isLoading = true; notifyListeners(); _fetch(); } + // void _fetch() async { + // final r = await _repo.getItems(); + // r.fold((f) { isLoading = false; _errorHandler.handleError(failure: f); notifyListeners(); }, + // (d) { /* items = d.data ?? []; */ isLoading = false; notifyListeners(); }); + // } +} +``` + +### `lib/presentation/{{feature}}/{{feature}}_page.dart` + +```dart +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:{{DART_PACKAGE}}/features/{{feature}}/{{feature}}_view_model.dart'; +import 'package:{{DART_PACKAGE}}/theme/colors.dart'; + +class {{Feature}}Page extends StatefulWidget { + const {{Feature}}Page({super.key}); + @override + State<{{Feature}}Page> createState() => _{{Feature}}PageState(); +} + +class _{{Feature}}PageState extends State<{{Feature}}Page> { + @override + void initState() { + super.initState(); + // Provider.of<{{Feature}}ViewModel>(context, listen: false).init(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.scaffoldBgColor, + appBar: AppBar(title: const Text('{{Feature}}')), + body: Consumer<{{Feature}}ViewModel>( + builder: (_, vm, __) { + if (vm.isLoading) return const Center(child: CircularProgressIndicator()); + return const Center(child: Text('Content here')); + }, + ), + ); + } +} +``` + +### After creating, REGISTER: + +**`dependencies.dart`:** +```dart +getIt.registerLazySingleton<{{Feature}}Repo>(() => {{Feature}}RepoImp(loggerService: getIt(), apiClient: getIt())); +getIt.registerLazySingleton<{{Feature}}ViewModel>(() => {{Feature}}ViewModel(repo: getIt(), errorHandler: getIt(), nav: getIt())); +``` + +**`main.dart` providers list:** +```dart +ChangeNotifierProvider<{{Feature}}ViewModel>(create: (_) => getIt.get<{{Feature}}ViewModel>()), +``` + +**`app_routes.dart`:** +```dart +static const String {{feature}}Page = '/{{feature}}'; +// in routes map: {{feature}}Page: (_) => const {{Feature}}Page(), +``` + +--- + +## 17. RULES — ALWAYS FOLLOW + +1. **Every service/repo = abstract class + implementation.** Never use concrete directly. +2. **All DI in `dependencies.dart`.** Only use `getIt.get()` elsewhere. +3. **All repos return `Future>>`.** +4. **All ViewModels extend `ChangeNotifier`.** Call `notifyListeners()` after state changes. +5. **ViewModels NEVER import widgets.** Use `NavigationService` for navigation. +6. **Pages use `Consumer` or `Provider.of` to read ViewModel state.** +7. **Colors from `AppColors`** — never hardcode hex in widgets. +8. **Text via string extensions** — `'Hello'.toText16()` not `Text('Hello')`. +9. **Spacing via int extensions** — `16.height` not `SizedBox(height: 16)`. +10. **Sizes via responsive extensions** — `16.f`, `16.w`, `16.h`, `16.r`. +11. **Assets via `AppAssets`** — never hardcode paths. +12. **Cache keys in `CacheConst`** — never raw strings for SharedPreferences. +13. **Endpoints in `ApiConsts`** — never hardcode URLs. +14. **Errors through `ErrorHandlerService`** — VMs never show dialogs. +15. **User-facing strings use `.tr()`** from easy_localization. + +--- + +## 18. CHECKLIST — Verify Before Delivering + +- [ ] `flutter pub get` succeeds +- [ ] All imports use `package:{{DART_PACKAGE}}/...` +- [ ] Every file in this spec exists +- [ ] `dependencies.dart` registers all existing services/repos/VMs +- [ ] `main.dart` providers list includes all registered VMs +- [ ] `app_routes.dart` includes all existing pages +- [ ] `pubspec.yaml` declares all existing asset directories +- [ ] Both `en-US.json` and `ar-SA.json` exist +- [ ] No circular imports +- [ ] `AppColors` used everywhere (no raw `Color()` in widgets) +- [ ] Extensions used for text, spacing, widget wrapping + +--- + +*End of specification. Generate all files above. When asked to add a feature, use Section 16.* + diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index f1a0ed0c..71d30372 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -199,8 +199,8 @@ class ApiClientImp implements ApiClient { body['TokenID'] = "@dm!n"; } - body['TokenID'] = "@dm!n"; - body['PatientID'] = 2007395; + // body['TokenID'] = "@dm!n"; + // body['PatientID'] = 2007395; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; // body['SessionID'] = "45786230487560q"; diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index 07cbbde3..4c689ab7 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -106,6 +106,11 @@ class LabViewModel extends ChangeNotifier { notifyListeners(); } + closeAILabResultAnalysis() { + labOrderResponseByAi = null; + notifyListeners(); + } + void setIsSortByClinic(bool value) { isSortByClinic = value; patientLabOrdersViewList = isSortByClinic ? patientLabOrdersByClinic : patientLabOrdersByHospital; diff --git a/lib/presentation/book_appointment/doctor_profile_page.dart b/lib/presentation/book_appointment/doctor_profile_page.dart index 549b8b0d..9fb6ee1d 100644 --- a/lib/presentation/book_appointment/doctor_profile_page.dart +++ b/lib/presentation/book_appointment/doctor_profile_page.dart @@ -1,4 +1,3 @@ - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; @@ -101,18 +100,12 @@ class DoctorProfilePage extends StatelessWidget { children: [ Column( children: [ - Utils.buildSvgWithAssets( - icon: AppAssets.doctor_profile_rating_icon, - width: 48.w, - height: 48.h, - fit: BoxFit.contain, - applyThemeColor: false - ), + Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), SizedBox(height: 16.h), "Ratings".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate .toString() - .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor), + .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), ], ).onPress(() { bookAppointmentsViewModel.getDoctorRatingDetails(); @@ -128,18 +121,12 @@ class DoctorProfilePage extends StatelessWidget { SizedBox(width: 36.w), Column( children: [ - Utils.buildSvgWithAssets( - icon: AppAssets.doctor_profile_reviews_icon, - width: 48.w, - height: 48.h, - fit: BoxFit.contain, - applyThemeColor: false - ), + Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), SizedBox(height: 16.h), "Reviews".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate .toString() - .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor), + .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), ], ).onPress(() { bookAppointmentsViewModel.getDoctorRatingDetails(); diff --git a/lib/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart b/lib/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart index af6c97f8..c883c863 100644 --- a/lib/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart +++ b/lib/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart @@ -164,7 +164,7 @@ class LabResultByClinic extends StatelessWidget { padding: EdgeInsets.only(right: 4.w, left: 4.w), child: Utils.buildSvgWithAssets(icon: AppAssets.aiOverView, width: 16.h, height: 16.h, iconColor: Colors.white), ), - LocaleKeys.generateAiAnalysis.tr(context: context).toText16(isBold: true) + LocaleKeys.generateAiAnalysis.tr(context: context).toText16(isBold: true, color: Colors.white) ], ), ).paddingSymmetrical(24.h, 24.h).onPress(() async { diff --git a/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart b/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart index 7a477761..2c552bc7 100644 --- a/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart +++ b/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart @@ -2,11 +2,14 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +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/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_order_response_by_ai_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'; class AiAnalysisWidget extends StatelessWidget { final LabOrderResponseByAi data; @@ -71,6 +74,14 @@ class AiAnalysisWidget extends StatelessWidget { ), ], ), + SizedBox(height: 16.h), + CustomButton( + height: 50.h, + text: LocaleKeys.close.tr(context: context), + onPressed: () { + getIt.get().closeAILabResultAnalysis(); + }, + ), ], ), ), diff --git a/lib/presentation/lab/lab_results/lab_result_details.dart b/lib/presentation/lab/lab_results/lab_result_details.dart index 8d5d0042..69254f69 100644 --- a/lib/presentation/lab/lab_results/lab_result_details.dart +++ b/lib/presentation/lab/lab_results/lab_result_details.dart @@ -35,97 +35,99 @@ class LabResultDetails extends StatelessWidget { LabViewModel labViewModel = Provider.of(context, listen: false); final appState = getIt.get(); return Scaffold( - body: Column( - children: [ - Expanded( - child: CollapsingListView( - title: LocaleKeys.labResultDetails.tr(context: context), - // aiOverview: () async { - // final _dialogService = getIt.get(); - // await _dialogService.showCommonBottomSheetWithoutH( - // message: LocaleKeys.aiDisclaimer.tr(), - // label: LocaleKeys.consent.tr(), - // okLabel: LocaleKeys.acceptLbl.tr(), - // cancelLabel: LocaleKeys.rejectView.tr(), - // onOkPressed: () { - // context.pop(); - // labViewModel.getAiOverviewSingleLabResult(langId: appState.getLanguageID().toString(), recentLabResult: recentLabResult, loadingText: LocaleKeys.loadingAIAnalysis.tr(context: context)); - // }, - // onCancelPressed: () { - // context.pop(); - // }); - // }, - child: SingleChildScrollView( - child: Column( - spacing: 16.h, - children: [ - LabNameAndStatus(context), - getLabDescription(context), - LabGraph(context), - Selector( - selector: (_, model) => model.labOrderResponseByAi, - builder: (_, aiData, __) { - if (aiData != null) { - return AiAnalysisWidget(data: aiData).paddingOnly(bottom: 16.h); - } - return const SizedBox.shrink(); - }, - ), - ], - ).paddingAll(24.h), + body: Consumer(builder: (context, labVM, child) { + return Column( + children: [ + Expanded( + child: CollapsingListView( + title: LocaleKeys.labResultDetails.tr(context: context), + // aiOverview: () async { + // final _dialogService = getIt.get(); + // await _dialogService.showCommonBottomSheetWithoutH( + // message: LocaleKeys.aiDisclaimer.tr(), + // label: LocaleKeys.consent.tr(), + // okLabel: LocaleKeys.acceptLbl.tr(), + // cancelLabel: LocaleKeys.rejectView.tr(), + // onOkPressed: () { + // context.pop(); + // labViewModel.getAiOverviewSingleLabResult(langId: appState.getLanguageID().toString(), recentLabResult: recentLabResult, loadingText: LocaleKeys.loadingAIAnalysis.tr(context: context)); + // }, + // onCancelPressed: () { + // context.pop(); + // }); + // }, + child: SingleChildScrollView( + child: Column( + spacing: 16.h, + children: [ + LabNameAndStatus(context), + getLabDescription(context), + LabGraph(context), + Selector( + selector: (_, model) => model.labOrderResponseByAi, + builder: (_, aiData, __) { + if (aiData != null) { + return AiAnalysisWidget(data: aiData).paddingOnly(bottom: 16.h); + } + return const SizedBox.shrink(); + }, + ), + ], + ).paddingAll(24.h), + ), ), ), - ), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24.h, - hasShadow: true, - ), - child: Container( - height: 56.h, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12.r), - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - stops: [0.236, 1.0], // 53.6% and 100% - colors: [ - Color(0xFF8A38F5), // Transparent - Color(0xFFE20BBB), // Solid #F8F8F8 - ], - ), + labVM.labOrderResponseByAi == null ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: true, ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(right: 4.w, left: 4.w), - child: Utils.buildSvgWithAssets(icon: AppAssets.aiOverView, width: 16.h, height: 16.h, iconColor: Colors.white), + child: Container( + height: 56.h, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.r), + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + stops: [0.236, 1.0], // 53.6% and 100% + colors: [ + Color(0xFF8A38F5), // Transparent + Color(0xFFE20BBB), // Solid #F8F8F8 + ], ), - LocaleKeys.generateAiAnalysisResult.tr(context: context).toText16(isBold: true) - ], - ), - ).paddingSymmetrical(24.h, 24.h).onPress(() async { - final _dialogService = getIt.get(); - await _dialogService.showCommonBottomSheetWithoutH( - message: LocaleKeys.aiDisclaimer.tr(), - label: LocaleKeys.consent.tr(), - okLabel: LocaleKeys.acceptLbl.tr(), - cancelLabel: LocaleKeys.rejectView.tr(), - onOkPressed: () { - context.pop(); - labViewModel.getAiOverviewSingleLabResult( - langId: appState.getLanguageID().toString(), recentLabResult: recentLabResult, loadingText: LocaleKeys.loadingAIAnalysis.tr(context: context)); - }, - onCancelPressed: () { - context.pop(); - }); - }), - ), - ], - ), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(right: 4.w, left: 4.w), + child: Utils.buildSvgWithAssets(icon: AppAssets.aiOverView, width: 16.h, height: 16.h, iconColor: Colors.white), + ), + LocaleKeys.generateAiAnalysisResult.tr(context: context).toText16(isBold: true, color: Colors.white) + ], + ), + ).paddingSymmetrical(24.h, 24.h).onPress(() async { + final _dialogService = getIt.get(); + await _dialogService.showCommonBottomSheetWithoutH( + message: LocaleKeys.aiDisclaimer.tr(), + label: LocaleKeys.consent.tr(), + okLabel: LocaleKeys.acceptLbl.tr(), + cancelLabel: LocaleKeys.rejectView.tr(), + onOkPressed: () { + context.pop(); + labViewModel.getAiOverviewSingleLabResult( + langId: appState.getLanguageID().toString(), recentLabResult: recentLabResult, loadingText: LocaleKeys.loadingAIAnalysis.tr(context: context)); + }, + onCancelPressed: () { + context.pop(); + }); + }), + ) : SizedBox.shrink(), + ], + ); + }), ); } From 08928ddd289d22b2b592ea79284a9f7b4e4b188f Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 16 Mar 2026 14:32:07 +0300 Subject: [PATCH 19/33] Habib Wallet updates --- assets/langs/translations.json | 6290 +++++++++++++++++ lib/core/api/api_client.dart | 18 +- .../habib_wallet/habib_wallet_view_model.dart | 2 + .../habib_wallet/habib_wallet_page.dart | 12 +- .../ai_analysis_widget.dart | 2 + 5 files changed, 6310 insertions(+), 14 deletions(-) create mode 100644 assets/langs/translations.json diff --git a/assets/langs/translations.json b/assets/langs/translations.json new file mode 100644 index 00000000..9750d779 --- /dev/null +++ b/assets/langs/translations.json @@ -0,0 +1,6290 @@ +{ + "english": { + "en": "English", + "ar": "الإنجليزية" + }, + "arabic": { + "en": "Arabic", + "ar": "العربية" + }, + "login": { + "en": "Login", + "ar": "تسجيل الدخول" + }, + "noDataAvailable": { + "en": "No Data Available", + "ar": "لا توجد بيانات متاحة" + }, + "confirm": { + "en": "Confirm", + "ar": "تأكيد" + }, + "loadingText": { + "en": "Loading, please wait...", + "ar": "جاري التحميل، يرجى الانتظار..." + }, + "kilometerUnit": { + "en": "KM", + "ar": "كم" + }, + "dashboardScreenToolbarTitle": { + "en": "Home", + "ar": "الرئيسية" + }, + "settings": { + "en": "Settings", + "ar": "الإعدادات" + }, + "language": { + "en": "App Language", + "ar": "لغة التطبيق" + }, + "lanEnglish": { + "en": "English", + "ar": "الإنجليزية" + }, + "lanArabic": { + "en": "العربية", + "ar": "العربية" + }, + "cancel": { + "en": "Cancel", + "ar": "إلغاء" + }, + "done": { + "en": "Done", + "ar": "تم" + }, + "replay2": { + "en": "Replay", + "ar": "إعادة التشغيل" + }, + "home": { + "en": "Home", + "ar": "الرئيسية" + }, + "services": { + "en": "SERVICES", + "ar": "الخدمات" + }, + "mySchedule": { + "en": "My Schedule", + "ar": "جدولي" + }, + "logout": { + "en": "Logout", + "ar": "تسجيل الخروج" + }, + "respirationRate": { + "en": "Respiration Rate", + "ar": "معدل التنفس" + }, + "bookAppo": { + "en": "Book Appointment", + "ar": "حجز موعد" + }, + "searchBy": { + "en": "Search By:", + "ar": "البحث بواسطة:" + }, + "clinic": { + "en": "Clinic", + "ar": "عيادة" + }, + "byClinic": { + "en": "By Clinic", + "ar": "حسب العيادة" + }, + "hospital": { + "en": "Hospital", + "ar": "مستشفى" + }, + "byHospital": { + "en": "By Hospital", + "ar": "حسب المستشفى" + }, + "name": { + "en": "Name", + "ar": "الاسم" + }, + "doctor": { + "en": "Doctor", + "ar": "طبيب" + }, + "clinicName": { + "en": "Clinic Name", + "ar": "اسم العيادة" + }, + "hospitalName": { + "en": "Hospital Name", + "ar": "اسم المستشفى" + }, + "noClinicFound": { + "en": "No Clinic Found", + "ar": "لم يتم العثور على عيادة" + }, + "doctorName": { + "en": "Doctor Name", + "ar": "اسم الطبيب" + }, + "nearestAppo": { + "en": "Nearest Appointment", + "ar": "أقرب موعد" + }, + "searchByDocText": { + "en": "Type the name of the doctor to help you find him", + "ar": "اكتب اسم الطبيب لمساعدتك في العثور عليه" + }, + "enterDocName": { + "en": "Enter Doctor name", + "ar": "أدخل اسم الطبيب" + }, + "search": { + "en": "Search", + "ar": "بحث" + }, + "noResultFound": { + "en": "No Result Found", + "ar": "لم يتم العثور على نتائج" + }, + "noSearchResultFound": { + "en": "No Result Found", + "ar": "لم يتم العثور على نتائج" + }, + "pleaseEnterProductName": { + "en": "Please Enter Product Name", + "ar": "يرجى إدخال اسم المنتج" + }, + "bookNow": { + "en": "Book Now", + "ar": "احجز الآن" + }, + "docInfo": { + "en": "Doctor Information", + "ar": "معلومات الطبيب" + }, + "appoInfo": { + "en": "Appointment Information", + "ar": "معلومات الموعد" + }, + "availableAppo": { + "en": "Available Appointments", + "ar": "المواعيد المتاحة" + }, + "gender": { + "en": "Gender", + "ar": "الجنس" + }, + "nationality": { + "en": "Nationality", + "ar": "الجنسية" + }, + "neverWait": { + "en": "Never wait in queue", + "ar": "لا تنتظر في الطابور أبدًا" + }, + "reminderTitle": { + "en": "You have appointment with Dr. ", + "ar": "لديك موعد مع الدكتور." + }, + "appointmentCalendar": { + "en": "Would you like to set a reminder for this appointment in your calendar?", + "ar": "هل ترغب في تعيين تذكير لهذا الموعد في التقويم الخاص بك؟" + }, + "appointmentSuccess": { + "en": "Appointment is successfully booked", + "ar": "تم حجز الموعد بنجاح" + }, + "docQualifications": { + "en": "Doctor Qualifications", + "ar": "مؤهلات الطبيب" + }, + "pressAgain": { + "en": "Press again to exit the app", + "ar": "اضغط مرة أخرى للخروج من التطبيق" + }, + "laserMaxLimitReach": { + "en": "Maximum limit is 90 minutes", + "ar": "الحد الأقصى هو 90 دقيقة" + }, + "confirmAppoHeading": { + "en": "Kindly review your Appointment", + "ar": "يرجى مراجعة موعدك" + }, + "patientInfo": { + "en": "Patient Information", + "ar": "معلومات المريض" + }, + "doctorFilter": { + "en": "Doctors will be filtered based on your gender and age", + "ar": "سيتم تصفية الأطباء بناءً على جنسك وعمرك" + }, + "bookSuccess": { + "en": "Book Success", + "ar": "تم الحجز بنجاح" + }, + "patientShare": { + "en": "Patient Share", + "ar": "نسبة المريض" + }, + "patientShareWithTax": { + "en": "Patient Share with Tax", + "ar": "نسبة المريض مع الضريبة" + }, + "confirmAppo": { + "en": "Confirm Appointment", + "ar": "تأكيد الموعد" + }, + "confirmLiveCare": { + "en": "Confirm LiveCare", + "ar": "تأكيد ال لايف كير" + }, + "waitingForDoctor": { + "en": "Waiting for doctor", + "ar": "في انتظار الطبيب" + }, + "appointment": { + "en": "Appointment", + "ar": "موعد" + }, + "confirmLater": { + "en": "Confirm Later", + "ar": "تأكيد لاحقًا" + }, + "todoList": { + "en": "Todo List", + "ar": "قائمة المهام" + }, + "appoActions": { + "en": "Appointment Actions", + "ar": "إجراءات الموعد" + }, + "date": { + "en": "Date", + "ar": "التاريخ" + }, + "time": { + "en": "Time", + "ar": "الوقت" + }, + "pendingPayment": { + "en": "Pending for payment", + "ar": "معلق للدفع" + }, + "payNow": { + "en": "Pay Now", + "ar": "ادفع الآن" + }, + "viewQR": { + "en": "View QR Code", + "ar": "عرض رمز الاستجابة السريعة" + }, + "instruction": { + "en": "Instructions", + "ar": "تعليمات" + }, + "livecare": { + "en": "LiveCare", + "ar": "لايف كير" + }, + "livecareAppo": { + "en": "LiveCare Appointment", + "ar": "موعد لايف كير" + }, + "agreeTo": { + "en": "I agree to the", + "ar": "أوافق على" + }, + "termsConditoins": { + "en": "Terms and Conditions", + "ar": "الشروط والأحكام" + }, + "cancelAppoMsg": { + "en": "Are you sure you want to cancel this appointment?", + "ar": "هل أنت متأكد أنك تريد إلغاء هذا الموعد؟" + }, + "changePayment": { + "en": "Change Payment Method", + "ar": "تغيير طريقة الدفع" + }, + "upcomingNoAction": { + "en": "No Action Required", + "ar": "لا يتطلب أي إجراء" + }, + "upcomingConfirm": { + "en": "Please confirm the appointment to avoid cancellation", + "ar": "يرجى تأكيد الموعد لتجنب الإلغاء" + }, + "bookSuccessConfirmMore2412": { + "en": "The online payment process will be available 24 hours before the appointment.", + "ar": "ستكون عملية الدفع عبر الإنترنت متاحة قبل 24 ساعة من الموعد." + }, + "upcomingPaymentPending": { + "en": "Online Payment will be Activated before 24 Hours of Appointment Time", + "ar": "سيتم تفعيل الدفع عبر الإنترنت قبل 24 ساعة من موعد الموعد" + }, + "upcomingPaymentNow": { + "en": "Pay Online now to avoid long waiting queue", + "ar": "ادفع عبر الإنترنت الآن لتجنب الانتظار الطويل" + }, + "upcomingQR": { + "en": "Use the QR Code to Check-In in hospital", + "ar": "استخدم رمز الاستجابة السريعة لتسجيل الوصول في المستشفى" + }, + "upcomingVirtual": { + "en": "This is a virtual appointment, Please adhere to the instructions for a seamless experience.", + "ar": "هذا موعد افتراضي، يرجى الالتزام بالتعليمات لتجربة سلسة." + }, + "upcomingLivecare": { + "en": "This is a LiveCare appointment", + "ar": "هذا موعد لايف كير" + }, + "upcomingDetails": { + "en": "More Details", + "ar": "المزيد من التفاصيل" + }, + "reschedule": { + "en": "Reschedule", + "ar": "إعادة جدولة" + }, + "raise": { + "en": "Raise", + "ar": "رفع" + }, + "complaint": { + "en": "Complaint", + "ar": "شكوى" + }, + "add": { + "en": "Add", + "ar": "إضافة" + }, + "reminder": { + "en": "Reminder", + "ar": "تذكير" + }, + "location": { + "en": "Locations", + "ar": "المواقع" + }, + "online": { + "en": "Online", + "ar": "عبر الإنترنت" + }, + "payment": { + "en": "Payment", + "ar": "الدفع" + }, + "onlinePayment": { + "en": "Online", + "ar": "عبر الإنترنت" + }, + "onlinePaymentSubtitle": { + "en": "Payment", + "ar": "الدفع" + }, + "cancelNocaps": { + "en": "Cancel", + "ar": "إلغاء" + }, + "setReminder": { + "en": "Set Reminder", + "ar": "ضبط تذكير" + }, + "nationalIdNumber": { + "en": "National ID Number", + "ar": "رقم الهوية الوطنية" + }, + "medicalFileNumber": { + "en": "Medical File Number", + "ar": "رقم الملف الطبي" + }, + "loginregister": { + "en": "Login / Register", + "ar": "تسجيل الدخول / التسجيل" + }, + "poweredBy": { + "en": "Powered by", + "ar": "مدعوم من" + }, + "welcome": { + "en": "Welcome", + "ar": "مرحبًا" + }, + "welcomeToDrSulaiman": { + "en": "Welcome to Dr. Sulaiman Al Habib Medical Group", + "ar": "مرحباً بكم في مجموعة الدكتور سليمان الحبيب الطبية" + }, + "patientApp": { + "en": "Patient App", + "ar": "تطبيق المريض" + }, + "welcomeText": { + "en": "Dr. Sulaiman Al Habib Mobile Application", + "ar": "تطبيق الدكتور سليمان الحبيب للهاتف المحمول" + }, + "drSulaimanText": { + "en": "Dr. Sulaiman Al Habib", + "ar": "الدكتور سليمان الحبيب" + }, + "welcomeText2": { + "en": "Have you previously visited the hospitals or medical centers of Dr. Sulaiman Al Habib?", + "ar": "هل زرت مستشفيات أو مراكز الدكتور سليمان الحبيب من قبل؟" + }, + "yes": { + "en": "Yes", + "ar": "نعم" + }, + "no": { + "en": "No", + "ar": "لا" + }, + "logintyperadio": { + "en": " Choose from the below options to login to your medical file.", + "ar": "اختر من الخيارات أدناه لتسجيل الدخول إلى ملفك الطبي." + }, + "registernow": { + "en": "Register Now", + "ar": "سجل الآن" + }, + "nationalID": { + "en": "Enter the Identification Number", + "ar": "أدخل رقم الهوية" + }, + "nationalId": { + "en": "National ID", + "ar": "الهوية الوطنية" + }, + "fileNo": { + "en": "File Number", + "ar": "رقم الملف" + }, + "fileno": { + "en": "File No", + "ar": "رقم الملف" + }, + "forgotFileNo": { + "en": "Forgot file Number?", + "ar": "نسيت رقم الملف؟" + }, + "forgotFileNoTitle": { + "en": "Forgot medical file", + "ar": "نسيت الملف الطبي" + }, + "enterNationalId": { + "en": "Please enter mobile number and identification number", + "ar": "يرجى إدخال رقم الهاتف المحمول ورقم الهوية" + }, + "profileInfo": { + "en": "Please enter profile information", + "ar": "يرجى إدخال معلومات الملف الشخصي" + }, + "submit": { + "en": "Submit", + "ar": "إرسال" + }, + "forgotDesc": { + "en": "Enter the mobile number to receive the Medical File Number via SMS", + "ar": "أدخل رقم الهاتف المحمول لاستلام رقم الملف الطبي عبر الرسائل القصيرة" + }, + "dob": { + "en": "Birth Date:", + "ar": "تاريخ الميلاد:" + }, + "hijriDate": { + "en": "Hijri Date", + "ar": "التاريخ الهجري" + }, + "gregorianDate": { + "en": "Gregorian Date", + "ar": "التاريخ الميلادي" + }, + "verifyLoginWith": { + "en": "Please choose one of the following options to verify", + "ar": "يرجى اختيار واحدة من الخيارات التالية للتحقق" + }, + "registerUser": { + "en": "Register", + "ar": "تسجيل" + }, + "verifyWithFingerprint": { + "en": "Biometric", + "ar": "البيومترية" + }, + "verifyWithFaceid": { + "en": "Face ID", + "ar": "معرف الوجه" + }, + "verifyWithSms": { + "en": "SMS", + "ar": "رسالة قصيرة" + }, + "verifyWithWhatsapp": { + "en": "Whatsapp", + "ar": "واتساب" + }, + "verifyThrough": { + "en": "Verify Through", + "ar": "التحقق من خلال" + }, + "lastLogin": { + "en": "LAST LOGIN AT:", + "ar": "آخر تسجيل دخول في:" + }, + "lastLoginWith": { + "en": "VERIFICATION TYPE:", + "ar": "نوع التحقق:" + }, + "verifyFingerprint": { + "en": "To activate the fingerprint login service, please verify data by using one of the following options.", + "ar": "لتفعيل خدمة تسجيل الدخول ببصمة الإصبع، يرجى التحقق من البيانات باستخدام واحدة من الخيارات التالية." + }, + "searchMedicine": { + "en": "Search Medicine", + "ar": "ابحث عن دواء" + }, + "pharmaciesList": { + "en": "Pharmacies List", + "ar": "قائمة الصيدليات" + }, + "searchMedicineHere": { + "en": "Search Medicine Here", + "ar": "ابحث عن دواء هنا" + }, + "description": { + "en": "Description", + "ar": "الوصف" + }, + "howToUse": { + "en": "How to Use", + "ar": "كيفية الاستخدام" + }, + "price": { + "en": "Price", + "ar": "السعر" + }, + "youCanFindItIn": { + "en": "You can find it in", + "ar": "يمكنك العثور عليه في" + }, + "pleaseEnterMedicineName": { + "en": "Please Enter Medicine Name", + "ar": "يرجى إدخال اسم الدواء" + }, + "verificationMessage": { + "en": "Please enter the Verification Code sent to", + "ar": "يرجى إدخال رمز التحقق المرسل إلى" + }, + "validationMessage": { + "en": "The verification code expires in", + "ar": "ينتهي رمز التحقق في" + }, + "notification": { + "en": "Notifications", + "ar": "الإشعارات" + }, + "appSettings": { + "en": "App Settings", + "ar": "إعدادات التطبيق" + }, + "rateApp": { + "en": "Rate Our App", + "ar": "قيم تطبيقنا" + }, + "before": { + "en": "Before", + "ar": "قبل" + }, + "minute": { + "en": "Minutes", + "ar": "دقائق" + }, + "hour": { + "en": "Hour", + "ar": "ساعة" + }, + "reminderSuccess": { + "en": "The reminder has been added successfully", + "ar": "تمت إضافة التذكير بنجاح" + }, + "reminderCancelSuccess": { + "en": "The reminder has been cancelled successfully", + "ar": "تم إلغاء التذكير بنجاح" + }, + "patientShareToDo": { + "en": "Amount before tax: ", + "ar": "المبلغ قبل الضريبة: " + }, + "patientTaxToDo": { + "en": "Tax amount: ", + "ar": "قيمة الضريبة: " + }, + "patientShareTotalToDo": { + "en": "Total amount due: ", + "ar": "إجمالي المبلغ المستحق: " + }, + "paymentMethod": { + "en": "Payment Method", + "ar": "طريقة الدفع" + }, + "noNeedToWaitInLine": { + "en": "No need to stand in line.", + "ar": "لا حاجة للانتظار في الطابور." + }, + "useQRAppoAttend": { + "en": "Use the QR code to register the appointment attendance.", + "ar": "استخدم رمز الاستجابة السريعة لتسجيل حضور الموعد." + }, + "passQRAppoAttend": { + "en": "Pass the QR code through the attendance devices available in the Hospital.", + "ar": "مرر رمز الاستجابة السريعة عبر أجهزة الحضور المتاحة في المستشفى." + }, + "sitWaitingQR": { + "en": "Sit in the waiting rooms until called by the nurse.", + "ar": "اجلس في غرف الانتظار حتى يتم استدعاؤك من قبل الممرضة." + }, + "attendRegisterCode": { + "en": "Attendance registration code", + "ar": "رمز تسجيل الحضور" + }, + "scanQRHospital": { + "en": "Approach the Online Check-In board in the hospital & scan via NFC or QR Code to Check-In", + "ar": "توجّه إلى لوحة تسجيل الوصول الإلكتروني في المستشفى، وقم بالمسح عبر تقنية NFC أو رمز الاستجابة السريعة (QR) لإتمام تسجيل الوصول." + }, + "scanNFC": { + "en": "Scan NFC to Check-In", + "ar": "امسح NFC لتسجيل الوصول" + }, + "sendEmail": { + "en": "Send Email", + "ar": "إرسال بريد إلكتروني" + }, + "success": { + "en": "Done successfully", + "ar": "تم بنجاح" + }, + "emailSentSuccessfully": { + "en": "Email Sent Successfully", + "ar": "تم إرسال البريد الإلكتروني بنجاح" + }, + "emailSentError": { + "en": "Error Sending Email", + "ar": "خطأ في إرسال البريد الإلكتروني" + }, + "close": { + "en": "Close", + "ar": "إغلاق" + }, + "closeIt": { + "en": "Close", + "ar": "أغلق" + }, + "booked": { + "en": "Booked", + "ar": "محجوز" + }, + "confirmed": { + "en": "Confirmed", + "ar": "مؤكد" + }, + "arrived": { + "en": "Arrived", + "ar": "وصل" + }, + "payNowBookSuccess": { + "en": "Pay now via Al Habib App", + "ar": "ادفع الآن عبر تطبيق الحبيب" + }, + "payNowBookSuccesstext1": { + "en": "Pay Now using online payment service from secure payment gateways", + "ar": "ادفع الآن باستخدام خدمة الدفع عبر الإنترنت من بوابات الدفع الآمنة" + }, + "payNowBookSuccesstext2": { + "en": "You can also Pay Later via online payment or in Hospital", + "ar": "يمكنك أيضًا الدفع لاحقًا عبر الدفع الإلكتروني أو في المستشفى." + }, + "payLater": { + "en": "Pay Later", + "ar": "ادفع لاحقًا" + }, + "askDocNotAllowed": { + "en": "This service will be available for last 15 days’ doctor Visit only", + "ar": "هذه الخدمة ستكون متاحة فقط لزيارة الطبيب قبل 15 يومًا" + }, + "moreVerify": { + "en": "More Verification Options", + "ar": "خيارات تحقق إضافية" + }, + "welcomeBack": { + "en": "Welcome back!", + "ar": "مرحبًا بعودتك!" + }, + "accountInfo": { + "en": "Would you like to login with current username?", + "ar": "هل ترغب في تسجيل الدخول باستخدام اسم المستخدم الحالي؟" + }, + "anotherAcc": { + "en": "Use Another Account", + "ar": "استخدم حسابًا آخر" + }, + "next": { + "en": "Next", + "ar": "التالي" + }, + "firstName": { + "en": "First Name", + "ar": "الاسم الأول" + }, + "middleName": { + "en": "Middle Name", + "ar": "اسم الأب" + }, + "lastName": { + "en": "Last Name", + "ar": "اسم العائلة" + }, + "female": { + "en": "Female", + "ar": "أنثى" + }, + "male": { + "en": "Male", + "ar": "ذكر" + }, + "preferredLanguage": { + "en": "Preferred Language *", + "ar": "اللغة المفضلة *" + }, + "locationsRegister": { + "en": "Where do you want to create this file?", + "ar": "أين ترغب في إنشاء هذا الملف؟" + }, + "ksa": { + "en": "KSA", + "ar": "السعودية" + }, + "dubai": { + "en": "Dubai", + "ar": "دبي" + }, + "enterEmail": { + "en": "Please Enter Email", + "ar": "يرجى إدخال البريد الإلكتروني" + }, + "family": { + "en": "My Family", + "ar": "عائلتي" + }, + "familyTitle": { + "en": "My Family Files", + "ar": "ملفات عائلتي" + }, + "myFamily": { + "en": "MY FAMILY", + "ar": "عائلتي" + }, + "addNewMember": { + "en": "Add Family Member", + "ar": "إضافة فرد جديد للعائلة" + }, + "sentRequests": { + "en": "Sent Requests", + "ar": "الطلبات المرسلة" + }, + "recievedRequests": { + "en": "Recieved Requests", + "ar": "الطلبات المستلمة" + }, + "manageFiles": { + "en": "Manage Family Files", + "ar": "إدارة ملفات العائلة" + }, + "oxygenation": { + "en": "Oxygenation", + "ar": "تشبع الأكسجين" + }, + "bodyMeasurements": { + "en": "body Mass Index", + "ar": "مؤشر كتلة الجسم" + }, + "temperature": { + "en": "Temperature", + "ar": "درجة الحرارة" + }, + "pulse": { + "en": "Pulse", + "ar": "النبض" + }, + "respiration": { + "en": "Respiration", + "ar": "التنفس" + }, + "bloodPressure": { + "en": "Blood Pressure", + "ar": "ضغط الدم" + }, + "painScale": { + "en": "Pain Scale", + "ar": "مقياس الألم" + }, + "weight": { + "en": "Weight", + "ar": "الوزن" + }, + "height": { + "en": "Height", + "ar": "الطول" + }, + "heart": { + "en": "Heart Rate", + "ar": "معدل ضربات القلب" + }, + "heightUnit": { + "en": "height unit", + "ar": "وحدة الطول" + }, + "weightUnit": { + "en": "Weight Unit", + "ar": "وحدة الوزن" + }, + "unit": { + "en": "Unit", + "ar": "الوحدة" + }, + "request": { + "en": "Request", + "ar": "طلب" + }, + "memberName": { + "en": "Member Name", + "ar": "اسم العضو" + }, + "switchLogin": { + "en": "Switch", + "ar": "تبديل" + }, + "removeMember": { + "en": "Remove", + "ar": "إزالة" + }, + "allowView": { + "en": "Allow", + "ar": "السماح" + }, + "rejectView": { + "en": "Reject", + "ar": "رفض" + }, + "deleteView": { + "en": "Delete", + "ar": "حذف" + }, + "approvals": { + "en": "Approvals", + "ar": "الموافقات" + }, + "approvalNo": { + "en": "Approval No:", + "ar": "رقم الموافقة:" + }, + "companyName": { + "en": "Company Name:", + "ar": "اسم الشركة:" + }, + "receiptOn": { + "en": "Receipt on:", + "ar": "الإيصال على:" + }, + "expiryDate": { + "en": "Expiry Date:", + "ar": "تاريخ الانتهاء:" + }, + "expiryPoints": { + "en": "Expired", + "ar": "منتهي الصلاحية" + }, + "expiryOn": { + "en": "Expiry on:", + "ar": "ينتهي في:" + }, + "procedureName": { + "en": "Procedure Name:", + "ar": "اسم الإجراء:" + }, + "procedure": { + "en": "Procedure", + "ar": "الإجراء" + }, + "procedureStatus": { + "en": "Procedure Status: ", + "ar": "حالة الإجراء: " + }, + "usageStatus": { + "en": "Usage Status", + "ar": "حالة الاستخدام" + }, + "unusedCount": { + "en": "Unused Count:", + "ar": "عدد غير المستخدم:" + }, + "totalApproval": { + "en": "Total approval unused", + "ar": "إجمالي الموافقة غير المستخدمة" + }, + "category": { + "en": "Category: ", + "ar": "الفئة: " + }, + "expirationDate": { + "en": "Expiration Date: ", + "ar": "تاريخ انتهاء الصلاحية: " + }, + "patientCard": { + "en": "Patient Card ID: ", + "ar": "رقم بطاقة المريض: " + }, + "policyNumber": { + "en": "Policy Number: ", + "ar": "رقم الوثيقة: " + }, + "seeDetails": { + "en": "SEE DETAILS", + "ar": "عرض التفاصيل" + }, + "insuranceCards": { + "en": "Insurance Cards", + "ar": "بطاقات التأمين" + }, + "requestType": { + "en": "Request Type", + "ar": "نوع الطلب" + }, + "registerInfoFamily": { + "en": "How would like to add the new member?", + "ar": "كيف تود إضافة عضو جديد؟" + }, + "removeFamilyMember": { + "en": "Remove this member?", + "ar": "هل تريد إزالة هذا العضو؟" + }, + "myMedicalFile": { + "en": "My Medical File", + "ar": "ملفي الطبي" + }, + "myMedicalFileSubTitle": { + "en": "All your medical records", + "ar": "جميع سجلاتك الطبية" + }, + "viewMore": { + "en": "View More", + "ar": "عرض المزيد" + }, + "homeHealthCareService": { + "en": "Home Health Care Service", + "ar": "خدمة الرعاية الصحية المنزلية" + }, + "onlinePharmacy": { + "en": "Online Pharmacy", + "ar": "الصيدلية الإلكترونية" + }, + "emergencyService": { + "en": "Emergency Service", + "ar": "خدمة الطوارئ" + }, + "onlinePaymentService": { + "en": "Online Payment Service", + "ar": "خدمة الدفع عبر الإنترنت" + }, + "offersAndPackages": { + "en": "Online transfer request", + "ar": "طلب تحويل عبر الإنترنت" + }, + "comprehensiveMedicalCheckup": { + "en": "Comprehensive Medical Check-up", + "ar": "فحص طبي شامل" + }, + "hmgService": { + "en": "HMG Service", + "ar": "خدمة HMG" + }, + "viewAllHabibMedicalService": { + "en": "View All Habib Medical Service", + "ar": "عرض جميع خدمات الحبيب الطبية" + }, + "viewAll": { + "en": "View All", + "ar": "عرض الكل" + }, + "view": { + "en": "View", + "ar": "عرض" + }, + "contactUs": { + "en": "Contact Us", + "ar": "اتصل بنا" + }, + "contactUsLocation": { + "en": "P.O.Box: 91877 - Riyadh 11643, King Fahad Road - Olaya - Kingdom of Saudi Arabia", + "ar": "ص.ب: 91877 - الرياض 11643، طريق الملك فهد - العليا - المملكة العربية السعودية" + }, + "contactUsTime": { + "en": "Saturday - Wednesday 8:00 AM - 10 PM, Thursday 8:00 AM- 8:00 PM, Friday 2:00 PM - 8:00 PM", + "ar": "السبت - الأربعاء 8:00 صباحًا - 10 مساءً، الخميس 8:00 صباحًا- 8:00 مساءً، الجمعة 2:00 مساءً - 8:00 مساءً" + }, + "viewAllWaysReachUs": { + "en": "View All Ways Reach Us", + "ar": "عرض جميع طرق التواصل معنا" + }, + "medicalProfile": { + "en": "Medical Profile", + "ar": "الملف الطبي" + }, + "consultation": { + "en": "Consultation", + "ar": "استشارة" + }, + "logs": { + "en": "Logs", + "ar": "السجلات" + }, + "textToSpeech": { + "en": "How May I Help You?", + "ar": "كيف يمكنني مساعدتك؟" + }, + "locationDialogMessage": { + "en": "Allow the HMG app to access your location will assist you in showing the hospitals according to the nearest to you.", + "ar": "السماح لتطبيق HMG بالوصول إلى موقعك سيساعدك في عرض المستشفيات الأقرب إليك." + }, + "userViewRequester": { + "en": "User Wants to View Your Medical File", + "ar": "يريد المستخدم عرض ملفك الطبي" + }, + "userView": { + "en": "User Can View Your Medical File", + "ar": "يمكن للمستخدم عرض ملفك الطبي" + }, + "parking": { + "en": "Parking", + "ar": "موقف السيارات" + }, + "alhabiServices": { + "en": "HMG Service", + "ar": "خدمة HMG" + }, + "parkingTitle": { + "en": "Car service, car service, service to save parking information, return to it later, 1- By clicking on (Read the code), save the parking data. 2- By clicking on the button (view my car park), it shows you the car’s location in Google Maps. 3- Read another position by pressing the Clear Position Data button.", + "ar": "خدمة السيارة، خدمة السيارة، خدمة لحفظ معلومات الموقف، العودة إليها لاحقًا، 1- من خلال النقر على (قراءة الرمز)، حفظ بيانات الموقف. 2- من خلال النقر على زر (عرض موقف سيارتي)، يظهر لك موقع السيارة في خرائط Google. 3- قراءة موضع آخر بالضغط على زر مسح بيانات الموضع." + }, + "parkingDescription": { + "en": "Parking service is for you to scan the car location so you can find it easy on you way out. click on (scan parking) button to save the parking location, then (show my park) button will appear to show you the way for the parking. if you want to rescan parking QR just click on (Clear My Data).", + "ar": "خدمة المواقف هي لك لمسح موقع السيارة حتى تتمكن من العثور عليها بسهولة عند مغادرتك. انقر على زر (مسح الموقف) لحفظ موقع الموقف، ثم سيظهر زر (عرض موقفي) لإظهار الطريق إلى الموقف. إذا كنت ترغب في إعادة مسح موقف السيارة QR فقط انقر على (مسح بياناتي)." + }, + "appointments": { + "en": "Appointments", + "ar": "المواعيد" + }, + "all2": { + "en": "All", + "ar": "الكل" + }, + "checkinOption": { + "en": "Check-In", + "ar": "تسجيل الوصول" + }, + "readBarcode": { + "en": "Read Barcode", + "ar": "قراءة الكود" + }, + "showMyPark": { + "en": "Show My Park", + "ar": "عرض الموقف" + }, + "clearMyData": { + "en": "Clear My Data", + "ar": "امسح البيانات" + }, + "floor": { + "en": "Floor:", + "ar": "الطابق:" + }, + "gate": { + "en": "Gate:", + "ar": "البوابة:" + }, + "building": { + "en": "Building:", + "ar": "المبنى:" + }, + "branch": { + "en": "Branch:", + "ar": "الفرع:" + }, + "emergencyServices": { + "en": "Emergency Services", + "ar": "خدمات الطوارئ" + }, + "nearester": { + "en": "Nearest ER", + "ar": "أقرب طوارئ" + }, + "locationa": { + "en": "Location", + "ar": "الموقع" + }, + "callNow": { + "en": "Call now", + "ar": "اتصل الآن" + }, + "ambulancerequest": { + "en": "Ambulance", + "ar": "طلب إسعاف" + }, + "requestA": { + "en": "Request", + "ar": "طلب" + }, + "noBookedAppointments": { + "en": "No Booked Appointments", + "ar": "لا توجد مواعيد محجوزة" + }, + "noConfirmedAppointments": { + "en": "No Confirmed Appointments", + "ar": "لا توجد مواعيد مؤكدة" + }, + "noArrivedAppointments": { + "en": "No Arrived Appointments", + "ar": "لا توجد مواعيد تم تسجيل الوصول إليها" + }, + "myAppointmentsList": { + "en": "Appointments", + "ar": "المواعيد" + }, + "myAppointments": { + "en": "My", + "ar": "مواعيدي" + }, + "radiology": { + "en": "Radiology", + "ar": "الأشعة" + }, + "radiologySubtitle": { + "en": "Result", + "ar": "النتيجة" + }, + "lab": { + "en": "Lab", + "ar": "المختبر" + }, + "labSubtitle": { + "en": "Results", + "ar": "النتائج" + }, + "medicines": { + "en": "Medicines", + "ar": "الأدوية" + }, + "medicinesSubtitle": { + "en": "Prescriptions", + "ar": "الوصفات" + }, + "vitalSigns": { + "en": "Vital Signs", + "ar": "علامات حيوية" + }, + "vitalSignsSubTitle": { + "en": "Reports", + "ar": "التقارير" + }, + "myMedical": { + "en": "Active", + "ar": "نشط" + }, + "myMedicalSubtitle": { + "en": "Medications", + "ar": "الأدوية" + }, + "myDoctor": { + "en": "My Doctor", + "ar": "طبيبي" + }, + "myDoctorSubtitle": { + "en": "List", + "ar": "القائمة" + }, + "eye": { + "en": "Eye", + "ar": "العين" + }, + "eyeSubtitle": { + "en": "Measurement", + "ar": "القياس" + }, + "insurance": { + "en": "Insurance", + "ar": "التأمين" + }, + "insuranceSubtitle": { + "en": "Card", + "ar": "البطاقة" + }, + "updateInsurance": { + "en": "Update", + "ar": "تحديث" + }, + "updateInsuranceSubtitle": { + "en": "Insurance", + "ar": "التأمين" + }, + "insuranceApproval": { + "en": "Insurance", + "ar": "التأمين" + }, + "insuranceApprovalSubtitle": { + "en": "Approvals", + "ar": "الموافقات" + }, + "allergies": { + "en": "Allergies", + "ar": "الحساسية" + }, + "allergiesSubtitle": { + "en": "List", + "ar": "القائمة" + }, + "myVaccines": { + "en": "My Vaccines", + "ar": "لقاحاتي" + }, + "myVaccinesSubtitle": { + "en": "List", + "ar": "القائمة" + }, + "medical": { + "en": "Medical", + "ar": "طبي" + }, + "medicalSubtitle": { + "en": "Report", + "ar": "التقرير" + }, + "monthly": { + "en": "Monthly", + "ar": "شهري" + }, + "monthlySubtitle": { + "en": "Report", + "ar": "التقرير" + }, + "sick": { + "en": "Sick", + "ar": "مريض" + }, + "sickSubtitle": { + "en": "Leaves", + "ar": "الإجازات" + }, + "myBalance": { + "en": "My Balance", + "ar": "رصيدي" + }, + "myBalanceSubtitle": { + "en": "Credit", + "ar": "الرصيد" + }, + "patientCall": { + "en": "Patient Call", + "ar": "مكالمة المريض" + }, + "patientCallSubtitle": { + "en": "Service", + "ar": "الخدمة" + }, + "smartWatches": { + "en": "Smart Watches", + "ar": "الساعات الذكية" + }, + "smartWatchesSubtitle": { + "en": "Pairing", + "ar": "الاقتران" + }, + "myTrackers": { + "en": "My Trackers", + "ar": "متعقباتي" + }, + "myTrackersSubtitle": { + "en": "Service", + "ar": "الخدمة" + }, + "askYour": { + "en": "Ask Your", + "ar": "اسأل" + }, + "askYourSubtitle": { + "en": "Doctor", + "ar": "طبيبك" + }, + "internet": { + "en": "Internet", + "ar": "الإنترنت" + }, + "internetSubtitle": { + "en": "Pairing", + "ar": "الاقتران" + }, + "chatbot": { + "en": "Chatbot", + "ar": "الدردشة الآلية" + }, + "chatbotSubtitle": { + "en": "", + "ar": "" + }, + "timeLine": { + "en": "Timeline", + "ar": "الخط الزمني" + }, + "labOrders": { + "en": "Lab Orders", + "ar": "طلبات المختبر" + }, + "billNo": { + "en": "Bill No:", + "ar": "رقم الفاتورة:" + }, + "prescriptions": { + "en": "Prescriptions", + "ar": "الوصفات" + }, + "history": { + "en": "History", + "ar": "التاريخ" + }, + "orderNo": { + "en": "Order No", + "ar": "رقم الطلب" + }, + "orderDetails": { + "en": "Order Details", + "ar": "تفاصيل الطلب" + }, + "deliveryDriverTrack": { + "en": "Driver Tracking", + "ar": "تتبع السائق" + }, + "deliveryLocation": { + "en": "Delivery Location", + "ar": "موقع التسليم" + }, + "driver": { + "en": "Driver", + "ar": "السائق" + }, + "vitalSign": { + "en": "Vital Sign", + "ar": "علامة حيوية" + }, + "monthlyReports": { + "en": "Monthly Reports", + "ar": "تقارير شهرية" + }, + "km": { + "en": "KMs:", + "ar": "كم:" + }, + "km_": { + "en": "KM", + "ar": "كم" + }, + "patientHealthSummaryReport": { + "en": "Patient Health Summary Report", + "ar": "تقرير ملخص صحة المريض" + }, + "toViewTheTermsAndConditions": { + "en": "To View the Terms and Conditions Report", + "ar": "لعرض الشروط والأحكام" + }, + "clickHere": { + "en": "Click here", + "ar": "انقر هنا" + }, + "iAgreeToTheTermsAndConditions": { + "en": "I agree to the terms and conditions ", + "ar": "أوافق على الشروط والأحكام " + }, + "iAgreeToTheTermsAndConditionsSubtitle": { + "en": "I agree to the terms and conditions ", + "ar": "أوافق على الشروط والأحكام " + }, + "save": { + "en": "Save", + "ar": "حفظ" + }, + "userAgreement": { + "en": "User Agreement", + "ar": "اتفاقية المستخدم" + }, + "updateSuccessfully": { + "en": "Update Successfully", + "ar": "تم التحديث بنجاح" + }, + "checkVaccineAvailability": { + "en": "CHECK VACCINE AVAILABILITY", + "ar": "تحقق من توفر اللقاح" + }, + "myVaccinesAvailability": { + "en": "My Vaccines Availability", + "ar": "توفر اللقاحات الخاصة بي" + }, + "paymentService": { + "en": "Payment Service", + "ar": "خدمة الدفع" + }, + "paymentOnline": { + "en": "Service", + "ar": "الخدمة" + }, + "onlineCheckIn": { + "en": "Online Check-In", + "ar": "تسجيل الوصول عبر الإنترنت" + }, + "myBalances": { + "en": "My Balances", + "ar": "رصيدي" + }, + "myWallet": { + "en": "My Wallet", + "ar": "محفظتي" + }, + "balanceAmount": { + "en": "Wallet Amount", + "ar": "مبلغ المحفظة" + }, + "totalBalance": { + "en": "Total Balance", + "ar": "إجمالي الرصيد" + }, + "createAdvancedPayment": { + "en": "Recharge Wallet", + "ar": "إعادة شحن المحفظة" + }, + "advancePayment": { + "en": "Advance Payment", + "ar": "دفع مسبق" + }, + "advancePaymentLabel": { + "en": "You can create and add an Advanced Payment for your account or other accounts.", + "ar": "يمكنك إنشاء وإضافة دفعة مقدمة لحسابك أو حسابات أخرى." + }, + "fileNumber": { + "en": "File Number", + "ar": "رقم الملف" + }, + "amount": { + "en": "Amount *", + "ar": "المبلغ *" + }, + "depositorEmail": { + "en": "Depositor Email *", + "ar": "البريد الإلكتروني للودائع *" + }, + "notes": { + "en": "Notes", + "ar": "ملاحظات" + }, + "selectPatientName": { + "en": "Select Patient Name", + "ar": "اختر اسم المريض" + }, + "selectFamilyPatientName": { + "en": "Family Members", + "ar": "أفراد العائلة" + }, + "selectHospital": { + "en": "Select Hospital", + "ar": "اختر المستشفى" + }, + "selectCity": { + "en": "Select City", + "ar": "اختر المدينة" + }, + "city": { + "en": "City", + "ar": "المدينة" + }, + "distance": { + "en": "Distance", + "ar": "المسافة" + }, + "myAccount": { + "en": "My Account", + "ar": "حسابي" + }, + "otherAccount": { + "en": "Other Account", + "ar": "حساب آخر" + }, + "selectBeneficiary": { + "en": "Select Beneficiary", + "ar": "اختر المستفيد" + }, + "confirmThePayment": { + "en": "Confirm The Payment", + "ar": "تأكيد الدفع" + }, + "depositorName": { + "en": "Depositor Name", + "ar": "اسم مُقدِّم الإيداع" + }, + "mobileNumber": { + "en": "Mobile Number", + "ar": "رقم الجوال" + }, + "phoneNumber": { + "en": "Phone Number", + "ar": "رقم الهاتف" + }, + "country": { + "en": "Country", + "ar": "البلد" + }, + "ok": { + "en": "Ok", + "ar": "حسنا" + }, + "averageWaitingTime": { + "en": "Average Waiting Time:", + "ar": "متوسط وقت الانتظار:" + }, + "waitingTime": { + "en": "Expected waiting time:", + "ar": "وقت الانتظار المتوقع:" + }, + "waterConsumedInWeek": { + "en": "Water consumed in a week", + "ar": "الماء المستهلك في أسبوع" + }, + "waterConsumedInMonth": { + "en": "Water consumed in a month", + "ar": "الماء المستهلك في شهر" + }, + "theVerificationCodeExpiresIn": { + "en": "The Verification Code Expires in", + "ar": "ينتهي رمز التحقق في" + }, + "pleaseEnterTheVerificationCode": { + "en": "Please enter the verification code send to", + "ar": "يرجى إدخال رمز التحقق المرسل إلى" + }, + "eyeMeasurements": { + "en": "Eye Measurements", + "ar": "قياسات العين" + }, + "measurements": { + "en": "Measurements", + "ar": "قياسات" + }, + "classes": { + "en": "Glasses", + "ar": "نظارات" + }, + "contactLens": { + "en": "Contact Lens", + "ar": "عدسات لاصقة" + }, + "rightEye": { + "en": "Right Eye", + "ar": "العين اليمنى" + }, + "sphere": { + "en": "Sphere", + "ar": "الكرة" + }, + "cylinder": { + "en": "Cylinder", + "ar": "الأسطوانة" + }, + "axis": { + "en": "Axis", + "ar": "المحور" + }, + "prism": { + "en": "Prism", + "ar": "الهرم" + }, + "va": { + "en": "VA", + "ar": "VA" + }, + "leftEye": { + "en": "Left Eye", + "ar": "العين اليسرى" + }, + "brand": { + "en": "Brand", + "ar": "العلامة التجارية" + }, + "power": { + "en": "Power", + "ar": "القوة" + }, + "diameter": { + "en": "Diameter", + "ar": "القطر" + }, + "remarks": { + "en": "", + "ar": "ملاحظات: " + }, + "activeMedications": { + "en": "Active Medications", + "ar": "الأدوية النشطة" + }, + "expDate": { + "en": "Active Exp Date :", + "ar": "تاريخ انتهاء الصلاحية:" + }, + "route": { + "en": "", + "ar": "الطريق" + }, + "frequency": { + "en": "", + "ar": "التكرار" + }, + "dailyQuantity": { + "en": "Daily Quantity :", + "ar": "الكمية اليومية:" + }, + "addReminder": { + "en": "Add Reminder", + "ar": "إضافة تذكير" + }, + "cancelReminder": { + "en": "Cancel Reminder", + "ar": "إلغاء التذكير" + }, + "reminderDes": { + "en": "Please select treatment start day and time to be notified when it's time to take the medicine", + "ar": "يرجى تحديد يوم ووقت بدء العلاج ليتم إعلامك عندما يحين وقت تناول الدواء" + }, + "pleaseSelectAllQuestionToContinue": { + "en": "Please answer all questions to continue...", + "ar": "يرجى الإجابة على جميع الأسئلة للمتابعة..." + }, + "startDay": { + "en": "Start Day", + "ar": "يوم البدء" + }, + "endDay": { + "en": "End Day", + "ar": "يوم الانتهاء" + }, + "days": { + "en": "Days ", + "ar": "أيام " + }, + "pleaseVerify": { + "en": "Please Verify ", + "ar": "يرجى التحقق " + }, + "scheduleTime": { + "en": "Schedule time", + "ar": "وقت الجدولة" + }, + "askDoctor": { + "en": "Ask Doctor", + "ar": "اسأل الطبيب" + }, + "doctorResponses": { + "en": "Doctor Responses", + "ar": "ردود الطبيب" + }, + "ne_w": { + "en": "New", + "ar": "جديد" + }, + "all": { + "en": "All", + "ar": "الكل" + }, + "dailyWater": { + "en": "Daily Water Check", + "ar": "متابعة الماء اليومية" + }, + "questionHere": { + "en": "Enter the question here...", + "ar": "أدخل السؤال هنا..." + }, + "viewDoctorResponses": { + "en": "View Doctor Responses", + "ar": "عرض ردود الطبيب" + }, + "serviceInformationButton": { + "en": "LOGIN / REGISTER", + "ar": "تسجيل الدخول / التسجيل" + }, + "serviceInformationTitle": { + "en": "Service Information", + "ar": "معلومات الخدمة" + }, + "serviceInformation": { + "en": "Service Information", + "ar": "معلومات الخدمة" + }, + "homeHealthCare": { + "en": "Home Health Care", + "ar": "الرعاية الصحية المنزلية" + }, + "noAppointmentAvailable": { + "en": "No Available Appointments", + "ar": "لا توجد مواعيد متاحة" + }, + "homeHealthCareText": { + "en": "This service provides a set of home health care services, continuous and comprehensive follow-up in their places of residence for those who cannot access health facilities, such as (laboratory analyzes - radiology - vaccinations - physical therapy), etc.", + "ar": "تقدم هذه الخدمة مجموعة من خدمات الرعاية الصحية المنزلية، والمتابعة المستمرة والشاملة في أماكن إقامتهم لأولئك الذين لا يمكنهم الوصول إلى المرافق الصحية، مثل (تحليلات المختبر - الأشعة - التطعيمات - العلاج الطبيعي)، إلخ." + }, + "loginRegister": { + "en": "Login/Register", + "ar": "تسجيل الدخول / التسجيل" + }, + "orderLog": { + "en": "Order Log", + "ar": "سجل الطلب" + }, + "infoLab": { + "en": "This service allows you to view the results of all laboratory tests performed in Al Habib Medical Group as well as sending the report via e-mail.", + "ar": "تتيح لك هذه الخدمة عرض نتائج جميع الفحوصات المخبرية التي أجريت في مجموعة الحبيب الطبية بالإضافة إلى إرسال التقرير عبر البريد الإلكتروني." + }, + "infoRadiology": { + "en": "This service allows you to view the reports and photos of radiology in Al Habib Medical Group as well as send the report by e-mail.", + "ar": "تتيح لك هذه الخدمة عرض تقارير وصور الأشعة في مجموعة الحبيب الطبية بالإضافة إلى إرسال التقرير عبر البريد الإلكتروني." + }, + "noReviewsAvailable": { + "en": "No Reviews Available", + "ar": "لا توجد تقييمات متاحة" + }, + "noLocationAvailable": { + "en": "No Location Available", + "ar": "لا توجد مواقع متاحة" + }, + "orders": { + "en": "Orders", + "ar": "الطلبات" + }, + "lakum": { + "en": "", + "ar": "لكم" + }, + "lakumMsg": { + "en": "", + "ar": "لا توجد تفاصيل عن النقاط" + }, + "lakumPoint": { + "en": "Lakum Points", + "ar": "نقاط لكم" + }, + "wishlist": { + "en": "Wishlist", + "ar": "قائمة الرغبات" + }, + "products": { + "en": "Products", + "ar": "المنتجات" + }, + "reviews": { + "en": "Reviews", + "ar": "التقييمات" + }, + "brands": { + "en": "Brands", + "ar": "العلامات التجارية" + }, + "productDetails": { + "en": "Product Details", + "ar": "تفاصيل المنتج" + }, + "medicationRefill": { + "en": "Medication Refill", + "ar": "إعادة تعبئة الدواء" + }, + "pillReminder": { + "en": "Pill Reminder", + "ar": "تذكير بالدواء" + }, + "shippingAddresses": { + "en": "Shipping Addresses", + "ar": "عناوين الشحن" + }, + "reachUs": { + "en": "Reach Us", + "ar": "تواصل معنا" + }, + "ourLocations": { + "en": "Our Locations", + "ar": "مواقعنا" + }, + "edit": { + "en": "Edit", + "ar": "تعديل" + }, + "whatsApp": { + "en": "Whats App", + "ar": "واتساب" + }, + "phone": { + "en": "Phone", + "ar": "الهاتف" + }, + "delete": { + "en": "Delete", + "ar": "حذف" + }, + "deleteAddress": { + "en": "Are you sure want to delete", + "ar": "هل أنت متأكد أنك تريد الحذف" + }, + "deletedAddres": { + "en": "Address has been deleted", + "ar": "تم حذف العنوان" + }, + "addAddress": { + "en": "ADD A NEW ADDRESS", + "ar": "إضافة عنوان جديد" + }, + "addNewAddress": { + "en": "Add New Address", + "ar": "إضافة عنوان جديد" + }, + "order": { + "en": "My Order", + "ar": "طلبي" + }, + "delivered": { + "en": "Delivered", + "ar": "تم التوصيل" + }, + "pending": { + "en": "Pending", + "ar": "قيد الانتظار" + }, + "enterNameHere": { + "en": "Enter Your Name", + "ar": "أدخل اسمك هنا" + }, + "processing": { + "en": "Processing", + "ar": "جاري المعالجة" + }, + "cancelled": { + "en": "Cancelled", + "ar": "ملغى" + }, + "writeReview": { + "en": "Write Review", + "ar": "اكتب تقييمًا" + }, + "shareReview": { + "en": "SHARE REVIEW", + "ar": "شارك التقييم" + }, + "review": { + "en": " reviews", + "ar": " التقييمات" + }, + "viewMedicalFile": { + "en": "View Details", + "ar": "عرض التفاصيل" + }, + "viewAllServices": { + "en": "View All Services", + "ar": "عرض جميع الخدمات" + }, + "medicalFile": { + "en": "Medical File", + "ar": "الملف الطبي" + }, + "verified": { + "en": "Verified", + "ar": "تم التحقق" + }, + "checkup": { + "en": "Checkup", + "ar": "فحص" + }, + "hhcHome": { + "en": "Home", + "ar": "الرئيسية" + }, + "refferal": { + "en": "E-Refferal", + "ar": "إحالة إلكترونية" + }, + "refferalTitle": { + "en": "E-Refferal", + "ar": "إحالة إلكترونية" + }, + "refferalSubTitle": { + "en": "Service", + "ar": "الخدمة" + }, + "healthCare": { + "en": "Health Care", + "ar": "الرعاية الصحية" + }, + "emergency": { + "en": "Emergency", + "ar": "حالة طوارئ" + }, + "erservices": { + "en": "Emergency", + "ar": "خدمات الطوارئ" + }, + "services2": { + "en": "Services", + "ar": "الخدمات" + }, + "cantSeeProfile": { + "en": "To view your medical profile, please log in or register now", + "ar": "لرؤية ملفك الطبي، يرجى تسجيل الدخول أو التسجيل الآن" + }, + "loginRegisterNow": { + "en": "Login or Register Now", + "ar": "تسجيل الدخول أو التسجيل الآن" + }, + "hmgPharmacy": { + "en": "HMG Pharmacy", + "ar": "صيدلية مجموعة الحبيب الطبية" + }, + "ecommerceSolution": { + "en": "Ecommerce Solution", + "ar": "حلول التجارة الإلكترونية" + }, + "comprehensive": { + "en": "Comprehensive", + "ar": "شامل" + }, + "onlineConsulting": { + "en": "Online Consulting", + "ar": "استشارات عبر الإنترنت" + }, + "pendingOrder": { + "en": " PENDING", + "ar": " قيد الانتظار" + }, + "deliveredOrder": { + "en": " DELIVERED", + "ar": " تم التوصيل" + }, + "processingOrder": { + "en": " PROCESSING", + "ar": " جارٍ المعالجة" + }, + "cancelledOrder": { + "en": " CANCELLED", + "ar": " ملغى" + }, + "compare": { + "en": " Compare", + "ar": " قارن" + }, + "medicationsRefill": { + "en": " Medication Refill", + "ar": " إعادة تعبئة الأدوية" + }, + "recommended": { + "en": " Recommended for You", + "ar": " موصى به لك" + }, + "myPrescription": { + "en": " My Prescriptions", + "ar": " وصفتي" + }, + "quantity": { + "en": " QTY ", + "ar": " الكمية " + }, + "reviewAppointment": { + "en": " Review Appointment ", + "ar": " مراجعة الموعد " + }, + "backMyAccount": { + "en": "BACK TO MY ACCOUNT ", + "ar": "العودة إلى حسابي " + }, + "reviewSuccessful": { + "en": "Review Successful", + "ar": "تمت مراجعة الطلب بنجاح" + }, + "reviewShared": { + "en": "Your review has been shared on product review section", + "ar": "تمت مشاركة تقييمك في قسم تقييم المنتج" + }, + "reviewComment": { + "en": "Your reviews help other to choose better product", + "ar": "تساعد تقييماتك الآخرين على اختيار منتج أفضل" + }, + "shippedMethod": { + "en": "SHIP BY:", + "ar": "الشحن بواسطة:" + }, + "orderDetail": { + "en": "Order Details", + "ar": "تفاصيل الطلب" + }, + "orderSummary": { + "en": "Order Summary", + "ar": "ملخص الطلب" + }, + "subtotal": { + "en": "Subtotal", + "ar": "المجموع الفرعي" + }, + "shipping": { + "en": "Shipping", + "ar": "الشحن" + }, + "shipBy": { + "en": "SHIP BY:", + "ar": "الشحن بواسطة:" + }, + "lakumPoints": { + "en": "Lakum Points", + "ar": "نقاط لكم" + }, + "useLakumPoints": { + "en": "Use Lakum points", + "ar": "استخدم نقاط لكم" + }, + "use": { + "en": "USE", + "ar": "استخدم" + }, + "proceedPay": { + "en": "PROCEED TO PAY", + "ar": "المتابعة للدفع" + }, + "vat": { + "en": "VAT (15%)", + "ar": "ضريبة القيمة المضافة (15%)" + }, + "inclusiveVat": { + "en": "(inclusive VAT)", + "ar": "(شاملة ضريبة القيمة المضافة)" + }, + "items": { + "en": "item(s)", + "ar": "عنصر(عناصر)" + }, + "checkOut": { + "en": "CHECK OUT", + "ar": "الدفع" + }, + "sar": { + "en": "SAR", + "ar": "ريال سعودي" + }, + "aed": { + "en": "AED", + "ar": "درهم إماراتي" + }, + "payOnline": { + "en": "PAY ONLINE", + "ar": "الدفع عبر الإنترنت" + }, + "cancelOrder": { + "en": "CANCEL ORDER", + "ar": "إلغاء الطلب" + }, + "confirmAddress": { + "en": "CONFIRM ADDRESS ", + "ar": "تأكيد العنوان " + }, + "confirmLocation": { + "en": "CONFIRM LOCATION ", + "ar": "أكد الموقع " + }, + "conditionsHMG": { + "en": "Terms & Conditions ", + "ar": "الشروط والأحكام " + }, + "conditions": { + "en": "Terms & Conditions of Lakum", + "ar": "الشروط والأحكام لكوم" + }, + "confirmDeleteMsg": { + "en": "Are you sure! want to delete ", + "ar": "هل أنت متأكد! تريد الحذف " + }, + "confirmDelete": { + "en": "DELETE", + "ar": "حذف" + }, + "confirmCancellation": { + "en": "Are you sure! want to cancel this order ", + "ar": "هل أنت متأكد! تريد إلغاء هذا الطلب " + }, + "orderNumber": { + "en": "Order#: ", + "ar": "رقم الطلب: " + }, + "orderDate": { + "en": "Date", + "ar": "التاريخ" + }, + "itemsNo": { + "en": "items(s)", + "ar": "عنصر(عناصر)" + }, + "noOrder": { + "en": "You Don't have any orders.", + "ar": "ليس لديك أي طلبات." + }, + "noResult": { + "en": "No Result.", + "ar": "لا توجد نتيجة." + }, + "nonRecommended": { + "en": "No Recommended Products.", + "ar": "لا توجد منتجات موصى بها." + }, + "termsService": { + "en": "Terms of Service", + "ar": "شروط الخدمة" + }, + "beforeusing": { + "en": "Before using the checkup, please read Terms of Service.", + "ar": "قبل استخدام الفحص، يرجى قراءة شروط الخدمة." + }, + "accept": { + "en": "I read and accept Terms of Service and Privacy Policy", + "ar": "أقرأ وأقبل شروط الخدمة وسياسة الخصوصية" + }, + "dataSafeInfo": { + "en": "Information that you provide is anonymous and not shared with anyone.", + "ar": "المعلومات التي تقدمها مجهولة الهوية وليست مشتركة مع أي شخص." + }, + "dataSafe": { + "en": " Your data is safe.", + "ar": " بياناتك آمنة." + }, + "informational": { + "en": "Checkup is for informational purposes and is not a qualified medical opinion", + "ar": "الفحص لأغراض معلوماتية وليس رأيًا طبيًا مؤهلاً" + }, + "notUseInEmerbency": { + "en": "Do not use in emergencies.", + "ar": "لا تستخدم في حالات الطوارئ." + }, + "notUseInEmerbencyDetails": { + "en": "In case of health emergency, ", + "ar": "في حالة الطوارئ الصحية، " + }, + "notUseInEmerbencyDetailsCall": { + "en": "call the nearest emergency number immediately", + "ar": "اتصل بأقرب رقم طوارئ على الفور" + }, + "checkDiagnosis": { + "en": "Checkup is not a diagnosis.", + "ar": "الفحص ليس تشخيصًا." + }, + "remeberthat": { + "en": "Remember that", + "ar": "تذكر أن" + }, + "loginToUseService": { + "en": "You need to login to use this service", + "ar": "تحتاج إلى تسجيل الدخول لاستخدام هذه الخدمة" + }, + "offersAndPromotions": { + "en": "OFFERS & SPECIAL PROMOTIONS", + "ar": "عروض وترويجيات خاصة" + }, + "offers": { + "en": "OFFERS", + "ar": "عروض" + }, + "myPrescriptions": { + "en": "MY PRESCRIPTIONS", + "ar": "وصفاتي" + }, + "searchAndScanMedication": { + "en": "SEARCH & SCAN FOR MEDICATION", + "ar": "البحث والمسح الضوئي للدواء" + }, + "shopByBrands": { + "en": "Shop by Brands", + "ar": "تسوق حسب العلامات التجارية" + }, + "recentlyViewed": { + "en": "Recently Viewed", + "ar": "تمت مشاهدته مؤخرًا" + }, + "bestSellers": { + "en": "Best Seller", + "ar": "الأكثر مبيعًا" + }, + "deleteAllItems": { + "en": "Delete All Items", + "ar": "حذف جميع العناصر" + }, + "total": { + "en": "Total", + "ar": "الإجمالي" + }, + "totalWithColonRight": { + "en": "Total:", + "ar": "الإجمالي:" + }, + "selectAddress": { + "en": "Select Address", + "ar": "اختر العنوان" + }, + "shippingAddress": { + "en": "SHIPPING ADDRESS", + "ar": "عنوان الشحن" + }, + "changeAddress": { + "en": "Change Address", + "ar": "تغيير العنوان" + }, + "selectPaymentOption": { + "en": "Select Payment Option", + "ar": "اختر طريقة الدفع" + }, + "selectTamaraPlan": { + "en": "Select Tamara Payment Plan", + "ar": "اختر خطة دفع تمارا" + }, + "changeMethod": { + "en": "Change Method", + "ar": "تغيير الطريقة" + }, + "reviewOrder": { + "en": "Review Order", + "ar": "مراجعة الطلب" + }, + "active": { + "en": "Active", + "ar": "نشط" + }, + "inactive": { + "en": "InActive", + "ar": "غير نشط" + }, + "balance": { + "en": "Balance", + "ar": "الرصيد" + }, + "gained": { + "en": "GAINED", + "ar": "المكتسب" + }, + "consumed": { + "en": "Consumed", + "ar": "المستهلك" + }, + "transferred": { + "en": "Transferred", + "ar": "المحول" + }, + "riyal": { + "en": "RIYAL", + "ar": "ريال" + }, + "membersince": { + "en": "MEMBER SINCE", + "ar": "عضو منذ" + }, + "identification": { + "en": "Identification Number", + "ar": "رقم الهوية" + }, + "lakumMobile": { + "en": "Mobile Number", + "ar": "رقم الجوال" + }, + "waitinggained": { + "en": "Waiting gained", + "ar": "انتظار المكتسب" + }, + "expired": { + "en": "Expired", + "ar": "منتهي" + }, + "willBeExpired": { + "en": "Will Be Expired", + "ar": "سينتهي" + }, + "activateLAKUMAccount": { + "en": "Activate LAKUM Account", + "ar": "تفعيل حساب لكم" + }, + "checkBeneficiary": { + "en": "CHECK BENEFICIARY", + "ar": "تحقق من المستفيد" + }, + "beneficiaryName": { + "en": "Beneficiary Name", + "ar": "اسم المستفيد" + }, + "accountActivation": { + "en": "Account Activation", + "ar": "تفعيل الحساب" + }, + "lakumTransfer": { + "en": "Lakum Transfer", + "ar": "تحويل لكم" + }, + "acceptLbl": { + "en": "Accept", + "ar": "قبول" + }, + "declineLbl": { + "en": "Decline", + "ar": "رفض" + }, + "selectGender": { + "en": "Select Gender", + "ar": "اختر الجنس" + }, + "iAmA": { + "en": "I am a ...", + "ar": "أنا ..." + }, + "selectAge": { + "en": "Select Your Age", + "ar": "اختر عمرك" + }, + "select": { + "en": "Select", + "ar": "اختر" + }, + "iAm": { + "en": "I am", + "ar": "أنا" + }, + "yearsOld": { + "en": "years old", + "ar": "سنوات" + }, + "dragPoint": { + "en": "Drag point to change your age", + "ar": "اسحب النقطة لتغيير عمرك" + }, + "refine": { + "en": "Refine", + "ar": "تنقيح" + }, + "subGroup": { + "en": "Subgroup", + "ar": "مجموعة فرعية" + }, + "max": { + "en": "Max", + "ar": "الحد الأقصى" + }, + "compeleteOrderMsg": { + "en": "Order has been placed successfully!!", + "ar": "تم تقديم الطلب بنجاح!!" + }, + "addToCompareMsg": { + "en": "You have added a product to the Compare list", + "ar": "لقد أضفت منتجًا إلى قائمة المقارنة" + }, + "itInListMsg": { + "en": "Item is already in the list", + "ar": "العنصر موجود بالفعل في القائمة" + }, + "compareListFull": { + "en": "Your compare list is full", + "ar": "قائمة المقارنة ممتلئة" + }, + "addQuantity": { + "en": "You should add quantity", + "ar": "يجب عليك إضافة الكمية" + }, + "addToCartMsg": { + "en": "You have added a product to the cart", + "ar": "لقد أضفت منتجًا إلى عربة التسوق" + }, + "addToWishlistMsg": { + "en": "You have added a product to the Wishlist", + "ar": "لقد أضفت منتجًا إلى قائمة الرغبات" + }, + "notifyMeMsg": { + "en": "You will be notified when product available", + "ar": "سوف يتم إبلاغك عند توفر المنتج" + }, + "removeFromWishlistMsg": { + "en": "You have removed a product from the Wishlist", + "ar": "لقد أزلت منتجًا من قائمة الرغبات" + }, + "min": { + "en": "Min", + "ar": "الحد الأدنى" + }, + "reset": { + "en": "Reset", + "ar": "إعادة تعيين" + }, + "apply": { + "en": "Apply", + "ar": "تطبيق" + }, + "viewCategorise": { + "en": "View All Categories", + "ar": "عرض جميع الفئات" + }, + "viewSubCategorise": { + "en": "View All Sub Categories", + "ar": "عرض جميع الفئات الفرعية" + }, + "categorise": { + "en": "Categories", + "ar": "الفئات" + }, + "wishList": { + "en": "WishList", + "ar": "قائمة الرغبات" + }, + "cart": { + "en": "Cart", + "ar": "عربة التسوق" + }, + "alhabibapp": { + "en": "Al Habib app", + "ar": "تطبيق الحبيب" + }, + "searchProductHere": { + "en": "Search Product here", + "ar": "ابحث عن المنتج هنا" + }, + "hhcNotAuthMsg": { + "en": "This service provides a set of home health care services, continuous and comprehensive follow-up in their places of residence for those who cannot access health facilities, such as (laboratory analyzes - radiology - vaccinations - physical therapy), etc.", + "ar": "تقدم هذه الخدمة مجموعة من خدمات الرعاية الصحية المنزلية، والمتابعة المستمرة والشاملة في أماكن إقامتهم لأولئك الذين لا يمكنهم الوصول إلى المرافق الصحية، مثل (تحليلات المختبر - الأشعة - التطعيمات - العلاج الطبيعي)، إلخ." + }, + "email": { + "en": "Email *", + "ar": "البريد الإلكتروني *" + }, + "book": { + "en": "Book", + "ar": "احجز" + }, + "appointmentLabel": { + "en": "Appointment", + "ar": "موعد" + }, + "bloodType": { + "en": "Blood Type", + "ar": "فصيلة الدم" + }, + "maritalStatus": { + "en": "Marital status", + "ar": "الحالة الاجتماعية" + }, + "general": { + "en": "General", + "ar": "عام" + }, + "profile": { + "en": "My Profile", + "ar": "ملفي" + }, + "notifications": { + "en": "Notifications", + "ar": "إشعارات" + }, + "notificationDetails": { + "en": "Notification Details", + "ar": "تفاصيل الإشعار" + }, + "notificationDetailsa": { + "en": "Notification Details", + "ar": "تفاصيل الإشعار" + }, + "infoMyDoctor": { + "en": "This service allows you to see all the doctors you have visited in Al Habib Medical Group, and through this service:", + "ar": "تتيح لك هذه الخدمة رؤية جميع الأطباء الذين زرتهم في مجموعة الحبيب الطبية، ومن خلال هذه الخدمة:" + }, + "infoPrescriptions": { + "en": "This service allows you to view all the medical prescriptions issued by Al Habib Medical Group, and through this service, you can:", + "ar": "تتيح لك هذه الخدمة عرض جميع الوصفات الطبية التي أصدرتها مجموعة الحبيب الطبية، ومن خلال هذه الخدمة، يمكنك:" + }, + "infoInsuranceCards": { + "en": "This service allows you to view all the insurance cards that recorded during your visits to Al Habib Medical Group in addition to:", + "ar": "تتيح لك هذه الخدمة عرض جميع بطاقات التأمين التي تم تسجيلها خلال زياراتك لمجموعة الحبيب الطبية بالإضافة إلى:" + }, + "infoAllergies": { + "en": "This service allows you to view all types of allergies recorded during your visits to Al Habib Medical Group.", + "ar": "تتيح لك هذه الخدمة عرض جميع أنواع الحساسية المسجلة خلال زياراتك لمجموعة الحبيب الطبية." + }, + "infoSickLeaves": { + "en": "This service allows you to view all sick leaves that were taken in Al Habib Medical Group in addition to:", + "ar": "تتيح لك هذه الخدمة عرض جميع الاجازات المرضيه التي تم أخذها في مجموعة الحبيب الطبية بالإضافة إلى:" + }, + "infoApprovals": { + "en": "This service allows you to view all approvals requests that have been sent to the insurance companies in addition to:", + "ar": "تتيح لك هذه الخدمة عرض جميع طلبات الموافقة التي تم إرسالها إلى شركات التأمين بالإضافة إلى:" + }, + "infoMonthReport": { + "en": "Upon activation of this service, the system will send a monthly report automatically to the registered email which lists the vital signs and the results for the last visits made in AlHabib Medical Group.", + "ar": "عند تفعيل هذه الخدمة، سيقوم النظام بإرسال تقرير شهري تلقائيًا إلى البريد الإلكتروني المسجل يتضمن العلامات الحيوية والنتائج لآخر الزيارات التي تمت في مجموعة الحبيب الطبية." + }, + "languageSetting": { + "en": "SMS, WhatsApp and Confirmation Calls Language", + "ar": "الرسائل القصيرة، واتساب، لغة مكالمات التأكيد" + }, + "alert": { + "en": "Alerts", + "ar": "تنبيهات" + }, + "emailAlert": { + "en": "Alert by Email", + "ar": "تنبيه عبر البريد الإلكتروني" + }, + "smsAlert": { + "en": "Alert by SMS", + "ar": "تنبيه عبر الرسائل القصيرة" + }, + "contactInfo": { + "en": "Contact Information", + "ar": "معلومات الاتصال" + }, + "emrgName": { + "en": "Emergency Contact Name", + "ar": "اسم جهة الاتصال في حالات الطوارئ" + }, + "emrgNo": { + "en": "Emergency Contact Number", + "ar": "رقم جهة الاتصال في حالات الطوارئ" + }, + "modes": { + "en": "Modes", + "ar": "الأوضاع" + }, + "vibration": { + "en": "Vibration Touch Feedback", + "ar": "اهتزاز عند اللمس" + }, + "blindModes": { + "en": "Modes for Partially Blind", + "ar": "أوضاع للمكفوفين جزئيًا" + }, + "invertTheme": { + "en": "Invert", + "ar": "عكس" + }, + "offTheme": { + "en": "Off", + "ar": "إيقاف" + }, + "dimTheme": { + "en": "Dim", + "ar": "خافت" + }, + "bwTheme": { + "en": "Black and White", + "ar": "أسود وأبيض" + }, + "permissions": { + "en": "Permission", + "ar": "إذن" + }, + "cameraPermission": { + "en": "Camera", + "ar": "الكاميرا" + }, + "locationPermission": { + "en": "Location", + "ar": "الموقع" + }, + "needPrescription": { + "en": "This product requires a prescription", + "ar": "يتطلب هذا المنتج وصفة طبية" + }, + "outOfStockMsg": { + "en": "You have added product which is out of stock now, Please remove that!", + "ar": "لقد أضفت منتجًا غير متوفر حاليًا، يرجى إزالته!" + }, + "noArabicLetters": { + "en": "It Is Not Allow to Use Arabic Letters", + "ar": "لا يُسمح باستخدام الحروف العربية" + }, + "noOffersAvailable": { + "en": "No Offers Available!", + "ar": "لا توجد عروض متاحة!" + }, + "accessibility": { + "en": "Accessibility Mode", + "ar": "وضع الوصول" + }, + "orderStatus": { + "en": "Order Status", + "ar": "حالة الطلب" + }, + "findUs": { + "en": "Find Us", + "ar": "اعثر علينا" + }, + "liveChat": { + "en": "Live Chat", + "ar": "دردشة مباشرة" + }, + "service": { + "en": "Service", + "ar": "خدمة" + }, + "hmgServiceLabel": { + "en": "HMG Service", + "ar": "خدمة مجموعة الحبيب الطبية" + }, + "healthWeatherIndicators": { + "en": "Health Weather Indicators", + "ar": "مؤشرات الطقس الصحية" + }, + "healthTipsBasedOnCurrentWeather": { + "en": "Health Tips Based On Current Weather", + "ar": "نصائح صحية بناءً على الطقس الحالي" + }, + "moreDetails": { + "en": "More details", + "ar": "المزيد من التفاصيل" + }, + "resendOrder": { + "en": "Refill and Delivery", + "ar": "إعادة التعبئة والتوصيل" + }, + "ports": { + "en": "Ports", + "ar": "المنافذ" + }, + "way": { + "en": "Way", + "ar": "الطريقة" + }, + "dailyDoses": { + "en": "Daily Doses", + "ar": "الجرعات اليومية" + }, + "period": { + "en": "Period", + "ar": "الفترة" + }, + "duration": { + "en": "المدة", + "ar": "المدة" + }, + "cm": { + "en": "CM", + "ar": "سم" + }, + "ft": { + "en": "ft", + "ar": "قدم" + }, + "kg": { + "en": "kg", + "ar": "كجم" + }, + "lb": { + "en": "lb", + "ar": "رطل" + }, + "birthDate": { + "en": "Birth Date", + "ar": "تاريخ الميلاد" + }, + "dateOfBirth": { + "en": "Date of Birth", + "ar": "تاريخ الميلاد" + }, + "mass": { + "en": "Mass", + "ar": "الكتلة" + }, + "tempC": { + "en": "°C", + "ar": "°م" + }, + "bpm": { + "en": "bpm", + "ar": "نبضة في الدقيقة" + }, + "respirationSigns": { + "en": "Respiration", + "ar": "التنفس" + }, + "sysDias": { + "en": "SBP/DBP", + "ar": "SBP/DBP" + }, + "body": { + "en": "Body Mass", + "ar": "مؤشر كتلة الجسم" + }, + "bodyString": { + "en": "Body", + "ar": "الجسم" + }, + "face": { + "en": "Face", + "ar": "وجه" + }, + "retouch": { + "en": "Re-touch", + "ar": "روتوش" + }, + "bikini": { + "en": "Bikini", + "ar": "بيكيني" + }, + "totalMinutes": { + "en": "Total Minutes", + "ar": "إجمالي الدقائق" + }, + "feedback": { + "en": "Feedback", + "ar": "ملاحظات" + }, + "likeToHear": { + "en": "We would love to hear the feedback, concerns on healthcare services and eServices experience. Please use the below form", + "ar": "نود سماع ملاحظاتك، ومخاوفك بشأن خدمات الرعاية الصحية وتجربة الخدمات الإلكترونية. يرجى استخدام النموذج أدناه" + }, + "emptySubject": { + "en": "Please enter the subject", + "ar": "يرجى إدخال الموضوع" + }, + "emptyMessage": { + "en": "Please enter message", + "ar": "يرجى إدخال الرسالة" + }, + "selectAttachment": { + "en": "Select Attachment", + "ar": "اختر المرفق" + }, + "complainAppo": { + "en": "Complaint for appointment", + "ar": "شكوى بخصوص الموعد" + }, + "complainAppoAlt": { + "en": "Complaint without appointment", + "ar": "شكوى بدون موعد" + }, + "messageType": { + "en": "Message Type", + "ar": "نوع الرسالة" + }, + "feedbackType": { + "en": "Feedback Type", + "ar": "نوع الملاحظات" + }, + "compliment": { + "en": "Appreciation", + "ar": "تقدير" + }, + "suggestion": { + "en": "Suggestion", + "ar": "اقتراح" + }, + "yourFeedback": { + "en": "Your feedback was sent", + "ar": "تم إرسال ملاحظاتك" + }, + "selectPart": { + "en": "Please select the part that complain about", + "ar": "يرجى اختيار الجزء الذي تشتكي منه" + }, + "number": { + "en": "Number", + "ar": "رقم" + }, + "notClassified": { + "en": "Not classified", + "ar": "غير مصنف" + }, + "selectClinic": { + "en": "Select Clinic", + "ar": "اختر العيادة" + }, + "selectProject": { + "en": "Select Hospital", + "ar": "اختر المستشفى" + }, + "searchItemError": { + "en": "Item name should be more than 3 character", + "ar": "يجب أن يكون اسم العنصر أكثر من 3 أحرف" + }, + "youCanFind": { + "en": "You Can Find ", + "ar": "يمكنك العثور على " + }, + "itemInSearch": { + "en": " Item in Search", + "ar": " عنصر في البحث" + }, + "bloodDonation": { + "en": "Blood Donation", + "ar": "التبرع بالدم" + }, + "bloodDonationInfo": { + "en": "Through this service, you can register your name as a blood donor where the blood bank in the Habib Medical Group will communicate you in case of need for blood type.", + "ar": "من خلال هذه الخدمة، يمكنك تسجيل اسمك كمتبرع بالدم حيث سيتواصل معك بنك الدم في مجموعة الحبيب الطبية في حالة الحاجة إلى فصيلة الدم." + }, + "bloodInstruction": { + "en": "Enter the required information, in order to register for Blood Donation Service", + "ar": "أدخل المعلومات المطلوبة، من أجل التسجيل في خدمة التبرع بالدم" + }, + "viewTerms": { + "en": "To view the terms and conditions", + "ar": "لعرض الشروط والأحكام" + }, + "wantConnectHmgNetwork": { + "en": "Dear customer there is no internet access, do you want to connect with HMG network to use our app, make sure you are in range of HMG network", + "ar": "عزيزي العميل، لا يوجد وصول إلى الإنترنت، هل ترغب في الاتصال بشبكة مجموعة الحبيب الطبية لاستخدام تطبيقنا، تأكد من أنك في نطاق شبكة مجموعة الحبيب الطبية" + }, + "failedToAccessHmgServices": { + "en": "Connected with HMG Network,\n\nBut failed to access HMG services", + "ar": "متصل بشبكة مجموعة الحبيب الطبية،\n\nلكن فشل في الوصول إلى خدمات مجموعة الحبيب الطبية" + }, + "offerAndPackages": { + "en": "Offers and Packages", + "ar": "عروض وباقات" + }, + "offerAndPackagesDetails": { + "en": "This service allows you to view all HMG Offers:", + "ar": "تتيح لك هذه الخدمة عرض جميع عروض مجموعة الحبيب الطبية:" + }, + "invoiceNo": { + "en": "Invoice No", + "ar": "رقم الفاتورة" + }, + "invoiceDate": { + "en": "Invoice Date", + "ar": "تاريخ الفاتورة" + }, + "specialResult": { + "en": "Special Result", + "ar": "نتيجة خاصة" + }, + "generalResult": { + "en": "General Result", + "ar": "نتيجة عامة" + }, + "showMoreBtn": { + "en": "Flow Chart", + "ar": "مخطط التدفق" + }, + "value": { + "en": "Value", + "ar": "القيمة" + }, + "report": { + "en": "Radiology Report", + "ar": "تقرير الأشعة" + }, + "openRad": { + "en": "Open Image", + "ar": "فتح الصورة" + }, + "sendCopy": { + "en": "Email the Report", + "ar": "إرسال التقرير عبر البريد الإلكتروني" + }, + "appoSurvey": { + "en": "Survey", + "ar": "استطلاع" + }, + "appoSurveySubtitle": { + "en": "Survey", + "ar": "استطلاع" + }, + "labResults": { + "en": "Lab Results", + "ar": "نتائج المختبر" + }, + "doctorRating": { + "en": "Doctor Rating", + "ar": "تقييم الطبيب" + }, + "good": { + "en": "Good", + "ar": "جيد" + }, + "vGood": { + "en": "Very Good", + "ar": "جيد جدًا" + }, + "excellent": { + "en": "Excellent", + "ar": "ممتاز" + }, + "average": { + "en": "Average", + "ar": "متوسط" + }, + "infoSigns": { + "en": "This service allows you to view all vital signs were performed in the Habib Medical Group, e.x (height, weight, body mass index, heart rate, etc.) as well shows some statistics charts.", + "ar": "تتيح لك هذه الخدمة عرض جميع العلامات الحيوية التي تم قياسها في مجموعة الحبيب الطبية، مثل (الطول، الوزن، مؤشر كتلة الجسم، معدل ضربات القلب، إلخ.) بالإضافة إلى عرض بعض الرسوم البيانية الإحصائية." + }, + "infoAdvancePayment": { + "en": "This service designed so that you can deposit an amount in advance either in your account or in someone else's account with Al Habib Medical Group.", + "ar": "تم تصميم هذه الخدمة بحيث يمكنك إيداع مبلغ مقدم إما في حسابك أو في حساب شخص آخر، في مجموعة الحبيب الطبية." + }, + "infoMyBalance": { + "en": "This service allows you to check your balance in all branchs", + "ar": "تتيح لك هذه الخدمة التحقق من رصيدك في جميع الفروع" + }, + "erContant": { + "en": "This service displays nearest branch among all the branches of Al Habib Medical Group based on your current location.", + "ar": "تظهر هذه الخدمة أقرب فرع من بين جميع فروع مجموعة الحبيب الطبية بناءً على موقعك الحالي." + }, + "infoAmbulance": { + "en": "Through this service, you can request evacuation by ambulance, whether from home or to home, in addition to a set of other services", + "ar": "من خلال هذه الخدمة، يمكنك طلب الإخلاء بواسطة سيارة إسعاف، سواء من المنزل أو إلى المنزل، بالإضافة إلى مجموعة من الخدمات الأخرى" + }, + "infoMyAppointments": { + "en": "This service allows you to see all the appointment you have visited in Al Habib Medical Group, and through this service:", + "ar": "تتيح لك هذه الخدمة رؤية جميع المواعيد التي زرتها في مجموعة الحبيب الطبية، ومن خلال هذه الخدمة:" + }, + "infoTodo": { + "en": "This service is designed to enable you to have a quick link to the list of tasks that need to be done", + "ar": "تم تصميم هذه الخدمة لتمكينك من الحصول على رابط سريع لقائمة المهام التي تحتاج القيام بها" + }, + "familyInfo": { + "en": "Through this service, you will be able to link your family medical files to your medical file so that you can manage their records by login to your medical file.", + "ar": "من خلال هذه الخدمة، ستتمكن من ربط ملفات عائلتك الطبية بملفك الطبي حتى تتمكن من إدارة سجلاتهم عن طريق تسجيل الدخول إلى ملفك الطبي." + }, + "rrtdDetails": { + "en": "The Rapid response team provides a comprehensive medical service for all sorts of urgent and stable cases of all ages, including adult and paediatric patients, the service is covered by a fully equipped and highly trained medical team capable of providing the best medical care at the patient’s home.", + "ar": "تقدم فريق الاستجابة السريعة خدمة طبية شاملة لجميع أنواع الحالات العاجلة والمستقرة من جميع الأعمار، بما في ذلك البالغين والمرضى الأطفال، وتغطي الخدمة فريق طبي مدرب تدريبًا عاليًا ومجهز تجهيزًا كاملًا قادرًا على تقديم أفضل رعاية طبية في منزل المريض." + }, + "onlineCheckInAgreement": { + "en": "The online check-in is for non-life threatening situation. Call the red crescent (997) or go to the nearest emergency department if there are: \n\nsigns of stroke or heart attack \nhistory of seizure or syncope \nthere is limb or life threatening injury \npicture of severe injuries", + "ar": "تسجيل الوصول عبر الإنترنت مخصص للحالات التي لا تهدد الحياة. اتصل بالهلال الأحمر (997) أو اذهب إلى أقرب قسم طوارئ إذا كان هناك: \n\nعلامات السكتة الدماغية أو النوبة القلبية \nhالة من النوبات أو الإغماء \nهناك إصابة تهدد الطرف أو الحياة \nصورة لإصابات خطيرة" + }, + "infoEreferral": { + "en": "This service allows you to submit a Referral request from any health care providers either inside or outside the kingdom of Saudi Arabia to any of HMG Hospitals, by filling some of the patient's data and attaching the medical reports, moreover you can track the request status (Under process, Accepted or Rejected)", + "ar": "تتيح لك هذه الخدمة تقديم طلب إحالة من أي مقدم رعاية صحية سواء داخل أو خارج المملكة العربية السعودية إلى أي من مستشفيات HMG، عن طريق ملء بعض بيانات المريض وإرفاق التقارير الطبية، علاوة على ذلك يمكنك تتبع حالة الطلب (قيد المعالجة، مقبول أو مرفوض)" + }, + "erConsultation": { + "en": "This service allows you to make an online virtual consultation via video call directly with the doctor from anywhere at any time.", + "ar": "تتيح لك هذه الخدمة إجراء استشارة افتراضية عبر الإنترنت عبر مكالمة فيديو مباشرة مع الطبيب من أي مكان وفي أي وقت." + }, + "myInvoice": { + "en": "List", + "ar": "القائمة" + }, + "invoiceList": { + "en": "My Invoice", + "ar": "فواتيري" + }, + "thisItemIsNotAvailable": { + "en": "This item is not available", + "ar": "هذا العنصر غير متوفر" + }, + "beforeAfterImages": { + "en": "Before & After Images", + "ar": "صور قبل وبعد" + }, + "clinicAcceptLivecare": { + "en": "No need to wait or visit You can now get medical consultation via Video call (LiveCare service) in The name of the clinic clinic and the doctor will contact you immediately", + "ar": "لا حاجة للانتظار أو الزيارة يمكنك الآن الحصول على استشارة طبية عبر مكالمة فيديو (لايف كير) في اسم العيادة وسيتصل بك الطبيب على الفور" + }, + "livecareModalTop": { + "en": "This Clinic is Accepting LiveCare services", + "ar": "تقبل هذه العيادة خدمات ال لايف كير" + }, + "livecarePoint2": { + "en": "A Specialized doctor will contact you", + "ar": "سوف يتصل بك طبيب متخصص" + }, + "livecarePoint3": { + "en": "A Doctor will be able to see your full medical file history", + "ar": "سيكون لدى الطبيب القدرة على رؤية تاريخ ملفك الطبي الكامل" + }, + "livecarePoint4": { + "en": "Free Medicine Delivery Available", + "ar": "تتوفر خدمة توصيل الأدوية المجانية" + }, + "livecarePoint5": { + "en": "No need to visit the service is in your place", + "ar": "لا حاجة للزيارة، الخدمة في مكانك" + }, + "bookImmediateLivecare": { + "en": "I accept to get the service immediately", + "ar": "أوافق على الحصول على الخدمة على الفور" + }, + "bookVideoLivecare2": { + "en": "I don't need to visit the clinic", + "ar": "لا أحتاج لزيارة العيادة" + }, + "noThankyou": { + "en": "No Thanks", + "ar": "لا شكرًا" + }, + "visitClinic": { + "en": "Schedule appointment with the doctor", + "ar": "جدولة موعد مع الطبيب" + }, + "generateCovidCertificate": { + "en": "Generate Covid-19 Certificate", + "ar": "إصدار شهادة كوفيد-19" + }, + "isReportOutsideKsa": { + "en": "Is the certificate needed for outside KSA?", + "ar": "هل الشهادة مطلوبة خارج المملكة العربية السعودية؟" + }, + "passportNumber": { + "en": "Passport Number", + "ar": "رقم جواز السفر" + }, + "enterPassportNumber": { + "en": "Please confirm or update your passport number:", + "ar": "يرجى تأكيد أو تحديث رقم جواز السفر الخاص بك:" + }, + "validPassportNumber": { + "en": "Please enter valid passport number", + "ar": "يرجى إدخال رقم جواز سفر صالح" + }, + "continuePlan": { + "en": "Continue with the treatment plan?", + "ar": "متابعة خطة العلاج؟" + }, + "aboutApp": { + "en": "About the app", + "ar": "حول التطبيق" + }, + "dontHaveAccount": { + "en": "Don't have an account?", + "ar": "ليس لديك حساب؟" + }, + "loginOrRegister": { + "en": "Login or Register", + "ar": "تسجيل الدخول أو التسجيل" + }, + "myFiles": { + "en": "My Files", + "ar": "ملفاتي" + }, + "resultsPending": { + "en": "Results pending", + "ar": "النتائج معلقة" + }, + "resultsAvailable": { + "en": "Results available", + "ar": "النتائج متاحة" + }, + "viewReport": { + "en": "View Report", + "ar": "عرض التقرير" + }, + "checkAvailability": { + "en": "Check Availability", + "ar": "التحقق من التوفر" + }, + "readInstructions": { + "en": "Read Instructions", + "ar": "قراءة التعليمات" + }, + "searchLabReport": { + "en": "Search Lab Report", + "ar": "ابحث عن تقرير المختبر" + }, + "prescriptionDeliveryError": { + "en": "This Clinic Does Not Support Refill And Delivery.", + "ar": "هذه العيادة لا تدعم إعادة التعبئة والتسليم." + }, + "receiveOtpToast": { + "en": "Where would you like to receive OTP?", + "ar": "أين تود تلقي رمز التحقق OTP؟" + }, + "enterPhoneNumber": { + "en": "Enter Phone Number", + "ar": "أدخل رقم الهاتف" + }, + "enterEmailDesc": { + "en": "Enter your email to complete medical profile creation process", + "ar": "أدخل عنوان بريدك الإلكتروني لإكمال عملية إنشاء ملف طبي" + }, + "enterPhoneDesc": { + "en": "Enter your phone number to receive OTP ", + "ar": "أدخل رقم هاتفك لتلقي رمز التحقق " + }, + "pleaseChooseOption": { + "en": "Please select from the below options to receive OTP", + "ar": "الرجاء اختيار من الخيارات أدناه لتلقي رمز التحقق OTP" + }, + "prepareToElevate": { + "en": "Prepared to elevate your health and well-being?", + "ar": "هل أنت مستعد لتحسين صحتك ورفاهيتك؟" + }, + "iAcceptTermsConditions": { + "en": "I Accept the Terms and Conditions", + "ar": "أوافق على الشروط والأحكام" + }, + "alreadyHaveAccount": { + "en": "Already have an account?", + "ar": "هل لديك حساب بالفعل؟" + }, + "loginNow": { + "en": "Login Now", + "ar": "تسجيل الدخول الآن" + }, + "notice": { + "en": "Notice", + "ar": "إشعار" + }, + "oR": { + "en": "OR", + "ar": "أو" + }, + "sendOTPWHATSAPP": { + "en": "Send me OTP on Whatsapp", + "ar": "أرسل لي OTP عبر واتساب" + }, + "sendOTPSMS": { + "en": "Send me OTP on SMS", + "ar": "أرسل لي OTP عبر الرسائل القصيرة" + }, + "fullName": { + "en": "Full Name", + "ar": "الاسم الكامل" + }, + "married": { + "en": "Married", + "ar": "متزوج" + }, + "uae": { + "en": "United Arab Emirates", + "ar": "الإمارات العربية المتحدة" + }, + "malE": { + "en": "Male", + "ar": "ذكر" + }, + "loginBy": { + "en": "Login By", + "ar": "تسجيل الدخول بواسطة" + }, + "loginByOTP": { + "en": "Login By OTP", + "ar": "تسجيل الدخول بواسطة OTP" + }, + "guest": { + "en": "Guest", + "ar": "زائر" + }, + "switchAccount": { + "en": "Switch Account", + "ar": "تبديل الحساب" + }, + "lastLoginBy": { + "en": "Last login by", + "ar": "آخر تسجيل دخول بواسطة" + }, + "allSet": { + "en": "All Set! Now you can login with Face ID or Biometric", + "ar": "جاهز! الآن يمكنك تسجيل الدخول باستخدام Face ID أو البصمة" + }, + "enableQuickLogin": { + "en": "Enable Quick Login", + "ar": "تمكين تسجيل الدخول السريع" + }, + "enableMsg": { + "en": "Enabling the quick login will verify through your existing device Face ID / Biometric", + "ar": "تمكين تسجيل الدخول السريع سيسمح بالتحقق من خلال Face ID / Biometric الخاص بجهازك الحالي" + }, + "notNow": { + "en": "Not Now", + "ar": "ليس الآن" + }, + "pendingActivation": { + "en": "Pending Activation", + "ar": "في انتظار التنشيط" + }, + "awaitingApproval": { + "en": "Awaiting Approval", + "ar": "انتظر القبول" + }, + "news": { + "en": "News", + "ar": "أخبار" + }, + "ready": { + "en": "Ready", + "ar": "جاهز" + }, + "enterValidNationalId": { + "en": "Please enter a valid national ID or file number", + "ar": "الرجاء إدخال رقم الهوية الوطنية أو رقم الملف الصحيح" + }, + "enterValidPhoneNumber": { + "en": "Please enter a valid phone number", + "ar": "الرجاء إدخال رقم هاتف صالح" + }, + "cannotEnterSaudiOrUAENumber": { + "en": "You cannot enter Saudi Arabia (00966) or UAE (00971) phone numbers when 'Others' country is selected", + "ar": "لا يمكنك إدخال أرقام هواتف السعودية (00966) أو الإمارات (00971) عند اختيار دولة 'أخرى'" + }, + "medicalCentersWithCount": { + "en": "{count} Medical Centers", + "ar": "{count} مراكز طبية" + }, + "medicalCenters": { + "en": " Medical Centers", + "ar": "مراكز طبية" + }, + "hospitalsWithCount": { + "en": "{count} Hospitals", + "ar": "{count} مستشفيات" + }, + "selectRegion": { + "en": "Select Region", + "ar": "اختر المنطقة" + }, + "selectFacility": { + "en": "Select Facilities", + "ar": "اختر المرافق" + }, + "selectFacilitiesSubTitle": { + "en": "Please select the facility for the appointment", + "ar": "يرجى اختيار المرفق للموعد" + }, + "selectHospitalSubTitle": { + "en": "Please select the hospital for the appointment", + "ar": "يرجى اختيار المستشفى للموعد" + }, + "iAcceptThe": { + "en": "I Accept the", + "ar": "أوافق على" + }, + "personalDetailsVerification": { + "en": "Personal Details Verification", + "ar": "التحقق من التفاصيل الشخصية" + }, + "otpVerification": { + "en": "OTP Verification", + "ar": "التحقق من OTP" + }, + "weHaveSendOTP": { + "en": "We have sent you the OTP code on", + "ar": "لقد أرسلنا OTP إلى" + }, + "via": { + "en": "via", + "ar": "عبر" + }, + "forRegistrationVerification": { + "en": "for registration verification", + "ar": "للتحقق من التسجيل" + }, + "didntReceiveIt": { + "en": "Didn't receive it?", + "ar": "لم تستلمه؟" + }, + "resendOTP": { + "en": "Resend", + "ar": "إعادة إرسال" + }, + "resendIn": { + "en": "resend in", + "ar": "إعادة الإرسال في" + }, + "pleaseEnterAnationalID": { + "en": "Please enter a national ID", + "ar": "يرجى إدخال رقم الهوية الوطنية" + }, + "pleaseEnterAFileNumber": { + "en": "Please enter a file number", + "ar": "يرجى إدخال رقم الملف" + }, + "pleaseEnterAValidEmail": { + "en": "Please enter a valid email", + "ar": "يرجى إدخال بريد إلكتروني صالح" + }, + "pleaseEnterFullName": { + "en": "Please enter full name", + "ar": "يرجى إدخال الاسم الكامل" + }, + "pleaseAcceptTermsConditions": { + "en": "Please accept the terms and conditions", + "ar": "يرجى قبول الشروط والأحكام" + }, + "pleaseEnterAValidIqamaID": { + "en": "Please enter a valid Iqama ID", + "ar": "يرجى إدخال رقم إقامة صالح" + }, + "pleaseEnterAValidNationalID": { + "en": "Please enter a valid national ID", + "ar": "يرجى إدخال رقم هوية وطنية صالح" + }, + "pleaseEnterAValidDateOfBirth": { + "en": "Please enter a valid date of birth", + "ar": "يرجى إدخال تاريخ ميلاد صالح" + }, + "pleaseEnterAValidName": { + "en": "Please enter a valid name", + "ar": "يرجى إدخال اسم صالح" + }, + "pleaseSelectAGender": { + "en": "Please select a gender", + "ar": "يرجى اختيار الجنس" + }, + "pleaseSelectAMaritalStatus": { + "en": "Please select a marital status", + "ar": "يرجى اختيار الحالة الاجتماعية" + }, + "pleaseSelectACountry": { + "en": "Please select a country", + "ar": "يرجى اختيار الدولة" + }, + "pleaseEnterEmail": { + "en": "Please enter email", + "ar": "يرجى إدخال البريد الإلكتروني" + }, + "pleaseEnterAValidEmailFormat": { + "en": "Please enter a valid email format", + "ar": "يرجى إدخال تنسيق بريد إلكتروني صالح" + }, + "selectCountry": { + "en": "Select Country", + "ar": "اختر الدولة" + }, + "forLoginVerification": { + "en": "for login verification", + "ar": "للتحقق من تسجيل الدخول" + }, + "searchHospital": { + "en": "Search Hospital", + "ar": "بحث في المستشفى" + }, + "skip": { + "en": "Skip", + "ar": "تخطي" + }, + "getStarted": { + "en": "Get Started", + "ar": "ابدأ الآن" + }, + "onboardingHeading1": { + "en": "Booking appointment has never been easy", + "ar": "حجز المواعيد لم يكن أسهل من الآن." + }, + "onboardingBody1": { + "en": "In few clicks find yourself having consultation with the doctor of your choice.", + "ar": "ببضع نقرات فقط يمكنك استشارة الطبيب الذي تختاره." + }, + "onboardingHeading2": { + "en": "Access the medical history on finger tips", + "ar": "الوصول إلى السجل الطبي بين يديك" + }, + "onboardingBody2": { + "en": "Keep track on your medical history including labs, prescription, insurance, etc", + "ar": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها." + }, + "hmgHospitals": { + "en": "HMG Hospitals", + "ar": "مستشفيات مجموعة الحبيب الطبية" + }, + "hmcMedicalClinic": { + "en": "HMC Medical Centers", + "ar": "مراكز مجموعة الحبيب الطبية" + }, + "applyFilter": { + "en": "Apply Filter", + "ar": "تطبيق الفلتر" + }, + "facilityAndLocation": { + "en": "Facility and Location", + "ar": "المرفق والموقع" + }, + "regionAndLocation": { + "en": "Region And Locations", + "ar": "المنطقة والمواقع" + }, + "clearAllFilters": { + "en": "Clear all filters", + "ar": "مسح جميع الفلاتر" + }, + "filters": { + "en": "Filters", + "ar": "فلاتر" + }, + "searchClinic": { + "en": "Search Clinic", + "ar": "بحث عن عيادة" + }, + "normal": { + "en": "Normal", + "ar": "عادي" + }, + "attention": { + "en": "Attention", + "ar": "انتباه" + }, + "monitor": { + "en": "Monitor", + "ar": "مراقبة" + }, + "noSpecialResult": { + "en": "No Special Results", + "ar": "لا توجد نتائج خاصة" + }, + "setTheDateRange": { + "en": "Set The Date Range", + "ar": "تعيين النطاق الزمني" + }, + "historyFlowchart": { + "en": "History FlowChart", + "ar": "مخطط تدفق التاريخ" + }, + "to": { + "en": "to", + "ar": "إلى" + }, + "startDate": { + "en": "Start Date", + "ar": "تاريخ البدء" + }, + "endDate": { + "en": "End Date", + "ar": "تاريخ الانتهاء" + }, + "walkin": { + "en": "Walk In", + "ar": "زيارة بدون موعد" + }, + "laserClinic": { + "en": "Laser Clinic", + "ar": "عيادة الليزر" + }, + "continueString": { + "en": "Continue", + "ar": "يكمل" + }, + "covid_info": { + "en": "Dr. Sulaiman Al Habib hospitals are conducting a test for the emerging corona virus and issuing travel certificates 24/7 in a short time and with high accuracy...", + "ar": "تجري مستشفيات د. سليمان الحبيب فحص فيروس كورونا المستجد وتصدر شهادات السفر على مدار الساعة..." + }, + "appointmentDetails": { + "en": "Appointment Details", + "ar": "تفاصيل الموعد" + }, + "checkingDoctorAvailability": { + "en": "Checking doctor availability...", + "ar": "جاري التحقق من توفر الطبيب..." + }, + "cancellingAppointmentPleaseWait": { + "en": "Cancelling Appointment, Please Wait...", + "ar": "جاري إلغاء الموعد، يرجى الانتظار..." + }, + "appointmentCancelledSuccessfully": { + "en": "Appointment Cancelled Successfully", + "ar": "تم إلغاء الموعد بنجاح" + }, + "notConfirmed": { + "en": "Not Confirmed", + "ar": "غير مؤكد" + }, + "appointmentStatus": { + "en": "Appointment Status", + "ar": "حالة الموعد" + }, + "doctorWillCallYou": { + "en": "The doctor will call you once the appointment time approaches.", + "ar": "سيتصل بك الطبيب عندما يقترب موعدك." + }, + "getDirections": { + "en": "Get Directions", + "ar": "الحصول على الاتجاهات" + }, + "notifyMeBeforeAppointment": { + "en": "Notify me before the appointment", + "ar": "أبلغني قبل الموعد" + }, + "fetchingLabResults": { + "en": "Fetching Lab Results...", + "ar": "جاري جلب نتائج المختبر..." + }, + "fetchingRadiologyResults": { + "en": "Fetching Radiology Results...", + "ar": "جاري جلب نتائج الأشعة..." + }, + "fetchingAppointmentPrescriptions": { + "en": "Fetching Appointment Prescriptions...", + "ar": "جاري جلب وصفات الموعد..." + }, + "noPrescriptionsForAppointment": { + "en": "You don't have any prescriptions for this appointment.", + "ar": "ليس لديك أي وصفات طبية لهذا الموعد." + }, + "amountBeforeTax": { + "en": "Amount before tax", + "ar": "المبلغ قبل الضريبة" + }, + "rebookAppointment": { + "en": "Re-book Appointment", + "ar": "إعادة حجز الموعد" + }, + "fetchingDoctorSchedulePleaseWait": { + "en": "Fetching Doctor Schedule, Please Wait...", + "ar": "جاري جلب جدول الطبيب، يرجى الانتظار..." + }, + "pickADate": { + "en": "Pick a Date", + "ar": "اختر تاريخاً" + }, + "confirmingAppointmentPleaseWait": { + "en": "Confirming Appointment, Please Wait...", + "ar": "جاري تأكيد الموعد، يرجى الانتظار..." + }, + "appointmentConfirmedSuccessfully": { + "en": "Appointment Confirmed Successfully", + "ar": "تم تأكيد الموعد بنجاح" + }, + "appointmentPayment": { + "en": "Appointment Payment", + "ar": "دفع الموعد" + }, + "checkingPaymentStatusPleaseWait": { + "en": "Checking payment status, Please wait...", + "ar": "جاري التحقق من حالة الدفع، يرجى الانتظار..." + }, + "paymentFailedPleaseTryAgain": { + "en": "Payment Failed! Please try again.", + "ar": "فشل الدفع! يرجى المحاولة مرة أخرى." + }, + "appointmentCheckIn": { + "en": "Appointment check in", + "ar": "تسجيل حضور الموعد" + }, + "insuranceExpiredOrInactive": { + "en": "Insurance expired or inactive", + "ar": "التأمين منتهي الصلاحية أو غير نشط" + }, + "totalAmountToPay": { + "en": "Total amount to pay", + "ar": "المبلغ الإجمالي المستحق" + }, + "vat15": { + "en": "VAT 15%", + "ar": "ضريبة القيمة المضافة 15%" + }, + "liveCare": { + "en": "LiveCare", + "ar": "لايف كير" + }, + "recentVisits": { + "en": "Recent Visits", + "ar": "الزيارات الأخيرة" + }, + "searchByClinic": { + "en": "Search By Clinic", + "ar": "البحث حسب العيادة" + }, + "tapToSelectClinic": { + "en": "Tap to select clinic", + "ar": "انقر لاختيار العيادة" + }, + "searchByDoctor": { + "en": "Search By Doctor", + "ar": "البحث حسب الطبيب" + }, + "tapToSelect": { + "en": "Tap to select", + "ar": "انقر للاختيار" + }, + "searchByRegion": { + "en": "Search By Region", + "ar": "البحث حسب المنطقة" + }, + "centralRegion": { + "en": "Central Region", + "ar": "المنطقة الوسطى" + }, + "immediateConsultation": { + "en": "Immediate Consultation", + "ar": "استشارة فورية" + }, + "scheduledConsultation": { + "en": "Scheduled Consultation", + "ar": "استشارة مجدولة" + }, + "pharmaLiveCare": { + "en": "Pharma LiveCare", + "ar": "لايف كير الصيدلية" + }, + "notSureHelpMeChooseClinic": { + "en": "Not sure? help me choose a clinic!", + "ar": "غير متأكد؟ ساعدني في اختيار عيادة!" + }, + "mentionYourSymptomsAndFindDoctors": { + "en": "Mention your symptoms and find the list of doctors accordingly", + "ar": "اذكر أعراضك واعثر على قائمة الأطباء وفقاً لذلك" + }, + "immediateService": { + "en": "Immediate service", + "ar": "خدمة فورية" + }, + "noNeedToWaitGetMedicalConsultation": { + "en": "No need to wait, you will get medical consultation immediately via video call", + "ar": "لا حاجة للانتظار، ستحصل على استشارة طبية فورية عبر مكالمة فيديو" + }, + "noVisitRequired": { + "en": "No visit required", + "ar": "لا حاجة للزيارة" + }, + "doctorWillContact": { + "en": "Doctor will contact", + "ar": "سيتصل بك الطبيب" + }, + "specialisedDoctorWillContactYou": { + "en": "A specialised doctor will contact you and will be able to view your medical history", + "ar": "سيتصل بك طبيب متخصص وسيكون قادراً على الاطلاع على تاريخك الطبي" + }, + "freeMedicineDelivery": { + "en": "Free medicine delivery", + "ar": "توصيل مجاني للأدوية" + }, + "offersFreeMedicineDelivery": { + "en": "Offers free medicine delivery for the LiveCare appointment", + "ar": "يوفر توصيل مجاني للأدوية لموعد لايف كير" + }, + "dentalChiefComplaints": { + "en": "Dental Chief Complaints", + "ar": "الشكاوى الرئيسة للأسنان" + }, + "viewAvailableAppointments": { + "en": "View available appointments", + "ar": "عرض المواعيد المتاحة" + }, + "doctorProfile": { + "en": "Doctor Profile", + "ar": " ملف الطبيب" + }, + "waitingAppointment": { + "en": "Waiting Appointment", + "ar": "موعد الانتظار" + }, + "hospitalInformation": { + "en": "Hospital Information", + "ar": "معلومات المستشفى" + }, + "fetchingAppointmentShare": { + "en": "Fetching Appointment Share...", + "ar": "جاري جلب تفاصيل الموعد..." + }, + "bookingYourAppointment": { + "en": "Booking your appointment...", + "ar": "جاري حجز موعدك..." + }, + "selectLiveCareClinic": { + "en": "Select LiveCare Clinic", + "ar": "اختر عيادة لايف كير" + }, + "checkingForExistingDentalPlan": { + "en": "Checking for an existing dental plan, Please wait...", + "ar": "جاري التحقق من وجود خطة أسنان حالية، يرجى الانتظار..." + }, + "dentalTreatmentPlan": { + "en": "Dental treatment plan", + "ar": "خطة علاج الأسنان" + }, + "youHaveExistingTreatmentPlan": { + "en": "You have an existing treatment plan: ", + "ar": "لديك خطة علاج حالية: " + }, + "mins": { + "en": "Mins", + "ar": "دقيقة" + }, + "totalTimeRequired": { + "en": "Total time required", + "ar": "إجمالي الوقت المطلوب" + }, + "wouldYouLikeToContinue": { + "en": "Would you like to continue it?", + "ar": "هل تريد متابعتها؟" + }, + "chooseDoctor": { + "en": "Choose Doctor", + "ar": "اختر الطبيب" + }, + "viewNearestAppos": { + "en": "View nearest available appointments", + "ar": "عرض أقرب المواعيد المتاحة" + }, + "noDoctorFound": { + "en": "No Doctor found for selected criteria...", + "ar": "لم يتم العثور على طبيب مطابق للمعايير المحددة..." + }, + "yesPleasImInAHurry": { + "en": "Yes please, I am in a hurry", + "ar": "نعم من فضلك، أنا في عجلة من أمري" + }, + "fetchingFeesPleaseWait": { + "en": "Fetching fees, Please wait...", + "ar": "جاري جلب الرسوم، يرجى الانتظار..." + }, + "noThanksPhysicalVisit": { + "en": "No, Thanks. I would like a physical visit", + "ar": "لا، شكراً. أفضل الزيارة الشخصية" + }, + "offline": { + "en": "Offline", + "ar": "غير متصل" + }, + "videoCall": { + "en": "Video Call", + "ar": "مكالمة فيديو" + }, + "liveVideoCallWithHMGDoctors": { + "en": "Live Video Call with HMG Doctors", + "ar": "مكالمة فيديو مباشرة مع أطباء مجموعة الحبيب الطبية" + }, + "liveAudioCallWithHMGDoctors": { + "en": "Live Audio Call with HMG Doctors", + "ar": "مكالمة صوتية مباشرة مع أطباء مجموعة الحبيب الطبية" + }, + "audioCall": { + "en": "Audio Call", + "ar": "مكالمة صوتية" + }, + "phoneCall": { + "en": "Phone Call", + "ar": "مكالمة هاتفية" + }, + "livePhoneCallWithHMGDoctors": { + "en": "Live Phone Call with HMG Doctors", + "ar": "مكالمة هاتفية مباشرة مع أطباء مجموعة الحبيب الطبية" + }, + "reviewLiveCareRequest": { + "en": "Review LiveCare Request", + "ar": "مراجعة طلب لايف كير" + }, + "selectedLiveCareType": { + "en": "Selected LiveCare Type", + "ar": "نوع لايف كير المحدد" + }, + "selectLiveCareCallType": { + "en": "Select LiveCare call type", + "ar": "اختر نوع مكالمة لايف كير" + }, + "confirmingLiveCareRequest": { + "en": "Confirming LiveCare request, Please wait...", + "ar": "جاري تأكيد طلب لايف كير، يرجى الانتظار..." + }, + "unknownErrorOccurred": { + "en": "Unknown error occurred...", + "ar": "حدث خطأ غير معروف..." + }, + "liveCarePermissionsMessage": { + "en": "LiveCare requires Camera, Microphone, Location & Notifications permissions to enable virtual consultation between patient & doctor...", + "ar": "يتطلب لايف كير أذونات الكاميرا والميكروفون والموقع والإشعارات لتمكين الاستشارة الافتراضية..." + }, + "liveCarePayment": { + "en": "LiveCare Payment", + "ar": "دفع لايف كير" + }, + "mada": { + "en": "Mada", + "ar": "مدى" + }, + "visaOrMastercard": { + "en": "Visa or Mastercard", + "ar": "فيزا أو ماستركارد" + }, + "tamara": { + "en": "Tamara", + "ar": "تمارا" + }, + "fetchingApplePayDetails": { + "en": "Fetching Apple Pay details, Please wait...", + "ar": "جاري جلب تفاصيل Apple Pay، يرجى الانتظار..." + }, + "liveCarePendingRequest": { + "en": "LiveCare Pending Request", + "ar": "طلب لايف كير قيد الانتظار" + }, + "callLiveCareSupport": { + "en": "Call LiveCare Support", + "ar": "اتصل بدعم لايف كير" + }, + "whatIsWaitingAppointment": { + "en": "What is Waiting Appointment?", + "ar": "ما هو موعد الانتظار؟" + }, + "waitingAppointmentsFeature": { + "en": "The waiting appointments feature allows you to book an appointment while you are inside the hospital building...", + "ar": "تتيح لك ميزة مواعيد الانتظار حجز موعد أثناء تواجدك داخل مبنى المستشفى..." + }, + "appointmentWithDoctorConfirmed": { + "en": "The appointment with the doctor is confirmed, but the time of entry is uncertain.", + "ar": "الموعد مع الطبيب مؤكد، ولكن وقت الدخول غير محدد." + }, + "paymentWithinTenMinutes": { + "en": "Note: You must have to pay within 10 minutes of booking, otherwise your appointment will be cancelled automatically", + "ar": "ملاحظة: يجب عليك الدفع خلال 10 دقائق من الحجز، وإلا سيتم إلغاء موعدك تلقائياً" + }, + "liveLocation": { + "en": "Live Location", + "ar": "الموقع المباشر" + }, + "verifyYourLocationAtHospital": { + "en": "Verify your location to be at hospital to check in", + "ar": "تحقق من موقعك في المستشفى لتسجيل الحضور" + }, + "error": { + "en": "Error", + "ar": "خطأ" + }, + "ensureWithinHospitalLocation": { + "en": "Please ensure you're within the hospital location to perform online check-in.", + "ar": "يرجى التأكد من أنك داخل موقع المستشفى لإجراء تسجيل الحضور عبر الإنترنت." + }, + "nfcNearFieldCommunication": { + "en": "NFC (Near Field Communication)", + "ar": "NFC (الاتصال قريب المدى)" + }, + "scanPhoneViaNFC": { + "en": "Scan your phone via NFC board to check in", + "ar": "امسح هاتفك عبر لوحة NFC لتسجيل الحضور" + }, + "qrCode": { + "en": "QR Code", + "ar": "رمز QR" + }, + "scanQRCodeToCheckIn": { + "en": "Scan QR code with your camera to check in", + "ar": "امسح رمز QR بالكاميرا لتسجيل الحضور" + }, + "processingCheckIn": { + "en": "Processing Check-In...", + "ar": "جاري معالجة تسجيل الحضور..." + }, + "bookingWaitingAppointment": { + "en": "Booking Waiting Appointment, Please wait...", + "ar": "جاري حجز موعد الانتظار، يرجى الانتظار..." + }, + "enterValidIDorIqama": { + "en": "Please enter a valid national ID or file number", + "ar": "يرجى إدخال رقم هوية وطنية أو رقم ملف صالح" + }, + "selectAppointment": { + "en": "Select Appointment", + "ar": "حدد الموعد" + }, + "rebookSameDoctor": { + "en": "Rebook with same doctor", + "ar": "أعد الحجز مع نفس الطبيب" + }, + "queueing": { + "en": "Queueing", + "ar": "قائمة الانتظار" + }, + "inQueue": { + "en": "In Queue", + "ar": "في قائمة الانتظار" + }, + "yourTurn": { + "en": "Your Turn", + "ar": "دورك" + }, + "halaFirstName": { + "en": "Hala {firstName}!!!", + "ar": "هلا {firstName}!!!" + }, + "thankYouForPatience": { + "en": "Thank you for your patience, here is your queue number.", + "ar": "شكراً لصبرك، هذا هو رقم قائمة الانتظار الخاص بك." + }, + "servingNow": { + "en": "Serving Now", + "ar": "يُخدم الآن" + }, + "callForVitalSigns": { + "en": "Call for vital signs", + "ar": "نداء للعلامات الحيوية" + }, + "callForDoctor": { + "en": "Call for Doctor", + "ar": "نداء للطبيب" + }, + "thingsToAskDoctor": { + "en": "Things to ask your doctor today", + "ar": "أشياء تسأل طبيبك عنها اليوم" + }, + "improveOverallHealth": { + "en": "What can I do to improve my overall health?", + "ar": "ماذا يمكنني أن أفعل لتحسين صحتي العامة؟" + }, + "routineScreenings": { + "en": "Are there any routine screenings I should get?", + "ar": "هل هناك أي فحوصات روتينية يجب أن أجريها؟" + }, + "whatIsThisMedicationFor": { + "en": "What is this medication for?", + "ar": "لماذا هذا الدواء؟" + }, + "sideEffectsToKnow": { + "en": "Are there any side effects I should know about?", + "ar": "هل هناك أي آثار جانبية يجب أن أعرفها؟" + }, + "whenFollowUp": { + "en": "When should I come back for a follow-up?", + "ar": "متى يجب أن أعود للمتابعة؟" + }, + "goToHomepage": { + "en": "Go to homepage", + "ar": "الذهاب إلى الصفحة الرئيسية" + }, + "appointmentsList": { + "en": "Appointments List", + "ar": "قائمة المواعيد" + }, + "allAppt": { + "en": "All Appt.", + "ar": "جميع المواعيد" + }, + "upcoming": { + "en": "Upcoming", + "ar": "القادمة" + }, + "completed": { + "en": "Completed", + "ar": "المكتملة" + }, + "noAppointmentsYet": { + "en": "You don't have any appointments yet.", + "ar": "ليس لديك أي مواعيد بعد." + }, + "viewProfile": { + "en": "View Profile", + "ar": "عرض الملف الشخصي" + }, + "choosePreferredHospitalForService": { + "en": "Choose your preferred hospital for the service", + "ar": "اختر المستشفى المفضل لديك للخدمة" + }, + "noHospitalsFound": { + "en": "No hospitals Found", + "ar": "لم يتم العثور على مستشفيات" + }, + "cancelOrderConfirmation": { + "en": "Are you sure you want to cancel this order?", + "ar": "هل أنت متأكد أنك تريد إلغاء هذا الطلب؟" + }, + "orderCancelledSuccessfully": { + "en": "Order has been cancelled successfully", + "ar": "تم إلغاء الطلب بنجاح" + }, + "requestID": { + "en": "Request ID:", + "ar": "معرف الطلب:" + }, + "noCMCOrdersYet": { + "en": "You don't have any CMC orders yet.", + "ar": "ليس لديك أي طلبات فحص شامل بعد." + }, + "cmcOrders": { + "en": "CMC Orders", + "ar": "طلبات الفحص الشامل" + }, + "summary": { + "en": "Summary", + "ar": "الملخص" + }, + "selectedService": { + "en": "Selected Service", + "ar": "الخدمة المحددة" + }, + "requestSubmittedSuccessfully": { + "en": "Your request has been successfully submitted.", + "ar": "تم إرسال طلبك بنجاح." + }, + "hereIsYourRequestNumber": { + "en": "Here is your request #: ", + "ar": "هذا هو رقم طلبك #: " + }, + "pleaseSelectHospitalToContinue": { + "en": "Please select a hospital to continue", + "ar": "يرجى اختيار مستشفى للمتابعة" + }, + "confirmSubmitRequest": { + "en": "Are you sure you want to submit this request?", + "ar": "هل أنت متأكد أنك تريد إرسال هذا الطلب؟" + }, + "pendingOrderWait": { + "en": "You have a pending order. Please wait for it to be processed.", + "ar": "لديك طلب معلق. يرجى الانتظار حتى تتم معالجته." + }, + "noServicesAvailable": { + "en": "No services available", + "ar": "لا توجد خدمات متاحة" + }, + "selectAService": { + "en": "Select a Service", + "ar": "اختر خدمة" + }, + "comprehensiveCheckup": { + "en": "Comprehensive Checkup", + "ar": "الفحص الشامل" + }, + "viewNearestHMGLocations": { + "en": "View your nearest HMG locations", + "ar": "عرض أقرب مواقع مجموعة الحبيب الطبية" + }, + "provideFeedbackOnServices": { + "en": "Provide your feedback on our services", + "ar": "قدم ملاحظاتك على خدماتنا" + }, + "liveChatWithHMG": { + "en": "Live chat option with HMG", + "ar": "خيار الدردشة المباشرة مع مجموعة الحبيب الطبية" + }, + "send": { + "en": "Send", + "ar": "إرسال" + }, + "status": { + "en": "Status", + "ar": "الحالة" + }, + "sendingFeedback": { + "en": "Sending Feedback...", + "ar": "جاري إرسال الملاحظات..." + }, + "selectFeedbackType": { + "en": "Select Feedback Type", + "ar": "اختر نوع الملاحظات" + }, + "loadingAppointmentsList": { + "en": "Loading appointments list...", + "ar": "جاري تحميل قائمة المواعيد..." + }, + "noAppointmentsForFeedback": { + "en": "You do not have any appointments to submit a feedback.", + "ar": "ليس لديك أي مواعيد لتقديم ملاحظات عنها." + }, + "selectedAppointment": { + "en": "Selected Appointment:", + "ar": "الموعد المحدد:" + }, + "subject": { + "en": "Subject", + "ar": "الموضوع" + }, + "enterSubjectHere": { + "en": "Enter subject here", + "ar": "أدخل الموضوع هنا" + }, + "message": { + "en": "Message", + "ar": "الرسالة" + }, + "enterMessageHere": { + "en": "Enter message here", + "ar": "أدخل الرسالة هنا" + }, + "filesSelected": { + "en": "{count} file(s) selected", + "ar": "تم تحديد {count} ملف(ات)" + }, + "otherDetails": { + "en": "Other Details", + "ar": "تفاصيل أخرى" + }, + "medicalReport": { + "en": "Medical Report", + "ar": "التقرير الطبي" + }, + "medicalReportNumber": { + "en": "Medical Report {number}", + "ar": "التقرير الطبي {number}" + }, + "patientIsInsured": { + "en": "Patient Is Insured", + "ar": "المريض مؤمن عليه" + }, + "insuranceDocument": { + "en": "Insurance Document", + "ar": "وثيقة التأمين" + }, + "selectBranch": { + "en": "Select Branch", + "ar": "اختر الفرع" + }, + "patientInformation": { + "en": "Patient Information", + "ar": "معلومات المريض" + }, + "patientLocation": { + "en": "Where the patient is located", + "ar": "أين يتواجد المريض" + }, + "identificationNumber": { + "en": "Identification Number", + "ar": "رقم الهوية" + }, + "enterIdentificationNumber": { + "en": "Enter Identification Number*", + "ar": "أدخل رقم الهوية*" + }, + "patientName": { + "en": "Patient Name*", + "ar": "اسم المريض*" + }, + "referralRequesterInformation": { + "en": "Referral Requester Information", + "ar": "معلومات مقدم طلب الإحالة" + }, + "enterReferralRequesterName": { + "en": "Enter Referral Requester Name*", + "ar": "أدخل اسم مقدم طلب الإحالة*" + }, + "requesterName": { + "en": "Requester Name", + "ar": "اسم مقدم الطلب" + }, + "relationship": { + "en": "Relationship", + "ar": "العلاقة" + }, + "selectRelation": { + "en": "Select Relation", + "ar": "اختر العلاقة" + }, + "otherName": { + "en": "Other Name", + "ar": "اسم آخر" + }, + "otherNameHint": { + "en": "Other Name*", + "ar": "اسم آخر*" + }, + "requesterNameRequired": { + "en": "Referral requester name is required", + "ar": "اسم مقدم طلب الإحالة مطلوب" + }, + "selectRelationshipRequired": { + "en": "Please select a relationship", + "ar": "يرجى اختيار العلاقة" + }, + "otherRelationshipNameRequired": { + "en": "Other relationship name is required", + "ar": "اسم العلاقة الأخرى مطلوب" + }, + "identificationNumberRequired": { + "en": "Identification number is required", + "ar": "رقم الهوية مطلوب" + }, + "patientNameRequired": { + "en": "Patient name is required", + "ar": "اسم المريض مطلوب" + }, + "enterPatientPhoneRequired": { + "en": "Please Enter patient phone number", + "ar": "يرجى إدخال رقم هاتف المريض" + }, + "selectPatientCityRequired": { + "en": "Please select patient city", + "ar": "يرجى اختيار مدينة المريض" + }, + "medicalReportRequired": { + "en": "At least one medical report is required", + "ar": "مطلوب تقرير طبي واحد على الأقل" + }, + "selectBranchRequired": { + "en": "Please select a branch", + "ar": "يرجى اختيار الفرع" + }, + "insuranceDocumentRequired": { + "en": "Insurance document is required for insured patients", + "ar": "وثيقة التأمين مطلوبة للمرضى المؤمن عليهم" + }, + "searchResult": { + "en": "Search Result", + "ar": "نتيجة البحث" + }, + "referralNo": { + "en": "Referral No {number}", + "ar": "رقم الإحالة {number}" + }, + "eReferral": { + "en": "E Referral", + "ar": "الإحالة الإلكترونية" + }, + "referralCreatedSuccessfully": { + "en": "Your Referral has been created Successfully.", + "ar": "تم إنشاء إحالتك بنجاح." + }, + "hereIsYourReferralNumber": { + "en": "Here is your Referral #: ", + "ar": "هذا هو رقم الإحالة الخاص بك #: " + }, + "searchEReferral": { + "en": "Search E-Referral", + "ar": "البحث عن إحالة إلكترونية" + }, + "enterRequiredInfoToSearch": { + "en": "Please enter the required information to search for an e-referral", + "ar": "يرجى إدخال المعلومات المطلوبة للبحث عن إحالة إلكترونية" + }, + "selectPickupDirection": { + "en": "Select Pickup Direction", + "ar": "اختر اتجاه الاستلام" + }, + "selectDirection": { + "en": "Select Direction", + "ar": "اختر الاتجاه" + }, + "toHospital": { + "en": "To Hospital", + "ar": "إلى المستشفى" + }, + "fromHospital": { + "en": "From Hospital", + "ar": "من المستشفى" + }, + "selectWay": { + "en": "Select Way", + "ar": "اختر الطريقة" + }, + "oneWay": { + "en": "One Way", + "ar": "اتجاه واحد" + }, + "twoWay": { + "en": "Two Way", + "ar": "اتجاهين" + }, + "selectPickupDetails": { + "en": "Select Pickup Details", + "ar": "اختر تفاصيل الاستلام" + }, + "pleaseSelectDetailsOfPickup": { + "en": " Please select the details of pickup", + "ar": " يرجى تحديد تفاصيل الاستلام" + }, + "selectDetails": { + "en": "Select Details", + "ar": "اختر التفاصيل" + }, + "work": { + "en": "Work", + "ar": "العمل" + }, + "pick": { + "en": "Pick", + "ar": "استلام" + }, + "insideTheHome": { + "en": "Inside the home", + "ar": "داخل المنزل" + }, + "haveAnyAppointment": { + "en": "Have any appointment", + "ar": "هل لديك أي موعد" + }, + "amountPaidAtHospital": { + "en": "Amount will be paid at the hospital", + "ar": "سيتم دفع المبلغ في المستشفى" + }, + "submitRequest": { + "en": "Submit Request", + "ar": "إرسال الطلب" + }, + "enterPickupLocationManually": { + "en": "Enter Pickup Location Manually", + "ar": "أدخل موقع الاستلام يدوياً" + }, + "enterPickupLocation": { + "en": "Enter Pickup Location", + "ar": "أدخل موقع الاستلام" + }, + "trackingDetails": { + "en": "Tracking Details", + "ar": "تفاصيل التتبع" + }, + "cancelRequest": { + "en": "Cancel Request", + "ar": "إلغاء الطلب" + }, + "shareLocationWhatsapp": { + "en": "Share Your Live Location on Whatsapp", + "ar": "مشاركة موقعك المباشر على واتساب" + }, + "pleaseWaitForCall": { + "en": "Please wait for the call", + "ar": "يرجى انتظار المكالمة" + }, + "toHospitalLower": { + "en": "to hospital", + "ar": "إلى المستشفى" + }, + "contact": { + "en": "Contact", + "ar": "اتصال" + }, + "failed": { + "en": "Failed", + "ar": "فشل" + }, + "confirmationCall": { + "en": "Confirmation Call", + "ar": "مكالمة التأكيد" + }, + "pickupFromHome": { + "en": "Pickup Up from Home", + "ar": "الاستلام من المنزل" + }, + "onTheWayToHospital": { + "en": " On The Way To Hospital", + "ar": " في الطريق إلى المستشفى" + }, + "arrivedAtHospital": { + "en": "Arrived at Hospital", + "ar": "وصل إلى المستشفى" + }, + "orderCancel": { + "en": "Order Cancel", + "ar": "إلغاء الطلب" + }, + "emergencyCheckIn": { + "en": "Emergency Check-In", + "ar": "تسجيل الطوارئ الإلكتروني" + }, + "erOnlineCheckInDescription": { + "en": "This service lets patients register their ER appointment prior to arrival.", + "ar": "تتيح هذه الخدمة للمرضى تسجيل موعد الطوارئ قبل الوصول." + }, + "erOnlineCheckInSuccess": { + "en": "Your ER Online Check-In has been successfully done. Please proceed to the waiting area.", + "ar": "تم تسجيل وصول الطوارئ بنجاح. الرجاء التوجه إلى منطقة الانتظار." + }, + "erOnlineCheckInError": { + "en": "Unexpected error occurred during check-in. Please contact support.", + "ar": "حدث خطأ غير متوقع أثناء عملية التسجيل. يرجى التواصل مع الدعم." + }, + "fetchingHospitalsList": { + "en": "Fetching hospitals list...", + "ar": "جاري جلب قائمة المستشفيات..." + }, + "fetchingPaymentInformation": { + "en": "Fetching payment information...", + "ar": "جاري جلب معلومات الدفع..." + }, + "erVisitDetails": { + "en": "ER Visit Details", + "ar": "تفاصيل زيارة الطوارئ" + }, + "erClinic": { + "en": "ER Clinic", + "ar": "عيادة الطوارئ" + }, + "vatWithAmount": { + "en": "VAT 15% ({amount})", + "ar": "الضريبة 15% ({amount})" + }, + "erAppointmentBookedSuccess": { + "en": "Your appointment has been booked successfully. Please perform Check-In once you arrive at the hospital.", + "ar": "تم حجز موعدك بنجاح. يرجى إتمام إجراءات تسجيل الوصول عند وصولك إلى المستشفى." + }, + "underProcessing": { + "en": "Under processing", + "ar": "قيد المعالجة" + }, + "canceledByPatient": { + "en": "Cancelled by patient", + "ar": "ملغى بواسطة المريض" + }, + "rapidResponseTeam": { + "en": "Rapid Response Team", + "ar": "فريق الاستجابة السريع" + }, + "allFacilities": { + "en": "All Facilities", + "ar": "جميع المرافق" + }, + "selectLocation": { + "en": "Select Location", + "ar": "اختر الموقع" + }, + "pleaseSelectTheLocation": { + "en": "Please select the location", + "ar": "يرجى اختيار الموقع" + }, + "viewLocationGoogleMaps": { + "en": "View Location on Google Maps", + "ar": "عرض الموقع على خرائط جوجل" + }, + "callAmbulance": { + "en": "Call Ambulance", + "ar": "استدعاء سيارة إسعاف" + }, + "requestAmbulanceInEmergency": { + "en": "Request an ambulance in emergency from home or hospital", + "ar": "طلب سيارة إسعاف في حالة الطوارئ من المنزل أو المستشفى" + }, + "confirmation": { + "en": "Confirmation", + "ar": "تأكيد" + }, + "areYouSureYouWantToCallAmbulance": { + "en": "Are you sure you want to call an ambulance?", + "ar": "هل أنت متأكد أنك تريد استدعاء سيارة إسعاف؟" + }, + "getDetailsOfNearestBranch": { + "en": "Get the details of nearest branch including directions", + "ar": "احصل على تفاصيل أقرب فرع بما في ذلك الاتجاهات" + }, + "areYouSureYouWantToCallRRT": { + "en": "Are you sure you want to call Rapid Response Team (RRT)?", + "ar": "هل أنت متأكد أنك تريد استدعاء فريق الاستجابة السريعة (RRT)؟" + }, + "priorERCheckInToSkipLine": { + "en": "Prior ER Check-In to skip the line & payment at the reception.", + "ar": "تسجيل الوصول المسبق في الطوارئ لتجاوز الطابور والدفع في الاستقبال." + }, + "areYouSureYouWantToMakeERCheckIn": { + "en": "Are you sure you want to make ER Check-In?", + "ar": "هل أنت متأكد أنك تريد إجراء تسجيل وصول الطوارئ؟" + }, + "checkingYourERAppointmentStatus": { + "en": "Checking your ER Appointment status...", + "ar": "جاري التحقق من حالة موعد الطوارئ الخاص بك..." + }, + "transportOptions": { + "en": "Transport Options", + "ar": "خيارات النقل" + }, + "selectHospitalForAdvancePayment": { + "en": "Please select the hospital you want to make an advance payment for.", + "ar": "يرجى اختيار المستشفى الذي ترغب في دفع مبلغ مقدم له." + }, + "recharge": { + "en": "Recharge", + "ar": "إعادة الشحن" + }, + "activityLevel": { + "en": "Activity Level", + "ar": "مستوى النشاط" + }, + "selectActivityLevel": { + "en": "Select Activity Level", + "ar": "حدد مستوى النشاط" + }, + "caloriesPerDay": { + "en": "Calories Per Day", + "ar": "السعرات الحرارية في اليوم الواحد" + }, + "dietType": { + "en": "Diet Type", + "ar": "نوع النظام الغذائي" + }, + "selectDietType": { + "en": "Select Diet Type", + "ar": "حدد نوع النظام الغذائي" + }, + "bodyFrameSize": { + "en": "Body Frame Size", + "ar": "حجم إطار الجسم" + }, + "selectBodyFrameSize": { + "en": "Select Body Frame Size", + "ar": "حدد حجم إطار الجسم" + }, + "averageCycleLength": { + "en": "Average Cycle Length (Usually 28 days)", + "ar": "متوسط طول الدورة الشهرية (عادةً 28 يومًا)" + }, + "averageLutealPhase": { + "en": "Average Luteal Phase Length(Usually 14 days)", + "ar": "متوسط طول المرحلة الأصفرية (عادةً 14 يومًا)" + }, + "convert": { + "en": "Convert", + "ar": "يتحول" + }, + "calculate": { + "en": "Calculate", + "ar": "احسب" + }, + "healthCalculators": { + "en": "Health Calculators", + "ar": "حاسبات الصحة" + }, + "healthConverters": { + "en": "Health Converters", + "ar": "محولات الصحة" + }, + "generalHealth": { + "en": "General Health", + "ar": "الصحة العامة" + }, + "relatedToBMICalories": { + "en": "Related To BMI, calories, body fat, etc to stay updated with your health.", + "ar": "متعلق بمؤشر كتلة الجسم والسعرات الحرارية ودهون الجسم وما إلى ذلك للبقاء على اطلاع دائم بصحتك." + }, + "selectCalculator": { + "en": "Select Calculator", + "ar": "اختر الآلة الحاسبة" + }, + "womensHealth": { + "en": "Women's Health", + "ar": "صحة المرأة" + }, + "relatedToPeriodsOvulation": { + "en": "Related To periods, ovulation, pregnancy, and other topics.", + "ar": "متعلق بالدورة الشهرية والإباضة والحمل ومواضيع أخرى." + }, + "bloodSugar": { + "en": "Blood Sugar", + "ar": "سكر الدم" + }, + "trackYourGlucoseLevels": { + "en": "Track your glucose levels, understand trends, and get personalized insights for better health.", + "ar": "تتبع مستويات الجلوكوز لديك، وفهم الاتجاهات، واحصل على رؤى مخصصة لصحة أفضل." + }, + "bloodCholesterol": { + "en": "Blood Cholesterol", + "ar": "كوليسترول الدم" + }, + "monitorCholesterolLevels": { + "en": "Monitor cholesterol levels, assess heart health risks, and take proactive steps for well-being.", + "ar": "راقب مستويات الكوليسترول، وقيّم مخاطر صحة القلب، واتخذ خطوات استباقية للرفاهية." + }, + "triglyceridesFatBlood": { + "en": "Triglycerides Fat Blood", + "ar": "الدهون الثلاثية في الدم" + }, + "understandTriglyceridesImpact": { + "en": "Understand triglycerides' impact on heart health with personalized insights and expert recommendations.", + "ar": "افهم تأثير الدهون الثلاثية على صحة القلب مع رؤى مخصصة وتوصيات الخبراء." + }, + "bmiCalculator": { + "en": "BMI\nCalculator", + "ar": "حاسبة\nمؤشر كتلة الجسم" + }, + "caloriesCalculator": { + "en": "Calories\nCalculator", + "ar": "حاسبة\nالسعرات الحرارية" + }, + "bmrCalculator": { + "en": "BMR\nCalculator", + "ar": "حاسبة\nمعدل الأيض الأساسي" + }, + "idealBodyWeight": { + "en": "Ideal Body\nWeight", + "ar": "الوزن المثالي\nللجسم" + }, + "bodyFatCalculator": { + "en": "Body Fat\nCalculator", + "ar": "حاسبة\nدهون الجسم" + }, + "carbsProteinFat": { + "en": "Carbs\nProtein & Fat", + "ar": "الكربوهيدرات\nالبروتين والدهون" + }, + "ovulationPeriod": { + "en": "Ovulation\nPeriod", + "ar": "فترة\nالإباضة" + }, + "deliveryDueDate": { + "en": "Delivery\nDue Date", + "ar": "تاريخ الولادة\nالمتوقع" + }, + "low": { + "en": "Low", + "ar": "منخفض" + }, + "preDiabetic": { + "en": "Pre-diabetic", + "ar": "ما قبل السكري" + }, + "high": { + "en": "High", + "ar": "مرتفع" + }, + "elevated": { + "en": "Elevated", + "ar": "مرتفع قليلاً" + }, + "recorded": { + "en": "Recorded", + "ar": "مسجل" + }, + "noRecordsYet": { + "en": "No records yet", + "ar": "لا توجد سجلات بعد" + }, + "lastRecord": { + "en": "Last Record", + "ar": "آخر سجل" + }, + "addBloodSugar": { + "en": "Add Blood Sugar", + "ar": "إضافة سكر الدم" + }, + "addBloodPressure": { + "en": "Add Blood Pressure", + "ar": "إضافة ضغط الدم" + }, + "addWeight": { + "en": "Add Weight", + "ar": "إضافة الوزن" + }, + "bloodSugarDataSavedSuccessfully": { + "en": "Blood Sugar Data saved successfully", + "ar": "تم حفظ بيانات سكر الدم بنجاح" + }, + "bloodPressureDataSavedSuccessfully": { + "en": "Blood Pressure Data saved successfully", + "ar": "تم حفظ بيانات ضغط الدم بنجاح" + }, + "weightDataSavedSuccessfully": { + "en": "Weight Data saved successfully", + "ar": "تم حفظ بيانات الوزن بنجاح" + }, + "pleaseWait": { + "en": "Please wait", + "ar": "يرجى الانتظار" + }, + "selectUnit": { + "en": "Select Unit", + "ar": "اختر الوحدة" + }, + "selectMeasureTime": { + "en": "Select Measure Time", + "ar": "اختر وقت القياس" + }, + "selectArm": { + "en": "Select Arm", + "ar": "اختر الذراع" + }, + "enterBloodSugar": { + "en": "Enter Blood Sugar", + "ar": "أدخل سكر الدم" + }, + "enterSystolicValue": { + "en": "Enter Systolic Value", + "ar": "أدخل القيمة الانقباضية" + }, + "enterDiastolicValue": { + "en": "Enter Diastolic Value", + "ar": "أدخل القيمة الانبساطية" + }, + "enterWeight": { + "en": "Enter Weight", + "ar": "أدخل الوزن" + }, + "selectDuration": { + "en": "Select Duration", + "ar": "اختر المدة" + }, + "systolic": { + "en": "Systolic", + "ar": "الانقباضي" + }, + "diastolic": { + "en": "Diastolic", + "ar": "الانبساطي" + }, + "sendReportByEmail": { + "en": "Send Report by Email", + "ar": "إرسال التقرير عبر البريد الإلكتروني" + }, + "enterYourEmailToReceiveReport": { + "en": "Enter your email address to receive the report", + "ar": "أدخل عنوان بريدك الإلكتروني لاستلام التقرير" + }, + "addNewRecord": { + "en": "Add new Record", + "ar": "إضافة سجل جديد" + }, + "healthTrackers": { + "en": "Health Trackers", + "ar": "متتبعات الصحة" + }, + "monitorBloodPressureLevels": { + "en": "Monitor your blood pressure levels, track systolic and diastolic readings, and maintain a healthy heart.", + "ar": "راقب مستويات ضغط الدم لديك، وتتبع القراءات الانقباضية والانبساطية، وحافظ على صحة قلبك." + }, + "trackWeightProgress": { + "en": "Track your weight progress, set goals, and maintain a healthy body mass for overall wellness.", + "ar": "تتبع تقدم وزنك، وضع الأهداف، وحافظ على كتلة جسم صحية من أجل العافية الشاملة." + }, + "bookAppointment": { + "en": "Book Appointment", + "ar": "احجز موعد" + }, + "completeCheckup": { + "en": "Complete Checkup", + "ar": "الفحص الشامل" + }, + "indoorNavigation": { + "en": "Indoor Navigation", + "ar": "الملاحة الداخلية" + }, + "eReferralServices": { + "en": "E-Referral Services", + "ar": "خدمات الإحالة الإلكترونية" + }, + "dailyWaterMonitor": { + "en": "Daily Water Monitor", + "ar": "مراقب الماء اليومي" + }, + "fetchingYourWaterIntakeDetails": { + "en": "Fetching your water intake details.", + "ar": "جاري جلب تفاصيل استهلاك الماء الخاص بك." + }, + "healthCalculatorsServices": { + "en": "Health\nCalculators", + "ar": "حاسبات\nالصحة" + }, + "healthConvertersServices": { + "en": "Health\nConverters", + "ar": "محولات\nالصحة" + }, + "smartWatchesServices": { + "en": "Smart\nWatches", + "ar": "الساعات\nالذكية" + }, + "exploreServices": { + "en": "Explore Services", + "ar": "استكشف الخدمات" + }, + "medicalAndCareServices": { + "en": "Medical & Care Services", + "ar": "الخدمات الطبية والرعاية" + }, + "hmgServices": { + "en": "HMG Services", + "ar": "خدمات مجموعة الحبيب الطبية" + }, + "personalServices": { + "en": "Personal Services", + "ar": "الخدمات الشخصية" + }, + "habibWallet": { + "en": "Habib Wallet", + "ar": "محفظة الحبيب" + }, + "loginToViewWalletBalance": { + "en": "Login to view your wallet balance", + "ar": "سجل الدخول لعرض رصيد محفظتك" + }, + "loginToViewMedicalFile": { + "en": "Login to view your medical file", + "ar": "سجل الدخول لعرض ملفك الطبي" + }, + "addMember": { + "en": "Add Member", + "ar": "إضافة عضو" + }, + "addFamilyMember": { + "en": "Add Family Member", + "ar": "إضافة فرد من العائلة" + }, + "pleaseFillBelowFieldToAddNewFamilyMember": { + "en": "Please fill the below field to add a new family member to your profile", + "ar": "يرجى ملء الحقل أدناه لإضافة فرد جديد من العائلة إلى ملفك الشخصي" + }, + "healthTools": { + "en": "Health Tools", + "ar": "أدوات الصحة" + }, + "supportServices": { + "en": "Support Services", + "ar": "خدمات الدعم" + }, + "virtualTour": { + "en": "Virtual Tour", + "ar": "جولة افتراضية" + }, + "carParking": { + "en": "Car Parking", + "ar": "موقف السيارات" + }, + "latestNews": { + "en": "Latest News", + "ar": "آخر الأخبار" + }, + "hmgContact": { + "en": "HMG Contact", + "ar": "اتصل بمجموعة الحبيب الطبية" + }, + "durationCannotExceed90": { + "en": "Duration can not exceed 90 mins", + "ar": "لا يجوز أن تتجاوز المدة 90 دقيقة" + }, + "unexpectedError": { + "en": "Unexpected Error Occurred", + "ar": "حدث خطأ غير متوقع" + }, + "gettingAmbulanceTransportOption": { + "en": "Getting Ambulance Transport Option", + "ar": "جاري الحصول على خيارات نقل الإسعاف" + }, + "fetchingAppointment": { + "en": "Fetching Appointment", + "ar": "جاري جلب الموعد" + }, + "doYouWantToCancelTheRequest": { + "en": "Do you want to cancel the request", + "ar": "هل تريد إلغاء الطلب" + }, + "cancellingRequest": { + "en": "Cancelling request", + "ar": "جاري إلغاء الطلب" + }, + "fetchingTermsAndConditions": { + "en": "Fetching Terms And Conditions", + "ar": "جاري جلب الشروط والأحكام" + }, + "selectLocationPrescriptionDelivery": { + "en": "Please select the location for prescription delivery", + "ar": "يرجى تحديد موقع توصيل الوصفة الطبية" + }, + "noRadiologyOrders": { + "en": "No Radiology Orders Found", + "ar": "لم يتم العثور على أي طلبات تصوير شعاعي" + }, + "ageIsRequired": { + "en": "Age is required", + "ar": "العمر مطلوب" + }, + "invalidAge": { + "en": "Invalid age", + "ar": "العمر غير صالح" + }, + "ageMustBeBetween11And120": { + "en": "Age must be between 11 and 120", + "ar": "يجب أن يكون العمر بين 11 و 120" + }, + "heightIsRequired": { + "en": "Height is required", + "ar": "الطول مطلوب" + }, + "invalidHeight": { + "en": "Invalid height", + "ar": "الطول غير صالح" + }, + "weightIsRequired": { + "en": "Weight is required", + "ar": "الوزن مطلوب" + }, + "invalidWeight": { + "en": "Invalid weight", + "ar": "الوزن غير صالح" + }, + "timeToDrinkWater": { + "en": "Time to Drink Water! 💧", + "ar": "حان وقت شرب الماء! 💧" + }, + "stayHydratedDrinkWater": { + "en": "Stay hydrated! Drink {amount}ml of water.", + "ar": "ابق رطبًا! اشرب {amount} مل من الماء." + }, + "visitPharmacyOnline": { + "en": "Visit Pharmacy Online", + "ar": "زيارة الصيدلية على الانترنت" + }, + "howAreYouFeelingToday": { + "en": "How are you feeling today?", + "ar": "كيف حالك اليوم؟" + }, + "checkYourSymptomsWithScale": { + "en": "Check your symptoms with this scale", + "ar": "تحقق من أعراضك باستخدام ذا المقياس" + }, + "checkYourSymptoms": { + "en": "Check your symptoms", + "ar": "تحقق من أعراضك" + }, + "noUpcomingAppointmentPleaseBook": { + "en": "You do not have any upcoming appointment. Please book an appointment", + "ar": "ليس لديك أي مواعيد قادمة. يرجى حجز موعد" + }, + "youHaveEROnlineCheckInRequest": { + "en": "You have ER Online Check-In Request", + "ar": "لديك طلب تسجيل وصول عبر الإنترنت للطوارئ" + }, + "quickLinks": { + "en": "Quick Links", + "ar": "روابط سريعة" + }, + "viewMedicalFileLandingPage": { + "en": "View medical file", + "ar": "عرض الملف الطبي" + }, + "immediateLiveCareRequest": { + "en": "Immediate LiveCare Request", + "ar": "طلب لايف كير فوري" + }, + "yourTurnIsAfterPatients": { + "en": "Your turn is after {count} patients.", + "ar": "دورك بعد {count} مريض." + }, + "dontHaveHHCOrders": { + "en": "You don't have any Home Health Care orders yet.", + "ar": "ليس لديك أي أوامر رعاية صحية منزلية حتى الآن." + }, + "hhcOrders": { + "en": "HHC Orders", + "ar": "أوامر الرعاية الصحية المنزلية" + }, + "requestedServices": { + "en": "Requested Services", + "ar": "الخدمات المطلوبة" + }, + "selectServices": { + "en": "Select Services", + "ar": "اختر الخدمات" + }, + "selectedServices": { + "en": "Selected Services", + "ar": "الخدمات المختارة" + }, + "createNewRequest": { + "en": "Create new request", + "ar": "إنشاء طلب جديد" + }, + "youHaveNoPendingRequests": { + "en": "You have no pending requests.", + "ar": "ليس لديك أي طلبات معلقة." + }, + "noInsuranceDataFound": { + "en": "No insurance data found...", + "ar": "لم يتم العثور على بيانات التأمين..." + }, + "noInsuranceUpdateRequest": { + "en": "No insurance update requests found.", + "ar": "لم يتم العثور على أي طلبات لتحديث بيانات التأمين." + }, + "policyNumberInsurancePage": { + "en": "Policy: {number}", + "ar": "الوثيقة: {number}" + }, + "insuranceExpired": { + "en": "Insurance Expired", + "ar": "التأمين منتهي الصلاحية" + }, + "insuranceActive": { + "en": "Insurance Active", + "ar": "التأمين نشط" + }, + "patientCardID": { + "en": "Patient Card ID: {id}", + "ar": "رقم بطاقة المريض: {id}" + }, + "noInsuranceApprovals": { + "en": "You don't have any insurance approvals yet.", + "ar": "لم تحصل على أي موافقات تأمينية حتى الآن." + }, + "noInsuranceWithHMG": { + "en": "You don't have an insurance registered with HMG.", + "ar": "ليس لديك تأمين مسجل لدى مجموعة الحبيب الطبية." + }, + "referenceRange": { + "en": "Reference Range", + "ar": "النطاق المرجعي" + }, + "downloadReport": { + "en": "Download Report", + "ar": "تنزيل التقرير" + }, + "generatingReport": { + "en": "Generating Report, Please wait...", + "ar": "جارٍ إنشاء التقرير، يرجى الانتظار..." + }, + "noLabResults": { + "en": "You don't have any lab results yet.", + "ar": "ليس لديك أي نتائج مختبرية حتى الآن." + }, + "labResultDetails": { + "en": "Lab Result Details", + "ar": "تفاصيل نتائج المختبر" + }, + "resultOf": { + "en": "Result of {date}", + "ar": "نتيجة {date}" + }, + "whatIsThisResult": { + "en": "What is this result?", + "ar": "ما هي هذه النتيجة؟" + }, + "lastTested": { + "en": "Last Tested", + "ar": "آخر اختبار" + }, + "byVisit": { + "en": "By Visit", + "ar": "حسب الزيارة" + }, + "byTest": { + "en": "By Test", + "ar": "حسب التحليل" + }, + "results": { + "en": "results", + "ar": "نتائج" + }, + "viewResults": { + "en": "View Results", + "ar": "عرض النتائج" + }, + "rebook": { + "en": "Rebook", + "ar": "إعادة الحجز" + }, + "noOphthalmologyAppointments": { + "en": "No Ophthalmology appointments found...", + "ar": "لم يتم العثور على أي مواعيد في قسم طب العيون..." + }, + "noVitalSignsRecordedYet": { + "en": "No vital signs recorded yet", + "ar": "لا توجد علامات حيوية مسجلة بعد" + }, + "appointmentsAndVisits": { + "en": "Appointments & visits", + "ar": "المواعيد والزيارات" + }, + "labAndRadiology": { + "en": "Lab & Radiology", + "ar": "المختبر والأشعة" + }, + "activeMedicationsAndPrescriptions": { + "en": "Active Medications & Prescriptions", + "ar": "الأدوية النشطة والوصفات الطبية" + }, + "allPrescriptions": { + "en": "All Prescriptions", + "ar": "جميع الوصفات" + }, + "allMedications": { + "en": "All Medications", + "ar": "جميع الأدوية" + }, + "youDontHaveAnyPrescriptionsYet": { + "en": "You don't have any prescriptions yet.", + "ar": "ليس لديك أي وصفات طبية بعد." + }, + "youDontHaveAnyCompletedVisitsYet": { + "en": "You don't have any completed visits yet", + "ar": "ليس لديك أي زيارات مكتملة بعد" + }, + "others": { + "en": "Others", + "ar": "أخرى" + }, + "allergyInfo": { + "en": "Allergy Info", + "ar": "معلومات الحساسية" + }, + "vaccineInfo": { + "en": "Vaccine Info", + "ar": "معلومات اللقاحات" + }, + "updateInsuranceInfo": { + "en": "Update Insurance", + "ar": "تحديث التأمين" + }, + "myInvoicesList": { + "en": "My Invoices List", + "ar": "قائمة فواتيري" + }, + "ancillaryOrdersList": { + "en": "Ancillary Orders List", + "ar": "قائمة الطلبات المساعدة" + }, + "youDontHaveAnySickLeavesYet": { + "en": "You don't have any sick leaves yet.", + "ar": "ليس لديك أي إجازات مرضية بعد." + }, + "medicalReports": { + "en": "Medical Reports", + "ar": "التقارير الطبية" + }, + "sickLeaveReport": { + "en": "Sick Leave Report", + "ar": "تقرير الإجازة المرضية" + }, + "weightTracker": { + "en": "Weight Tracker", + "ar": "متتبع الوزن" + }, + "askYourDoctor": { + "en": "Ask Your Doctor", + "ar": "اسأل طبيبك" + }, + "internetPairing": { + "en": "Internet Pairing", + "ar": "الاقتران بالإنترنت" + }, + "requested": { + "en": "Requested", + "ar": "مطلوب" + }, + "youDontHaveAnyMedicalReportsYet": { + "en": "You don't have any medical reports yet.", + "ar": "ليس لديك أي تقارير طبية بعد." + }, + "requestMedicalReport": { + "en": "Request medical report", + "ar": "طلب تقرير طبي" + }, + "youDoNotHaveAnyAppointmentsToRequestMedicalReport": { + "en": "You do not have any appointments to request a medical report.", + "ar": "ليس لديك أي مواعيد لطلب تقرير طبي." + }, + "areYouSureYouWantToRequestMedicalReport": { + "en": "Are you sure you want to request a medical report for this appointment?", + "ar": "هل أنت متأكد أنك تريد طلب تقرير طبي لهذا الموعد؟" + }, + "yourMedicalReportRequestSubmittedSuccessfully": { + "en": "Your medical report request has been successfully submitted.", + "ar": "تم إرسال طلب التقرير الطبي بنجاح." + }, + "monthlyHealthSummaryReportDisclaimer": { + "en": "This monthly health summary report reflects the health indicators and analysis results of the latest visits. Please note that this will be sent automatically from the system and it's not considered as a official report so no medical decision should be taken based on it", + "ar": "يعكس تقرير الملخص الصحي الشهري هذا المؤشرات الصحية ونتائج التحليل لأحدث الزيارات. يرجى ملاحظة أن هذا سيتم إرساله تلقائيًا من النظام ولا يعتبر تقريرًا رسميًا لذا لا ينبغي اتخاذ أي قرار طبي بناءً عليه" + }, + "updatingMonthlyReportStatus": { + "en": "Updating Monthly Report Status...", + "ar": "جاري تحديث حالة التقرير الشهري..." + }, + "monthlyReportStatusUpdatedSuccessfully": { + "en": "Monthly Report Status Updated Successfully", + "ar": "تم تحديث حالة التقرير الشهري بنجاح" + }, + "whoCanViewMyMedicalFile": { + "en": "Who can view my medical file?", + "ar": "من يمكنه عرض ملفي الطبي؟" + }, + "acceptedYourRequestToBeYourFamilyMember": { + "en": "{status} your request to be your family member", + "ar": "{status} طلب الانضمام الى أفراد عائلتك" + }, + "canViewYourFile": { + "en": "can view your file", + "ar": "يمكنه عرض ملفك" + }, + "hasARequestPendingToBeYourFamilyMember": { + "en": "has a request {status} to be your family member", + "ar": "لديه طلب {status} ليكون فردًا من عائلتك" + }, + "wantsToAddYouAsTheirFamilyMember": { + "en": "wants to add you as their family member", + "ar": "يرغب في إضافتك كفرد من أفراد العائلة" + }, + "rejectedYourRequestToBeYourFamilyMember": { + "en": "{status} your request to be your family member", + "ar": "{status} طلب الانضمام إلى عائلتك" + }, + "rejectedYourFamilyMemberRequest": { + "en": "{status} your family member request", + "ar": "{status} طلب أحد أفراد عائلتك" + }, + "notAvailable": { + "en": "N/A", + "ar": "غير متاح" + }, + "selectAProfile": { + "en": "Please select a profile", + "ar": "الرجاء تحديد ملف تعريف" + }, + "switchFamilyFile": { + "en": "Switch from the below list of medical file", + "ar": "قم بالتبديل من قائمة الملفات الطبية أدناه" + }, + "medicalFiles": { + "en": "Medical Files", + "ar": "الملفات الطبية" + }, + "addANewFamilyMember": { + "en": "Add a new family member", + "ar": "إضافة فرد جديد من العائلة" + }, + "viewInvoiceDetails": { + "en": "View invoice details", + "ar": "عرض تفاصيل الفاتورة" + }, + "outPatient": { + "en": "OutPatient", + "ar": "مريض خارجي" + }, + "invoiceDetails": { + "en": "Invoice Details", + "ar": "تفاصيل الفاتورة" + }, + "sendingEmailPleaseWait": { + "en": "Sending email, Please wait...", + "ar": "جاري إرسال البريد الإلكتروني، يرجى الانتظار..." + }, + "emailSentSuccessfullyMessage": { + "en": "Email sent successfully.", + "ar": "تم إرسال البريد الإلكتروني بنجاح." + }, + "discount": { + "en": "Discount", + "ar": "خصم" + }, + "paid": { + "en": "Paid", + "ar": "مدفوع" + }, + "fetchingInvoiceDetails": { + "en": "Fetching invoice details, Please wait...", + "ar": "جارٍ جلب تفاصيل الفاتورة، يرجى الانتظار..." + }, + "scanQRCode": { + "en": "Scan QR code", + "ar": "مسح رمز الاستجابة السريعة" + }, + "parkingSlotDetails": { + "en": "Parking Slot Details", + "ar": "تفاصيل موقف السيارة" + }, + "slotNumber": { + "en": "Slot: {code}", + "ar": "رقم الموقف: {code}" + }, + "basement": { + "en": "Basement: {description}", + "ar": "الطابق: {description}" + }, + "parkingDate": { + "en": "Date: {date}", + "ar": "التاريخ: {date}" + }, + "parkedSince": { + "en": "Parked Since: {time}", + "ar": "متوقف منذ: {time}" + }, + "resetDirection": { + "en": "Reset Direction", + "ar": "إعادة تعيين الاتجاه" + }, + "noPrescriptionOrdersYet": { + "en": "You don't have any prescription orders yet.", + "ar": "ليس لديك أي طلبات وصفات طبية حتى الآن." + }, + "fetchingPrescriptionPDFPleaseWait": { + "en": "Fetching prescription PDF, Please wait...", + "ar": "جاري جلب ملف الوصفة الطبية، يرجى الانتظار..." + }, + "ratingValue": { + "en": "Rating: {rating}", + "ar": "التقييم: {rating}" + }, + "downloadPrescription": { + "en": "Download Prescription", + "ar": "تحميل الوصفة الطبية" + }, + "fetchingPrescriptionDetails": { + "en": "Fetching prescription details...", + "ar": "جاري جلب تفاصيل الوصفة الطبية..." + }, + "switchBackFamilyFile": { + "en": "Switch Back To Family File", + "ar": "العودة إلى ملف العائلة" + }, + "profileAndSettings": { + "en": "Profile & Settings", + "ar": "الملف الشخصي والإعدادات" + }, + "quickActions": { + "en": "Quick Actions", + "ar": "إجراءات سريعة" + }, + "notificationsSettings": { + "en": "Notifications Settings", + "ar": "إعدادات الإشعارات" + }, + "touchIDFaceIDServices": { + "en": "Touch ID / Face ID Services", + "ar": "خدمات Touch ID / Face ID" + }, + "personalInformation": { + "en": "Personal Information", + "ar": "المعلومات الشخصية" + }, + "updateEmailAddress": { + "en": "Update Email Address", + "ar": "تحديث عنوان البريد الإلكتروني" + }, + "helpAndSupport": { + "en": "Help & Support", + "ar": "المساعدة والدعم" + }, + "permissionsProfile": { + "en": "Permissions", + "ar": "الأذونات" + }, + "privacyPolicy": { + "en": "Privacy Policy", + "ar": "سياسة الخصوصية" + }, + "deactivateAccount": { + "en": "Deactivate account", + "ar": "إلغاء تنشيط الحساب" + }, + "ageYearsOld": { + "en": "{age} {yearsOld}", + "ar": "{age} {yearsOld}" + }, + "youDontHaveRadiologyOrders": { + "en": "You don't have any radiology results yet.", + "ar": "ليس لديك أي نتائج للأشعة حتى الآن." + }, + "radiologyResult": { + "en": "Radiology Result", + "ar": "نتيجة الأشعة" + }, + "viewRadiologyImage": { + "en": "View Radiology Image", + "ar": "عرض صورة الأشعة" + }, + "rateClinic": { + "en": "Rate Clinic", + "ar": "تقييم العيادة" + }, + "back": { + "en": "Back", + "ar": "رجوع" + }, + "rateDoctor": { + "en": "Rate Doctor", + "ar": "تقييم الطبيب" + }, + "howWasYourLastVisitWithDoctor": { + "en": "How was your last visit with doctor?", + "ar": "كيف كانت زيارتك الأخيرة مع الطبيب؟" + }, + "dateOfBirthSymptoms": { + "en": "What is your Date of Birth?", + "ar": "ما هو تاريخ ميلادك؟" + }, + "genderSymptoms": { + "en": "What is your gender?", + "ar": "ما هو جنسك؟" + }, + "heightSymptoms": { + "en": "How tall are you?", + "ar": "كم طولك؟" + }, + "weightSymptoms": { + "en": "What is your weight?", + "ar": "ما هو وزنك؟" + }, + "femaleGender": { + "en": "Female", + "ar": "أنثى" + }, + "previous": { + "en": "Previous", + "ar": "سابق" + }, + "selectedOrgans": { + "en": "Selected Organs", + "ar": "الهيئات المختارة" + }, + "noOrgansSelected": { + "en": "No organs selected yet", + "ar": "لم يتم تحديد أي أعضاء بعد" + }, + "organSelector": { + "en": "Organ Selector", + "ar": "محدد الأعضاء" + }, + "noPredictionsAvailable": { + "en": "No Predictions available", + "ar": "لا توجد تنبؤات متاحة" + }, + "areYouSureYouWantToRestartOrganSelection": { + "en": "Are you sure you want to restart the organ selection?", + "ar": "هل أنت متأكد أنك تريد إعادة تشغيل اختيار الأعضاء؟" + }, + "possibleConditions": { + "en": "Possible Conditions", + "ar": "الحالات المحتملة" + }, + "pleaseSelectAtLeastOneRiskBeforeProceeding": { + "en": "Please select at least one risk before proceeding", + "ar": "يرجى اختيار عامل خطر واحد على الأقل قبل المتابعة" + }, + "aboveYouSeeCommonRiskFactors": { + "en": "Above you see the most common risk factors. Although /diagnosis may return questions about risk factors, ", + "ar": "أعلاه ترى عوامل الخطر الأكثر شيوعًا. على الرغم من أن /diagnosis قد تعيد أسئلة حول عوامل الخطر، " + }, + "readMore": { + "en": "Read more", + "ar": "اقرأ المزيد" + }, + "riskFactors": { + "en": "Risk Factors", + "ar": "عوامل الخطر" + }, + "noRiskFactorsFound": { + "en": "No risk factors found", + "ar": "لم يتم العثور على عوامل خطر" + }, + "basedOnYourSelectedSymptomsNoRiskFactors": { + "en": "Based on your selected symptoms, no additional risk factors were identified.", + "ar": "بناءً على الأعراض المحددة، لم يتم تحديد عوامل خطر إضافية." + }, + "messageNotification": { + "en": "Message", + "ar": "الرسالة" + }, + "attachedImage": { + "en": "Attached Image", + "ar": "الصورة المرفقة" + }, + "failedToLoadImage": { + "en": "Failed to load image", + "ar": "فشل تحميل الصورة" + }, + "typeNotification": { + "en": "Type", + "ar": "النوع" + }, + "pleaseSelectAtLeastOneOptionBeforeProceeding": { + "en": "Please select at least one option before proceeding", + "ar": "يرجى اختيار خيار واحد على الأقل قبل المتابعة" + }, + "suggestions": { + "en": "Suggestions", + "ar": "الاقتراحات" + }, + "pleaseGoBackAndSelectOrgansFirst": { + "en": "Please go back and select organs first", + "ar": "يرجى العودة واختيار الأعضاء أولاً" + }, + "symptomsSelector": { + "en": "Symptoms Selector", + "ar": "محدد الأعراض" + }, + "possibleSymptomsRelatedTo": { + "en": "Possible symptoms related to", + "ar": "الأعراض المحتملة المتعلقة بـ" + }, + "suggestionAIListDescription": { + "en": "This is a list of symptoms suggested by our AI, based on the information gathered so far during the interview", + "ar": "هذه قائمة بالأعراض المقترحة من قبل الذكاء الاصطناعي، بناءً على المعلومات التي تم جمعها حتى الآن خلال المقابلة" + }, + "analyzing": { + "en": "Analyzing...", + "ar": "جاري التحليل..." + }, + "seekMedicalAdvice": { + "en": "Seek Medical Advice", + "ar": "اطلب المشورة الطبية" + }, + "monitorDescription": { + "en": "No need to seek medical advice. Just keep healthy routine.", + "ar": "لا حاجة لطلب المشورة الطبية. فقط حافظ على روتين صحي." + }, + "seekMedicalAdviceDescription": { + "en": "Not emergency but better to monitor the symptoms.", + "ar": "ليست حالة طوارئ ولكن من الأفضل مراقبة الأعراض." + }, + "emergencyDescription": { + "en": "Need to consult doctor as soon as possible before getting too late.", + "ar": "تحتاج إلى استشارة الطبيب في أقرب وقت ممكن قبل فوات الأوان." + }, + "colorScience": { + "en": "Color Science", + "ar": "دلالات الألوان" + }, + "noNeedToVisitDoctor": { + "en": "No need to visit doctor", + "ar": "لا حاجة لزيارة الطبيب" + }, + "commonSymptom": { + "en": "Common Symptom", + "ar": "الأعراض الشائعة" + }, + "notApplicable": { + "en": "Not Applicable", + "ar": "لا ينطبق" + }, + "emergencyTriage": { + "en": "Emergency", + "ar": "طوارئ" + }, + "emergencyEvidenceDetected": { + "en": "Emergency evidence detected. Please seek medical attention.", + "ar": "تم اكتشاف دليل طوارئ. يرجى طلب العناية الطبية." + }, + "noQuestionItemsAvailable": { + "en": "No question items available", + "ar": "لا توجد عناصر أسئلة متاحة" + }, + "pleaseAnswerAllQuestionsBeforeProceeding": { + "en": "Please answer all questions before proceeding", + "ar": "يرجى الإجابة على جميع الأسئلة قبل المتابعة" + }, + "triage": { + "en": "Triage", + "ar": "الفرز" + }, + "areYouSureYouWantToExitProgress": { + "en": "Are you sure you want to exit? Your progress will be lost.", + "ar": "هل أنت متأكد أنك تريد الخروج؟ سيتم فقدان تقدمك." + }, + "noQuestionAvailable": { + "en": "No question available", + "ar": "لا يوجد سؤال متاح" + }, + "possibleSymptom": { + "en": "Possible symptom: ", + "ar": "عرض محتمل: " + }, + "symptomsCheckerFindingScore": { + "en": "- Symptoms checker finding score", + "ar": "- درجة نتائج فاحص الأعراض" + }, + "notSet": { + "en": "Not set", + "ar": "غير محدد" + }, + "years": { + "en": "Years", + "ar": "سنوات" + }, + "symptomsChecker": { + "en": "Symptoms Checker", + "ar": "فاحص الأعراض" + }, + "helloIsYourInformationUpToDate": { + "en": "Hello {name}, Is your information up to date?", + "ar": "مرحباً {name}، هل معلوماتك محدثة؟" + }, + "noEditAll": { + "en": "No, Edit all", + "ar": "لا، تعديل الكل" + }, + "yesItIs": { + "en": "Yes, It is", + "ar": "نعم، إنها كذلك" + }, + "age": { + "en": "Age", + "ar": "العمر" + }, + "youDontHaveAnyAncillaryOrdersYet": { + "en": "You don't have any ancillary orders yet.", + "ar": "ليس لديك أي طلبات مساعدة بعد." + }, + "invoiceWithNumber": { + "en": "Invoice: {invoiceNo}", + "ar": "الفاتورة: {invoiceNo}" + }, + "queued": { + "en": "Queued", + "ar": "في قائمة الانتظار" + }, + "checkInReady": { + "en": "Check-in Ready", + "ar": "جاهز للتسجيل" + }, + "checkIn": { + "en": "Check In", + "ar": "تسجيل الوصول" + }, + "viewDetails": { + "en": "View Details", + "ar": "عرض التفاصيل" + }, + "selectPaymentMethod": { + "en": "Select Payment Method", + "ar": "اختر طريقة الدفع" + }, + "processingPaymentPleaseWait": { + "en": "Processing payment, Please wait...", + "ar": "جاري معالجة الدفع، يرجى الانتظار..." + }, + "finalizingPaymentPleaseWait": { + "en": "Finalizing payment, Please wait...", + "ar": "جاري إتمام الدفع، يرجى الانتظار..." + }, + "generatingInvoicePleaseWait": { + "en": "Generating invoice, Please wait...", + "ar": "جاري إنشاء الفاتورة، يرجى الانتظار..." + }, + "hereIsYourInvoiceNumber": { + "en": "Here is your invoice #: ", + "ar": "هذا هو رقم فاتورتك #: " + }, + "paymentCompletedSuccessfully": { + "en": "Payment Completed Successfully", + "ar": "تم الدفع بنجاح" + }, + "failedToInitializeApplePay": { + "en": "Failed to initialize Apple Pay. Please try again.", + "ar": "فشل في تهيئة Apple Pay. يرجى المحاولة مرة أخرى." + }, + "cash": { + "en": "Cash", + "ar": "نقدي" + }, + "approved": { + "en": "Approved", + "ar": "موافق عليه" + }, + "approvalRejectedPleaseVisitReceptionist": { + "en": "Approval Rejected - Please visit receptionist", + "ar": "تم رفض الموافقة - يرجى زيارة موظف الاستقبال" + }, + "sentForApproval": { + "en": "Sent For Approval", + "ar": "تم إرساله للموافقة" + }, + "ancillaryOrderDetails": { + "en": "Ancillary Order Details", + "ar": "تفاصيل الطلبات المساندة" + }, + "noProceduresAvailableForSelectedOrder": { + "en": "No Procedures available for the selected order.", + "ar": "لا توجد إجراءات متاحة للطلب المحدد." + }, + "procedures": { + "en": "Procedures", + "ar": "الإجراءات" + }, + "totalAmount": { + "en": "Total Amount", + "ar": "المبلغ الإجمالي" + }, + "covered": { + "en": "Covered", + "ar": "مغطى" + }, + "vatPercent": { + "en": "VAT (15%)", + "ar": "ضريبة القيمة المضافة (15%)" + }, + "proceedToPayment": { + "en": "Proceed to Payment", + "ar": "المتابعة للدفع" + }, + "supportedSmartWatches": { + "en": "Supported Smart Watches", + "ar": "الساعات الذكية المدعومة" + }, + "pleaseMakeSureSamsungWatchConnected": { + "en": "Please make sure that your Samsung Watch is connected to your Phone, is actively synced & updated.", + "ar": "يرجى التأكد من أن ساعة Samsung الخاصة بك متصلة بهاتفك، ومتزامنة ومحدثة بشكل نشط." + }, + "beforeSyncingDataFollowInstructions": { + "en": "Before syncing data, please make sure that you have followed the instructions properly.", + "ar": "قبل مزامنة البيانات، يرجى التأكد من اتباع التعليمات بشكل صحيح." + }, + "viewWatchInstructions": { + "en": "View watch instructions", + "ar": "عرض تعليمات الساعة" + }, + "healthConnectAppNotInstalled": { + "en": "Seems like you do not have Health Connect App installed. Please install it from the Play Store to sync your health data.", + "ar": "يبدو أنه ليس لديك تطبيق Health Connect مثبتًا. يرجى تثبيته من متجر Play لمزامنة بيانات صحتك." + }, + "setTimerOfReminder": { + "en": "Set the timer of reminder", + "ar": "ضبط مؤقت التذكير" + }, + "youHaveAppointmentWithDr": { + "en": "You have appointment with Dr. ", + "ar": "لديك موعد مع د. " + }, + "hours": { + "en": "Hours", + "ar": "ساعات" + }, + "secs": { + "en": "Secs", + "ar": "ثواني" + }, + "noAllergiesDataFound": { + "en": "No allergies data found...", + "ar": "لم يتم العثور على بيانات الحساسية..." + }, + "heartRateDescription": { + "en": "Your heart rate indicates how many times your heart beats per minute", + "ar": "معدل ضربات قلبك يشير إلى عدد المرات التي ينبض فيها قلبك في الدقيقة" + }, + "bloodOxygenDescription": { + "en": "Blood oxygen level indicates how much oxygen your red blood cells are carrying", + "ar": "مستوى الأكسجين في الدم يشير إلى كمية الأكسجين التي تحملها خلايا الدم الحمراء" + }, + "stepsDescription": { + "en": "Number of steps taken throughout the day", + "ar": "عدد الخطوات المتخذة على مدار اليوم" + }, + "caloriesDescription": { + "en": "Calories burned during physical activity", + "ar": "السعرات الحرارية المحروقة أثناء النشاط البدني" + }, + "distanceDescription": { + "en": "Distance covered throughout the day", + "ar": "المسافة المقطوعة على مدار اليوم" + }, + "overview": { + "en": "Overview", + "ar": "نظرة عامة" + }, + "details": { + "en": "Details", + "ar": "التفاصيل" + }, + "healthy": { + "en": "Healthy", + "ar": "صحي" + }, + "warning": { + "en": "Warning", + "ar": "تحذير" + }, + "vitalSignDetails": { + "en": "Vital Sign Details", + "ar": "تفاصيل العلامات الحيوية" + }, + "resultOfNoDate": { + "en": "Result of --", + "ar": "نتيجة --" + }, + "referenceRangeBetween": { + "en": "Reference range: {low} – {high} {unit}", + "ar": "النطاق المرجعي: {low} – {high} {unit}" + }, + "referenceRangeMin": { + "en": "Reference range: ≥ {low} {unit}", + "ar": "النطاق المرجعي: ≥ {low} {unit}" + }, + "referenceRangeMax": { + "en": "Reference range: ≤ {high} {unit}", + "ar": "النطاق المرجعي: ≤ {high} {unit}" + }, + "noHistoryAvailable": { + "en": "No history available", + "ar": "لا يوجد تاريخ متاح" + }, + "bmiDescription": { + "en": "BMI is a measurement based on height and weight that estimates body fat.", + "ar": "مؤشر كتلة الجسم هو قياس يعتمد على الطول والوزن لتقدير دهون الجسم." + }, + "heightDescription": { + "en": "Height is measured in centimeters and is used to calculate BMI and dosage recommendations.", + "ar": "يقاس الطول بالسنتيمتر ويستخدم لحساب مؤشر كتلة الجسم وتوصيات الجرعات." + }, + "weightDescription": { + "en": "Weight helps track overall health, nutrition, and changes over time.", + "ar": "الوزن يساعد في تتبع الصحة العامة والتغذية والتغيرات مع مرور الوقت." + }, + "bloodPressureDescription": { + "en": "Blood pressure reflects the force of blood against artery walls. It is shown as systolic/diastolic.", + "ar": "ضغط الدم يعكس قوة الدم على جدران الشرايين. يظهر كانقباضي/انبساطي." + }, + "temperatureDescription": { + "en": "Body temperature reflects how hot your body is and may change with infection or inflammation.", + "ar": "درجة حرارة الجسم تعكس مدى سخونة جسمك وقد تتغير مع العدوى أو الالتهاب." + }, + "heartRateDescriptionVital": { + "en": "Heart rate refers to the number of heart beats per minute.", + "ar": "معدل ضربات القلب يشير إلى عدد نبضات القلب في الدقيقة." + }, + "respiratoryRateDescription": { + "en": "Respiratory rate is the number of breaths taken per minute.", + "ar": "معدل التنفس هو عدد الأنفاس المأخوذة في الدقيقة." + }, + "bmiAdvice": { + "en": "Maintain a balanced diet and regular activity. If your BMI is high or low, consider consulting your doctor.", + "ar": "حافظ على نظام غذائي متوازن ونشاط منتظم. إذا كان مؤشر كتلة جسمك مرتفعًا أو منخفضًا، فكر في استشارة طبيبك." + }, + "heightAdvice": { + "en": "No action is needed unless your measurement looks incorrect. Update it during your next visit.", + "ar": "لا حاجة لاتخاذ أي إجراء إلا إذا بدا قياسك غير صحيح. قم بتحديثه في زيارتك القادمة." + }, + "weightAdvice": { + "en": "Monitor weight changes. Sudden gain or loss may require medical advice.", + "ar": "راقب تغيرات الوزن. الزيادة أو الخسارة المفاجئة قد تتطلب استشارة طبية." + }, + "bloodPressureAdvice": { + "en": "Keep tracking your blood pressure. High or low readings should be discussed with your doctor.", + "ar": "استمر في تتبع ضغط دمك. يجب مناقشة القراءات المرتفعة أو المنخفضة مع طبيبك." + }, + "temperatureAdvice": { + "en": "If you have a persistent fever or symptoms, contact your healthcare provider.", + "ar": "إذا كان لديك حمى مستمرة أو أعراض، اتصل بمقدم الرعاية الصحية." + }, + "heartRateAdvice": { + "en": "Track your heart rate trends. If you feel dizziness or chest pain, seek medical care.", + "ar": "تتبع اتجاهات معدل ضربات قلبك. إذا شعرت بدوار أو ألم في الصدر، اطلب الرعاية الطبية." + }, + "respiratoryRateAdvice": { + "en": "If you notice shortness of breath or abnormal breathing, seek medical advice.", + "ar": "إذا لاحظت ضيقًا في التنفس أو تنفسًا غير طبيعي، اطلب المشورة الطبية." + }, + "whatShouldIDoNext": { + "en": "What should I do next?", + "ar": "ماذا يجب أن أفعل بعد ذلك؟" + }, + "customizeDrinkCup": { + "en": "Customize your drink cup", + "ar": "قم بتخصيص كوب مشروبك" + }, + "tipsToStayHydrated": { + "en": "Tips to stay hydrated", + "ar": "نصائح للبقاء رطبًا" + }, + "drinkBeforeYouFeelThirsty": { + "en": "Drink before you feel thirsty", + "ar": "اشرب قبل أن تشعر بالعطش" + }, + "keepRefillableBottleNextToYou": { + "en": "Keep a refillable bottle next to you", + "ar": "احتفظ بزجاجة قابلة لإعادة التعبئة بجانبك" + }, + "trackYourDailyIntakeToStayMotivated": { + "en": "Track your daily intake to stay motivated", + "ar": "تتبع كمية الماء اليومية للحفاظ على الحافز" + }, + "chooseSparklingWaterInsteadOfSoda": { + "en": "Choose sparkling water instead of soda", + "ar": "اختر الماء الفوار بدلاً من الصودا" + }, + "switchCup": { + "en": "Switch Cup", + "ar": "تبديل الكوب" + }, + "plainWater": { + "en": "Plain Water", + "ar": "ماء عادي" + }, + "yourGoal": { + "en": "Your Goal", + "ar": "هدفك" + }, + "remaining": { + "en": "Remaining", + "ar": "المتبقي" + }, + "hydrationStatus": { + "en": "Hydration Status", + "ar": "حالة الترطيب" + }, + "areYouSureYouWantToCancelAllWaterReminders": { + "en": "Are you sure you want to cancel all water reminders?", + "ar": "هل أنت متأكد أنك تريد إلغاء جميع تذكيرات الماء؟" + }, + "remindersSet": { + "en": "Reminders Set!", + "ar": "تم ضبط التذكيرات!" + }, + "dailyWaterRemindersScheduledAt": { + "en": "Daily water reminders scheduled at:", + "ar": "تم جدولة تذكيرات الماء اليومية في:" + }, + "waterConsumption": { + "en": "Water Consumption", + "ar": "استهلاك المياه" + }, + "selectNumberOfReminders": { + "en": "Select Number of Reminders", + "ar": "حدد عدد التذكيرات" + }, + "h2oSettings": { + "en": "H20 Settings", + "ar": "إعدادات H20" + }, + "settingsSavedSuccessfully": { + "en": "Settings saved successfully", + "ar": "تم حفظ الإعدادات بنجاح" + }, + "yourName": { + "en": "Your Name", + "ar": "اسمك" + }, + "ageYears": { + "en": "Age (11-120) yrs", + "ar": "العمر (11-120) سنة" + }, + "numberOfRemindersInADay": { + "en": "Number of reminders in a day", + "ar": "عدد التذكيرات في اليوم" + }, + "medications": { + "en": "Medications", + "ar": "الأدوية" + }, + "someRemarksAboutPrescription": { + "en": "some remarks about the prescription will be here", + "ar": "ستجدون هنا بعض الملاحظات حول الوصفة الطبية" + }, + "notifyMeBeforeConsumptionTime": { + "en": "Notify me before the consumption time", + "ar": "أبلغني قبل وقت الاستهلاك" + }, + "noMedicationsToday": { + "en": "No medications today", + "ar": "لا أدوية اليوم" + }, + "reminders": { + "en": "Reminders", + "ar": "تذكيرات" + }, + "reminderAddedToCalendar": { + "en": "Reminder added to calendar ✅", + "ar": "تمت إضافة تذكير إلى التقويم ✅" + }, + "errorWhileSettingCalendar": { + "en": "Error while setting calendar: {error}", + "ar": "حدث خطأ أثناء ضبط التقويم:{error}" + }, + "instructions": { + "en": "Instructions", + "ar": "التعليمات" + }, + "requests": { + "en": "Requests", + "ar": "الطلبات" + }, + "thisWeek": { + "en": "This Week", + "ar": "هذا الأسبوع" + }, + "lastMonth": { + "en": "Last Month", + "ar": "الشهر الماضي" + }, + "lastSixMonths": { + "en": "Last 6 Months", + "ar": "آخر 6 أشهر" + }, + "selectTime": { + "en": "Select Time", + "ar": "حدد الوقت" + }, + "pleaseWaitYouWillBeCalledForVitalSigns": { + "en": "Please wait! you will be called for vital signs", + "ar": "يرجى الانتظار! سيتم استدعاؤك لقياس العلامات الحيوية" + }, + "pleaseVisitRoomForVitalSigns": { + "en": "Please visit Room {roomNumber} for vital signs", + "ar": "يرجى زيارة الغرفة {roomNumber} لقياس العلامات الحيوية" + }, + "pleaseVisitRoomToTheDoctor": { + "en": "Please visit Room {roomNumber} to the Doctor", + "ar": "يرجى زيارة الغرفة {roomNumber} لمقابلة الطبيب" + }, + "erOnlineCheckInRequest": { + "en": "ER Online Check-In Request", + "ar": "طلب تسجيل الوصول عبر الإنترنت لقسم الطوارئ" + }, + "indoor": { + "en": "Indoor", + "ar": "داخلي" + }, + "navigation": { + "en": "Navigation", + "ar": "الملاحة" + }, + "health": { + "en": "Health", + "ar": "الصحة" + }, + "calculators": { + "en": "Calculators", + "ar": "الحاسبات" + }, + "converters": { + "en": "Converters", + "ar": "المحولات" + }, + "guide": { + "en": "Guide", + "ar": "الدليل" + }, + "liveCareServiceDesc": { + "en": "Get medical advice with a specialist doctor Via a video call", + "ar": "احصل على استشارة طبية من طبيب متخصص عبر مكالمة فيديو" + }, + "bloodGroup": { + "en": "Blood: {bloodType}", + "ar": "فصيلة الدم: {bloodType}" + }, + "medicalServices": { + "en": "Medical Services", + "ar": "الخدمات الطبية" + }, + "insuranceAndPayments": { + "en": "Insurance & Payments", + "ar": "التأمين والمدفوعات" + }, + "trackerAndOthers": { + "en": "Tracker & Others", + "ar": "المتتبع وأخرى" + }, + "bmi": { + "en": "BMI", + "ar": "مؤشر كتلة الجسم" + }, + "yesPleaseINeedHelp": { + "en": "Yes, Please I need help", + "ar": "نعم، من فضلك أريد المساعدة" + }, + "aiOverView": { + "en": "AI Overview", + "ar": "AI ملخص" + }, + "generateAiAnalysis": { + "en": "Generate AI analysis for this order", + "ar": "قم بإجراء تحليل لهذا الطلب AI" + }, + "aiAnalysis": { + "en": "AI Analysis", + "ar": "AI تحليل" + }, + "prediction": { + "en": "Prediction", + "ar": "تنبؤ" + }, + "prevention": { + "en": "Prevention", + "ar": "وقاية" + }, + "disclaimer": { + "en": "Disclaimer", + "ar": "تنصل" + }, + "thisAboveInfo": { + "en": "The above information is generated by AI based on your lab results and is intended for informational purposes only. It should not be considered a medical diagnosis or treatment plan. Always consult with your healthcare provider for personalized medical advice and before making any health-related decisions.", + "ar": "المعلومات المذكورة أعلاه مُولّدة بواسطة AI بناءً على نتائج تحاليلك المخبرية، وهي لأغراض إعلامية فقط. لا ينبغي اعتبارها تشخيصًا طبيًا أو خطة علاجية. استشر طبيبك دائمًا للحصول على نصيحة طبية مُخصصة قبل اتخاذ أي قرارات تتعلق بصحتك." + }, + "aiDisclaimer": { + "en": "Your lab result data will be securely shared with our AI Analyzer for analysis. This helps provide personalized health insights. Do you want to proceed?", + "ar": "سيتم مشاركة بيانات نتائج تحاليلك المخبرية بشكل آمن مع خدمة الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في تقديم رؤى صحية مُخصصة. هل ترغب في المتابعة؟" + }, + "consent": { + "en": "Consent", + "ar": "موافقة" + }, + "bmiNormalDescription": { + "en": "Your BMI is within the healthy range. Continue a balanced diet, regular physical activity, and routine checkups to maintain good health. Monitor any significant changes over time.", + "ar": "مؤشر كتلة جسمك ضمن المعدل الصحي. استمر في اتباع نظام غذائي متوازن، وممارسة النشاط البدني بانتظام، وإجراء الفحوصات الدورية للحفاظ على صحة جيدة. راقب أي تغييرات ملحوظة مع مرور الوقت." + }, + "bmiUnderweightDescription": { + "en": "BMI suggests you are underweight. Consider increasing calorie intake with nutrient-dense foods, include resistance training to build muscle, and consult a healthcare professional to check for underlying causes.", + "ar": "يشير مؤشر كتلة الجسم إلى أنك تعاني من نقص الوزن. لذا، يُنصح بزيادة السعرات الحرارية المتناولة من خلال تناول الأطعمة الغنية بالعناصر الغذائية، وممارسة تمارين المقاومة لبناء العضلات، واستشارة أخصائي رعاية صحية للتحقق من وجود أسباب كامنة." + }, + "bmiOverweightDescription": { + "en": "BMI suggests overweight. It is advised to aim for gradual, sustainable weight loss through moderate calorie reduction, regular physical activity, and healthy food choices. Consult your doctor before making any major lifestyle changes.", + "ar": "يشير مؤشر كتلة الجسم إلى زيادة الوزن. لذا، يُنصح بالسعي إلى إنقاص الوزن تدريجياً وبشكل مستدام من خلال تقليل السعرات الحرارية بشكل معتدل، وممارسة النشاط البدني بانتظام، واختيار الأطعمة الصحية. استشر طبيبك قبل إجراء أي تغييرات جذرية في نمط حياتك." + }, + "caloriesMaintenanceDescription": { + "en": "Estimated daily calories to maintain your current weight based on your activity level and metabolic rate. Use this as a baseline: slightly increase for muscle gain or slightly decrease for gradual weight loss. Monitor progress and adjust every 2–4 weeks.", + "ar": "السعرات الحرارية اليومية المُقدَّرة للحفاظ على وزنك الحالي بناءً على مستوى نشاطك ومعدل الأيض لديك. استخدم هذه الكمية كخط أساس: زدها قليلاً لزيادة الكتلة العضلية، أو قللها قليلاً لإنقاص الوزن تدريجياً. تابع تقدمك وعدّل الخطة كل أسبوعين إلى أربعة أسابيع." + }, + "caloriesModerateDeficitDescription": { + "en": "A moderate calorie reduction plan designed for steady, sustainable weight loss (typically 0.25 to 0.5 kg per week). Combine with resistance training and adequate protein to preserve muscle mass. Avoid sharp calorie drops and consult a professional if you have medical conditions.", + "ar": "نظام غذائي معتدل لتقليل السعرات الحرارية مصمم لإنقاص الوزن بشكل ثابت ومستدام (عادةً من 0.25 إلى 0.5 كيلوغرام أسبوعيًا). يُنصح بدمجه مع تمارين المقاومة وتناول كمية كافية من البروتين للحفاظ على الكتلة العضلية. تجنب التخفيضات الحادة في السعرات الحرارية واستشر طبيبًا مختصًا إذا كنت تعاني من أي حالة صحية." + }, + "caloriesAggressiveDeficitDescription": { + "en": "A large calorie reduction that may produce faster weight loss but can be hard to sustain and increase risk of nutrient deficiencies, fatigue, or muscle loss. Not recommended long-term; seek guidance from a healthcare or nutrition professional before continuing.", + "ar": "يؤدي خفض السعرات الحرارية بشكل كبير إلى فقدان الوزن بشكل أسرع، ولكنه قد يصعب الاستمرار عليه ويزيد من خطر نقص العناصر الغذائية والإرهاق وفقدان الكتلة العضلية. لا يُنصح باتباعه على المدى الطويل؛ استشر طبيبًا أو أخصائي تغذية قبل الاستمرار." + }, + "bodyFatEssentialDescription": { + "en": "Your body fat percentage is in the essential/athletic range. This level is typical for athletes and indicates very low body fat. While this may be optimal for performance, ensure you maintain adequate nutrition and hormone function. Consult a healthcare professional if you experience fatigue, hormonal issues, or other health concerns.", + "ar": "نسبة الدهون في جسمك ضمن النطاق الأساسي/الرياضي. هذا المستوى شائع لدى الرياضيين ويشير إلى انخفاض نسبة الدهون في الجسم. مع أن هذا قد يكون مثاليًا للأداء، تأكد من الحفاظ على تغذية سليمة ووظائف هرمونية متوازنة. استشر طبيبًا إذا شعرت بالتعب، أو واجهت مشاكل هرمونية، أو أي مخاوف صحية أخرى." + }, + "bodyFatFitnessDescription": { + "en": "Your body fat percentage is in the fitness range. This indicates a healthy level of body fat associated with good physical conditioning. Maintain your current lifestyle habits including regular exercise and balanced nutrition to sustain this healthy range.", + "ar": "نسبة الدهون في جسمك ضمن النطاق الصحي. وهذا يدل على مستوى صحي من الدهون في الجسم يرتبط بلياقة بدنية جيدة. حافظ على نمط حياتك الحالي، بما في ذلك ممارسة الرياضة بانتظام واتباع نظام غذائي متوازن، للحفاظ على هذا المستوى الصحي." + }, + "bodyFatAverageDescription": { + "en": "Your body fat percentage is in the average/acceptable range. This is considered a healthy range for general population. To improve body composition, consider incorporating strength training, cardiovascular exercise, and a balanced diet. Focus on gradual, sustainable changes for long-term health.", + "ar": "نسبة الدهون في جسمك ضمن المعدل الطبيعي/المقبول، وهي نسبة تُعتبر صحية لعموم الناس. لتحسين تكوين جسمك، يُنصح بممارسة تمارين القوة، وتمارين القلب والأوعية الدموية، واتباع نظام غذائي متوازن. ركّز على التغييرات التدريجية والمستدامة للحفاظ على صحتك على المدى الطويل." + }, + "bodyFatObeseDescription": { + "en": "Your body fat percentage is above the recommended healthy range. This may increase health risks including cardiovascular disease, diabetes, and joint problems. Consider consulting a healthcare provider or registered dietitian to develop a personalized plan that includes balanced nutrition, regular physical activity, and lifestyle modifications for sustainable weight management.", + "ar": "نسبة الدهون في جسمك أعلى من المعدل الصحي الموصى به. قد يزيد هذا من المخاطر الصحية، بما في ذلك أمراض القلب والأوعية الدموية، والسكري، ومشاكل المفاصل. يُنصح باستشارة طبيب أو أخصائي تغذية معتمد لوضع خطة علاجية شخصية تشمل التغذية المتوازنة، والنشاط البدني المنتظم، وتعديلات نمط الحياة لتحقيق إدارة مستدامة للوزن." + }, + "bmrNormalDescription": { + "en": "Your Basal Metabolic Rate (BMR) is within the expected range for your profile. BMR is the energy your body needs at rest to maintain vital functions (breathing, circulation, temperature). Use this value as the baseline for estimating total daily energy needs by applying an activity multiplier. Maintain a balanced diet and regular physical activity to support metabolic health.", + "ar": "معدل الأيض الأساسي لديك ضمن النطاق المتوقع لحالتك. معدل الأيض الأساسي هو الطاقة التي يحتاجها جسمك في حالة الراحة للحفاظ على وظائفه الحيوية (التنفس، الدورة الدموية، درجة الحرارة). استخدم هذه القيمة كأساس لتقدير إجمالي احتياجاتك اليومية من الطاقة من خلال تطبيق مُعامل النشاط. حافظ على نظام غذائي متوازن وممارسة النشاط البدني بانتظام لدعم صحة التمثيل الغذائي." + }, + "bmrLowDescription": { + "en": "Your BMR is lower than typical for your profile. Possible causes include lower lean muscle mass, age-related metabolic decline, or metabolic adaptation from prolonged calorie restriction. Consider focusing on resistance training to build/maintain muscle, ensure adequate protein and micronutrient intake, and consult a healthcare professional if this is unexpected.", + "ar": "معدل الأيض الأساسي لديك أقل من المعدل الطبيعي لحالتك. تشمل الأسباب المحتملة انخفاض كتلة العضلات، أو تراجع التمثيل الغذائي المرتبط بالتقدم في السن، أو التكيف الأيضي الناتج عن تقييد السعرات الحرارية لفترة طويلة. يُنصح بالتركيز على تمارين المقاومة لبناء العضلات والحفاظ عليها، والتأكد من تناول كميات كافية من البروتين والمغذيات الدقيقة، واستشارة أخصائي رعاية صحية إذا كان هذا الأمر غير متوقع." + }, + "bmrHighDescription": { + "en": "Your BMR is higher than average for your profile. This can reflect greater lean mass, younger age, or a naturally higher metabolic rate, meaning you burn more energy at rest. Use this information to tailor calorie targets: higher needs for maintenance or muscle gain, moderate deficit for weight loss. Seek medical advice if you notice rapid unexplained changes.", + "ar": "معدل الأيض الأساسي لديك أعلى من المتوسط ​​بالنسبة لحالتك. قد يعكس هذا زيادة في كتلة العضلات، أو صغر السن، أو ارتفاع معدل الأيض لديك بشكل طبيعي، مما يعني أنك تحرق طاقة أكبر أثناء الراحة. استخدم هذه المعلومات لتحديد احتياجاتك من السعرات الحرارية: احتياجات أعلى للحفاظ على الوزن أو بناء العضلات، ونقص معتدل في السعرات الحرارية لإنقاص الوزن. استشر طبيبك إذا لاحظت أي تغيرات سريعة غير مبررة." + }, + "ibwAtTargetDescription": { + "en": "Your weight is at the ideal target. Maintain your current habits — balanced diet and regular activity — to keep this.", + "ar": "وزنك في النطاق المثالي. حافظ على عاداتك الحالية — نظام غذائي متوازن ونشاط بدني منتظم — للاستمرار على هذا المستوى." + }, + "ibwBelowTargetDescription": { + "en": "You are below the ideal weight by {kg} kg. Aim to gradually increase weight with a modest calorie surplus, nutrient-dense foods, and resistance training.", + "ar": "أنتِ أقل من الوزن المثالي بمقدار {kg} كجم. يُنصح بزيادة الوزن تدريجيًا من خلال فائضٍ بسيط في السعرات الحرارية، وتناول أطعمة غنية بالعناصر الغذائية، مع ممارسة تمارين المقاومة." + }, + "ibwAboveTargetDescription": { + "en": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight reduction through a moderate calorie deficit, increased activity, and balanced nutrition.", + "ar": "أنتِ أعلى من الوزن المثالي بمقدار {kg} كجم. يُنصح باتباع خفضٍ تدريجي ومستدام للوزن من خلال عجزٍ معتدل في السعرات الحرارية، وزيادة مستوى النشاط البدني، واتباع تغذية متوازنة." + }, + "ibwCloseToRangeDescription": { + "en": "Your weight is close to the ideal range. Maintain a balanced diet and regular activity; follow personalized advice from a healthcare professional if needed.", + "ar": "وزنك قريب من النطاق المثالي. حافظ على نظام غذائي متوازن ونشاط بدني منتظم، مع اتباع إرشادات شخصية من مختص صحي عند الحاجة." + }, + "ibwUnderweightDescription": { + "en": "You are below the ideal weight by {kg} kg. Focus on increasing calorie intake with nutrient-dense foods, prioritize protein and resistance training to build healthy mass, and consider consulting a healthcare professional.", + "ar": "أنت أقل من الوزن المثالي بمقدار {kg} كجم. ركّز على زيادة السعرات الحرارية من خلال أطعمة غنية بالعناصر الغذائية، وأعط الأولوية للبروتين وتمارين المقاومة لبناء كتلة صحية، مع اتباع إرشادات شخصية من مختص صحي." + }, + "ibwUnderweightGenericDescription": { + "en": "You appear underweight compared to the ideal. Consider increasing calorie intake with nutrient-dense foods and resistance training; seek professional guidance if needed.", + "ar": "يبدو أنكِ أقل من الوزن المثالي. يُنصح بزيادة السعرات الحرارية من خلال أطعمة غنية بالعناصر الغذائية وممارسة تمارين المقاومة؛ مع الحصول على استشارة مختص صحي عند الحاجة." + }, + "ibwOverweightDescription": { + "en": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight loss strategy — moderate calorie deficit, regular physical activity, and balanced nutrition. Consult a professional before major changes.", + "ar": "أنت أعلى من الوزن المثالي بمقدار {kg} كجم. يُنصح باتباع استراتيجية تدريجية ومستدامة لفقدان الوزن — من خلال عجزٍ معتدل في السعرات الحرارية، وممارسة نشاط بدني منتظم، وتغذية متوازنة. يُفضّل استشارة مختص صحي قبل إجراء تغييرات كبيرة." + }, + "ibwOverweightGenericDescription": { + "en": "You appear above the ideal weight. Consider a gradual, sustainable calorie deficit combined with activity and balanced nutrition; consult a professional if needed.", + "ar": "يبدو أنك أعلى من الوزن المثالي. يُنصح باتباع عجزٍ تدريجي ومستدام في السعرات الحرارية مع ممارسة النشاط البدني واتباع تغذية متوازنة؛ مع الحصول على استشارة مختص صحي عند الحاجة." + }, + "dietVeryLowCarbsDescription": { + "en": "Very low‑carb (ketogenic) approach: minimal carbohydrates, higher fat and moderate protein. May support rapid weight loss and improved blood sugar control for some, but can be hard to sustain and may cause nutrient gaps. Monitor hydration/electrolytes and consult a professional for long‑term use.", + "ar": "نهج منخفض الكربوهيدرات جدًا (الكيتوني): تقليل الكربوهيدرات إلى الحد الأدنى مع زيادة الدهون وبروتين معتدل. قد يساعد على فقدان الوزن بسرعة وتحسين التحكم في سكر الدم لدى بعض الأشخاص، لكنه قد يكون صعب الاستمرار عليه وقد يسبب نقصًا في بعض العناصر الغذائية. يجب مراقبة الترطيب ، والحصول على استشارة مختص صحي عند استخدامه لفترة طويلة." + }, + "dietLowCarbsDescription": { + "en": "Low‑carb, higher‑protein plan: reduced carbohydrates with increased protein to support satiety and muscle maintenance. Helpful for weight management and glycemic control when balanced with vegetables and healthy fats. Ensure adequate fiber and micronutrients.", + "ar": "خطة منخفضة الكربوهيدرات وعالية البروتين: تقليل الكربوهيدرات مع زيادة البروتين لدعم الشعور بالشبع والحفاظ على الكتلة العضلية. مفيدة لإدارة الوزن وضبط سكر الدم عند موازنتها مع الخضروات والدهون الصحية. احرص على الحصول على كمية كافية من الألياف والعناصر الدقيقة (الفيتامينات والمعادن)." + }, + "dietModerateCarbsDescription": { + "en": "Moderate carbohydrate intake with balanced protein and fats: provides steady energy for daily activity and exercise while allowing flexibility. Suitable for many people aiming for sustainable weight management and performance.", + "ar": "تناول معتدل للكربوهيدرات مع توازن في البروتين والدهون: يوفر طاقة مستقرة للأنشطة اليومية والتمارين مع قدر من المرونة. مناسب لكثير من الأشخاص الذين يسعون لإدارة وزن مستدامة وتحسين الأداء." + }, + "dietUSDAGuidelinesDescription": { + "en": "USDA‑based balanced pattern: emphasizes fruits, vegetables, whole grains, lean proteins, and limited added sugars and saturated fats. Evidence‑based framework for general health, nutrient adequacy, and chronic disease prevention.", + "ar": "نمط متوازن مستند إلى (USDA): يركز على الفواكه والخضروات والحبوب الكاملة والبروتينات قليلة الدهن، مع الحد من السكريات المضافة والدهون المشبعة. يُعد إطارًا قائمًا على الأدلة لدعم الصحة العامة، وكفاية العناصر الغذائية، والوقاية من الأمراض المزمنة." + }, + "dietZoneDietDescription": { + "en": "Zone Diet (~40% carbs / 30% protein / 30% fat): emphasizes hormonal balance and portion control. May improve body composition and energy for some, but requires planning; personalize with a nutrition professional.", + "ar": "حمية الزون (~40٪ كربوهيدرات / 30٪ بروتين / 30٪ دهون): تركز على التوازن الهرموني وضبط الحصص الغذائية. قد تُحسّن تركيب الجسم ومستوى الطاقة لدى بعض الأشخاص، لكنها تتطلب تخطيطًا جيدًا؛ ويُفضّل تخصيصها بالتعاون مع مختص تغذية." + }, + "contextDependent": { + "en": "Context Dependent", + "ar": "يعتمد السياق" + }, + "calculatedValue": { + "en": "Calculated Value", + "ar": "القيمة المحسوبة" + }, + "calculationFormula": { + "en": "Calculation Formula", + "ar": "صيغة الحساب" + }, + "confirmYourLocation": { + "en": "Confirm your location", + "ar": "قم بتأكيد موقعك" + }, + "confirmYourLocationDesc": { + "en": "Please confirm your current location to show appropriate directions.", + "ar": "يرجى تأكيد موقعك الحالي لعرض الاتجاهات المناسبة." + }, + "insideHospital": { + "en": "I am inside the hospital", + "ar": "أنا داخل المستشفى" + }, + "outsideHospital": { + "en": "I am outside the hospital", + "ar": "أنا خارج المستشفى" + }, + "servicePriceList": { + "en": "Service Price List", + "ar": "قائمة أسعار الخدمات" + }, + "servicePriceListDesc": { + "en": "The service price list below shows the fees for health services provided to patients on a cash payment basis. Regarding services covered by insurance, insurance coverage will be applied, eligibility verified, and co-payment percentages calculated according to the terms of the insurance policy and the approved benefit schedule for each insurance company.", + "ar": "توضح قائمة أسعار الخدمات أدناه رسوم الخدمات الصحية المقدمة للمرضى بنظام الدفع النقدي. أما فيما يتعلق بالخدمات المشمولة بالتأمين، فسيتم تطبيق التغطية التأمينية والتحقق من الأهلية واحتساب نسب التحمل وفقًا لشروط وثيقة التأمين وجدول المنافع المعتمد لكل شركة تأمين." + }, + "servicePriceListRights": { + "en": "The patient is entitled to a free follow-up within 14 days of the first visit", + "ar": "يحق للمريض الحصول على متابعة مجانية في غضون 14 يومًا من الزيارة الأولى" + }, + "serviceName": { + "en": "Service Name", + "ar": "اسم الخدمة" + }, + "noFreeSlot": { + "en": "There are no appointments available on the selected date. Please choose another date or try again later.", + "ar": "لا توجد مواعيد متاحة في التاريخ المحدد. يرجى اختيار تاريخ آخر أو إعادة المحاولة لاحقاً." + }, + "noThanksIKnowTheClinic": { + "en": "No, thanks. I know the clinic.", + "ar": "لا، شكراً. أنا أعرف العيادة." + }, + "unableToSendOTP": { + "en": "Unable to send One-Time Password", + "ar": "تعذر إرسال رمز التحقق لمرة واحدة" + }, + "loadingAIAnalysis": { + "en": "Analysing your lab results, Please be patient and let the AI do the magic, This might take some time.", + "ar": "جارٍ تحليل نتائج المختبر، يرجى التحلي بالصبر والسماح للذكاء الاصطناعي بالقيام بالمهمة، قد يستغرق هذا بعض الوقت." + }, + "symptoms": { + "en": "Symptoms", + "ar": "أعراض" + }, + "insuranceInActive": { + "en": "Insurance Inactive", + "ar": "التأمين غير نشط" + }, + "insuranceInActiveContactSupport": { + "en": "You have a valid insurance but it is currently inactive in HMG. Please contact HMG customer support to activate it.", + "ar": "لديك تأمين ساري المفعول، ولكنه غير مُفعّل حاليًا في مجموعة حبيب الطبية. يُرجى التواصل مع خدمة عملاء مجموعة حبيب الطبية." + }, + "updateAppNow": { + "en": "Update App Now", + "ar": "تحديث التطبيق الآن" + }, + "Dr": { + "en": "Dr.", + "ar": "الدكتور." + }, + "reschedulingAppo": { + "en": "Rescheduling Appointment, Please wait...", + "ar": "إعادة جدولة الموعد، يرجى الانتظار..." + }, + "invalidEligibility": { + "en": "You cannot make online payment because you are not eligible to use the provided service.", + "ar": "لا يمكنك إجراء الدفع عبر الإنترنت لأنك غير مؤهل لاستخدام الخدمة المقدمة." + }, + "invalidInsurance": { + "en": "You cannot make online payment because you do not have a valid insurance.", + "ar": "لا يمكنك إجراء الدفع عبر الإنترنت لأنه ليس لديك تأمين صالح." + }, + "continueCash": { + "en": "Continue as cash", + "ar": "متابعة الدفع نقدًا" + }, + "timeFor": { + "en": "Time For", + "ar": "الوقت" + }, + "hmgPolicies": { + "en": "HMG Policies", + "ar": "سياسات مجموعة الحبيب الطبية" + }, + "darkMode": { + "en": "Dark Mode", + "ar": "المظهر الداكن" + }, + "generateAiAnalysisResult": { + "en": "Generate AI analysis for this result", + "ar": "قم بإجراء تحليل لهذا المختبر AI" + } +} \ No newline at end of file diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 71d30372..f415d8ac 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -184,15 +184,15 @@ class ApiClientImp implements ApiClient { body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken; } - if (url.contains("HMGAI_Lab_Analyze_Orders_API")) { - url = "https://uat.hmgwebservices.com/Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API"; - body['TokenID'] = "@dm!n"; - } - - if (url.contains("HMGAI_Lab_Analyzer_API")) { - url = "https://uat.hmgwebservices.com/Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API"; - body['TokenID'] = "@dm!n"; - } + // if (url.contains("HMGAI_Lab_Analyze_Orders_API")) { + // url = "https://uat.hmgwebservices.com/Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API"; + // body['TokenID'] = "@dm!n"; + // } + // + // if (url.contains("HMGAI_Lab_Analyzer_API")) { + // url = "https://uat.hmgwebservices.com/Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API"; + // body['TokenID'] = "@dm!n"; + // } if (url == 'https://uat.hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo') { url = "https://hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo"; diff --git a/lib/features/habib_wallet/habib_wallet_view_model.dart b/lib/features/habib_wallet/habib_wallet_view_model.dart index 65e8e276..3d72f651 100644 --- a/lib/features/habib_wallet/habib_wallet_view_model.dart +++ b/lib/features/habib_wallet/habib_wallet_view_model.dart @@ -112,6 +112,8 @@ class HabibWalletViewModel extends ChangeNotifier { habibWalletBalanceList.sort((a, b) => b.patientAdvanceBalanceAmount!.compareTo(a.patientAdvanceBalanceAmount!)); + habibWalletBalanceList.removeWhere((element) => element.patientAdvanceBalanceAmount == 0); + isWalletAmountLoading = false; notifyListeners(); if (onSuccess != null) { diff --git a/lib/presentation/habib_wallet/habib_wallet_page.dart b/lib/presentation/habib_wallet/habib_wallet_page.dart index 780c3d64..2a3da660 100644 --- a/lib/presentation/habib_wallet/habib_wallet_page.dart +++ b/lib/presentation/habib_wallet/habib_wallet_page.dart @@ -56,8 +56,10 @@ class _HabibWalletState extends State { width: double.infinity, height: 180.h, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, + // color: AppColors.blackBgColor, + color: Color(0xFF2E3039), + borderRadius: 24.r, + hasShadow: true ), child: Padding( padding: EdgeInsets.all(16.h), @@ -71,7 +73,7 @@ class _HabibWalletState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - "${_appState.getAuthenticatedUser()!.firstName!} ${_appState.getAuthenticatedUser()!.lastName!}".toText19(isBold: true, color: AppColors.textColor), + "${_appState.getAuthenticatedUser()!.firstName!} ${_appState.getAuthenticatedUser()!.lastName!}".toText19(isBold: true, color: Colors.white), "MRN: ${_appState.getAuthenticatedUser()!.patientId!}".toText14(weight: FontWeight.w500, color: AppColors.greyTextColor), ], ).expanded, @@ -79,10 +81,10 @@ class _HabibWalletState extends State { ], ), Spacer(), - LocaleKeys.balanceAmount.tr(context: context).toText14(weight: FontWeight.w500, color: AppColors.textColor), + LocaleKeys.balanceAmount.tr(context: context).toText14(weight: FontWeight.w500, color: Colors.white), SizedBox(height: 4.h), Consumer(builder: (context, habibWalletVM, child) { - return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, textColor: AppColors.textColor, iconColor: AppColors.textColor, iconSize: 16, isExpanded: false) + return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, textColor: Colors.white, iconColor: Colors.white, iconSize: 16, isExpanded: false) .toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 24.h); }), ], diff --git a/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart b/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart index 2c552bc7..ebf802df 100644 --- a/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart +++ b/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart @@ -78,6 +78,8 @@ class AiAnalysisWidget extends StatelessWidget { CustomButton( height: 50.h, text: LocaleKeys.close.tr(context: context), + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, onPressed: () { getIt.get().closeAILabResultAnalysis(); }, From 55b8bc162c87b55b935f9e2ce98b1d1dff60fd06 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Sat, 21 Mar 2026 21:00:03 -0600 Subject: [PATCH 20/33] Updates --- assets/langs/ar-SA.json | 5 +- assets/langs/en-US.json | 3 +- assets/langs/translations.json | 6290 ----------------- lib/core/api_consts.dart | 4 +- lib/extensions/string_extensions.dart | 4 +- .../book_appointments_view_model.dart | 1 + lib/generated/locale_keys.g.dart | 1 + .../widgets/appointment_card.dart | 10 +- .../widgets/appointment_doctor_card.dart | 50 +- .../book_appointment/doctor_profile_page.dart | 4 +- .../book_appointment/select_doctor_page.dart | 2 +- .../widgets/appointment_calendar.dart | 155 +- .../book_appointment/widgets/doctor_card.dart | 2 +- .../home/widgets/welcome_widget.dart | 2 +- .../widgets/patient_insurance_card.dart | 2 +- lib/presentation/lab/lab_orders_page.dart | 2 +- .../medical_file/medical_file_page.dart | 16 +- .../medical_file_appointment_card.dart | 2 +- .../prescription_detail_page.dart | 26 +- .../prescriptions/prescription_item_view.dart | 8 +- .../prescriptions_list_page.dart | 9 +- .../profile_settings/profile_settings.dart | 2 +- .../radiology/radiology_orders_page.dart | 13 +- .../radiology/radiology_result_page.dart | 83 +- lib/widgets/appbar/collapsing_list_view.dart | 6 + lib/widgets/chip/app_custom_chip_widget.dart | 6 +- pubspec.yaml | 4 +- 27 files changed, 233 insertions(+), 6479 deletions(-) delete mode 100644 assets/langs/translations.json diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 76736da7..04684df5 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -448,7 +448,7 @@ "lakumPoint": "نقطة", "wishlist": "قائمة الرغبات", "products": "المنتجات", - "reviews": "التقييمات", + "reviews": "التعليقات", "brands": "العلامات التجارية", "productDetails": "تفاصيل المنتج", "medicationRefill": "إعادة تعبئة الدواء", @@ -1584,5 +1584,6 @@ "timeFor": "الوقت", "hmgPolicies": "سياسات مجموعة الحبيب الطبية", "darkMode": "المظهر الداكن", - "generateAiAnalysisResult": "قم بإجراء تحليل لهذا المختبر AI" + "generateAiAnalysisResult": "قم بإجراء تحليل لهذا المختبر AI", + "ratings": "التقييمات" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index b7c8def0..c43d730e 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1577,5 +1577,6 @@ "timeFor": "Time For", "hmgPolicies": "HMG Policies", "darkMode": "Dark Mode", - "generateAiAnalysisResult": "Generate AI analysis for this result" + "generateAiAnalysisResult": "Generate AI analysis for this result", + "ratings": "Ratings" } diff --git a/assets/langs/translations.json b/assets/langs/translations.json deleted file mode 100644 index 9750d779..00000000 --- a/assets/langs/translations.json +++ /dev/null @@ -1,6290 +0,0 @@ -{ - "english": { - "en": "English", - "ar": "الإنجليزية" - }, - "arabic": { - "en": "Arabic", - "ar": "العربية" - }, - "login": { - "en": "Login", - "ar": "تسجيل الدخول" - }, - "noDataAvailable": { - "en": "No Data Available", - "ar": "لا توجد بيانات متاحة" - }, - "confirm": { - "en": "Confirm", - "ar": "تأكيد" - }, - "loadingText": { - "en": "Loading, please wait...", - "ar": "جاري التحميل، يرجى الانتظار..." - }, - "kilometerUnit": { - "en": "KM", - "ar": "كم" - }, - "dashboardScreenToolbarTitle": { - "en": "Home", - "ar": "الرئيسية" - }, - "settings": { - "en": "Settings", - "ar": "الإعدادات" - }, - "language": { - "en": "App Language", - "ar": "لغة التطبيق" - }, - "lanEnglish": { - "en": "English", - "ar": "الإنجليزية" - }, - "lanArabic": { - "en": "العربية", - "ar": "العربية" - }, - "cancel": { - "en": "Cancel", - "ar": "إلغاء" - }, - "done": { - "en": "Done", - "ar": "تم" - }, - "replay2": { - "en": "Replay", - "ar": "إعادة التشغيل" - }, - "home": { - "en": "Home", - "ar": "الرئيسية" - }, - "services": { - "en": "SERVICES", - "ar": "الخدمات" - }, - "mySchedule": { - "en": "My Schedule", - "ar": "جدولي" - }, - "logout": { - "en": "Logout", - "ar": "تسجيل الخروج" - }, - "respirationRate": { - "en": "Respiration Rate", - "ar": "معدل التنفس" - }, - "bookAppo": { - "en": "Book Appointment", - "ar": "حجز موعد" - }, - "searchBy": { - "en": "Search By:", - "ar": "البحث بواسطة:" - }, - "clinic": { - "en": "Clinic", - "ar": "عيادة" - }, - "byClinic": { - "en": "By Clinic", - "ar": "حسب العيادة" - }, - "hospital": { - "en": "Hospital", - "ar": "مستشفى" - }, - "byHospital": { - "en": "By Hospital", - "ar": "حسب المستشفى" - }, - "name": { - "en": "Name", - "ar": "الاسم" - }, - "doctor": { - "en": "Doctor", - "ar": "طبيب" - }, - "clinicName": { - "en": "Clinic Name", - "ar": "اسم العيادة" - }, - "hospitalName": { - "en": "Hospital Name", - "ar": "اسم المستشفى" - }, - "noClinicFound": { - "en": "No Clinic Found", - "ar": "لم يتم العثور على عيادة" - }, - "doctorName": { - "en": "Doctor Name", - "ar": "اسم الطبيب" - }, - "nearestAppo": { - "en": "Nearest Appointment", - "ar": "أقرب موعد" - }, - "searchByDocText": { - "en": "Type the name of the doctor to help you find him", - "ar": "اكتب اسم الطبيب لمساعدتك في العثور عليه" - }, - "enterDocName": { - "en": "Enter Doctor name", - "ar": "أدخل اسم الطبيب" - }, - "search": { - "en": "Search", - "ar": "بحث" - }, - "noResultFound": { - "en": "No Result Found", - "ar": "لم يتم العثور على نتائج" - }, - "noSearchResultFound": { - "en": "No Result Found", - "ar": "لم يتم العثور على نتائج" - }, - "pleaseEnterProductName": { - "en": "Please Enter Product Name", - "ar": "يرجى إدخال اسم المنتج" - }, - "bookNow": { - "en": "Book Now", - "ar": "احجز الآن" - }, - "docInfo": { - "en": "Doctor Information", - "ar": "معلومات الطبيب" - }, - "appoInfo": { - "en": "Appointment Information", - "ar": "معلومات الموعد" - }, - "availableAppo": { - "en": "Available Appointments", - "ar": "المواعيد المتاحة" - }, - "gender": { - "en": "Gender", - "ar": "الجنس" - }, - "nationality": { - "en": "Nationality", - "ar": "الجنسية" - }, - "neverWait": { - "en": "Never wait in queue", - "ar": "لا تنتظر في الطابور أبدًا" - }, - "reminderTitle": { - "en": "You have appointment with Dr. ", - "ar": "لديك موعد مع الدكتور." - }, - "appointmentCalendar": { - "en": "Would you like to set a reminder for this appointment in your calendar?", - "ar": "هل ترغب في تعيين تذكير لهذا الموعد في التقويم الخاص بك؟" - }, - "appointmentSuccess": { - "en": "Appointment is successfully booked", - "ar": "تم حجز الموعد بنجاح" - }, - "docQualifications": { - "en": "Doctor Qualifications", - "ar": "مؤهلات الطبيب" - }, - "pressAgain": { - "en": "Press again to exit the app", - "ar": "اضغط مرة أخرى للخروج من التطبيق" - }, - "laserMaxLimitReach": { - "en": "Maximum limit is 90 minutes", - "ar": "الحد الأقصى هو 90 دقيقة" - }, - "confirmAppoHeading": { - "en": "Kindly review your Appointment", - "ar": "يرجى مراجعة موعدك" - }, - "patientInfo": { - "en": "Patient Information", - "ar": "معلومات المريض" - }, - "doctorFilter": { - "en": "Doctors will be filtered based on your gender and age", - "ar": "سيتم تصفية الأطباء بناءً على جنسك وعمرك" - }, - "bookSuccess": { - "en": "Book Success", - "ar": "تم الحجز بنجاح" - }, - "patientShare": { - "en": "Patient Share", - "ar": "نسبة المريض" - }, - "patientShareWithTax": { - "en": "Patient Share with Tax", - "ar": "نسبة المريض مع الضريبة" - }, - "confirmAppo": { - "en": "Confirm Appointment", - "ar": "تأكيد الموعد" - }, - "confirmLiveCare": { - "en": "Confirm LiveCare", - "ar": "تأكيد ال لايف كير" - }, - "waitingForDoctor": { - "en": "Waiting for doctor", - "ar": "في انتظار الطبيب" - }, - "appointment": { - "en": "Appointment", - "ar": "موعد" - }, - "confirmLater": { - "en": "Confirm Later", - "ar": "تأكيد لاحقًا" - }, - "todoList": { - "en": "Todo List", - "ar": "قائمة المهام" - }, - "appoActions": { - "en": "Appointment Actions", - "ar": "إجراءات الموعد" - }, - "date": { - "en": "Date", - "ar": "التاريخ" - }, - "time": { - "en": "Time", - "ar": "الوقت" - }, - "pendingPayment": { - "en": "Pending for payment", - "ar": "معلق للدفع" - }, - "payNow": { - "en": "Pay Now", - "ar": "ادفع الآن" - }, - "viewQR": { - "en": "View QR Code", - "ar": "عرض رمز الاستجابة السريعة" - }, - "instruction": { - "en": "Instructions", - "ar": "تعليمات" - }, - "livecare": { - "en": "LiveCare", - "ar": "لايف كير" - }, - "livecareAppo": { - "en": "LiveCare Appointment", - "ar": "موعد لايف كير" - }, - "agreeTo": { - "en": "I agree to the", - "ar": "أوافق على" - }, - "termsConditoins": { - "en": "Terms and Conditions", - "ar": "الشروط والأحكام" - }, - "cancelAppoMsg": { - "en": "Are you sure you want to cancel this appointment?", - "ar": "هل أنت متأكد أنك تريد إلغاء هذا الموعد؟" - }, - "changePayment": { - "en": "Change Payment Method", - "ar": "تغيير طريقة الدفع" - }, - "upcomingNoAction": { - "en": "No Action Required", - "ar": "لا يتطلب أي إجراء" - }, - "upcomingConfirm": { - "en": "Please confirm the appointment to avoid cancellation", - "ar": "يرجى تأكيد الموعد لتجنب الإلغاء" - }, - "bookSuccessConfirmMore2412": { - "en": "The online payment process will be available 24 hours before the appointment.", - "ar": "ستكون عملية الدفع عبر الإنترنت متاحة قبل 24 ساعة من الموعد." - }, - "upcomingPaymentPending": { - "en": "Online Payment will be Activated before 24 Hours of Appointment Time", - "ar": "سيتم تفعيل الدفع عبر الإنترنت قبل 24 ساعة من موعد الموعد" - }, - "upcomingPaymentNow": { - "en": "Pay Online now to avoid long waiting queue", - "ar": "ادفع عبر الإنترنت الآن لتجنب الانتظار الطويل" - }, - "upcomingQR": { - "en": "Use the QR Code to Check-In in hospital", - "ar": "استخدم رمز الاستجابة السريعة لتسجيل الوصول في المستشفى" - }, - "upcomingVirtual": { - "en": "This is a virtual appointment, Please adhere to the instructions for a seamless experience.", - "ar": "هذا موعد افتراضي، يرجى الالتزام بالتعليمات لتجربة سلسة." - }, - "upcomingLivecare": { - "en": "This is a LiveCare appointment", - "ar": "هذا موعد لايف كير" - }, - "upcomingDetails": { - "en": "More Details", - "ar": "المزيد من التفاصيل" - }, - "reschedule": { - "en": "Reschedule", - "ar": "إعادة جدولة" - }, - "raise": { - "en": "Raise", - "ar": "رفع" - }, - "complaint": { - "en": "Complaint", - "ar": "شكوى" - }, - "add": { - "en": "Add", - "ar": "إضافة" - }, - "reminder": { - "en": "Reminder", - "ar": "تذكير" - }, - "location": { - "en": "Locations", - "ar": "المواقع" - }, - "online": { - "en": "Online", - "ar": "عبر الإنترنت" - }, - "payment": { - "en": "Payment", - "ar": "الدفع" - }, - "onlinePayment": { - "en": "Online", - "ar": "عبر الإنترنت" - }, - "onlinePaymentSubtitle": { - "en": "Payment", - "ar": "الدفع" - }, - "cancelNocaps": { - "en": "Cancel", - "ar": "إلغاء" - }, - "setReminder": { - "en": "Set Reminder", - "ar": "ضبط تذكير" - }, - "nationalIdNumber": { - "en": "National ID Number", - "ar": "رقم الهوية الوطنية" - }, - "medicalFileNumber": { - "en": "Medical File Number", - "ar": "رقم الملف الطبي" - }, - "loginregister": { - "en": "Login / Register", - "ar": "تسجيل الدخول / التسجيل" - }, - "poweredBy": { - "en": "Powered by", - "ar": "مدعوم من" - }, - "welcome": { - "en": "Welcome", - "ar": "مرحبًا" - }, - "welcomeToDrSulaiman": { - "en": "Welcome to Dr. Sulaiman Al Habib Medical Group", - "ar": "مرحباً بكم في مجموعة الدكتور سليمان الحبيب الطبية" - }, - "patientApp": { - "en": "Patient App", - "ar": "تطبيق المريض" - }, - "welcomeText": { - "en": "Dr. Sulaiman Al Habib Mobile Application", - "ar": "تطبيق الدكتور سليمان الحبيب للهاتف المحمول" - }, - "drSulaimanText": { - "en": "Dr. Sulaiman Al Habib", - "ar": "الدكتور سليمان الحبيب" - }, - "welcomeText2": { - "en": "Have you previously visited the hospitals or medical centers of Dr. Sulaiman Al Habib?", - "ar": "هل زرت مستشفيات أو مراكز الدكتور سليمان الحبيب من قبل؟" - }, - "yes": { - "en": "Yes", - "ar": "نعم" - }, - "no": { - "en": "No", - "ar": "لا" - }, - "logintyperadio": { - "en": " Choose from the below options to login to your medical file.", - "ar": "اختر من الخيارات أدناه لتسجيل الدخول إلى ملفك الطبي." - }, - "registernow": { - "en": "Register Now", - "ar": "سجل الآن" - }, - "nationalID": { - "en": "Enter the Identification Number", - "ar": "أدخل رقم الهوية" - }, - "nationalId": { - "en": "National ID", - "ar": "الهوية الوطنية" - }, - "fileNo": { - "en": "File Number", - "ar": "رقم الملف" - }, - "fileno": { - "en": "File No", - "ar": "رقم الملف" - }, - "forgotFileNo": { - "en": "Forgot file Number?", - "ar": "نسيت رقم الملف؟" - }, - "forgotFileNoTitle": { - "en": "Forgot medical file", - "ar": "نسيت الملف الطبي" - }, - "enterNationalId": { - "en": "Please enter mobile number and identification number", - "ar": "يرجى إدخال رقم الهاتف المحمول ورقم الهوية" - }, - "profileInfo": { - "en": "Please enter profile information", - "ar": "يرجى إدخال معلومات الملف الشخصي" - }, - "submit": { - "en": "Submit", - "ar": "إرسال" - }, - "forgotDesc": { - "en": "Enter the mobile number to receive the Medical File Number via SMS", - "ar": "أدخل رقم الهاتف المحمول لاستلام رقم الملف الطبي عبر الرسائل القصيرة" - }, - "dob": { - "en": "Birth Date:", - "ar": "تاريخ الميلاد:" - }, - "hijriDate": { - "en": "Hijri Date", - "ar": "التاريخ الهجري" - }, - "gregorianDate": { - "en": "Gregorian Date", - "ar": "التاريخ الميلادي" - }, - "verifyLoginWith": { - "en": "Please choose one of the following options to verify", - "ar": "يرجى اختيار واحدة من الخيارات التالية للتحقق" - }, - "registerUser": { - "en": "Register", - "ar": "تسجيل" - }, - "verifyWithFingerprint": { - "en": "Biometric", - "ar": "البيومترية" - }, - "verifyWithFaceid": { - "en": "Face ID", - "ar": "معرف الوجه" - }, - "verifyWithSms": { - "en": "SMS", - "ar": "رسالة قصيرة" - }, - "verifyWithWhatsapp": { - "en": "Whatsapp", - "ar": "واتساب" - }, - "verifyThrough": { - "en": "Verify Through", - "ar": "التحقق من خلال" - }, - "lastLogin": { - "en": "LAST LOGIN AT:", - "ar": "آخر تسجيل دخول في:" - }, - "lastLoginWith": { - "en": "VERIFICATION TYPE:", - "ar": "نوع التحقق:" - }, - "verifyFingerprint": { - "en": "To activate the fingerprint login service, please verify data by using one of the following options.", - "ar": "لتفعيل خدمة تسجيل الدخول ببصمة الإصبع، يرجى التحقق من البيانات باستخدام واحدة من الخيارات التالية." - }, - "searchMedicine": { - "en": "Search Medicine", - "ar": "ابحث عن دواء" - }, - "pharmaciesList": { - "en": "Pharmacies List", - "ar": "قائمة الصيدليات" - }, - "searchMedicineHere": { - "en": "Search Medicine Here", - "ar": "ابحث عن دواء هنا" - }, - "description": { - "en": "Description", - "ar": "الوصف" - }, - "howToUse": { - "en": "How to Use", - "ar": "كيفية الاستخدام" - }, - "price": { - "en": "Price", - "ar": "السعر" - }, - "youCanFindItIn": { - "en": "You can find it in", - "ar": "يمكنك العثور عليه في" - }, - "pleaseEnterMedicineName": { - "en": "Please Enter Medicine Name", - "ar": "يرجى إدخال اسم الدواء" - }, - "verificationMessage": { - "en": "Please enter the Verification Code sent to", - "ar": "يرجى إدخال رمز التحقق المرسل إلى" - }, - "validationMessage": { - "en": "The verification code expires in", - "ar": "ينتهي رمز التحقق في" - }, - "notification": { - "en": "Notifications", - "ar": "الإشعارات" - }, - "appSettings": { - "en": "App Settings", - "ar": "إعدادات التطبيق" - }, - "rateApp": { - "en": "Rate Our App", - "ar": "قيم تطبيقنا" - }, - "before": { - "en": "Before", - "ar": "قبل" - }, - "minute": { - "en": "Minutes", - "ar": "دقائق" - }, - "hour": { - "en": "Hour", - "ar": "ساعة" - }, - "reminderSuccess": { - "en": "The reminder has been added successfully", - "ar": "تمت إضافة التذكير بنجاح" - }, - "reminderCancelSuccess": { - "en": "The reminder has been cancelled successfully", - "ar": "تم إلغاء التذكير بنجاح" - }, - "patientShareToDo": { - "en": "Amount before tax: ", - "ar": "المبلغ قبل الضريبة: " - }, - "patientTaxToDo": { - "en": "Tax amount: ", - "ar": "قيمة الضريبة: " - }, - "patientShareTotalToDo": { - "en": "Total amount due: ", - "ar": "إجمالي المبلغ المستحق: " - }, - "paymentMethod": { - "en": "Payment Method", - "ar": "طريقة الدفع" - }, - "noNeedToWaitInLine": { - "en": "No need to stand in line.", - "ar": "لا حاجة للانتظار في الطابور." - }, - "useQRAppoAttend": { - "en": "Use the QR code to register the appointment attendance.", - "ar": "استخدم رمز الاستجابة السريعة لتسجيل حضور الموعد." - }, - "passQRAppoAttend": { - "en": "Pass the QR code through the attendance devices available in the Hospital.", - "ar": "مرر رمز الاستجابة السريعة عبر أجهزة الحضور المتاحة في المستشفى." - }, - "sitWaitingQR": { - "en": "Sit in the waiting rooms until called by the nurse.", - "ar": "اجلس في غرف الانتظار حتى يتم استدعاؤك من قبل الممرضة." - }, - "attendRegisterCode": { - "en": "Attendance registration code", - "ar": "رمز تسجيل الحضور" - }, - "scanQRHospital": { - "en": "Approach the Online Check-In board in the hospital & scan via NFC or QR Code to Check-In", - "ar": "توجّه إلى لوحة تسجيل الوصول الإلكتروني في المستشفى، وقم بالمسح عبر تقنية NFC أو رمز الاستجابة السريعة (QR) لإتمام تسجيل الوصول." - }, - "scanNFC": { - "en": "Scan NFC to Check-In", - "ar": "امسح NFC لتسجيل الوصول" - }, - "sendEmail": { - "en": "Send Email", - "ar": "إرسال بريد إلكتروني" - }, - "success": { - "en": "Done successfully", - "ar": "تم بنجاح" - }, - "emailSentSuccessfully": { - "en": "Email Sent Successfully", - "ar": "تم إرسال البريد الإلكتروني بنجاح" - }, - "emailSentError": { - "en": "Error Sending Email", - "ar": "خطأ في إرسال البريد الإلكتروني" - }, - "close": { - "en": "Close", - "ar": "إغلاق" - }, - "closeIt": { - "en": "Close", - "ar": "أغلق" - }, - "booked": { - "en": "Booked", - "ar": "محجوز" - }, - "confirmed": { - "en": "Confirmed", - "ar": "مؤكد" - }, - "arrived": { - "en": "Arrived", - "ar": "وصل" - }, - "payNowBookSuccess": { - "en": "Pay now via Al Habib App", - "ar": "ادفع الآن عبر تطبيق الحبيب" - }, - "payNowBookSuccesstext1": { - "en": "Pay Now using online payment service from secure payment gateways", - "ar": "ادفع الآن باستخدام خدمة الدفع عبر الإنترنت من بوابات الدفع الآمنة" - }, - "payNowBookSuccesstext2": { - "en": "You can also Pay Later via online payment or in Hospital", - "ar": "يمكنك أيضًا الدفع لاحقًا عبر الدفع الإلكتروني أو في المستشفى." - }, - "payLater": { - "en": "Pay Later", - "ar": "ادفع لاحقًا" - }, - "askDocNotAllowed": { - "en": "This service will be available for last 15 days’ doctor Visit only", - "ar": "هذه الخدمة ستكون متاحة فقط لزيارة الطبيب قبل 15 يومًا" - }, - "moreVerify": { - "en": "More Verification Options", - "ar": "خيارات تحقق إضافية" - }, - "welcomeBack": { - "en": "Welcome back!", - "ar": "مرحبًا بعودتك!" - }, - "accountInfo": { - "en": "Would you like to login with current username?", - "ar": "هل ترغب في تسجيل الدخول باستخدام اسم المستخدم الحالي؟" - }, - "anotherAcc": { - "en": "Use Another Account", - "ar": "استخدم حسابًا آخر" - }, - "next": { - "en": "Next", - "ar": "التالي" - }, - "firstName": { - "en": "First Name", - "ar": "الاسم الأول" - }, - "middleName": { - "en": "Middle Name", - "ar": "اسم الأب" - }, - "lastName": { - "en": "Last Name", - "ar": "اسم العائلة" - }, - "female": { - "en": "Female", - "ar": "أنثى" - }, - "male": { - "en": "Male", - "ar": "ذكر" - }, - "preferredLanguage": { - "en": "Preferred Language *", - "ar": "اللغة المفضلة *" - }, - "locationsRegister": { - "en": "Where do you want to create this file?", - "ar": "أين ترغب في إنشاء هذا الملف؟" - }, - "ksa": { - "en": "KSA", - "ar": "السعودية" - }, - "dubai": { - "en": "Dubai", - "ar": "دبي" - }, - "enterEmail": { - "en": "Please Enter Email", - "ar": "يرجى إدخال البريد الإلكتروني" - }, - "family": { - "en": "My Family", - "ar": "عائلتي" - }, - "familyTitle": { - "en": "My Family Files", - "ar": "ملفات عائلتي" - }, - "myFamily": { - "en": "MY FAMILY", - "ar": "عائلتي" - }, - "addNewMember": { - "en": "Add Family Member", - "ar": "إضافة فرد جديد للعائلة" - }, - "sentRequests": { - "en": "Sent Requests", - "ar": "الطلبات المرسلة" - }, - "recievedRequests": { - "en": "Recieved Requests", - "ar": "الطلبات المستلمة" - }, - "manageFiles": { - "en": "Manage Family Files", - "ar": "إدارة ملفات العائلة" - }, - "oxygenation": { - "en": "Oxygenation", - "ar": "تشبع الأكسجين" - }, - "bodyMeasurements": { - "en": "body Mass Index", - "ar": "مؤشر كتلة الجسم" - }, - "temperature": { - "en": "Temperature", - "ar": "درجة الحرارة" - }, - "pulse": { - "en": "Pulse", - "ar": "النبض" - }, - "respiration": { - "en": "Respiration", - "ar": "التنفس" - }, - "bloodPressure": { - "en": "Blood Pressure", - "ar": "ضغط الدم" - }, - "painScale": { - "en": "Pain Scale", - "ar": "مقياس الألم" - }, - "weight": { - "en": "Weight", - "ar": "الوزن" - }, - "height": { - "en": "Height", - "ar": "الطول" - }, - "heart": { - "en": "Heart Rate", - "ar": "معدل ضربات القلب" - }, - "heightUnit": { - "en": "height unit", - "ar": "وحدة الطول" - }, - "weightUnit": { - "en": "Weight Unit", - "ar": "وحدة الوزن" - }, - "unit": { - "en": "Unit", - "ar": "الوحدة" - }, - "request": { - "en": "Request", - "ar": "طلب" - }, - "memberName": { - "en": "Member Name", - "ar": "اسم العضو" - }, - "switchLogin": { - "en": "Switch", - "ar": "تبديل" - }, - "removeMember": { - "en": "Remove", - "ar": "إزالة" - }, - "allowView": { - "en": "Allow", - "ar": "السماح" - }, - "rejectView": { - "en": "Reject", - "ar": "رفض" - }, - "deleteView": { - "en": "Delete", - "ar": "حذف" - }, - "approvals": { - "en": "Approvals", - "ar": "الموافقات" - }, - "approvalNo": { - "en": "Approval No:", - "ar": "رقم الموافقة:" - }, - "companyName": { - "en": "Company Name:", - "ar": "اسم الشركة:" - }, - "receiptOn": { - "en": "Receipt on:", - "ar": "الإيصال على:" - }, - "expiryDate": { - "en": "Expiry Date:", - "ar": "تاريخ الانتهاء:" - }, - "expiryPoints": { - "en": "Expired", - "ar": "منتهي الصلاحية" - }, - "expiryOn": { - "en": "Expiry on:", - "ar": "ينتهي في:" - }, - "procedureName": { - "en": "Procedure Name:", - "ar": "اسم الإجراء:" - }, - "procedure": { - "en": "Procedure", - "ar": "الإجراء" - }, - "procedureStatus": { - "en": "Procedure Status: ", - "ar": "حالة الإجراء: " - }, - "usageStatus": { - "en": "Usage Status", - "ar": "حالة الاستخدام" - }, - "unusedCount": { - "en": "Unused Count:", - "ar": "عدد غير المستخدم:" - }, - "totalApproval": { - "en": "Total approval unused", - "ar": "إجمالي الموافقة غير المستخدمة" - }, - "category": { - "en": "Category: ", - "ar": "الفئة: " - }, - "expirationDate": { - "en": "Expiration Date: ", - "ar": "تاريخ انتهاء الصلاحية: " - }, - "patientCard": { - "en": "Patient Card ID: ", - "ar": "رقم بطاقة المريض: " - }, - "policyNumber": { - "en": "Policy Number: ", - "ar": "رقم الوثيقة: " - }, - "seeDetails": { - "en": "SEE DETAILS", - "ar": "عرض التفاصيل" - }, - "insuranceCards": { - "en": "Insurance Cards", - "ar": "بطاقات التأمين" - }, - "requestType": { - "en": "Request Type", - "ar": "نوع الطلب" - }, - "registerInfoFamily": { - "en": "How would like to add the new member?", - "ar": "كيف تود إضافة عضو جديد؟" - }, - "removeFamilyMember": { - "en": "Remove this member?", - "ar": "هل تريد إزالة هذا العضو؟" - }, - "myMedicalFile": { - "en": "My Medical File", - "ar": "ملفي الطبي" - }, - "myMedicalFileSubTitle": { - "en": "All your medical records", - "ar": "جميع سجلاتك الطبية" - }, - "viewMore": { - "en": "View More", - "ar": "عرض المزيد" - }, - "homeHealthCareService": { - "en": "Home Health Care Service", - "ar": "خدمة الرعاية الصحية المنزلية" - }, - "onlinePharmacy": { - "en": "Online Pharmacy", - "ar": "الصيدلية الإلكترونية" - }, - "emergencyService": { - "en": "Emergency Service", - "ar": "خدمة الطوارئ" - }, - "onlinePaymentService": { - "en": "Online Payment Service", - "ar": "خدمة الدفع عبر الإنترنت" - }, - "offersAndPackages": { - "en": "Online transfer request", - "ar": "طلب تحويل عبر الإنترنت" - }, - "comprehensiveMedicalCheckup": { - "en": "Comprehensive Medical Check-up", - "ar": "فحص طبي شامل" - }, - "hmgService": { - "en": "HMG Service", - "ar": "خدمة HMG" - }, - "viewAllHabibMedicalService": { - "en": "View All Habib Medical Service", - "ar": "عرض جميع خدمات الحبيب الطبية" - }, - "viewAll": { - "en": "View All", - "ar": "عرض الكل" - }, - "view": { - "en": "View", - "ar": "عرض" - }, - "contactUs": { - "en": "Contact Us", - "ar": "اتصل بنا" - }, - "contactUsLocation": { - "en": "P.O.Box: 91877 - Riyadh 11643, King Fahad Road - Olaya - Kingdom of Saudi Arabia", - "ar": "ص.ب: 91877 - الرياض 11643، طريق الملك فهد - العليا - المملكة العربية السعودية" - }, - "contactUsTime": { - "en": "Saturday - Wednesday 8:00 AM - 10 PM, Thursday 8:00 AM- 8:00 PM, Friday 2:00 PM - 8:00 PM", - "ar": "السبت - الأربعاء 8:00 صباحًا - 10 مساءً، الخميس 8:00 صباحًا- 8:00 مساءً، الجمعة 2:00 مساءً - 8:00 مساءً" - }, - "viewAllWaysReachUs": { - "en": "View All Ways Reach Us", - "ar": "عرض جميع طرق التواصل معنا" - }, - "medicalProfile": { - "en": "Medical Profile", - "ar": "الملف الطبي" - }, - "consultation": { - "en": "Consultation", - "ar": "استشارة" - }, - "logs": { - "en": "Logs", - "ar": "السجلات" - }, - "textToSpeech": { - "en": "How May I Help You?", - "ar": "كيف يمكنني مساعدتك؟" - }, - "locationDialogMessage": { - "en": "Allow the HMG app to access your location will assist you in showing the hospitals according to the nearest to you.", - "ar": "السماح لتطبيق HMG بالوصول إلى موقعك سيساعدك في عرض المستشفيات الأقرب إليك." - }, - "userViewRequester": { - "en": "User Wants to View Your Medical File", - "ar": "يريد المستخدم عرض ملفك الطبي" - }, - "userView": { - "en": "User Can View Your Medical File", - "ar": "يمكن للمستخدم عرض ملفك الطبي" - }, - "parking": { - "en": "Parking", - "ar": "موقف السيارات" - }, - "alhabiServices": { - "en": "HMG Service", - "ar": "خدمة HMG" - }, - "parkingTitle": { - "en": "Car service, car service, service to save parking information, return to it later, 1- By clicking on (Read the code), save the parking data. 2- By clicking on the button (view my car park), it shows you the car’s location in Google Maps. 3- Read another position by pressing the Clear Position Data button.", - "ar": "خدمة السيارة، خدمة السيارة، خدمة لحفظ معلومات الموقف، العودة إليها لاحقًا، 1- من خلال النقر على (قراءة الرمز)، حفظ بيانات الموقف. 2- من خلال النقر على زر (عرض موقف سيارتي)، يظهر لك موقع السيارة في خرائط Google. 3- قراءة موضع آخر بالضغط على زر مسح بيانات الموضع." - }, - "parkingDescription": { - "en": "Parking service is for you to scan the car location so you can find it easy on you way out. click on (scan parking) button to save the parking location, then (show my park) button will appear to show you the way for the parking. if you want to rescan parking QR just click on (Clear My Data).", - "ar": "خدمة المواقف هي لك لمسح موقع السيارة حتى تتمكن من العثور عليها بسهولة عند مغادرتك. انقر على زر (مسح الموقف) لحفظ موقع الموقف، ثم سيظهر زر (عرض موقفي) لإظهار الطريق إلى الموقف. إذا كنت ترغب في إعادة مسح موقف السيارة QR فقط انقر على (مسح بياناتي)." - }, - "appointments": { - "en": "Appointments", - "ar": "المواعيد" - }, - "all2": { - "en": "All", - "ar": "الكل" - }, - "checkinOption": { - "en": "Check-In", - "ar": "تسجيل الوصول" - }, - "readBarcode": { - "en": "Read Barcode", - "ar": "قراءة الكود" - }, - "showMyPark": { - "en": "Show My Park", - "ar": "عرض الموقف" - }, - "clearMyData": { - "en": "Clear My Data", - "ar": "امسح البيانات" - }, - "floor": { - "en": "Floor:", - "ar": "الطابق:" - }, - "gate": { - "en": "Gate:", - "ar": "البوابة:" - }, - "building": { - "en": "Building:", - "ar": "المبنى:" - }, - "branch": { - "en": "Branch:", - "ar": "الفرع:" - }, - "emergencyServices": { - "en": "Emergency Services", - "ar": "خدمات الطوارئ" - }, - "nearester": { - "en": "Nearest ER", - "ar": "أقرب طوارئ" - }, - "locationa": { - "en": "Location", - "ar": "الموقع" - }, - "callNow": { - "en": "Call now", - "ar": "اتصل الآن" - }, - "ambulancerequest": { - "en": "Ambulance", - "ar": "طلب إسعاف" - }, - "requestA": { - "en": "Request", - "ar": "طلب" - }, - "noBookedAppointments": { - "en": "No Booked Appointments", - "ar": "لا توجد مواعيد محجوزة" - }, - "noConfirmedAppointments": { - "en": "No Confirmed Appointments", - "ar": "لا توجد مواعيد مؤكدة" - }, - "noArrivedAppointments": { - "en": "No Arrived Appointments", - "ar": "لا توجد مواعيد تم تسجيل الوصول إليها" - }, - "myAppointmentsList": { - "en": "Appointments", - "ar": "المواعيد" - }, - "myAppointments": { - "en": "My", - "ar": "مواعيدي" - }, - "radiology": { - "en": "Radiology", - "ar": "الأشعة" - }, - "radiologySubtitle": { - "en": "Result", - "ar": "النتيجة" - }, - "lab": { - "en": "Lab", - "ar": "المختبر" - }, - "labSubtitle": { - "en": "Results", - "ar": "النتائج" - }, - "medicines": { - "en": "Medicines", - "ar": "الأدوية" - }, - "medicinesSubtitle": { - "en": "Prescriptions", - "ar": "الوصفات" - }, - "vitalSigns": { - "en": "Vital Signs", - "ar": "علامات حيوية" - }, - "vitalSignsSubTitle": { - "en": "Reports", - "ar": "التقارير" - }, - "myMedical": { - "en": "Active", - "ar": "نشط" - }, - "myMedicalSubtitle": { - "en": "Medications", - "ar": "الأدوية" - }, - "myDoctor": { - "en": "My Doctor", - "ar": "طبيبي" - }, - "myDoctorSubtitle": { - "en": "List", - "ar": "القائمة" - }, - "eye": { - "en": "Eye", - "ar": "العين" - }, - "eyeSubtitle": { - "en": "Measurement", - "ar": "القياس" - }, - "insurance": { - "en": "Insurance", - "ar": "التأمين" - }, - "insuranceSubtitle": { - "en": "Card", - "ar": "البطاقة" - }, - "updateInsurance": { - "en": "Update", - "ar": "تحديث" - }, - "updateInsuranceSubtitle": { - "en": "Insurance", - "ar": "التأمين" - }, - "insuranceApproval": { - "en": "Insurance", - "ar": "التأمين" - }, - "insuranceApprovalSubtitle": { - "en": "Approvals", - "ar": "الموافقات" - }, - "allergies": { - "en": "Allergies", - "ar": "الحساسية" - }, - "allergiesSubtitle": { - "en": "List", - "ar": "القائمة" - }, - "myVaccines": { - "en": "My Vaccines", - "ar": "لقاحاتي" - }, - "myVaccinesSubtitle": { - "en": "List", - "ar": "القائمة" - }, - "medical": { - "en": "Medical", - "ar": "طبي" - }, - "medicalSubtitle": { - "en": "Report", - "ar": "التقرير" - }, - "monthly": { - "en": "Monthly", - "ar": "شهري" - }, - "monthlySubtitle": { - "en": "Report", - "ar": "التقرير" - }, - "sick": { - "en": "Sick", - "ar": "مريض" - }, - "sickSubtitle": { - "en": "Leaves", - "ar": "الإجازات" - }, - "myBalance": { - "en": "My Balance", - "ar": "رصيدي" - }, - "myBalanceSubtitle": { - "en": "Credit", - "ar": "الرصيد" - }, - "patientCall": { - "en": "Patient Call", - "ar": "مكالمة المريض" - }, - "patientCallSubtitle": { - "en": "Service", - "ar": "الخدمة" - }, - "smartWatches": { - "en": "Smart Watches", - "ar": "الساعات الذكية" - }, - "smartWatchesSubtitle": { - "en": "Pairing", - "ar": "الاقتران" - }, - "myTrackers": { - "en": "My Trackers", - "ar": "متعقباتي" - }, - "myTrackersSubtitle": { - "en": "Service", - "ar": "الخدمة" - }, - "askYour": { - "en": "Ask Your", - "ar": "اسأل" - }, - "askYourSubtitle": { - "en": "Doctor", - "ar": "طبيبك" - }, - "internet": { - "en": "Internet", - "ar": "الإنترنت" - }, - "internetSubtitle": { - "en": "Pairing", - "ar": "الاقتران" - }, - "chatbot": { - "en": "Chatbot", - "ar": "الدردشة الآلية" - }, - "chatbotSubtitle": { - "en": "", - "ar": "" - }, - "timeLine": { - "en": "Timeline", - "ar": "الخط الزمني" - }, - "labOrders": { - "en": "Lab Orders", - "ar": "طلبات المختبر" - }, - "billNo": { - "en": "Bill No:", - "ar": "رقم الفاتورة:" - }, - "prescriptions": { - "en": "Prescriptions", - "ar": "الوصفات" - }, - "history": { - "en": "History", - "ar": "التاريخ" - }, - "orderNo": { - "en": "Order No", - "ar": "رقم الطلب" - }, - "orderDetails": { - "en": "Order Details", - "ar": "تفاصيل الطلب" - }, - "deliveryDriverTrack": { - "en": "Driver Tracking", - "ar": "تتبع السائق" - }, - "deliveryLocation": { - "en": "Delivery Location", - "ar": "موقع التسليم" - }, - "driver": { - "en": "Driver", - "ar": "السائق" - }, - "vitalSign": { - "en": "Vital Sign", - "ar": "علامة حيوية" - }, - "monthlyReports": { - "en": "Monthly Reports", - "ar": "تقارير شهرية" - }, - "km": { - "en": "KMs:", - "ar": "كم:" - }, - "km_": { - "en": "KM", - "ar": "كم" - }, - "patientHealthSummaryReport": { - "en": "Patient Health Summary Report", - "ar": "تقرير ملخص صحة المريض" - }, - "toViewTheTermsAndConditions": { - "en": "To View the Terms and Conditions Report", - "ar": "لعرض الشروط والأحكام" - }, - "clickHere": { - "en": "Click here", - "ar": "انقر هنا" - }, - "iAgreeToTheTermsAndConditions": { - "en": "I agree to the terms and conditions ", - "ar": "أوافق على الشروط والأحكام " - }, - "iAgreeToTheTermsAndConditionsSubtitle": { - "en": "I agree to the terms and conditions ", - "ar": "أوافق على الشروط والأحكام " - }, - "save": { - "en": "Save", - "ar": "حفظ" - }, - "userAgreement": { - "en": "User Agreement", - "ar": "اتفاقية المستخدم" - }, - "updateSuccessfully": { - "en": "Update Successfully", - "ar": "تم التحديث بنجاح" - }, - "checkVaccineAvailability": { - "en": "CHECK VACCINE AVAILABILITY", - "ar": "تحقق من توفر اللقاح" - }, - "myVaccinesAvailability": { - "en": "My Vaccines Availability", - "ar": "توفر اللقاحات الخاصة بي" - }, - "paymentService": { - "en": "Payment Service", - "ar": "خدمة الدفع" - }, - "paymentOnline": { - "en": "Service", - "ar": "الخدمة" - }, - "onlineCheckIn": { - "en": "Online Check-In", - "ar": "تسجيل الوصول عبر الإنترنت" - }, - "myBalances": { - "en": "My Balances", - "ar": "رصيدي" - }, - "myWallet": { - "en": "My Wallet", - "ar": "محفظتي" - }, - "balanceAmount": { - "en": "Wallet Amount", - "ar": "مبلغ المحفظة" - }, - "totalBalance": { - "en": "Total Balance", - "ar": "إجمالي الرصيد" - }, - "createAdvancedPayment": { - "en": "Recharge Wallet", - "ar": "إعادة شحن المحفظة" - }, - "advancePayment": { - "en": "Advance Payment", - "ar": "دفع مسبق" - }, - "advancePaymentLabel": { - "en": "You can create and add an Advanced Payment for your account or other accounts.", - "ar": "يمكنك إنشاء وإضافة دفعة مقدمة لحسابك أو حسابات أخرى." - }, - "fileNumber": { - "en": "File Number", - "ar": "رقم الملف" - }, - "amount": { - "en": "Amount *", - "ar": "المبلغ *" - }, - "depositorEmail": { - "en": "Depositor Email *", - "ar": "البريد الإلكتروني للودائع *" - }, - "notes": { - "en": "Notes", - "ar": "ملاحظات" - }, - "selectPatientName": { - "en": "Select Patient Name", - "ar": "اختر اسم المريض" - }, - "selectFamilyPatientName": { - "en": "Family Members", - "ar": "أفراد العائلة" - }, - "selectHospital": { - "en": "Select Hospital", - "ar": "اختر المستشفى" - }, - "selectCity": { - "en": "Select City", - "ar": "اختر المدينة" - }, - "city": { - "en": "City", - "ar": "المدينة" - }, - "distance": { - "en": "Distance", - "ar": "المسافة" - }, - "myAccount": { - "en": "My Account", - "ar": "حسابي" - }, - "otherAccount": { - "en": "Other Account", - "ar": "حساب آخر" - }, - "selectBeneficiary": { - "en": "Select Beneficiary", - "ar": "اختر المستفيد" - }, - "confirmThePayment": { - "en": "Confirm The Payment", - "ar": "تأكيد الدفع" - }, - "depositorName": { - "en": "Depositor Name", - "ar": "اسم مُقدِّم الإيداع" - }, - "mobileNumber": { - "en": "Mobile Number", - "ar": "رقم الجوال" - }, - "phoneNumber": { - "en": "Phone Number", - "ar": "رقم الهاتف" - }, - "country": { - "en": "Country", - "ar": "البلد" - }, - "ok": { - "en": "Ok", - "ar": "حسنا" - }, - "averageWaitingTime": { - "en": "Average Waiting Time:", - "ar": "متوسط وقت الانتظار:" - }, - "waitingTime": { - "en": "Expected waiting time:", - "ar": "وقت الانتظار المتوقع:" - }, - "waterConsumedInWeek": { - "en": "Water consumed in a week", - "ar": "الماء المستهلك في أسبوع" - }, - "waterConsumedInMonth": { - "en": "Water consumed in a month", - "ar": "الماء المستهلك في شهر" - }, - "theVerificationCodeExpiresIn": { - "en": "The Verification Code Expires in", - "ar": "ينتهي رمز التحقق في" - }, - "pleaseEnterTheVerificationCode": { - "en": "Please enter the verification code send to", - "ar": "يرجى إدخال رمز التحقق المرسل إلى" - }, - "eyeMeasurements": { - "en": "Eye Measurements", - "ar": "قياسات العين" - }, - "measurements": { - "en": "Measurements", - "ar": "قياسات" - }, - "classes": { - "en": "Glasses", - "ar": "نظارات" - }, - "contactLens": { - "en": "Contact Lens", - "ar": "عدسات لاصقة" - }, - "rightEye": { - "en": "Right Eye", - "ar": "العين اليمنى" - }, - "sphere": { - "en": "Sphere", - "ar": "الكرة" - }, - "cylinder": { - "en": "Cylinder", - "ar": "الأسطوانة" - }, - "axis": { - "en": "Axis", - "ar": "المحور" - }, - "prism": { - "en": "Prism", - "ar": "الهرم" - }, - "va": { - "en": "VA", - "ar": "VA" - }, - "leftEye": { - "en": "Left Eye", - "ar": "العين اليسرى" - }, - "brand": { - "en": "Brand", - "ar": "العلامة التجارية" - }, - "power": { - "en": "Power", - "ar": "القوة" - }, - "diameter": { - "en": "Diameter", - "ar": "القطر" - }, - "remarks": { - "en": "", - "ar": "ملاحظات: " - }, - "activeMedications": { - "en": "Active Medications", - "ar": "الأدوية النشطة" - }, - "expDate": { - "en": "Active Exp Date :", - "ar": "تاريخ انتهاء الصلاحية:" - }, - "route": { - "en": "", - "ar": "الطريق" - }, - "frequency": { - "en": "", - "ar": "التكرار" - }, - "dailyQuantity": { - "en": "Daily Quantity :", - "ar": "الكمية اليومية:" - }, - "addReminder": { - "en": "Add Reminder", - "ar": "إضافة تذكير" - }, - "cancelReminder": { - "en": "Cancel Reminder", - "ar": "إلغاء التذكير" - }, - "reminderDes": { - "en": "Please select treatment start day and time to be notified when it's time to take the medicine", - "ar": "يرجى تحديد يوم ووقت بدء العلاج ليتم إعلامك عندما يحين وقت تناول الدواء" - }, - "pleaseSelectAllQuestionToContinue": { - "en": "Please answer all questions to continue...", - "ar": "يرجى الإجابة على جميع الأسئلة للمتابعة..." - }, - "startDay": { - "en": "Start Day", - "ar": "يوم البدء" - }, - "endDay": { - "en": "End Day", - "ar": "يوم الانتهاء" - }, - "days": { - "en": "Days ", - "ar": "أيام " - }, - "pleaseVerify": { - "en": "Please Verify ", - "ar": "يرجى التحقق " - }, - "scheduleTime": { - "en": "Schedule time", - "ar": "وقت الجدولة" - }, - "askDoctor": { - "en": "Ask Doctor", - "ar": "اسأل الطبيب" - }, - "doctorResponses": { - "en": "Doctor Responses", - "ar": "ردود الطبيب" - }, - "ne_w": { - "en": "New", - "ar": "جديد" - }, - "all": { - "en": "All", - "ar": "الكل" - }, - "dailyWater": { - "en": "Daily Water Check", - "ar": "متابعة الماء اليومية" - }, - "questionHere": { - "en": "Enter the question here...", - "ar": "أدخل السؤال هنا..." - }, - "viewDoctorResponses": { - "en": "View Doctor Responses", - "ar": "عرض ردود الطبيب" - }, - "serviceInformationButton": { - "en": "LOGIN / REGISTER", - "ar": "تسجيل الدخول / التسجيل" - }, - "serviceInformationTitle": { - "en": "Service Information", - "ar": "معلومات الخدمة" - }, - "serviceInformation": { - "en": "Service Information", - "ar": "معلومات الخدمة" - }, - "homeHealthCare": { - "en": "Home Health Care", - "ar": "الرعاية الصحية المنزلية" - }, - "noAppointmentAvailable": { - "en": "No Available Appointments", - "ar": "لا توجد مواعيد متاحة" - }, - "homeHealthCareText": { - "en": "This service provides a set of home health care services, continuous and comprehensive follow-up in their places of residence for those who cannot access health facilities, such as (laboratory analyzes - radiology - vaccinations - physical therapy), etc.", - "ar": "تقدم هذه الخدمة مجموعة من خدمات الرعاية الصحية المنزلية، والمتابعة المستمرة والشاملة في أماكن إقامتهم لأولئك الذين لا يمكنهم الوصول إلى المرافق الصحية، مثل (تحليلات المختبر - الأشعة - التطعيمات - العلاج الطبيعي)، إلخ." - }, - "loginRegister": { - "en": "Login/Register", - "ar": "تسجيل الدخول / التسجيل" - }, - "orderLog": { - "en": "Order Log", - "ar": "سجل الطلب" - }, - "infoLab": { - "en": "This service allows you to view the results of all laboratory tests performed in Al Habib Medical Group as well as sending the report via e-mail.", - "ar": "تتيح لك هذه الخدمة عرض نتائج جميع الفحوصات المخبرية التي أجريت في مجموعة الحبيب الطبية بالإضافة إلى إرسال التقرير عبر البريد الإلكتروني." - }, - "infoRadiology": { - "en": "This service allows you to view the reports and photos of radiology in Al Habib Medical Group as well as send the report by e-mail.", - "ar": "تتيح لك هذه الخدمة عرض تقارير وصور الأشعة في مجموعة الحبيب الطبية بالإضافة إلى إرسال التقرير عبر البريد الإلكتروني." - }, - "noReviewsAvailable": { - "en": "No Reviews Available", - "ar": "لا توجد تقييمات متاحة" - }, - "noLocationAvailable": { - "en": "No Location Available", - "ar": "لا توجد مواقع متاحة" - }, - "orders": { - "en": "Orders", - "ar": "الطلبات" - }, - "lakum": { - "en": "", - "ar": "لكم" - }, - "lakumMsg": { - "en": "", - "ar": "لا توجد تفاصيل عن النقاط" - }, - "lakumPoint": { - "en": "Lakum Points", - "ar": "نقاط لكم" - }, - "wishlist": { - "en": "Wishlist", - "ar": "قائمة الرغبات" - }, - "products": { - "en": "Products", - "ar": "المنتجات" - }, - "reviews": { - "en": "Reviews", - "ar": "التقييمات" - }, - "brands": { - "en": "Brands", - "ar": "العلامات التجارية" - }, - "productDetails": { - "en": "Product Details", - "ar": "تفاصيل المنتج" - }, - "medicationRefill": { - "en": "Medication Refill", - "ar": "إعادة تعبئة الدواء" - }, - "pillReminder": { - "en": "Pill Reminder", - "ar": "تذكير بالدواء" - }, - "shippingAddresses": { - "en": "Shipping Addresses", - "ar": "عناوين الشحن" - }, - "reachUs": { - "en": "Reach Us", - "ar": "تواصل معنا" - }, - "ourLocations": { - "en": "Our Locations", - "ar": "مواقعنا" - }, - "edit": { - "en": "Edit", - "ar": "تعديل" - }, - "whatsApp": { - "en": "Whats App", - "ar": "واتساب" - }, - "phone": { - "en": "Phone", - "ar": "الهاتف" - }, - "delete": { - "en": "Delete", - "ar": "حذف" - }, - "deleteAddress": { - "en": "Are you sure want to delete", - "ar": "هل أنت متأكد أنك تريد الحذف" - }, - "deletedAddres": { - "en": "Address has been deleted", - "ar": "تم حذف العنوان" - }, - "addAddress": { - "en": "ADD A NEW ADDRESS", - "ar": "إضافة عنوان جديد" - }, - "addNewAddress": { - "en": "Add New Address", - "ar": "إضافة عنوان جديد" - }, - "order": { - "en": "My Order", - "ar": "طلبي" - }, - "delivered": { - "en": "Delivered", - "ar": "تم التوصيل" - }, - "pending": { - "en": "Pending", - "ar": "قيد الانتظار" - }, - "enterNameHere": { - "en": "Enter Your Name", - "ar": "أدخل اسمك هنا" - }, - "processing": { - "en": "Processing", - "ar": "جاري المعالجة" - }, - "cancelled": { - "en": "Cancelled", - "ar": "ملغى" - }, - "writeReview": { - "en": "Write Review", - "ar": "اكتب تقييمًا" - }, - "shareReview": { - "en": "SHARE REVIEW", - "ar": "شارك التقييم" - }, - "review": { - "en": " reviews", - "ar": " التقييمات" - }, - "viewMedicalFile": { - "en": "View Details", - "ar": "عرض التفاصيل" - }, - "viewAllServices": { - "en": "View All Services", - "ar": "عرض جميع الخدمات" - }, - "medicalFile": { - "en": "Medical File", - "ar": "الملف الطبي" - }, - "verified": { - "en": "Verified", - "ar": "تم التحقق" - }, - "checkup": { - "en": "Checkup", - "ar": "فحص" - }, - "hhcHome": { - "en": "Home", - "ar": "الرئيسية" - }, - "refferal": { - "en": "E-Refferal", - "ar": "إحالة إلكترونية" - }, - "refferalTitle": { - "en": "E-Refferal", - "ar": "إحالة إلكترونية" - }, - "refferalSubTitle": { - "en": "Service", - "ar": "الخدمة" - }, - "healthCare": { - "en": "Health Care", - "ar": "الرعاية الصحية" - }, - "emergency": { - "en": "Emergency", - "ar": "حالة طوارئ" - }, - "erservices": { - "en": "Emergency", - "ar": "خدمات الطوارئ" - }, - "services2": { - "en": "Services", - "ar": "الخدمات" - }, - "cantSeeProfile": { - "en": "To view your medical profile, please log in or register now", - "ar": "لرؤية ملفك الطبي، يرجى تسجيل الدخول أو التسجيل الآن" - }, - "loginRegisterNow": { - "en": "Login or Register Now", - "ar": "تسجيل الدخول أو التسجيل الآن" - }, - "hmgPharmacy": { - "en": "HMG Pharmacy", - "ar": "صيدلية مجموعة الحبيب الطبية" - }, - "ecommerceSolution": { - "en": "Ecommerce Solution", - "ar": "حلول التجارة الإلكترونية" - }, - "comprehensive": { - "en": "Comprehensive", - "ar": "شامل" - }, - "onlineConsulting": { - "en": "Online Consulting", - "ar": "استشارات عبر الإنترنت" - }, - "pendingOrder": { - "en": " PENDING", - "ar": " قيد الانتظار" - }, - "deliveredOrder": { - "en": " DELIVERED", - "ar": " تم التوصيل" - }, - "processingOrder": { - "en": " PROCESSING", - "ar": " جارٍ المعالجة" - }, - "cancelledOrder": { - "en": " CANCELLED", - "ar": " ملغى" - }, - "compare": { - "en": " Compare", - "ar": " قارن" - }, - "medicationsRefill": { - "en": " Medication Refill", - "ar": " إعادة تعبئة الأدوية" - }, - "recommended": { - "en": " Recommended for You", - "ar": " موصى به لك" - }, - "myPrescription": { - "en": " My Prescriptions", - "ar": " وصفتي" - }, - "quantity": { - "en": " QTY ", - "ar": " الكمية " - }, - "reviewAppointment": { - "en": " Review Appointment ", - "ar": " مراجعة الموعد " - }, - "backMyAccount": { - "en": "BACK TO MY ACCOUNT ", - "ar": "العودة إلى حسابي " - }, - "reviewSuccessful": { - "en": "Review Successful", - "ar": "تمت مراجعة الطلب بنجاح" - }, - "reviewShared": { - "en": "Your review has been shared on product review section", - "ar": "تمت مشاركة تقييمك في قسم تقييم المنتج" - }, - "reviewComment": { - "en": "Your reviews help other to choose better product", - "ar": "تساعد تقييماتك الآخرين على اختيار منتج أفضل" - }, - "shippedMethod": { - "en": "SHIP BY:", - "ar": "الشحن بواسطة:" - }, - "orderDetail": { - "en": "Order Details", - "ar": "تفاصيل الطلب" - }, - "orderSummary": { - "en": "Order Summary", - "ar": "ملخص الطلب" - }, - "subtotal": { - "en": "Subtotal", - "ar": "المجموع الفرعي" - }, - "shipping": { - "en": "Shipping", - "ar": "الشحن" - }, - "shipBy": { - "en": "SHIP BY:", - "ar": "الشحن بواسطة:" - }, - "lakumPoints": { - "en": "Lakum Points", - "ar": "نقاط لكم" - }, - "useLakumPoints": { - "en": "Use Lakum points", - "ar": "استخدم نقاط لكم" - }, - "use": { - "en": "USE", - "ar": "استخدم" - }, - "proceedPay": { - "en": "PROCEED TO PAY", - "ar": "المتابعة للدفع" - }, - "vat": { - "en": "VAT (15%)", - "ar": "ضريبة القيمة المضافة (15%)" - }, - "inclusiveVat": { - "en": "(inclusive VAT)", - "ar": "(شاملة ضريبة القيمة المضافة)" - }, - "items": { - "en": "item(s)", - "ar": "عنصر(عناصر)" - }, - "checkOut": { - "en": "CHECK OUT", - "ar": "الدفع" - }, - "sar": { - "en": "SAR", - "ar": "ريال سعودي" - }, - "aed": { - "en": "AED", - "ar": "درهم إماراتي" - }, - "payOnline": { - "en": "PAY ONLINE", - "ar": "الدفع عبر الإنترنت" - }, - "cancelOrder": { - "en": "CANCEL ORDER", - "ar": "إلغاء الطلب" - }, - "confirmAddress": { - "en": "CONFIRM ADDRESS ", - "ar": "تأكيد العنوان " - }, - "confirmLocation": { - "en": "CONFIRM LOCATION ", - "ar": "أكد الموقع " - }, - "conditionsHMG": { - "en": "Terms & Conditions ", - "ar": "الشروط والأحكام " - }, - "conditions": { - "en": "Terms & Conditions of Lakum", - "ar": "الشروط والأحكام لكوم" - }, - "confirmDeleteMsg": { - "en": "Are you sure! want to delete ", - "ar": "هل أنت متأكد! تريد الحذف " - }, - "confirmDelete": { - "en": "DELETE", - "ar": "حذف" - }, - "confirmCancellation": { - "en": "Are you sure! want to cancel this order ", - "ar": "هل أنت متأكد! تريد إلغاء هذا الطلب " - }, - "orderNumber": { - "en": "Order#: ", - "ar": "رقم الطلب: " - }, - "orderDate": { - "en": "Date", - "ar": "التاريخ" - }, - "itemsNo": { - "en": "items(s)", - "ar": "عنصر(عناصر)" - }, - "noOrder": { - "en": "You Don't have any orders.", - "ar": "ليس لديك أي طلبات." - }, - "noResult": { - "en": "No Result.", - "ar": "لا توجد نتيجة." - }, - "nonRecommended": { - "en": "No Recommended Products.", - "ar": "لا توجد منتجات موصى بها." - }, - "termsService": { - "en": "Terms of Service", - "ar": "شروط الخدمة" - }, - "beforeusing": { - "en": "Before using the checkup, please read Terms of Service.", - "ar": "قبل استخدام الفحص، يرجى قراءة شروط الخدمة." - }, - "accept": { - "en": "I read and accept Terms of Service and Privacy Policy", - "ar": "أقرأ وأقبل شروط الخدمة وسياسة الخصوصية" - }, - "dataSafeInfo": { - "en": "Information that you provide is anonymous and not shared with anyone.", - "ar": "المعلومات التي تقدمها مجهولة الهوية وليست مشتركة مع أي شخص." - }, - "dataSafe": { - "en": " Your data is safe.", - "ar": " بياناتك آمنة." - }, - "informational": { - "en": "Checkup is for informational purposes and is not a qualified medical opinion", - "ar": "الفحص لأغراض معلوماتية وليس رأيًا طبيًا مؤهلاً" - }, - "notUseInEmerbency": { - "en": "Do not use in emergencies.", - "ar": "لا تستخدم في حالات الطوارئ." - }, - "notUseInEmerbencyDetails": { - "en": "In case of health emergency, ", - "ar": "في حالة الطوارئ الصحية، " - }, - "notUseInEmerbencyDetailsCall": { - "en": "call the nearest emergency number immediately", - "ar": "اتصل بأقرب رقم طوارئ على الفور" - }, - "checkDiagnosis": { - "en": "Checkup is not a diagnosis.", - "ar": "الفحص ليس تشخيصًا." - }, - "remeberthat": { - "en": "Remember that", - "ar": "تذكر أن" - }, - "loginToUseService": { - "en": "You need to login to use this service", - "ar": "تحتاج إلى تسجيل الدخول لاستخدام هذه الخدمة" - }, - "offersAndPromotions": { - "en": "OFFERS & SPECIAL PROMOTIONS", - "ar": "عروض وترويجيات خاصة" - }, - "offers": { - "en": "OFFERS", - "ar": "عروض" - }, - "myPrescriptions": { - "en": "MY PRESCRIPTIONS", - "ar": "وصفاتي" - }, - "searchAndScanMedication": { - "en": "SEARCH & SCAN FOR MEDICATION", - "ar": "البحث والمسح الضوئي للدواء" - }, - "shopByBrands": { - "en": "Shop by Brands", - "ar": "تسوق حسب العلامات التجارية" - }, - "recentlyViewed": { - "en": "Recently Viewed", - "ar": "تمت مشاهدته مؤخرًا" - }, - "bestSellers": { - "en": "Best Seller", - "ar": "الأكثر مبيعًا" - }, - "deleteAllItems": { - "en": "Delete All Items", - "ar": "حذف جميع العناصر" - }, - "total": { - "en": "Total", - "ar": "الإجمالي" - }, - "totalWithColonRight": { - "en": "Total:", - "ar": "الإجمالي:" - }, - "selectAddress": { - "en": "Select Address", - "ar": "اختر العنوان" - }, - "shippingAddress": { - "en": "SHIPPING ADDRESS", - "ar": "عنوان الشحن" - }, - "changeAddress": { - "en": "Change Address", - "ar": "تغيير العنوان" - }, - "selectPaymentOption": { - "en": "Select Payment Option", - "ar": "اختر طريقة الدفع" - }, - "selectTamaraPlan": { - "en": "Select Tamara Payment Plan", - "ar": "اختر خطة دفع تمارا" - }, - "changeMethod": { - "en": "Change Method", - "ar": "تغيير الطريقة" - }, - "reviewOrder": { - "en": "Review Order", - "ar": "مراجعة الطلب" - }, - "active": { - "en": "Active", - "ar": "نشط" - }, - "inactive": { - "en": "InActive", - "ar": "غير نشط" - }, - "balance": { - "en": "Balance", - "ar": "الرصيد" - }, - "gained": { - "en": "GAINED", - "ar": "المكتسب" - }, - "consumed": { - "en": "Consumed", - "ar": "المستهلك" - }, - "transferred": { - "en": "Transferred", - "ar": "المحول" - }, - "riyal": { - "en": "RIYAL", - "ar": "ريال" - }, - "membersince": { - "en": "MEMBER SINCE", - "ar": "عضو منذ" - }, - "identification": { - "en": "Identification Number", - "ar": "رقم الهوية" - }, - "lakumMobile": { - "en": "Mobile Number", - "ar": "رقم الجوال" - }, - "waitinggained": { - "en": "Waiting gained", - "ar": "انتظار المكتسب" - }, - "expired": { - "en": "Expired", - "ar": "منتهي" - }, - "willBeExpired": { - "en": "Will Be Expired", - "ar": "سينتهي" - }, - "activateLAKUMAccount": { - "en": "Activate LAKUM Account", - "ar": "تفعيل حساب لكم" - }, - "checkBeneficiary": { - "en": "CHECK BENEFICIARY", - "ar": "تحقق من المستفيد" - }, - "beneficiaryName": { - "en": "Beneficiary Name", - "ar": "اسم المستفيد" - }, - "accountActivation": { - "en": "Account Activation", - "ar": "تفعيل الحساب" - }, - "lakumTransfer": { - "en": "Lakum Transfer", - "ar": "تحويل لكم" - }, - "acceptLbl": { - "en": "Accept", - "ar": "قبول" - }, - "declineLbl": { - "en": "Decline", - "ar": "رفض" - }, - "selectGender": { - "en": "Select Gender", - "ar": "اختر الجنس" - }, - "iAmA": { - "en": "I am a ...", - "ar": "أنا ..." - }, - "selectAge": { - "en": "Select Your Age", - "ar": "اختر عمرك" - }, - "select": { - "en": "Select", - "ar": "اختر" - }, - "iAm": { - "en": "I am", - "ar": "أنا" - }, - "yearsOld": { - "en": "years old", - "ar": "سنوات" - }, - "dragPoint": { - "en": "Drag point to change your age", - "ar": "اسحب النقطة لتغيير عمرك" - }, - "refine": { - "en": "Refine", - "ar": "تنقيح" - }, - "subGroup": { - "en": "Subgroup", - "ar": "مجموعة فرعية" - }, - "max": { - "en": "Max", - "ar": "الحد الأقصى" - }, - "compeleteOrderMsg": { - "en": "Order has been placed successfully!!", - "ar": "تم تقديم الطلب بنجاح!!" - }, - "addToCompareMsg": { - "en": "You have added a product to the Compare list", - "ar": "لقد أضفت منتجًا إلى قائمة المقارنة" - }, - "itInListMsg": { - "en": "Item is already in the list", - "ar": "العنصر موجود بالفعل في القائمة" - }, - "compareListFull": { - "en": "Your compare list is full", - "ar": "قائمة المقارنة ممتلئة" - }, - "addQuantity": { - "en": "You should add quantity", - "ar": "يجب عليك إضافة الكمية" - }, - "addToCartMsg": { - "en": "You have added a product to the cart", - "ar": "لقد أضفت منتجًا إلى عربة التسوق" - }, - "addToWishlistMsg": { - "en": "You have added a product to the Wishlist", - "ar": "لقد أضفت منتجًا إلى قائمة الرغبات" - }, - "notifyMeMsg": { - "en": "You will be notified when product available", - "ar": "سوف يتم إبلاغك عند توفر المنتج" - }, - "removeFromWishlistMsg": { - "en": "You have removed a product from the Wishlist", - "ar": "لقد أزلت منتجًا من قائمة الرغبات" - }, - "min": { - "en": "Min", - "ar": "الحد الأدنى" - }, - "reset": { - "en": "Reset", - "ar": "إعادة تعيين" - }, - "apply": { - "en": "Apply", - "ar": "تطبيق" - }, - "viewCategorise": { - "en": "View All Categories", - "ar": "عرض جميع الفئات" - }, - "viewSubCategorise": { - "en": "View All Sub Categories", - "ar": "عرض جميع الفئات الفرعية" - }, - "categorise": { - "en": "Categories", - "ar": "الفئات" - }, - "wishList": { - "en": "WishList", - "ar": "قائمة الرغبات" - }, - "cart": { - "en": "Cart", - "ar": "عربة التسوق" - }, - "alhabibapp": { - "en": "Al Habib app", - "ar": "تطبيق الحبيب" - }, - "searchProductHere": { - "en": "Search Product here", - "ar": "ابحث عن المنتج هنا" - }, - "hhcNotAuthMsg": { - "en": "This service provides a set of home health care services, continuous and comprehensive follow-up in their places of residence for those who cannot access health facilities, such as (laboratory analyzes - radiology - vaccinations - physical therapy), etc.", - "ar": "تقدم هذه الخدمة مجموعة من خدمات الرعاية الصحية المنزلية، والمتابعة المستمرة والشاملة في أماكن إقامتهم لأولئك الذين لا يمكنهم الوصول إلى المرافق الصحية، مثل (تحليلات المختبر - الأشعة - التطعيمات - العلاج الطبيعي)، إلخ." - }, - "email": { - "en": "Email *", - "ar": "البريد الإلكتروني *" - }, - "book": { - "en": "Book", - "ar": "احجز" - }, - "appointmentLabel": { - "en": "Appointment", - "ar": "موعد" - }, - "bloodType": { - "en": "Blood Type", - "ar": "فصيلة الدم" - }, - "maritalStatus": { - "en": "Marital status", - "ar": "الحالة الاجتماعية" - }, - "general": { - "en": "General", - "ar": "عام" - }, - "profile": { - "en": "My Profile", - "ar": "ملفي" - }, - "notifications": { - "en": "Notifications", - "ar": "إشعارات" - }, - "notificationDetails": { - "en": "Notification Details", - "ar": "تفاصيل الإشعار" - }, - "notificationDetailsa": { - "en": "Notification Details", - "ar": "تفاصيل الإشعار" - }, - "infoMyDoctor": { - "en": "This service allows you to see all the doctors you have visited in Al Habib Medical Group, and through this service:", - "ar": "تتيح لك هذه الخدمة رؤية جميع الأطباء الذين زرتهم في مجموعة الحبيب الطبية، ومن خلال هذه الخدمة:" - }, - "infoPrescriptions": { - "en": "This service allows you to view all the medical prescriptions issued by Al Habib Medical Group, and through this service, you can:", - "ar": "تتيح لك هذه الخدمة عرض جميع الوصفات الطبية التي أصدرتها مجموعة الحبيب الطبية، ومن خلال هذه الخدمة، يمكنك:" - }, - "infoInsuranceCards": { - "en": "This service allows you to view all the insurance cards that recorded during your visits to Al Habib Medical Group in addition to:", - "ar": "تتيح لك هذه الخدمة عرض جميع بطاقات التأمين التي تم تسجيلها خلال زياراتك لمجموعة الحبيب الطبية بالإضافة إلى:" - }, - "infoAllergies": { - "en": "This service allows you to view all types of allergies recorded during your visits to Al Habib Medical Group.", - "ar": "تتيح لك هذه الخدمة عرض جميع أنواع الحساسية المسجلة خلال زياراتك لمجموعة الحبيب الطبية." - }, - "infoSickLeaves": { - "en": "This service allows you to view all sick leaves that were taken in Al Habib Medical Group in addition to:", - "ar": "تتيح لك هذه الخدمة عرض جميع الاجازات المرضيه التي تم أخذها في مجموعة الحبيب الطبية بالإضافة إلى:" - }, - "infoApprovals": { - "en": "This service allows you to view all approvals requests that have been sent to the insurance companies in addition to:", - "ar": "تتيح لك هذه الخدمة عرض جميع طلبات الموافقة التي تم إرسالها إلى شركات التأمين بالإضافة إلى:" - }, - "infoMonthReport": { - "en": "Upon activation of this service, the system will send a monthly report automatically to the registered email which lists the vital signs and the results for the last visits made in AlHabib Medical Group.", - "ar": "عند تفعيل هذه الخدمة، سيقوم النظام بإرسال تقرير شهري تلقائيًا إلى البريد الإلكتروني المسجل يتضمن العلامات الحيوية والنتائج لآخر الزيارات التي تمت في مجموعة الحبيب الطبية." - }, - "languageSetting": { - "en": "SMS, WhatsApp and Confirmation Calls Language", - "ar": "الرسائل القصيرة، واتساب، لغة مكالمات التأكيد" - }, - "alert": { - "en": "Alerts", - "ar": "تنبيهات" - }, - "emailAlert": { - "en": "Alert by Email", - "ar": "تنبيه عبر البريد الإلكتروني" - }, - "smsAlert": { - "en": "Alert by SMS", - "ar": "تنبيه عبر الرسائل القصيرة" - }, - "contactInfo": { - "en": "Contact Information", - "ar": "معلومات الاتصال" - }, - "emrgName": { - "en": "Emergency Contact Name", - "ar": "اسم جهة الاتصال في حالات الطوارئ" - }, - "emrgNo": { - "en": "Emergency Contact Number", - "ar": "رقم جهة الاتصال في حالات الطوارئ" - }, - "modes": { - "en": "Modes", - "ar": "الأوضاع" - }, - "vibration": { - "en": "Vibration Touch Feedback", - "ar": "اهتزاز عند اللمس" - }, - "blindModes": { - "en": "Modes for Partially Blind", - "ar": "أوضاع للمكفوفين جزئيًا" - }, - "invertTheme": { - "en": "Invert", - "ar": "عكس" - }, - "offTheme": { - "en": "Off", - "ar": "إيقاف" - }, - "dimTheme": { - "en": "Dim", - "ar": "خافت" - }, - "bwTheme": { - "en": "Black and White", - "ar": "أسود وأبيض" - }, - "permissions": { - "en": "Permission", - "ar": "إذن" - }, - "cameraPermission": { - "en": "Camera", - "ar": "الكاميرا" - }, - "locationPermission": { - "en": "Location", - "ar": "الموقع" - }, - "needPrescription": { - "en": "This product requires a prescription", - "ar": "يتطلب هذا المنتج وصفة طبية" - }, - "outOfStockMsg": { - "en": "You have added product which is out of stock now, Please remove that!", - "ar": "لقد أضفت منتجًا غير متوفر حاليًا، يرجى إزالته!" - }, - "noArabicLetters": { - "en": "It Is Not Allow to Use Arabic Letters", - "ar": "لا يُسمح باستخدام الحروف العربية" - }, - "noOffersAvailable": { - "en": "No Offers Available!", - "ar": "لا توجد عروض متاحة!" - }, - "accessibility": { - "en": "Accessibility Mode", - "ar": "وضع الوصول" - }, - "orderStatus": { - "en": "Order Status", - "ar": "حالة الطلب" - }, - "findUs": { - "en": "Find Us", - "ar": "اعثر علينا" - }, - "liveChat": { - "en": "Live Chat", - "ar": "دردشة مباشرة" - }, - "service": { - "en": "Service", - "ar": "خدمة" - }, - "hmgServiceLabel": { - "en": "HMG Service", - "ar": "خدمة مجموعة الحبيب الطبية" - }, - "healthWeatherIndicators": { - "en": "Health Weather Indicators", - "ar": "مؤشرات الطقس الصحية" - }, - "healthTipsBasedOnCurrentWeather": { - "en": "Health Tips Based On Current Weather", - "ar": "نصائح صحية بناءً على الطقس الحالي" - }, - "moreDetails": { - "en": "More details", - "ar": "المزيد من التفاصيل" - }, - "resendOrder": { - "en": "Refill and Delivery", - "ar": "إعادة التعبئة والتوصيل" - }, - "ports": { - "en": "Ports", - "ar": "المنافذ" - }, - "way": { - "en": "Way", - "ar": "الطريقة" - }, - "dailyDoses": { - "en": "Daily Doses", - "ar": "الجرعات اليومية" - }, - "period": { - "en": "Period", - "ar": "الفترة" - }, - "duration": { - "en": "المدة", - "ar": "المدة" - }, - "cm": { - "en": "CM", - "ar": "سم" - }, - "ft": { - "en": "ft", - "ar": "قدم" - }, - "kg": { - "en": "kg", - "ar": "كجم" - }, - "lb": { - "en": "lb", - "ar": "رطل" - }, - "birthDate": { - "en": "Birth Date", - "ar": "تاريخ الميلاد" - }, - "dateOfBirth": { - "en": "Date of Birth", - "ar": "تاريخ الميلاد" - }, - "mass": { - "en": "Mass", - "ar": "الكتلة" - }, - "tempC": { - "en": "°C", - "ar": "°م" - }, - "bpm": { - "en": "bpm", - "ar": "نبضة في الدقيقة" - }, - "respirationSigns": { - "en": "Respiration", - "ar": "التنفس" - }, - "sysDias": { - "en": "SBP/DBP", - "ar": "SBP/DBP" - }, - "body": { - "en": "Body Mass", - "ar": "مؤشر كتلة الجسم" - }, - "bodyString": { - "en": "Body", - "ar": "الجسم" - }, - "face": { - "en": "Face", - "ar": "وجه" - }, - "retouch": { - "en": "Re-touch", - "ar": "روتوش" - }, - "bikini": { - "en": "Bikini", - "ar": "بيكيني" - }, - "totalMinutes": { - "en": "Total Minutes", - "ar": "إجمالي الدقائق" - }, - "feedback": { - "en": "Feedback", - "ar": "ملاحظات" - }, - "likeToHear": { - "en": "We would love to hear the feedback, concerns on healthcare services and eServices experience. Please use the below form", - "ar": "نود سماع ملاحظاتك، ومخاوفك بشأن خدمات الرعاية الصحية وتجربة الخدمات الإلكترونية. يرجى استخدام النموذج أدناه" - }, - "emptySubject": { - "en": "Please enter the subject", - "ar": "يرجى إدخال الموضوع" - }, - "emptyMessage": { - "en": "Please enter message", - "ar": "يرجى إدخال الرسالة" - }, - "selectAttachment": { - "en": "Select Attachment", - "ar": "اختر المرفق" - }, - "complainAppo": { - "en": "Complaint for appointment", - "ar": "شكوى بخصوص الموعد" - }, - "complainAppoAlt": { - "en": "Complaint without appointment", - "ar": "شكوى بدون موعد" - }, - "messageType": { - "en": "Message Type", - "ar": "نوع الرسالة" - }, - "feedbackType": { - "en": "Feedback Type", - "ar": "نوع الملاحظات" - }, - "compliment": { - "en": "Appreciation", - "ar": "تقدير" - }, - "suggestion": { - "en": "Suggestion", - "ar": "اقتراح" - }, - "yourFeedback": { - "en": "Your feedback was sent", - "ar": "تم إرسال ملاحظاتك" - }, - "selectPart": { - "en": "Please select the part that complain about", - "ar": "يرجى اختيار الجزء الذي تشتكي منه" - }, - "number": { - "en": "Number", - "ar": "رقم" - }, - "notClassified": { - "en": "Not classified", - "ar": "غير مصنف" - }, - "selectClinic": { - "en": "Select Clinic", - "ar": "اختر العيادة" - }, - "selectProject": { - "en": "Select Hospital", - "ar": "اختر المستشفى" - }, - "searchItemError": { - "en": "Item name should be more than 3 character", - "ar": "يجب أن يكون اسم العنصر أكثر من 3 أحرف" - }, - "youCanFind": { - "en": "You Can Find ", - "ar": "يمكنك العثور على " - }, - "itemInSearch": { - "en": " Item in Search", - "ar": " عنصر في البحث" - }, - "bloodDonation": { - "en": "Blood Donation", - "ar": "التبرع بالدم" - }, - "bloodDonationInfo": { - "en": "Through this service, you can register your name as a blood donor where the blood bank in the Habib Medical Group will communicate you in case of need for blood type.", - "ar": "من خلال هذه الخدمة، يمكنك تسجيل اسمك كمتبرع بالدم حيث سيتواصل معك بنك الدم في مجموعة الحبيب الطبية في حالة الحاجة إلى فصيلة الدم." - }, - "bloodInstruction": { - "en": "Enter the required information, in order to register for Blood Donation Service", - "ar": "أدخل المعلومات المطلوبة، من أجل التسجيل في خدمة التبرع بالدم" - }, - "viewTerms": { - "en": "To view the terms and conditions", - "ar": "لعرض الشروط والأحكام" - }, - "wantConnectHmgNetwork": { - "en": "Dear customer there is no internet access, do you want to connect with HMG network to use our app, make sure you are in range of HMG network", - "ar": "عزيزي العميل، لا يوجد وصول إلى الإنترنت، هل ترغب في الاتصال بشبكة مجموعة الحبيب الطبية لاستخدام تطبيقنا، تأكد من أنك في نطاق شبكة مجموعة الحبيب الطبية" - }, - "failedToAccessHmgServices": { - "en": "Connected with HMG Network,\n\nBut failed to access HMG services", - "ar": "متصل بشبكة مجموعة الحبيب الطبية،\n\nلكن فشل في الوصول إلى خدمات مجموعة الحبيب الطبية" - }, - "offerAndPackages": { - "en": "Offers and Packages", - "ar": "عروض وباقات" - }, - "offerAndPackagesDetails": { - "en": "This service allows you to view all HMG Offers:", - "ar": "تتيح لك هذه الخدمة عرض جميع عروض مجموعة الحبيب الطبية:" - }, - "invoiceNo": { - "en": "Invoice No", - "ar": "رقم الفاتورة" - }, - "invoiceDate": { - "en": "Invoice Date", - "ar": "تاريخ الفاتورة" - }, - "specialResult": { - "en": "Special Result", - "ar": "نتيجة خاصة" - }, - "generalResult": { - "en": "General Result", - "ar": "نتيجة عامة" - }, - "showMoreBtn": { - "en": "Flow Chart", - "ar": "مخطط التدفق" - }, - "value": { - "en": "Value", - "ar": "القيمة" - }, - "report": { - "en": "Radiology Report", - "ar": "تقرير الأشعة" - }, - "openRad": { - "en": "Open Image", - "ar": "فتح الصورة" - }, - "sendCopy": { - "en": "Email the Report", - "ar": "إرسال التقرير عبر البريد الإلكتروني" - }, - "appoSurvey": { - "en": "Survey", - "ar": "استطلاع" - }, - "appoSurveySubtitle": { - "en": "Survey", - "ar": "استطلاع" - }, - "labResults": { - "en": "Lab Results", - "ar": "نتائج المختبر" - }, - "doctorRating": { - "en": "Doctor Rating", - "ar": "تقييم الطبيب" - }, - "good": { - "en": "Good", - "ar": "جيد" - }, - "vGood": { - "en": "Very Good", - "ar": "جيد جدًا" - }, - "excellent": { - "en": "Excellent", - "ar": "ممتاز" - }, - "average": { - "en": "Average", - "ar": "متوسط" - }, - "infoSigns": { - "en": "This service allows you to view all vital signs were performed in the Habib Medical Group, e.x (height, weight, body mass index, heart rate, etc.) as well shows some statistics charts.", - "ar": "تتيح لك هذه الخدمة عرض جميع العلامات الحيوية التي تم قياسها في مجموعة الحبيب الطبية، مثل (الطول، الوزن، مؤشر كتلة الجسم، معدل ضربات القلب، إلخ.) بالإضافة إلى عرض بعض الرسوم البيانية الإحصائية." - }, - "infoAdvancePayment": { - "en": "This service designed so that you can deposit an amount in advance either in your account or in someone else's account with Al Habib Medical Group.", - "ar": "تم تصميم هذه الخدمة بحيث يمكنك إيداع مبلغ مقدم إما في حسابك أو في حساب شخص آخر، في مجموعة الحبيب الطبية." - }, - "infoMyBalance": { - "en": "This service allows you to check your balance in all branchs", - "ar": "تتيح لك هذه الخدمة التحقق من رصيدك في جميع الفروع" - }, - "erContant": { - "en": "This service displays nearest branch among all the branches of Al Habib Medical Group based on your current location.", - "ar": "تظهر هذه الخدمة أقرب فرع من بين جميع فروع مجموعة الحبيب الطبية بناءً على موقعك الحالي." - }, - "infoAmbulance": { - "en": "Through this service, you can request evacuation by ambulance, whether from home or to home, in addition to a set of other services", - "ar": "من خلال هذه الخدمة، يمكنك طلب الإخلاء بواسطة سيارة إسعاف، سواء من المنزل أو إلى المنزل، بالإضافة إلى مجموعة من الخدمات الأخرى" - }, - "infoMyAppointments": { - "en": "This service allows you to see all the appointment you have visited in Al Habib Medical Group, and through this service:", - "ar": "تتيح لك هذه الخدمة رؤية جميع المواعيد التي زرتها في مجموعة الحبيب الطبية، ومن خلال هذه الخدمة:" - }, - "infoTodo": { - "en": "This service is designed to enable you to have a quick link to the list of tasks that need to be done", - "ar": "تم تصميم هذه الخدمة لتمكينك من الحصول على رابط سريع لقائمة المهام التي تحتاج القيام بها" - }, - "familyInfo": { - "en": "Through this service, you will be able to link your family medical files to your medical file so that you can manage their records by login to your medical file.", - "ar": "من خلال هذه الخدمة، ستتمكن من ربط ملفات عائلتك الطبية بملفك الطبي حتى تتمكن من إدارة سجلاتهم عن طريق تسجيل الدخول إلى ملفك الطبي." - }, - "rrtdDetails": { - "en": "The Rapid response team provides a comprehensive medical service for all sorts of urgent and stable cases of all ages, including adult and paediatric patients, the service is covered by a fully equipped and highly trained medical team capable of providing the best medical care at the patient’s home.", - "ar": "تقدم فريق الاستجابة السريعة خدمة طبية شاملة لجميع أنواع الحالات العاجلة والمستقرة من جميع الأعمار، بما في ذلك البالغين والمرضى الأطفال، وتغطي الخدمة فريق طبي مدرب تدريبًا عاليًا ومجهز تجهيزًا كاملًا قادرًا على تقديم أفضل رعاية طبية في منزل المريض." - }, - "onlineCheckInAgreement": { - "en": "The online check-in is for non-life threatening situation. Call the red crescent (997) or go to the nearest emergency department if there are: \n\nsigns of stroke or heart attack \nhistory of seizure or syncope \nthere is limb or life threatening injury \npicture of severe injuries", - "ar": "تسجيل الوصول عبر الإنترنت مخصص للحالات التي لا تهدد الحياة. اتصل بالهلال الأحمر (997) أو اذهب إلى أقرب قسم طوارئ إذا كان هناك: \n\nعلامات السكتة الدماغية أو النوبة القلبية \nhالة من النوبات أو الإغماء \nهناك إصابة تهدد الطرف أو الحياة \nصورة لإصابات خطيرة" - }, - "infoEreferral": { - "en": "This service allows you to submit a Referral request from any health care providers either inside or outside the kingdom of Saudi Arabia to any of HMG Hospitals, by filling some of the patient's data and attaching the medical reports, moreover you can track the request status (Under process, Accepted or Rejected)", - "ar": "تتيح لك هذه الخدمة تقديم طلب إحالة من أي مقدم رعاية صحية سواء داخل أو خارج المملكة العربية السعودية إلى أي من مستشفيات HMG، عن طريق ملء بعض بيانات المريض وإرفاق التقارير الطبية، علاوة على ذلك يمكنك تتبع حالة الطلب (قيد المعالجة، مقبول أو مرفوض)" - }, - "erConsultation": { - "en": "This service allows you to make an online virtual consultation via video call directly with the doctor from anywhere at any time.", - "ar": "تتيح لك هذه الخدمة إجراء استشارة افتراضية عبر الإنترنت عبر مكالمة فيديو مباشرة مع الطبيب من أي مكان وفي أي وقت." - }, - "myInvoice": { - "en": "List", - "ar": "القائمة" - }, - "invoiceList": { - "en": "My Invoice", - "ar": "فواتيري" - }, - "thisItemIsNotAvailable": { - "en": "This item is not available", - "ar": "هذا العنصر غير متوفر" - }, - "beforeAfterImages": { - "en": "Before & After Images", - "ar": "صور قبل وبعد" - }, - "clinicAcceptLivecare": { - "en": "No need to wait or visit You can now get medical consultation via Video call (LiveCare service) in The name of the clinic clinic and the doctor will contact you immediately", - "ar": "لا حاجة للانتظار أو الزيارة يمكنك الآن الحصول على استشارة طبية عبر مكالمة فيديو (لايف كير) في اسم العيادة وسيتصل بك الطبيب على الفور" - }, - "livecareModalTop": { - "en": "This Clinic is Accepting LiveCare services", - "ar": "تقبل هذه العيادة خدمات ال لايف كير" - }, - "livecarePoint2": { - "en": "A Specialized doctor will contact you", - "ar": "سوف يتصل بك طبيب متخصص" - }, - "livecarePoint3": { - "en": "A Doctor will be able to see your full medical file history", - "ar": "سيكون لدى الطبيب القدرة على رؤية تاريخ ملفك الطبي الكامل" - }, - "livecarePoint4": { - "en": "Free Medicine Delivery Available", - "ar": "تتوفر خدمة توصيل الأدوية المجانية" - }, - "livecarePoint5": { - "en": "No need to visit the service is in your place", - "ar": "لا حاجة للزيارة، الخدمة في مكانك" - }, - "bookImmediateLivecare": { - "en": "I accept to get the service immediately", - "ar": "أوافق على الحصول على الخدمة على الفور" - }, - "bookVideoLivecare2": { - "en": "I don't need to visit the clinic", - "ar": "لا أحتاج لزيارة العيادة" - }, - "noThankyou": { - "en": "No Thanks", - "ar": "لا شكرًا" - }, - "visitClinic": { - "en": "Schedule appointment with the doctor", - "ar": "جدولة موعد مع الطبيب" - }, - "generateCovidCertificate": { - "en": "Generate Covid-19 Certificate", - "ar": "إصدار شهادة كوفيد-19" - }, - "isReportOutsideKsa": { - "en": "Is the certificate needed for outside KSA?", - "ar": "هل الشهادة مطلوبة خارج المملكة العربية السعودية؟" - }, - "passportNumber": { - "en": "Passport Number", - "ar": "رقم جواز السفر" - }, - "enterPassportNumber": { - "en": "Please confirm or update your passport number:", - "ar": "يرجى تأكيد أو تحديث رقم جواز السفر الخاص بك:" - }, - "validPassportNumber": { - "en": "Please enter valid passport number", - "ar": "يرجى إدخال رقم جواز سفر صالح" - }, - "continuePlan": { - "en": "Continue with the treatment plan?", - "ar": "متابعة خطة العلاج؟" - }, - "aboutApp": { - "en": "About the app", - "ar": "حول التطبيق" - }, - "dontHaveAccount": { - "en": "Don't have an account?", - "ar": "ليس لديك حساب؟" - }, - "loginOrRegister": { - "en": "Login or Register", - "ar": "تسجيل الدخول أو التسجيل" - }, - "myFiles": { - "en": "My Files", - "ar": "ملفاتي" - }, - "resultsPending": { - "en": "Results pending", - "ar": "النتائج معلقة" - }, - "resultsAvailable": { - "en": "Results available", - "ar": "النتائج متاحة" - }, - "viewReport": { - "en": "View Report", - "ar": "عرض التقرير" - }, - "checkAvailability": { - "en": "Check Availability", - "ar": "التحقق من التوفر" - }, - "readInstructions": { - "en": "Read Instructions", - "ar": "قراءة التعليمات" - }, - "searchLabReport": { - "en": "Search Lab Report", - "ar": "ابحث عن تقرير المختبر" - }, - "prescriptionDeliveryError": { - "en": "This Clinic Does Not Support Refill And Delivery.", - "ar": "هذه العيادة لا تدعم إعادة التعبئة والتسليم." - }, - "receiveOtpToast": { - "en": "Where would you like to receive OTP?", - "ar": "أين تود تلقي رمز التحقق OTP؟" - }, - "enterPhoneNumber": { - "en": "Enter Phone Number", - "ar": "أدخل رقم الهاتف" - }, - "enterEmailDesc": { - "en": "Enter your email to complete medical profile creation process", - "ar": "أدخل عنوان بريدك الإلكتروني لإكمال عملية إنشاء ملف طبي" - }, - "enterPhoneDesc": { - "en": "Enter your phone number to receive OTP ", - "ar": "أدخل رقم هاتفك لتلقي رمز التحقق " - }, - "pleaseChooseOption": { - "en": "Please select from the below options to receive OTP", - "ar": "الرجاء اختيار من الخيارات أدناه لتلقي رمز التحقق OTP" - }, - "prepareToElevate": { - "en": "Prepared to elevate your health and well-being?", - "ar": "هل أنت مستعد لتحسين صحتك ورفاهيتك؟" - }, - "iAcceptTermsConditions": { - "en": "I Accept the Terms and Conditions", - "ar": "أوافق على الشروط والأحكام" - }, - "alreadyHaveAccount": { - "en": "Already have an account?", - "ar": "هل لديك حساب بالفعل؟" - }, - "loginNow": { - "en": "Login Now", - "ar": "تسجيل الدخول الآن" - }, - "notice": { - "en": "Notice", - "ar": "إشعار" - }, - "oR": { - "en": "OR", - "ar": "أو" - }, - "sendOTPWHATSAPP": { - "en": "Send me OTP on Whatsapp", - "ar": "أرسل لي OTP عبر واتساب" - }, - "sendOTPSMS": { - "en": "Send me OTP on SMS", - "ar": "أرسل لي OTP عبر الرسائل القصيرة" - }, - "fullName": { - "en": "Full Name", - "ar": "الاسم الكامل" - }, - "married": { - "en": "Married", - "ar": "متزوج" - }, - "uae": { - "en": "United Arab Emirates", - "ar": "الإمارات العربية المتحدة" - }, - "malE": { - "en": "Male", - "ar": "ذكر" - }, - "loginBy": { - "en": "Login By", - "ar": "تسجيل الدخول بواسطة" - }, - "loginByOTP": { - "en": "Login By OTP", - "ar": "تسجيل الدخول بواسطة OTP" - }, - "guest": { - "en": "Guest", - "ar": "زائر" - }, - "switchAccount": { - "en": "Switch Account", - "ar": "تبديل الحساب" - }, - "lastLoginBy": { - "en": "Last login by", - "ar": "آخر تسجيل دخول بواسطة" - }, - "allSet": { - "en": "All Set! Now you can login with Face ID or Biometric", - "ar": "جاهز! الآن يمكنك تسجيل الدخول باستخدام Face ID أو البصمة" - }, - "enableQuickLogin": { - "en": "Enable Quick Login", - "ar": "تمكين تسجيل الدخول السريع" - }, - "enableMsg": { - "en": "Enabling the quick login will verify through your existing device Face ID / Biometric", - "ar": "تمكين تسجيل الدخول السريع سيسمح بالتحقق من خلال Face ID / Biometric الخاص بجهازك الحالي" - }, - "notNow": { - "en": "Not Now", - "ar": "ليس الآن" - }, - "pendingActivation": { - "en": "Pending Activation", - "ar": "في انتظار التنشيط" - }, - "awaitingApproval": { - "en": "Awaiting Approval", - "ar": "انتظر القبول" - }, - "news": { - "en": "News", - "ar": "أخبار" - }, - "ready": { - "en": "Ready", - "ar": "جاهز" - }, - "enterValidNationalId": { - "en": "Please enter a valid national ID or file number", - "ar": "الرجاء إدخال رقم الهوية الوطنية أو رقم الملف الصحيح" - }, - "enterValidPhoneNumber": { - "en": "Please enter a valid phone number", - "ar": "الرجاء إدخال رقم هاتف صالح" - }, - "cannotEnterSaudiOrUAENumber": { - "en": "You cannot enter Saudi Arabia (00966) or UAE (00971) phone numbers when 'Others' country is selected", - "ar": "لا يمكنك إدخال أرقام هواتف السعودية (00966) أو الإمارات (00971) عند اختيار دولة 'أخرى'" - }, - "medicalCentersWithCount": { - "en": "{count} Medical Centers", - "ar": "{count} مراكز طبية" - }, - "medicalCenters": { - "en": " Medical Centers", - "ar": "مراكز طبية" - }, - "hospitalsWithCount": { - "en": "{count} Hospitals", - "ar": "{count} مستشفيات" - }, - "selectRegion": { - "en": "Select Region", - "ar": "اختر المنطقة" - }, - "selectFacility": { - "en": "Select Facilities", - "ar": "اختر المرافق" - }, - "selectFacilitiesSubTitle": { - "en": "Please select the facility for the appointment", - "ar": "يرجى اختيار المرفق للموعد" - }, - "selectHospitalSubTitle": { - "en": "Please select the hospital for the appointment", - "ar": "يرجى اختيار المستشفى للموعد" - }, - "iAcceptThe": { - "en": "I Accept the", - "ar": "أوافق على" - }, - "personalDetailsVerification": { - "en": "Personal Details Verification", - "ar": "التحقق من التفاصيل الشخصية" - }, - "otpVerification": { - "en": "OTP Verification", - "ar": "التحقق من OTP" - }, - "weHaveSendOTP": { - "en": "We have sent you the OTP code on", - "ar": "لقد أرسلنا OTP إلى" - }, - "via": { - "en": "via", - "ar": "عبر" - }, - "forRegistrationVerification": { - "en": "for registration verification", - "ar": "للتحقق من التسجيل" - }, - "didntReceiveIt": { - "en": "Didn't receive it?", - "ar": "لم تستلمه؟" - }, - "resendOTP": { - "en": "Resend", - "ar": "إعادة إرسال" - }, - "resendIn": { - "en": "resend in", - "ar": "إعادة الإرسال في" - }, - "pleaseEnterAnationalID": { - "en": "Please enter a national ID", - "ar": "يرجى إدخال رقم الهوية الوطنية" - }, - "pleaseEnterAFileNumber": { - "en": "Please enter a file number", - "ar": "يرجى إدخال رقم الملف" - }, - "pleaseEnterAValidEmail": { - "en": "Please enter a valid email", - "ar": "يرجى إدخال بريد إلكتروني صالح" - }, - "pleaseEnterFullName": { - "en": "Please enter full name", - "ar": "يرجى إدخال الاسم الكامل" - }, - "pleaseAcceptTermsConditions": { - "en": "Please accept the terms and conditions", - "ar": "يرجى قبول الشروط والأحكام" - }, - "pleaseEnterAValidIqamaID": { - "en": "Please enter a valid Iqama ID", - "ar": "يرجى إدخال رقم إقامة صالح" - }, - "pleaseEnterAValidNationalID": { - "en": "Please enter a valid national ID", - "ar": "يرجى إدخال رقم هوية وطنية صالح" - }, - "pleaseEnterAValidDateOfBirth": { - "en": "Please enter a valid date of birth", - "ar": "يرجى إدخال تاريخ ميلاد صالح" - }, - "pleaseEnterAValidName": { - "en": "Please enter a valid name", - "ar": "يرجى إدخال اسم صالح" - }, - "pleaseSelectAGender": { - "en": "Please select a gender", - "ar": "يرجى اختيار الجنس" - }, - "pleaseSelectAMaritalStatus": { - "en": "Please select a marital status", - "ar": "يرجى اختيار الحالة الاجتماعية" - }, - "pleaseSelectACountry": { - "en": "Please select a country", - "ar": "يرجى اختيار الدولة" - }, - "pleaseEnterEmail": { - "en": "Please enter email", - "ar": "يرجى إدخال البريد الإلكتروني" - }, - "pleaseEnterAValidEmailFormat": { - "en": "Please enter a valid email format", - "ar": "يرجى إدخال تنسيق بريد إلكتروني صالح" - }, - "selectCountry": { - "en": "Select Country", - "ar": "اختر الدولة" - }, - "forLoginVerification": { - "en": "for login verification", - "ar": "للتحقق من تسجيل الدخول" - }, - "searchHospital": { - "en": "Search Hospital", - "ar": "بحث في المستشفى" - }, - "skip": { - "en": "Skip", - "ar": "تخطي" - }, - "getStarted": { - "en": "Get Started", - "ar": "ابدأ الآن" - }, - "onboardingHeading1": { - "en": "Booking appointment has never been easy", - "ar": "حجز المواعيد لم يكن أسهل من الآن." - }, - "onboardingBody1": { - "en": "In few clicks find yourself having consultation with the doctor of your choice.", - "ar": "ببضع نقرات فقط يمكنك استشارة الطبيب الذي تختاره." - }, - "onboardingHeading2": { - "en": "Access the medical history on finger tips", - "ar": "الوصول إلى السجل الطبي بين يديك" - }, - "onboardingBody2": { - "en": "Keep track on your medical history including labs, prescription, insurance, etc", - "ar": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها." - }, - "hmgHospitals": { - "en": "HMG Hospitals", - "ar": "مستشفيات مجموعة الحبيب الطبية" - }, - "hmcMedicalClinic": { - "en": "HMC Medical Centers", - "ar": "مراكز مجموعة الحبيب الطبية" - }, - "applyFilter": { - "en": "Apply Filter", - "ar": "تطبيق الفلتر" - }, - "facilityAndLocation": { - "en": "Facility and Location", - "ar": "المرفق والموقع" - }, - "regionAndLocation": { - "en": "Region And Locations", - "ar": "المنطقة والمواقع" - }, - "clearAllFilters": { - "en": "Clear all filters", - "ar": "مسح جميع الفلاتر" - }, - "filters": { - "en": "Filters", - "ar": "فلاتر" - }, - "searchClinic": { - "en": "Search Clinic", - "ar": "بحث عن عيادة" - }, - "normal": { - "en": "Normal", - "ar": "عادي" - }, - "attention": { - "en": "Attention", - "ar": "انتباه" - }, - "monitor": { - "en": "Monitor", - "ar": "مراقبة" - }, - "noSpecialResult": { - "en": "No Special Results", - "ar": "لا توجد نتائج خاصة" - }, - "setTheDateRange": { - "en": "Set The Date Range", - "ar": "تعيين النطاق الزمني" - }, - "historyFlowchart": { - "en": "History FlowChart", - "ar": "مخطط تدفق التاريخ" - }, - "to": { - "en": "to", - "ar": "إلى" - }, - "startDate": { - "en": "Start Date", - "ar": "تاريخ البدء" - }, - "endDate": { - "en": "End Date", - "ar": "تاريخ الانتهاء" - }, - "walkin": { - "en": "Walk In", - "ar": "زيارة بدون موعد" - }, - "laserClinic": { - "en": "Laser Clinic", - "ar": "عيادة الليزر" - }, - "continueString": { - "en": "Continue", - "ar": "يكمل" - }, - "covid_info": { - "en": "Dr. Sulaiman Al Habib hospitals are conducting a test for the emerging corona virus and issuing travel certificates 24/7 in a short time and with high accuracy...", - "ar": "تجري مستشفيات د. سليمان الحبيب فحص فيروس كورونا المستجد وتصدر شهادات السفر على مدار الساعة..." - }, - "appointmentDetails": { - "en": "Appointment Details", - "ar": "تفاصيل الموعد" - }, - "checkingDoctorAvailability": { - "en": "Checking doctor availability...", - "ar": "جاري التحقق من توفر الطبيب..." - }, - "cancellingAppointmentPleaseWait": { - "en": "Cancelling Appointment, Please Wait...", - "ar": "جاري إلغاء الموعد، يرجى الانتظار..." - }, - "appointmentCancelledSuccessfully": { - "en": "Appointment Cancelled Successfully", - "ar": "تم إلغاء الموعد بنجاح" - }, - "notConfirmed": { - "en": "Not Confirmed", - "ar": "غير مؤكد" - }, - "appointmentStatus": { - "en": "Appointment Status", - "ar": "حالة الموعد" - }, - "doctorWillCallYou": { - "en": "The doctor will call you once the appointment time approaches.", - "ar": "سيتصل بك الطبيب عندما يقترب موعدك." - }, - "getDirections": { - "en": "Get Directions", - "ar": "الحصول على الاتجاهات" - }, - "notifyMeBeforeAppointment": { - "en": "Notify me before the appointment", - "ar": "أبلغني قبل الموعد" - }, - "fetchingLabResults": { - "en": "Fetching Lab Results...", - "ar": "جاري جلب نتائج المختبر..." - }, - "fetchingRadiologyResults": { - "en": "Fetching Radiology Results...", - "ar": "جاري جلب نتائج الأشعة..." - }, - "fetchingAppointmentPrescriptions": { - "en": "Fetching Appointment Prescriptions...", - "ar": "جاري جلب وصفات الموعد..." - }, - "noPrescriptionsForAppointment": { - "en": "You don't have any prescriptions for this appointment.", - "ar": "ليس لديك أي وصفات طبية لهذا الموعد." - }, - "amountBeforeTax": { - "en": "Amount before tax", - "ar": "المبلغ قبل الضريبة" - }, - "rebookAppointment": { - "en": "Re-book Appointment", - "ar": "إعادة حجز الموعد" - }, - "fetchingDoctorSchedulePleaseWait": { - "en": "Fetching Doctor Schedule, Please Wait...", - "ar": "جاري جلب جدول الطبيب، يرجى الانتظار..." - }, - "pickADate": { - "en": "Pick a Date", - "ar": "اختر تاريخاً" - }, - "confirmingAppointmentPleaseWait": { - "en": "Confirming Appointment, Please Wait...", - "ar": "جاري تأكيد الموعد، يرجى الانتظار..." - }, - "appointmentConfirmedSuccessfully": { - "en": "Appointment Confirmed Successfully", - "ar": "تم تأكيد الموعد بنجاح" - }, - "appointmentPayment": { - "en": "Appointment Payment", - "ar": "دفع الموعد" - }, - "checkingPaymentStatusPleaseWait": { - "en": "Checking payment status, Please wait...", - "ar": "جاري التحقق من حالة الدفع، يرجى الانتظار..." - }, - "paymentFailedPleaseTryAgain": { - "en": "Payment Failed! Please try again.", - "ar": "فشل الدفع! يرجى المحاولة مرة أخرى." - }, - "appointmentCheckIn": { - "en": "Appointment check in", - "ar": "تسجيل حضور الموعد" - }, - "insuranceExpiredOrInactive": { - "en": "Insurance expired or inactive", - "ar": "التأمين منتهي الصلاحية أو غير نشط" - }, - "totalAmountToPay": { - "en": "Total amount to pay", - "ar": "المبلغ الإجمالي المستحق" - }, - "vat15": { - "en": "VAT 15%", - "ar": "ضريبة القيمة المضافة 15%" - }, - "liveCare": { - "en": "LiveCare", - "ar": "لايف كير" - }, - "recentVisits": { - "en": "Recent Visits", - "ar": "الزيارات الأخيرة" - }, - "searchByClinic": { - "en": "Search By Clinic", - "ar": "البحث حسب العيادة" - }, - "tapToSelectClinic": { - "en": "Tap to select clinic", - "ar": "انقر لاختيار العيادة" - }, - "searchByDoctor": { - "en": "Search By Doctor", - "ar": "البحث حسب الطبيب" - }, - "tapToSelect": { - "en": "Tap to select", - "ar": "انقر للاختيار" - }, - "searchByRegion": { - "en": "Search By Region", - "ar": "البحث حسب المنطقة" - }, - "centralRegion": { - "en": "Central Region", - "ar": "المنطقة الوسطى" - }, - "immediateConsultation": { - "en": "Immediate Consultation", - "ar": "استشارة فورية" - }, - "scheduledConsultation": { - "en": "Scheduled Consultation", - "ar": "استشارة مجدولة" - }, - "pharmaLiveCare": { - "en": "Pharma LiveCare", - "ar": "لايف كير الصيدلية" - }, - "notSureHelpMeChooseClinic": { - "en": "Not sure? help me choose a clinic!", - "ar": "غير متأكد؟ ساعدني في اختيار عيادة!" - }, - "mentionYourSymptomsAndFindDoctors": { - "en": "Mention your symptoms and find the list of doctors accordingly", - "ar": "اذكر أعراضك واعثر على قائمة الأطباء وفقاً لذلك" - }, - "immediateService": { - "en": "Immediate service", - "ar": "خدمة فورية" - }, - "noNeedToWaitGetMedicalConsultation": { - "en": "No need to wait, you will get medical consultation immediately via video call", - "ar": "لا حاجة للانتظار، ستحصل على استشارة طبية فورية عبر مكالمة فيديو" - }, - "noVisitRequired": { - "en": "No visit required", - "ar": "لا حاجة للزيارة" - }, - "doctorWillContact": { - "en": "Doctor will contact", - "ar": "سيتصل بك الطبيب" - }, - "specialisedDoctorWillContactYou": { - "en": "A specialised doctor will contact you and will be able to view your medical history", - "ar": "سيتصل بك طبيب متخصص وسيكون قادراً على الاطلاع على تاريخك الطبي" - }, - "freeMedicineDelivery": { - "en": "Free medicine delivery", - "ar": "توصيل مجاني للأدوية" - }, - "offersFreeMedicineDelivery": { - "en": "Offers free medicine delivery for the LiveCare appointment", - "ar": "يوفر توصيل مجاني للأدوية لموعد لايف كير" - }, - "dentalChiefComplaints": { - "en": "Dental Chief Complaints", - "ar": "الشكاوى الرئيسة للأسنان" - }, - "viewAvailableAppointments": { - "en": "View available appointments", - "ar": "عرض المواعيد المتاحة" - }, - "doctorProfile": { - "en": "Doctor Profile", - "ar": " ملف الطبيب" - }, - "waitingAppointment": { - "en": "Waiting Appointment", - "ar": "موعد الانتظار" - }, - "hospitalInformation": { - "en": "Hospital Information", - "ar": "معلومات المستشفى" - }, - "fetchingAppointmentShare": { - "en": "Fetching Appointment Share...", - "ar": "جاري جلب تفاصيل الموعد..." - }, - "bookingYourAppointment": { - "en": "Booking your appointment...", - "ar": "جاري حجز موعدك..." - }, - "selectLiveCareClinic": { - "en": "Select LiveCare Clinic", - "ar": "اختر عيادة لايف كير" - }, - "checkingForExistingDentalPlan": { - "en": "Checking for an existing dental plan, Please wait...", - "ar": "جاري التحقق من وجود خطة أسنان حالية، يرجى الانتظار..." - }, - "dentalTreatmentPlan": { - "en": "Dental treatment plan", - "ar": "خطة علاج الأسنان" - }, - "youHaveExistingTreatmentPlan": { - "en": "You have an existing treatment plan: ", - "ar": "لديك خطة علاج حالية: " - }, - "mins": { - "en": "Mins", - "ar": "دقيقة" - }, - "totalTimeRequired": { - "en": "Total time required", - "ar": "إجمالي الوقت المطلوب" - }, - "wouldYouLikeToContinue": { - "en": "Would you like to continue it?", - "ar": "هل تريد متابعتها؟" - }, - "chooseDoctor": { - "en": "Choose Doctor", - "ar": "اختر الطبيب" - }, - "viewNearestAppos": { - "en": "View nearest available appointments", - "ar": "عرض أقرب المواعيد المتاحة" - }, - "noDoctorFound": { - "en": "No Doctor found for selected criteria...", - "ar": "لم يتم العثور على طبيب مطابق للمعايير المحددة..." - }, - "yesPleasImInAHurry": { - "en": "Yes please, I am in a hurry", - "ar": "نعم من فضلك، أنا في عجلة من أمري" - }, - "fetchingFeesPleaseWait": { - "en": "Fetching fees, Please wait...", - "ar": "جاري جلب الرسوم، يرجى الانتظار..." - }, - "noThanksPhysicalVisit": { - "en": "No, Thanks. I would like a physical visit", - "ar": "لا، شكراً. أفضل الزيارة الشخصية" - }, - "offline": { - "en": "Offline", - "ar": "غير متصل" - }, - "videoCall": { - "en": "Video Call", - "ar": "مكالمة فيديو" - }, - "liveVideoCallWithHMGDoctors": { - "en": "Live Video Call with HMG Doctors", - "ar": "مكالمة فيديو مباشرة مع أطباء مجموعة الحبيب الطبية" - }, - "liveAudioCallWithHMGDoctors": { - "en": "Live Audio Call with HMG Doctors", - "ar": "مكالمة صوتية مباشرة مع أطباء مجموعة الحبيب الطبية" - }, - "audioCall": { - "en": "Audio Call", - "ar": "مكالمة صوتية" - }, - "phoneCall": { - "en": "Phone Call", - "ar": "مكالمة هاتفية" - }, - "livePhoneCallWithHMGDoctors": { - "en": "Live Phone Call with HMG Doctors", - "ar": "مكالمة هاتفية مباشرة مع أطباء مجموعة الحبيب الطبية" - }, - "reviewLiveCareRequest": { - "en": "Review LiveCare Request", - "ar": "مراجعة طلب لايف كير" - }, - "selectedLiveCareType": { - "en": "Selected LiveCare Type", - "ar": "نوع لايف كير المحدد" - }, - "selectLiveCareCallType": { - "en": "Select LiveCare call type", - "ar": "اختر نوع مكالمة لايف كير" - }, - "confirmingLiveCareRequest": { - "en": "Confirming LiveCare request, Please wait...", - "ar": "جاري تأكيد طلب لايف كير، يرجى الانتظار..." - }, - "unknownErrorOccurred": { - "en": "Unknown error occurred...", - "ar": "حدث خطأ غير معروف..." - }, - "liveCarePermissionsMessage": { - "en": "LiveCare requires Camera, Microphone, Location & Notifications permissions to enable virtual consultation between patient & doctor...", - "ar": "يتطلب لايف كير أذونات الكاميرا والميكروفون والموقع والإشعارات لتمكين الاستشارة الافتراضية..." - }, - "liveCarePayment": { - "en": "LiveCare Payment", - "ar": "دفع لايف كير" - }, - "mada": { - "en": "Mada", - "ar": "مدى" - }, - "visaOrMastercard": { - "en": "Visa or Mastercard", - "ar": "فيزا أو ماستركارد" - }, - "tamara": { - "en": "Tamara", - "ar": "تمارا" - }, - "fetchingApplePayDetails": { - "en": "Fetching Apple Pay details, Please wait...", - "ar": "جاري جلب تفاصيل Apple Pay، يرجى الانتظار..." - }, - "liveCarePendingRequest": { - "en": "LiveCare Pending Request", - "ar": "طلب لايف كير قيد الانتظار" - }, - "callLiveCareSupport": { - "en": "Call LiveCare Support", - "ar": "اتصل بدعم لايف كير" - }, - "whatIsWaitingAppointment": { - "en": "What is Waiting Appointment?", - "ar": "ما هو موعد الانتظار؟" - }, - "waitingAppointmentsFeature": { - "en": "The waiting appointments feature allows you to book an appointment while you are inside the hospital building...", - "ar": "تتيح لك ميزة مواعيد الانتظار حجز موعد أثناء تواجدك داخل مبنى المستشفى..." - }, - "appointmentWithDoctorConfirmed": { - "en": "The appointment with the doctor is confirmed, but the time of entry is uncertain.", - "ar": "الموعد مع الطبيب مؤكد، ولكن وقت الدخول غير محدد." - }, - "paymentWithinTenMinutes": { - "en": "Note: You must have to pay within 10 minutes of booking, otherwise your appointment will be cancelled automatically", - "ar": "ملاحظة: يجب عليك الدفع خلال 10 دقائق من الحجز، وإلا سيتم إلغاء موعدك تلقائياً" - }, - "liveLocation": { - "en": "Live Location", - "ar": "الموقع المباشر" - }, - "verifyYourLocationAtHospital": { - "en": "Verify your location to be at hospital to check in", - "ar": "تحقق من موقعك في المستشفى لتسجيل الحضور" - }, - "error": { - "en": "Error", - "ar": "خطأ" - }, - "ensureWithinHospitalLocation": { - "en": "Please ensure you're within the hospital location to perform online check-in.", - "ar": "يرجى التأكد من أنك داخل موقع المستشفى لإجراء تسجيل الحضور عبر الإنترنت." - }, - "nfcNearFieldCommunication": { - "en": "NFC (Near Field Communication)", - "ar": "NFC (الاتصال قريب المدى)" - }, - "scanPhoneViaNFC": { - "en": "Scan your phone via NFC board to check in", - "ar": "امسح هاتفك عبر لوحة NFC لتسجيل الحضور" - }, - "qrCode": { - "en": "QR Code", - "ar": "رمز QR" - }, - "scanQRCodeToCheckIn": { - "en": "Scan QR code with your camera to check in", - "ar": "امسح رمز QR بالكاميرا لتسجيل الحضور" - }, - "processingCheckIn": { - "en": "Processing Check-In...", - "ar": "جاري معالجة تسجيل الحضور..." - }, - "bookingWaitingAppointment": { - "en": "Booking Waiting Appointment, Please wait...", - "ar": "جاري حجز موعد الانتظار، يرجى الانتظار..." - }, - "enterValidIDorIqama": { - "en": "Please enter a valid national ID or file number", - "ar": "يرجى إدخال رقم هوية وطنية أو رقم ملف صالح" - }, - "selectAppointment": { - "en": "Select Appointment", - "ar": "حدد الموعد" - }, - "rebookSameDoctor": { - "en": "Rebook with same doctor", - "ar": "أعد الحجز مع نفس الطبيب" - }, - "queueing": { - "en": "Queueing", - "ar": "قائمة الانتظار" - }, - "inQueue": { - "en": "In Queue", - "ar": "في قائمة الانتظار" - }, - "yourTurn": { - "en": "Your Turn", - "ar": "دورك" - }, - "halaFirstName": { - "en": "Hala {firstName}!!!", - "ar": "هلا {firstName}!!!" - }, - "thankYouForPatience": { - "en": "Thank you for your patience, here is your queue number.", - "ar": "شكراً لصبرك، هذا هو رقم قائمة الانتظار الخاص بك." - }, - "servingNow": { - "en": "Serving Now", - "ar": "يُخدم الآن" - }, - "callForVitalSigns": { - "en": "Call for vital signs", - "ar": "نداء للعلامات الحيوية" - }, - "callForDoctor": { - "en": "Call for Doctor", - "ar": "نداء للطبيب" - }, - "thingsToAskDoctor": { - "en": "Things to ask your doctor today", - "ar": "أشياء تسأل طبيبك عنها اليوم" - }, - "improveOverallHealth": { - "en": "What can I do to improve my overall health?", - "ar": "ماذا يمكنني أن أفعل لتحسين صحتي العامة؟" - }, - "routineScreenings": { - "en": "Are there any routine screenings I should get?", - "ar": "هل هناك أي فحوصات روتينية يجب أن أجريها؟" - }, - "whatIsThisMedicationFor": { - "en": "What is this medication for?", - "ar": "لماذا هذا الدواء؟" - }, - "sideEffectsToKnow": { - "en": "Are there any side effects I should know about?", - "ar": "هل هناك أي آثار جانبية يجب أن أعرفها؟" - }, - "whenFollowUp": { - "en": "When should I come back for a follow-up?", - "ar": "متى يجب أن أعود للمتابعة؟" - }, - "goToHomepage": { - "en": "Go to homepage", - "ar": "الذهاب إلى الصفحة الرئيسية" - }, - "appointmentsList": { - "en": "Appointments List", - "ar": "قائمة المواعيد" - }, - "allAppt": { - "en": "All Appt.", - "ar": "جميع المواعيد" - }, - "upcoming": { - "en": "Upcoming", - "ar": "القادمة" - }, - "completed": { - "en": "Completed", - "ar": "المكتملة" - }, - "noAppointmentsYet": { - "en": "You don't have any appointments yet.", - "ar": "ليس لديك أي مواعيد بعد." - }, - "viewProfile": { - "en": "View Profile", - "ar": "عرض الملف الشخصي" - }, - "choosePreferredHospitalForService": { - "en": "Choose your preferred hospital for the service", - "ar": "اختر المستشفى المفضل لديك للخدمة" - }, - "noHospitalsFound": { - "en": "No hospitals Found", - "ar": "لم يتم العثور على مستشفيات" - }, - "cancelOrderConfirmation": { - "en": "Are you sure you want to cancel this order?", - "ar": "هل أنت متأكد أنك تريد إلغاء هذا الطلب؟" - }, - "orderCancelledSuccessfully": { - "en": "Order has been cancelled successfully", - "ar": "تم إلغاء الطلب بنجاح" - }, - "requestID": { - "en": "Request ID:", - "ar": "معرف الطلب:" - }, - "noCMCOrdersYet": { - "en": "You don't have any CMC orders yet.", - "ar": "ليس لديك أي طلبات فحص شامل بعد." - }, - "cmcOrders": { - "en": "CMC Orders", - "ar": "طلبات الفحص الشامل" - }, - "summary": { - "en": "Summary", - "ar": "الملخص" - }, - "selectedService": { - "en": "Selected Service", - "ar": "الخدمة المحددة" - }, - "requestSubmittedSuccessfully": { - "en": "Your request has been successfully submitted.", - "ar": "تم إرسال طلبك بنجاح." - }, - "hereIsYourRequestNumber": { - "en": "Here is your request #: ", - "ar": "هذا هو رقم طلبك #: " - }, - "pleaseSelectHospitalToContinue": { - "en": "Please select a hospital to continue", - "ar": "يرجى اختيار مستشفى للمتابعة" - }, - "confirmSubmitRequest": { - "en": "Are you sure you want to submit this request?", - "ar": "هل أنت متأكد أنك تريد إرسال هذا الطلب؟" - }, - "pendingOrderWait": { - "en": "You have a pending order. Please wait for it to be processed.", - "ar": "لديك طلب معلق. يرجى الانتظار حتى تتم معالجته." - }, - "noServicesAvailable": { - "en": "No services available", - "ar": "لا توجد خدمات متاحة" - }, - "selectAService": { - "en": "Select a Service", - "ar": "اختر خدمة" - }, - "comprehensiveCheckup": { - "en": "Comprehensive Checkup", - "ar": "الفحص الشامل" - }, - "viewNearestHMGLocations": { - "en": "View your nearest HMG locations", - "ar": "عرض أقرب مواقع مجموعة الحبيب الطبية" - }, - "provideFeedbackOnServices": { - "en": "Provide your feedback on our services", - "ar": "قدم ملاحظاتك على خدماتنا" - }, - "liveChatWithHMG": { - "en": "Live chat option with HMG", - "ar": "خيار الدردشة المباشرة مع مجموعة الحبيب الطبية" - }, - "send": { - "en": "Send", - "ar": "إرسال" - }, - "status": { - "en": "Status", - "ar": "الحالة" - }, - "sendingFeedback": { - "en": "Sending Feedback...", - "ar": "جاري إرسال الملاحظات..." - }, - "selectFeedbackType": { - "en": "Select Feedback Type", - "ar": "اختر نوع الملاحظات" - }, - "loadingAppointmentsList": { - "en": "Loading appointments list...", - "ar": "جاري تحميل قائمة المواعيد..." - }, - "noAppointmentsForFeedback": { - "en": "You do not have any appointments to submit a feedback.", - "ar": "ليس لديك أي مواعيد لتقديم ملاحظات عنها." - }, - "selectedAppointment": { - "en": "Selected Appointment:", - "ar": "الموعد المحدد:" - }, - "subject": { - "en": "Subject", - "ar": "الموضوع" - }, - "enterSubjectHere": { - "en": "Enter subject here", - "ar": "أدخل الموضوع هنا" - }, - "message": { - "en": "Message", - "ar": "الرسالة" - }, - "enterMessageHere": { - "en": "Enter message here", - "ar": "أدخل الرسالة هنا" - }, - "filesSelected": { - "en": "{count} file(s) selected", - "ar": "تم تحديد {count} ملف(ات)" - }, - "otherDetails": { - "en": "Other Details", - "ar": "تفاصيل أخرى" - }, - "medicalReport": { - "en": "Medical Report", - "ar": "التقرير الطبي" - }, - "medicalReportNumber": { - "en": "Medical Report {number}", - "ar": "التقرير الطبي {number}" - }, - "patientIsInsured": { - "en": "Patient Is Insured", - "ar": "المريض مؤمن عليه" - }, - "insuranceDocument": { - "en": "Insurance Document", - "ar": "وثيقة التأمين" - }, - "selectBranch": { - "en": "Select Branch", - "ar": "اختر الفرع" - }, - "patientInformation": { - "en": "Patient Information", - "ar": "معلومات المريض" - }, - "patientLocation": { - "en": "Where the patient is located", - "ar": "أين يتواجد المريض" - }, - "identificationNumber": { - "en": "Identification Number", - "ar": "رقم الهوية" - }, - "enterIdentificationNumber": { - "en": "Enter Identification Number*", - "ar": "أدخل رقم الهوية*" - }, - "patientName": { - "en": "Patient Name*", - "ar": "اسم المريض*" - }, - "referralRequesterInformation": { - "en": "Referral Requester Information", - "ar": "معلومات مقدم طلب الإحالة" - }, - "enterReferralRequesterName": { - "en": "Enter Referral Requester Name*", - "ar": "أدخل اسم مقدم طلب الإحالة*" - }, - "requesterName": { - "en": "Requester Name", - "ar": "اسم مقدم الطلب" - }, - "relationship": { - "en": "Relationship", - "ar": "العلاقة" - }, - "selectRelation": { - "en": "Select Relation", - "ar": "اختر العلاقة" - }, - "otherName": { - "en": "Other Name", - "ar": "اسم آخر" - }, - "otherNameHint": { - "en": "Other Name*", - "ar": "اسم آخر*" - }, - "requesterNameRequired": { - "en": "Referral requester name is required", - "ar": "اسم مقدم طلب الإحالة مطلوب" - }, - "selectRelationshipRequired": { - "en": "Please select a relationship", - "ar": "يرجى اختيار العلاقة" - }, - "otherRelationshipNameRequired": { - "en": "Other relationship name is required", - "ar": "اسم العلاقة الأخرى مطلوب" - }, - "identificationNumberRequired": { - "en": "Identification number is required", - "ar": "رقم الهوية مطلوب" - }, - "patientNameRequired": { - "en": "Patient name is required", - "ar": "اسم المريض مطلوب" - }, - "enterPatientPhoneRequired": { - "en": "Please Enter patient phone number", - "ar": "يرجى إدخال رقم هاتف المريض" - }, - "selectPatientCityRequired": { - "en": "Please select patient city", - "ar": "يرجى اختيار مدينة المريض" - }, - "medicalReportRequired": { - "en": "At least one medical report is required", - "ar": "مطلوب تقرير طبي واحد على الأقل" - }, - "selectBranchRequired": { - "en": "Please select a branch", - "ar": "يرجى اختيار الفرع" - }, - "insuranceDocumentRequired": { - "en": "Insurance document is required for insured patients", - "ar": "وثيقة التأمين مطلوبة للمرضى المؤمن عليهم" - }, - "searchResult": { - "en": "Search Result", - "ar": "نتيجة البحث" - }, - "referralNo": { - "en": "Referral No {number}", - "ar": "رقم الإحالة {number}" - }, - "eReferral": { - "en": "E Referral", - "ar": "الإحالة الإلكترونية" - }, - "referralCreatedSuccessfully": { - "en": "Your Referral has been created Successfully.", - "ar": "تم إنشاء إحالتك بنجاح." - }, - "hereIsYourReferralNumber": { - "en": "Here is your Referral #: ", - "ar": "هذا هو رقم الإحالة الخاص بك #: " - }, - "searchEReferral": { - "en": "Search E-Referral", - "ar": "البحث عن إحالة إلكترونية" - }, - "enterRequiredInfoToSearch": { - "en": "Please enter the required information to search for an e-referral", - "ar": "يرجى إدخال المعلومات المطلوبة للبحث عن إحالة إلكترونية" - }, - "selectPickupDirection": { - "en": "Select Pickup Direction", - "ar": "اختر اتجاه الاستلام" - }, - "selectDirection": { - "en": "Select Direction", - "ar": "اختر الاتجاه" - }, - "toHospital": { - "en": "To Hospital", - "ar": "إلى المستشفى" - }, - "fromHospital": { - "en": "From Hospital", - "ar": "من المستشفى" - }, - "selectWay": { - "en": "Select Way", - "ar": "اختر الطريقة" - }, - "oneWay": { - "en": "One Way", - "ar": "اتجاه واحد" - }, - "twoWay": { - "en": "Two Way", - "ar": "اتجاهين" - }, - "selectPickupDetails": { - "en": "Select Pickup Details", - "ar": "اختر تفاصيل الاستلام" - }, - "pleaseSelectDetailsOfPickup": { - "en": " Please select the details of pickup", - "ar": " يرجى تحديد تفاصيل الاستلام" - }, - "selectDetails": { - "en": "Select Details", - "ar": "اختر التفاصيل" - }, - "work": { - "en": "Work", - "ar": "العمل" - }, - "pick": { - "en": "Pick", - "ar": "استلام" - }, - "insideTheHome": { - "en": "Inside the home", - "ar": "داخل المنزل" - }, - "haveAnyAppointment": { - "en": "Have any appointment", - "ar": "هل لديك أي موعد" - }, - "amountPaidAtHospital": { - "en": "Amount will be paid at the hospital", - "ar": "سيتم دفع المبلغ في المستشفى" - }, - "submitRequest": { - "en": "Submit Request", - "ar": "إرسال الطلب" - }, - "enterPickupLocationManually": { - "en": "Enter Pickup Location Manually", - "ar": "أدخل موقع الاستلام يدوياً" - }, - "enterPickupLocation": { - "en": "Enter Pickup Location", - "ar": "أدخل موقع الاستلام" - }, - "trackingDetails": { - "en": "Tracking Details", - "ar": "تفاصيل التتبع" - }, - "cancelRequest": { - "en": "Cancel Request", - "ar": "إلغاء الطلب" - }, - "shareLocationWhatsapp": { - "en": "Share Your Live Location on Whatsapp", - "ar": "مشاركة موقعك المباشر على واتساب" - }, - "pleaseWaitForCall": { - "en": "Please wait for the call", - "ar": "يرجى انتظار المكالمة" - }, - "toHospitalLower": { - "en": "to hospital", - "ar": "إلى المستشفى" - }, - "contact": { - "en": "Contact", - "ar": "اتصال" - }, - "failed": { - "en": "Failed", - "ar": "فشل" - }, - "confirmationCall": { - "en": "Confirmation Call", - "ar": "مكالمة التأكيد" - }, - "pickupFromHome": { - "en": "Pickup Up from Home", - "ar": "الاستلام من المنزل" - }, - "onTheWayToHospital": { - "en": " On The Way To Hospital", - "ar": " في الطريق إلى المستشفى" - }, - "arrivedAtHospital": { - "en": "Arrived at Hospital", - "ar": "وصل إلى المستشفى" - }, - "orderCancel": { - "en": "Order Cancel", - "ar": "إلغاء الطلب" - }, - "emergencyCheckIn": { - "en": "Emergency Check-In", - "ar": "تسجيل الطوارئ الإلكتروني" - }, - "erOnlineCheckInDescription": { - "en": "This service lets patients register their ER appointment prior to arrival.", - "ar": "تتيح هذه الخدمة للمرضى تسجيل موعد الطوارئ قبل الوصول." - }, - "erOnlineCheckInSuccess": { - "en": "Your ER Online Check-In has been successfully done. Please proceed to the waiting area.", - "ar": "تم تسجيل وصول الطوارئ بنجاح. الرجاء التوجه إلى منطقة الانتظار." - }, - "erOnlineCheckInError": { - "en": "Unexpected error occurred during check-in. Please contact support.", - "ar": "حدث خطأ غير متوقع أثناء عملية التسجيل. يرجى التواصل مع الدعم." - }, - "fetchingHospitalsList": { - "en": "Fetching hospitals list...", - "ar": "جاري جلب قائمة المستشفيات..." - }, - "fetchingPaymentInformation": { - "en": "Fetching payment information...", - "ar": "جاري جلب معلومات الدفع..." - }, - "erVisitDetails": { - "en": "ER Visit Details", - "ar": "تفاصيل زيارة الطوارئ" - }, - "erClinic": { - "en": "ER Clinic", - "ar": "عيادة الطوارئ" - }, - "vatWithAmount": { - "en": "VAT 15% ({amount})", - "ar": "الضريبة 15% ({amount})" - }, - "erAppointmentBookedSuccess": { - "en": "Your appointment has been booked successfully. Please perform Check-In once you arrive at the hospital.", - "ar": "تم حجز موعدك بنجاح. يرجى إتمام إجراءات تسجيل الوصول عند وصولك إلى المستشفى." - }, - "underProcessing": { - "en": "Under processing", - "ar": "قيد المعالجة" - }, - "canceledByPatient": { - "en": "Cancelled by patient", - "ar": "ملغى بواسطة المريض" - }, - "rapidResponseTeam": { - "en": "Rapid Response Team", - "ar": "فريق الاستجابة السريع" - }, - "allFacilities": { - "en": "All Facilities", - "ar": "جميع المرافق" - }, - "selectLocation": { - "en": "Select Location", - "ar": "اختر الموقع" - }, - "pleaseSelectTheLocation": { - "en": "Please select the location", - "ar": "يرجى اختيار الموقع" - }, - "viewLocationGoogleMaps": { - "en": "View Location on Google Maps", - "ar": "عرض الموقع على خرائط جوجل" - }, - "callAmbulance": { - "en": "Call Ambulance", - "ar": "استدعاء سيارة إسعاف" - }, - "requestAmbulanceInEmergency": { - "en": "Request an ambulance in emergency from home or hospital", - "ar": "طلب سيارة إسعاف في حالة الطوارئ من المنزل أو المستشفى" - }, - "confirmation": { - "en": "Confirmation", - "ar": "تأكيد" - }, - "areYouSureYouWantToCallAmbulance": { - "en": "Are you sure you want to call an ambulance?", - "ar": "هل أنت متأكد أنك تريد استدعاء سيارة إسعاف؟" - }, - "getDetailsOfNearestBranch": { - "en": "Get the details of nearest branch including directions", - "ar": "احصل على تفاصيل أقرب فرع بما في ذلك الاتجاهات" - }, - "areYouSureYouWantToCallRRT": { - "en": "Are you sure you want to call Rapid Response Team (RRT)?", - "ar": "هل أنت متأكد أنك تريد استدعاء فريق الاستجابة السريعة (RRT)؟" - }, - "priorERCheckInToSkipLine": { - "en": "Prior ER Check-In to skip the line & payment at the reception.", - "ar": "تسجيل الوصول المسبق في الطوارئ لتجاوز الطابور والدفع في الاستقبال." - }, - "areYouSureYouWantToMakeERCheckIn": { - "en": "Are you sure you want to make ER Check-In?", - "ar": "هل أنت متأكد أنك تريد إجراء تسجيل وصول الطوارئ؟" - }, - "checkingYourERAppointmentStatus": { - "en": "Checking your ER Appointment status...", - "ar": "جاري التحقق من حالة موعد الطوارئ الخاص بك..." - }, - "transportOptions": { - "en": "Transport Options", - "ar": "خيارات النقل" - }, - "selectHospitalForAdvancePayment": { - "en": "Please select the hospital you want to make an advance payment for.", - "ar": "يرجى اختيار المستشفى الذي ترغب في دفع مبلغ مقدم له." - }, - "recharge": { - "en": "Recharge", - "ar": "إعادة الشحن" - }, - "activityLevel": { - "en": "Activity Level", - "ar": "مستوى النشاط" - }, - "selectActivityLevel": { - "en": "Select Activity Level", - "ar": "حدد مستوى النشاط" - }, - "caloriesPerDay": { - "en": "Calories Per Day", - "ar": "السعرات الحرارية في اليوم الواحد" - }, - "dietType": { - "en": "Diet Type", - "ar": "نوع النظام الغذائي" - }, - "selectDietType": { - "en": "Select Diet Type", - "ar": "حدد نوع النظام الغذائي" - }, - "bodyFrameSize": { - "en": "Body Frame Size", - "ar": "حجم إطار الجسم" - }, - "selectBodyFrameSize": { - "en": "Select Body Frame Size", - "ar": "حدد حجم إطار الجسم" - }, - "averageCycleLength": { - "en": "Average Cycle Length (Usually 28 days)", - "ar": "متوسط طول الدورة الشهرية (عادةً 28 يومًا)" - }, - "averageLutealPhase": { - "en": "Average Luteal Phase Length(Usually 14 days)", - "ar": "متوسط طول المرحلة الأصفرية (عادةً 14 يومًا)" - }, - "convert": { - "en": "Convert", - "ar": "يتحول" - }, - "calculate": { - "en": "Calculate", - "ar": "احسب" - }, - "healthCalculators": { - "en": "Health Calculators", - "ar": "حاسبات الصحة" - }, - "healthConverters": { - "en": "Health Converters", - "ar": "محولات الصحة" - }, - "generalHealth": { - "en": "General Health", - "ar": "الصحة العامة" - }, - "relatedToBMICalories": { - "en": "Related To BMI, calories, body fat, etc to stay updated with your health.", - "ar": "متعلق بمؤشر كتلة الجسم والسعرات الحرارية ودهون الجسم وما إلى ذلك للبقاء على اطلاع دائم بصحتك." - }, - "selectCalculator": { - "en": "Select Calculator", - "ar": "اختر الآلة الحاسبة" - }, - "womensHealth": { - "en": "Women's Health", - "ar": "صحة المرأة" - }, - "relatedToPeriodsOvulation": { - "en": "Related To periods, ovulation, pregnancy, and other topics.", - "ar": "متعلق بالدورة الشهرية والإباضة والحمل ومواضيع أخرى." - }, - "bloodSugar": { - "en": "Blood Sugar", - "ar": "سكر الدم" - }, - "trackYourGlucoseLevels": { - "en": "Track your glucose levels, understand trends, and get personalized insights for better health.", - "ar": "تتبع مستويات الجلوكوز لديك، وفهم الاتجاهات، واحصل على رؤى مخصصة لصحة أفضل." - }, - "bloodCholesterol": { - "en": "Blood Cholesterol", - "ar": "كوليسترول الدم" - }, - "monitorCholesterolLevels": { - "en": "Monitor cholesterol levels, assess heart health risks, and take proactive steps for well-being.", - "ar": "راقب مستويات الكوليسترول، وقيّم مخاطر صحة القلب، واتخذ خطوات استباقية للرفاهية." - }, - "triglyceridesFatBlood": { - "en": "Triglycerides Fat Blood", - "ar": "الدهون الثلاثية في الدم" - }, - "understandTriglyceridesImpact": { - "en": "Understand triglycerides' impact on heart health with personalized insights and expert recommendations.", - "ar": "افهم تأثير الدهون الثلاثية على صحة القلب مع رؤى مخصصة وتوصيات الخبراء." - }, - "bmiCalculator": { - "en": "BMI\nCalculator", - "ar": "حاسبة\nمؤشر كتلة الجسم" - }, - "caloriesCalculator": { - "en": "Calories\nCalculator", - "ar": "حاسبة\nالسعرات الحرارية" - }, - "bmrCalculator": { - "en": "BMR\nCalculator", - "ar": "حاسبة\nمعدل الأيض الأساسي" - }, - "idealBodyWeight": { - "en": "Ideal Body\nWeight", - "ar": "الوزن المثالي\nللجسم" - }, - "bodyFatCalculator": { - "en": "Body Fat\nCalculator", - "ar": "حاسبة\nدهون الجسم" - }, - "carbsProteinFat": { - "en": "Carbs\nProtein & Fat", - "ar": "الكربوهيدرات\nالبروتين والدهون" - }, - "ovulationPeriod": { - "en": "Ovulation\nPeriod", - "ar": "فترة\nالإباضة" - }, - "deliveryDueDate": { - "en": "Delivery\nDue Date", - "ar": "تاريخ الولادة\nالمتوقع" - }, - "low": { - "en": "Low", - "ar": "منخفض" - }, - "preDiabetic": { - "en": "Pre-diabetic", - "ar": "ما قبل السكري" - }, - "high": { - "en": "High", - "ar": "مرتفع" - }, - "elevated": { - "en": "Elevated", - "ar": "مرتفع قليلاً" - }, - "recorded": { - "en": "Recorded", - "ar": "مسجل" - }, - "noRecordsYet": { - "en": "No records yet", - "ar": "لا توجد سجلات بعد" - }, - "lastRecord": { - "en": "Last Record", - "ar": "آخر سجل" - }, - "addBloodSugar": { - "en": "Add Blood Sugar", - "ar": "إضافة سكر الدم" - }, - "addBloodPressure": { - "en": "Add Blood Pressure", - "ar": "إضافة ضغط الدم" - }, - "addWeight": { - "en": "Add Weight", - "ar": "إضافة الوزن" - }, - "bloodSugarDataSavedSuccessfully": { - "en": "Blood Sugar Data saved successfully", - "ar": "تم حفظ بيانات سكر الدم بنجاح" - }, - "bloodPressureDataSavedSuccessfully": { - "en": "Blood Pressure Data saved successfully", - "ar": "تم حفظ بيانات ضغط الدم بنجاح" - }, - "weightDataSavedSuccessfully": { - "en": "Weight Data saved successfully", - "ar": "تم حفظ بيانات الوزن بنجاح" - }, - "pleaseWait": { - "en": "Please wait", - "ar": "يرجى الانتظار" - }, - "selectUnit": { - "en": "Select Unit", - "ar": "اختر الوحدة" - }, - "selectMeasureTime": { - "en": "Select Measure Time", - "ar": "اختر وقت القياس" - }, - "selectArm": { - "en": "Select Arm", - "ar": "اختر الذراع" - }, - "enterBloodSugar": { - "en": "Enter Blood Sugar", - "ar": "أدخل سكر الدم" - }, - "enterSystolicValue": { - "en": "Enter Systolic Value", - "ar": "أدخل القيمة الانقباضية" - }, - "enterDiastolicValue": { - "en": "Enter Diastolic Value", - "ar": "أدخل القيمة الانبساطية" - }, - "enterWeight": { - "en": "Enter Weight", - "ar": "أدخل الوزن" - }, - "selectDuration": { - "en": "Select Duration", - "ar": "اختر المدة" - }, - "systolic": { - "en": "Systolic", - "ar": "الانقباضي" - }, - "diastolic": { - "en": "Diastolic", - "ar": "الانبساطي" - }, - "sendReportByEmail": { - "en": "Send Report by Email", - "ar": "إرسال التقرير عبر البريد الإلكتروني" - }, - "enterYourEmailToReceiveReport": { - "en": "Enter your email address to receive the report", - "ar": "أدخل عنوان بريدك الإلكتروني لاستلام التقرير" - }, - "addNewRecord": { - "en": "Add new Record", - "ar": "إضافة سجل جديد" - }, - "healthTrackers": { - "en": "Health Trackers", - "ar": "متتبعات الصحة" - }, - "monitorBloodPressureLevels": { - "en": "Monitor your blood pressure levels, track systolic and diastolic readings, and maintain a healthy heart.", - "ar": "راقب مستويات ضغط الدم لديك، وتتبع القراءات الانقباضية والانبساطية، وحافظ على صحة قلبك." - }, - "trackWeightProgress": { - "en": "Track your weight progress, set goals, and maintain a healthy body mass for overall wellness.", - "ar": "تتبع تقدم وزنك، وضع الأهداف، وحافظ على كتلة جسم صحية من أجل العافية الشاملة." - }, - "bookAppointment": { - "en": "Book Appointment", - "ar": "احجز موعد" - }, - "completeCheckup": { - "en": "Complete Checkup", - "ar": "الفحص الشامل" - }, - "indoorNavigation": { - "en": "Indoor Navigation", - "ar": "الملاحة الداخلية" - }, - "eReferralServices": { - "en": "E-Referral Services", - "ar": "خدمات الإحالة الإلكترونية" - }, - "dailyWaterMonitor": { - "en": "Daily Water Monitor", - "ar": "مراقب الماء اليومي" - }, - "fetchingYourWaterIntakeDetails": { - "en": "Fetching your water intake details.", - "ar": "جاري جلب تفاصيل استهلاك الماء الخاص بك." - }, - "healthCalculatorsServices": { - "en": "Health\nCalculators", - "ar": "حاسبات\nالصحة" - }, - "healthConvertersServices": { - "en": "Health\nConverters", - "ar": "محولات\nالصحة" - }, - "smartWatchesServices": { - "en": "Smart\nWatches", - "ar": "الساعات\nالذكية" - }, - "exploreServices": { - "en": "Explore Services", - "ar": "استكشف الخدمات" - }, - "medicalAndCareServices": { - "en": "Medical & Care Services", - "ar": "الخدمات الطبية والرعاية" - }, - "hmgServices": { - "en": "HMG Services", - "ar": "خدمات مجموعة الحبيب الطبية" - }, - "personalServices": { - "en": "Personal Services", - "ar": "الخدمات الشخصية" - }, - "habibWallet": { - "en": "Habib Wallet", - "ar": "محفظة الحبيب" - }, - "loginToViewWalletBalance": { - "en": "Login to view your wallet balance", - "ar": "سجل الدخول لعرض رصيد محفظتك" - }, - "loginToViewMedicalFile": { - "en": "Login to view your medical file", - "ar": "سجل الدخول لعرض ملفك الطبي" - }, - "addMember": { - "en": "Add Member", - "ar": "إضافة عضو" - }, - "addFamilyMember": { - "en": "Add Family Member", - "ar": "إضافة فرد من العائلة" - }, - "pleaseFillBelowFieldToAddNewFamilyMember": { - "en": "Please fill the below field to add a new family member to your profile", - "ar": "يرجى ملء الحقل أدناه لإضافة فرد جديد من العائلة إلى ملفك الشخصي" - }, - "healthTools": { - "en": "Health Tools", - "ar": "أدوات الصحة" - }, - "supportServices": { - "en": "Support Services", - "ar": "خدمات الدعم" - }, - "virtualTour": { - "en": "Virtual Tour", - "ar": "جولة افتراضية" - }, - "carParking": { - "en": "Car Parking", - "ar": "موقف السيارات" - }, - "latestNews": { - "en": "Latest News", - "ar": "آخر الأخبار" - }, - "hmgContact": { - "en": "HMG Contact", - "ar": "اتصل بمجموعة الحبيب الطبية" - }, - "durationCannotExceed90": { - "en": "Duration can not exceed 90 mins", - "ar": "لا يجوز أن تتجاوز المدة 90 دقيقة" - }, - "unexpectedError": { - "en": "Unexpected Error Occurred", - "ar": "حدث خطأ غير متوقع" - }, - "gettingAmbulanceTransportOption": { - "en": "Getting Ambulance Transport Option", - "ar": "جاري الحصول على خيارات نقل الإسعاف" - }, - "fetchingAppointment": { - "en": "Fetching Appointment", - "ar": "جاري جلب الموعد" - }, - "doYouWantToCancelTheRequest": { - "en": "Do you want to cancel the request", - "ar": "هل تريد إلغاء الطلب" - }, - "cancellingRequest": { - "en": "Cancelling request", - "ar": "جاري إلغاء الطلب" - }, - "fetchingTermsAndConditions": { - "en": "Fetching Terms And Conditions", - "ar": "جاري جلب الشروط والأحكام" - }, - "selectLocationPrescriptionDelivery": { - "en": "Please select the location for prescription delivery", - "ar": "يرجى تحديد موقع توصيل الوصفة الطبية" - }, - "noRadiologyOrders": { - "en": "No Radiology Orders Found", - "ar": "لم يتم العثور على أي طلبات تصوير شعاعي" - }, - "ageIsRequired": { - "en": "Age is required", - "ar": "العمر مطلوب" - }, - "invalidAge": { - "en": "Invalid age", - "ar": "العمر غير صالح" - }, - "ageMustBeBetween11And120": { - "en": "Age must be between 11 and 120", - "ar": "يجب أن يكون العمر بين 11 و 120" - }, - "heightIsRequired": { - "en": "Height is required", - "ar": "الطول مطلوب" - }, - "invalidHeight": { - "en": "Invalid height", - "ar": "الطول غير صالح" - }, - "weightIsRequired": { - "en": "Weight is required", - "ar": "الوزن مطلوب" - }, - "invalidWeight": { - "en": "Invalid weight", - "ar": "الوزن غير صالح" - }, - "timeToDrinkWater": { - "en": "Time to Drink Water! 💧", - "ar": "حان وقت شرب الماء! 💧" - }, - "stayHydratedDrinkWater": { - "en": "Stay hydrated! Drink {amount}ml of water.", - "ar": "ابق رطبًا! اشرب {amount} مل من الماء." - }, - "visitPharmacyOnline": { - "en": "Visit Pharmacy Online", - "ar": "زيارة الصيدلية على الانترنت" - }, - "howAreYouFeelingToday": { - "en": "How are you feeling today?", - "ar": "كيف حالك اليوم؟" - }, - "checkYourSymptomsWithScale": { - "en": "Check your symptoms with this scale", - "ar": "تحقق من أعراضك باستخدام ذا المقياس" - }, - "checkYourSymptoms": { - "en": "Check your symptoms", - "ar": "تحقق من أعراضك" - }, - "noUpcomingAppointmentPleaseBook": { - "en": "You do not have any upcoming appointment. Please book an appointment", - "ar": "ليس لديك أي مواعيد قادمة. يرجى حجز موعد" - }, - "youHaveEROnlineCheckInRequest": { - "en": "You have ER Online Check-In Request", - "ar": "لديك طلب تسجيل وصول عبر الإنترنت للطوارئ" - }, - "quickLinks": { - "en": "Quick Links", - "ar": "روابط سريعة" - }, - "viewMedicalFileLandingPage": { - "en": "View medical file", - "ar": "عرض الملف الطبي" - }, - "immediateLiveCareRequest": { - "en": "Immediate LiveCare Request", - "ar": "طلب لايف كير فوري" - }, - "yourTurnIsAfterPatients": { - "en": "Your turn is after {count} patients.", - "ar": "دورك بعد {count} مريض." - }, - "dontHaveHHCOrders": { - "en": "You don't have any Home Health Care orders yet.", - "ar": "ليس لديك أي أوامر رعاية صحية منزلية حتى الآن." - }, - "hhcOrders": { - "en": "HHC Orders", - "ar": "أوامر الرعاية الصحية المنزلية" - }, - "requestedServices": { - "en": "Requested Services", - "ar": "الخدمات المطلوبة" - }, - "selectServices": { - "en": "Select Services", - "ar": "اختر الخدمات" - }, - "selectedServices": { - "en": "Selected Services", - "ar": "الخدمات المختارة" - }, - "createNewRequest": { - "en": "Create new request", - "ar": "إنشاء طلب جديد" - }, - "youHaveNoPendingRequests": { - "en": "You have no pending requests.", - "ar": "ليس لديك أي طلبات معلقة." - }, - "noInsuranceDataFound": { - "en": "No insurance data found...", - "ar": "لم يتم العثور على بيانات التأمين..." - }, - "noInsuranceUpdateRequest": { - "en": "No insurance update requests found.", - "ar": "لم يتم العثور على أي طلبات لتحديث بيانات التأمين." - }, - "policyNumberInsurancePage": { - "en": "Policy: {number}", - "ar": "الوثيقة: {number}" - }, - "insuranceExpired": { - "en": "Insurance Expired", - "ar": "التأمين منتهي الصلاحية" - }, - "insuranceActive": { - "en": "Insurance Active", - "ar": "التأمين نشط" - }, - "patientCardID": { - "en": "Patient Card ID: {id}", - "ar": "رقم بطاقة المريض: {id}" - }, - "noInsuranceApprovals": { - "en": "You don't have any insurance approvals yet.", - "ar": "لم تحصل على أي موافقات تأمينية حتى الآن." - }, - "noInsuranceWithHMG": { - "en": "You don't have an insurance registered with HMG.", - "ar": "ليس لديك تأمين مسجل لدى مجموعة الحبيب الطبية." - }, - "referenceRange": { - "en": "Reference Range", - "ar": "النطاق المرجعي" - }, - "downloadReport": { - "en": "Download Report", - "ar": "تنزيل التقرير" - }, - "generatingReport": { - "en": "Generating Report, Please wait...", - "ar": "جارٍ إنشاء التقرير، يرجى الانتظار..." - }, - "noLabResults": { - "en": "You don't have any lab results yet.", - "ar": "ليس لديك أي نتائج مختبرية حتى الآن." - }, - "labResultDetails": { - "en": "Lab Result Details", - "ar": "تفاصيل نتائج المختبر" - }, - "resultOf": { - "en": "Result of {date}", - "ar": "نتيجة {date}" - }, - "whatIsThisResult": { - "en": "What is this result?", - "ar": "ما هي هذه النتيجة؟" - }, - "lastTested": { - "en": "Last Tested", - "ar": "آخر اختبار" - }, - "byVisit": { - "en": "By Visit", - "ar": "حسب الزيارة" - }, - "byTest": { - "en": "By Test", - "ar": "حسب التحليل" - }, - "results": { - "en": "results", - "ar": "نتائج" - }, - "viewResults": { - "en": "View Results", - "ar": "عرض النتائج" - }, - "rebook": { - "en": "Rebook", - "ar": "إعادة الحجز" - }, - "noOphthalmologyAppointments": { - "en": "No Ophthalmology appointments found...", - "ar": "لم يتم العثور على أي مواعيد في قسم طب العيون..." - }, - "noVitalSignsRecordedYet": { - "en": "No vital signs recorded yet", - "ar": "لا توجد علامات حيوية مسجلة بعد" - }, - "appointmentsAndVisits": { - "en": "Appointments & visits", - "ar": "المواعيد والزيارات" - }, - "labAndRadiology": { - "en": "Lab & Radiology", - "ar": "المختبر والأشعة" - }, - "activeMedicationsAndPrescriptions": { - "en": "Active Medications & Prescriptions", - "ar": "الأدوية النشطة والوصفات الطبية" - }, - "allPrescriptions": { - "en": "All Prescriptions", - "ar": "جميع الوصفات" - }, - "allMedications": { - "en": "All Medications", - "ar": "جميع الأدوية" - }, - "youDontHaveAnyPrescriptionsYet": { - "en": "You don't have any prescriptions yet.", - "ar": "ليس لديك أي وصفات طبية بعد." - }, - "youDontHaveAnyCompletedVisitsYet": { - "en": "You don't have any completed visits yet", - "ar": "ليس لديك أي زيارات مكتملة بعد" - }, - "others": { - "en": "Others", - "ar": "أخرى" - }, - "allergyInfo": { - "en": "Allergy Info", - "ar": "معلومات الحساسية" - }, - "vaccineInfo": { - "en": "Vaccine Info", - "ar": "معلومات اللقاحات" - }, - "updateInsuranceInfo": { - "en": "Update Insurance", - "ar": "تحديث التأمين" - }, - "myInvoicesList": { - "en": "My Invoices List", - "ar": "قائمة فواتيري" - }, - "ancillaryOrdersList": { - "en": "Ancillary Orders List", - "ar": "قائمة الطلبات المساعدة" - }, - "youDontHaveAnySickLeavesYet": { - "en": "You don't have any sick leaves yet.", - "ar": "ليس لديك أي إجازات مرضية بعد." - }, - "medicalReports": { - "en": "Medical Reports", - "ar": "التقارير الطبية" - }, - "sickLeaveReport": { - "en": "Sick Leave Report", - "ar": "تقرير الإجازة المرضية" - }, - "weightTracker": { - "en": "Weight Tracker", - "ar": "متتبع الوزن" - }, - "askYourDoctor": { - "en": "Ask Your Doctor", - "ar": "اسأل طبيبك" - }, - "internetPairing": { - "en": "Internet Pairing", - "ar": "الاقتران بالإنترنت" - }, - "requested": { - "en": "Requested", - "ar": "مطلوب" - }, - "youDontHaveAnyMedicalReportsYet": { - "en": "You don't have any medical reports yet.", - "ar": "ليس لديك أي تقارير طبية بعد." - }, - "requestMedicalReport": { - "en": "Request medical report", - "ar": "طلب تقرير طبي" - }, - "youDoNotHaveAnyAppointmentsToRequestMedicalReport": { - "en": "You do not have any appointments to request a medical report.", - "ar": "ليس لديك أي مواعيد لطلب تقرير طبي." - }, - "areYouSureYouWantToRequestMedicalReport": { - "en": "Are you sure you want to request a medical report for this appointment?", - "ar": "هل أنت متأكد أنك تريد طلب تقرير طبي لهذا الموعد؟" - }, - "yourMedicalReportRequestSubmittedSuccessfully": { - "en": "Your medical report request has been successfully submitted.", - "ar": "تم إرسال طلب التقرير الطبي بنجاح." - }, - "monthlyHealthSummaryReportDisclaimer": { - "en": "This monthly health summary report reflects the health indicators and analysis results of the latest visits. Please note that this will be sent automatically from the system and it's not considered as a official report so no medical decision should be taken based on it", - "ar": "يعكس تقرير الملخص الصحي الشهري هذا المؤشرات الصحية ونتائج التحليل لأحدث الزيارات. يرجى ملاحظة أن هذا سيتم إرساله تلقائيًا من النظام ولا يعتبر تقريرًا رسميًا لذا لا ينبغي اتخاذ أي قرار طبي بناءً عليه" - }, - "updatingMonthlyReportStatus": { - "en": "Updating Monthly Report Status...", - "ar": "جاري تحديث حالة التقرير الشهري..." - }, - "monthlyReportStatusUpdatedSuccessfully": { - "en": "Monthly Report Status Updated Successfully", - "ar": "تم تحديث حالة التقرير الشهري بنجاح" - }, - "whoCanViewMyMedicalFile": { - "en": "Who can view my medical file?", - "ar": "من يمكنه عرض ملفي الطبي؟" - }, - "acceptedYourRequestToBeYourFamilyMember": { - "en": "{status} your request to be your family member", - "ar": "{status} طلب الانضمام الى أفراد عائلتك" - }, - "canViewYourFile": { - "en": "can view your file", - "ar": "يمكنه عرض ملفك" - }, - "hasARequestPendingToBeYourFamilyMember": { - "en": "has a request {status} to be your family member", - "ar": "لديه طلب {status} ليكون فردًا من عائلتك" - }, - "wantsToAddYouAsTheirFamilyMember": { - "en": "wants to add you as their family member", - "ar": "يرغب في إضافتك كفرد من أفراد العائلة" - }, - "rejectedYourRequestToBeYourFamilyMember": { - "en": "{status} your request to be your family member", - "ar": "{status} طلب الانضمام إلى عائلتك" - }, - "rejectedYourFamilyMemberRequest": { - "en": "{status} your family member request", - "ar": "{status} طلب أحد أفراد عائلتك" - }, - "notAvailable": { - "en": "N/A", - "ar": "غير متاح" - }, - "selectAProfile": { - "en": "Please select a profile", - "ar": "الرجاء تحديد ملف تعريف" - }, - "switchFamilyFile": { - "en": "Switch from the below list of medical file", - "ar": "قم بالتبديل من قائمة الملفات الطبية أدناه" - }, - "medicalFiles": { - "en": "Medical Files", - "ar": "الملفات الطبية" - }, - "addANewFamilyMember": { - "en": "Add a new family member", - "ar": "إضافة فرد جديد من العائلة" - }, - "viewInvoiceDetails": { - "en": "View invoice details", - "ar": "عرض تفاصيل الفاتورة" - }, - "outPatient": { - "en": "OutPatient", - "ar": "مريض خارجي" - }, - "invoiceDetails": { - "en": "Invoice Details", - "ar": "تفاصيل الفاتورة" - }, - "sendingEmailPleaseWait": { - "en": "Sending email, Please wait...", - "ar": "جاري إرسال البريد الإلكتروني، يرجى الانتظار..." - }, - "emailSentSuccessfullyMessage": { - "en": "Email sent successfully.", - "ar": "تم إرسال البريد الإلكتروني بنجاح." - }, - "discount": { - "en": "Discount", - "ar": "خصم" - }, - "paid": { - "en": "Paid", - "ar": "مدفوع" - }, - "fetchingInvoiceDetails": { - "en": "Fetching invoice details, Please wait...", - "ar": "جارٍ جلب تفاصيل الفاتورة، يرجى الانتظار..." - }, - "scanQRCode": { - "en": "Scan QR code", - "ar": "مسح رمز الاستجابة السريعة" - }, - "parkingSlotDetails": { - "en": "Parking Slot Details", - "ar": "تفاصيل موقف السيارة" - }, - "slotNumber": { - "en": "Slot: {code}", - "ar": "رقم الموقف: {code}" - }, - "basement": { - "en": "Basement: {description}", - "ar": "الطابق: {description}" - }, - "parkingDate": { - "en": "Date: {date}", - "ar": "التاريخ: {date}" - }, - "parkedSince": { - "en": "Parked Since: {time}", - "ar": "متوقف منذ: {time}" - }, - "resetDirection": { - "en": "Reset Direction", - "ar": "إعادة تعيين الاتجاه" - }, - "noPrescriptionOrdersYet": { - "en": "You don't have any prescription orders yet.", - "ar": "ليس لديك أي طلبات وصفات طبية حتى الآن." - }, - "fetchingPrescriptionPDFPleaseWait": { - "en": "Fetching prescription PDF, Please wait...", - "ar": "جاري جلب ملف الوصفة الطبية، يرجى الانتظار..." - }, - "ratingValue": { - "en": "Rating: {rating}", - "ar": "التقييم: {rating}" - }, - "downloadPrescription": { - "en": "Download Prescription", - "ar": "تحميل الوصفة الطبية" - }, - "fetchingPrescriptionDetails": { - "en": "Fetching prescription details...", - "ar": "جاري جلب تفاصيل الوصفة الطبية..." - }, - "switchBackFamilyFile": { - "en": "Switch Back To Family File", - "ar": "العودة إلى ملف العائلة" - }, - "profileAndSettings": { - "en": "Profile & Settings", - "ar": "الملف الشخصي والإعدادات" - }, - "quickActions": { - "en": "Quick Actions", - "ar": "إجراءات سريعة" - }, - "notificationsSettings": { - "en": "Notifications Settings", - "ar": "إعدادات الإشعارات" - }, - "touchIDFaceIDServices": { - "en": "Touch ID / Face ID Services", - "ar": "خدمات Touch ID / Face ID" - }, - "personalInformation": { - "en": "Personal Information", - "ar": "المعلومات الشخصية" - }, - "updateEmailAddress": { - "en": "Update Email Address", - "ar": "تحديث عنوان البريد الإلكتروني" - }, - "helpAndSupport": { - "en": "Help & Support", - "ar": "المساعدة والدعم" - }, - "permissionsProfile": { - "en": "Permissions", - "ar": "الأذونات" - }, - "privacyPolicy": { - "en": "Privacy Policy", - "ar": "سياسة الخصوصية" - }, - "deactivateAccount": { - "en": "Deactivate account", - "ar": "إلغاء تنشيط الحساب" - }, - "ageYearsOld": { - "en": "{age} {yearsOld}", - "ar": "{age} {yearsOld}" - }, - "youDontHaveRadiologyOrders": { - "en": "You don't have any radiology results yet.", - "ar": "ليس لديك أي نتائج للأشعة حتى الآن." - }, - "radiologyResult": { - "en": "Radiology Result", - "ar": "نتيجة الأشعة" - }, - "viewRadiologyImage": { - "en": "View Radiology Image", - "ar": "عرض صورة الأشعة" - }, - "rateClinic": { - "en": "Rate Clinic", - "ar": "تقييم العيادة" - }, - "back": { - "en": "Back", - "ar": "رجوع" - }, - "rateDoctor": { - "en": "Rate Doctor", - "ar": "تقييم الطبيب" - }, - "howWasYourLastVisitWithDoctor": { - "en": "How was your last visit with doctor?", - "ar": "كيف كانت زيارتك الأخيرة مع الطبيب؟" - }, - "dateOfBirthSymptoms": { - "en": "What is your Date of Birth?", - "ar": "ما هو تاريخ ميلادك؟" - }, - "genderSymptoms": { - "en": "What is your gender?", - "ar": "ما هو جنسك؟" - }, - "heightSymptoms": { - "en": "How tall are you?", - "ar": "كم طولك؟" - }, - "weightSymptoms": { - "en": "What is your weight?", - "ar": "ما هو وزنك؟" - }, - "femaleGender": { - "en": "Female", - "ar": "أنثى" - }, - "previous": { - "en": "Previous", - "ar": "سابق" - }, - "selectedOrgans": { - "en": "Selected Organs", - "ar": "الهيئات المختارة" - }, - "noOrgansSelected": { - "en": "No organs selected yet", - "ar": "لم يتم تحديد أي أعضاء بعد" - }, - "organSelector": { - "en": "Organ Selector", - "ar": "محدد الأعضاء" - }, - "noPredictionsAvailable": { - "en": "No Predictions available", - "ar": "لا توجد تنبؤات متاحة" - }, - "areYouSureYouWantToRestartOrganSelection": { - "en": "Are you sure you want to restart the organ selection?", - "ar": "هل أنت متأكد أنك تريد إعادة تشغيل اختيار الأعضاء؟" - }, - "possibleConditions": { - "en": "Possible Conditions", - "ar": "الحالات المحتملة" - }, - "pleaseSelectAtLeastOneRiskBeforeProceeding": { - "en": "Please select at least one risk before proceeding", - "ar": "يرجى اختيار عامل خطر واحد على الأقل قبل المتابعة" - }, - "aboveYouSeeCommonRiskFactors": { - "en": "Above you see the most common risk factors. Although /diagnosis may return questions about risk factors, ", - "ar": "أعلاه ترى عوامل الخطر الأكثر شيوعًا. على الرغم من أن /diagnosis قد تعيد أسئلة حول عوامل الخطر، " - }, - "readMore": { - "en": "Read more", - "ar": "اقرأ المزيد" - }, - "riskFactors": { - "en": "Risk Factors", - "ar": "عوامل الخطر" - }, - "noRiskFactorsFound": { - "en": "No risk factors found", - "ar": "لم يتم العثور على عوامل خطر" - }, - "basedOnYourSelectedSymptomsNoRiskFactors": { - "en": "Based on your selected symptoms, no additional risk factors were identified.", - "ar": "بناءً على الأعراض المحددة، لم يتم تحديد عوامل خطر إضافية." - }, - "messageNotification": { - "en": "Message", - "ar": "الرسالة" - }, - "attachedImage": { - "en": "Attached Image", - "ar": "الصورة المرفقة" - }, - "failedToLoadImage": { - "en": "Failed to load image", - "ar": "فشل تحميل الصورة" - }, - "typeNotification": { - "en": "Type", - "ar": "النوع" - }, - "pleaseSelectAtLeastOneOptionBeforeProceeding": { - "en": "Please select at least one option before proceeding", - "ar": "يرجى اختيار خيار واحد على الأقل قبل المتابعة" - }, - "suggestions": { - "en": "Suggestions", - "ar": "الاقتراحات" - }, - "pleaseGoBackAndSelectOrgansFirst": { - "en": "Please go back and select organs first", - "ar": "يرجى العودة واختيار الأعضاء أولاً" - }, - "symptomsSelector": { - "en": "Symptoms Selector", - "ar": "محدد الأعراض" - }, - "possibleSymptomsRelatedTo": { - "en": "Possible symptoms related to", - "ar": "الأعراض المحتملة المتعلقة بـ" - }, - "suggestionAIListDescription": { - "en": "This is a list of symptoms suggested by our AI, based on the information gathered so far during the interview", - "ar": "هذه قائمة بالأعراض المقترحة من قبل الذكاء الاصطناعي، بناءً على المعلومات التي تم جمعها حتى الآن خلال المقابلة" - }, - "analyzing": { - "en": "Analyzing...", - "ar": "جاري التحليل..." - }, - "seekMedicalAdvice": { - "en": "Seek Medical Advice", - "ar": "اطلب المشورة الطبية" - }, - "monitorDescription": { - "en": "No need to seek medical advice. Just keep healthy routine.", - "ar": "لا حاجة لطلب المشورة الطبية. فقط حافظ على روتين صحي." - }, - "seekMedicalAdviceDescription": { - "en": "Not emergency but better to monitor the symptoms.", - "ar": "ليست حالة طوارئ ولكن من الأفضل مراقبة الأعراض." - }, - "emergencyDescription": { - "en": "Need to consult doctor as soon as possible before getting too late.", - "ar": "تحتاج إلى استشارة الطبيب في أقرب وقت ممكن قبل فوات الأوان." - }, - "colorScience": { - "en": "Color Science", - "ar": "دلالات الألوان" - }, - "noNeedToVisitDoctor": { - "en": "No need to visit doctor", - "ar": "لا حاجة لزيارة الطبيب" - }, - "commonSymptom": { - "en": "Common Symptom", - "ar": "الأعراض الشائعة" - }, - "notApplicable": { - "en": "Not Applicable", - "ar": "لا ينطبق" - }, - "emergencyTriage": { - "en": "Emergency", - "ar": "طوارئ" - }, - "emergencyEvidenceDetected": { - "en": "Emergency evidence detected. Please seek medical attention.", - "ar": "تم اكتشاف دليل طوارئ. يرجى طلب العناية الطبية." - }, - "noQuestionItemsAvailable": { - "en": "No question items available", - "ar": "لا توجد عناصر أسئلة متاحة" - }, - "pleaseAnswerAllQuestionsBeforeProceeding": { - "en": "Please answer all questions before proceeding", - "ar": "يرجى الإجابة على جميع الأسئلة قبل المتابعة" - }, - "triage": { - "en": "Triage", - "ar": "الفرز" - }, - "areYouSureYouWantToExitProgress": { - "en": "Are you sure you want to exit? Your progress will be lost.", - "ar": "هل أنت متأكد أنك تريد الخروج؟ سيتم فقدان تقدمك." - }, - "noQuestionAvailable": { - "en": "No question available", - "ar": "لا يوجد سؤال متاح" - }, - "possibleSymptom": { - "en": "Possible symptom: ", - "ar": "عرض محتمل: " - }, - "symptomsCheckerFindingScore": { - "en": "- Symptoms checker finding score", - "ar": "- درجة نتائج فاحص الأعراض" - }, - "notSet": { - "en": "Not set", - "ar": "غير محدد" - }, - "years": { - "en": "Years", - "ar": "سنوات" - }, - "symptomsChecker": { - "en": "Symptoms Checker", - "ar": "فاحص الأعراض" - }, - "helloIsYourInformationUpToDate": { - "en": "Hello {name}, Is your information up to date?", - "ar": "مرحباً {name}، هل معلوماتك محدثة؟" - }, - "noEditAll": { - "en": "No, Edit all", - "ar": "لا، تعديل الكل" - }, - "yesItIs": { - "en": "Yes, It is", - "ar": "نعم، إنها كذلك" - }, - "age": { - "en": "Age", - "ar": "العمر" - }, - "youDontHaveAnyAncillaryOrdersYet": { - "en": "You don't have any ancillary orders yet.", - "ar": "ليس لديك أي طلبات مساعدة بعد." - }, - "invoiceWithNumber": { - "en": "Invoice: {invoiceNo}", - "ar": "الفاتورة: {invoiceNo}" - }, - "queued": { - "en": "Queued", - "ar": "في قائمة الانتظار" - }, - "checkInReady": { - "en": "Check-in Ready", - "ar": "جاهز للتسجيل" - }, - "checkIn": { - "en": "Check In", - "ar": "تسجيل الوصول" - }, - "viewDetails": { - "en": "View Details", - "ar": "عرض التفاصيل" - }, - "selectPaymentMethod": { - "en": "Select Payment Method", - "ar": "اختر طريقة الدفع" - }, - "processingPaymentPleaseWait": { - "en": "Processing payment, Please wait...", - "ar": "جاري معالجة الدفع، يرجى الانتظار..." - }, - "finalizingPaymentPleaseWait": { - "en": "Finalizing payment, Please wait...", - "ar": "جاري إتمام الدفع، يرجى الانتظار..." - }, - "generatingInvoicePleaseWait": { - "en": "Generating invoice, Please wait...", - "ar": "جاري إنشاء الفاتورة، يرجى الانتظار..." - }, - "hereIsYourInvoiceNumber": { - "en": "Here is your invoice #: ", - "ar": "هذا هو رقم فاتورتك #: " - }, - "paymentCompletedSuccessfully": { - "en": "Payment Completed Successfully", - "ar": "تم الدفع بنجاح" - }, - "failedToInitializeApplePay": { - "en": "Failed to initialize Apple Pay. Please try again.", - "ar": "فشل في تهيئة Apple Pay. يرجى المحاولة مرة أخرى." - }, - "cash": { - "en": "Cash", - "ar": "نقدي" - }, - "approved": { - "en": "Approved", - "ar": "موافق عليه" - }, - "approvalRejectedPleaseVisitReceptionist": { - "en": "Approval Rejected - Please visit receptionist", - "ar": "تم رفض الموافقة - يرجى زيارة موظف الاستقبال" - }, - "sentForApproval": { - "en": "Sent For Approval", - "ar": "تم إرساله للموافقة" - }, - "ancillaryOrderDetails": { - "en": "Ancillary Order Details", - "ar": "تفاصيل الطلبات المساندة" - }, - "noProceduresAvailableForSelectedOrder": { - "en": "No Procedures available for the selected order.", - "ar": "لا توجد إجراءات متاحة للطلب المحدد." - }, - "procedures": { - "en": "Procedures", - "ar": "الإجراءات" - }, - "totalAmount": { - "en": "Total Amount", - "ar": "المبلغ الإجمالي" - }, - "covered": { - "en": "Covered", - "ar": "مغطى" - }, - "vatPercent": { - "en": "VAT (15%)", - "ar": "ضريبة القيمة المضافة (15%)" - }, - "proceedToPayment": { - "en": "Proceed to Payment", - "ar": "المتابعة للدفع" - }, - "supportedSmartWatches": { - "en": "Supported Smart Watches", - "ar": "الساعات الذكية المدعومة" - }, - "pleaseMakeSureSamsungWatchConnected": { - "en": "Please make sure that your Samsung Watch is connected to your Phone, is actively synced & updated.", - "ar": "يرجى التأكد من أن ساعة Samsung الخاصة بك متصلة بهاتفك، ومتزامنة ومحدثة بشكل نشط." - }, - "beforeSyncingDataFollowInstructions": { - "en": "Before syncing data, please make sure that you have followed the instructions properly.", - "ar": "قبل مزامنة البيانات، يرجى التأكد من اتباع التعليمات بشكل صحيح." - }, - "viewWatchInstructions": { - "en": "View watch instructions", - "ar": "عرض تعليمات الساعة" - }, - "healthConnectAppNotInstalled": { - "en": "Seems like you do not have Health Connect App installed. Please install it from the Play Store to sync your health data.", - "ar": "يبدو أنه ليس لديك تطبيق Health Connect مثبتًا. يرجى تثبيته من متجر Play لمزامنة بيانات صحتك." - }, - "setTimerOfReminder": { - "en": "Set the timer of reminder", - "ar": "ضبط مؤقت التذكير" - }, - "youHaveAppointmentWithDr": { - "en": "You have appointment with Dr. ", - "ar": "لديك موعد مع د. " - }, - "hours": { - "en": "Hours", - "ar": "ساعات" - }, - "secs": { - "en": "Secs", - "ar": "ثواني" - }, - "noAllergiesDataFound": { - "en": "No allergies data found...", - "ar": "لم يتم العثور على بيانات الحساسية..." - }, - "heartRateDescription": { - "en": "Your heart rate indicates how many times your heart beats per minute", - "ar": "معدل ضربات قلبك يشير إلى عدد المرات التي ينبض فيها قلبك في الدقيقة" - }, - "bloodOxygenDescription": { - "en": "Blood oxygen level indicates how much oxygen your red blood cells are carrying", - "ar": "مستوى الأكسجين في الدم يشير إلى كمية الأكسجين التي تحملها خلايا الدم الحمراء" - }, - "stepsDescription": { - "en": "Number of steps taken throughout the day", - "ar": "عدد الخطوات المتخذة على مدار اليوم" - }, - "caloriesDescription": { - "en": "Calories burned during physical activity", - "ar": "السعرات الحرارية المحروقة أثناء النشاط البدني" - }, - "distanceDescription": { - "en": "Distance covered throughout the day", - "ar": "المسافة المقطوعة على مدار اليوم" - }, - "overview": { - "en": "Overview", - "ar": "نظرة عامة" - }, - "details": { - "en": "Details", - "ar": "التفاصيل" - }, - "healthy": { - "en": "Healthy", - "ar": "صحي" - }, - "warning": { - "en": "Warning", - "ar": "تحذير" - }, - "vitalSignDetails": { - "en": "Vital Sign Details", - "ar": "تفاصيل العلامات الحيوية" - }, - "resultOfNoDate": { - "en": "Result of --", - "ar": "نتيجة --" - }, - "referenceRangeBetween": { - "en": "Reference range: {low} – {high} {unit}", - "ar": "النطاق المرجعي: {low} – {high} {unit}" - }, - "referenceRangeMin": { - "en": "Reference range: ≥ {low} {unit}", - "ar": "النطاق المرجعي: ≥ {low} {unit}" - }, - "referenceRangeMax": { - "en": "Reference range: ≤ {high} {unit}", - "ar": "النطاق المرجعي: ≤ {high} {unit}" - }, - "noHistoryAvailable": { - "en": "No history available", - "ar": "لا يوجد تاريخ متاح" - }, - "bmiDescription": { - "en": "BMI is a measurement based on height and weight that estimates body fat.", - "ar": "مؤشر كتلة الجسم هو قياس يعتمد على الطول والوزن لتقدير دهون الجسم." - }, - "heightDescription": { - "en": "Height is measured in centimeters and is used to calculate BMI and dosage recommendations.", - "ar": "يقاس الطول بالسنتيمتر ويستخدم لحساب مؤشر كتلة الجسم وتوصيات الجرعات." - }, - "weightDescription": { - "en": "Weight helps track overall health, nutrition, and changes over time.", - "ar": "الوزن يساعد في تتبع الصحة العامة والتغذية والتغيرات مع مرور الوقت." - }, - "bloodPressureDescription": { - "en": "Blood pressure reflects the force of blood against artery walls. It is shown as systolic/diastolic.", - "ar": "ضغط الدم يعكس قوة الدم على جدران الشرايين. يظهر كانقباضي/انبساطي." - }, - "temperatureDescription": { - "en": "Body temperature reflects how hot your body is and may change with infection or inflammation.", - "ar": "درجة حرارة الجسم تعكس مدى سخونة جسمك وقد تتغير مع العدوى أو الالتهاب." - }, - "heartRateDescriptionVital": { - "en": "Heart rate refers to the number of heart beats per minute.", - "ar": "معدل ضربات القلب يشير إلى عدد نبضات القلب في الدقيقة." - }, - "respiratoryRateDescription": { - "en": "Respiratory rate is the number of breaths taken per minute.", - "ar": "معدل التنفس هو عدد الأنفاس المأخوذة في الدقيقة." - }, - "bmiAdvice": { - "en": "Maintain a balanced diet and regular activity. If your BMI is high or low, consider consulting your doctor.", - "ar": "حافظ على نظام غذائي متوازن ونشاط منتظم. إذا كان مؤشر كتلة جسمك مرتفعًا أو منخفضًا، فكر في استشارة طبيبك." - }, - "heightAdvice": { - "en": "No action is needed unless your measurement looks incorrect. Update it during your next visit.", - "ar": "لا حاجة لاتخاذ أي إجراء إلا إذا بدا قياسك غير صحيح. قم بتحديثه في زيارتك القادمة." - }, - "weightAdvice": { - "en": "Monitor weight changes. Sudden gain or loss may require medical advice.", - "ar": "راقب تغيرات الوزن. الزيادة أو الخسارة المفاجئة قد تتطلب استشارة طبية." - }, - "bloodPressureAdvice": { - "en": "Keep tracking your blood pressure. High or low readings should be discussed with your doctor.", - "ar": "استمر في تتبع ضغط دمك. يجب مناقشة القراءات المرتفعة أو المنخفضة مع طبيبك." - }, - "temperatureAdvice": { - "en": "If you have a persistent fever or symptoms, contact your healthcare provider.", - "ar": "إذا كان لديك حمى مستمرة أو أعراض، اتصل بمقدم الرعاية الصحية." - }, - "heartRateAdvice": { - "en": "Track your heart rate trends. If you feel dizziness or chest pain, seek medical care.", - "ar": "تتبع اتجاهات معدل ضربات قلبك. إذا شعرت بدوار أو ألم في الصدر، اطلب الرعاية الطبية." - }, - "respiratoryRateAdvice": { - "en": "If you notice shortness of breath or abnormal breathing, seek medical advice.", - "ar": "إذا لاحظت ضيقًا في التنفس أو تنفسًا غير طبيعي، اطلب المشورة الطبية." - }, - "whatShouldIDoNext": { - "en": "What should I do next?", - "ar": "ماذا يجب أن أفعل بعد ذلك؟" - }, - "customizeDrinkCup": { - "en": "Customize your drink cup", - "ar": "قم بتخصيص كوب مشروبك" - }, - "tipsToStayHydrated": { - "en": "Tips to stay hydrated", - "ar": "نصائح للبقاء رطبًا" - }, - "drinkBeforeYouFeelThirsty": { - "en": "Drink before you feel thirsty", - "ar": "اشرب قبل أن تشعر بالعطش" - }, - "keepRefillableBottleNextToYou": { - "en": "Keep a refillable bottle next to you", - "ar": "احتفظ بزجاجة قابلة لإعادة التعبئة بجانبك" - }, - "trackYourDailyIntakeToStayMotivated": { - "en": "Track your daily intake to stay motivated", - "ar": "تتبع كمية الماء اليومية للحفاظ على الحافز" - }, - "chooseSparklingWaterInsteadOfSoda": { - "en": "Choose sparkling water instead of soda", - "ar": "اختر الماء الفوار بدلاً من الصودا" - }, - "switchCup": { - "en": "Switch Cup", - "ar": "تبديل الكوب" - }, - "plainWater": { - "en": "Plain Water", - "ar": "ماء عادي" - }, - "yourGoal": { - "en": "Your Goal", - "ar": "هدفك" - }, - "remaining": { - "en": "Remaining", - "ar": "المتبقي" - }, - "hydrationStatus": { - "en": "Hydration Status", - "ar": "حالة الترطيب" - }, - "areYouSureYouWantToCancelAllWaterReminders": { - "en": "Are you sure you want to cancel all water reminders?", - "ar": "هل أنت متأكد أنك تريد إلغاء جميع تذكيرات الماء؟" - }, - "remindersSet": { - "en": "Reminders Set!", - "ar": "تم ضبط التذكيرات!" - }, - "dailyWaterRemindersScheduledAt": { - "en": "Daily water reminders scheduled at:", - "ar": "تم جدولة تذكيرات الماء اليومية في:" - }, - "waterConsumption": { - "en": "Water Consumption", - "ar": "استهلاك المياه" - }, - "selectNumberOfReminders": { - "en": "Select Number of Reminders", - "ar": "حدد عدد التذكيرات" - }, - "h2oSettings": { - "en": "H20 Settings", - "ar": "إعدادات H20" - }, - "settingsSavedSuccessfully": { - "en": "Settings saved successfully", - "ar": "تم حفظ الإعدادات بنجاح" - }, - "yourName": { - "en": "Your Name", - "ar": "اسمك" - }, - "ageYears": { - "en": "Age (11-120) yrs", - "ar": "العمر (11-120) سنة" - }, - "numberOfRemindersInADay": { - "en": "Number of reminders in a day", - "ar": "عدد التذكيرات في اليوم" - }, - "medications": { - "en": "Medications", - "ar": "الأدوية" - }, - "someRemarksAboutPrescription": { - "en": "some remarks about the prescription will be here", - "ar": "ستجدون هنا بعض الملاحظات حول الوصفة الطبية" - }, - "notifyMeBeforeConsumptionTime": { - "en": "Notify me before the consumption time", - "ar": "أبلغني قبل وقت الاستهلاك" - }, - "noMedicationsToday": { - "en": "No medications today", - "ar": "لا أدوية اليوم" - }, - "reminders": { - "en": "Reminders", - "ar": "تذكيرات" - }, - "reminderAddedToCalendar": { - "en": "Reminder added to calendar ✅", - "ar": "تمت إضافة تذكير إلى التقويم ✅" - }, - "errorWhileSettingCalendar": { - "en": "Error while setting calendar: {error}", - "ar": "حدث خطأ أثناء ضبط التقويم:{error}" - }, - "instructions": { - "en": "Instructions", - "ar": "التعليمات" - }, - "requests": { - "en": "Requests", - "ar": "الطلبات" - }, - "thisWeek": { - "en": "This Week", - "ar": "هذا الأسبوع" - }, - "lastMonth": { - "en": "Last Month", - "ar": "الشهر الماضي" - }, - "lastSixMonths": { - "en": "Last 6 Months", - "ar": "آخر 6 أشهر" - }, - "selectTime": { - "en": "Select Time", - "ar": "حدد الوقت" - }, - "pleaseWaitYouWillBeCalledForVitalSigns": { - "en": "Please wait! you will be called for vital signs", - "ar": "يرجى الانتظار! سيتم استدعاؤك لقياس العلامات الحيوية" - }, - "pleaseVisitRoomForVitalSigns": { - "en": "Please visit Room {roomNumber} for vital signs", - "ar": "يرجى زيارة الغرفة {roomNumber} لقياس العلامات الحيوية" - }, - "pleaseVisitRoomToTheDoctor": { - "en": "Please visit Room {roomNumber} to the Doctor", - "ar": "يرجى زيارة الغرفة {roomNumber} لمقابلة الطبيب" - }, - "erOnlineCheckInRequest": { - "en": "ER Online Check-In Request", - "ar": "طلب تسجيل الوصول عبر الإنترنت لقسم الطوارئ" - }, - "indoor": { - "en": "Indoor", - "ar": "داخلي" - }, - "navigation": { - "en": "Navigation", - "ar": "الملاحة" - }, - "health": { - "en": "Health", - "ar": "الصحة" - }, - "calculators": { - "en": "Calculators", - "ar": "الحاسبات" - }, - "converters": { - "en": "Converters", - "ar": "المحولات" - }, - "guide": { - "en": "Guide", - "ar": "الدليل" - }, - "liveCareServiceDesc": { - "en": "Get medical advice with a specialist doctor Via a video call", - "ar": "احصل على استشارة طبية من طبيب متخصص عبر مكالمة فيديو" - }, - "bloodGroup": { - "en": "Blood: {bloodType}", - "ar": "فصيلة الدم: {bloodType}" - }, - "medicalServices": { - "en": "Medical Services", - "ar": "الخدمات الطبية" - }, - "insuranceAndPayments": { - "en": "Insurance & Payments", - "ar": "التأمين والمدفوعات" - }, - "trackerAndOthers": { - "en": "Tracker & Others", - "ar": "المتتبع وأخرى" - }, - "bmi": { - "en": "BMI", - "ar": "مؤشر كتلة الجسم" - }, - "yesPleaseINeedHelp": { - "en": "Yes, Please I need help", - "ar": "نعم، من فضلك أريد المساعدة" - }, - "aiOverView": { - "en": "AI Overview", - "ar": "AI ملخص" - }, - "generateAiAnalysis": { - "en": "Generate AI analysis for this order", - "ar": "قم بإجراء تحليل لهذا الطلب AI" - }, - "aiAnalysis": { - "en": "AI Analysis", - "ar": "AI تحليل" - }, - "prediction": { - "en": "Prediction", - "ar": "تنبؤ" - }, - "prevention": { - "en": "Prevention", - "ar": "وقاية" - }, - "disclaimer": { - "en": "Disclaimer", - "ar": "تنصل" - }, - "thisAboveInfo": { - "en": "The above information is generated by AI based on your lab results and is intended for informational purposes only. It should not be considered a medical diagnosis or treatment plan. Always consult with your healthcare provider for personalized medical advice and before making any health-related decisions.", - "ar": "المعلومات المذكورة أعلاه مُولّدة بواسطة AI بناءً على نتائج تحاليلك المخبرية، وهي لأغراض إعلامية فقط. لا ينبغي اعتبارها تشخيصًا طبيًا أو خطة علاجية. استشر طبيبك دائمًا للحصول على نصيحة طبية مُخصصة قبل اتخاذ أي قرارات تتعلق بصحتك." - }, - "aiDisclaimer": { - "en": "Your lab result data will be securely shared with our AI Analyzer for analysis. This helps provide personalized health insights. Do you want to proceed?", - "ar": "سيتم مشاركة بيانات نتائج تحاليلك المخبرية بشكل آمن مع خدمة الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في تقديم رؤى صحية مُخصصة. هل ترغب في المتابعة؟" - }, - "consent": { - "en": "Consent", - "ar": "موافقة" - }, - "bmiNormalDescription": { - "en": "Your BMI is within the healthy range. Continue a balanced diet, regular physical activity, and routine checkups to maintain good health. Monitor any significant changes over time.", - "ar": "مؤشر كتلة جسمك ضمن المعدل الصحي. استمر في اتباع نظام غذائي متوازن، وممارسة النشاط البدني بانتظام، وإجراء الفحوصات الدورية للحفاظ على صحة جيدة. راقب أي تغييرات ملحوظة مع مرور الوقت." - }, - "bmiUnderweightDescription": { - "en": "BMI suggests you are underweight. Consider increasing calorie intake with nutrient-dense foods, include resistance training to build muscle, and consult a healthcare professional to check for underlying causes.", - "ar": "يشير مؤشر كتلة الجسم إلى أنك تعاني من نقص الوزن. لذا، يُنصح بزيادة السعرات الحرارية المتناولة من خلال تناول الأطعمة الغنية بالعناصر الغذائية، وممارسة تمارين المقاومة لبناء العضلات، واستشارة أخصائي رعاية صحية للتحقق من وجود أسباب كامنة." - }, - "bmiOverweightDescription": { - "en": "BMI suggests overweight. It is advised to aim for gradual, sustainable weight loss through moderate calorie reduction, regular physical activity, and healthy food choices. Consult your doctor before making any major lifestyle changes.", - "ar": "يشير مؤشر كتلة الجسم إلى زيادة الوزن. لذا، يُنصح بالسعي إلى إنقاص الوزن تدريجياً وبشكل مستدام من خلال تقليل السعرات الحرارية بشكل معتدل، وممارسة النشاط البدني بانتظام، واختيار الأطعمة الصحية. استشر طبيبك قبل إجراء أي تغييرات جذرية في نمط حياتك." - }, - "caloriesMaintenanceDescription": { - "en": "Estimated daily calories to maintain your current weight based on your activity level and metabolic rate. Use this as a baseline: slightly increase for muscle gain or slightly decrease for gradual weight loss. Monitor progress and adjust every 2–4 weeks.", - "ar": "السعرات الحرارية اليومية المُقدَّرة للحفاظ على وزنك الحالي بناءً على مستوى نشاطك ومعدل الأيض لديك. استخدم هذه الكمية كخط أساس: زدها قليلاً لزيادة الكتلة العضلية، أو قللها قليلاً لإنقاص الوزن تدريجياً. تابع تقدمك وعدّل الخطة كل أسبوعين إلى أربعة أسابيع." - }, - "caloriesModerateDeficitDescription": { - "en": "A moderate calorie reduction plan designed for steady, sustainable weight loss (typically 0.25 to 0.5 kg per week). Combine with resistance training and adequate protein to preserve muscle mass. Avoid sharp calorie drops and consult a professional if you have medical conditions.", - "ar": "نظام غذائي معتدل لتقليل السعرات الحرارية مصمم لإنقاص الوزن بشكل ثابت ومستدام (عادةً من 0.25 إلى 0.5 كيلوغرام أسبوعيًا). يُنصح بدمجه مع تمارين المقاومة وتناول كمية كافية من البروتين للحفاظ على الكتلة العضلية. تجنب التخفيضات الحادة في السعرات الحرارية واستشر طبيبًا مختصًا إذا كنت تعاني من أي حالة صحية." - }, - "caloriesAggressiveDeficitDescription": { - "en": "A large calorie reduction that may produce faster weight loss but can be hard to sustain and increase risk of nutrient deficiencies, fatigue, or muscle loss. Not recommended long-term; seek guidance from a healthcare or nutrition professional before continuing.", - "ar": "يؤدي خفض السعرات الحرارية بشكل كبير إلى فقدان الوزن بشكل أسرع، ولكنه قد يصعب الاستمرار عليه ويزيد من خطر نقص العناصر الغذائية والإرهاق وفقدان الكتلة العضلية. لا يُنصح باتباعه على المدى الطويل؛ استشر طبيبًا أو أخصائي تغذية قبل الاستمرار." - }, - "bodyFatEssentialDescription": { - "en": "Your body fat percentage is in the essential/athletic range. This level is typical for athletes and indicates very low body fat. While this may be optimal for performance, ensure you maintain adequate nutrition and hormone function. Consult a healthcare professional if you experience fatigue, hormonal issues, or other health concerns.", - "ar": "نسبة الدهون في جسمك ضمن النطاق الأساسي/الرياضي. هذا المستوى شائع لدى الرياضيين ويشير إلى انخفاض نسبة الدهون في الجسم. مع أن هذا قد يكون مثاليًا للأداء، تأكد من الحفاظ على تغذية سليمة ووظائف هرمونية متوازنة. استشر طبيبًا إذا شعرت بالتعب، أو واجهت مشاكل هرمونية، أو أي مخاوف صحية أخرى." - }, - "bodyFatFitnessDescription": { - "en": "Your body fat percentage is in the fitness range. This indicates a healthy level of body fat associated with good physical conditioning. Maintain your current lifestyle habits including regular exercise and balanced nutrition to sustain this healthy range.", - "ar": "نسبة الدهون في جسمك ضمن النطاق الصحي. وهذا يدل على مستوى صحي من الدهون في الجسم يرتبط بلياقة بدنية جيدة. حافظ على نمط حياتك الحالي، بما في ذلك ممارسة الرياضة بانتظام واتباع نظام غذائي متوازن، للحفاظ على هذا المستوى الصحي." - }, - "bodyFatAverageDescription": { - "en": "Your body fat percentage is in the average/acceptable range. This is considered a healthy range for general population. To improve body composition, consider incorporating strength training, cardiovascular exercise, and a balanced diet. Focus on gradual, sustainable changes for long-term health.", - "ar": "نسبة الدهون في جسمك ضمن المعدل الطبيعي/المقبول، وهي نسبة تُعتبر صحية لعموم الناس. لتحسين تكوين جسمك، يُنصح بممارسة تمارين القوة، وتمارين القلب والأوعية الدموية، واتباع نظام غذائي متوازن. ركّز على التغييرات التدريجية والمستدامة للحفاظ على صحتك على المدى الطويل." - }, - "bodyFatObeseDescription": { - "en": "Your body fat percentage is above the recommended healthy range. This may increase health risks including cardiovascular disease, diabetes, and joint problems. Consider consulting a healthcare provider or registered dietitian to develop a personalized plan that includes balanced nutrition, regular physical activity, and lifestyle modifications for sustainable weight management.", - "ar": "نسبة الدهون في جسمك أعلى من المعدل الصحي الموصى به. قد يزيد هذا من المخاطر الصحية، بما في ذلك أمراض القلب والأوعية الدموية، والسكري، ومشاكل المفاصل. يُنصح باستشارة طبيب أو أخصائي تغذية معتمد لوضع خطة علاجية شخصية تشمل التغذية المتوازنة، والنشاط البدني المنتظم، وتعديلات نمط الحياة لتحقيق إدارة مستدامة للوزن." - }, - "bmrNormalDescription": { - "en": "Your Basal Metabolic Rate (BMR) is within the expected range for your profile. BMR is the energy your body needs at rest to maintain vital functions (breathing, circulation, temperature). Use this value as the baseline for estimating total daily energy needs by applying an activity multiplier. Maintain a balanced diet and regular physical activity to support metabolic health.", - "ar": "معدل الأيض الأساسي لديك ضمن النطاق المتوقع لحالتك. معدل الأيض الأساسي هو الطاقة التي يحتاجها جسمك في حالة الراحة للحفاظ على وظائفه الحيوية (التنفس، الدورة الدموية، درجة الحرارة). استخدم هذه القيمة كأساس لتقدير إجمالي احتياجاتك اليومية من الطاقة من خلال تطبيق مُعامل النشاط. حافظ على نظام غذائي متوازن وممارسة النشاط البدني بانتظام لدعم صحة التمثيل الغذائي." - }, - "bmrLowDescription": { - "en": "Your BMR is lower than typical for your profile. Possible causes include lower lean muscle mass, age-related metabolic decline, or metabolic adaptation from prolonged calorie restriction. Consider focusing on resistance training to build/maintain muscle, ensure adequate protein and micronutrient intake, and consult a healthcare professional if this is unexpected.", - "ar": "معدل الأيض الأساسي لديك أقل من المعدل الطبيعي لحالتك. تشمل الأسباب المحتملة انخفاض كتلة العضلات، أو تراجع التمثيل الغذائي المرتبط بالتقدم في السن، أو التكيف الأيضي الناتج عن تقييد السعرات الحرارية لفترة طويلة. يُنصح بالتركيز على تمارين المقاومة لبناء العضلات والحفاظ عليها، والتأكد من تناول كميات كافية من البروتين والمغذيات الدقيقة، واستشارة أخصائي رعاية صحية إذا كان هذا الأمر غير متوقع." - }, - "bmrHighDescription": { - "en": "Your BMR is higher than average for your profile. This can reflect greater lean mass, younger age, or a naturally higher metabolic rate, meaning you burn more energy at rest. Use this information to tailor calorie targets: higher needs for maintenance or muscle gain, moderate deficit for weight loss. Seek medical advice if you notice rapid unexplained changes.", - "ar": "معدل الأيض الأساسي لديك أعلى من المتوسط ​​بالنسبة لحالتك. قد يعكس هذا زيادة في كتلة العضلات، أو صغر السن، أو ارتفاع معدل الأيض لديك بشكل طبيعي، مما يعني أنك تحرق طاقة أكبر أثناء الراحة. استخدم هذه المعلومات لتحديد احتياجاتك من السعرات الحرارية: احتياجات أعلى للحفاظ على الوزن أو بناء العضلات، ونقص معتدل في السعرات الحرارية لإنقاص الوزن. استشر طبيبك إذا لاحظت أي تغيرات سريعة غير مبررة." - }, - "ibwAtTargetDescription": { - "en": "Your weight is at the ideal target. Maintain your current habits — balanced diet and regular activity — to keep this.", - "ar": "وزنك في النطاق المثالي. حافظ على عاداتك الحالية — نظام غذائي متوازن ونشاط بدني منتظم — للاستمرار على هذا المستوى." - }, - "ibwBelowTargetDescription": { - "en": "You are below the ideal weight by {kg} kg. Aim to gradually increase weight with a modest calorie surplus, nutrient-dense foods, and resistance training.", - "ar": "أنتِ أقل من الوزن المثالي بمقدار {kg} كجم. يُنصح بزيادة الوزن تدريجيًا من خلال فائضٍ بسيط في السعرات الحرارية، وتناول أطعمة غنية بالعناصر الغذائية، مع ممارسة تمارين المقاومة." - }, - "ibwAboveTargetDescription": { - "en": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight reduction through a moderate calorie deficit, increased activity, and balanced nutrition.", - "ar": "أنتِ أعلى من الوزن المثالي بمقدار {kg} كجم. يُنصح باتباع خفضٍ تدريجي ومستدام للوزن من خلال عجزٍ معتدل في السعرات الحرارية، وزيادة مستوى النشاط البدني، واتباع تغذية متوازنة." - }, - "ibwCloseToRangeDescription": { - "en": "Your weight is close to the ideal range. Maintain a balanced diet and regular activity; follow personalized advice from a healthcare professional if needed.", - "ar": "وزنك قريب من النطاق المثالي. حافظ على نظام غذائي متوازن ونشاط بدني منتظم، مع اتباع إرشادات شخصية من مختص صحي عند الحاجة." - }, - "ibwUnderweightDescription": { - "en": "You are below the ideal weight by {kg} kg. Focus on increasing calorie intake with nutrient-dense foods, prioritize protein and resistance training to build healthy mass, and consider consulting a healthcare professional.", - "ar": "أنت أقل من الوزن المثالي بمقدار {kg} كجم. ركّز على زيادة السعرات الحرارية من خلال أطعمة غنية بالعناصر الغذائية، وأعط الأولوية للبروتين وتمارين المقاومة لبناء كتلة صحية، مع اتباع إرشادات شخصية من مختص صحي." - }, - "ibwUnderweightGenericDescription": { - "en": "You appear underweight compared to the ideal. Consider increasing calorie intake with nutrient-dense foods and resistance training; seek professional guidance if needed.", - "ar": "يبدو أنكِ أقل من الوزن المثالي. يُنصح بزيادة السعرات الحرارية من خلال أطعمة غنية بالعناصر الغذائية وممارسة تمارين المقاومة؛ مع الحصول على استشارة مختص صحي عند الحاجة." - }, - "ibwOverweightDescription": { - "en": "You are above the ideal weight by {kg} kg. Aim for a gradual, sustainable weight loss strategy — moderate calorie deficit, regular physical activity, and balanced nutrition. Consult a professional before major changes.", - "ar": "أنت أعلى من الوزن المثالي بمقدار {kg} كجم. يُنصح باتباع استراتيجية تدريجية ومستدامة لفقدان الوزن — من خلال عجزٍ معتدل في السعرات الحرارية، وممارسة نشاط بدني منتظم، وتغذية متوازنة. يُفضّل استشارة مختص صحي قبل إجراء تغييرات كبيرة." - }, - "ibwOverweightGenericDescription": { - "en": "You appear above the ideal weight. Consider a gradual, sustainable calorie deficit combined with activity and balanced nutrition; consult a professional if needed.", - "ar": "يبدو أنك أعلى من الوزن المثالي. يُنصح باتباع عجزٍ تدريجي ومستدام في السعرات الحرارية مع ممارسة النشاط البدني واتباع تغذية متوازنة؛ مع الحصول على استشارة مختص صحي عند الحاجة." - }, - "dietVeryLowCarbsDescription": { - "en": "Very low‑carb (ketogenic) approach: minimal carbohydrates, higher fat and moderate protein. May support rapid weight loss and improved blood sugar control for some, but can be hard to sustain and may cause nutrient gaps. Monitor hydration/electrolytes and consult a professional for long‑term use.", - "ar": "نهج منخفض الكربوهيدرات جدًا (الكيتوني): تقليل الكربوهيدرات إلى الحد الأدنى مع زيادة الدهون وبروتين معتدل. قد يساعد على فقدان الوزن بسرعة وتحسين التحكم في سكر الدم لدى بعض الأشخاص، لكنه قد يكون صعب الاستمرار عليه وقد يسبب نقصًا في بعض العناصر الغذائية. يجب مراقبة الترطيب ، والحصول على استشارة مختص صحي عند استخدامه لفترة طويلة." - }, - "dietLowCarbsDescription": { - "en": "Low‑carb, higher‑protein plan: reduced carbohydrates with increased protein to support satiety and muscle maintenance. Helpful for weight management and glycemic control when balanced with vegetables and healthy fats. Ensure adequate fiber and micronutrients.", - "ar": "خطة منخفضة الكربوهيدرات وعالية البروتين: تقليل الكربوهيدرات مع زيادة البروتين لدعم الشعور بالشبع والحفاظ على الكتلة العضلية. مفيدة لإدارة الوزن وضبط سكر الدم عند موازنتها مع الخضروات والدهون الصحية. احرص على الحصول على كمية كافية من الألياف والعناصر الدقيقة (الفيتامينات والمعادن)." - }, - "dietModerateCarbsDescription": { - "en": "Moderate carbohydrate intake with balanced protein and fats: provides steady energy for daily activity and exercise while allowing flexibility. Suitable for many people aiming for sustainable weight management and performance.", - "ar": "تناول معتدل للكربوهيدرات مع توازن في البروتين والدهون: يوفر طاقة مستقرة للأنشطة اليومية والتمارين مع قدر من المرونة. مناسب لكثير من الأشخاص الذين يسعون لإدارة وزن مستدامة وتحسين الأداء." - }, - "dietUSDAGuidelinesDescription": { - "en": "USDA‑based balanced pattern: emphasizes fruits, vegetables, whole grains, lean proteins, and limited added sugars and saturated fats. Evidence‑based framework for general health, nutrient adequacy, and chronic disease prevention.", - "ar": "نمط متوازن مستند إلى (USDA): يركز على الفواكه والخضروات والحبوب الكاملة والبروتينات قليلة الدهن، مع الحد من السكريات المضافة والدهون المشبعة. يُعد إطارًا قائمًا على الأدلة لدعم الصحة العامة، وكفاية العناصر الغذائية، والوقاية من الأمراض المزمنة." - }, - "dietZoneDietDescription": { - "en": "Zone Diet (~40% carbs / 30% protein / 30% fat): emphasizes hormonal balance and portion control. May improve body composition and energy for some, but requires planning; personalize with a nutrition professional.", - "ar": "حمية الزون (~40٪ كربوهيدرات / 30٪ بروتين / 30٪ دهون): تركز على التوازن الهرموني وضبط الحصص الغذائية. قد تُحسّن تركيب الجسم ومستوى الطاقة لدى بعض الأشخاص، لكنها تتطلب تخطيطًا جيدًا؛ ويُفضّل تخصيصها بالتعاون مع مختص تغذية." - }, - "contextDependent": { - "en": "Context Dependent", - "ar": "يعتمد السياق" - }, - "calculatedValue": { - "en": "Calculated Value", - "ar": "القيمة المحسوبة" - }, - "calculationFormula": { - "en": "Calculation Formula", - "ar": "صيغة الحساب" - }, - "confirmYourLocation": { - "en": "Confirm your location", - "ar": "قم بتأكيد موقعك" - }, - "confirmYourLocationDesc": { - "en": "Please confirm your current location to show appropriate directions.", - "ar": "يرجى تأكيد موقعك الحالي لعرض الاتجاهات المناسبة." - }, - "insideHospital": { - "en": "I am inside the hospital", - "ar": "أنا داخل المستشفى" - }, - "outsideHospital": { - "en": "I am outside the hospital", - "ar": "أنا خارج المستشفى" - }, - "servicePriceList": { - "en": "Service Price List", - "ar": "قائمة أسعار الخدمات" - }, - "servicePriceListDesc": { - "en": "The service price list below shows the fees for health services provided to patients on a cash payment basis. Regarding services covered by insurance, insurance coverage will be applied, eligibility verified, and co-payment percentages calculated according to the terms of the insurance policy and the approved benefit schedule for each insurance company.", - "ar": "توضح قائمة أسعار الخدمات أدناه رسوم الخدمات الصحية المقدمة للمرضى بنظام الدفع النقدي. أما فيما يتعلق بالخدمات المشمولة بالتأمين، فسيتم تطبيق التغطية التأمينية والتحقق من الأهلية واحتساب نسب التحمل وفقًا لشروط وثيقة التأمين وجدول المنافع المعتمد لكل شركة تأمين." - }, - "servicePriceListRights": { - "en": "The patient is entitled to a free follow-up within 14 days of the first visit", - "ar": "يحق للمريض الحصول على متابعة مجانية في غضون 14 يومًا من الزيارة الأولى" - }, - "serviceName": { - "en": "Service Name", - "ar": "اسم الخدمة" - }, - "noFreeSlot": { - "en": "There are no appointments available on the selected date. Please choose another date or try again later.", - "ar": "لا توجد مواعيد متاحة في التاريخ المحدد. يرجى اختيار تاريخ آخر أو إعادة المحاولة لاحقاً." - }, - "noThanksIKnowTheClinic": { - "en": "No, thanks. I know the clinic.", - "ar": "لا، شكراً. أنا أعرف العيادة." - }, - "unableToSendOTP": { - "en": "Unable to send One-Time Password", - "ar": "تعذر إرسال رمز التحقق لمرة واحدة" - }, - "loadingAIAnalysis": { - "en": "Analysing your lab results, Please be patient and let the AI do the magic, This might take some time.", - "ar": "جارٍ تحليل نتائج المختبر، يرجى التحلي بالصبر والسماح للذكاء الاصطناعي بالقيام بالمهمة، قد يستغرق هذا بعض الوقت." - }, - "symptoms": { - "en": "Symptoms", - "ar": "أعراض" - }, - "insuranceInActive": { - "en": "Insurance Inactive", - "ar": "التأمين غير نشط" - }, - "insuranceInActiveContactSupport": { - "en": "You have a valid insurance but it is currently inactive in HMG. Please contact HMG customer support to activate it.", - "ar": "لديك تأمين ساري المفعول، ولكنه غير مُفعّل حاليًا في مجموعة حبيب الطبية. يُرجى التواصل مع خدمة عملاء مجموعة حبيب الطبية." - }, - "updateAppNow": { - "en": "Update App Now", - "ar": "تحديث التطبيق الآن" - }, - "Dr": { - "en": "Dr.", - "ar": "الدكتور." - }, - "reschedulingAppo": { - "en": "Rescheduling Appointment, Please wait...", - "ar": "إعادة جدولة الموعد، يرجى الانتظار..." - }, - "invalidEligibility": { - "en": "You cannot make online payment because you are not eligible to use the provided service.", - "ar": "لا يمكنك إجراء الدفع عبر الإنترنت لأنك غير مؤهل لاستخدام الخدمة المقدمة." - }, - "invalidInsurance": { - "en": "You cannot make online payment because you do not have a valid insurance.", - "ar": "لا يمكنك إجراء الدفع عبر الإنترنت لأنه ليس لديك تأمين صالح." - }, - "continueCash": { - "en": "Continue as cash", - "ar": "متابعة الدفع نقدًا" - }, - "timeFor": { - "en": "Time For", - "ar": "الوقت" - }, - "hmgPolicies": { - "en": "HMG Policies", - "ar": "سياسات مجموعة الحبيب الطبية" - }, - "darkMode": { - "en": "Dark Mode", - "ar": "المظهر الداكن" - }, - "generateAiAnalysisResult": { - "en": "Generate AI analysis for this result", - "ar": "قم بإجراء تحليل لهذا المختبر AI" - } -} \ No newline at end of file diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 99f62aad..6ad7b7ce 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -234,6 +234,7 @@ class ApiConsts { // ************ static values for Api **************** static final double appVersionID = 20.3; + // static final double appVersionID = 50.7; static final int appChannelId = 3; static final String appIpAddress = "10.20.10.20"; @@ -777,8 +778,7 @@ var GET_CUSTOMER_INFO = "VerifyCustomer"; //Pharmacy -var GET_PHARMACY_CATEGORISE = - 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0'; +var GET_PHARMACY_CATEGORISE = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0'; var GET_OFFERS_CATEGORISE = 'discountcategories'; var GET_OFFERS_PRODUCTS = 'offerproducts/'; var GET_CATEGORISE_PARENT = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id='; diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 3f9327fc..93901497 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -258,12 +258,12 @@ extension EmailValidator on String { style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 17.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'), ); - Widget toText18({Color? color, FontWeight? weight, bool isBold = false, bool isCenter = false, int? maxlines, TextOverflow? textOverflow}) => Text( + Widget toText18({Color? color, FontWeight? weight, bool isBold = false, bool isCenter = false, int? maxlines, TextOverflow? textOverflow, bool isEnglishOnly = false,}) => Text( maxLines: maxlines, textAlign: isCenter ? TextAlign.center : null, this, overflow: textOverflow, - style: TextStyle(fontSize: 18.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4), + style: TextStyle(fontSize: 18.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4, fontFamily: (isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),), ); Widget toText19({Color? color, bool isBold = false}) => Text( diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart index 4dd103b8..676a299a 100644 --- a/lib/features/book_appointments/book_appointments_view_model.dart +++ b/lib/features/book_appointments/book_appointments_view_model.dart @@ -536,6 +536,7 @@ class BookAppointmentsViewModel extends ChangeNotifier { clearSearchFilters(); getFiltersFromDoctorList(); _groupDoctorsList(); + setIsNearestAppointmentSelected(true); notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 2ba5dbc4..73a18102 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1578,5 +1578,6 @@ abstract class LocaleKeys { static const hmgPolicies = 'hmgPolicies'; static const darkMode = 'darkMode'; static const generateAiAnalysisResult = 'generateAiAnalysisResult'; + static const ratings = 'ratings'; } diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index 89a18bf5..210de466 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -161,9 +161,13 @@ class AppointmentCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - (isLoading ? 'John Doe' : "${patientAppointmentHistoryResponseModel.doctorTitle} ${patientAppointmentHistoryResponseModel.doctorNameObj!}") - .toText16(isBold: true, maxlines: 1) - .toShimmer2(isShow: isLoading), + Row( + children: [ + (isLoading ? 'Dr' : "${patientAppointmentHistoryResponseModel.doctorTitle}").toText16(isBold: true, maxlines: 1), + (isLoading ? 'John Doe' : " ${patientAppointmentHistoryResponseModel.doctorNameObj!.truncate(20)}") + .toText16(isBold: true, maxlines: 1, isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? "John Doe")) + ], + ).toShimmer2(isShow: isLoading), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index 298e8732..ef8c76ee 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -16,11 +16,7 @@ import 'dart:ui' as ui; class AppointmentDoctorCard extends StatelessWidget { const AppointmentDoctorCard( - {super.key, - required this.patientAppointmentHistoryResponseModel, - required this.onRescheduleTap, - required this.onCancelTap, - required this.onAskDoctorTap, this.renderWidgetForERDisplay = false}); + {super.key, required this.patientAppointmentHistoryResponseModel, required this.onRescheduleTap, required this.onCancelTap, required this.onAskDoctorTap, this.renderWidgetForERDisplay = false}); final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; final VoidCallback onRescheduleTap; @@ -82,7 +78,7 @@ class AppointmentDoctorCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - patientAppointmentHistoryResponseModel.doctorNameObj!.toText16(isBold: true), + patientAppointmentHistoryResponseModel.doctorNameObj!.toText16(isBold: true, isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? "")), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, @@ -107,20 +103,16 @@ class AppointmentDoctorCard extends StatelessWidget { richText: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang( DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false, - )}".toText10(isEnglishOnly: true), + )}" + .toText10(isEnglishOnly: true), ), ), AppCustomChipWidget( labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), - icon: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! - ? AppAssets.walkin_appointment_icon - : AppAssets.small_livecare_icon, + icon: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppAssets.walkin_appointment_icon : AppAssets.small_livecare_icon, iconColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : Colors.white, - labelText: patientAppointmentHistoryResponseModel.isLiveCareAppointment! - ? LocaleKeys.livecare.tr(context: context) - : LocaleKeys.walkin.tr(context: context), - backgroundColor: - !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.greyColor : AppColors.successColor, + labelText: patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? LocaleKeys.livecare.tr(context: context) : LocaleKeys.walkin.tr(context: context), + backgroundColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.greyColor : AppColors.successColor, textColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : Colors.white, ), ], @@ -166,20 +158,20 @@ class AppointmentDoctorCard extends StatelessWidget { : !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? CustomButton( text: LocaleKeys.rebookSameDoctor.tr(), - onPressed: () { - onRescheduleTap(); - }, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 12.f, - fontWeight: FontWeight.w500, - borderRadius: 12.r, - padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), - height: 40.h, - icon: AppAssets.rebook_appointment_icon, - iconColor: AppColors.blackColor, - iconSize: 14.h, + onPressed: () { + onRescheduleTap(); + }, + backgroundColor: AppColors.greyColor, + borderColor: AppColors.greyColor, + textColor: AppColors.blackColor, + fontSize: 12.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), + height: 40.h, + icon: AppAssets.rebook_appointment_icon, + iconColor: AppColors.blackColor, + iconSize: 14.h, ) : SizedBox.shrink(); } else { diff --git a/lib/presentation/book_appointment/doctor_profile_page.dart b/lib/presentation/book_appointment/doctor_profile_page.dart index 9fb6ee1d..fdd1af0f 100644 --- a/lib/presentation/book_appointment/doctor_profile_page.dart +++ b/lib/presentation/book_appointment/doctor_profile_page.dart @@ -102,7 +102,7 @@ class DoctorProfilePage extends StatelessWidget { children: [ Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), SizedBox(height: 16.h), - "Ratings".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + LocaleKeys.ratings.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate .toString() .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), @@ -123,7 +123,7 @@ class DoctorProfilePage extends StatelessWidget { children: [ Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), SizedBox(height: 16.h), - "Reviews".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + LocaleKeys.reviews.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate .toString() .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), diff --git a/lib/presentation/book_appointment/select_doctor_page.dart b/lib/presentation/book_appointment/select_doctor_page.dart index 1fc9d9ad..7947fa05 100644 --- a/lib/presentation/book_appointment/select_doctor_page.dart +++ b/lib/presentation/book_appointment/select_doctor_page.dart @@ -46,7 +46,7 @@ class _SelectDoctorPageState extends State { void initState() { _scrollController = ScrollController(); scheduleMicrotask(() { - bookAppointmentsViewModel.setIsNearestAppointmentSelected(false); + bookAppointmentsViewModel.setIsNearestAppointmentSelected(true); if (bookAppointmentsViewModel.isLiveCareSchedule) { bookAppointmentsViewModel.getLiveCareDoctorsList(); } else { diff --git a/lib/presentation/book_appointment/widgets/appointment_calendar.dart b/lib/presentation/book_appointment/widgets/appointment_calendar.dart index 9124a16b..57a045cc 100644 --- a/lib/presentation/book_appointment/widgets/appointment_calendar.dart +++ b/lib/presentation/book_appointment/widgets/appointment_calendar.dart @@ -90,59 +90,64 @@ class _AppointmentCalendarState extends State { // ), SizedBox( height: 350.h, - child: SfCalendar( - controller: _calendarController, - minDate: DateTime.now(), - showNavigationArrow: true, - headerHeight: 60.h, - headerStyle: CalendarHeaderStyle( - backgroundColor: AppColors.scaffoldBgColor, - textAlign: TextAlign.start, - textStyle: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.primaryRedColor, fontFamily: "Poppins"), - ), - viewHeaderStyle: ViewHeaderStyle( - backgroundColor: AppColors.scaffoldBgColor, - dayTextStyle: TextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.textColor), - ), - view: CalendarView.month, - todayHighlightColor: Colors.transparent, - todayTextStyle: TextStyle(color: AppColors.textColor, fontWeight: FontWeight.bold), - selectionDecoration: ShapeDecoration( - color: AppColors.transparent, - shape: SmoothRectangleBorder( - borderRadius: BorderRadius.circular(10.r), - smoothness: 1, - side: BorderSide(color: AppColors.primaryRedColor, width: 1.5), + child: Localizations.override( + context: context, + locale: const Locale('en'), + child: SfCalendar( + controller: _calendarController, + minDate: DateTime.now(), + showNavigationArrow: true, + headerHeight: 60.h, + headerStyle: CalendarHeaderStyle( + backgroundColor: AppColors.scaffoldBgColor, + textAlign: TextAlign.start, + textStyle: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.primaryRedColor, fontFamily: "Poppins"), ), - ), - cellBorderColor: AppColors.transparent, - dataSource: MeetingDataSource(_getDataSource()), - monthCellBuilder: (context, details) => Padding( - padding: EdgeInsets.all(12.h), - child: details.date.day.toString().toText14( - isCenter: true, - color: details.date == _calendarController.selectedDate ? AppColors.primaryRedColor : AppColors.textColor, - ), - ), - monthViewSettings: MonthViewSettings( - dayFormat: "EEE", - appointmentDisplayMode: MonthAppointmentDisplayMode.indicator, - showTrailingAndLeadingDates: false, - appointmentDisplayCount: 1, - monthCellStyle: MonthCellStyle( - textStyle: TextStyle(fontSize: 19.f), + viewHeaderStyle: ViewHeaderStyle( + backgroundColor: AppColors.scaffoldBgColor, + dayTextStyle: TextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.textColor, fontFamily: "Poppins"), ), + view: CalendarView.month, + todayHighlightColor: Colors.transparent, + todayTextStyle: TextStyle(color: AppColors.textColor, fontWeight: FontWeight.bold, fontFamily: "Poppins"), + selectionDecoration: ShapeDecoration( + color: AppColors.transparent, + shape: SmoothRectangleBorder( + borderRadius: BorderRadius.circular(10.r), + smoothness: 1, + side: BorderSide(color: AppColors.primaryRedColor, width: 1.5), + ), + ), + cellBorderColor: AppColors.transparent, + dataSource: MeetingDataSource(_getDataSource()), + monthCellBuilder: (context, details) => Padding( + padding: EdgeInsets.all(12.h), + child: details.date.day.toString().toText14( + isCenter: true, + color: details.date == _calendarController.selectedDate ? AppColors.primaryRedColor : AppColors.textColor, + isEnglishOnly: true, + ), + ), + monthViewSettings: MonthViewSettings( + dayFormat: "EEE", + appointmentDisplayMode: MonthAppointmentDisplayMode.indicator, + showTrailingAndLeadingDates: false, + appointmentDisplayCount: 1, + monthCellStyle: MonthCellStyle( + textStyle: TextStyle(fontSize: 19.f), + ), + ), + onTap: (CalendarTapDetails details) { + _calendarController.selectedDate = details.date; + _onDaySelected(details.date!); + }, ), - onTap: (CalendarTapDetails details) { - _calendarController.selectedDate = details.date; - _onDaySelected(details.date!); - }, ), ), SizedBox(height: 10.h), Transform.translate( offset: const Offset(0.0, -10.0), - child: selectedDateDisplay.toText16(weight: FontWeight.w500), + child: selectedDateDisplay.toText16(weight: FontWeight.w500, isEnglishOnly: true), ), //TODO: Add Next Day Span here dayEvents.isNotEmpty @@ -153,23 +158,23 @@ class _AppointmentCalendarState extends State { child: Wrap( direction: Axis.horizontal, alignment: WrapAlignment.start, - spacing: 6.h, - runSpacing: 6.h, - children: List.generate( - dayEvents.length, // Generate a large number of items to ensure scrolling - (index) => TimeSlotChip( - label: dayEvents[index].isoTime!, - isSelected: index == selectedButtonIndex, - onTap: () { - setState(() { - selectedButtonIndex = index; - selectedTime = dayEvents[index].isoTime!; - }); - }, + spacing: 6.h, + runSpacing: 6.h, + children: List.generate( + dayEvents.length, // Generate a large number of items to ensure scrolling + (index) => TimeSlotChip( + label: dayEvents[index].isoTime!, + isSelected: index == selectedButtonIndex, + onTap: () { + setState(() { + selectedButtonIndex = index; + selectedTime = dayEvents[index].isoTime!; + }); + }, + ), + ), + ), ), - ), - ), - ), ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noFreeSlot.tr(context: context)), @@ -179,7 +184,7 @@ class _AppointmentCalendarState extends State { isDisabled: dayEvents.isEmpty, onPressed: () async { if (appState.isAuthenticated) { - if(selectedTime == LocaleKeys.waitingAppointment.tr(context: context)){ + if (selectedTime == LocaleKeys.waitingAppointment.tr(context: context)) { bookAppointmentsViewModel.setWaitingAppointmentProjectID(bookAppointmentsViewModel.selectedDoctor.projectID!); bookAppointmentsViewModel.setWaitingAppointmentDoctor(bookAppointmentsViewModel.selectedDoctor); @@ -351,26 +356,20 @@ class TimeSlotChip extends StatelessWidget { side: BorderSide(color: isSelected ? AppColors.warningColorYellow : AppColors.borderOnlyColor.withOpacity(0.2), width: 1), ), ), - child: label.toText12( - color: isSelected ? AppColors.whiteColor : Colors.black87, - fontWeight: FontWeight.w500, - ), + child: label.toText12(color: isSelected ? AppColors.whiteColor : Colors.black87, fontWeight: FontWeight.w500, isEnglishOnly: true), ) : Container( padding: EdgeInsets.symmetric(horizontal: 14.h, vertical: 8.h), decoration: ShapeDecoration( - color: AppColors.whiteColor, - shape: SmoothRectangleBorder( - borderRadius: BorderRadius.circular(8.h), - smoothness: 1, - side: BorderSide(color: isSelected ? AppColors.primaryRedColor : AppColors.borderOnlyColor.withOpacity(0.2), width: 1), - ), - ), - child: label.toText12( - color: isSelected ? AppColors.primaryRedColor : AppColors.textColor, - fontWeight: FontWeight.w500, - ), - ), + color: AppColors.whiteColor, + shape: SmoothRectangleBorder( + borderRadius: BorderRadius.circular(8.h), + smoothness: 1, + side: BorderSide(color: isSelected ? AppColors.primaryRedColor : AppColors.borderOnlyColor.withOpacity(0.2), width: 1), + ), + ), + child: label.toText12(color: isSelected ? AppColors.primaryRedColor : AppColors.textColor, fontWeight: FontWeight.w500, isEnglishOnly: true), + ), ); } } diff --git a/lib/presentation/book_appointment/widgets/doctor_card.dart b/lib/presentation/book_appointment/widgets/doctor_card.dart index 6eecf5f8..02b2e55d 100644 --- a/lib/presentation/book_appointment/widgets/doctor_card.dart +++ b/lib/presentation/book_appointment/widgets/doctor_card.dart @@ -109,7 +109,7 @@ class DoctorCard extends StatelessWidget { : doctorsListResponseModel.speciality!.first) : "") .toString() - .toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, maxLine: 2) + .toText12(fontWeight: FontWeight.w500, color: AppColors.textColor, maxLine: 2, isEnglishOnly: true) .toShimmer2(isShow: isLoading), ), SizedBox(width: 6.w), diff --git a/lib/presentation/home/widgets/welcome_widget.dart b/lib/presentation/home/widgets/welcome_widget.dart index 4ccc126a..21f01c8b 100644 --- a/lib/presentation/home/widgets/welcome_widget.dart +++ b/lib/presentation/home/widgets/welcome_widget.dart @@ -39,7 +39,7 @@ class WelcomeWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - Flexible(child: name.toText16(weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1, height: 1)), + Flexible(child: name.toText16(weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1, height: 1, isEnglishOnly: true)), Icon(Icons.keyboard_arrow_down, size: 20, color: AppColors.greyTextColor), ], ), diff --git a/lib/presentation/insurance/widgets/patient_insurance_card.dart b/lib/presentation/insurance/widgets/patient_insurance_card.dart index 531341b5..2d3ba9ea 100644 --- a/lib/presentation/insurance/widgets/patient_insurance_card.dart +++ b/lib/presentation/insurance/widgets/patient_insurance_card.dart @@ -52,7 +52,7 @@ class PatientInsuranceCard extends StatelessWidget { children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.4, - child: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true, textOverflow: TextOverflow.clip)), + child: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true, textOverflow: TextOverflow.clip, isEnglishOnly: true)), LocaleKeys.policyNumber.tr(namedArgs: {'number': insuranceCardDetailsModel.insurancePolicyNo ?? ''}, context: context).toText12(isBold: true, color: AppColors.lightGrayColor), ], ), diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index 15461659..bb2c3034 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -1 +1 @@ -import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_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/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ CustomButton( text: LocaleKeys.byClinic.tr(context: context), onPressed: () { labViewModel.setIsSortByClinic(true); }, backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12.f, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), SizedBox(width: 8.h), CustomButton( text: LocaleKeys.byHospital.tr(context: context), onPressed: () { labViewModel.setIsSortByClinic(false); }, backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrdersViewList.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.patientLabOrdersViewList.length, itemBuilder: (context, index) { final group = labViewModel.patientLabOrdersViewList[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget(labelText: "${group.length} ${LocaleKeys.results.tr(context: context)}"), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Text( labViewModel.isSortByClinic ? (group.first.clinicDescription ?? 'Unknown') : (group.first.projectName ?? 'Unknown'), style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group[index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), ), AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), ), AppCustomChipWidget( labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), ), ], ), // Row( // children: [ // CustomButton( // text: ("Order No: ".needTranslation + order.orderNo!), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), // SizedBox(height: 8.h), // Row( // children: [ // CustomButton( // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), SizedBox(height: 12.h), Row( children: [ Expanded(flex: 2, child: SizedBox()), // Expanded( // flex: 1, // child: Container( // height: 40.h, // width: 40.w, // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // color: AppColors.textColor, // borderRadius: 12, // ), // child: Padding( // padding: EdgeInsets.all(12.h), // child: Transform.flip( // flipX: _appState.isArabic(), // child: Utils.buildSvgWithAssets( // icon: AppAssets.forward_arrow_icon_small, // iconColor: AppColors.whiteColor, // fit: BoxFit.contain, // ), // ), // ), // ).onPress(() { // model.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }), // ) Expanded( flex: 2, child: CustomButton( icon: AppAssets.view_report_icon, iconColor: AppColors.primaryRedColor, iconSize: 16.h, text: LocaleKeys.viewResults.tr(context: context), onPressed: () { labViewModel.currentlySelectedPatientOrder = order; labProvider.getPatientLabResultByHospital(order); labProvider.getPatientSpecialResult(order); Navigator.of(context).push( CustomPageRoute(page: LabResultByClinic(labOrder: order)), ); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ) ], ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.length)) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.indexedCharacterForUniqueTest, details: labViewModel.uniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file +import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_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/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; import 'dart:ui' as ui; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ CustomButton( text: LocaleKeys.byClinic.tr(context: context), onPressed: () { labViewModel.setIsSortByClinic(true); }, backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12.f, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), SizedBox(width: 8.h), CustomButton( text: LocaleKeys.byHospital.tr(context: context), onPressed: () { labViewModel.setIsSortByClinic(false); }, backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrdersViewList.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.patientLabOrdersViewList.length, itemBuilder: (context, index) { final group = labViewModel.patientLabOrdersViewList[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget(labelText: "${group.length} ${LocaleKeys.results.tr(context: context)}"), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Text( labViewModel.isSortByClinic ? (group.first.clinicDescription ?? 'Unknown') : (group.first.projectName ?? 'Unknown'), style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group[index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), isEnglishOnly: true, ), Directionality( textDirection: ui.TextDirection.ltr, child: AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), isEnglishOnly: true, )), AppCustomChipWidget( labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), ), ], ), // Row( // children: [ // CustomButton( // text: ("Order No: ".needTranslation + order.orderNo!), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), // SizedBox(height: 8.h), // Row( // children: [ // CustomButton( // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), SizedBox(height: 12.h), Row( children: [ Expanded(flex: 2, child: SizedBox()), // Expanded( // flex: 1, // child: Container( // height: 40.h, // width: 40.w, // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // color: AppColors.textColor, // borderRadius: 12, // ), // child: Padding( // padding: EdgeInsets.all(12.h), // child: Transform.flip( // flipX: _appState.isArabic(), // child: Utils.buildSvgWithAssets( // icon: AppAssets.forward_arrow_icon_small, // iconColor: AppColors.whiteColor, // fit: BoxFit.contain, // ), // ), // ), // ).onPress(() { // model.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }), // ) Expanded( flex: 2, child: CustomButton( icon: AppAssets.view_report_icon, iconColor: AppColors.primaryRedColor, iconSize: 16.h, text: LocaleKeys.viewResults.tr(context: context), onPressed: () { labViewModel.currentlySelectedPatientOrder = order; labProvider.getPatientLabResultByHospital(order); labProvider.getPatientSpecialResult(order); Navigator.of(context).push( CustomPageRoute(page: LabResultByClinic(labOrder: order)), ); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ) ], ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.length)) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.indexedCharacterForUniqueTest, details: labViewModel.uniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index f288af66..89843ea7 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -85,6 +85,8 @@ import '../../features/active_prescriptions/active_prescriptions_view_model.dart import '../prescriptions/prescription_detail_page.dart'; import 'widgets/medical_file_appointment_card.dart'; +import 'dart:ui' as ui; + class MedicalFilePage extends StatefulWidget { bool showBackIcon; @@ -784,11 +786,15 @@ class _MedicalFilePageState extends State { runSpacing: 4.w, children: [ AppCustomChipWidget(labelText: prescriptionVM.patientPrescriptionOrders[index].clinicDescription!), - AppCustomChipWidget( - icon: AppAssets.doctor_calendar_icon, - labelText: DateUtil.formatDateToDate( - DateUtil.convertStringToDate(prescriptionVM.patientPrescriptionOrders[index].appointmentDate), - false, + Directionality( + textDirection: ui.TextDirection.ltr, + child: AppCustomChipWidget( + icon: AppAssets.doctor_calendar_icon, + labelText: DateUtil.formatDateToDate( + DateUtil.convertStringToDate(prescriptionVM.patientPrescriptionOrders[index].appointmentDate), + false, + ), + isEnglishOnly: true, ), ), ], diff --git a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart index 73dd1652..4c1a72b7 100644 --- a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart +++ b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart @@ -74,7 +74,7 @@ class MedicalFileAppointmentCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - (patientAppointmentHistoryResponseModel.doctorNameObj ?? "").toText14(isBold: true, maxlines: 1).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading), + (patientAppointmentHistoryResponseModel.doctorNameObj ?? "").toText14(isBold: true, maxlines: 1, isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? "")).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading), (patientAppointmentHistoryResponseModel.clinicName ?? "") .toText12(maxLine: 1, fontWeight: FontWeight.w500, color: AppColors.greyTextColor) .toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading), diff --git a/lib/presentation/prescriptions/prescription_detail_page.dart b/lib/presentation/prescriptions/prescription_detail_page.dart index b9b5b789..ec2cd1a0 100644 --- a/lib/presentation/prescriptions/prescription_detail_page.dart +++ b/lib/presentation/prescriptions/prescription_detail_page.dart @@ -23,6 +23,8 @@ import 'package:open_filex/open_filex.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'dart:ui' as ui; + class PrescriptionDetailPage extends StatefulWidget { PrescriptionDetailPage({super.key, required this.prescriptionsResponseModel, required this.isFromAppointments}); @@ -124,11 +126,15 @@ class _PrescriptionDetailPageState extends State { spacing: 4.h, runSpacing: 4.h, children: [ - AppCustomChipWidget( - icon: AppAssets.doctor_calendar_icon, - labelText: DateUtil.formatDateToDate( - DateUtil.convertStringToDate(widget.prescriptionsResponseModel.appointmentDate), false), - labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: 8.h), + Directionality( + textDirection: ui.TextDirection.ltr, + child: AppCustomChipWidget( + icon: AppAssets.doctor_calendar_icon, + labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.prescriptionsResponseModel.appointmentDate), false), + isEnglishOnly: true + , + labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: 8.h), + ), ), AppCustomChipWidget( labelText: widget.prescriptionsResponseModel.clinicDescription!, @@ -225,9 +231,7 @@ class _PrescriptionDetailPageState extends State { hasShadow: true, ), child: CustomButton( - text: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! - ? LocaleKeys.resendOrder.tr(context: context) - : LocaleKeys.prescriptionDeliveryError.tr(context: context), + text: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? LocaleKeys.resendOrder.tr(context: context) : LocaleKeys.prescriptionDeliveryError.tr(context: context), onPressed: () async { if (widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported!) { LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPrescriptionDetails.tr(context: context)); @@ -239,16 +243,14 @@ class _PrescriptionDetailPageState extends State { }, backgroundColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.greyF7Color, borderColor: AppColors.successColor.withOpacity(0.01), - textColor: - widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? Colors.white : AppColors.textColor.withOpacity(0.35), + textColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? Colors.white : AppColors.textColor.withOpacity(0.35), fontSize: 16, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 50.h, icon: AppAssets.prescription_refill_icon, - iconColor: - widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? Colors.white : AppColors.textColor.withOpacity(0.35), + iconColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? Colors.white : AppColors.textColor.withOpacity(0.35), iconSize: 20.h, ).paddingSymmetrical(24.h, 24.h), ), diff --git a/lib/presentation/prescriptions/prescription_item_view.dart b/lib/presentation/prescriptions/prescription_item_view.dart index 38b96d37..c5cd50c2 100644 --- a/lib/presentation/prescriptions/prescription_item_view.dart +++ b/lib/presentation/prescriptions/prescription_item_view.dart @@ -47,7 +47,7 @@ class PrescriptionItemView extends StatelessWidget { fit: BoxFit.fill, ).toShimmer2(isShow: isLoading).circle(100), Expanded( - child: (isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].itemDescription!).toText16(isBold: true, maxlines: 2).toShimmer2(isShow: isLoading), + child: (isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].itemDescription!).toText16(isBold: true, maxlines: 2, isEnglishOnly: true).toShimmer2(isShow: isLoading), ), ], ).paddingSymmetrical(16.h, 0.h), @@ -78,7 +78,9 @@ class PrescriptionItemView extends StatelessWidget { children: [ Utils.buildSvgWithAssets(icon: AppAssets.prescription_remarks_icon, width: 18.h, height: 18.h), SizedBox(width: 9.h), - Expanded(child: "${LocaleKeys.remarks.tr(context: context)}: ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].remarks!}".toText10(isBold: true)), + Expanded( + child: "${LocaleKeys.remarks.tr(context: context)} ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].remarks!}".toText10(isBold: true, isEnglishOnly: true), + ), ], ).paddingSymmetrical(16.h, 0.h), SizedBox(height: 14.h), @@ -95,7 +97,7 @@ class PrescriptionItemView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ LocaleKeys.setReminder.tr(context: context).toText13(isBold: true), - "Notify me before the consumption time".toText10(color: AppColors.textColorLight), + "Notify me before the consumption time".toText10(color: AppColors.textColorLight, isEnglishOnly: true), ], ).toShimmer2(isShow: isLoading).expanded, Switch( diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart index cd507d41..4eb297d5 100644 --- a/lib/presentation/prescriptions/prescriptions_list_page.dart +++ b/lib/presentation/prescriptions/prescriptions_list_page.dart @@ -24,6 +24,8 @@ import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; +import 'dart:ui' as ui; + class PrescriptionsListPage extends StatefulWidget { const PrescriptionsListPage({super.key}); @@ -213,8 +215,11 @@ class _PrescriptionsListPageState extends State { spacing: 6.h, runSpacing: 6.h, children: [ - AppCustomChipWidget( - labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false), + Directionality( + textDirection: ui.TextDirection.ltr, + child: AppCustomChipWidget( + labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false), isEnglishOnly: true, + ), ), AppCustomChipWidget( labelText: model.isSortByClinic ? prescription.name ?? "" : prescription.clinicDescription!, diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index 2bd41f06..27f74826 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -378,7 +378,7 @@ class FamilyCardWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - "${profile.patientName}".toText18(isBold: true, weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1), + "${profile.patientName}".toText18(isBold: true, weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1, isEnglishOnly: true), AppCustomChipWidget( icon: AppAssets.file_icon, labelText: "${LocaleKeys.fileNo.tr(context: context)}: ${profile.responseId}", diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart index a07face1..81aef5c7 100644 --- a/lib/presentation/radiology/radiology_orders_page.dart +++ b/lib/presentation/radiology/radiology_orders_page.dart @@ -24,6 +24,8 @@ import 'package:provider/provider.dart'; import '../../features/radiology/radiology_view_model.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'dart:ui' as ui; + class RadiologyOrdersPage extends StatefulWidget { const RadiologyOrdersPage({super.key}); @@ -289,10 +291,13 @@ class _RadiologyOrdersPageState extends State { AppCustomChipWidget( labelText: (order.description ?? '').toString(), ), - AppCustomChipWidget( - labelText: DateUtil.formatDateToDate( - (order.orderDate ?? order.appointmentDate), - false, + Directionality( + textDirection: ui.TextDirection.ltr, + child: AppCustomChipWidget( + labelText: DateUtil.formatDateToDate( + (order.orderDate ?? order.appointmentDate), + false, + ), isEnglishOnly: true, ), ), AppCustomChipWidget( diff --git a/lib/presentation/radiology/radiology_result_page.dart b/lib/presentation/radiology/radiology_result_page.dart index 7b3f11d4..02f30be5 100644 --- a/lib/presentation/radiology/radiology_result_page.dart +++ b/lib/presentation/radiology/radiology_result_page.dart @@ -20,6 +20,7 @@ import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:open_filex/open_filex.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'dart:ui' as ui; class RadiologyResultPage extends StatefulWidget { RadiologyResultPage({super.key, required this.patientRadiologyResponseModel}); @@ -52,6 +53,14 @@ class _RadiologyResultPageState extends State { Expanded( child: CollapsingListView( title: LocaleKeys.radiologyResult.tr(context: context), + viewImage: () { + if (radiologyViewModel.radiologyImageURL.isNotEmpty) { + Uri uri = Uri.parse(radiologyViewModel.radiologyImageURL); + launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: ""); + } else { + Utils.showToast("Radiology image not available"); + } + }, child: SingleChildScrollView( child: Padding( padding: EdgeInsets.symmetric(horizontal: 24.h), @@ -71,31 +80,34 @@ class _RadiologyResultPageState extends State { SizedBox(height: 16.h), // widget.patientRadiologyResponseModel.description!.toText16(isBold: true), SizedBox(height: 8.h), - widget.patientRadiologyResponseModel.reportData!.trim().toText12(isBold: true, color: AppColors.textColorLight), - SizedBox(height: 16.h), - CustomButton( - text: LocaleKeys.viewRadiologyImage.tr(context: context), - onPressed: () async { - if (radiologyViewModel.radiologyImageURL.isNotEmpty) { - Uri uri = Uri.parse(radiologyViewModel.radiologyImageURL); - launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: ""); - } else { - Utils.showToast("Radiology image not available"); - } - }, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: Colors.white, - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - icon: AppAssets.download, - iconColor: Colors.white, - iconSize: 20.h, + Directionality( + textDirection: ui.TextDirection.ltr, + child: widget.patientRadiologyResponseModel.reportData!.trim().toText12(isBold: true, color: AppColors.textColorLight, isEnglishOnly: true), ), SizedBox(height: 16.h), + // CustomButton( + // text: LocaleKeys.viewRadiologyImage.tr(context: context), + // onPressed: () async { + // if (radiologyViewModel.radiologyImageURL.isNotEmpty) { + // Uri uri = Uri.parse(radiologyViewModel.radiologyImageURL); + // launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: ""); + // } else { + // Utils.showToast("Radiology image not available"); + // } + // }, + // backgroundColor: AppColors.primaryRedColor, + // borderColor: AppColors.primaryRedColor, + // textColor: Colors.white, + // fontSize: 14, + // fontWeight: FontWeight.w500, + // borderRadius: 12, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // icon: AppAssets.download, + // iconColor: Colors.white, + // iconSize: 20.h, + // ), + // SizedBox(height: 16.h), ], ).paddingSymmetrical(16.h, 0.h), ), @@ -116,16 +128,21 @@ class _RadiologyResultPageState extends State { text: LocaleKeys.downloadReport.tr(context: context), onPressed: () async { LoaderBottomSheet.showLoader(); - await radiologyViewModel.getRadiologyPDF(patientRadiologyResponseModel: widget.patientRadiologyResponseModel, authenticatedUser: _appState.getAuthenticatedUser()!, onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: err), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }).then((val) async { + await radiologyViewModel + .getRadiologyPDF( + patientRadiologyResponseModel: widget.patientRadiologyResponseModel, + authenticatedUser: _appState.getAuthenticatedUser()!, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }) + .then((val) async { LoaderBottomSheet.hideLoader(); if (radiologyViewModel.patientRadiologyReportPDFBase64.isNotEmpty) { String path = await Utils.createFileFromString(radiologyViewModel.patientRadiologyReportPDFBase64, "pdf"); diff --git a/lib/widgets/appbar/collapsing_list_view.dart b/lib/widgets/appbar/collapsing_list_view.dart index 0c32d87d..4a315c6e 100644 --- a/lib/widgets/appbar/collapsing_list_view.dart +++ b/lib/widgets/appbar/collapsing_list_view.dart @@ -26,6 +26,7 @@ class CollapsingListView extends StatelessWidget { VoidCallback? sendEmail; VoidCallback? doctorResponse; VoidCallback? downloadReport; + VoidCallback? viewImage; Widget? bottomChild; Widget? trailing; bool isClose; @@ -49,6 +50,7 @@ class CollapsingListView extends StatelessWidget { this.sendEmail, this.doctorResponse, this.downloadReport, + this.viewImage, this.isLeading = true, this.trailing, this.leadingCallback, @@ -92,6 +94,7 @@ class CollapsingListView extends StatelessWidget { sendEmail: sendEmail, doctorResponse: doctorResponse, downloadReport: downloadReport, + viewImage: viewImage, bottomChild: bottomChild, trailing: trailing, aiOverview: aiOverview, @@ -204,6 +207,7 @@ class ScrollAnimatedTitle extends StatefulWidget implements PreferredSizeWidget VoidCallback? sendEmail; VoidCallback? doctorResponse; VoidCallback? downloadReport; + VoidCallback? viewImage; Widget? bottomChild; Widget? trailing; @@ -222,6 +226,7 @@ class ScrollAnimatedTitle extends StatefulWidget implements PreferredSizeWidget this.sendEmail, this.doctorResponse, this.downloadReport, + this.viewImage, this.bottomChild, this.trailing, }); @@ -301,6 +306,7 @@ class _ScrollAnimatedTitleState extends State { if (widget.search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(widget.search!), if (widget.aiOverview != null) actionButton(context, t, title: LocaleKeys.aiOverView.tr(context: context), icon: AppAssets.aiOverView, isAiButton: true).onPress(widget.aiOverview!), if (widget.downloadReport != null) actionButton(context, t, title: LocaleKeys.downloadReport.tr(context: context), icon: AppAssets.download).onPress(widget.downloadReport!), + if (widget.viewImage != null) actionButton(context, t, title: LocaleKeys.viewRadiologyImage.tr(context: context), icon: AppAssets.download).onPress(widget.viewImage!), if (widget.trailing != null) widget.trailing!, ] ], diff --git a/lib/widgets/chip/app_custom_chip_widget.dart b/lib/widgets/chip/app_custom_chip_widget.dart index 77345933..0a6d1169 100644 --- a/lib/widgets/chip/app_custom_chip_widget.dart +++ b/lib/widgets/chip/app_custom_chip_widget.dart @@ -27,6 +27,7 @@ class AppCustomChipWidget extends StatelessWidget { this.labelPadding, this.onDeleteTap, this.applyThemeColor = true, + this.isEnglishOnly = false }); final String? labelText; @@ -48,6 +49,7 @@ class AppCustomChipWidget extends StatelessWidget { final void Function()? onChipTap; final void Function()? onDeleteTap; final bool applyThemeColor; + final bool isEnglishOnly; @override Widget build(BuildContext context) { @@ -85,7 +87,7 @@ class AppCustomChipWidget extends StatelessWidget { applyThemeColor: applyThemeColor, ) : SizedBox.shrink(), - label: richText ?? (labelText?? "").toText10(weight: FontWeight.w500, letterSpacing: 0, color: resolvedTextColor), + label: richText ?? (labelText?? "").toText10(weight: FontWeight.w500, letterSpacing: 0, color: resolvedTextColor, isEnglishOnly: isEnglishOnly), padding: padding, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, labelPadding: labelPadding ?? EdgeInsetsDirectional.only(end: deleteIcon?.isNotEmpty == true ? 2.w : 8.w), @@ -112,7 +114,7 @@ class AppCustomChipWidget extends StatelessWidget { ) : Chip( materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - label: richText ?? (labelText?? "").toText10(weight: FontWeight.w500, letterSpacing: 0, color: resolvedTextColor, isCenter: true), + label: richText ?? (labelText?? "").toText10(weight: FontWeight.w500, letterSpacing: 0, color: resolvedTextColor, isCenter: true, isEnglishOnly: isEnglishOnly), padding: EdgeInsets.zero, backgroundColor: resolvedBackgroundColor, shape: shape ?? diff --git a/pubspec.yaml b/pubspec.yaml index 27a81c7e..bca92d54 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,8 +2,8 @@ name: hmg_patient_app_new description: "New HMG Patient App" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -#version: 0.0.11+8 -version: 0.0.1+9 +#version: 0.0.13+10 +version: 0.0.1+13 environment: sdk: ">=3.6.0 <4.0.0" From 3d877ed28da872b0ef97abeb81b7dd817da91f76 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 25 Mar 2026 13:34:31 +0300 Subject: [PATCH 21/33] Updates --- assets/langs/ar-SA.json | 4 +- assets/langs/en-US.json | 3 +- .../book_appointments_view_model.dart | 22 ++++++++++ lib/generated/locale_keys.g.dart | 3 +- .../appointment_details_page.dart | 12 ++--- .../widgets/appointment_card.dart | 4 +- .../book_appointment_page.dart | 28 ++++++++---- .../home/data/landing_page_data.dart | 8 ++-- lib/presentation/home/landing_page.dart | 2 +- .../home/widgets/large_service_card.dart | 5 ++- .../home_health_care/hhc_procedures_page.dart | 21 ++++++--- .../insurance_update_details_card.dart | 26 +++++------ .../widgets/patient_insurance_card.dart | 44 +++++++++++-------- .../medical_file/medical_file_page.dart | 44 +++++++++++-------- .../profile_settings/profile_settings.dart | 44 +++++++++++-------- lib/widgets/chip/app_custom_chip_widget.dart | 17 ++++--- 16 files changed, 181 insertions(+), 106 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 04684df5..071374e6 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -435,7 +435,6 @@ "serviceInformation": "معلومات الخدمة", "homeHealthCare": "الرعاية الصحية المنزلية", "noAppointmentAvailable": "لا توجد مواعيد متاحة", - "homeHealthCareText": "تقدم هذه الخدمة مجموعة من خدمات الرعاية الصحية المنزلية، والمتابعة المستمرة والشاملة في أماكن إقامتهم لأولئك الذين لا يمكنهم الوصول إلى المرافق الصحية، مثل (تحليلات المختبر - الأشعة - التطعيمات - العلاج الطبيعي)، إلخ.", "loginRegister": "تسجيل الدخول / التسجيل", "orderLog": "سجل الطلب", "infoLab": "تتيح لك هذه الخدمة عرض نتائج جميع الفحوصات المخبرية التي أجريت في مجموعة الحبيب الطبية بالإضافة إلى إرسال التقرير عبر البريد الإلكتروني.", @@ -1585,5 +1584,6 @@ "hmgPolicies": "سياسات مجموعة الحبيب الطبية", "darkMode": "المظهر الداكن", "generateAiAnalysisResult": "قم بإجراء تحليل لهذا المختبر AI", - "ratings": "التقييمات" + "ratings": "التقييمات", + "hmgPharmacyText": "صيدلية الحبيب، المتجر الصيدلاني الإلكتروني المتكامل الذي تقدمه لكم مجموعة خدمات الدكتور سليمان الحبيب الطبية." } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index c43d730e..a76898ba 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1578,5 +1578,6 @@ "hmgPolicies": "HMG Policies", "darkMode": "Dark Mode", "generateAiAnalysisResult": "Generate AI analysis for this result", - "ratings": "Ratings" + "ratings": "Ratings", + "hmgPharmacyText": "Al Habib Pharmacy, the complete online Pharmaceutical store brought to you by Dr. Sulaiman Al Habib Medical Services Group." } diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart index 676a299a..0d2a8f82 100644 --- a/lib/features/book_appointments/book_appointments_view_model.dart +++ b/lib/features/book_appointments/book_appointments_view_model.dart @@ -49,6 +49,7 @@ class BookAppointmentsViewModel extends ChangeNotifier { bool isDoctorSearchByNameStarted = false; bool isAppointmentNearestGateLoading = false; + bool isLiveCareSelectedFromHomePage = false; bool isLiveCareSchedule = false; bool isGetDocForHealthCal = false; bool showSortFilterButtons = false; @@ -318,6 +319,11 @@ class BookAppointmentsViewModel extends ChangeNotifier { notifyListeners(); } + setIsLiveCareSelectedFromHomePage(bool isLiveCareSelectedFromHomePage) { + this.isLiveCareSelectedFromHomePage = isLiveCareSelectedFromHomePage; + notifyListeners(); + } + setIsWaitingAppointmentSelected(bool isWaitingAppointmentSelected) { this.isWaitingAppointmentSelected = isWaitingAppointmentSelected; notifyListeners(); @@ -423,9 +429,25 @@ class BookAppointmentsViewModel extends ChangeNotifier { calculationID = null; isGetDocForHealthCal = false; selectedTabIndex = index; + checkLiveCareSymptomCheckerStatus(); notifyListeners(); } + bool checkLiveCareSymptomCheckerStatus() { + bool isAllowed = false; + + if (selectedTabIndex == 1) { + if (_appState.isAuthenticated) { + isAllowed = true; + } else { + isAllowed = false; + } + } else { + isAllowed = true; + } + return isAllowed; + } + /// this function will decide which clinic api to be called /// either api for region flow or the select clinic api Future getClinics() async { diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 73a18102..951dbf90 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -436,7 +436,6 @@ abstract class LocaleKeys { static const serviceInformation = 'serviceInformation'; static const homeHealthCare = 'homeHealthCare'; static const noAppointmentAvailable = 'noAppointmentAvailable'; - static const homeHealthCareText = 'homeHealthCareText'; static const loginRegister = 'loginRegister'; static const orderLog = 'orderLog'; static const infoLab = 'infoLab'; @@ -746,6 +745,7 @@ abstract class LocaleKeys { static const infoTodo = 'infoTodo'; static const familyInfo = 'familyInfo'; static const rrtdDetails = 'rrtdDetails'; + static const homeHealthCareText = 'homeHealthCareText'; static const onlineCheckInAgreement = 'onlineCheckInAgreement'; static const infoEreferral = 'infoEreferral'; static const erConsultation = 'erConsultation'; @@ -1579,5 +1579,6 @@ abstract class LocaleKeys { static const darkMode = 'darkMode'; static const generateAiAnalysisResult = 'generateAiAnalysisResult'; static const ratings = 'ratings'; + static const hmgPharmacyText = 'hmgPharmacyText'; } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index cafb740e..71cf4e16 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -69,12 +69,12 @@ class _AppointmentDetailsPageState extends State { @override void initState() { scheduleMicrotask(() async { - CalenderUtilsNew calendarUtils = await CalenderUtilsNew.instance; - var doesExist = await calendarUtils.checkIfEventExist("${widget.patientAppointmentHistoryResponseModel.appointmentNo}"); - myAppointmentsViewModel.setAppointmentReminder(doesExist, widget.patientAppointmentHistoryResponseModel); - setState((){ - - }); + if (!AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)) { + CalenderUtilsNew calendarUtils = await CalenderUtilsNew.instance; + var doesExist = await calendarUtils.checkIfEventExist("${widget.patientAppointmentHistoryResponseModel.appointmentNo}"); + myAppointmentsViewModel.setAppointmentReminder(doesExist, widget.patientAppointmentHistoryResponseModel); + setState(() {}); + } }); super.initState(); diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index 210de466..ac63432f 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -424,7 +424,9 @@ class AppointmentCard extends StatelessWidget { ), ); } else { - bookAppointmentsViewModel.getAppointmentNearestGate(projectID: patientAppointmentHistoryResponseModel.projectID, clinicID: patientAppointmentHistoryResponseModel.clinicID); + if (!AppointmentType.isArrived(patientAppointmentHistoryResponseModel)) { + bookAppointmentsViewModel.getAppointmentNearestGate(projectID: patientAppointmentHistoryResponseModel.projectID, clinicID: patientAppointmentHistoryResponseModel.clinicID); + } Navigator.of(context) .push( CustomPageRoute( diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index ab548449..aea34ff0 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -61,7 +61,13 @@ class _BookAppointmentPageState extends State { immediateLiveCareViewModel.initImmediateLiveCare(); }); WidgetsBinding.instance.addPostFrameCallback((_) { - showUnKnownClinicBottomSheet(); + if (bookAppointmentsViewModel.selectedTabIndex == 1) { + if (appState.isAuthenticated) { + showUnKnownClinicBottomSheet(); + } + } else { + showUnKnownClinicBottomSheet(); + } }); super.initState(); } @@ -203,7 +209,9 @@ class _BookAppointmentPageState extends State { ), ), ), - _buildSymptomsBottomCard(), + Consumer(builder: (context, bookAppointmentsVM, child) { + return _buildSymptomsBottomCard(); + }), ], ), ); @@ -414,12 +422,13 @@ class _BookAppointmentPageState extends State { } Widget _buildSymptomsBottomCard() { - return Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), - child: Row( - children: [ - Expanded( - child: Column( + return bookAppointmentsViewModel.checkLiveCareSymptomCheckerStatus() + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), + child: Row( + children: [ + Expanded( + child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -442,7 +451,8 @@ class _BookAppointmentPageState extends State { ) ], ).paddingAll(24.w), - ); + ) + : SizedBox.shrink(); } void openRegionListBottomSheet(BuildContext context, RegionBottomSheetType type) { diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart index b74e57f3..4606c800 100644 --- a/lib/presentation/home/data/landing_page_data.dart +++ b/lib/presentation/home/data/landing_page_data.dart @@ -165,8 +165,8 @@ class LandingPageData { serviceName: "home_health_care", icon: AppAssets.homeBottom, title: LocaleKeys.homeHealthCare, - subtitle: LocaleKeys.liveCareServiceDesc, - largeCardIcon: AppAssets.homeHealthCareService, + subtitle: LocaleKeys.homeHealthCareText, + largeCardIcon: AppAssets.homeHealthCareService, backgroundColor: AppColors.primaryRedColor, iconColor: AppColors.whiteColor, isBold: false, @@ -175,8 +175,8 @@ class LandingPageData { serviceName: "pharmacy", icon: AppAssets.pharmacy_icon, //359846 title: LocaleKeys.hmgPharmacy, - subtitle: LocaleKeys.liveCareServiceDesc, - largeCardIcon: AppAssets.pharmacyService, + subtitle: LocaleKeys.hmgPharmacyText, + largeCardIcon: AppAssets.pharmacyService, backgroundColor: AppColors.pharmacyBGColor, iconColor: null, isBold: true, diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index a7ae78b9..5d068b6c 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -258,7 +258,7 @@ class _LandingPageState extends State { ); }), !appState.isAuthenticated - ? Utils.buildSvgWithAssets(icon: AppAssets.changeLanguageHomePageIcon, height: 24.h, width: 24.h).onPress(() { + ? Utils.buildSvgWithAssets(icon: appState.isArabic() ? AppAssets.enLangIcon : AppAssets.arLangIcon, height: 24.h, width: 24.h).onPress(() { context.setLocale(appState.isArabic() ? Locale('en', 'US') : Locale('ar', 'SA')); }) : SizedBox.shrink() diff --git a/lib/presentation/home/widgets/large_service_card.dart b/lib/presentation/home/widgets/large_service_card.dart index 7c86dd09..4405a197 100644 --- a/lib/presentation/home/widgets/large_service_card.dart +++ b/lib/presentation/home/widgets/large_service_card.dart @@ -229,10 +229,10 @@ class FadedLargeServiceCard extends StatelessWidget { ], ), SizedBox(height: 10.h), - serviceCardData.subtitle.tr(context: context).toText14(weight: FontWeight.w500, color: AppColors.blackBgColor, letterSpacing: 0), + serviceCardData.subtitle.tr(context: context).toText14(weight: FontWeight.w500, color: AppColors.blackBgColor, letterSpacing: 0, maxlines: 2), SizedBox(height: 12.h), CustomButton( - text: serviceCardData.isBold ? "Visit Pharmacy Online".needTranslation : LocaleKeys.bookNow.tr(context: context), + text: serviceCardData.isBold ? LocaleKeys.visitPharmacyOnline.tr(context: context) : LocaleKeys.bookNow.tr(context: context), onPressed: () { handleOnTap(); }, @@ -255,6 +255,7 @@ class FadedLargeServiceCard extends StatelessWidget { case "livecare": { getIt.get().onTabChanged(1); + getIt.get().setIsLiveCareSelectedFromHomePage(true); Navigator.of(getIt.get().navigatorKey.currentContext!).push( CustomPageRoute( page: BookAppointmentPage(), diff --git a/lib/presentation/home_health_care/hhc_procedures_page.dart b/lib/presentation/home_health_care/hhc_procedures_page.dart index c420742c..88766ea0 100644 --- a/lib/presentation/home_health_care/hhc_procedures_page.dart +++ b/lib/presentation/home_health_care/hhc_procedures_page.dart @@ -8,6 +8,7 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart'; @@ -33,11 +34,13 @@ class HhcProceduresPage extends StatefulWidget { } class _HhcProceduresPageState extends State { + + late AppState appState; + @override void initState() { super.initState(); final HmgServicesViewModel hmgServicesViewModel = context.read(); - final AppState appState = getIt.get(); scheduleMicrotask(() async { final user = appState.getAuthenticatedUser(); @@ -445,11 +448,12 @@ class _HhcProceduresPageState extends State { @override Widget build(BuildContext context) { + appState = getIt.get(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: CollapsingListView( title: LocaleKeys.homeHealthCare.tr(context: context), - history: () => Navigator.of(context).push(CustomPageRoute(page: HhcOrderDetailPage(), direction: AxisDirection.up)), + history: () => appState.isAuthenticated ? Navigator.of(context).push(CustomPageRoute(page: HhcOrderDetailPage(), direction: AxisDirection.up)) : null, bottomChild: Consumer( builder: (BuildContext context, HmgServicesViewModel hmgServicesViewModel, Widget? child) { if (hmgServicesViewModel.isHhcOrdersLoading || hmgServicesViewModel.isHhcServicesLoading) { @@ -467,8 +471,14 @@ class _HhcProceduresPageState extends State { padding: EdgeInsets.all(24.w), child: CustomButton( borderWidth: 0, - text: LocaleKeys.createNewRequest.tr(context: context), - onPressed: () => _buildServicesListBottomsSheet(hmgServicesViewModel.hhcServicesList), + text: appState.isAuthenticated ? LocaleKeys.createNewRequest.tr(context: context) : LocaleKeys.loginToUseService.tr(context: context), + onPressed: () { + if(appState.isAuthenticated) { + _buildServicesListBottomsSheet(hmgServicesViewModel.hhcServicesList); + } else { + getIt().onLoginPressed(); + } + }, textColor: AppColors.whiteColor, borderRadius: 12.r, borderColor: Colors.transparent, @@ -492,12 +502,13 @@ class _HhcProceduresPageState extends State { } else { return Column( children: [ + appState.isAuthenticated ? Center( child: Utils.getNoDataWidget( context, noDataText: LocaleKeys.youHaveNoPendingRequests.tr(context: context), ), - ), + ) : LocaleKeys.homeHealthCareText.tr(context: context).toText18(weight: FontWeight.w500).paddingSymmetrical(24.h, 24.h), ], ); } diff --git a/lib/presentation/insurance/widgets/insurance_update_details_card.dart b/lib/presentation/insurance/widgets/insurance_update_details_card.dart index 35be7f9e..bf86671e 100644 --- a/lib/presentation/insurance/widgets/insurance_update_details_card.dart +++ b/lib/presentation/insurance/widgets/insurance_update_details_card.dart @@ -3,6 +3,7 @@ import 'package:flutter/cupertino.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -75,21 +76,18 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget { ], ), SizedBox(height: 8.h), - Row( + Wrap( + direction: Axis.horizontal, + spacing: 4.h, + runSpacing: 4.h, children: [ - Wrap( - direction: Axis.horizontal, - spacing: 4.h, - runSpacing: 4.h, - children: [ - AppCustomChipWidget( - icon: AppAssets.doctor_calendar_icon, - labelText: "${LocaleKeys.expiryOn.tr(context: context)} ${insuranceViewModel.patientInsuranceUpdateResponseModel!.effectiveTo}", - ), - AppCustomChipWidget( - labelText: "Member ID: ${insuranceViewModel.patientInsuranceUpdateResponseModel!.memberID!}", - ), - ], + AppCustomChipWidget( + icon: AppAssets.doctor_calendar_icon, + labelText: + "${LocaleKeys.expiryOn.tr(context: context)} ${DateUtil.formatDateToDate(DateTime.parse(insuranceViewModel.patientInsuranceUpdateResponseModel!.effectiveTo!), false)}", + ), + AppCustomChipWidget( + labelText: "Member ID: ${insuranceViewModel.patientInsuranceUpdateResponseModel!.memberID!}", ), ], ), diff --git a/lib/presentation/insurance/widgets/patient_insurance_card.dart b/lib/presentation/insurance/widgets/patient_insurance_card.dart index 2d3ba9ea..d6bb204f 100644 --- a/lib/presentation/insurance/widgets/patient_insurance_card.dart +++ b/lib/presentation/insurance/widgets/patient_insurance_card.dart @@ -79,27 +79,35 @@ class PatientInsuranceCard extends StatelessWidget { : AppColors.warningColorYellow, iconSize: 12.w, deleteIcon: insuranceViewModel.isInsuranceActive ? null : AppAssets.forward_chevron_icon, - deleteIconColor: AppColors.warningColorYellow, + deleteIconColor: insuranceViewModel.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceViewModel.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, deleteIconHasColor: true, onChipTap: () { if (!insuranceViewModel.isInsuranceActive) { - showCommonBottomSheetWithoutHeight( - title: LocaleKeys.notice.tr(context: context), - context, - child: Utils.getWarningWidget( - loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), - confirmText: LocaleKeys.contactUs.tr(context: context), - isShowActionButtons: true, - onCancelTap: () { - Navigator.pop(context); - }, - onConfirmTap: () async { - launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); - }), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); + insuranceViewModel.setIsInsuranceUpdateDetailsLoading(true); + insuranceViewModel.getPatientInsuranceDetailsForUpdate( + appState.getAuthenticatedUser()!.patientId.toString(), appState.getAuthenticatedUser()!.patientIdentificationNo.toString()); + showCommonBottomSheetWithoutHeight(context, child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); + // showCommonBottomSheetWithoutHeight( + // title: LocaleKeys.notice.tr(context: context), + // context, + // child: Utils.getWarningWidget( + // loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + // confirmText: LocaleKeys.contactUs.tr(context: context), + // isShowActionButtons: true, + // onCancelTap: () { + // Navigator.pop(context); + // }, + // onConfirmTap: () async { + // launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + // }), + // callBackFunc: () {}, + // isFullScreen: false, + // isCloseButtonVisible: true, + // ); } }, backgroundColor: insuranceViewModel.isInsuranceExpired diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 89843ea7..b804a751 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -312,27 +312,35 @@ class _MedicalFilePageState extends State { : AppColors.warningColorYellow, iconSize: 12.w, deleteIcon: insuranceVM.isInsuranceActive ? null : AppAssets.forward_chevron_icon, - deleteIconColor: AppColors.warningColorYellow, + deleteIconColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, deleteIconHasColor: true, onChipTap: () { if (!insuranceVM.isInsuranceActive) { - showCommonBottomSheetWithoutHeight( - title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), - navigationService.navigatorKey.currentContext!, - child: Utils.getWarningWidget( - loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), - confirmText: LocaleKeys.contactUs.tr(context: context), - isShowActionButtons: true, - onCancelTap: () { - navigationService.pop(); - }, - onConfirmTap: () async { - launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); - }), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); + insuranceVM.setIsInsuranceUpdateDetailsLoading(true); + insuranceVM.getPatientInsuranceDetailsForUpdate( + appState.getAuthenticatedUser()!.patientId.toString(), appState.getAuthenticatedUser()!.patientIdentificationNo.toString()); + showCommonBottomSheetWithoutHeight(context, child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); + // showCommonBottomSheetWithoutHeight( + // title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), + // navigationService.navigatorKey.currentContext!, + // child: Utils.getWarningWidget( + // loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + // confirmText: LocaleKeys.contactUs.tr(context: context), + // isShowActionButtons: true, + // onCancelTap: () { + // navigationService.pop(); + // }, + // onConfirmTap: () async { + // launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + // }), + // callBackFunc: () {}, + // isFullScreen: false, + // isCloseButtonVisible: true, + // ); } }, backgroundColor: insuranceVM.isInsuranceExpired diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index 27f74826..7d6af196 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -23,6 +23,7 @@ import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_v import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart'; +import 'package:hmg_patient_app_new/presentation/insurance/widgets/insurance_update_details_card.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/app_language_change.dart'; @@ -431,27 +432,34 @@ class FamilyCardWidget extends StatelessWidget { : AppColors.warningColorYellow, iconSize: 12.w, deleteIcon: insuranceVM.isInsuranceActive ? null : AppAssets.forward_chevron_icon, - deleteIconColor: AppColors.warningColorYellow, + deleteIconColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, deleteIconHasColor: true, onChipTap: () { if (!insuranceVM.isInsuranceActive) { - showCommonBottomSheetWithoutHeight( - title: LocaleKeys.notice.tr(context: context), - context, - child: Utils.getWarningWidget( - loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), - confirmText: LocaleKeys.contactUs.tr(context: context), - isShowActionButtons: true, - onCancelTap: () { - Navigator.pop(context); - }, - onConfirmTap: () async { - launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); - }), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); + insuranceVM.setIsInsuranceUpdateDetailsLoading(true); + insuranceVM.getPatientInsuranceDetailsForUpdate(appState.getAuthenticatedUser()!.patientId.toString(), appState.getAuthenticatedUser()!.patientIdentificationNo.toString()); + showCommonBottomSheetWithoutHeight(context, child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); + // showCommonBottomSheetWithoutHeight( + // title: LocaleKeys.notice.tr(context: context), + // context, + // child: Utils.getWarningWidget( + // loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + // confirmText: LocaleKeys.contactUs.tr(context: context), + // isShowActionButtons: true, + // onCancelTap: () { + // Navigator.pop(context); + // }, + // onConfirmTap: () async { + // launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + // }), + // callBackFunc: () {}, + // isFullScreen: false, + // isCloseButtonVisible: true, + // ); } }, backgroundColor: insuranceVM.isInsuranceExpired diff --git a/lib/widgets/chip/app_custom_chip_widget.dart b/lib/widgets/chip/app_custom_chip_widget.dart index 0a6d1169..b2ae4288 100644 --- a/lib/widgets/chip/app_custom_chip_widget.dart +++ b/lib/widgets/chip/app_custom_chip_widget.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.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/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -101,12 +103,15 @@ class AppCustomChipWidget extends StatelessWidget { deleteIcon: deleteIcon?.isNotEmpty == true ? InkWell( onTap: onDeleteTap, - child: Utils.buildSvgWithAssets( - icon: deleteIcon!, - width: iconS, - height: iconS, - iconColor: deleteIconHasColor ? resolvedDeleteIconColor : null, - applyThemeColor: applyThemeColor, + child: Transform.flip( + flipX: getIt.get().isArabic(), + child: Utils.buildSvgWithAssets( + icon: deleteIcon!, + width: iconS, + height: iconS, + iconColor: deleteIconHasColor ? resolvedDeleteIconColor : null, + applyThemeColor: applyThemeColor, + ), ), ) : null, From d703c382e5e350fee56a59f1396468ca4d2ed8c3 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 25 Mar 2026 17:02:17 +0300 Subject: [PATCH 22/33] Updates --- assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 3 +- lib/core/api/api_client.dart | 5 +- lib/extensions/widget_extensions.dart | 23 ++--- .../insurance/insurance_view_model.dart | 2 +- lib/generated/locale_keys.g.dart | 1 + lib/presentation/home/landing_page.dart | 57 ++++++------ .../insurance_update_details_card.dart | 72 ++++++++------- .../profile_settings/profile_settings.dart | 87 ++++++++++--------- 9 files changed, 141 insertions(+), 112 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 071374e6..958a4902 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1585,5 +1585,6 @@ "darkMode": "المظهر الداكن", "generateAiAnalysisResult": "قم بإجراء تحليل لهذا المختبر AI", "ratings": "التقييمات", - "hmgPharmacyText": "صيدلية الحبيب، المتجر الصيدلاني الإلكتروني المتكامل الذي تقدمه لكم مجموعة خدمات الدكتور سليمان الحبيب الطبية." + "hmgPharmacyText": "صيدلية الحبيب، المتجر الصيدلاني الإلكتروني المتكامل الذي تقدمه لكم مجموعة خدمات الدكتور سليمان الحبيب الطبية.", + "insuranceRequestSubmittedSuccessfully": "تم إرسال طلب تحديث بيانات التأمين بنجاح. سيتم إعلامك بمجرد الانتهاء." } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index a76898ba..cea0082a 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1579,5 +1579,6 @@ "darkMode": "Dark Mode", "generateAiAnalysisResult": "Generate AI analysis for this result", "ratings": "Ratings", - "hmgPharmacyText": "Al Habib Pharmacy, the complete online Pharmaceutical store brought to you by Dr. Sulaiman Al Habib Medical Services Group." + "hmgPharmacyText": "Al Habib Pharmacy, the complete online Pharmaceutical store brought to you by Dr. Sulaiman Al Habib Medical Services Group.", + "insuranceRequestSubmittedSuccessfully": "Your insurance update request has been successfully submitted. You will be notified once completed." } diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index f415d8ac..0131a938 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -200,7 +200,7 @@ class ApiClientImp implements ApiClient { } // body['TokenID'] = "@dm!n"; - // body['PatientID'] = 2007395; + // body['PatientID'] = 4774402; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; // body['SessionID'] = "45786230487560q"; @@ -359,7 +359,8 @@ class ApiClientImp implements ApiClient { onFailure( parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode, - failureType: ServerFailure("Error While Fetching data"), + // failureType: ServerFailure("Error While Fetching data"), + failureType: ServerFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']), ); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 64672f5f..5e4d4e1f 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -152,6 +152,7 @@ extension SmoothContainerExtension on ShapeBorder { BorderSide? side, BorderRadius? customBorder, bool hasShadow = false, + bool hasDenseShadow = false, }) { final bgColor = backgroundColor ?? color; return ShapeDecoration( @@ -161,17 +162,17 @@ extension SmoothContainerExtension on ShapeBorder { smoothness: 1, side: side ?? BorderSide.none, ), - shadows: - // hasShadow - // ? [ - // BoxShadow( - // color: const Color(0xff000000).withOpacity(.05), - // blurRadius: 32, - // offset: const Offset(0, 0), - // ) - // ] - // : - [], + shadows: hasShadow + ? [ + BoxShadow( + color: hasDenseShadow ? const Color(0xff000000).withOpacity(.30) : const Color(0xff000000).withOpacity(.1), + // color: AppColors.primaryRedColor.withOpacity(.5), + blurRadius: 10, + spreadRadius: 0, + offset: const Offset(0, 0), + ) + ] + : [], ); } } diff --git a/lib/features/insurance/insurance_view_model.dart b/lib/features/insurance/insurance_view_model.dart index 515743c6..d66a7a22 100644 --- a/lib/features/insurance/insurance_view_model.dart +++ b/lib/features/insurance/insurance_view_model.dart @@ -214,7 +214,7 @@ class InsuranceViewModel extends ChangeNotifier { (failure) async { notifyListeners(); if (onError != null) { - onError(failure.toString()); + onError(failure.message.toString()); } }, (apiResponse) { diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 951dbf90..2aeb87f1 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1580,5 +1580,6 @@ abstract class LocaleKeys { static const generateAiAnalysisResult = 'generateAiAnalysisResult'; static const ratings = 'ratings'; static const hmgPharmacyText = 'hmgPharmacyText'; + static const insuranceRequestSubmittedSuccessfully = 'insuranceRequestSubmittedSuccessfully'; } diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 5d068b6c..3012876f 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -331,7 +331,6 @@ class _LandingPageState extends State { ).paddingSymmetrical(24.h, 0.h).onPress(() { Navigator.of(context).push(CustomPageRoute(page: MyAppointmentsPage())); }), - SizedBox(height: 16.h), Consumer3( builder: (context, myAppointmentsVM, immediateLiveCareVM, todoSectionVM, child) { return myAppointmentsVM.isMyAppointmentsLoading @@ -348,7 +347,7 @@ class _LandingPageState extends State { isLoading: true, isFromHomePage: true, ), - ).paddingSymmetrical(24.h, 0.h) + ).paddingSymmetrical(24.h, 16.h) : myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty ? myAppointmentsVM.patientAppointmentsHistoryList.length == 1 ? Container( @@ -399,27 +398,34 @@ class _LandingPageState extends State { ), ), ) - : 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: 255.h, - pagination: SwiperPagination( - alignment: Alignment.bottomCenter, - margin: EdgeInsets.only(top: 240.h + 8 + 24), - builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + : SizedBox( + height: 255.h + 20 + 30, // itemHeight + shadow padding (10 top + 10 bottom) + pagination dots space + child: 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: 255.h + 20, + // extra space for shadow + pagination: SwiperPagination( + alignment: Alignment.bottomCenter, + margin: EdgeInsets.only(top: 220.h + 20 + 8 + 24), + builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + ), + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: getIndexSwiperCard(index), + ); + }, ), - itemBuilder: (BuildContext context, int index) { - return getIndexSwiperCard(index); - }, ) : Container( width: double.infinity, @@ -451,7 +457,7 @@ class _LandingPageState extends State { ], ), ), - ).paddingSymmetrical(24.h, 0.h); + ).paddingSymmetrical(24.h, 16.h); }, ), @@ -466,7 +472,7 @@ class _LandingPageState extends State { decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 20.r, - hasShadow: true, + hasShadow: false, side: BorderSide(color: AppColors.primaryRedColor, width: 3.h), ), width: double.infinity, @@ -775,7 +781,7 @@ class _LandingPageState extends State { decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 20.h, - hasShadow: false, + hasShadow: true, side: BorderSide( color: Utils.getCardBorderColor(currentStatus), width: 2.w, @@ -1006,6 +1012,7 @@ class _LandingPageState extends State { color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true, + hasDenseShadow: true ), child: AppointmentCard( patientAppointmentHistoryResponseModel: appointment, diff --git a/lib/presentation/insurance/widgets/insurance_update_details_card.dart b/lib/presentation/insurance/widgets/insurance_update_details_card.dart index bf86671e..59a4dd97 100644 --- a/lib/presentation/insurance/widgets/insurance_update_details_card.dart +++ b/lib/presentation/insurance/widgets/insurance_update_details_card.dart @@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; @@ -105,38 +106,47 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget { text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}", onPressed: () { LoaderBottomSheet.showLoader(); - insuranceViewModel.updatePatientInsuranceCard( - patientID: appState.getAuthenticatedUser()!.patientId!, - patientType: appState.getAuthenticatedUser()!.patientType!, - patientIdentificationID: appState.getAuthenticatedUser()!.patientIdentificationNo!, - mobileNo: appState.getAuthenticatedUser()!.mobileNumber!, - insuranceCardImage: "", - onSuccess: (val) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - title: LocaleKeys.success.tr(context: context), - context, - child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr(context: context)), - callBackFunc: () { + getIt().sendPatientUpdateRequest(onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + insuranceViewModel.setIsInsuranceDataToBeLoaded(true); + insuranceViewModel.initInsuranceProvider(); + }, onError: (err) { + insuranceViewModel.updatePatientInsuranceCard( + patientID: appState.getAuthenticatedUser()!.patientId!, + patientType: appState.getAuthenticatedUser()!.patientType!, + patientIdentificationID: appState.getAuthenticatedUser()!.patientIdentificationNo!, + mobileNo: appState.getAuthenticatedUser()!.mobileNumber!, + insuranceCardImage: "", + onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.success.tr(context: context), + context, + child: Utils.getSuccessWidget(loadingText: LocaleKeys.insuranceRequestSubmittedSuccessfully.tr(context: context)), + callBackFunc: () { + Navigator.pop(context); + }, + isFullScreen: false, + isCloseButtonVisible: false, + ); + Future.delayed(Duration(milliseconds: 2000)).then((value) async { Navigator.pop(context); - }, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }, - onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - title: LocaleKeys.notice.tr(context: context), - context, - child: Utils.getErrorWidget(loadingText: err.toString()), - callBackFunc: () { - Navigator.pop(context); - }, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); + }); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getErrorWidget(loadingText: err.toString()), + callBackFunc: () { + Navigator.pop(context); + }, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + }); }, backgroundColor: insuranceViewModel.patientInsuranceUpdateResponseModel != null ? AppColors.successColor : AppColors.lightGrayBGColor, borderColor: AppColors.successColor.withOpacity(0.01), diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index 7d6af196..e975d6f4 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -98,46 +98,53 @@ class ProfileSettingsState extends State { }, isClose: true, child: SingleChildScrollView( - padding: EdgeInsets.only(top: 24.h, bottom: 24.h), + padding: EdgeInsets.only(top: 0.h, bottom: 24.h), physics: NeverScrollableScrollPhysics(), child: Consumer2( builder: (context, profileVm, medicalVm, child) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Swiper( - itemCount: medicalVm.patientFamilyFiles.length, - layout: SwiperLayout.STACK, - loop: true, - itemHeight: dynamicItemHeight(context), - itemWidth: SizeUtils.width - 30.w, - indicatorLayout: PageIndicatorLayout.COLOR, - axisDirection: AxisDirection.right, - controller: _controller, - pagination: SwiperPagination( - alignment: Alignment.bottomCenter, - margin: EdgeInsets.only(top: (210.h + 8.h + 24.h)), - builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + SizedBox( + height: dynamicItemHeight(context) + 20 + 30, // itemHeight + shadow padding (10 top + 10 bottom) + pagination dots space + child: Swiper( + itemCount: medicalVm.patientFamilyFiles.length, + layout: SwiperLayout.STACK, + loop: true, + itemHeight: dynamicItemHeight(context) + 20, + // extra space for shadow + itemWidth: SizeUtils.width - 30.w, + indicatorLayout: PageIndicatorLayout.COLOR, + axisDirection: AxisDirection.right, + controller: _controller, + pagination: SwiperPagination( + alignment: Alignment.bottomCenter, + margin: EdgeInsets.only(top: (180.h + 20 + 8.h + 24.h)), + builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + ), + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: FamilyCardWidget( + profile: medicalVm.patientFamilyFiles[index], + onAddFamilyMemberPress: () { + DialogService dialogService = getIt.get(); + dialogService.showAddFamilyFileSheet( + label: LocaleKeys.addFamilyMember.tr(context: context), + message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(context: context), + onVerificationPress: () { + medicalVm.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); + }); + }, + onFamilySwitchPress: (FamilyFileResponseModelLists profile) { + medicalVm.switchFamilyFiles(responseID: profile.responseId, patientID: profile.patientId, phoneNumber: profile.mobileNumber); + }, + ).paddingOnly(right: 16.w, left: 8.w), + ); + }, ), - itemBuilder: (BuildContext context, int index) { - return FamilyCardWidget( - profile: medicalVm.patientFamilyFiles[index], - onAddFamilyMemberPress: () { - DialogService dialogService = getIt.get(); - dialogService.showAddFamilyFileSheet( - label: LocaleKeys.addFamilyMember.tr(context: context), - message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(context: context), - onVerificationPress: () { - medicalVm.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); - }); - }, - onFamilySwitchPress: (FamilyFileResponseModelLists profile) { - medicalVm.switchFamilyFiles(responseID: profile.responseId, patientID: profile.patientId, phoneNumber: profile.mobileNumber); - }, - ).paddingOnly(right: 16.w, left: 8.w); - }, ), - SizedBox(height: 5.h), + SizedBox(height: 16.h), GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 3 : 2), physics: const NeverScrollableScrollPhysics(), @@ -362,9 +369,7 @@ class FamilyCardWidget extends StatelessWidget { return Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, - borderRadius: 24.r, - hasShadow: true, - ), + borderRadius: 24.r, hasShadow: true, hasDenseShadow: true), child: Column( children: [ Column( @@ -409,10 +414,11 @@ class FamilyCardWidget extends StatelessWidget { iconColor: AppColors.primaryRedColor) : SizedBox(), Consumer(builder: (context, insuranceVM, child) { - return AppCustomChipWidget( - icon: insuranceVM.isInsuranceExpired - ? AppAssets.cancel_circle_icon - : insuranceVM.isInsuranceActive + return isActive + ? AppCustomChipWidget( + icon: insuranceVM.isInsuranceExpired + ? AppAssets.cancel_circle_icon + : insuranceVM.isInsuranceActive ? AppAssets.insurance_active_icon : AppAssets.alertSquare, labelText: insuranceVM.isInsuranceExpired @@ -468,7 +474,8 @@ class FamilyCardWidget extends StatelessWidget { ? AppColors.successColor.withOpacity(0.1) : AppColors.warningColorYellow.withOpacity(0.1), labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: insuranceVM.isInsuranceActive ? 6.w : 0.w), - ).toShimmer2(isShow: insuranceVM.isInsuranceLoading); + ).toShimmer2(isShow: insuranceVM.isInsuranceLoading) + : SizedBox.shrink(); }), ], ), From d053f58b7deb730dd263efbab232862046d2a32d Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 26 Mar 2026 22:34:25 +0300 Subject: [PATCH 23/33] Updates --- assets/langs/ar-SA.json | 7 +- assets/langs/en-US.json | 7 +- ios/Runner.xcodeproj/project.pbxproj | 14 +- ios/Runner/Info.plist | 1 - lib/core/api_consts.dart | 6 +- lib/core/dependencies.dart | 8 +- lib/core/utils/validation_utils.dart | 8 + lib/extensions/string_extensions.dart | 4 +- .../authentication_view_model.dart | 7 +- .../widgets/otp_verification_screen.dart | 42 +++-- .../hmg_services/hmg_services_view_model.dart | 5 + .../insurance/insurance_view_model.dart | 2 +- .../my_appointments_view_model.dart | 1 + .../profile_settings_repo.dart | 100 ++++++++++ .../profile_settings_view_model.dart | 99 +++++++++- lib/generated/locale_keys.g.dart | 1 + .../appointments/my_doctors_page.dart | 4 +- .../widgets/doctor_rating_details.dart | 23 ++- lib/presentation/home/landing_page.dart | 4 +- .../home/widgets/large_service_card.dart | 22 ++- .../insurance_update_details_card.dart | 7 +- lib/presentation/lab/lab_order_by_test.dart | 2 +- .../medical_file/medical_file_page.dart | 173 +++++++++++------- .../widgets/patient_sick_leave_card.dart | 23 ++- .../my_family/widget/family_cards.dart | 8 +- .../profile_settings/profile_settings.dart | 84 ++++++--- .../widgets/update_email_widget.dart | 106 +++++++++++ .../symptoms_checker/user_info_selection.dart | 2 +- .../widgets/condition_card.dart | 4 +- lib/widgets/appbar/collapsing_list_view.dart | 2 +- pubspec.yaml | 4 +- 31 files changed, 598 insertions(+), 182 deletions(-) create mode 100644 lib/features/profile_settings/profile_settings_repo.dart create mode 100644 lib/presentation/profile_settings/widgets/update_email_widget.dart diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 958a4902..268bf0a3 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -811,7 +811,7 @@ "awaitingApproval": "انتظر القبول", "news": "أخبار", "ready": "جاهز", - "enterValidNationalId": "الرجاء إدخال رقم الهوية الوطنية أو رقم الملف الصحيح", + "enterValidNationalId": "رقم الهوية أو رقم الملف غير صحيح", "enterValidPhoneNumber": "الرجاء إدخال رقم هاتف صالح", "cannotEnterSaudiOrUAENumber": "لا يمكنك إدخال أرقام هواتف السعودية (00966) أو الإمارات (00971) عند اختيار دولة 'أخرى'", "medicalCentersWithCount": "{count} مراكز طبية", @@ -1274,7 +1274,7 @@ "noVitalSignsRecordedYet": "لا توجد علامات حيوية مسجلة بعد", "appointmentsAndVisits": "المواعيد والزيارات", "labAndRadiology": "المختبر والأشعة", - "activeMedicationsAndPrescriptions": "الأدوية النشطة والوصفات الطبية", + "activeMedicationsAndPrescriptions": "الوصفات الطبية", "allPrescriptions": "جميع الوصفات", "allMedications": "جميع الأدوية", "youDontHaveAnyPrescriptionsYet": "ليس لديك أي وصفات طبية بعد.", @@ -1586,5 +1586,6 @@ "generateAiAnalysisResult": "قم بإجراء تحليل لهذا المختبر AI", "ratings": "التقييمات", "hmgPharmacyText": "صيدلية الحبيب، المتجر الصيدلاني الإلكتروني المتكامل الذي تقدمه لكم مجموعة خدمات الدكتور سليمان الحبيب الطبية.", - "insuranceRequestSubmittedSuccessfully": "تم إرسال طلب تحديث بيانات التأمين بنجاح. سيتم إعلامك بمجرد الانتهاء." + "insuranceRequestSubmittedSuccessfully": "تم إرسال طلب تحديث بيانات التأمين بنجاح. سيتم إعلامك بمجرد الانتهاء.", + "updatingEmailAddress": "جارٍ تحديث عنوان البريد الإلكتروني، يرجى الانتظار..." } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index cea0082a..d1a48222 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -802,7 +802,7 @@ "notNow": "Not Now", "pendingActivation": "Pending Activation", "awaitingApproval": "Awaiting Approval", - "enterValidNationalId": "Please enter a valid national ID or file number", + "enterValidNationalId": "Invalid Identification or file number", "enterValidPhoneNumber": "Please enter a valid phone number", "cannotEnterSaudiOrUAENumber": "You cannot enter Saudi Arabia (00966) or UAE (00971) phone numbers when 'Others' country is selected", "ready": "Ready", @@ -1266,7 +1266,7 @@ "noVitalSignsRecordedYet": "No vital signs recorded yet", "appointmentsAndVisits": "Appointments & visits", "labAndRadiology": "Lab & Radiology", - "activeMedicationsAndPrescriptions": "Active Medications & Prescriptions", + "activeMedicationsAndPrescriptions": "Recent Prescriptions", "allPrescriptions": "All Prescriptions", "allMedications": "All Medications", "youDontHaveAnyPrescriptionsYet": "You don't have any prescriptions yet.", @@ -1580,5 +1580,6 @@ "generateAiAnalysisResult": "Generate AI analysis for this result", "ratings": "Ratings", "hmgPharmacyText": "Al Habib Pharmacy, the complete online Pharmaceutical store brought to you by Dr. Sulaiman Al Habib Medical Services Group.", - "insuranceRequestSubmittedSuccessfully": "Your insurance update request has been successfully submitted. You will be notified once completed." + "insuranceRequestSubmittedSuccessfully": "Your insurance update request has been successfully submitted. You will be notified once completed.", + "updatingEmailAddress": "Updating email address, Please wait..." } diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8ed9d257..6a81b151 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -343,10 +343,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; @@ -360,10 +364,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; @@ -523,7 +531,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 8; + CURRENT_PROJECT_VERSION = 14; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -709,7 +717,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 8; + CURRENT_PROJECT_VERSION = 14; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -738,7 +746,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 8; + CURRENT_PROJECT_VERSION = 14; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 9c805ac5..f412b006 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -101,7 +101,6 @@ audio fetch - location remote-notification voip diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 6ad7b7ce..5fae22b1 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -233,7 +233,7 @@ class ApiConsts { static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API"; // ************ static values for Api **************** - static final double appVersionID = 20.3; + static final double appVersionID = 20.5; // static final double appVersionID = 50.7; static final int appChannelId = 3; @@ -920,6 +920,10 @@ const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard'; const SEND_PATIENT_IMMEDIATE_UPDATE_INSURANCE_REQUEST = 'Services/OUTPs.svc/REST/PatientCompanyUpdate'; +const PROFILE_SETTING = 'Services/Patients.svc/REST/GetPateintInfoForUpdate'; + +const SAVE_SETTING = 'Services/Patients.svc/REST/UpdatePateintInfo'; + class ApiKeyConstants { static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng'; } diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 4266aa3b..657d03ea 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -50,6 +50,7 @@ import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart'; import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; +import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_repo.dart'; import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/features/qr_parking/qr_parking_repo.dart'; import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart'; @@ -172,6 +173,7 @@ class AppDependencies { getIt.registerLazySingleton(() => NotificationsRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => AskDoctorRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => ServicesPriceListRepoImp(loggerService: getIt(), apiClient: getIt())); + getIt.registerLazySingleton(() => ProfileSettingsRepoImp(loggerService: getIt(), apiClient: getIt())); // ViewModels // Global/shared VMs → LazySingleton @@ -224,7 +226,11 @@ class AppDependencies { authenticationRepo: getIt(), cacheService: getIt(), navigationService: getIt(), dialogService: getIt(), appState: getIt(), errorHandlerService: getIt(), localAuthService: getIt()), ); - getIt.registerLazySingleton(() => ProfileSettingsViewModel(cacheService: getIt())); + getIt.registerLazySingleton(() => ProfileSettingsViewModel( + cacheService: getIt(), + profileSettingsRepo: getIt(), + errorHandlerService: getIt(), + )); getIt.registerLazySingleton(() => DateRangeSelectorRangeViewModel()); diff --git a/lib/core/utils/validation_utils.dart b/lib/core/utils/validation_utils.dart index a8bc03d3..b5651648 100644 --- a/lib/core/utils/validation_utils.dart +++ b/lib/core/utils/validation_utils.dart @@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.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/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; @@ -32,6 +33,13 @@ class ValidationUtils { isCorrectID = false; } + if(nationalId!.length == 10) { + if (Utils.isSAUDIIDValid(nationalId!) == false) { + _dialogService.showExceptionBottomSheet(message: LocaleKeys.enterValidNationalId.tr(), onOkPressed: onOkPress); + isCorrectID = false; + } + } + if (nationalId != null && nationalId.isNotEmpty && selectedCountry != null) { if (selectedCountry == CountryEnum.saudiArabia) { if (!validateIqama(nationalId)) { diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 93901497..6e28ffda 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -320,9 +320,9 @@ extension EmailValidator on String { height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.f, letterSpacing: -1, fontFamily: isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal), ); - Widget toText44({Color? color, bool isBold = false}) => Text( + Widget toText44({Color? color, bool isBold = false, bool isEnglishOnly = false,}) => Text( this, - style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), + style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: (isEnglishOnly ? "Poppins" : getIt.get().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),), ); Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) { diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index ce54c69f..336b35ae 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -28,6 +28,7 @@ import 'package:hmg_patient_app_new/features/authentication/models/resp_models/a import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_activation_code_resp_model.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_user_staus_nhic_response_model.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; @@ -619,11 +620,12 @@ class AuthenticationViewModel extends ChangeNotifier { } else { activation.list!.first.isParentUser = true; } - activation.list!.first.bloodGroup = activation.patientBlodType; + activation.list!.first.bloodGroup = activation.patientBloodType; activation.list!.first.zipCode = selectedCountrySignup == CountryEnum.others ? '0' : selectedCountrySignup.countryCode; _appState.setAuthenticatedUser(activation.list!.first); _appState.setPrivilegeModelList(activation.list!.first.listPrivilege!); - _appState.setUserBloodGroup = activation.patientBlodType ?? "N/A"; + // _appState.setUserBloodGroup = activation.patientBlodType ?? "N/A"; + _appState.setUserBloodGroup = activation.patientBloodType ?? "N/A"; } // _appState.setUserBloodGroup = (activation.patientBlodType ?? ""); _appState.setAppAuthToken = activation.authenticationTokenId; @@ -646,6 +648,7 @@ class AuthenticationViewModel extends ChangeNotifier { await clearDefaultInputValues(); myAppointmentsVM.setIsAppointmentDataToBeLoaded(true); getIt.get().setIsInsuranceDataToBeLoaded(true); + getIt.get().setHasVitalSignDataLoaded(false); if (isUserAgreedBefore) { LoaderBottomSheet.hideLoader(); navigateToHomeScreen(); diff --git a/lib/features/authentication/widgets/otp_verification_screen.dart b/lib/features/authentication/widgets/otp_verification_screen.dart index 7ddccda8..9e80dbb9 100644 --- a/lib/features/authentication/widgets/otp_verification_screen.dart +++ b/lib/features/authentication/widgets/otp_verification_screen.dart @@ -20,6 +20,8 @@ import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; import 'package:provider/provider.dart'; import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart'; +import 'dart:ui' as ui; + typedef OnDone = void Function(String text); class ProvidedPinBoxTextAnimation { @@ -564,23 +566,27 @@ class _OTPVerificationScreenState extends State { SizedBox(height: 16.h), Center( - child: OTPWidget( - maxLength: _otpLength, - controller: _otpController, - pinBoxWidth: 70.h, - pinBoxHeight: 100.h, - pinBoxRadius: 16, - pinBoxBorderWidth: 0, - pinBoxOuterPadding: EdgeInsets.symmetric(horizontal: 4.h), - defaultBorderColor: Colors.transparent, - textBorderColor: Colors.transparent, - pinBoxColor: AppColors.whiteColor, - autoFocus: true, - onTextChanged: _onOtpChanged, - pinTextStyle: TextStyle( - fontSize: 40.f, - fontWeight: FontWeight.bold, - color: AppColors.whiteColor, + child: Directionality( + textDirection: ui.TextDirection.ltr, + child: OTPWidget( + maxLength: _otpLength, + controller: _otpController, + pinBoxWidth: 70.h, + pinBoxHeight: 100.h, + pinBoxRadius: 16, + pinBoxBorderWidth: 0, + pinBoxOuterPadding: EdgeInsets.symmetric(horizontal: 4.h), + defaultBorderColor: Colors.transparent, + textBorderColor: Colors.transparent, + pinBoxColor: AppColors.whiteColor, + autoFocus: true, + onTextChanged: _onOtpChanged, + pinTextStyle: TextStyle( + fontSize: 40.f, + fontWeight: FontWeight.bold, + color: AppColors.whiteColor, + fontFamily: "Poppins" + ), ), ), ), @@ -601,7 +607,7 @@ class _OTPVerificationScreenState extends State { children: [ LocaleKeys.resendIn.tr(context: context).toText16(color: AppColors.inputLabelTextColor), SizedBox(width: 2.h), - ' ($minutes:$seconds). '.toText16(color: AppColors.inputLabelTextColor) + ' ($minutes:$seconds). '.toText16(color: AppColors.inputLabelTextColor, isEnglishOnly: true) ], ); }, diff --git a/lib/features/hmg_services/hmg_services_view_model.dart b/lib/features/hmg_services/hmg_services_view_model.dart index 5bf450ba..7b32cc6e 100644 --- a/lib/features/hmg_services/hmg_services_view_model.dart +++ b/lib/features/hmg_services/hmg_services_view_model.dart @@ -85,6 +85,11 @@ class HmgServicesViewModel extends ChangeNotifier { List covidTestProcedureList = []; Covid19GetPaymentInfo? covidPaymentInfo; + void setHasVitalSignDataLoaded(bool hasVitalSignDataLoaded) { + this.hasVitalSignDataLoaded = hasVitalSignDataLoaded; + notifyListeners(); + } + Future getOrdersList() async {} // HHC multiple services selection diff --git a/lib/features/insurance/insurance_view_model.dart b/lib/features/insurance/insurance_view_model.dart index d66a7a22..d1423113 100644 --- a/lib/features/insurance/insurance_view_model.dart +++ b/lib/features/insurance/insurance_view_model.dart @@ -88,7 +88,7 @@ class InsuranceViewModel extends ChangeNotifier { (failure) async { debugPrint("InsuranceViewModel: API call failed - ${failure.toString()}"); isInsuranceLoading = false; - isInsuranceDataToBeLoaded = false; + isInsuranceDataToBeLoaded = true; isInsuranceExpired = false; isInsuranceActive = false; notifyListeners(); diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index d2296a66..1584f891 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -634,6 +634,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { Future getPatientMyDoctors({Function(dynamic)? onSuccess, Function(String)? onError}) async { // if (!isAppointmentDataToBeLoaded) return; isPatientMyDoctorsLoading = true; + patientMyDoctorsList.clear(); notifyListeners(); final result = await myAppointmentsRepo.getPatientDoctorsList(); diff --git a/lib/features/profile_settings/profile_settings_repo.dart b/lib/features/profile_settings/profile_settings_repo.dart new file mode 100644 index 00000000..253bf505 --- /dev/null +++ b/lib/features/profile_settings/profile_settings_repo.dart @@ -0,0 +1,100 @@ +import 'package:dartz/dartz.dart'; +import 'package:hmg_patient_app_new/core/api/api_client.dart'; +import 'package:hmg_patient_app_new/core/api_consts.dart'; +import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; + +abstract class ProfileSettingsRepo { + /// Updates general patient info (name, phone, etc.). + Future>> updatePatientInfo({ + required Map patientInfo, + }); + + /// Deactivates (deletes) the patient's account. + Future>> deactivateAccount(); +} + +class ProfileSettingsRepoImp implements ProfileSettingsRepo { + final ApiClient apiClient; + final LoggerService loggerService; + + ProfileSettingsRepoImp({ + required this.loggerService, + required this.apiClient, + }); + + @override + Future>> updatePatientInfo({ + required Map patientInfo, + }) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + + await apiClient.post( + SAVE_SETTING, + body: patientInfo, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: response, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } + + @override + Future>> deactivateAccount() async { + final Map body = {}; + + try { + GenericApiModel? apiResponse; + Failure? failure; + + await apiClient.post( + // TODO: Replace with actual deactivate-account endpoint once available + 'Services/Patients.svc/REST/Patient_DeactivateAccount', + body: body, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: response, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } +} + diff --git a/lib/features/profile_settings/profile_settings_view_model.dart b/lib/features/profile_settings/profile_settings_view_model.dart index e001d1bd..92f11528 100644 --- a/lib/features/profile_settings/profile_settings_view_model.dart +++ b/lib/features/profile_settings/profile_settings_view_model.dart @@ -1,18 +1,42 @@ import 'package:flutter/foundation.dart'; +import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_repo.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; +import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; class ProfileSettingsViewModel extends ChangeNotifier { static const String _darkModeKey = 'is_dark_mode'; final CacheService _cacheService; + final ProfileSettingsRepo profileSettingsRepo; + final ErrorHandlerService errorHandlerService; + // ── Dark-mode state ────────────────────────────────────────────────── bool _isDarkMode = false; - bool get isDarkMode => _isDarkMode; - ProfileSettingsViewModel({required CacheService cacheService}) - : _cacheService = cacheService; + // ── Update email state ─────────────────────────────────────────────── + bool isUpdateEmailLoading = false; + bool isUpdateEmailSuccess = false; + String? updateEmailError; + + // ── Update patient info state ──────────────────────────────────────── + bool isUpdatePatientInfoLoading = false; + bool isUpdatePatientInfoSuccess = false; + String? updatePatientInfoError; + + // ── Deactivate account state ───────────────────────────────────────── + bool isDeactivateAccountLoading = false; + bool isDeactivateAccountSuccess = false; + String? deactivateAccountError; + + ProfileSettingsViewModel({ + required CacheService cacheService, + required this.profileSettingsRepo, + required this.errorHandlerService, + }) : _cacheService = cacheService; + + // ── Dark mode ──────────────────────────────────────────────────────── /// Call once at app startup (before the first frame) to restore the /// persisted dark-mode preference. @@ -30,6 +54,75 @@ class ProfileSettingsViewModel extends ChangeNotifier { notifyListeners(); } + // ── Update patient info ────────────────────────────────────────────── + + Future updatePatientInfo({ + required Map patientInfo, + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { + isUpdatePatientInfoLoading = true; + isUpdatePatientInfoSuccess = false; + updatePatientInfoError = null; + notifyListeners(); + + final result = await profileSettingsRepo.updatePatientInfo(patientInfo: patientInfo); + + result.fold( + (failure) { + isUpdatePatientInfoLoading = false; + updatePatientInfoError = failure.message; + notifyListeners(); + if (onError != null) { + onError(failure.message); + } else { + errorHandlerService.handleError(failure: failure); + } + }, + (response) { + isUpdatePatientInfoLoading = false; + isUpdatePatientInfoSuccess = true; + notifyListeners(); + onSuccess?.call(response.data); + }, + ); + } + + // ── Deactivate account ─────────────────────────────────────────────── + + Future deactivateAccount({ + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { + isDeactivateAccountLoading = true; + isDeactivateAccountSuccess = false; + deactivateAccountError = null; + notifyListeners(); + + final result = await profileSettingsRepo.deactivateAccount(); + + result.fold( + (failure) { + isDeactivateAccountLoading = false; + deactivateAccountError = failure.message; + notifyListeners(); + if (onError != null) { + onError(failure.message); + } else { + errorHandlerService.handleError(failure: failure); + } + }, + (response) { + isDeactivateAccountLoading = false; + isDeactivateAccountSuccess = true; + notifyListeners(); + onSuccess?.call(response.data); + }, + ); + } + + // ── Helpers ────────────────────────────────────────────────────────── + void notify() { notifyListeners(); } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 2aeb87f1..031e1be9 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1581,5 +1581,6 @@ abstract class LocaleKeys { static const ratings = 'ratings'; static const hmgPharmacyText = 'hmgPharmacyText'; static const insuranceRequestSubmittedSuccessfully = 'insuranceRequestSubmittedSuccessfully'; + static const updatingEmailAddress = 'updatingEmailAddress'; } diff --git a/lib/presentation/appointments/my_doctors_page.dart b/lib/presentation/appointments/my_doctors_page.dart index d1ea0e98..002f537c 100644 --- a/lib/presentation/appointments/my_doctors_page.dart +++ b/lib/presentation/appointments/my_doctors_page.dart @@ -93,8 +93,6 @@ class _MyDoctorsPageState extends State { borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, - - ), SizedBox(width: 8.h), CustomButton( @@ -280,7 +278,7 @@ class _MyDoctorsPageState extends State { runSpacing: 4.h, children: [ AppCustomChipWidget( - labelText: isSortByClinic ? (doctor?.clinicName ?? "") : (doctor?.projectName ?? ""), + labelText: isSortByClinic ? (doctor?.projectName ?? "") : (doctor?.clinicName ?? ""), ), ], ), diff --git a/lib/presentation/book_appointment/widgets/doctor_rating_details.dart b/lib/presentation/book_appointment/widgets/doctor_rating_details.dart index 6d9e1cb2..1a5eedfe 100644 --- a/lib/presentation/book_appointment/widgets/doctor_rating_details.dart +++ b/lib/presentation/book_appointment/widgets/doctor_rating_details.dart @@ -20,13 +20,20 @@ class DoctorRatingDetails extends StatelessWidget { : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.ceilToDouble().toString().toText44(isBold: true), + bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.ceilToDouble().toString().toText44(isBold: true, isEnglishOnly: true), SizedBox(height: 4.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "${bookAppointmentsVM.doctorsProfileResponseModel.noOfPatientsRate} ${LocaleKeys.reviews.tr(context: context)}" - .toText16(weight: FontWeight.w500, color: AppColors.greyInfoTextColor), + Row( + children: [ + "${bookAppointmentsVM.doctorsProfileResponseModel.noOfPatientsRate} " + .toText16(weight: FontWeight.w500, color: AppColors.greyInfoTextColor, isEnglishOnly: true), + LocaleKeys.reviews.tr(context: context) + .toText16(weight: FontWeight.w500, color: AppColors.greyInfoTextColor,), + ], + ), + RatingBar( initialRating: bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.toDouble(), direction: Axis.horizontal, @@ -75,7 +82,7 @@ class DoctorRatingDetails extends StatelessWidget { ), Container( margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), - child: Text("${getRatingWidth(bookAppointmentsVM.doctorDetailsList[0].ratio).round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), + child: Text("${getRatingWidth(bookAppointmentsVM.doctorDetailsList[0].ratio).round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")), ), ], ), @@ -95,7 +102,7 @@ class DoctorRatingDetails extends StatelessWidget { ), Container( margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), - child: Text("${bookAppointmentsVM.doctorDetailsList[1].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), + child: Text("${bookAppointmentsVM.doctorDetailsList[1].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")), ), ], ), @@ -115,7 +122,7 @@ class DoctorRatingDetails extends StatelessWidget { ), Container( margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), - child: Text("${bookAppointmentsVM.doctorDetailsList[2].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), + child: Text("${bookAppointmentsVM.doctorDetailsList[2].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")), ), ], ), @@ -135,7 +142,7 @@ class DoctorRatingDetails extends StatelessWidget { ), Container( margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), - child: Text("${bookAppointmentsVM.doctorDetailsList[3].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), + child: Text("${bookAppointmentsVM.doctorDetailsList[3].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")), ), ], ), @@ -156,7 +163,7 @@ class DoctorRatingDetails extends StatelessWidget { ), Container( margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0), - child: Text("${bookAppointmentsVM.doctorDetailsList[4].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600)), + child: Text("${bookAppointmentsVM.doctorDetailsList[4].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: AppColors.textColor, fontWeight: FontWeight.w600, fontFamily: "Poppins")), ), ], ), diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 3012876f..0c17434e 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -407,10 +407,10 @@ class _LandingPageState extends State { ? myAppointmentsVM.patientAppointmentsHistoryList.length : 3, layout: SwiperLayout.STACK, - loop: true, + loop: false, itemWidth: MediaQuery.of(context).size.width - 48.h, indicatorLayout: PageIndicatorLayout.COLOR, - axisDirection: AxisDirection.right, + axisDirection: getIt.get().isArabic() ? AxisDirection.left : AxisDirection.right, controller: _controller, itemHeight: 255.h + 20, // extra space for shadow diff --git a/lib/presentation/home/widgets/large_service_card.dart b/lib/presentation/home/widgets/large_service_card.dart index 4405a197..b89e58c5 100644 --- a/lib/presentation/home/widgets/large_service_card.dart +++ b/lib/presentation/home/widgets/large_service_card.dart @@ -1,6 +1,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/api_consts.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/size_utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -92,12 +93,12 @@ class LargeServiceCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ serviceCardData.title.tr(context: context).toText14(isBold: true, color: AppColors.textColor), - serviceCardData.subtitle.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), + serviceCardData.subtitle.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight, maxLine: 2), ], ), ), ], - ).paddingSymmetrical(16.w, 0.h).expanded, + ).paddingSymmetrical(8.w, 0.h).expanded, CustomButton( text: serviceCardData.isBold ? LocaleKeys.visitPharmacyOnline.tr(context: context) : LocaleKeys.bookNow.tr(context: context), onPressed: () { @@ -177,7 +178,9 @@ class FadedLargeServiceCard extends StatelessWidget { children: [ ClipRRect( borderRadius: BorderRadius.circular(24.r), - child: Image.asset(serviceCardData.largeCardIcon, fit: BoxFit.cover, width: 520.w, height: 250.h), + child: Transform.flip( + flipX: getIt.get().isArabic(), + child: Image.asset(serviceCardData.largeCardIcon, fit: BoxFit.cover, width: 520.w, height: 250.h)), ), Positioned( top: 0, @@ -216,11 +219,14 @@ class FadedLargeServiceCard extends StatelessWidget { ), child: Padding( padding: EdgeInsets.all(8.h), - child: Utils.buildSvgWithAssets( - icon: serviceCardData.icon, - iconColor: serviceCardData.iconColor, - fit: BoxFit.contain, - applyThemeColor: false + child: Transform.flip( + flipX: getIt.get().isArabic(), + child: Utils.buildSvgWithAssets( + icon: serviceCardData.icon, + iconColor: serviceCardData.iconColor, + fit: BoxFit.contain, + applyThemeColor: false + ), ), ), ), diff --git a/lib/presentation/insurance/widgets/insurance_update_details_card.dart b/lib/presentation/insurance/widgets/insurance_update_details_card.dart index 59a4dd97..2136f0cb 100644 --- a/lib/presentation/insurance/widgets/insurance_update_details_card.dart +++ b/lib/presentation/insurance/widgets/insurance_update_details_card.dart @@ -110,6 +110,7 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget { LoaderBottomSheet.hideLoader(); insuranceViewModel.setIsInsuranceDataToBeLoaded(true); insuranceViewModel.initInsuranceProvider(); + Navigator.pop(context); }, onError: (err) { insuranceViewModel.updatePatientInsuranceCard( patientID: appState.getAuthenticatedUser()!.patientId!, @@ -129,9 +130,9 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget { isFullScreen: false, isCloseButtonVisible: false, ); - Future.delayed(Duration(milliseconds: 2000)).then((value) async { - Navigator.pop(context); - }); + // Future.delayed(Duration(milliseconds: 2000)).then((value) async { + // Navigator.pop(context); + // }); }, onError: (err) { LoaderBottomSheet.hideLoader(); diff --git a/lib/presentation/lab/lab_order_by_test.dart b/lib/presentation/lab/lab_order_by_test.dart index 1b5db920..ac6f0f3b 100644 --- a/lib/presentation/lab/lab_order_by_test.dart +++ b/lib/presentation/lab/lab_order_by_test.dart @@ -59,7 +59,7 @@ class LabOrderByTest extends StatelessWidget { icon: AppAssets.view_report_icon, iconColor: AppColors.primaryRedColor, iconSize: 16.h, - text: LocaleKeys.viewReport.tr(context: context), + text: LocaleKeys.viewResults.tr(context: context), onPressed: () { onTap(); }, diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index b804a751..1c839c10 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -283,9 +283,9 @@ class _MedicalFilePageState extends State { ), AppCustomChipWidget( icon: AppAssets.blood_icon, - labelText: LocaleKeys.bloodGroup.tr(namedArgs: {'bloodType': appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup}, context: context), + labelText: appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup, iconColor: AppColors.primaryRedColor, - labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), + labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), padding: EdgeInsets.zero, ), Consumer(builder: (context, insuranceVM, child) { @@ -749,7 +749,26 @@ class _MedicalFilePageState extends State { ], ).paddingSymmetrical(0.w, 0.h), SizedBox(height: 24.h), - LocaleKeys.activeMedicationsAndPrescriptions.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.activeMedicationsAndPrescriptions.tr(context: context).toText16(weight: FontWeight.w500, letterSpacing: -0.2), + Row( + children: [ + LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + SizedBox(width: 2.w), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], + ).onPress(() { + // myAppointmentsViewModel.getPatientMyDoctors(); + Navigator.of(context).push( + CustomPageRoute( + page: PrescriptionsListPage(), + ), + ); + }), + ], + ), SizedBox(height: 16.h), Consumer(builder: (context, prescriptionVM, child) { return prescriptionVM.isPrescriptionsOrdersLoading @@ -830,55 +849,55 @@ class _MedicalFilePageState extends State { separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), ), SizedBox(height: 16.h), - Divider(color: AppColors.dividerColor), - SizedBox(height: 16.h), - Row( - children: [ - Expanded( - child: CustomButton( - text: LocaleKeys.allPrescriptions.tr(context: context), - onPressed: () { - Navigator.of(context).push( - CustomPageRoute( - page: PrescriptionsListPage(), - ), - ); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 12.f, - fontWeight: FontWeight.w500, - borderRadius: 12.r, - height: 40.h, - icon: AppAssets.requests, - iconColor: AppColors.primaryRedColor, - iconSize: 16.w, - ), - ), - SizedBox(width: 6.w), - Expanded( - child: CustomButton( - text: LocaleKeys.allMedications.tr(context: context), - onPressed: () { Navigator.of(context).push( - CustomPageRoute( - page: ActiveMedicationPage(), - ), - );}, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 12.f, - fontWeight: FontWeight.w500, - borderRadius: 12.h, - height: 40.h, - icon: AppAssets.all_medications_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 16.h, - ), - ), - ], - ), + // Divider(color: AppColors.dividerColor), + // SizedBox(height: 16.h), + // Row( + // children: [ + // Expanded( + // child: CustomButton( + // text: LocaleKeys.allPrescriptions.tr(context: context), + // onPressed: () { + // Navigator.of(context).push( + // CustomPageRoute( + // page: PrescriptionsListPage(), + // ), + // ); + // }, + // backgroundColor: AppColors.secondaryLightRedColor, + // borderColor: AppColors.secondaryLightRedColor, + // textColor: AppColors.primaryRedColor, + // fontSize: 12.f, + // fontWeight: FontWeight.w500, + // borderRadius: 12.r, + // height: 40.h, + // icon: AppAssets.requests, + // iconColor: AppColors.primaryRedColor, + // iconSize: 16.w, + // ), + // ), + // SizedBox(width: 6.w), + // Expanded( + // child: CustomButton( + // text: LocaleKeys.allMedications.tr(context: context), + // onPressed: () { Navigator.of(context).push( + // CustomPageRoute( + // page: ActiveMedicationPage(), + // ), + // );}, + // backgroundColor: AppColors.secondaryLightRedColor, + // borderColor: AppColors.secondaryLightRedColor, + // textColor: AppColors.primaryRedColor, + // fontSize: 12.f, + // fontWeight: FontWeight.w500, + // borderRadius: 12.h, + // height: 40.h, + // icon: AppAssets.all_medications_icon, + // iconColor: AppColors.primaryRedColor, + // iconSize: 16.h, + // ), + // ), + // ], + // ), ], ), ), @@ -911,7 +930,7 @@ class _MedicalFilePageState extends State { Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), ], ).onPress(() { - myAppointmentsViewModel.getPatientMyDoctors(); + // myAppointmentsViewModel.getPatientMyDoctors(); Navigator.of(context).push( CustomPageRoute( page: MyDoctorsPage(), @@ -1210,6 +1229,26 @@ class _MedicalFilePageState extends State { // Requests Tab Data return Column( children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}".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), + ], + ), + ], + ).onPress(() { + Navigator.of(context).push( + CustomPageRoute( + page: PatientSickleavesListPage(), + ), + ); + }), + SizedBox(height: 16.h), Consumer(builder: (context, medicalFileVM, child) { return medicalFileVM.isPatientSickLeaveListLoading ? PatientSickLeaveCard( @@ -1279,20 +1318,20 @@ class _MedicalFilePageState extends State { ), ); }), - MedicalFileCard( - label: LocaleKeys.sickLeaveReport.tr(context: context), - textColor: AppColors.blackColor, - backgroundColor: AppColors.whiteColor, - svgIcon: AppAssets.sick_leave_report_icon, - isLargeText: true, - iconSize: 36.h, - ).onPress(() { - Navigator.of(context).push( - CustomPageRoute( - page: PatientSickleavesListPage(), - ), - ); - }), + // MedicalFileCard( + // label: LocaleKeys.sickLeaveReport.tr(context: context), + // textColor: AppColors.blackColor, + // backgroundColor: AppColors.whiteColor, + // svgIcon: AppAssets.sick_leave_report_icon, + // isLargeText: true, + // iconSize: 36.h, + // ).onPress(() { + // Navigator.of(context).push( + // CustomPageRoute( + // page: PatientSickleavesListPage(), + // ), + // ); + // }), ], ).paddingSymmetrical(0.w, 0.0), SizedBox(height: 24.h), diff --git a/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart b/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart index a0c54e68..18bd2e69 100644 --- a/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart +++ b/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart @@ -40,18 +40,17 @@ class PatientSickLeaveCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}".toText16(isBold: true).toShimmer2(isShow: isLoading), - AppCustomChipWidget( - labelText: isLoading ? "" : getStatusText(context), - backgroundColor: getStatusColor().withOpacity(0.15), - textColor: getStatusColor(), - ).toShimmer2(isShow: isLoading, width: 100.h), - ], - ), - SizedBox(height: 16.h), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // AppCustomChipWidget( + // labelText: isLoading ? "" : getStatusText(context), + // backgroundColor: getStatusColor().withOpacity(0.15), + // textColor: getStatusColor(), + // ).toShimmer2(isShow: isLoading, width: 100.h), + // ], + // ), + // SizedBox(height: 16.h), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart index 826b1741..f304fcc3 100644 --- a/lib/presentation/my_family/widget/family_cards.dart +++ b/lib/presentation/my_family/widget/family_cards.dart @@ -102,7 +102,7 @@ class _FamilyCardsState extends State { : profile.status == FamilyFileEnum.active.toInt ? AppColors.lightGreenColor : AppColors.lightGrayBGColor, - chipText: profile.statusDescription ?? "N/A", + chipText: profile.statusDescription ?? " N/A", iconAsset: null, isShowBorder: false, borderRadius: 8.h, @@ -154,7 +154,7 @@ class _FamilyCardsState extends State { crossAxisCount: 2, crossAxisSpacing: 10.w, mainAxisSpacing: 10.h, - childAspectRatio: widget.isShowDetails ? 0.56.h : 0.64.h, + childAspectRatio: widget.isShowDetails ? 0.56.h : 0.74.h, ), padding: EdgeInsets.only(bottom: 20.h), itemBuilder: (context, index) { @@ -164,7 +164,7 @@ class _FamilyCardsState extends State { final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID); return Container( padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 15.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), child: Opacity( opacity: isActive || profile.status == FamilyFileEnum.pending.toInt || !canSwitch ? 0.4 : 1.0, // Fade all content if active child: Stack( @@ -187,7 +187,7 @@ class _FamilyCardsState extends State { CustomChipWidget( chipType: ChipTypeEnum.alert, backgroundColor: AppColors.lightGrayBGColor, - chipText: "Relation:${profile.relationship ?? " N/A"}", + chipText: "Relation: ${profile.relationship ?? " N/A"}", iconAsset: AppAssets.heart, isShowBorder: false, borderRadius: 8.h, diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index e975d6f4..98002ca9 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -24,6 +24,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/insurance/widgets/insurance_update_details_card.dart'; +import 'package:hmg_patient_app_new/presentation/profile_settings/widgets/update_email_widget.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/app_language_change.dart'; @@ -115,7 +116,7 @@ class ProfileSettingsState extends State { // extra space for shadow itemWidth: SizeUtils.width - 30.w, indicatorLayout: PageIndicatorLayout.COLOR, - axisDirection: AxisDirection.right, + axisDirection: getIt.get().isArabic() ? AxisDirection.left : AxisDirection.right, controller: _controller, pagination: SwiperPagination( alignment: Alignment.bottomCenter, @@ -234,24 +235,24 @@ class ProfileSettingsState extends State { ], ), ), - 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), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), - child: Column( - children: [ - actionItem(AppAssets.language_change, LocaleKeys.language.tr(context: context), () { - showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.language.tr(context: context), child: AppLanguageChange(), callBackFunc: () {}, isFullScreen: false); - }, trailingLabel: Utils.appState.isArabic() ? "العربية" : "English"), - 1.divider, - actionItem(AppAssets.bell, LocaleKeys.notificationsSettings.tr(context: context), () { - openAppSettings(); - }), - // 1.divider, - // actionItem(AppAssets.touch_face_id, LocaleKeys.touchIDFaceIDServices.tr(context: context), () {}, switchValue: true), - ], - ), - ), + // 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), + // decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), + // child: Column( + // children: [ + // actionItem(AppAssets.language_change, LocaleKeys.language.tr(context: context), () { + // showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.language.tr(context: context), child: AppLanguageChange(), callBackFunc: () {}, isFullScreen: false); + // }, trailingLabel: Utils.appState.isArabic() ? "العربية" : "English"), + // 1.divider, + // actionItem(AppAssets.bell, LocaleKeys.notificationsSettings.tr(context: context), () { + // openAppSettings(); + // }), + // // 1.divider, + // // actionItem(AppAssets.touch_face_id, LocaleKeys.touchIDFaceIDServices.tr(context: context), () {}, switchValue: true), + // ], + // ), + // ), LocaleKeys.personalInformation.tr(context: context).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), @@ -259,7 +260,15 @@ class ProfileSettingsState extends State { decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), child: Column( children: [ - actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(context: context), () {}), + actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(context: context), () { + showCommonBottomSheetWithoutHeight( + context, + title: LocaleKeys.updateEmailAddress.tr(context: context), + child: UpdateEmailDialog(), + callBackFunc: () {}, + isFullScreen: false, + ); + }), // 1.divider, // actionItem(AppAssets.smart_phone_fill, "Phone Number".needTranslation, () {}), // 1.divider, @@ -385,10 +394,24 @@ class FamilyCardWidget extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ "${profile.patientName}".toText18(isBold: true, weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1, isEnglishOnly: true), - AppCustomChipWidget( - icon: AppAssets.file_icon, - labelText: "${LocaleKeys.fileNo.tr(context: context)}: ${profile.responseId}", - iconSize: 12.w, + Wrap( + direction: Axis.horizontal, + spacing: 4.w, + runSpacing: 6.w, + children: [ + AppCustomChipWidget( + labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), + icon: AppAssets.file_icon, + labelText: "${LocaleKeys.fileno.tr(context: context)}: ${profile.responseId}", + iconSize: 12.w, + ), + isActive ? AppCustomChipWidget( + icon: AppAssets.checkmark_icon, + labelText: LocaleKeys.verified.tr(context: context), + iconColor: AppColors.successColor, + labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), + ) : SizedBox.shrink(), + ], ), ], ).expanded, @@ -406,13 +429,14 @@ class FamilyCardWidget extends StatelessWidget { AppCustomChipWidget( labelText: LocaleKeys.ageYearsOld.tr(namedArgs: {'age': profile.age.toString(), 'yearsOld': LocaleKeys.yearsOld.tr(context: context)}), ), - isActive && appState.getAuthenticatedUser()!.bloodGroup != null - ? AppCustomChipWidget( - icon: AppAssets.blood_icon, + // isActive && appState.getAuthenticatedUser()!.bloodGroup != null + // ? + isActive ? AppCustomChipWidget( + icon: AppAssets.blood_icon, labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 8.w), - labelText: "Blood: ${appState.getAuthenticatedUser()!.bloodGroup ?? ""}", - iconColor: AppColors.primaryRedColor) - : SizedBox(), + labelText: appState.getAuthenticatedUser()!.bloodGroup ?? "N/A", + iconColor: AppColors.primaryRedColor) + : SizedBox(), Consumer(builder: (context, insuranceVM, child) { return isActive ? AppCustomChipWidget( diff --git a/lib/presentation/profile_settings/widgets/update_email_widget.dart b/lib/presentation/profile_settings/widgets/update_email_widget.dart new file mode 100644 index 00000000..ad9b9d5a --- /dev/null +++ b/lib/presentation/profile_settings/widgets/update_email_widget.dart @@ -0,0 +1,106 @@ +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_state.dart'; +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/string_extensions.dart'; +import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_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/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:provider/provider.dart'; + +class UpdateEmailDialog extends StatefulWidget { + UpdateEmailDialog({super.key}); + + @override + State createState() => _UpdateEmailDialogState(); +} + +class _UpdateEmailDialogState extends State { + late FocusNode _textFieldFocusNode; + late TextEditingController? textController; + ProfileSettingsViewModel? profileSettingsViewModel; + + @override + void initState() { + _textFieldFocusNode = FocusNode(); + textController = TextEditingController(); + textController!.text = getIt.get().getAuthenticatedUser()!.emailAddress ?? ""; + super.initState(); + } + + @override + void dispose() { + _textFieldFocusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + profileSettingsViewModel = Provider.of(context); + return GestureDetector( + onTap: () { + _textFieldFocusNode.unfocus(); + FocusScope.of(context).unfocus(); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Enter the new email address to be updated in your HMG File: ".toText16(textAlign: TextAlign.start, weight: FontWeight.w500), + SizedBox(height: 12.h), + TextInputWidget( + labelText: LocaleKeys.email.tr(), + hintText: "demo@gmail.com", + controller: textController, + focusNode: _textFieldFocusNode, + autoFocus: true, + padding: EdgeInsets.all(8.h), + keyboardType: TextInputType.emailAddress, + isEnable: true, + isReadOnly: false, + prefix: null, + isBorderAllowed: false, + isAllowLeadingIcon: true, + fontSize: 14.f, + isCountryDropDown: false, + leadingIcon: AppAssets.email, + fontFamily: "Poppins", + ), + SizedBox(height: 12.h), + CustomButton( + text: LocaleKeys.submit.tr(context: context), + onPressed: () { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.updatingEmailAddress.tr(context: context)); + profileSettingsViewModel!.updatePatientInfo( + patientInfo: {"EmailAddress": textController!.text}, + onSuccess: (response) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), + callBackFunc: () async { + Navigator.of(context).pop(); + }, isFullScreen: false); + }, + onError: (error) { + LoaderBottomSheet.hideLoader(); + // Show error message + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(error)), + ); + }, + ); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: const Color(0xFFffffff), + ), + ], + ), + ); + } +} diff --git a/lib/presentation/symptoms_checker/user_info_selection.dart b/lib/presentation/symptoms_checker/user_info_selection.dart index f1e8413d..b245c014 100644 --- a/lib/presentation/symptoms_checker/user_info_selection.dart +++ b/lib/presentation/symptoms_checker/user_info_selection.dart @@ -100,7 +100,7 @@ class _UserInfoSelectionPageState extends State { children: [ title.toText14(weight: FontWeight.w500), subTitle - .toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500) + .toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500, isEnglishOnly: true) .toShimmer2(isShow: (leadingIcon == AppAssets.rulerIcon || leadingIcon == AppAssets.weightScale) && hmgServicesVM.isVitalSignLoading), ], ), diff --git a/lib/presentation/symptoms_checker/widgets/condition_card.dart b/lib/presentation/symptoms_checker/widgets/condition_card.dart index e48f41ea..d753b780 100644 --- a/lib/presentation/symptoms_checker/widgets/condition_card.dart +++ b/lib/presentation/symptoms_checker/widgets/condition_card.dart @@ -168,7 +168,7 @@ class ConditionCard extends StatelessWidget { crossAxisAlignment: WrapCrossAlignment.center, children: [ for (int i = 0; i < symptoms.length; i++) ...[ - "● ${symptoms[i]}".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + "● ${symptoms[i]}".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, isEnglishOnly: true), if (i != symptoms.length - 1) Padding( padding: EdgeInsets.symmetric(horizontal: 2.w), @@ -228,7 +228,7 @@ class ConditionCard extends StatelessWidget { backgroundColor: AppColors.scaffoldBgColor, titleWidget: Row( children: [ - "$percentage%".toText12(fontWeight: FontWeight.bold, color: getChipColorBySeverityEnum(severityEnum)), + "$percentage%".toText12(fontWeight: FontWeight.bold, color: getChipColorBySeverityEnum(severityEnum), isEnglishOnly: true), ], ).paddingSymmetrical(0, 4.h), ), diff --git a/lib/widgets/appbar/collapsing_list_view.dart b/lib/widgets/appbar/collapsing_list_view.dart index 4a315c6e..b933e530 100644 --- a/lib/widgets/appbar/collapsing_list_view.dart +++ b/lib/widgets/appbar/collapsing_list_view.dart @@ -259,7 +259,7 @@ class _ScrollAnimatedTitleState extends State { super.dispose(); } - double t = 0; + double t = 1.0; void _onScroll() { final double offset = widget.controller.offset; diff --git a/pubspec.yaml b/pubspec.yaml index bca92d54..4484fa77 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,8 +2,8 @@ name: hmg_patient_app_new description: "New HMG Patient App" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -#version: 0.0.13+10 -version: 0.0.1+13 +version: 0.0.15+12 +#version: 0.0.1+14 environment: sdk: ">=3.6.0 <4.0.0" From 0ed6103b1527134f3194de2deb5cc452494fd6b5 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 29 Mar 2026 13:58:36 +0300 Subject: [PATCH 24/33] updates --- lib/extensions/widget_extensions.dart | 8 +- lib/presentation/contact_us/contact_us.dart | 41 +- lib/presentation/home/landing_page.dart | 989 ++++++++++-------- .../home/widgets/welcome_widget.dart | 58 +- .../medical_file/medical_file_page.dart | 25 +- .../my_family/widget/family_cards.dart | 371 +++++-- .../profile_settings/profile_settings.dart | 260 ++--- lib/services/dialog_service.dart | 3 +- lib/theme/colors.dart | 2 +- 9 files changed, 1027 insertions(+), 730 deletions(-) diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 5e4d4e1f..f0897950 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -165,11 +165,11 @@ extension SmoothContainerExtension on ShapeBorder { shadows: hasShadow ? [ BoxShadow( - color: hasDenseShadow ? const Color(0xff000000).withOpacity(.30) : const Color(0xff000000).withOpacity(.1), - // color: AppColors.primaryRedColor.withOpacity(.5), - blurRadius: 10, + // color: hasDenseShadow ? const Color(0xff000000).withOpacity(.06) : const Color(0xff000000).withOpacity(.1), + color: const Color(0xffE1E1E1).withOpacity(1.0), + blurRadius: 0, spreadRadius: 0, - offset: const Offset(0, 0), + offset: const Offset(1, 0), ) ] : [], diff --git a/lib/presentation/contact_us/contact_us.dart b/lib/presentation/contact_us/contact_us.dart index fd0a439b..16a154a1 100644 --- a/lib/presentation/contact_us/contact_us.dart +++ b/lib/presentation/contact_us/contact_us.dart @@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/presentation/contact_us/live_chat_page.dart' import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; class ContactUs extends StatelessWidget { ContactUs({super.key}); @@ -33,6 +34,15 @@ class ContactUs extends StatelessWidget { contactUsViewModel = Provider.of(context); return Column( children: [ + checkInOptionCard( + AppAssets.call_fill, + LocaleKeys.callNow.tr(), + // LocaleKeys.viewNearestHMGLocationsviewNearestHMGLocations.tr(), + "Call for immediate assistance", + ).onPress(() { + launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + }), + SizedBox(height: 16.h), checkInOptionCard( AppAssets.location, LocaleKeys.findUs.tr(), @@ -46,26 +56,23 @@ class ContactUs extends StatelessWidget { page: FindUsPage(), ), ); + }, onFailure: () { + Navigator.pop(context); + Navigator.of(context).push( + CustomPageRoute( + page: FindUsPage(), + ), + ); + }, onLocationDeniedForever: () { + Navigator.pop(context); + Navigator.of(context).push( + CustomPageRoute( + page: FindUsPage(), + ), + ); }); }), SizedBox(height: 16.h), - checkInOptionCard( - AppAssets.feedbackFill, - LocaleKeys.feedback.tr(), - LocaleKeys.provideFeedbackOnServices.tr(), - ).onPress(() { - contactUsViewModel.setSelectedFeedbackType( - FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'), - ); - contactUsViewModel.setIsSendFeedbackTabSelected(true); - Navigator.pop(context); - Navigator.of(context).push( - CustomPageRoute( - page: FeedbackPage(), - ), - ); - }), - SizedBox(height: 16.h), checkInOptionCard( AppAssets.ask_doctor_icon, LocaleKeys.liveChat.tr(), diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 0c17434e..768a31d1 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -25,6 +25,8 @@ import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_mode import 'package:hmg_patient_app_new/features/hospital/hospital_selection_view_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart'; import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart'; +import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; +import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; @@ -45,7 +47,9 @@ import 'package:hmg_patient_app_new/presentation/home/widgets/habib_wallet_card. import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/welcome_widget.dart'; +import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; +import 'package:hmg_patient_app_new/presentation/my_family/my_family.dart'; import 'package:hmg_patient_app_new/presentation/notifications/notifications_list_page.dart'; import 'package:hmg_patient_app_new/presentation/profile_settings/profile_settings.dart'; import 'package:hmg_patient_app_new/presentation/rate_appointment/rate_appointment_doctor.dart'; @@ -53,6 +57,7 @@ import 'package:hmg_patient_app_new/presentation/todo_section/ancillary_procedur import 'package:hmg_patient_app_new/presentation/todo_section/widgets/ancillary_orders_list.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/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/zoom_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; @@ -62,6 +67,7 @@ import 'package:hmg_patient_app_new/widgets/countdown_timer.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/routes/spring_page_route_builder.dart'; import 'package:provider/provider.dart'; +import 'package:smooth_corner/smooth_corner.dart'; import '../emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart'; @@ -122,6 +128,7 @@ class _LandingPageState extends State { emergencyServicesViewModel.checkPatientERAdvanceBalance(); // myAppointmentsViewModel.getPatientAppointmentQueueDetails(); notificationsViewModel.initNotificationsViewModel(); + insuranceViewModel.initInsuranceProvider(); // Commented as per new requirement to remove rating popup from the app @@ -160,29 +167,46 @@ class _LandingPageState extends State { canPop: false, child: Scaffold( backgroundColor: AppColors.bgScaffoldColor, - body: SingleChildScrollView( - padding: EdgeInsets.only(top: kToolbarHeight + 0.h, bottom: 24), - child: Column( - spacing: 16.h, + body: Consumer(builder: (context, insuranceVM, child) { + return Stack( children: [ - Row( - spacing: 8.h, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - appState.isAuthenticated - ? WelcomeWidget( - onTap: () { - Navigator.of(context).push(springPageRoute(ProfileSettings())); - }, - name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), - imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, - ).expanded - : CustomButton( - text: LocaleKeys.loginOrRegister.tr(context: context), - onPressed: () async { - await authVM.onLoginPressed(); + SingleChildScrollView( + padding: EdgeInsets.only(top: (!insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired) ? (MediaQuery.paddingOf(context).top + 70.h) : kToolbarHeight + 0.h, bottom: 24), + child: Column( + spacing: 16.h, + children: [ + Row( + spacing: 8.h, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + appState.isAuthenticated + ? WelcomeWidget( + onTap: () { + // DialogService dialogService = getIt.get(); + // dialogService.showFamilyBottomSheetWithoutH( + // label: LocaleKeys.familyTitle.tr(context: context), + // message: "", + // isShowManageButton: true, + // onSwitchPress: (FamilyFileResponseModelLists profile) { + // getIt.get().switchFamilyFiles(responseID: profile.responseId, patientID: profile.patientId, phoneNumber: profile.mobileNumber); + // }, + // profiles: getIt.get().patientFamilyFiles); + + Navigator.of(context).push( + CustomPageRoute( + page: FamilyMedicalScreen(), + ), + ); + }, + name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), + imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, + ).expanded + : CustomButton( + text: LocaleKeys.loginOrRegister.tr(context: context), + onPressed: () async { + await authVM.onLoginPressed(); - // Navigator.pushReplacementNamed( + // Navigator.pushReplacementNamed( // // context, // context, // AppRoutes.zoomCallPage, @@ -223,476 +247,539 @@ class _LandingPageState extends State { }), (appState.isAuthenticated && (int.parse(todoSectionVM.notificationsCount ?? "0") > 0)) ? Positioned( - right: 0, - top: 0, - child: Container( - width: 8.w, - height: 8.h, - padding: EdgeInsets.all(4), - decoration: BoxDecoration( - color: AppColors.primaryRedColor, - borderRadius: BorderRadius.circular(20.r), - ), - child: Text( - "", - style: TextStyle( - color: Colors.white, - fontSize: 8.f, - ), - textAlign: TextAlign.center, - ), - ), - ) - : SizedBox.shrink(), - ]), - Utils.buildSvgWithAssets(icon: AppAssets.indoor_nav_icon, height: 24.h, width: 24.w).onPress(() { - openIndoorNavigationBottomSheet(context); - }), - Utils.buildSvgWithAssets(icon: AppAssets.contact_icon, height: 24.h, width: 24.h).onPress(() { - showCommonBottomSheetWithoutHeight( - context, + right: 0, + top: 0, + child: Container( + width: 8.w, + height: 8.h, + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: AppColors.primaryRedColor, + borderRadius: BorderRadius.circular(20.r), + ), + child: Text( + "", + style: TextStyle( + color: Colors.white, + fontSize: 8.f, + ), + textAlign: TextAlign.center, + ), + ), + ) + : SizedBox.shrink(), + ]), + Utils.buildSvgWithAssets(icon: AppAssets.location, height: 24.h, width: 24.w).onPress(() { + // openIndoorNavigationBottomSheet(context); + showCommonBottomSheetWithoutHeight( + context, title: LocaleKeys.contactUs.tr(), child: ContactUs(), callBackFunc: () {}, isFullScreen: false, ); }), - !appState.isAuthenticated - ? Utils.buildSvgWithAssets(icon: appState.isArabic() ? AppAssets.enLangIcon : AppAssets.arLangIcon, height: 24.h, width: 24.h).onPress(() { - context.setLocale(appState.isArabic() ? Locale('en', 'US') : Locale('ar', 'SA')); - }) - : SizedBox.shrink() - ], + // Utils.buildSvgWithAssets(icon: AppAssets.contact_icon, height: 24.h, width: 24.h).onPress(() { + // showCommonBottomSheetWithoutHeight( + // context, + // title: LocaleKeys.contactUs.tr(), + // child: ContactUs(), + // callBackFunc: () {}, + // isFullScreen: false, + // ); + // }), + !appState.isAuthenticated + ? Utils.buildSvgWithAssets(icon: appState.isArabic() ? AppAssets.enLangIcon : AppAssets.arLangIcon, height: 24.h, width: 24.h).onPress(() { + context.setLocale(appState.isArabic() ? Locale('en', 'US') : Locale('ar', 'SA')); + }) + : SizedBox.shrink() + ], ); }), ], ).paddingSymmetrical(24.h, 0.h), !appState.isAuthenticated ? Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24.r, - hasShadow: false, - ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Row( - children: [ - Utils.buildSvgWithAssets( - width: 50.w, - height: 60.h, - icon: AppAssets.symptomCheckerIcon, - fit: BoxFit.contain, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: false, ), - SizedBox(width: 12.w), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.howAreYouFeelingToday.tr(context: context).toText14(weight: FontWeight.w600), - LocaleKeys.checkYourSymptomsWithScale.tr(context: context).toText12(fontWeight: FontWeight.w500), - SizedBox(height: 14.h), - CustomButton( - text: LocaleKeys.checkYourSymptoms.tr(context: context), - onPressed: () async { - context.navigateWithName(AppRoutes.userInfoSelection); - }, - padding: EdgeInsetsGeometry.zero, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: Colors.white, - fontSize: 14.f, - fontWeight: FontWeight.w600, - borderRadius: 12.r, - height: 40.h, - ), - ], - ).expanded - ], - ), - ), - ).paddingSymmetrical(24.w, 0.h) - : SizedBox.shrink(), - appState.isAuthenticated - ? Column( - children: [ - SizedBox(height: 12.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - LocaleKeys.appointmentsAndVisits.tr(context: context).toText16(weight: FontWeight.w600), - Row( - children: [ - LocaleKeys.viewAll.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h), - ], + child: Padding( + padding: EdgeInsets.all(16.h), + child: Row( + children: [ + Utils.buildSvgWithAssets( + width: 50.w, + height: 60.h, + icon: AppAssets.symptomCheckerIcon, + fit: BoxFit.contain, + ), + SizedBox(width: 12.w), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.howAreYouFeelingToday.tr(context: context).toText14(weight: FontWeight.w600), + LocaleKeys.checkYourSymptomsWithScale.tr(context: context).toText12(fontWeight: FontWeight.w500), + SizedBox(height: 14.h), + CustomButton( + text: LocaleKeys.checkYourSymptoms.tr(context: context), + onPressed: () async { + context.navigateWithName(AppRoutes.userInfoSelection); + }, + padding: EdgeInsetsGeometry.zero, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: Colors.white, + fontSize: 14.f, + fontWeight: FontWeight.w600, + borderRadius: 12.r, + height: 40.h, + ), + ], + ).expanded + ], + ), ), - ], - ).paddingSymmetrical(24.h, 0.h).onPress(() { - Navigator.of(context).push(CustomPageRoute(page: MyAppointmentsPage())); - }), - Consumer3( - builder: (context, myAppointmentsVM, immediateLiveCareVM, todoSectionVM, 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, 16.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) - : isTablet - ? SizedBox( - height: isFoldable ? 290.h : 255.h, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: 3, - shrinkWrap: true, - padding: EdgeInsets.only(left: 16.h, right: 16.h), - itemBuilder: (context, index) { - return SizedBox( - height: 255.h, - width: 250.w, - child: getIndexSwiperCard(index), - ); - // return AnimationConfiguration.staggeredList( - // position: index, - // duration: const Duration(milliseconds: 1000), - // child: SlideAnimation( - // horizontalOffset: 100.0, - // child: FadeInAnimation( - // child: SizedBox( - // height: 255.h, - // width: 250.w, - // child: getIndexSwiperCard(index), - // ), - // ), - // ), - // ); - }, - separatorBuilder: (BuildContext cxt, int index) => SizedBox( - width: 10.w, + ).paddingSymmetrical(24.w, 0.h) + : SizedBox.shrink(), + appState.isAuthenticated + ? Column( + children: [ + SizedBox(height: 12.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.appointmentsAndVisits.tr(context: context).toText16(weight: FontWeight.w600), + Row( + children: [ + LocaleKeys.viewAll.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h), + ], + ), + ], + ).paddingSymmetrical(24.h, 0.h).onPress(() { + Navigator.of(context).push(CustomPageRoute(page: MyAppointmentsPage())); + }), + Consumer3( + builder: (context, myAppointmentsVM, immediateLiveCareVM, todoSectionVM, 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, 16.h) + : myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty + ? myAppointmentsVM.patientAppointmentsHistoryList.length == 1 + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, ), - ), - ) - : SizedBox( - height: 255.h + 20 + 30, // itemHeight + shadow padding (10 top + 10 bottom) + pagination dots space - child: Swiper( - itemCount: myAppointmentsVM.isMyAppointmentsLoading - ? 3 - : myAppointmentsVM.patientAppointmentsHistoryList.length < 3 - ? myAppointmentsVM.patientAppointmentsHistoryList.length - : 3, - layout: SwiperLayout.STACK, - loop: false, - itemWidth: MediaQuery.of(context).size.width - 48.h, - indicatorLayout: PageIndicatorLayout.COLOR, - axisDirection: getIt.get().isArabic() ? AxisDirection.left : AxisDirection.right, - controller: _controller, - itemHeight: 255.h + 20, - // extra space for shadow - pagination: SwiperPagination( - alignment: Alignment.bottomCenter, - margin: EdgeInsets.only(top: 220.h + 20 + 8 + 24), - builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + child: AppointmentCard( + patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList.first, + myAppointmentsViewModel: myAppointmentsViewModel, + bookAppointmentsViewModel: bookAppointmentsViewModel, + isLoading: false, + isFromHomePage: true, ), - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: getIndexSwiperCard(index), - ); - }, + ).paddingSymmetrical(24.h, 0.h) + : isTablet + ? SizedBox( + height: isFoldable ? 290.h : 255.h, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: 3, + shrinkWrap: true, + padding: EdgeInsets.only(left: 16.h, right: 16.h), + itemBuilder: (context, index) { + return SizedBox( + height: 255.h, + width: 250.w, + child: getIndexSwiperCard(index), + ); + // return AnimationConfiguration.staggeredList( + // position: index, + // duration: const Duration(milliseconds: 1000), + // child: SlideAnimation( + // horizontalOffset: 100.0, + // child: FadeInAnimation( + // child: SizedBox( + // height: 255.h, + // width: 250.w, + // child: getIndexSwiperCard(index), + // ), + // ), + // ), + // ); + }, + separatorBuilder: (BuildContext cxt, int index) => SizedBox( + width: 10.w, + ), + ), + ) + : SizedBox( + height: 255.h + 20 + 30, // itemHeight + shadow padding (10 top + 10 bottom) + pagination dots space + child: Swiper( + itemCount: myAppointmentsVM.isMyAppointmentsLoading + ? 3 + : myAppointmentsVM.patientAppointmentsHistoryList.length < 3 + ? myAppointmentsVM.patientAppointmentsHistoryList.length + : 3, + layout: SwiperLayout.STACK, + loop: false, + itemWidth: MediaQuery.of(context).size.width - 48.h, + indicatorLayout: PageIndicatorLayout.COLOR, + axisDirection: getIt.get().isArabic() ? AxisDirection.left : AxisDirection.right, + controller: _controller, + itemHeight: 255.h + 20, + // extra space for shadow + pagination: SwiperPagination( + alignment: Alignment.bottomCenter, + margin: EdgeInsets.only(top: 220.h + 20 + 8 + 24), + builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + ), + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: getIndexSwiperCard(index), + ); + }, + ), + ) + : Container( + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), + SizedBox(height: 12.h), + LocaleKeys.noUpcomingAppointmentPleaseBook.tr(context: context).toText12(isCenter: true), + SizedBox(height: 12.h), + CustomButton( + text: LocaleKeys.bookAppo.tr(context: context), + onPressed: () { + getIt.get().onTabChanged(0); + 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: 40.h, + ), + ], ), - ) - : Container( - width: double.infinity, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), - SizedBox(height: 12.h), - LocaleKeys.noUpcomingAppointmentPleaseBook.tr(context: context).toText12(isCenter: true), - SizedBox(height: 12.h), - CustomButton( - text: LocaleKeys.bookAppo.tr(context: context), - onPressed: () { - getIt.get().onTabChanged(0); - 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: 40.h, ), - ], - ), - ), - ).paddingSymmetrical(24.h, 16.h); - }, - ), + ).paddingSymmetrical(24.h, 16.h); + }, + ), - // Consumer for ER Online Check-In pending request - Consumer( - builder: (context, emergencyServicesVM, child) { - return emergencyServicesVM.patientHasAdvanceERBalance - ? Column( + // Consumer for ER Online Check-In pending request + Consumer( + builder: (context, emergencyServicesVM, child) { + return emergencyServicesVM.patientHasAdvanceERBalance + ? Column( + children: [ + SizedBox(height: 16.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.r, + hasShadow: false, + 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: LocaleKeys.erOnlineCheckInRequest.tr(context: context), + // 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: [ - SizedBox(height: 16.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.r, - hasShadow: false, - 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: LocaleKeys.erOnlineCheckInRequest.tr(context: context), - 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: [ - LocaleKeys.youHaveEROnlineCheckInRequest.tr(context: context).toText12(isBold: true), - Transform.flip( - flipX: getIt.get().isArabic(), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon_small, - iconColor: AppColors.blackColor, - width: 20.h, - height: 15.h, - fit: BoxFit.contain, - ), - ), - ], - ), - ], - ), + LocaleKeys.youHaveEROnlineCheckInRequest.tr(context: context).toText12(isBold: true), + Transform.flip( + flipX: getIt.get().isArabic(), + child: 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: 0.h); - }, + ), + ], + ), + ), + ).paddingSymmetrical(24.h, 0.h).onPress(() { + Navigator.of(context).push(CustomPageRoute(page: ErOnlineCheckinHome())); + // context.read().navigateToEROnlineCheckIn(); + }), + SizedBox(height: 12.h), + ], + ) + : SizedBox(height: 0.h); + }, + ), + SizedBox(height: 16.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.quickLinks.tr(context: context).toText16(weight: FontWeight.w600), + Row( + children: [ + LocaleKeys.viewMedicalFile.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.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: [ + SizedBox( + height: 92.h + 32.h - 4.h, + child: RawScrollbar( + controller: _horizontalScrollController, + thumbVisibility: true, + radius: Radius.circular(10.0), + thumbColor: AppColors.primaryRedColor, + trackVisibility: true, + trackColor: Color(0xffD9D9D9), + trackBorderColor: Colors.transparent, + trackRadius: Radius.circular(10.0), + padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery + .sizeOf(context) + .width / 2 - 35, right: MediaQuery + .sizeOf(context) + .width / 2 - 35), + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getLoggedInServiceCardsList.length, + shrinkWrap: true, + controller: _horizontalScrollController, + padding: EdgeInsets.only(left: 16.h, right: 16.h, top: 16.h, bottom: 12.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, + ), + ), ), SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - LocaleKeys.quickLinks.tr(context: context).toText16(weight: FontWeight.w600), - Row( + ], + ), + ).paddingSymmetrical(24.h, 0.h), + ], + ) + : Container( + // height: 141.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), + child: Column( children: [ - LocaleKeys.viewMedicalFile.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h), + SizedBox( + height: 92.h + 32.h - 4.h, + child: RawScrollbar( + controller: _horizontalScrollController, + thumbVisibility: true, + radius: Radius.circular(10.0), + thumbColor: AppColors.primaryRedColor, + trackVisibility: true, + trackColor: Color(0xffD9D9D9), + trackBorderColor: Colors.transparent, + trackRadius: Radius.circular(10.0), + padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2 - 35, right: MediaQuery.sizeOf(context).width / 2 - 35), + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, + shrinkWrap: true, + controller: _horizontalScrollController, + padding: EdgeInsets.only(left: 16.h, right: 16.h, top: 16.h, bottom: 12.h), + // padding: EdgeInsets.zero, + 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, + ), + ), + ), + SizedBox(height: 16.h), ], ), + ).paddingSymmetrical(24.h, 0.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.services2.tr(context: context).toText18(weight: FontWeight.w600), + Row( + children: [ + LocaleKeys.viewAllServices.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h), ], - ).paddingSymmetrical(24.h, 0.h).onPress(() { - Navigator.of(context).push(CustomPageRoute(page: MedicalFilePage())); + ).onPress(() { + Navigator.of(context).push(CustomPageRoute(page: ServicesPage())); }), - SizedBox(height: 16.h), - Container( - // height: 121.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), - child: Column( + ], + ).paddingSymmetrical(24.w, 0.h), + SizedBox( + height: 431.h, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getServiceCardsList.length, + shrinkWrap: true, + padding: EdgeInsets.only(left: 24.w, right: 24.w), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: FadedLargeServiceCard( + serviceCardData: LandingPageData.getServiceCardsList[index], + image: LandingPageData.getServiceCardsList[index].icon, + title: LandingPageData.getServiceCardsList[index].title, + subtitle: LandingPageData.getServiceCardsList[index].subtitle, + icon: LandingPageData.getServiceCardsList[index].largeCardIcon, + ), + ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 16.w), + ), + ), + appState.isAuthenticated ? HabibWalletCard() : SizedBox(), + ], + ), + ), + (!insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired) + ? Container( + height: MediaQuery.paddingOf(context).top + 50.h, + decoration: ShapeDecoration( + color: AppColors.secondaryLightRedBorderColor, + shape: SmoothRectangleBorder( + side: BorderSide(width: 1, color: AppColors.primaryRedColor.withAlpha(20)), + // borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), + smoothness: 1, + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SizedBox( - height: 92.h + 32.h - 4.h, - child: RawScrollbar( - controller: _horizontalScrollController, - thumbVisibility: true, - radius: Radius.circular(10.0), - thumbColor: AppColors.primaryRedColor, - trackVisibility: true, - trackColor: Color(0xffD9D9D9), - trackBorderColor: Colors.transparent, - trackRadius: Radius.circular(10.0), - padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2 - 35, right: MediaQuery.sizeOf(context).width / 2 - 35), - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getLoggedInServiceCardsList.length, - shrinkWrap: true, - controller: _horizontalScrollController, - padding: EdgeInsets.only(left: 16.h, right: 16.h, top: 16.h, bottom: 12.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, - ), - ), + LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h), + Row( + children: [ + CustomButton( + text: LocaleKeys.updateInsurance.tr(context: context), + onPressed: () { + Navigator.of(context).push( + CustomPageRoute( + page: InsuranceHomePage(), ), ); }, - separatorBuilder: (BuildContext cxt, int index) => 10.width, - ), - ), + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.secondaryLightRedBorderColor, + textColor: AppColors.whiteColor, + fontSize: 10.f, + fontWeight: FontWeight.bold, + borderRadius: 8.r, + padding: EdgeInsets.fromLTRB(15, 0, 15, 0), + height: 36.h, + ).paddingSymmetrical(24.h, 0.h), + ], ), - SizedBox(height: 16.h), ], ), - ).paddingSymmetrical(24.h, 0.h), - ], - ) - : Container( - // height: 141.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), - child: Column( - children: [ SizedBox( - height: 92.h + 32.h - 4.h, - child: RawScrollbar( - controller: _horizontalScrollController, - thumbVisibility: true, - radius: Radius.circular(10.0), - thumbColor: AppColors.primaryRedColor, - trackVisibility: true, - trackColor: Color(0xffD9D9D9), - trackBorderColor: Colors.transparent, - trackRadius: Radius.circular(10.0), - padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2 - 35, right: MediaQuery.sizeOf(context).width / 2 - 35), - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, - shrinkWrap: true, - controller: _horizontalScrollController, - padding: EdgeInsets.only(left: 16.h, right: 16.h, top: 16.h, bottom: 12.h), - // padding: EdgeInsets.zero, - 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, - ), - ), - ), - SizedBox(height: 16.h), + height: 10.h, + ) ], ), - ).paddingSymmetrical(24.h, 0.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - LocaleKeys.services2.tr(context: context).toText18(weight: FontWeight.w600), - Row( - children: [ - LocaleKeys.viewAllServices.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h), - ], - ).onPress(() { - Navigator.of(context).push(CustomPageRoute(page: ServicesPage())); - }), - ], - ).paddingSymmetrical(24.w, 0.h), - SizedBox( - height: 431.h, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getServiceCardsList.length, - shrinkWrap: true, - padding: EdgeInsets.only(left: 24.w, right: 24.w), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: FadedLargeServiceCard( - serviceCardData: LandingPageData.getServiceCardsList[index], - image: LandingPageData.getServiceCardsList[index].icon, - title: LandingPageData.getServiceCardsList[index].title, - subtitle: LandingPageData.getServiceCardsList[index].subtitle, - icon: LandingPageData.getServiceCardsList[index].largeCardIcon, - ), - ), - ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 16.w), - ), - ), - appState.isAuthenticated ? HabibWalletCard() : SizedBox(), + ) + : SizedBox.shrink() ], - ), - ), + ); + }), ), ); } diff --git a/lib/presentation/home/widgets/welcome_widget.dart b/lib/presentation/home/widgets/welcome_widget.dart index 21f01c8b..9b613e64 100644 --- a/lib/presentation/home/widgets/welcome_widget.dart +++ b/lib/presentation/home/widgets/welcome_widget.dart @@ -1,10 +1,20 @@ 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/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/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/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; +import 'package:hmg_patient_app_new/presentation/profile_settings/profile_settings.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; +import 'package:hmg_patient_app_new/widgets/routes/spring_page_route_builder.dart'; +import 'package:smooth_corner/smooth_corner.dart'; class WelcomeWidget extends StatelessWidget { final String name; @@ -20,33 +30,41 @@ class WelcomeWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(30), - child: Row( - mainAxisSize: MainAxisSize.min, - spacing: 8.h, - children: [ - Image.asset(imageUrl, width: 40, height: 40), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 4.h, + return Column( + children: [ + InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(30), + child: Row( mainAxisSize: MainAxisSize.min, + spacing: 8.h, children: [ - LocaleKeys.welcome.tr(context: context).toText14(color: AppColors.greyTextColor, height: 1, weight: FontWeight.w500), - Row( + Icon(Icons.menu, color: AppColors.textColor).onPress(() { + Navigator.of(context).push(springPageRoute(ProfileSettings())); + }), + Image.asset(imageUrl, width: 40, height: 40), + Column( + crossAxisAlignment: CrossAxisAlignment.start, spacing: 4.h, - crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - Flexible(child: name.toText16(weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1, height: 1, isEnglishOnly: true)), - Icon(Icons.keyboard_arrow_down, size: 20, color: AppColors.greyTextColor), + LocaleKeys.welcome.tr(context: context).toText14(color: AppColors.greyTextColor, height: 1, weight: FontWeight.w500), + Row( + spacing: 4.h, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible(child: name.toText16(weight: FontWeight.w500, textOverflow: TextOverflow.ellipsis, maxlines: 1, height: 1, isEnglishOnly: true)), + // Icon(Icons.keyboard_arrow_down, size: 20, color: AppColors.greyTextColor), + Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, height: 22.h, width: 22.w) + ], + ), ], - ), + ).expanded, ], - ).expanded, - ], - ), + ), + ), + ], ); } } diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 1c839c10..5301d2e0 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -199,18 +199,23 @@ class _MedicalFilePageState extends State { ], ), SizedBox(width: 4.h), - Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, height: 22.h, width: 22.w) + Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, height: 22.h, width: 22.w) ], ).onPress(() { - DialogService dialogService = getIt.get(); - dialogService.showFamilyBottomSheetWithoutH( - label: LocaleKeys.familyTitle.tr(context: context), - message: "", - isShowManageButton: true, - onSwitchPress: (FamilyFileResponseModelLists profile) { - medicalFileViewModel.switchFamilyFiles(responseID: profile.responseId, patientID: profile.patientId, phoneNumber: profile.mobileNumber); - }, - profiles: medicalFileViewModel.patientFamilyFiles); + Navigator.of(context).push( + CustomPageRoute( + page: FamilyMedicalScreen(), + ), + ); + // DialogService dialogService = getIt.get(); + // dialogService.showFamilyBottomSheetWithoutH( + // label: LocaleKeys.familyTitle.tr(context: context), + // message: "", + // isShowManageButton: true, + // onSwitchPress: (FamilyFileResponseModelLists profile) { + // medicalFileViewModel.switchFamilyFiles(responseID: profile.responseId, patientID: profile.patientId, phoneNumber: profile.mobileNumber); + // }, + // profiles: medicalFileViewModel.patientFamilyFiles); }), isLeading: widget.showBackIcon, // leadingCallback: () { diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart index f304fcc3..a621168f 100644 --- a/lib/presentation/my_family/widget/family_cards.dart +++ b/lib/presentation/my_family/widget/family_cards.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; @@ -9,16 +11,22 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.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/presentation/insurance/widgets/insurance_update_details_card.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.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:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:provider/provider.dart'; class FamilyCards extends StatefulWidget { final List profiles; + late List? profileViewList; final Function(FamilyFileResponseModelLists) onSelect; final Function(FamilyFileResponseModelLists) onRemove; final bool isShowDetails; @@ -28,11 +36,12 @@ class FamilyCards extends StatefulWidget { final bool isShowRemoveButton; final bool isForWalletRecharge; - const FamilyCards( + FamilyCards( {super.key, required this.profiles, required this.onSelect, required this.onRemove, + this.profileViewList, this.isShowDetails = false, this.isBottomSheet = false, this.isRequestDesign = false, @@ -46,9 +55,22 @@ class FamilyCards extends StatefulWidget { class _FamilyCardsState extends State { AppState appState = getIt(); + late InsuranceViewModel insuranceViewModel; + + @override + void initState() { + scheduleMicrotask(() { + insuranceViewModel.initInsuranceProvider(); + }); + super.initState(); + } @override Widget build(BuildContext context) { + widget.profileViewList = []; + widget.profileViewList!.addAll(widget.profiles); + widget.profileViewList!.removeWhere((element) => element.responseId == appState.getAuthenticatedUser()?.patientId); + insuranceViewModel = Provider.of(context, listen: false); DialogService dialogService = getIt.get(); if (widget.isRequestDesign) { return Column( @@ -71,15 +93,15 @@ class _FamilyCardsState extends State { ], ), SizedBox(height: 24.h), - widget.profiles.where((profile) => profile.isRequestFromMySide ?? false).isEmpty + widget.profileViewList!.where((profile) => profile.isRequestFromMySide ?? false).isEmpty ? Utils.getNoDataWidget(context) : ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, - itemCount: widget.profiles.where((profile) => profile.isRequestFromMySide ?? false).length, + itemCount: widget.profileViewList!.where((profile) => profile.isRequestFromMySide ?? false).length, itemBuilder: (context, index) { - final mySideProfiles = widget.profiles.where((profile) => profile.isRequestFromMySide ?? false).toList(); + final mySideProfiles = widget.profileViewList!.where((profile) => profile.isRequestFromMySide ?? false).toList(); FamilyFileResponseModelLists profile = mySideProfiles[index]; return Container( margin: EdgeInsets.only(bottom: 12.h), @@ -146,113 +168,252 @@ class _FamilyCardsState extends State { ], ); } else { - return GridView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: widget.profiles.length, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 10.w, - mainAxisSpacing: 10.h, - childAspectRatio: widget.isShowDetails ? 0.56.h : 0.74.h, - ), - padding: EdgeInsets.only(bottom: 20.h), - itemBuilder: (context, index) { - final profile = widget.profiles[index]; - final isActive = (profile.responseId == appState.getAuthenticatedUser()?.patientId); - final isParentUser = appState.getAuthenticatedUser()?.isParentUser ?? false; - final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID); - return Container( - padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 15.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), - child: Opacity( - opacity: isActive || profile.status == FamilyFileEnum.pending.toInt || !canSwitch ? 0.4 : 1.0, // Fade all content if active - child: Stack( + return Column( + children: [ + Container( + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r), + child: Padding( + padding: EdgeInsets.all(16.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Column( - mainAxisSize: MainAxisSize.min, + Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Utils.buildImgWithAssets( - icon: profile.gender == null - ? AppAssets.dummyUser - : profile.gender == 1 - ? ((profile.age ?? 0) < 7 ? AppAssets.babyBoyImg : AppAssets.maleImg) - : (profile.age! < 7 ? AppAssets.babyGirlImg : AppAssets.femaleImg), - width: 72.h, - height: 70.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, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.6, + child: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}" + .toText18(isBold: true, weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 2), + ), + SizedBox(height: 4.h), + Wrap( + direction: Axis.horizontal, + spacing: 4.w, + runSpacing: 6.w, + children: [ + AppCustomChipWidget( + icon: AppAssets.file_icon, + richText: "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText10(isEnglishOnly: true), + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), + ), + AppCustomChipWidget( + icon: AppAssets.checkmark_icon, + labelText: LocaleKeys.verified.tr(context: context), + iconColor: AppColors.successColor, + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), + ), + ], + ), + ], + ) + ], + ), + SizedBox(height: 16.h), + Divider(color: AppColors.dividerColor, height: 1.h), + SizedBox(height: 16.h), + Wrap( + direction: Axis.horizontal, + spacing: 4.h, + runSpacing: 4.h, + children: [ + AppCustomChipWidget( + labelText: LocaleKeys.ageYearsOld.tr(namedArgs: {'age': '${appState.getAuthenticatedUser()!.age}', 'yearsOld': LocaleKeys.yearsOld.tr(context: context)}, context: context), + labelPadding: EdgeInsetsDirectional.only(start: 8.w, end: 8.w), ), - SizedBox(height: 8.h), - (profile.patientName ?? "Unknown").toText14(isBold: false, isCenter: true, maxlines: 1, weight: FontWeight.w600), - SizedBox(height: 8.h), - CustomChipWidget( - chipType: ChipTypeEnum.alert, - backgroundColor: AppColors.lightGrayBGColor, - chipText: "Relation: ${profile.relationship ?? " N/A"}", - iconAsset: AppAssets.heart, - isShowBorder: false, - borderRadius: 8.h, - textColor: AppColors.textColor), - widget.isShowDetails ? SizedBox(height: 4.h) : SizedBox(), - widget.isShowDetails - ? CustomChipWidget( + AppCustomChipWidget( + icon: AppAssets.blood_icon, + labelText: appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup, + iconColor: AppColors.primaryRedColor, + labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), + padding: EdgeInsets.zero, + ), + Consumer(builder: (context, insuranceVM, child) { + return AppCustomChipWidget( + icon: insuranceVM.isInsuranceExpired + ? AppAssets.cancel_circle_icon + : insuranceVM.isInsuranceActive + ? AppAssets.insurance_active_icon + : AppAssets.alertSquare, + labelText: insuranceVM.isInsuranceExpired + ? LocaleKeys.insuranceExpired.tr(context: context) + : insuranceVM.isInsuranceActive + ? LocaleKeys.insuranceActive.tr(context: context) + : LocaleKeys.insuranceInActive.tr(context: context), + iconColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + textColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + iconSize: 12.w, + deleteIcon: insuranceVM.isInsuranceActive ? null : AppAssets.forward_chevron_icon, + deleteIconColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + deleteIconHasColor: true, + onChipTap: () { + if (!insuranceVM.isInsuranceActive) { + insuranceVM.setIsInsuranceUpdateDetailsLoading(true); + insuranceVM.getPatientInsuranceDetailsForUpdate( + appState.getAuthenticatedUser()!.patientId.toString(), appState.getAuthenticatedUser()!.patientIdentificationNo.toString()); + showCommonBottomSheetWithoutHeight(context, child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); + // showCommonBottomSheetWithoutHeight( + // title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), + // navigationService.navigatorKey.currentContext!, + // child: Utils.getWarningWidget( + // loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + // confirmText: LocaleKeys.contactUs.tr(context: context), + // isShowActionButtons: true, + // onCancelTap: () { + // navigationService.pop(); + // }, + // onConfirmTap: () async { + // launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + // }), + // callBackFunc: () {}, + // isFullScreen: false, + // isCloseButtonVisible: true, + // ); + } + }, + backgroundColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor.withOpacity(0.1) + : insuranceVM.isInsuranceActive + ? AppColors.successColor.withOpacity(0.1) + : AppColors.warningColorYellow.withOpacity(0.1), + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: insuranceVM.isInsuranceActive ? 6.w : 0.w), + ).toShimmer2(isShow: insuranceVM.isInsuranceLoading); + }), + ], + ), + ], + ), + ), + ).paddingSymmetrical(0.w, 0.0), + SizedBox(height: 16.h), + GridView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: widget.profileViewList!.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 10.w, + mainAxisSpacing: 10.h, + childAspectRatio: widget.isShowDetails ? 0.56.h : 0.74.h, + ), + padding: EdgeInsets.only(bottom: 20.h), + itemBuilder: (context, index) { + final profile = widget.profileViewList![index]; + final isActive = (profile.responseId == appState.getAuthenticatedUser()?.patientId); + final isParentUser = appState.getAuthenticatedUser()?.isParentUser ?? false; + final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID); + return Container( + padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 15.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), + child: Opacity( + opacity: isActive || profile.status == FamilyFileEnum.pending.toInt || !canSwitch ? 0.4 : 1.0, // Fade all content if active + child: Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Utils.buildImgWithAssets( + icon: profile.gender == null + ? AppAssets.dummyUser + : profile.gender == 1 + ? ((profile.age ?? 0) < 7 ? AppAssets.babyBoyImg : AppAssets.maleImg) + : (profile.age! < 7 ? AppAssets.babyGirlImg : AppAssets.femaleImg), + width: 72.h, + height: 70.h, + ), + SizedBox(height: 8.h), + (profile.patientName ?? "Unknown").toText14(isBold: false, isCenter: true, maxlines: 1, weight: FontWeight.w600), + SizedBox(height: 8.h), + CustomChipWidget( chipType: ChipTypeEnum.alert, backgroundColor: AppColors.lightGrayBGColor, - chipText: "Age:${profile.age ?? "N/A"} Years", + chipText: "Relation: ${profile.relationship ?? " N/A"}", + iconAsset: AppAssets.heart, isShowBorder: false, borderRadius: 8.h, - textColor: AppColors.textColor, - ) - : SizedBox(), - widget.isShowDetails - ? SizedBox(height: 8.h) - : SizedBox( - height: 4.h, - ), - Spacer(), - widget.isForWalletRecharge ? CustomButton( - height: 40.h, - onPressed: () { - widget.onSelect(profile); - // if (canSwitch) widget.onSelect(profile); - }, - text: LocaleKeys.select.tr(context: context), - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 13.h, - icon: AppAssets.activeCheck, - iconColor: isActive || !canSwitch ? (isActive ? null : AppColors.greyTextColor) : AppColors.primaryRedColor, - padding: EdgeInsets.symmetric(vertical: 0, horizontal: 0), - ).paddingOnly(top: 0, bottom: 0) : CustomButton( - height: 40.h, - onPressed: () { - if (canSwitch) widget.onSelect(profile); - }, - text: isActive ? LocaleKeys.active.tr(context: context) : LocaleKeys.switchLogin.tr(context: context), - backgroundColor: isActive || !canSwitch ? Colors.grey.shade200 : AppColors.secondaryLightRedColor, - borderColor: isActive || !canSwitch ? Colors.grey.shade200 : AppColors.secondaryLightRedColor, - textColor: isActive || !canSwitch ? AppColors.greyTextColor : AppColors.primaryRedColor, - fontSize: 13.h, - icon: isActive ? AppAssets.activeCheck : AppAssets.switch_user, - iconColor: isActive || !canSwitch ? (isActive ? null : AppColors.greyTextColor) : AppColors.primaryRedColor, - padding: EdgeInsets.symmetric(vertical: 0, horizontal: 0), - ).paddingOnly(top: 0, bottom: 0), + textColor: AppColors.textColor), + widget.isShowDetails ? SizedBox(height: 4.h) : SizedBox(), + widget.isShowDetails + ? CustomChipWidget( + chipType: ChipTypeEnum.alert, + backgroundColor: AppColors.lightGrayBGColor, + chipText: "Age: ${profile.age ?? "N/A"} Years", + isShowBorder: false, + borderRadius: 8.h, + textColor: AppColors.textColor, + ) + : SizedBox(), + widget.isShowDetails + ? SizedBox(height: 8.h) + : SizedBox( + height: 4.h, + ), + Spacer(), + widget.isForWalletRecharge + ? CustomButton( + height: 40.h, + onPressed: () { + widget.onSelect(profile); + // if (canSwitch) widget.onSelect(profile); + }, + text: LocaleKeys.select.tr(context: context), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 13.h, + icon: AppAssets.activeCheck, + iconColor: isActive || !canSwitch ? (isActive ? null : AppColors.greyTextColor) : AppColors.primaryRedColor, + padding: EdgeInsets.symmetric(vertical: 0, horizontal: 0), + ).paddingOnly(top: 0, bottom: 0) + : CustomButton( + height: 40.h, + onPressed: () { + if (canSwitch) widget.onSelect(profile); + }, + text: isActive ? LocaleKeys.active.tr(context: context) : LocaleKeys.switchLogin.tr(context: context), + backgroundColor: isActive || !canSwitch ? Colors.grey.shade200 : AppColors.secondaryLightRedColor, + borderColor: isActive || !canSwitch ? Colors.grey.shade200 : AppColors.secondaryLightRedColor, + textColor: isActive || !canSwitch ? AppColors.greyTextColor : AppColors.primaryRedColor, + fontSize: 13.h, + icon: isActive ? AppAssets.activeCheck : AppAssets.switch_user, + iconColor: isActive || !canSwitch ? (isActive ? null : AppColors.greyTextColor) : AppColors.primaryRedColor, + padding: EdgeInsets.symmetric(vertical: 0, horizontal: 0), + ).paddingOnly(top: 0, bottom: 0), + ], + ), + if (widget.isShowRemoveButton) ...[ + Positioned( + top: 0, + right: 0, + child: Utils.buildSvgWithAssets(icon: AppAssets.deleteIcon).onPress(() { + if (!isActive) widget.onRemove(profile); + }), + ), + ], ], ), - if (widget.isShowRemoveButton) ...[ - Positioned( - top: 0, - right: 0, - child: Utils.buildSvgWithAssets(icon: AppAssets.deleteIcon).onPress(() { - if (!isActive) widget.onRemove(profile); - }), - ), - ], - ], - ), - ), - ); - }, + ), + ); + }, + ), + ], ); } } @@ -260,15 +421,15 @@ class _FamilyCardsState extends State { Widget manageFamily() { NavigationService navigationService = getIt(); - return widget.profiles.where((profile) => !(profile.isRequestFromMySide ?? false)).isEmpty + return widget.profileViewList!.where((profile) => !(profile.isRequestFromMySide ?? false)).isEmpty ? Utils.getNoDataWidget(context) : ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsetsGeometry.zero, - itemCount: widget.profiles.where((profile) => !(profile.isRequestFromMySide ?? false)).length, + itemCount: widget.profileViewList!.where((profile) => !(profile.isRequestFromMySide ?? false)).length, itemBuilder: (context, index) { - final otherProfiles = widget.profiles.where((profile) => !(profile.isRequestFromMySide ?? false)).toList(); + final otherProfiles = widget.profileViewList!.where((profile) => !(profile.isRequestFromMySide ?? false)).toList(); FamilyFileResponseModelLists profile = otherProfiles[index]; return Container( margin: EdgeInsets.only(bottom: 12.h), diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index 98002ca9..50b8eb07 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -15,12 +15,15 @@ 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/authentication/authentication_view_model.dart'; +import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart'; +import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart'; import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/insurance/widgets/insurance_update_details_card.dart'; @@ -88,10 +91,12 @@ class ProfileSettingsState extends State { int length = 3; final SwiperController _controller = SwiperController(); late InsuranceViewModel insuranceViewModel; + late ContactUsViewModel contactUsViewModel; @override Widget build(BuildContext context) { insuranceViewModel = Provider.of(context, listen: false); + contactUsViewModel = Provider.of(context, listen: false); return CollapsingListView( title: LocaleKeys.profileAndSettings.tr(context: context), logout: () { @@ -106,102 +111,102 @@ class ProfileSettingsState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - height: dynamicItemHeight(context) + 20 + 30, // itemHeight + shadow padding (10 top + 10 bottom) + pagination dots space - child: Swiper( - itemCount: medicalVm.patientFamilyFiles.length, - layout: SwiperLayout.STACK, - loop: true, - itemHeight: dynamicItemHeight(context) + 20, - // extra space for shadow - itemWidth: SizeUtils.width - 30.w, - indicatorLayout: PageIndicatorLayout.COLOR, - axisDirection: getIt.get().isArabic() ? AxisDirection.left : AxisDirection.right, - controller: _controller, - pagination: SwiperPagination( - alignment: Alignment.bottomCenter, - margin: EdgeInsets.only(top: (180.h + 20 + 8.h + 24.h)), - builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), - ), - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: FamilyCardWidget( - profile: medicalVm.patientFamilyFiles[index], - onAddFamilyMemberPress: () { - DialogService dialogService = getIt.get(); - dialogService.showAddFamilyFileSheet( - label: LocaleKeys.addFamilyMember.tr(context: context), - message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(context: context), - onVerificationPress: () { - medicalVm.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); - }); - }, - onFamilySwitchPress: (FamilyFileResponseModelLists profile) { - medicalVm.switchFamilyFiles(responseID: profile.responseId, patientID: profile.patientId, phoneNumber: profile.mobileNumber); - }, - ).paddingOnly(right: 16.w, left: 8.w), - ); - }, - ), - ), - SizedBox(height: 16.h), - GridView( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 3 : 2), - physics: const NeverScrollableScrollPhysics(), - padding: EdgeInsets.only(left: 24.w, right: 24.w, bottom: 24.h), - shrinkWrap: true, - children: [ - Container( - padding: EdgeInsets.all(16.w), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.r, - hasShadow: true, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - // spacing: 4.h, - children: [ - Row( - spacing: 8.w, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.wallet, width: 40.w, height: 40.h, applyThemeColor: false), - LocaleKeys.habibWallet.tr(context: context).toText16(weight: FontWeight.w600, maxlines: 2).expanded, - Utils.buildSvgWithAssets(icon: getIt.get().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward), - ], - ), - Spacer(), - Consumer(builder: (context, habibWalletVM, child) { - return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, isExpanded: false) - .toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.r, width: 80.w, height: 24.h); - }), - Spacer(), - CustomButton( - height: 40.h, - icon: AppAssets.recharge_icon, - iconSize: 22.w, - iconColor: AppColors.infoColor, - textColor: AppColors.infoColor, - text: LocaleKeys.recharge.tr(context: context), - borderWidth: 0.w, - fontWeight: FontWeight.w500, - borderColor: Colors.transparent, - backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08), - padding: EdgeInsets.all(8.w), - fontSize: 14.f, - onPressed: () { - Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage())); - }, - ), - ], - ).onPress(() { - Navigator.of(context).push(CustomPageRoute(page: HabibWalletPage())); - }), - ), - ], - ), + // SizedBox( + // height: dynamicItemHeight(context) + 20 + 30, // itemHeight + shadow padding (10 top + 10 bottom) + pagination dots space + // child: Swiper( + // itemCount: medicalVm.patientFamilyFiles.length, + // layout: SwiperLayout.STACK, + // loop: true, + // itemHeight: dynamicItemHeight(context) + 20, + // // extra space for shadow + // itemWidth: SizeUtils.width - 30.w, + // indicatorLayout: PageIndicatorLayout.COLOR, + // axisDirection: getIt.get().isArabic() ? AxisDirection.left : AxisDirection.right, + // controller: _controller, + // pagination: SwiperPagination( + // alignment: Alignment.bottomCenter, + // margin: EdgeInsets.only(top: (180.h + 20 + 8.h + 24.h)), + // builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + // ), + // itemBuilder: (BuildContext context, int index) { + // return Padding( + // padding: const EdgeInsets.symmetric(vertical: 10), + // child: FamilyCardWidget( + // profile: medicalVm.patientFamilyFiles[index], + // onAddFamilyMemberPress: () { + // DialogService dialogService = getIt.get(); + // dialogService.showAddFamilyFileSheet( + // label: LocaleKeys.addFamilyMember.tr(context: context), + // message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(context: context), + // onVerificationPress: () { + // medicalVm.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); + // }); + // }, + // onFamilySwitchPress: (FamilyFileResponseModelLists profile) { + // medicalVm.switchFamilyFiles(responseID: profile.responseId, patientID: profile.patientId, phoneNumber: profile.mobileNumber); + // }, + // ).paddingOnly(right: 16.w, left: 8.w), + // ); + // }, + // ), + // ), + // SizedBox(height: 16.h), + // GridView( + // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 3 : 2), + // physics: const NeverScrollableScrollPhysics(), + // padding: EdgeInsets.only(left: 24.w, right: 24.w, bottom: 24.h), + // shrinkWrap: true, + // children: [ + // Container( + // padding: EdgeInsets.all(16.w), + // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + // color: AppColors.whiteColor, + // borderRadius: 20.r, + // hasShadow: true, + // ), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // // spacing: 4.h, + // children: [ + // Row( + // spacing: 8.w, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // Utils.buildSvgWithAssets(icon: AppAssets.wallet, width: 40.w, height: 40.h, applyThemeColor: false), + // LocaleKeys.habibWallet.tr(context: context).toText16(weight: FontWeight.w600, maxlines: 2).expanded, + // Utils.buildSvgWithAssets(icon: getIt.get().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward), + // ], + // ), + // Spacer(), + // Consumer(builder: (context, habibWalletVM, child) { + // return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, isExpanded: false) + // .toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.r, width: 80.w, height: 24.h); + // }), + // Spacer(), + // CustomButton( + // height: 40.h, + // icon: AppAssets.recharge_icon, + // iconSize: 22.w, + // iconColor: AppColors.infoColor, + // textColor: AppColors.infoColor, + // text: LocaleKeys.recharge.tr(context: context), + // borderWidth: 0.w, + // fontWeight: FontWeight.w500, + // borderColor: Colors.transparent, + // backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08), + // padding: EdgeInsets.all(8.w), + // fontSize: 14.f, + // onPressed: () { + // Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage())); + // }, + // ), + // ], + // ).onPress(() { + // Navigator.of(context).push(CustomPageRoute(page: HabibWalletPage())); + // }), + // ), + // ], + // ), LocaleKeys.quickActions.tr(context: context).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), @@ -253,31 +258,31 @@ class ProfileSettingsState extends State { // ], // ), // ), - LocaleKeys.personalInformation.tr(context: context).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), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), - child: Column( - children: [ - actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(context: context), () { - showCommonBottomSheetWithoutHeight( - context, - title: LocaleKeys.updateEmailAddress.tr(context: context), - child: UpdateEmailDialog(), - callBackFunc: () {}, - isFullScreen: false, - ); - }), - // 1.divider, - // actionItem(AppAssets.smart_phone_fill, "Phone Number".needTranslation, () {}), - // 1.divider, - // actionItem(AppAssets.my_address, "My Addresses".needTranslation, () {}), - // 1.divider, - // actionItem(AppAssets.emergency, "Emergency Contact".needTranslation, () {}), - ], - ), - ), + // LocaleKeys.personalInformation.tr(context: context).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), + // decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), + // child: Column( + // children: [ + // actionItem(AppAssets.email_transparent, LocaleKeys.updateEmailAddress.tr(context: context), () { + // showCommonBottomSheetWithoutHeight( + // context, + // title: LocaleKeys.updateEmailAddress.tr(context: context), + // child: UpdateEmailDialog(), + // callBackFunc: () {}, + // isFullScreen: false, + // ); + // }), + // // 1.divider, + // // actionItem(AppAssets.smart_phone_fill, "Phone Number".needTranslation, () {}), + // // 1.divider, + // // actionItem(AppAssets.my_address, "My Addresses".needTranslation, () {}), + // // 1.divider, + // // actionItem(AppAssets.emergency, "Emergency Contact".needTranslation, () {}), + // ], + // ), + // ), LocaleKeys.helpAndSupport.tr(context: context).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), @@ -289,6 +294,19 @@ class ProfileSettingsState extends State { launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); }, trailingLabel: "92 006 6666"), 1.divider, + actionItem(AppAssets.feedbackFill, LocaleKeys.feedback.tr(context: context), () { + contactUsViewModel.setSelectedFeedbackType( + FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'), + ); + contactUsViewModel.setIsSendFeedbackTabSelected(true); + Navigator.pop(context); + Navigator.of(context).push( + CustomPageRoute( + page: FeedbackPage(), + ), + ); + }, trailingLabel: ""), + 1.divider, // actionItem(AppAssets.permission, LocaleKeys.permissions.tr(context: context), () {}, trailingLabel: "Location, Camera"), // 1.divider, actionItem(AppAssets.rate, LocaleKeys.rateApp.tr(context: context), () { diff --git a/lib/services/dialog_service.dart b/lib/services/dialog_service.dart index c4dfb7c4..d2ba2723 100644 --- a/lib/services/dialog_service.dart +++ b/lib/services/dialog_service.dart @@ -166,7 +166,7 @@ class DialogServiceImp implements DialogService { mainAxisAlignment: MainAxisAlignment.start, children: [ if (message != null) (message).toText16(isBold: false, color: AppColors.textColor), - SizedBox(height: 24.h), + // SizedBox(height: 24.h), FamilyCards( profiles: profiles, onSelect: (FamilyFileResponseModelLists profile) { @@ -190,6 +190,7 @@ class DialogServiceImp implements DialogService { }) ], ), + useSafeArea: true, callBackFunc: () {}); } diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index 514acfb4..467edd92 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -8,7 +8,7 @@ class AppColors { static const transparent = Colors.transparent; // ── Scaffold / Background ───────────────────────────────────────────────── - static Color get scaffoldBgColor => isDarkMode ? dark.scaffoldBgColor : const Color(0xFFF8F8F8); + static Color get scaffoldBgColor => isDarkMode ? dark.scaffoldBgColor : const Color(0xFFF0F0F0); static Color get bottomSheetBgColor => isDarkMode ? dark.bottomSheetBgColor : const Color(0xFFF8F8FA); static Color get lightGreyEFColor => isDarkMode ? dark.lightGreyEFColor : const Color(0xffeaeaff); static Color get greyF7Color => isDarkMode ? dark.greyF7Color : const Color(0xffF7F7F7); From 4a3d66f01a1b9a00e925c6a17c46cd0c9be9f69c Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 29 Mar 2026 18:02:12 +0300 Subject: [PATCH 25/33] Updates --- assets/langs/ar-SA.json | 4 +- assets/langs/en-US.json | 4 +- lib/core/api/api_client.dart | 2 +- lib/extensions/widget_extensions.dart | 4 +- lib/features/ask_doctor/ask_doctor_repo.dart | 2 +- .../models/ask_doctor_appointments_list.dart | 2 +- .../insurance/insurance_view_model.dart | 12 +++ lib/features/lab/lab_view_model.dart | 29 +++--- lib/generated/locale_keys.g.dart | 2 + .../appointment_details_page.dart | 23 ++++- .../widgets/appointment_card.dart | 16 +++- .../widgets/appointment_doctor_card.dart | 40 +++++---- .../emergency_services_page.dart | 2 +- lib/presentation/home/landing_page.dart | 32 ++++--- .../insurance/insurance_home_page.dart | 33 ++++--- .../insurance_update_details_card.dart | 88 ++++++++++--------- .../widgets/patient_insurance_card.dart | 51 ++++++++--- lib/presentation/lab/lab_orders_page.dart | 2 +- .../lab_order_result_item.dart | 8 +- .../medical_file/medical_file_page.dart | 55 ++++++------ 20 files changed, 257 insertions(+), 154 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 268bf0a3..6df6d8c7 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1587,5 +1587,7 @@ "ratings": "التقييمات", "hmgPharmacyText": "صيدلية الحبيب، المتجر الصيدلاني الإلكتروني المتكامل الذي تقدمه لكم مجموعة خدمات الدكتور سليمان الحبيب الطبية.", "insuranceRequestSubmittedSuccessfully": "تم إرسال طلب تحديث بيانات التأمين بنجاح. سيتم إعلامك بمجرد الانتهاء.", - "updatingEmailAddress": "جارٍ تحديث عنوان البريد الإلكتروني، يرجى الانتظار..." + "updatingEmailAddress": "جارٍ تحديث عنوان البريد الإلكتروني، يرجى الانتظار...", + "verifyInsurance": "التحقق من التأمين", + "tests": "تحليل" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index d1a48222..bedf03fd 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1581,5 +1581,7 @@ "ratings": "Ratings", "hmgPharmacyText": "Al Habib Pharmacy, the complete online Pharmaceutical store brought to you by Dr. Sulaiman Al Habib Medical Services Group.", "insuranceRequestSubmittedSuccessfully": "Your insurance update request has been successfully submitted. You will be notified once completed.", - "updatingEmailAddress": "Updating email address, Please wait..." + "updatingEmailAddress": "Updating email address, Please wait...", + "verifyInsurance": "Verify Insurance", + "tests": "tests" } diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 0131a938..2de4ce5c 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -200,7 +200,7 @@ class ApiClientImp implements ApiClient { } // body['TokenID'] = "@dm!n"; - // body['PatientID'] = 4774402; + // body['PatientID'] = 1231755; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; // body['SessionID'] = "45786230487560q"; diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index f0897950..866c26a4 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.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/extensions/int_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:shimmer/shimmer.dart'; import 'package:sizer/sizer.dart'; @@ -166,7 +168,7 @@ extension SmoothContainerExtension on ShapeBorder { ? [ BoxShadow( // color: hasDenseShadow ? const Color(0xff000000).withOpacity(.06) : const Color(0xff000000).withOpacity(.1), - color: const Color(0xffE1E1E1).withOpacity(1.0), + color: getIt.get().isDarkMode ? Color(0xff3a3a3a).withOpacity(1.0) : Color(0xffE1E1E1).withOpacity(1.0), blurRadius: 0, spreadRadius: 0, offset: const Offset(1, 0), diff --git a/lib/features/ask_doctor/ask_doctor_repo.dart b/lib/features/ask_doctor/ask_doctor_repo.dart index 4e4a4006..bd6af5b8 100644 --- a/lib/features/ask_doctor/ask_doctor_repo.dart +++ b/lib/features/ask_doctor/ask_doctor_repo.dart @@ -47,7 +47,7 @@ class AskDoctorRepoImp implements AskDoctorRepo { try { final list = response['PatientDoctorAppointmentResultList']; - final clinicsList = list.map((item) => AskDoctorAppointmentHistoryList.fromJson(item as Map)).toList().cast(); + final clinicsList = list != null ? list.map((item) => AskDoctorAppointmentHistoryList.fromJson(item as Map)).toList().cast() : []; apiResponse = GenericApiModel>( messageStatus: messageStatus, diff --git a/lib/features/ask_doctor/models/ask_doctor_appointments_list.dart b/lib/features/ask_doctor/models/ask_doctor_appointments_list.dart index 7f40d71c..6b337662 100644 --- a/lib/features/ask_doctor/models/ask_doctor_appointments_list.dart +++ b/lib/features/ask_doctor/models/ask_doctor_appointments_list.dart @@ -143,7 +143,7 @@ class AskDoctorAppointmentHistoryList { noOfPatientsRate = json['NoOfPatientsRate']; projectName = json['ProjectName']; qR = json['QR']; - speciality = json['Speciality'].cast(); + // speciality = json['Speciality'].cast(); } Map toJson() { diff --git a/lib/features/insurance/insurance_view_model.dart b/lib/features/insurance/insurance_view_model.dart index d1423113..28210d39 100644 --- a/lib/features/insurance/insurance_view_model.dart +++ b/lib/features/insurance/insurance_view_model.dart @@ -13,6 +13,7 @@ class InsuranceViewModel extends ChangeNotifier { bool isInsuranceHistoryLoading = false; bool isInsuranceDetailsLoading = false; bool isInsuranceUpdateDetailsLoading = false; + bool isInsuranceExpiryBannerShown = false; bool isInsuranceDataToBeLoaded = true; bool isInsuranceApprovalsLoading = false; @@ -49,6 +50,11 @@ class InsuranceViewModel extends ChangeNotifier { notifyListeners(); } + setIsInsuranceExpiryBannerShown(bool isInsuranceExpiryBannerShown) { + this.isInsuranceExpiryBannerShown = isInsuranceExpiryBannerShown; + notifyListeners(); + } + setIsInsuranceHistoryLoading(bool val) { isInsuranceHistoryLoading = val; notifyListeners(); @@ -91,6 +97,7 @@ class InsuranceViewModel extends ChangeNotifier { isInsuranceDataToBeLoaded = true; isInsuranceExpired = false; isInsuranceActive = false; + isInsuranceExpiryBannerShown = false; notifyListeners(); }, (apiResponse) { @@ -111,6 +118,8 @@ class InsuranceViewModel extends ChangeNotifier { debugPrint("InsuranceViewModel: Insurance card expired: $isInsuranceExpired"); } + isInsuranceExpiryBannerShown = isInsuranceExpired; + isInsuranceActive = patientInsuranceList.first.isActive ?? false; // isInsuranceActive = true; @@ -148,6 +157,9 @@ class InsuranceViewModel extends ChangeNotifier { } Future getPatientInsuranceDetailsForUpdate(String patientID, String identificationNo, {Function(dynamic)? onSuccess, Function(String)? onError}) async { + patientInsuranceUpdateResponseModel = null; + notifyListeners(); + final result = await insuranceRepo.getPatientInsuranceDetailsForUpdate(patientId: patientID, identificationNo: identificationNo); result.fold( diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index 4c689ab7..1af2654e 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -149,21 +149,26 @@ class LabViewModel extends ChangeNotifier { isLabOrdersLoading = false; isLabResultsLoading = false; - // --- Build groups by clinic and by hospital (projectName) --- - final clinicMap = >{}; - final hospitalMap = >{}; - for (var order in patientLabOrders) { - final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); - clinicMap.putIfAbsent(clinicKey, () => []).add(order); - - final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); - hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); + order.testDetails!.sort((a, b) => a.description!.compareTo(b.description!)); } - patientLabOrdersByClinic = clinicMap.values.toList(); - patientLabOrdersByHospital = hospitalMap.values.toList(); - patientLabOrdersViewList = isSortByClinic ? patientLabOrdersByClinic : patientLabOrdersByHospital; + // --- Build groups by clinic and by hospital (projectName) --- + // final clinicMap = >{}; + // final hospitalMap = >{}; + // + // for (var order in patientLabOrders) { + // final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); + // clinicMap.putIfAbsent(clinicKey, () => []).add(order); + // + // final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); + // hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); + // } + + // patientLabOrdersByClinic = clinicMap.values.toList(); + // patientLabOrdersByHospital = hospitalMap.values.toList(); + // patientLabOrdersViewList = isSortByClinic ? patientLabOrdersByClinic : patientLabOrdersByHospital; + // patientLabOrdersViewList = patientLabOrdersByClinic; filterSuggestions(); getUniqueTestDescription(); diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 031e1be9..ac9f3f7c 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1582,5 +1582,7 @@ abstract class LocaleKeys { static const hmgPharmacyText = 'hmgPharmacyText'; static const insuranceRequestSubmittedSuccessfully = 'insuranceRequestSubmittedSuccessfully'; static const updatingEmailAddress = 'updatingEmailAddress'; + static const verifyInsurance = 'verifyInsurance'; + static const tests = 'tests'; } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 71cf4e16..072cb04a 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -14,6 +14,7 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/ask_doctor/ask_doctor_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart'; import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart'; @@ -31,6 +32,8 @@ import 'package:hmg_patient_app_new/presentation/appointments/appointment_paymen import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart'; +import 'package:hmg_patient_app_new/presentation/ask_doctor/ask_doctor_page.dart'; +import 'package:hmg_patient_app_new/presentation/ask_doctor/doctor_response_page.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart'; @@ -556,6 +559,22 @@ class _AppointmentDetailsPageState extends State { // ), // ); }), + MedicalFileCard( + label: LocaleKeys.doctorResponses.tr(context: context), + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.ask_doctor_medical_file_icon, + isLargeText: true, + iconSize: 36.w, + ).onPress(() { + getIt.get().initAskDoctorViewModel(); + getIt.get().getDoctorResponses(); + Navigator.of(context).push( + CustomPageRoute( + page: DoctorResponsePage(), + ), + ); + }), ], ), // Column( @@ -839,8 +858,8 @@ class _AppointmentDetailsPageState extends State { onPressed: () { openDoctorScheduleCalendar(); }, - backgroundColor: AppColors.successColor, - borderColor: AppColors.successColor, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, textColor: Colors.white, fontSize: 16.f, fontWeight: FontWeight.w500, diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index ac63432f..44fcfa86 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -329,12 +329,19 @@ class AppointmentCard extends StatelessWidget { flex: 1, child: Container( height: (isFoldable || isTablet) ? 50.h : 40.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.textColor, borderRadius: 10.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.transparent, + borderRadius: 10.h, + side: BorderSide( + color: AppColors.textColor, + width: 1.2, + ), + ), child: Transform.flip( flipX: appState.isArabic(), child: Utils.buildSvgWithAssets( icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.whiteColor, + iconColor: AppColors.textColor, width: 24.w, height: 24.h, fit: BoxFit.contain, @@ -401,9 +408,10 @@ class AppointmentCard extends StatelessWidget { return CustomButton( text: LocaleKeys.rebookSameDoctor.tr(context: context), onPressed: () => openDoctorScheduleCalendar(context), - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, + backgroundColor: AppColors.transparent, + borderColor: AppColors.textColor, textColor: AppColors.blackColor, + borderWidth: 1.h, fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontWeight: FontWeight.w500, borderRadius: 12.r, diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index ef8c76ee..5a47708e 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -155,25 +155,27 @@ class AppointmentDoctorCard extends StatelessWidget { icon: AppAssets.ask_doctor_icon, iconColor: AppColors.primaryRedColor, ) - : !patientAppointmentHistoryResponseModel.isLiveCareAppointment! - ? CustomButton( - text: LocaleKeys.rebookSameDoctor.tr(), - onPressed: () { - onRescheduleTap(); - }, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 12.f, - fontWeight: FontWeight.w500, - borderRadius: 12.r, - padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), - height: 40.h, - icon: AppAssets.rebook_appointment_icon, - iconColor: AppColors.blackColor, - iconSize: 14.h, - ) - : SizedBox.shrink(); + : + // !patientAppointmentHistoryResponseModel.isLiveCareAppointment! + // ? CustomButton( + // text: LocaleKeys.rebookSameDoctor.tr(), + // onPressed: () { + // onRescheduleTap(); + // }, + // backgroundColor: AppColors.greyColor, + // borderColor: AppColors.greyColor, + // textColor: AppColors.blackColor, + // fontSize: 12.f, + // fontWeight: FontWeight.w500, + // borderRadius: 12.r, + // padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), + // height: 40.h, + // icon: AppAssets.rebook_appointment_icon, + // iconColor: AppColors.blackColor, + // iconSize: 14.h, + // ) + // : + SizedBox.shrink(); } else { return patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? CustomButton( diff --git a/lib/presentation/emergency_services/emergency_services_page.dart b/lib/presentation/emergency_services/emergency_services_page.dart index 41597e40..7970d819 100644 --- a/lib/presentation/emergency_services/emergency_services_page.dart +++ b/lib/presentation/emergency_services/emergency_services_page.dart @@ -35,7 +35,7 @@ class EmergencyServicesPage extends StatelessWidget { return CollapsingListView( title: LocaleKeys.emergencyServices.tr(), - requests: () { + history: () { emergencyServicesViewModel.changeOrderDisplayItems(OrderDislpay.ALL); Navigator.of(context).push(CustomPageRoute(page: ErHistoryListing(), direction: AxisDirection.up)); }, diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 768a31d1..14684c0c 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -48,6 +48,7 @@ import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/welcome_widget.dart'; import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; +import 'package:hmg_patient_app_new/presentation/insurance/widgets/insurance_update_details_card.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; import 'package:hmg_patient_app_new/presentation/my_family/my_family.dart'; import 'package:hmg_patient_app_new/presentation/notifications/notifications_list_page.dart'; @@ -171,7 +172,11 @@ class _LandingPageState extends State { return Stack( children: [ SingleChildScrollView( - padding: EdgeInsets.only(top: (!insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired) ? (MediaQuery.paddingOf(context).top + 70.h) : kToolbarHeight + 0.h, bottom: 24), + padding: EdgeInsets.only( + top: (!insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown) + ? (MediaQuery.paddingOf(context).top + 70.h) + : kToolbarHeight + 0.h, + bottom: 24), child: Column( spacing: 16.h, children: [ @@ -728,7 +733,7 @@ class _LandingPageState extends State { ], ), ), - (!insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired) + (!insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown) ? Container( height: MediaQuery.paddingOf(context).top + 50.h, decoration: ShapeDecoration( @@ -745,27 +750,30 @@ class _LandingPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h), + LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(0.h, 0.h), Row( children: [ CustomButton( text: LocaleKeys.updateInsurance.tr(context: context), onPressed: () { - Navigator.of(context).push( - CustomPageRoute( - page: InsuranceHomePage(), - ), - ); + insuranceVM.setIsInsuranceUpdateDetailsLoading(true); + insuranceVM.getPatientInsuranceDetailsForUpdate( + appState.getAuthenticatedUser()!.patientId.toString(), appState.getAuthenticatedUser()!.patientIdentificationNo.toString()); + showCommonBottomSheetWithoutHeight(context, + child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); }, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.secondaryLightRedBorderColor, - textColor: AppColors.whiteColor, - fontSize: 10.f, + textColor: Colors.white, + fontSize: 12.f, fontWeight: FontWeight.bold, borderRadius: 8.r, padding: EdgeInsets.fromLTRB(15, 0, 15, 0), height: 36.h, - ).paddingSymmetrical(24.h, 0.h), + ).paddingSymmetrical(12.h, 0.h), + Icon(Icons.close, color: AppColors.primaryRedColor).onPress(() { + insuranceVM.setIsInsuranceExpiryBannerShown(false); + }), ], ), ], @@ -774,7 +782,7 @@ class _LandingPageState extends State { height: 10.h, ) ], - ), + ).paddingSymmetrical(24.h, 0.h), ) : SizedBox.shrink() ], diff --git a/lib/presentation/insurance/insurance_home_page.dart b/lib/presentation/insurance/insurance_home_page.dart index 519d8306..35e3acb8 100644 --- a/lib/presentation/insurance/insurance_home_page.dart +++ b/lib/presentation/insurance/insurance_home_page.dart @@ -48,11 +48,11 @@ class _InsuranceHomePageState extends State { insuranceViewModel = Provider.of(context, listen: false); return CollapsingListView( title: "${LocaleKeys.insurance.tr(context: context)} ${LocaleKeys.updateInsurance.tr(context: context)}", - history: () { - insuranceViewModel.setIsInsuranceHistoryLoading(true); - insuranceViewModel.getPatientInsuranceCardHistory(); - showCommonBottomSheetWithoutHeight(context, child: InsuranceHistory(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); - }, + // history: () { + // // insuranceViewModel.setIsInsuranceHistoryLoading(true); + // // insuranceViewModel.getPatientInsuranceCardHistory(); + // showCommonBottomSheetWithoutHeight(context, child: InsuranceHistory(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); + // }, child: SingleChildScrollView( child: Consumer(builder: (context, insuranceVM, child) { return Column( @@ -66,12 +66,23 @@ class _InsuranceHomePageState extends State { isLoading: true, ).paddingSymmetrical(24.h, 24.h) : insuranceVM.patientInsuranceList.isNotEmpty - ? Padding( - padding: EdgeInsets.only(top: 24.h), - child: PatientInsuranceCard( - insuranceCardDetailsModel: insuranceVM.patientInsuranceList.first, - isInsuranceExpired: DateTime.now().isAfter(DateUtil.convertStringToDate(insuranceVM.patientInsuranceList.first.cardValidTo))) - .paddingSymmetrical(24.w, 0.h), + ? ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.all(16.h), + physics: const BouncingScrollPhysics(), + itemBuilder: (context, index) { + return Column( + children: [ + PatientInsuranceCard( + insuranceCardDetailsModel: insuranceVM.patientInsuranceList[index], + isInsuranceExpired: DateTime.now().isAfter(DateUtil.convertStringToDate(insuranceVM.patientInsuranceList.first.cardValidTo))), + SizedBox( + height: 12.h, + ) + ], + ); + }, + itemCount: insuranceVM.patientInsuranceList.length, ) : Padding( padding: EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.12), diff --git a/lib/presentation/insurance/widgets/insurance_update_details_card.dart b/lib/presentation/insurance/widgets/insurance_update_details_card.dart index 2136f0cb..770f4da2 100644 --- a/lib/presentation/insurance/widgets/insurance_update_details_card.dart +++ b/lib/presentation/insurance/widgets/insurance_update_details_card.dart @@ -105,49 +105,51 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget { iconSize: 20.w, text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}", onPressed: () { - LoaderBottomSheet.showLoader(); - getIt().sendPatientUpdateRequest(onSuccess: (val) { - LoaderBottomSheet.hideLoader(); - insuranceViewModel.setIsInsuranceDataToBeLoaded(true); - insuranceViewModel.initInsuranceProvider(); - Navigator.pop(context); - }, onError: (err) { - insuranceViewModel.updatePatientInsuranceCard( - patientID: appState.getAuthenticatedUser()!.patientId!, - patientType: appState.getAuthenticatedUser()!.patientType!, - patientIdentificationID: appState.getAuthenticatedUser()!.patientIdentificationNo!, - mobileNo: appState.getAuthenticatedUser()!.mobileNumber!, - insuranceCardImage: "", - onSuccess: (val) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - title: LocaleKeys.success.tr(context: context), - context, - child: Utils.getSuccessWidget(loadingText: LocaleKeys.insuranceRequestSubmittedSuccessfully.tr(context: context)), - callBackFunc: () { - Navigator.pop(context); - }, - isFullScreen: false, - isCloseButtonVisible: false, - ); - // Future.delayed(Duration(milliseconds: 2000)).then((value) async { - // Navigator.pop(context); - // }); - }, - onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - title: LocaleKeys.notice.tr(context: context), - context, - child: Utils.getErrorWidget(loadingText: err.toString()), - callBackFunc: () { - Navigator.pop(context); - }, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); - }); + if (insuranceViewModel.patientInsuranceUpdateResponseModel != null) { + LoaderBottomSheet.showLoader(); + getIt().sendPatientUpdateRequest(onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + insuranceViewModel.setIsInsuranceDataToBeLoaded(true); + insuranceViewModel.initInsuranceProvider(); + Navigator.pop(context); + }, onError: (err) { + insuranceViewModel.updatePatientInsuranceCard( + patientID: appState.getAuthenticatedUser()!.patientId!, + patientType: appState.getAuthenticatedUser()!.patientType!, + patientIdentificationID: appState.getAuthenticatedUser()!.patientIdentificationNo!, + mobileNo: appState.getAuthenticatedUser()!.mobileNumber!, + insuranceCardImage: "", + onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.success.tr(context: context), + context, + child: Utils.getSuccessWidget(loadingText: LocaleKeys.insuranceRequestSubmittedSuccessfully.tr(context: context)), + callBackFunc: () { + Navigator.pop(context); + }, + isFullScreen: false, + isCloseButtonVisible: false, + ); + // Future.delayed(Duration(milliseconds: 2000)).then((value) async { + // Navigator.pop(context); + // }); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getErrorWidget(loadingText: err.toString()), + callBackFunc: () { + Navigator.pop(context); + }, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + }); + } }, backgroundColor: insuranceViewModel.patientInsuranceUpdateResponseModel != null ? AppColors.successColor : AppColors.lightGrayBGColor, borderColor: AppColors.successColor.withOpacity(0.01), diff --git a/lib/presentation/insurance/widgets/patient_insurance_card.dart b/lib/presentation/insurance/widgets/patient_insurance_card.dart index d6bb204f..1607a7c6 100644 --- a/lib/presentation/insurance/widgets/patient_insurance_card.dart +++ b/lib/presentation/insurance/widgets/patient_insurance_card.dart @@ -53,26 +53,30 @@ class PatientInsuranceCard extends StatelessWidget { SizedBox( width: MediaQuery.of(context).size.width * 0.4, child: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true, textOverflow: TextOverflow.clip, isEnglishOnly: true)), - LocaleKeys.policyNumber.tr(namedArgs: {'number': insuranceCardDetailsModel.insurancePolicyNo ?? ''}, context: context).toText12(isBold: true, color: AppColors.lightGrayColor), + Row( + children: [ + "${LocaleKeys.policyNumber.tr(context: context)}${insuranceCardDetailsModel.insurancePolicyNo}".toText12(isBold: true, color: AppColors.lightGrayColor), + ], + ), ], ), AppCustomChipWidget( - icon: insuranceViewModel.isInsuranceExpired + icon: isCurrentPatientInsuranceExpired(insuranceCardDetailsModel.cardValidTo!) ? AppAssets.cancel_circle_icon : insuranceViewModel.isInsuranceActive ? AppAssets.insurance_active_icon : AppAssets.alertSquare, - labelText: insuranceViewModel.isInsuranceExpired + labelText: isCurrentPatientInsuranceExpired(insuranceCardDetailsModel.cardValidTo!) ? LocaleKeys.insuranceExpired.tr(context: context) : insuranceViewModel.isInsuranceActive ? LocaleKeys.insuranceActive.tr(context: context) : LocaleKeys.insuranceInActive.tr(context: context), - iconColor: insuranceViewModel.isInsuranceExpired + iconColor: isCurrentPatientInsuranceExpired(insuranceCardDetailsModel.cardValidTo!) ? AppColors.primaryRedColor : insuranceViewModel.isInsuranceActive ? AppColors.successColor : AppColors.warningColorYellow, - textColor: insuranceViewModel.isInsuranceExpired + textColor: isCurrentPatientInsuranceExpired(insuranceCardDetailsModel.cardValidTo!) ? AppColors.primaryRedColor : insuranceViewModel.isInsuranceActive ? AppColors.successColor @@ -110,7 +114,7 @@ class PatientInsuranceCard extends StatelessWidget { // ); } }, - backgroundColor: insuranceViewModel.isInsuranceExpired + backgroundColor: isCurrentPatientInsuranceExpired(insuranceCardDetailsModel.cardValidTo!) ? AppColors.primaryRedColor.withOpacity(0.1) : insuranceViewModel.isInsuranceActive ? AppColors.successColor.withOpacity(0.1) @@ -130,7 +134,23 @@ class PatientInsuranceCard extends StatelessWidget { ), SizedBox(height: 12.h), insuranceCardDetailsModel.groupName!.toText12(isBold: true), - insuranceCardDetailsModel.companyName!.toText12(isBold: true), + Row( + children: [ + insuranceCardDetailsModel.companyName!.toText12(isBold: true), + SizedBox( + width: 6.h, + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 6.h, vertical: 4.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.infoColor, + borderRadius: 50.r, + ), + child: (insuranceCardDetailsModel.subCategoryDesc!.length > 5 ? insuranceCardDetailsModel.subCategoryDesc!.substring(0, 12) : insuranceCardDetailsModel.subCategoryDesc!) + .toText8(isBold: true, color: AppColors.whiteColor), + ), + ], + ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, @@ -150,9 +170,10 @@ class PatientInsuranceCard extends StatelessWidget { isInsuranceExpired ? CustomButton( icon: AppAssets.update_insurance_card_icon, - iconColor: AppColors.successColor, + iconColor: AppColors.warningColorYellow, iconSize: 15.h, - text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}", + // text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}", + text: LocaleKeys.verifyInsurance.tr(context: context), onPressed: () { insuranceViewModel.setIsInsuranceUpdateDetailsLoading(true); insuranceViewModel.getPatientInsuranceDetailsForUpdate( @@ -165,9 +186,9 @@ class PatientInsuranceCard extends StatelessWidget { isCloseButtonVisible: false, isFullScreen: false); }, - backgroundColor: AppColors.bgGreenColor.withOpacity(0.20), - borderColor: AppColors.bgGreenColor.withOpacity(0.0), - textColor: AppColors.bgGreenColor, + backgroundColor: AppColors.warningColorYellow.withOpacity(0.20), + borderColor: AppColors.warningColorYellow.withOpacity(0.0), + textColor: AppColors.warningColorYellow, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12, @@ -180,4 +201,10 @@ class PatientInsuranceCard extends StatelessWidget { ), ).paddingSymmetrical(0.h, 0.h); } + + bool isCurrentPatientInsuranceExpired(String cardValidTo) { + return DateTime.now().isAfter( + DateUtil.convertStringToDate(cardValidTo), + ); + } } diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index bb2c3034..b38ad737 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -1 +1 @@ -import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_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/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; import 'dart:ui' as ui; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ CustomButton( text: LocaleKeys.byClinic.tr(context: context), onPressed: () { labViewModel.setIsSortByClinic(true); }, backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, fontSize: 12.f, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), SizedBox(width: 8.h), CustomButton( text: LocaleKeys.byHospital.tr(context: context), onPressed: () { labViewModel.setIsSortByClinic(false); }, backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, fontSize: 12, fontWeight: FontWeight.w500, borderRadius: 10, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrdersViewList.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.patientLabOrdersViewList.length, itemBuilder: (context, index) { final group = labViewModel.patientLabOrdersViewList[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget(labelText: "${group.length} ${LocaleKeys.results.tr(context: context)}"), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Text( labViewModel.isSortByClinic ? (group.first.clinicDescription ?? 'Unknown') : (group.first.projectName ?? 'Unknown'), style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group[index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), isEnglishOnly: true, ), Directionality( textDirection: ui.TextDirection.ltr, child: AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), isEnglishOnly: true, )), AppCustomChipWidget( labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), ), ], ), // Row( // children: [ // CustomButton( // text: ("Order No: ".needTranslation + order.orderNo!), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), // SizedBox(height: 8.h), // Row( // children: [ // CustomButton( // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // onPressed: () {}, // backgroundColor: AppColors.greyColor, // borderColor: AppColors.greyColor, // textColor: AppColors.blackColor, // fontSize: 10, // fontWeight: FontWeight.w500, // borderRadius: 8, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 24.h, // ), // ], // ), SizedBox(height: 12.h), Row( children: [ Expanded(flex: 2, child: SizedBox()), // Expanded( // flex: 1, // child: Container( // height: 40.h, // width: 40.w, // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // color: AppColors.textColor, // borderRadius: 12, // ), // child: Padding( // padding: EdgeInsets.all(12.h), // child: Transform.flip( // flipX: _appState.isArabic(), // child: Utils.buildSvgWithAssets( // icon: AppAssets.forward_arrow_icon_small, // iconColor: AppColors.whiteColor, // fit: BoxFit.contain, // ), // ), // ), // ).onPress(() { // model.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }), // ) Expanded( flex: 2, child: CustomButton( icon: AppAssets.view_report_icon, iconColor: AppColors.primaryRedColor, iconSize: 16.h, text: LocaleKeys.viewResults.tr(context: context), onPressed: () { labViewModel.currentlySelectedPatientOrder = order; labProvider.getPatientLabResultByHospital(order); labProvider.getPatientSpecialResult(order); Navigator.of(context).push( CustomPageRoute(page: LabResultByClinic(labOrder: order)), ); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ) ], ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.length)) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.indexedCharacterForUniqueTest, details: labViewModel.uniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file +import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_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/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; import 'dart:ui' as ui; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ // CustomButton( // text: LocaleKeys.byClinic.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(true); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, // borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), // textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, // fontSize: 12.f, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: LocaleKeys.byHospital.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(false); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, // borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, // textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, // fontSize: 12, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrders.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.patientLabOrders.length, itemBuilder: (context, index) { final group = labViewModel.patientLabOrders[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget( labelText: "${group.testDetails!.length} ${LocaleKeys.tests.tr(context: context)}", backgroundColor: AppColors.successColor.withOpacity(0.1), textColor: AppColors.successColor, ), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (group.doctorName ?? group.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ Directionality( textDirection: ui.TextDirection.ltr, child: AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(group.orderDate ?? ""), false), isEnglishOnly: true, )), AppCustomChipWidget( labelText: (group.projectName ?? ""), ), AppCustomChipWidget( labelText: (group.clinicDescription ?? ""), ), ], ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: Column( children: [ ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "• ${order.testDetails![index].description!}".toText14(weight: FontWeight.w500), SizedBox(height: 4.h), order.testDetails![index].testDescriptionEn!.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), // Row( // mainAxisSize: MainAxisSize.min, // children: [ // Image.network( // order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", // width: 24.w, // height: 24.h, // fit: BoxFit.cover, // ).circle(100), // SizedBox(width: 8.h), // Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), // ], // ), // SizedBox(height: 8.h), // Wrap( // direction: Axis.horizontal, // spacing: 4.h, // runSpacing: 4.h, // children: [ // AppCustomChipWidget( // labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), isEnglishOnly: true, // ), // Directionality( // textDirection: ui.TextDirection.ltr, // child: AppCustomChipWidget( // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // isEnglishOnly: true, // )), // AppCustomChipWidget( // labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), // ), // ], // ), // // Row( // // children: [ // // CustomButton( // // text: ("Order No: ".needTranslation + order.orderNo!), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // SizedBox(width: 8.h), // // CustomButton( // // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // // SizedBox(height: 8.h), // // Row( // // children: [ // // CustomButton( // // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // SizedBox(height: 12.h), // Row( // children: [ // Expanded(flex: 2, child: SizedBox()), // // Expanded( // // flex: 1, // // child: Container( // // height: 40.h, // // width: 40.w, // // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // // color: AppColors.textColor, // // borderRadius: 12, // // ), // // child: Padding( // // padding: EdgeInsets.all(12.h), // // child: Transform.flip( // // flipX: _appState.isArabic(), // // child: Utils.buildSvgWithAssets( // // icon: AppAssets.forward_arrow_icon_small, // // iconColor: AppColors.whiteColor, // // fit: BoxFit.contain, // // ), // // ), // // ), // // ).onPress(() { // // model.currentlySelectedPatientOrder = order; // // labProvider.getPatientLabResultByHospital(order); // // labProvider.getPatientSpecialResult(order); // // Navigator.of(context).push( // // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // // ); // // }), // // ) // // Expanded( // flex: 2, // child: CustomButton( // icon: AppAssets.view_report_icon, // iconColor: AppColors.primaryRedColor, // iconSize: 16.h, // text: LocaleKeys.viewResults.tr(context: context), // onPressed: () { // labViewModel.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }, // backgroundColor: AppColors.secondaryLightRedColor, // borderColor: AppColors.secondaryLightRedColor, // textColor: AppColors.primaryRedColor, // fontSize: 14, // fontWeight: FontWeight.w500, // borderRadius: 12, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // ) // ], // ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.testDetails!.length > 3 ? 3 : group.testDetails!.length), SizedBox(height: 16.h), CustomButton( text: "${LocaleKeys.viewResults.tr()} (${group.testDetails!.length})", onPressed: () { labProvider.currentlySelectedPatientOrder = group; labProvider.getPatientLabResultByHospital(group); labProvider.getPatientSpecialResult(group); Navigator.of(context).push( CustomPageRoute( page: LabResultByClinic(labOrder: group), ), ); }, backgroundColor: AppColors.infoColor.withAlpha(20), borderColor: AppColors.infoColor.withAlpha(0), textColor: AppColors.infoColor, fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontWeight: FontWeight.w500, borderRadius: 12.r, padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), height: 40.h, iconSize: 14.h, icon: AppAssets.view_report_icon, iconColor: AppColors.infoColor, ), SizedBox(height: 16.h), ], ), ) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.indexedCharacterForUniqueTest, details: labViewModel.uniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file diff --git a/lib/presentation/lab/lab_result_via_clinic/lab_order_result_item.dart b/lib/presentation/lab/lab_result_via_clinic/lab_order_result_item.dart index cf6ce97b..1a97d48d 100644 --- a/lib/presentation/lab/lab_result_via_clinic/lab_order_result_item.dart +++ b/lib/presentation/lab/lab_result_via_clinic/lab_order_result_item.dart @@ -114,15 +114,15 @@ class LabOrderResultItem extends StatelessWidget { ), CustomButton( icon: AppAssets.view_report_icon, - iconColor: AppColors.primaryRedColor, + iconColor: AppColors.infoColor, iconSize: 16.h, text: LocaleKeys.viewReport.tr(context: context), onPressed: () { onTap(); }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, + backgroundColor: AppColors.infoColor.withAlpha(20), + borderColor: AppColors.infoColor.withAlpha(0), + textColor: AppColors.infoColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12, diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 5301d2e0..cddc4757 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -522,7 +522,7 @@ class _MedicalFilePageState extends State { ], ), ExpandableListItem( - title: LocaleKeys.trackerAndOthers.tr(context: context).toText18(weight: FontWeight.w600), + title: LocaleKeys.healthTrackers.tr(context: context).toText18(weight: FontWeight.w600), expandedBackgroundColor: Colors.transparent, children: [ SizedBox(height: 10.h), @@ -1347,12 +1347,12 @@ class _MedicalFilePageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - LocaleKeys.healthTrackers.tr(context: context).toText16(weight: FontWeight.w500, color: AppColors.textColor), - ], - ), - SizedBox(height: 16.h), + // Row( + // children: [ + // LocaleKeys.healthTrackers.tr(context: context).toText16(weight: FontWeight.w500, color: AppColors.textColor), + // ], + // ), + // SizedBox(height: 16.h), GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, @@ -1391,11 +1391,11 @@ class _MedicalFilePageState extends State { ], ).paddingSymmetrical(0.w, 0.0), SizedBox(height: 16.h), - Row( - children: [ - LocaleKeys.others.tr(context: context).toText16(weight: FontWeight.w500, color: AppColors.textColor), - ], - ), + // Row( + // children: [ + // LocaleKeys.others.tr(context: context).toText16(weight: FontWeight.w500, color: AppColors.textColor), + // ], + // ), SizedBox(height: 16.h), GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( @@ -1408,21 +1408,22 @@ class _MedicalFilePageState extends State { padding: EdgeInsets.zero, shrinkWrap: true, children: [ - MedicalFileCard( - label: LocaleKeys.askYourDoctor.tr(context: context), - textColor: AppColors.blackColor, - backgroundColor: AppColors.whiteColor, - svgIcon: AppAssets.ask_doctor_medical_file_icon, - isLargeText: true, - iconSize: 36.w, - ).onPress(() { - getIt.get().initAskDoctorViewModel(); - Navigator.of(context).push( - CustomPageRoute( - page: AskDoctorPage(), - ), - ); - }), + // MedicalFileCard( + // label: LocaleKeys.askYourDoctor.tr(context: context), + // textColor: AppColors.blackColor, + // backgroundColor: AppColors.whiteColor, + // svgIcon: AppAssets.ask_doctor_medical_file_icon, + // isLargeText: true, + // iconSize: 36.w, + // ).onPress(() { + // getIt.get().initAskDoctorViewModel(); + // Navigator.of(context).push( + // CustomPageRoute( + // page: AskDoctorPage(), + // ), + // ); + // }), + // MedicalFileCard( // label: LocaleKeys.internetPairing.tr(context: context), // textColor: AppColors.blackColor, From 1709b80e84191906e489c0186dfde6475c308f26 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 30 Mar 2026 13:41:24 +0300 Subject: [PATCH 26/33] Updates --- assets/images/svg/image_icon.svg | 4 + assets/langs/ar-SA.json | 4 +- assets/langs/en-US.json | 4 +- lib/core/app_assets.dart | 1 + lib/core/location_util.dart | 22 +- lib/core/utils/calender_utils_new.dart | 28 +- .../contact_us/contact_us_view_model.dart | 30 +- .../prescriptions_view_model.dart | 2 +- .../radiology/radiology_view_model.dart | 28 +- lib/generated/locale_keys.g.dart | 2 + lib/presentation/contact_us/contact_us.dart | 2 + lib/presentation/contact_us/find_us_page.dart | 13 + .../contact_us/widgets/find_us_item_card.dart | 10 +- lib/presentation/lab/lab_orders_page.dart | 2 +- .../prescription_detail_page.dart | 19 +- .../prescriptions/prescription_item_view.dart | 93 +-- .../prescriptions_list_page.dart | 634 +++++++++++----- .../profile_settings/profile_settings.dart | 33 + .../radiology/radiology_orders_page.dart | 705 +++++++++++++----- .../radiology/radiology_result_page.dart | 98 +-- lib/widgets/appbar/collapsing_list_view.dart | 6 + lib/widgets/common_bottom_sheet.dart | 61 +- 22 files changed, 1289 insertions(+), 512 deletions(-) create mode 100644 assets/images/svg/image_icon.svg diff --git a/assets/images/svg/image_icon.svg b/assets/images/svg/image_icon.svg new file mode 100644 index 00000000..73945847 --- /dev/null +++ b/assets/images/svg/image_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 6df6d8c7..b78b8545 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1589,5 +1589,7 @@ "insuranceRequestSubmittedSuccessfully": "تم إرسال طلب تحديث بيانات التأمين بنجاح. سيتم إعلامك بمجرد الانتهاء.", "updatingEmailAddress": "جارٍ تحديث عنوان البريد الإلكتروني، يرجى الانتظار...", "verifyInsurance": "التحقق من التأمين", - "tests": "تحليل" + "tests": "تحليل", + "calendarPermissionAlert": "يرجى منح إذن الوصول إلى التقويم من إعدادات التطبيق لضبط تذكير تناول الدواء.", + "sortByLocation": "الترتيب حسب الموقع" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index bedf03fd..cbea7b94 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1583,5 +1583,7 @@ "insuranceRequestSubmittedSuccessfully": "Your insurance update request has been successfully submitted. You will be notified once completed.", "updatingEmailAddress": "Updating email address, Please wait...", "verifyInsurance": "Verify Insurance", - "tests": "tests" + "tests": "tests", + "calendarPermissionAlert": "Please grant calendar access permission from app settings to set medication reminder.", + "sortByLocation": "Sort by location" } diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 9d5f28c8..86fbb07e 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -336,6 +336,7 @@ class AppAssets { static const String aiOverView = '$svgBasePath/ai_overview.svg'; static const String darkModeIcon = '$svgBasePath/dark_mode_icon.svg'; static const String biometricLockIcon = '$svgBasePath/biometric_lock_icon.svg'; + static const String imageIcon = '$svgBasePath/image_icon.svg'; // PNGS // static const String hmgLogo = '$pngBasePath/hmg_logo.png'; diff --git a/lib/core/location_util.dart b/lib/core/location_util.dart index cf26d24e..95b154ba 100644 --- a/lib/core/location_util.dart +++ b/lib/core/location_util.dart @@ -94,7 +94,27 @@ class LocationUtils { permissionGranted = await Geolocator.requestPermission(); if (permissionGranted != LocationPermission.whileInUse && permissionGranted != LocationPermission.always) { appState.resetLocation(); - onFailure?.call(); + if (onFailure == null && isShowConfirmDialog) { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), + navigationService.navigatorKey.currentContext!, + child: Utils.getWarningWidget( + loadingText: "Please grant location permission from app settings to see better results", + isShowActionButtons: true, + onCancelTap: () { + navigationService.pop(); + }, + onConfirmTap: () async { + navigationService.pop(); + openAppSettings(); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } else { + onFailure?.call(); + } return; } } else if (permissionGranted == LocationPermission.deniedForever) { diff --git a/lib/core/utils/calender_utils_new.dart b/lib/core/utils/calender_utils_new.dart index 9edfdced..331cf6d5 100644 --- a/lib/core/utils/calender_utils_new.dart +++ b/lib/core/utils/calender_utils_new.dart @@ -1,9 +1,16 @@ import 'dart:async'; import 'package:device_calendar_plus/device_calendar_plus.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:get_it/get_it.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:jiffy/jiffy.dart' show Jiffy; import 'package:manage_calendar_events/manage_calendar_events.dart' hide Calendar; +import 'package:permission_handler/permission_handler.dart'; class CalenderUtilsNew { final DeviceCalendar calender = DeviceCalendar.instance; @@ -17,7 +24,26 @@ class CalenderUtilsNew { Future getCalenders() async { CalendarPermissionStatus result = await DeviceCalendar.instance.hasPermissions(); - if (result != CalendarPermissionStatus.granted) await DeviceCalendar.instance.requestPermissions(); + if (result != CalendarPermissionStatus.granted) { + // await DeviceCalendar.instance.requestPermissions(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: GetIt.instance().navigatorKey.currentContext!), + GetIt.instance().navigatorKey.currentContext!, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.calendarPermissionAlert.tr(), + isShowActionButtons: true, + onCancelTap: () { + GetIt.instance().pop(); + }, + onConfirmTap: () async { + GetIt.instance().pop(); + openAppSettings(); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } var calenders = await calender.listCalendars(); calenders.forEach((calender) { if (!calender.readOnly) { diff --git a/lib/features/contact_us/contact_us_view_model.dart b/lib/features/contact_us/contact_us_view_model.dart index d627c55e..dba89a51 100644 --- a/lib/features/contact_us/contact_us_view_model.dart +++ b/lib/features/contact_us/contact_us_view_model.dart @@ -12,6 +12,7 @@ import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_p import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_status_coc_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; +import 'package:permission_handler/permission_handler.dart'; class ContactUsViewModel extends ChangeNotifier { ContactUsRepo contactUsRepo; @@ -22,6 +23,7 @@ class ContactUsViewModel extends ChangeNotifier { bool isHMGHospitalsListSelected = true; bool isLiveChatProjectsListLoading = false; bool isSendFeedbackTabSelected = true; + bool hasLocationEnabled = false; List hmgHospitalsLocationsList = []; List hmgPharmacyLocationsList = []; @@ -52,11 +54,12 @@ class ContactUsViewModel extends ChangeNotifier { ContactUsViewModel({required this.contactUsRepo, required this.errorHandlerService, required this.appState}); - initContactUsViewModel() { + initContactUsViewModel() async { isHMGLocationsListLoading = true; isHMGHospitalsListSelected = true; isLiveChatProjectsListLoading = true; isCOCItemsListLoading = true; + hasLocationEnabled = false; hmgHospitalsLocationsList.clear(); hmgPharmacyLocationsList.clear(); liveChatProjectsList.clear(); @@ -65,6 +68,18 @@ class ContactUsViewModel extends ChangeNotifier { selectedFeedbackType = FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'); setPatientFeedbackSelectedAppointment(null); getHMGLocations(); + + if (await Permission.location.isGranted) { + setHasLocationEnabled(true); + } else { + setHasLocationEnabled(false); + } + + notifyListeners(); + } + + setHasLocationEnabled(bool hasLocationEnabled) { + this.hasLocationEnabled = hasLocationEnabled; notifyListeners(); } @@ -128,6 +143,19 @@ class ContactUsViewModel extends ChangeNotifier { hmgPharmacyLocationsList.add(location); } } + + if (hmgHospitalsLocationsList.first.distanceInKilometers != 0) { + hmgHospitalsLocationsList.sort((a, b) => a.distanceInKilometers.compareTo(b.distanceInKilometers)); + } else { + hmgHospitalsLocationsList.sort((a, b) => a.locationName!.compareTo(b.locationName!)); + } + + if (hmgPharmacyLocationsList.first.distanceInKilometers != 0) { + hmgPharmacyLocationsList.sort((a, b) => a.distanceInKilometers.compareTo(b.distanceInKilometers)); + } else { + hmgPharmacyLocationsList.sort((a, b) => a.locationName!.compareTo(b.locationName!)); + } + isHMGLocationsListLoading = false; notifyListeners(); if (onSuccess != null) { diff --git a/lib/features/prescriptions/prescriptions_view_model.dart b/lib/features/prescriptions/prescriptions_view_model.dart index c0f9c7b5..1fd8a000 100644 --- a/lib/features/prescriptions/prescriptions_view_model.dart +++ b/lib/features/prescriptions/prescriptions_view_model.dart @@ -163,7 +163,7 @@ class PrescriptionsViewModel extends ChangeNotifier { } else if (apiResponse.messageStatus == 1) { prescriptionDetailsList = apiResponse.data!; prescriptionDetailsList.forEach((element) async { - await checkIfReminderExistForPrescription(prescriptionDetailsList.indexOf(element)); + // await checkIfReminderExistForPrescription(prescriptionDetailsList.indexOf(element)); }); isPrescriptionsDetailsLoading = false; notifyListeners(); diff --git a/lib/features/radiology/radiology_view_model.dart b/lib/features/radiology/radiology_view_model.dart index ee5c970f..fa43a96d 100644 --- a/lib/features/radiology/radiology_view_model.dart +++ b/lib/features/radiology/radiology_view_model.dart @@ -68,17 +68,17 @@ class RadiologyViewModel extends ChangeNotifier { filteredRadiologyOrders = List.from(patientRadiologyOrders); tempRadiologyOrders = [...patientRadiologyOrders]; - final clinicMap = >{}; - final hospitalMap = >{}; - for (var order in patientRadiologyOrders) { - final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); - clinicMap.putIfAbsent(clinicKey, () => []).add(order); - final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); - hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); - } - patientRadiologyOrdersByClinic = clinicMap.values.toList(); - patientRadiologyOrdersByHospital = hospitalMap.values.toList(); - patientRadiologyOrdersViewList = isSortByClinic ? patientRadiologyOrdersByClinic : patientRadiologyOrdersByHospital; + // final clinicMap = >{}; + // final hospitalMap = >{}; + // for (var order in patientRadiologyOrders) { + // final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); + // clinicMap.putIfAbsent(clinicKey, () => []).add(order); + // final hospitalKey = (order.projectName ?? order.projectID ?? 'Unknown').toString().trim(); + // hospitalMap.putIfAbsent(hospitalKey, () => []).add(order); + // } + // patientRadiologyOrdersByClinic = clinicMap.values.toList(); + // patientRadiologyOrdersByHospital = hospitalMap.values.toList(); + // patientRadiologyOrdersViewList = isSortByClinic ? patientRadiologyOrdersByClinic : patientRadiologyOrdersByHospital; isRadiologyOrdersLoading = false; filterSuggestions(); @@ -173,7 +173,7 @@ class RadiologyViewModel extends ChangeNotifier { } filterSuggestions() { - final List labels = patientRadiologyOrders.map((detail) => detail.description).whereType().toList(); + final List labels = patientRadiologyOrders.map((detail) => detail.procedureName.toString().trim()).whereType().toList(); _radiologySuggestionsList = labels.toSet().toList(); notifyListeners(); } @@ -193,7 +193,7 @@ class RadiologyViewModel extends ChangeNotifier { patientRadiologyOrdersByHospital = hospitalMap.values.toList(); patientRadiologyOrdersViewList = isSortByClinic ? patientRadiologyOrdersByClinic : patientRadiologyOrdersByHospital; } else { - filteredRadiologyOrders = filteredRadiologyOrders.where((desc) => (desc.description ?? "").toLowerCase().contains(query.toLowerCase())).toList(); + filteredRadiologyOrders = filteredRadiologyOrders.where((desc) => (desc.procedureName ?? "").toLowerCase().contains(query.toLowerCase())).toList(); final clinicMap = >{}; final hospitalMap = >{}; @@ -206,6 +206,8 @@ class RadiologyViewModel extends ChangeNotifier { patientRadiologyOrdersByClinic = clinicMap.values.toList(); patientRadiologyOrdersByHospital = hospitalMap.values.toList(); patientRadiologyOrdersViewList = isSortByClinic ? patientRadiologyOrdersByClinic : patientRadiologyOrdersByHospital; + + patientRadiologyOrders = filteredRadiologyOrders; } notifyListeners(); } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index ac9f3f7c..4f66d29c 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1584,5 +1584,7 @@ abstract class LocaleKeys { static const updatingEmailAddress = 'updatingEmailAddress'; static const verifyInsurance = 'verifyInsurance'; static const tests = 'tests'; + static const calendarPermissionAlert = 'calendarPermissionAlert'; + static const sortByLocation = 'sortByLocation'; } diff --git a/lib/presentation/contact_us/contact_us.dart b/lib/presentation/contact_us/contact_us.dart index 16a154a1..70ef6e3f 100644 --- a/lib/presentation/contact_us/contact_us.dart +++ b/lib/presentation/contact_us/contact_us.dart @@ -57,6 +57,7 @@ class ContactUs extends StatelessWidget { ), ); }, onFailure: () { + contactUsViewModel.initContactUsViewModel(); Navigator.pop(context); Navigator.of(context).push( CustomPageRoute( @@ -64,6 +65,7 @@ class ContactUs extends StatelessWidget { ), ); }, onLocationDeniedForever: () { + contactUsViewModel.initContactUsViewModel(); Navigator.pop(context); Navigator.of(context).push( CustomPageRoute( diff --git a/lib/presentation/contact_us/find_us_page.dart b/lib/presentation/contact_us/find_us_page.dart index 5957bb83..7707754a 100644 --- a/lib/presentation/contact_us/find_us_page.dart +++ b/lib/presentation/contact_us/find_us_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.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/location_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; @@ -20,15 +21,27 @@ class FindUsPage extends StatelessWidget { late AppState appState; late ContactUsViewModel contactUsViewModel; + late LocationUtils locationUtils; @override Widget build(BuildContext context) { contactUsViewModel = Provider.of(context); appState = getIt.get(); + locationUtils = getIt.get(); + locationUtils.isShowConfirmDialog = true; return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: CollapsingListView( title: LocaleKeys.location.tr(), + location: contactUsViewModel.hasLocationEnabled + ? null + : () { + locationUtils.getCurrentLocation( + onSuccess: (value) { + contactUsViewModel.initContactUsViewModel(); + }, + onFailure: () {},); + }, child: Consumer(builder: (context, contactUsVM, child) { return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/presentation/contact_us/widgets/find_us_item_card.dart b/lib/presentation/contact_us/widgets/find_us_item_card.dart index 4738a63a..063ea153 100644 --- a/lib/presentation/contact_us/widgets/find_us_item_card.dart +++ b/lib/presentation/contact_us/widgets/find_us_item_card.dart @@ -69,13 +69,15 @@ class FindUsItemCard extends StatelessWidget { Widget get distanceInfo => Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - AppCustomChipWidget( - labelText: "${getHMGLocationsModel.distanceInKilometers ?? ""} km", - icon: AppAssets.location_red, + getHMGLocationsModel.distanceInKilometers != 0 + ? AppCustomChipWidget( + labelText: "${getHMGLocationsModel.distanceInKilometers ?? ""} km", + icon: AppAssets.location_red, iconColor: AppColors.primaryRedColor, backgroundColor: AppColors.secondaryLightRedColor, textColor: AppColors.errorColor, - ), + ) + : SizedBox.shrink(), Row( children: [ AppCustomChipWidget( diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index b38ad737..bde9d90e 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -1 +1 @@ -import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_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/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; import 'dart:ui' as ui; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ // CustomButton( // text: LocaleKeys.byClinic.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(true); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, // borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), // textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, // fontSize: 12.f, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: LocaleKeys.byHospital.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(false); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, // borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, // textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, // fontSize: 12, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrders.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.patientLabOrders.length, itemBuilder: (context, index) { final group = labViewModel.patientLabOrders[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget( labelText: "${group.testDetails!.length} ${LocaleKeys.tests.tr(context: context)}", backgroundColor: AppColors.successColor.withOpacity(0.1), textColor: AppColors.successColor, ), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (group.doctorName ?? group.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ Directionality( textDirection: ui.TextDirection.ltr, child: AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(group.orderDate ?? ""), false), isEnglishOnly: true, )), AppCustomChipWidget( labelText: (group.projectName ?? ""), ), AppCustomChipWidget( labelText: (group.clinicDescription ?? ""), ), ], ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: Column( children: [ ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "• ${order.testDetails![index].description!}".toText14(weight: FontWeight.w500), SizedBox(height: 4.h), order.testDetails![index].testDescriptionEn!.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), // Row( // mainAxisSize: MainAxisSize.min, // children: [ // Image.network( // order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", // width: 24.w, // height: 24.h, // fit: BoxFit.cover, // ).circle(100), // SizedBox(width: 8.h), // Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), // ], // ), // SizedBox(height: 8.h), // Wrap( // direction: Axis.horizontal, // spacing: 4.h, // runSpacing: 4.h, // children: [ // AppCustomChipWidget( // labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), isEnglishOnly: true, // ), // Directionality( // textDirection: ui.TextDirection.ltr, // child: AppCustomChipWidget( // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // isEnglishOnly: true, // )), // AppCustomChipWidget( // labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), // ), // ], // ), // // Row( // // children: [ // // CustomButton( // // text: ("Order No: ".needTranslation + order.orderNo!), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // SizedBox(width: 8.h), // // CustomButton( // // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // // SizedBox(height: 8.h), // // Row( // // children: [ // // CustomButton( // // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // SizedBox(height: 12.h), // Row( // children: [ // Expanded(flex: 2, child: SizedBox()), // // Expanded( // // flex: 1, // // child: Container( // // height: 40.h, // // width: 40.w, // // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // // color: AppColors.textColor, // // borderRadius: 12, // // ), // // child: Padding( // // padding: EdgeInsets.all(12.h), // // child: Transform.flip( // // flipX: _appState.isArabic(), // // child: Utils.buildSvgWithAssets( // // icon: AppAssets.forward_arrow_icon_small, // // iconColor: AppColors.whiteColor, // // fit: BoxFit.contain, // // ), // // ), // // ), // // ).onPress(() { // // model.currentlySelectedPatientOrder = order; // // labProvider.getPatientLabResultByHospital(order); // // labProvider.getPatientSpecialResult(order); // // Navigator.of(context).push( // // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // // ); // // }), // // ) // // Expanded( // flex: 2, // child: CustomButton( // icon: AppAssets.view_report_icon, // iconColor: AppColors.primaryRedColor, // iconSize: 16.h, // text: LocaleKeys.viewResults.tr(context: context), // onPressed: () { // labViewModel.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }, // backgroundColor: AppColors.secondaryLightRedColor, // borderColor: AppColors.secondaryLightRedColor, // textColor: AppColors.primaryRedColor, // fontSize: 14, // fontWeight: FontWeight.w500, // borderRadius: 12, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // ) // ], // ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.testDetails!.length > 3 ? 3 : group.testDetails!.length), SizedBox(height: 16.h), CustomButton( text: "${LocaleKeys.viewResults.tr()} (${group.testDetails!.length})", onPressed: () { labProvider.currentlySelectedPatientOrder = group; labProvider.getPatientLabResultByHospital(group); labProvider.getPatientSpecialResult(group); Navigator.of(context).push( CustomPageRoute( page: LabResultByClinic(labOrder: group), ), ); }, backgroundColor: AppColors.infoColor.withAlpha(20), borderColor: AppColors.infoColor.withAlpha(0), textColor: AppColors.infoColor, fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontWeight: FontWeight.w500, borderRadius: 12.r, padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), height: 40.h, iconSize: 14.h, icon: AppAssets.view_report_icon, iconColor: AppColors.infoColor, ), SizedBox(height: 16.h), ], ), ) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.indexedCharacterForUniqueTest, details: labViewModel.uniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file +import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_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/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; import 'dart:ui' as ui; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ // CustomButton( // text: LocaleKeys.byClinic.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(true); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, // borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), // textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, // fontSize: 12.f, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: LocaleKeys.byHospital.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(false); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, // borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, // textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, // fontSize: 12, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrders.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.patientLabOrders.length, itemBuilder: (context, index) { final group = labViewModel.patientLabOrders[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: "${group.testDetails!.length} ${LocaleKeys.tests.tr(context: context)}", backgroundColor: AppColors.successColor.withOpacity(0.1), textColor: AppColors.successColor, ), AppCustomChipWidget( labelText: "${_appState.isArabic() ? group.isInOutPatientDescriptionN : group.isInOutPatientDescription}", backgroundColor: group.isInOutPatient! ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.warningColorYellow.withOpacity(0.1), textColor: group.isInOutPatient! ? AppColors.primaryRedColor : AppColors.warningColorYellow, ) ], ), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (group.doctorName ?? group.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ Directionality( textDirection: ui.TextDirection.ltr, child: AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(group.orderDate ?? ""), false), isEnglishOnly: true, )), AppCustomChipWidget( labelText: (group.projectName ?? ""), ), AppCustomChipWidget( labelText: (group.clinicDescription ?? ""), ), ], ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: Column( children: [ ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "• ${order.testDetails![index].description!}".toText14(weight: FontWeight.w500), SizedBox(height: 4.h), order.testDetails![index].testDescriptionEn!.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), // Row( // mainAxisSize: MainAxisSize.min, // children: [ // Image.network( // order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", // width: 24.w, // height: 24.h, // fit: BoxFit.cover, // ).circle(100), // SizedBox(width: 8.h), // Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), // ], // ), // SizedBox(height: 8.h), // Wrap( // direction: Axis.horizontal, // spacing: 4.h, // runSpacing: 4.h, // children: [ // AppCustomChipWidget( // labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), isEnglishOnly: true, // ), // Directionality( // textDirection: ui.TextDirection.ltr, // child: AppCustomChipWidget( // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // isEnglishOnly: true, // )), // AppCustomChipWidget( // labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), // ), // ], // ), // // Row( // // children: [ // // CustomButton( // // text: ("Order No: ".needTranslation + order.orderNo!), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // SizedBox(width: 8.h), // // CustomButton( // // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // // SizedBox(height: 8.h), // // Row( // // children: [ // // CustomButton( // // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // SizedBox(height: 12.h), // Row( // children: [ // Expanded(flex: 2, child: SizedBox()), // // Expanded( // // flex: 1, // // child: Container( // // height: 40.h, // // width: 40.w, // // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // // color: AppColors.textColor, // // borderRadius: 12, // // ), // // child: Padding( // // padding: EdgeInsets.all(12.h), // // child: Transform.flip( // // flipX: _appState.isArabic(), // // child: Utils.buildSvgWithAssets( // // icon: AppAssets.forward_arrow_icon_small, // // iconColor: AppColors.whiteColor, // // fit: BoxFit.contain, // // ), // // ), // // ), // // ).onPress(() { // // model.currentlySelectedPatientOrder = order; // // labProvider.getPatientLabResultByHospital(order); // // labProvider.getPatientSpecialResult(order); // // Navigator.of(context).push( // // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // // ); // // }), // // ) // // Expanded( // flex: 2, // child: CustomButton( // icon: AppAssets.view_report_icon, // iconColor: AppColors.primaryRedColor, // iconSize: 16.h, // text: LocaleKeys.viewResults.tr(context: context), // onPressed: () { // labViewModel.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }, // backgroundColor: AppColors.secondaryLightRedColor, // borderColor: AppColors.secondaryLightRedColor, // textColor: AppColors.primaryRedColor, // fontSize: 14, // fontWeight: FontWeight.w500, // borderRadius: 12, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // ) // ], // ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.testDetails!.length > 3 ? 3 : group.testDetails!.length), SizedBox(height: 16.h), CustomButton( text: "${LocaleKeys.viewResults.tr()} (${group.testDetails!.length})", onPressed: () { labProvider.currentlySelectedPatientOrder = group; labProvider.getPatientLabResultByHospital(group); labProvider.getPatientSpecialResult(group); Navigator.of(context).push( CustomPageRoute( page: LabResultByClinic(labOrder: group), ), ); }, backgroundColor: AppColors.infoColor.withAlpha(20), borderColor: AppColors.infoColor.withAlpha(0), textColor: AppColors.infoColor, fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontWeight: FontWeight.w500, borderRadius: 12.r, padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), height: 40.h, iconSize: 14.h, icon: AppAssets.view_report_icon, iconColor: AppColors.infoColor, ), SizedBox(height: 16.h), ], ), ) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.indexedCharacterForUniqueTest, details: labViewModel.uniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file diff --git a/lib/presentation/prescriptions/prescription_detail_page.dart b/lib/presentation/prescriptions/prescription_detail_page.dart index ec2cd1a0..235ad554 100644 --- a/lib/presentation/prescriptions/prescription_detail_page.dart +++ b/lib/presentation/prescriptions/prescription_detail_page.dart @@ -4,6 +4,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; @@ -63,8 +65,9 @@ class _PrescriptionDetailPageState extends State { Expanded( child: CollapsingListView( title: LocaleKeys.prescriptions.tr(context: context), - instructions: () async { - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPrescriptionPDFPleaseWait.tr(context: context)); + instructions: widget.prescriptionsResponseModel.isInOutPatient! + ? () async { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPrescriptionPDFPleaseWait.tr(context: context)); await prescriptionsViewModel.getPrescriptionInstructionsPDF(widget.prescriptionsResponseModel, onSuccess: (val) { LoaderBottomSheet.hideLoader(); if (prescriptionsViewModel.prescriptionInstructionsPDFLink.isNotEmpty) { @@ -89,7 +92,8 @@ class _PrescriptionDetailPageState extends State { isCloseButtonVisible: true, ); }); - }, + } + : null, child: SingleChildScrollView( child: Consumer(builder: (context, prescriptionVM, child) { return Column( @@ -107,6 +111,13 @@ class _PrescriptionDetailPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + AppCustomChipWidget( + labelText: + "${getIt.get().isArabic() ? widget.prescriptionsResponseModel.isInOutPatientDescriptionN : widget.prescriptionsResponseModel.isInOutPatientDescription}", + backgroundColor: widget.prescriptionsResponseModel.isInOutPatient! ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.warningColorYellow.withOpacity(0.1), + textColor: widget.prescriptionsResponseModel.isInOutPatient! ? AppColors.primaryRedColor : AppColors.warningColorYellow, + ), + SizedBox(height: 16.h), Row( mainAxisSize: MainAxisSize.min, children: [ @@ -241,7 +252,7 @@ class _PrescriptionDetailPageState extends State { }); } }, - backgroundColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.greyF7Color, + backgroundColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.15), borderColor: AppColors.successColor.withOpacity(0.01), textColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? Colors.white : AppColors.textColor.withOpacity(0.35), fontSize: 16, diff --git a/lib/presentation/prescriptions/prescription_item_view.dart b/lib/presentation/prescriptions/prescription_item_view.dart index c5cd50c2..2b19e3a4 100644 --- a/lib/presentation/prescriptions/prescription_item_view.dart +++ b/lib/presentation/prescriptions/prescription_item_view.dart @@ -103,55 +103,60 @@ class PrescriptionItemView extends StatelessWidget { Switch( activeColor: AppColors.successColor, activeTrackColor: AppColors.successColor.withValues(alpha: .15), - value: isLoading ? false : prescriptionVM.prescriptionDetailsList[index].hasReminder!, + // value: isLoading ? false : prescriptionVM.prescriptionDetailsList[index].hasReminder!, + value: prescriptionVM.prescriptionDetailsList[index].hasReminder!, onChanged: (newValue) async { CalenderUtilsNew calender = CalenderUtilsNew.instance; - if (prescriptionVM.prescriptionDetailsList[index].hasReminder ?? false) { - LoaderBottomSheet.showLoader(loadingText: "Removing Reminders"); - bool resultValue = await calender.checkAndRemoveMultipleItems(id: prescriptionVM.prescriptionDetailsList[index].itemID.toString()); + if (await prescriptionVM.checkIfReminderExistForPrescription(index)) { + prescriptionVM.prescriptionDetailsList[index].hasReminder = true; + } else { + if (prescriptionVM.prescriptionDetailsList[index].hasReminder ?? false) { + LoaderBottomSheet.showLoader(loadingText: "Removing Reminders"); + bool resultValue = await calender.checkAndRemoveMultipleItems(id: prescriptionVM.prescriptionDetailsList[index].itemID.toString()); - prescriptionVM.setPrescriptionItemReminder(newValue, prescriptionVM.prescriptionDetailsList[index]); - LoaderBottomSheet.hideLoader(); - return; - } + prescriptionVM.setPrescriptionItemReminder(newValue, prescriptionVM.prescriptionDetailsList[index]); + LoaderBottomSheet.hideLoader(); + return; + } - DateTime startDate = DateTime.now(); - DateTime endDate = DateTime(startDate.year, startDate.month, startDate.day + prescriptionVM.prescriptionDetailsList[index].days!.toInt()); - BottomSheetUtils().showReminderBottomSheet( - context, - endDate, - "", - prescriptionVM.prescriptionDetailsList[index].itemID.toString(), - "", - "", - title: "${prescriptionVM.prescriptionDetailsList[index].itemDescription} Prescription Reminder", - description: - "${prescriptionVM.prescriptionDetailsList[index].itemDescription} ${prescriptionVM.prescriptionDetailsList[index].frequency} ${prescriptionVM.prescriptionDetailsList[index].route} ", - onSuccess: () {}, - isMultiAllowed: true, - onMultiDateSuccess: (int selectedIndex) async { - bool isEventAdded = await calender.createMultipleEvents( - reminderMinutes: selectedIndex, - frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), - days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), - orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, - itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, - route: prescriptionVM.prescriptionDetailsList[index].route!, - onFailure: (errorMessage) => prescriptionVM.showError(errorMessage), - prescriptionNumber: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), - ); - prescriptionVM.setPrescriptionItemReminder(isEventAdded, prescriptionVM.prescriptionDetailsList[index]); - // setCalender(context, - // eventId: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), - // selectedMinutes: selectedIndex, - // frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), - // days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), - // orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, - // itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, - // route: prescriptionVM.prescriptionDetailsList[index].route!); - }, - ); + DateTime startDate = DateTime.now(); + DateTime endDate = DateTime(startDate.year, startDate.month, startDate.day + prescriptionVM.prescriptionDetailsList[index].days!.toInt()); + BottomSheetUtils().showReminderBottomSheet( + context, + endDate, + "", + prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + "", + "", + title: "${prescriptionVM.prescriptionDetailsList[index].itemDescription} Prescription Reminder", + description: + "${prescriptionVM.prescriptionDetailsList[index].itemDescription} ${prescriptionVM.prescriptionDetailsList[index].frequency} ${prescriptionVM.prescriptionDetailsList[index].route} ", + onSuccess: () {}, + isMultiAllowed: true, + onMultiDateSuccess: (int selectedIndex) async { + bool isEventAdded = await calender.createMultipleEvents( + reminderMinutes: selectedIndex, + frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), + days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), + orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, + itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, + route: prescriptionVM.prescriptionDetailsList[index].route!, + onFailure: (errorMessage) => prescriptionVM.showError(errorMessage), + prescriptionNumber: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + ); + prescriptionVM.setPrescriptionItemReminder(isEventAdded, prescriptionVM.prescriptionDetailsList[index]); + // setCalender(context, + // eventId: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + // selectedMinutes: selectedIndex, + // frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), + // days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), + // orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, + // itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, + // route: prescriptionVM.prescriptionDetailsList[index].route!); + }, + ); + } }, ).toShimmer2(isShow: isLoading), ], diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart index 4eb297d5..da211f9d 100644 --- a/lib/presentation/prescriptions/prescriptions_list_page.dart +++ b/lib/presentation/prescriptions/prescriptions_list_page.dart @@ -69,52 +69,52 @@ class _PrescriptionsListPageState extends State { children: [ SizedBox(height: 16.h), // Clinic & Hospital Sort - Row( - children: [ - CustomButton( - text: LocaleKeys.byClinic.tr(context: context), - onPressed: () { - model.setIsSortByClinic(true); - }, - backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), - textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 10, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - ), - SizedBox(width: 8.h), - CustomButton( - text: LocaleKeys.byHospital.tr(context: context), - onPressed: () { - model.setIsSortByClinic(false); - }, - backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, - borderColor: model.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor, - textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 10, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - ), - ], - ).paddingSymmetrical(24.h, 0.h), - SizedBox(height: 20.h), + // Row( + // children: [ + // CustomButton( + // text: LocaleKeys.byClinic.tr(context: context), + // onPressed: () { + // model.setIsSortByClinic(true); + // }, + // backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, + // borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), + // textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, + // fontSize: 12, + // fontWeight: FontWeight.w500, + // borderRadius: 10, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // ), + // SizedBox(width: 8.h), + // CustomButton( + // text: LocaleKeys.byHospital.tr(context: context), + // onPressed: () { + // model.setIsSortByClinic(false); + // }, + // backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, + // borderColor: model.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor, + // textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, + // fontSize: 12, + // fontWeight: FontWeight.w500, + // borderRadius: 10, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // ), + // ], + // ).paddingSymmetrical(24.h, 0.h), + // SizedBox(height: 20.h), // Expandable list ListView.builder( itemCount: model.isPrescriptionsOrdersLoading ? 4 : model.patientPrescriptionOrders.isNotEmpty - ? model.patientPrescriptionOrdersViewList.length + ? model.patientPrescriptionOrders.length : 1, physics: NeverScrollableScrollPhysics(), shrinkWrap: true, padding: const EdgeInsets.only(left: 0, right: 8), itemBuilder: (context, index) { - final isExpanded = expandedIndex == index; + // final isExpanded = expandedIndex == index; return model.isPrescriptionsOrdersLoading ? LabResultItemView( onTap: () {}, @@ -134,180 +134,416 @@ class _PrescriptionsListPageState extends State { curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), - child: InkWell( - onTap: () { - setState(() { - expandedIndex = isExpanded ? null : index; - }); - }, + child: Container( + key: ValueKey(index), + padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: EdgeInsets.all(16.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CustomButton( - text: "${model.patientPrescriptionOrdersViewList[index].prescriptionsList!.length} Prescriptions Available", - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.w500, - borderRadius: 8, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 30.h, - ), - Icon(isExpanded ? Icons.expand_less : Icons.expand_more), - ], + AppCustomChipWidget( + labelText: + "${getIt.get().isArabic() ? model.patientPrescriptionOrders[index].isInOutPatientDescriptionN : model.patientPrescriptionOrders[index].isInOutPatientDescription}", + backgroundColor: + model.patientPrescriptionOrders[index].isInOutPatient! ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.warningColorYellow.withOpacity(0.1), + textColor: model.patientPrescriptionOrders[index].isInOutPatient! ? AppColors.primaryRedColor : AppColors.warningColorYellow, + ), + SizedBox(height: 16.h), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Image.network( + model.patientPrescriptionOrders[index].doctorImageURL!, + width: 24.h, + height: 24.h, + fit: BoxFit.fill, + ).circle(100), + SizedBox(width: 8.h), + Expanded(child: model.patientPrescriptionOrders[index].doctorName!.toText14(weight: FontWeight.w500)), + ], + ), + SizedBox(height: 8.h), + Wrap( + direction: Axis.horizontal, + spacing: 6.h, + runSpacing: 6.h, + children: [ + Directionality( + textDirection: ui.TextDirection.ltr, + child: AppCustomChipWidget( + labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientPrescriptionOrders[index].appointmentDate), false), + isEnglishOnly: true, ), - SizedBox(height: 8.h), - (model.patientPrescriptionOrdersViewList[index].filterName ?? "").toText16(isBold: true) - ], - ), + ), + AppCustomChipWidget( + labelText: model.patientPrescriptionOrders[index].name, + ), + AppCustomChipWidget( + labelText: model.patientPrescriptionOrders[index].clinicDescription!, + ), + ], ), - AnimatedSwitcher( - duration: Duration(milliseconds: 500), - switchInCurve: Curves.easeIn, - switchOutCurve: Curves.easeOut, - transitionBuilder: (Widget child, Animation animation) { - return FadeTransition( - opacity: animation, - child: SizeTransition( - sizeFactor: animation, - axisAlignment: 0.0, - child: child, + SizedBox(height: 8.h), + Row( + children: [ + Expanded( + flex: 6, + child: CustomButton( + text: model.patientPrescriptionOrders[index].isHomeMedicineDeliverySupported! + ? LocaleKeys.resendOrder.tr(context: context) + : LocaleKeys.prescriptionDeliveryError.tr(context: context), + onPressed: () async { + if (model.patientPrescriptionOrders[index].isHomeMedicineDeliverySupported!) { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPrescriptionDetails.tr(context: context)); + await prescriptionsViewModel.getPrescriptionDetails(prescriptionsViewModel.patientPrescriptionOrders[index], onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + prescriptionsViewModel.initiatePrescriptionDelivery(); + }); + } + }, + backgroundColor: model.patientPrescriptionOrders[index].isHomeMedicineDeliverySupported! + ? AppColors.successColor.withOpacity(0.15) + : AppColors.textColor.withOpacity(0.15), + borderColor: AppColors.successColor.withOpacity(0.01), + textColor: model.patientPrescriptionOrders[index].isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35), + fontSize: model.patientPrescriptionOrders[index].isHomeMedicineDeliverySupported! ? 14.f : 12.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + icon: AppAssets.prescription_refill_icon, + iconColor: model.patientPrescriptionOrders[index].isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35), + iconSize: 16.h, ), - ); - }, - child: isExpanded - ? Container( - key: ValueKey(index), - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...model.patientPrescriptionOrdersViewList[index].prescriptionsList!.map((prescription) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.network( - prescription.doctorImageURL!, - width: 24.h, - height: 24.h, - fit: BoxFit.fill, - ).circle(100), - SizedBox(width: 8.h), - Expanded(child: prescription.doctorName!.toText14(weight: FontWeight.w500)), - ], - ), - SizedBox(height: 8.h), - Wrap( - direction: Axis.horizontal, - spacing: 6.h, - runSpacing: 6.h, - children: [ - Directionality( - textDirection: ui.TextDirection.ltr, - child: AppCustomChipWidget( - labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false), isEnglishOnly: true, - ), - ), - AppCustomChipWidget( - labelText: model.isSortByClinic ? prescription.name ?? "" : prescription.clinicDescription!, - ), - ], - ), - SizedBox(height: 8.h), - Row( - children: [ - Expanded( - flex: 6, - child: CustomButton( - text: prescription.isHomeMedicineDeliverySupported! - ? LocaleKeys.resendOrder.tr(context: context) - : LocaleKeys.prescriptionDeliveryError.tr(context: context), - onPressed: () async { - if (prescription.isHomeMedicineDeliverySupported!) { - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPrescriptionDetails.tr(context: context)); - await prescriptionsViewModel.getPrescriptionDetails(prescriptionsViewModel.patientPrescriptionOrders[index], - onSuccess: (val) { - LoaderBottomSheet.hideLoader(); - prescriptionsViewModel.initiatePrescriptionDelivery(); - }); - } - }, - backgroundColor: - prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor.withOpacity(0.15) : AppColors.greyF7Color, - borderColor: AppColors.successColor.withOpacity(0.01), - textColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35), - fontSize: prescription.isHomeMedicineDeliverySupported! ? 14.f : 12.f, - fontWeight: FontWeight.w500, - borderRadius: 12.r, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - icon: AppAssets.prescription_refill_icon, - iconColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35), - iconSize: 16.h, - ), - ), - SizedBox(width: 8.h), - Expanded( - flex: 1, - child: Container( - height: 40.h, - width: 40.w, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.textColor, - borderRadius: 12, - ), - child: Padding( - padding: EdgeInsets.all(12.h), - child: Transform.flip( - flipX: appState.isArabic(), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon_small, - iconColor: AppColors.whiteColor, - fit: BoxFit.contain, - ), - ), - ), - ).onPress(() { - model.setPrescriptionsDetailsLoading(); - Navigator.of(context).push( - CustomPageRoute( - page: PrescriptionDetailPage( - prescriptionsResponseModel: prescription, - isFromAppointments: false, - ), - ), - ); - }), - ), - ], - ), - SizedBox(height: 12.h), - Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), - SizedBox(height: 12.h), - ], - ); - }).toList(), - ], + ), + SizedBox(width: 8.h), + Expanded( + flex: 1, + child: Container( + height: 40.h, + width: 40.w, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.textColor, + borderRadius: 12, + ), + child: Padding( + padding: EdgeInsets.all(12.h), + child: Transform.flip( + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon_small, + iconColor: AppColors.whiteColor, + fit: BoxFit.contain, + ), + ), + ), + ).onPress(() { + model.setPrescriptionsDetailsLoading(); + Navigator.of(context).push( + CustomPageRoute( + page: PrescriptionDetailPage( + prescriptionsResponseModel: model.patientPrescriptionOrders[index], + isFromAppointments: false, + ), ), - ) - : SizedBox.shrink(), + ); + }), + ), + ], ), + // SizedBox(height: 12.h), + // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), + // SizedBox(height: 12.h), ], ), + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // ...model.patientPrescriptionOrders.map((prescription) { + // return Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Image.network( + // prescription.doctorImageURL!, + // width: 24.h, + // height: 24.h, + // fit: BoxFit.fill, + // ).circle(100), + // SizedBox(width: 8.h), + // Expanded(child: prescription.doctorName!.toText14(weight: FontWeight.w500)), + // ], + // ), + // SizedBox(height: 8.h), + // Wrap( + // direction: Axis.horizontal, + // spacing: 6.h, + // runSpacing: 6.h, + // children: [ + // Directionality( + // textDirection: ui.TextDirection.ltr, + // child: AppCustomChipWidget( + // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false), isEnglishOnly: true, + // ), + // ), + // AppCustomChipWidget( + // labelText: model.isSortByClinic ? prescription.name ?? "" : prescription.clinicDescription!, + // ), + // ], + // ), + // SizedBox(height: 8.h), + // Row( + // children: [ + // Expanded( + // flex: 6, + // child: CustomButton( + // text: prescription.isHomeMedicineDeliverySupported! + // ? LocaleKeys.resendOrder.tr(context: context) + // : LocaleKeys.prescriptionDeliveryError.tr(context: context), + // onPressed: () async { + // if (prescription.isHomeMedicineDeliverySupported!) { + // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPrescriptionDetails.tr(context: context)); + // await prescriptionsViewModel.getPrescriptionDetails(prescriptionsViewModel.patientPrescriptionOrders[index], + // onSuccess: (val) { + // LoaderBottomSheet.hideLoader(); + // prescriptionsViewModel.initiatePrescriptionDelivery(); + // }); + // } + // }, + // backgroundColor: + // prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor.withOpacity(0.15) : AppColors.greyF7Color, + // borderColor: AppColors.successColor.withOpacity(0.01), + // textColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35), + // fontSize: prescription.isHomeMedicineDeliverySupported! ? 14.f : 12.f, + // fontWeight: FontWeight.w500, + // borderRadius: 12.r, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // icon: AppAssets.prescription_refill_icon, + // iconColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35), + // iconSize: 16.h, + // ), + // ), + // SizedBox(width: 8.h), + // Expanded( + // flex: 1, + // child: Container( + // height: 40.h, + // width: 40.w, + // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + // color: AppColors.textColor, + // borderRadius: 12, + // ), + // child: Padding( + // padding: EdgeInsets.all(12.h), + // child: Transform.flip( + // flipX: appState.isArabic(), + // child: Utils.buildSvgWithAssets( + // icon: AppAssets.forward_arrow_icon_small, + // iconColor: AppColors.whiteColor, + // fit: BoxFit.contain, + // ), + // ), + // ), + // ).onPress(() { + // model.setPrescriptionsDetailsLoading(); + // Navigator.of(context).push( + // CustomPageRoute( + // page: PrescriptionDetailPage( + // prescriptionsResponseModel: prescription, + // isFromAppointments: false, + // ), + // ), + // ); + // }), + // ), + // ], + // ), + // SizedBox(height: 12.h), + // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), + // SizedBox(height: 12.h), + // ], + // ); + // }).toList(), + // ], + // ), ), + + // InkWell( + // onTap: () { + // setState(() { + // expandedIndex = isExpanded ? null : index; + // }); + // }, + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Padding( + // padding: EdgeInsets.all(16.h), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // CustomButton( + // text: "${model.patientPrescriptionOrdersViewList[index].prescriptionsList!.length} Prescriptions Available", + // onPressed: () {}, + // backgroundColor: AppColors.greyColor, + // borderColor: AppColors.greyColor, + // textColor: AppColors.blackColor, + // fontSize: 10, + // fontWeight: FontWeight.w500, + // borderRadius: 8, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 30.h, + // ), + // Icon(isExpanded ? Icons.expand_less : Icons.expand_more), + // ], + // ), + // SizedBox(height: 8.h), + // (model.patientPrescriptionOrdersViewList[index].filterName ?? "").toText16(isBold: true) + // ], + // ), + // ), + // AnimatedSwitcher( + // duration: Duration(milliseconds: 500), + // switchInCurve: Curves.easeIn, + // switchOutCurve: Curves.easeOut, + // transitionBuilder: (Widget child, Animation animation) { + // return FadeTransition( + // opacity: animation, + // child: SizeTransition( + // sizeFactor: animation, + // axisAlignment: 0.0, + // child: child, + // ), + // ); + // }, + // // child: isExpanded + // // ? Container( + // // key: ValueKey(index), + // // padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), + // // child: Column( + // // crossAxisAlignment: CrossAxisAlignment.start, + // // children: [ + // // ...model.patientPrescriptionOrdersViewList[index].prescriptionsList!.map((prescription) { + // // return Column( + // // crossAxisAlignment: CrossAxisAlignment.start, + // // children: [ + // // Row( + // // mainAxisSize: MainAxisSize.min, + // // children: [ + // // Image.network( + // // prescription.doctorImageURL!, + // // width: 24.h, + // // height: 24.h, + // // fit: BoxFit.fill, + // // ).circle(100), + // // SizedBox(width: 8.h), + // // Expanded(child: prescription.doctorName!.toText14(weight: FontWeight.w500)), + // // ], + // // ), + // // SizedBox(height: 8.h), + // // Wrap( + // // direction: Axis.horizontal, + // // spacing: 6.h, + // // runSpacing: 6.h, + // // children: [ + // // Directionality( + // // textDirection: ui.TextDirection.ltr, + // // child: AppCustomChipWidget( + // // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false), isEnglishOnly: true, + // // ), + // // ), + // // AppCustomChipWidget( + // // labelText: model.isSortByClinic ? prescription.name ?? "" : prescription.clinicDescription!, + // // ), + // // ], + // // ), + // // SizedBox(height: 8.h), + // // Row( + // // children: [ + // // Expanded( + // // flex: 6, + // // child: CustomButton( + // // text: prescription.isHomeMedicineDeliverySupported! + // // ? LocaleKeys.resendOrder.tr(context: context) + // // : LocaleKeys.prescriptionDeliveryError.tr(context: context), + // // onPressed: () async { + // // if (prescription.isHomeMedicineDeliverySupported!) { + // // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPrescriptionDetails.tr(context: context)); + // // await prescriptionsViewModel.getPrescriptionDetails(prescriptionsViewModel.patientPrescriptionOrders[index], + // // onSuccess: (val) { + // // LoaderBottomSheet.hideLoader(); + // // prescriptionsViewModel.initiatePrescriptionDelivery(); + // // }); + // // } + // // }, + // // backgroundColor: + // // prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor.withOpacity(0.15) : AppColors.greyF7Color, + // // borderColor: AppColors.successColor.withOpacity(0.01), + // // textColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35), + // // fontSize: prescription.isHomeMedicineDeliverySupported! ? 14.f : 12.f, + // // fontWeight: FontWeight.w500, + // // borderRadius: 12.r, + // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // // height: 40.h, + // // icon: AppAssets.prescription_refill_icon, + // // iconColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35), + // // iconSize: 16.h, + // // ), + // // ), + // // SizedBox(width: 8.h), + // // Expanded( + // // flex: 1, + // // child: Container( + // // height: 40.h, + // // width: 40.w, + // // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + // // color: AppColors.textColor, + // // borderRadius: 12, + // // ), + // // child: Padding( + // // padding: EdgeInsets.all(12.h), + // // child: Transform.flip( + // // flipX: appState.isArabic(), + // // child: Utils.buildSvgWithAssets( + // // icon: AppAssets.forward_arrow_icon_small, + // // iconColor: AppColors.whiteColor, + // // fit: BoxFit.contain, + // // ), + // // ), + // // ), + // // ).onPress(() { + // // model.setPrescriptionsDetailsLoading(); + // // Navigator.of(context).push( + // // CustomPageRoute( + // // page: PrescriptionDetailPage( + // // prescriptionsResponseModel: prescription, + // // isFromAppointments: false, + // // ), + // // ), + // // ); + // // }), + // // ), + // // ], + // // ), + // // SizedBox(height: 12.h), + // // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), + // // SizedBox(height: 12.h), + // // ], + // // ); + // // }).toList(), + // // ], + // // ), + // // ) + // // : SizedBox.shrink(), + // ), + // ], + // ), + // ), ), ), ), diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index 50b8eb07..1a10e0de 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -53,6 +53,7 @@ class ProfileSettingsState extends State { scheduleMicrotask(() { insuranceViewModel.initInsuranceProvider(); }); + _loadPermissions(); super.initState(); } @@ -92,6 +93,7 @@ class ProfileSettingsState extends State { final SwiperController _controller = SwiperController(); late InsuranceViewModel insuranceViewModel; late ContactUsViewModel contactUsViewModel; + String _permissionsLabel = ""; @override Widget build(BuildContext context) { @@ -294,6 +296,9 @@ class ProfileSettingsState extends State { launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); }, trailingLabel: "92 006 6666"), 1.divider, + actionItem(AppAssets.permission, LocaleKeys.permissionsProfile.tr(context: context), () { + openAppSettings(); + }, trailingLabel: getCurrentPermissions()), actionItem(AppAssets.feedbackFill, LocaleKeys.feedback.tr(context: context), () { contactUsViewModel.setSelectedFeedbackType( FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'), @@ -349,6 +354,34 @@ class ProfileSettingsState extends State { ); } + Future _loadPermissions() async { + final Map permissionMap = { + 'Camera': Permission.camera, + 'Microphone': Permission.microphone, + 'Location': Permission.location, + 'Notifications': Permission.notification, + 'Calendar': Permission.calendarFullAccess, + }; + + final List granted = []; + + for (final entry in permissionMap.entries) { + if (await entry.value.isGranted) { + granted.add(entry.key); + } + } + + if (mounted) { + setState(() { + _permissionsLabel = granted.isEmpty ? 'No permissions granted' : granted.join(', '); + }); + } + } + + String getCurrentPermissions() { + return _permissionsLabel; + } + Widget actionItem(String icon, String label, VoidCallback onPress, {String trailingLabel = "", bool? switchValue, ValueChanged? onSwitchChanged, bool isExternalLink = false}) { return SizedBox( height: 56.h, diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart index 81aef5c7..e24c3472 100644 --- a/lib/presentation/radiology/radiology_orders_page.dart +++ b/lib/presentation/radiology/radiology_orders_page.dart @@ -3,6 +3,8 @@ import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; @@ -96,40 +98,40 @@ class _RadiologyOrdersPageState extends State { children: [ // Clinic / Hospital toggle SizedBox(height: 16.h), - Row( - children: [ - CustomButton( - text: LocaleKeys.byClinic.tr(context: context), - onPressed: () { - model.setIsSortByClinic(true); - }, - backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), - textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 10, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - ), - SizedBox(width: 8.h), - CustomButton( - text: LocaleKeys.byHospital.tr(context: context), - onPressed: () { - model.setIsSortByClinic(false); - }, - backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, - borderColor: model.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, - textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 10, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - ), - ], - ), - SizedBox(height: 8.h), + // Row( + // children: [ + // CustomButton( + // text: LocaleKeys.byClinic.tr(context: context), + // onPressed: () { + // model.setIsSortByClinic(true); + // }, + // backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, + // borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), + // textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, + // fontSize: 12, + // fontWeight: FontWeight.w500, + // borderRadius: 10, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // ), + // SizedBox(width: 8.h), + // CustomButton( + // text: LocaleKeys.byHospital.tr(context: context), + // onPressed: () { + // model.setIsSortByClinic(false); + // }, + // backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, + // borderColor: model.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, + // textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, + // fontSize: 12, + // fontWeight: FontWeight.w500, + // borderRadius: 10, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // ), + // ], + // ), + // SizedBox(height: 8.h), selectedFilterText.isNotEmpty ? AppCustomChipWidget( padding: EdgeInsets.symmetric(horizontal: 5.h), @@ -171,198 +173,521 @@ class _RadiologyOrdersPageState extends State { return Utils.getNoDataWidget(ctx, noDataText: LocaleKeys.youDontHaveRadiologyOrders.tr(context: context)); } - return ListView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - padding: EdgeInsets.zero, - itemCount: model.patientRadiologyOrdersViewList.length, - itemBuilder: (context, index) { - final group = model.patientRadiologyOrdersViewList[index]; - final displayName = model.isSortByClinic ? (group.first.clinicDescription ?? 'Unknown') : (group.first.projectName ?? 'Unknown'); - final isExpanded = expandedIndex == index; - return AnimationConfiguration.staggeredList( + // return ListView.builder( + // shrinkWrap: true, + // physics: NeverScrollableScrollPhysics(), + // padding: EdgeInsets.zero, + // itemCount: model.patientRadiologyOrdersViewList.length, + // itemBuilder: (context, index) { + // final group = model.patientRadiologyOrdersViewList[index]; + // final displayName = model.isSortByClinic ? (group.first.clinicDescription ?? 'Unknown') : (group.first.projectName ?? 'Unknown'); + // final isExpanded = expandedIndex == index; + // return AnimationConfiguration.staggeredList( + // position: index, + // duration: const Duration(milliseconds: 400), + // child: SlideAnimation( + // verticalOffset: 50.0, + // child: FadeInAnimation( + // child: AnimatedContainer( + // duration: const Duration(milliseconds: 300), + // curve: Curves.easeInOut, + // margin: EdgeInsets.symmetric(vertical: 8.h), + // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + // color: AppColors.whiteColor, + // borderRadius: 20.h, + // hasShadow: true, + // ), + // child: InkWell( + // onTap: () { + // setState(() { + // expandedIndex = isExpanded ? null : index; + // }); + // WidgetsBinding.instance.addPostFrameCallback((_) { + // final key = _groupKeys.putIfAbsent(index, () => GlobalKey()); + // if (key.currentContext != null && expandedIndex == index) { + // Future.delayed(const Duration(milliseconds: 450), () { + // if (key.currentContext != null) { + // Scrollable.ensureVisible( + // key.currentContext!, + // duration: const Duration(milliseconds: 350), + // curve: Curves.easeInOut, + // alignment: 0.0, + // ); + // } + // }); + // } + // }); + // }, + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Padding( + // key: _groupKeys.putIfAbsent(index, () => GlobalKey()), + // padding: EdgeInsets.all(16.h), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // AppCustomChipWidget(labelText: "${group.length} ${LocaleKeys.results.tr(context: context)}"), + // Icon(isExpanded ? Icons.expand_less : Icons.expand_more), + // ], + // ), + // SizedBox(height: 8.h), + // Text( + // displayName, + // style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), + // overflow: TextOverflow.ellipsis, + // ), + // ], + // ), + // ), + // AnimatedSwitcher( + // duration: const Duration(milliseconds: 500), + // switchInCurve: Curves.easeIn, + // switchOutCurve: Curves.easeOut, + // transitionBuilder: (Widget child, Animation animation) { + // return FadeTransition( + // opacity: animation, + // child: SizeTransition( + // sizeFactor: animation, + // axisAlignment: 0.0, + // child: child, + // ), + // ); + // }, + // child: isExpanded + // ? Container( + // key: ValueKey(index), + // padding: EdgeInsets.symmetric(horizontal: 16.w), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // ...group.map((order) { + // return Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Image.network( + // order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", + // width: 24.w, + // height: 24.h, + // fit: BoxFit.cover, + // ).circle(100), + // SizedBox(width: 8.h), + // Expanded( + // child: (order.doctorName ?? '').toString().toText14(weight: FontWeight.w500), + // ), + // ], + // ), + // SizedBox(height: 8.h), + // Wrap( + // direction: Axis.horizontal, + // spacing: 4.h, + // runSpacing: 4.h, + // children: [ + // if ((order.description ?? '').isNotEmpty) + // AppCustomChipWidget( + // labelText: (order.description ?? '').toString(), + // ), + // Directionality( + // textDirection: ui.TextDirection.ltr, + // child: AppCustomChipWidget( + // labelText: DateUtil.formatDateToDate( + // (order.orderDate ?? order.appointmentDate), + // false, + // ), isEnglishOnly: true, + // ), + // ), + // AppCustomChipWidget( + // labelText: model.isSortByClinic ? (order.projectName ?? '') : (order.clinicDescription ?? ''), + // ), + // ], + // ), + // SizedBox(height: 12.h), + // Row( + // children: [ + // Expanded(flex: 2, child: const SizedBox()), + // Expanded( + // flex: 2, + // child: CustomButton( + // icon: AppAssets.view_report_icon, + // iconColor: AppColors.primaryRedColor, + // iconSize: 16.h, + // text: LocaleKeys.viewResults.tr(context: context), + // onPressed: () { + // model.navigationService.push( + // CustomPageRoute( + // page: RadiologyResultPage(patientRadiologyResponseModel: order), + // ), + // ); + // }, + // backgroundColor: AppColors.secondaryLightRedColor, + // borderColor: AppColors.secondaryLightRedColor, + // textColor: AppColors.primaryRedColor, + // fontSize: 14, + // fontWeight: FontWeight.w500, + // borderRadius: 12, + // padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // ), + // ), + // ], + // ), + // SizedBox(height: 12.h), + // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), + // SizedBox(height: 12.h), + // ], + // ); + // }).toList(), + // ], + // ), + // ) + // : const SizedBox.shrink(), + // ), + // ], + // ), + // ), + // ), + // ), + // ), + // ); + // }, + // ); + + return ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, + itemCount: model.patientRadiologyOrders.length, + itemBuilder: (context, index) { + final group = model.patientRadiologyOrders[index]; + final isExpanded = expandedIndex == index; + return AnimationConfiguration.staggeredList( position: index, - duration: const Duration(milliseconds: 400), + duration: const Duration(milliseconds: 500), child: SlideAnimation( - verticalOffset: 50.0, + verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( - duration: const Duration(milliseconds: 300), + duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.h, - hasShadow: true, - ), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); - WidgetsBinding.instance.addPostFrameCallback((_) { - final key = _groupKeys.putIfAbsent(index, () => GlobalKey()); - if (key.currentContext != null && expandedIndex == index) { - Future.delayed(const Duration(milliseconds: 450), () { - if (key.currentContext != null) { - Scrollable.ensureVisible( - key.currentContext!, - duration: const Duration(milliseconds: 350), - curve: Curves.easeInOut, - alignment: 0.0, - ); - } - }); - } - }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - key: _groupKeys.putIfAbsent(index, () => GlobalKey()), padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + AppCustomChipWidget( + labelText: "${getIt.get().isArabic() ? group.isInOutPatientDescriptionN : group.isInOutPatientDescription}", + backgroundColor: group.isInOutPatient! ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.warningColorYellow.withOpacity(0.1), + textColor: group.isInOutPatient! ? AppColors.primaryRedColor : AppColors.warningColorYellow, + ), + SizedBox(height: 16.h), Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, children: [ - AppCustomChipWidget(labelText: "${group.length} ${LocaleKeys.results.tr(context: context)}"), - Icon(isExpanded ? Icons.expand_less : Icons.expand_more), + Image.network( + group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", + width: 24.w, + height: 24.h, + fit: BoxFit.cover, + ).circle(100), + SizedBox(width: 8.h), + Expanded(child: (group.doctorName ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), - Text( - displayName, - style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), - overflow: TextOverflow.ellipsis, + Wrap( + direction: Axis.horizontal, + spacing: 4.h, + runSpacing: 4.h, + children: [ + Directionality( + textDirection: ui.TextDirection.ltr, + child: AppCustomChipWidget( + labelText: DateUtil.formatDateToDate(group.orderDate!, false), + isEnglishOnly: true, + )), + AppCustomChipWidget( + labelText: (group.projectName ?? ""), + ), + AppCustomChipWidget( + labelText: (group.clinicDescription ?? ""), + ), + ], ), + SizedBox(height: 16.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "• ${group.procedureName.toString().trim() ?? ""}".toText14(weight: FontWeight.w500), + // "Lorem ipsum text".toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), + SizedBox(height: 16.h), + CustomButton( + text: LocaleKeys.viewReport.tr(), + onPressed: () { + model.navigationService.push( + CustomPageRoute( + page: RadiologyResultPage(patientRadiologyResponseModel: group), + ), + ); + }, + backgroundColor: AppColors.infoColor.withAlpha(20), + borderColor: AppColors.infoColor.withAlpha(0), + textColor: AppColors.infoColor, + fontSize: (isFoldable || isTablet) ? 12.f : 14.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), + height: 40.h, + iconSize: 14.h, + icon: AppAssets.view_report_icon, + iconColor: AppColors.infoColor, + ), + ], + ) ], ), ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 500), - switchInCurve: Curves.easeIn, - switchOutCurve: Curves.easeOut, - transitionBuilder: (Widget child, Animation animation) { - return FadeTransition( - opacity: animation, - child: SizeTransition( - sizeFactor: animation, - axisAlignment: 0.0, - child: child, - ), - ); - }, - child: isExpanded - ? Container( - key: ValueKey(index), - padding: EdgeInsets.symmetric(horizontal: 16.w), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...group.map((order) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.network( - order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", - width: 24.w, - height: 24.h, - fit: BoxFit.cover, - ).circle(100), - SizedBox(width: 8.h), - Expanded( - child: (order.doctorName ?? '').toString().toText14(weight: FontWeight.w500), - ), - ], - ), - SizedBox(height: 8.h), - Wrap( - direction: Axis.horizontal, - spacing: 4.h, - runSpacing: 4.h, - children: [ - if ((order.description ?? '').isNotEmpty) - AppCustomChipWidget( - labelText: (order.description ?? '').toString(), - ), - Directionality( - textDirection: ui.TextDirection.ltr, - child: AppCustomChipWidget( - labelText: DateUtil.formatDateToDate( - (order.orderDate ?? order.appointmentDate), - false, - ), isEnglishOnly: true, - ), - ), - AppCustomChipWidget( - labelText: model.isSortByClinic ? (order.projectName ?? '') : (order.clinicDescription ?? ''), - ), - ], - ), - SizedBox(height: 12.h), - Row( - children: [ - Expanded(flex: 2, child: const SizedBox()), - Expanded( - flex: 2, - child: CustomButton( - icon: AppAssets.view_report_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 16.h, - text: LocaleKeys.viewResults.tr(context: context), - onPressed: () { - model.navigationService.push( - CustomPageRoute( - page: RadiologyResultPage(patientRadiologyResponseModel: order), - ), - ); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - ), - ), - ], - ), - SizedBox(height: 12.h), - Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), - SizedBox(height: 12.h), - ], - ); - }).toList(), - ], - ), - ) - : const SizedBox.shrink(), - ), + // AnimatedSwitcher( + // duration: Duration(milliseconds: 500), + // switchInCurve: Curves.easeIn, + // switchOutCurve: Curves.easeOut, + // transitionBuilder: (Widget child, Animation animation) { + // return FadeTransition( + // opacity: animation, + // child: SizeTransition( + // sizeFactor: animation, + // axisAlignment: 0.0, + // child: child, + // ), + // ); + // }, + // child: isExpanded + // ? Container( + // key: ValueKey(index), + // padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), + // child: Column( + // children: [ + // ListView.separated( + // shrinkWrap: true, + // physics: NeverScrollableScrollPhysics(), + // padding: EdgeInsets.zero, + // itemBuilder: (cxt, index) { + // PatientRadiologyResponseModel order = group; + // return Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // "• ${order.procedureName ?? ""}".toText14(weight: FontWeight.w500), + // "Lorem ipsum text".toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), + // // SizedBox(height: 4.h), + // // order.testDetails![index].testDescriptionEn!.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), + // // Row( + // // mainAxisSize: MainAxisSize.min, + // // children: [ + // // Image.network( + // // order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", + // // width: 24.w, + // // height: 24.h, + // // fit: BoxFit.cover, + // // ).circle(100), + // // SizedBox(width: 8.h), + // // Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), + // // ], + // // ), + // // SizedBox(height: 8.h), + // // Wrap( + // // direction: Axis.horizontal, + // // spacing: 4.h, + // // runSpacing: 4.h, + // // children: [ + // // AppCustomChipWidget( + // // labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), isEnglishOnly: true, + // // ), + // // Directionality( + // // textDirection: ui.TextDirection.ltr, + // // child: AppCustomChipWidget( + // // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), + // // isEnglishOnly: true, + // // )), + // // AppCustomChipWidget( + // // labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), + // // ), + // // ], + // // ), + // // // Row( + // // // children: [ + // // // CustomButton( + // // // text: ("Order No: ".needTranslation + order.orderNo!), + // // // onPressed: () {}, + // // // backgroundColor: AppColors.greyColor, + // // // borderColor: AppColors.greyColor, + // // // textColor: AppColors.blackColor, + // // // fontSize: 10, + // // // fontWeight: FontWeight.w500, + // // // borderRadius: 8, + // // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // // // height: 24.h, + // // // ), + // // // SizedBox(width: 8.h), + // // // CustomButton( + // // // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), + // // // onPressed: () {}, + // // // backgroundColor: AppColors.greyColor, + // // // borderColor: AppColors.greyColor, + // // // textColor: AppColors.blackColor, + // // // fontSize: 10, + // // // fontWeight: FontWeight.w500, + // // // borderRadius: 8, + // // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // // // height: 24.h, + // // // ), + // // // ], + // // // ), + // // // SizedBox(height: 8.h), + // // // Row( + // // // children: [ + // // // CustomButton( + // // // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), + // // // onPressed: () {}, + // // // backgroundColor: AppColors.greyColor, + // // // borderColor: AppColors.greyColor, + // // // textColor: AppColors.blackColor, + // // // fontSize: 10, + // // // fontWeight: FontWeight.w500, + // // // borderRadius: 8, + // // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // // // height: 24.h, + // // // ), + // // // ], + // // // ), + // // SizedBox(height: 12.h), + // // Row( + // // children: [ + // // Expanded(flex: 2, child: SizedBox()), + // // // Expanded( + // // // flex: 1, + // // // child: Container( + // // // height: 40.h, + // // // width: 40.w, + // // // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + // // // color: AppColors.textColor, + // // // borderRadius: 12, + // // // ), + // // // child: Padding( + // // // padding: EdgeInsets.all(12.h), + // // // child: Transform.flip( + // // // flipX: _appState.isArabic(), + // // // child: Utils.buildSvgWithAssets( + // // // icon: AppAssets.forward_arrow_icon_small, + // // // iconColor: AppColors.whiteColor, + // // // fit: BoxFit.contain, + // // // ), + // // // ), + // // // ), + // // // ).onPress(() { + // // // model.currentlySelectedPatientOrder = order; + // // // labProvider.getPatientLabResultByHospital(order); + // // // labProvider.getPatientSpecialResult(order); + // // // Navigator.of(context).push( + // // // CustomPageRoute(page: LabResultByClinic(labOrder: order)), + // // // ); + // // // }), + // // // ) + // // + // // Expanded( + // // flex: 2, + // // child: CustomButton( + // // icon: AppAssets.view_report_icon, + // // iconColor: AppColors.primaryRedColor, + // // iconSize: 16.h, + // // text: LocaleKeys.viewResults.tr(context: context), + // // onPressed: () { + // // labViewModel.currentlySelectedPatientOrder = order; + // // labProvider.getPatientLabResultByHospital(order); + // // labProvider.getPatientSpecialResult(order); + // // Navigator.of(context).push( + // // CustomPageRoute(page: LabResultByClinic(labOrder: order)), + // // ); + // // }, + // // backgroundColor: AppColors.secondaryLightRedColor, + // // borderColor: AppColors.secondaryLightRedColor, + // // textColor: AppColors.primaryRedColor, + // // fontSize: 14, + // // fontWeight: FontWeight.w500, + // // borderRadius: 12, + // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // // height: 40.h, + // // ), + // // ) + // // ], + // // ), + // // SizedBox(height: 12.h), + // // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), + // // SizedBox(height: 12.h), + // ], + // ).paddingOnly(top: 16, bottom: 16); + // }, + // separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), + // itemCount: 1), + // SizedBox(height: 16.h), + // CustomButton( + // text: LocaleKeys.viewReport.tr(), + // onPressed: () { + // model.navigationService.push( + // CustomPageRoute( + // page: RadiologyResultPage(patientRadiologyResponseModel: group), + // ), + // ); + // }, + // backgroundColor: AppColors.infoColor.withAlpha(20), + // borderColor: AppColors.infoColor.withAlpha(0), + // textColor: AppColors.infoColor, + // fontSize: (isFoldable || isTablet) ? 12.f : 14.f, + // fontWeight: FontWeight.w500, + // borderRadius: 12.r, + // padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), + // height: 40.h, + // iconSize: 14.h, + // icon: AppAssets.view_report_icon, + // iconColor: AppColors.infoColor, + // ), + // SizedBox(height: 16.h), + // ], + // ), + // ) + // : SizedBox.shrink(), + // ), ], ), ), ), ), - ), - ); - }, - ); - }), - ], - ), - ); - }, - ), + )); + }, + ); + }), + ], + ), + ); + }, ), ), + ), ); } diff --git a/lib/presentation/radiology/radiology_result_page.dart b/lib/presentation/radiology/radiology_result_page.dart index 02f30be5..05f23530 100644 --- a/lib/presentation/radiology/radiology_result_page.dart +++ b/lib/presentation/radiology/radiology_result_page.dart @@ -53,14 +53,48 @@ class _RadiologyResultPageState extends State { Expanded( child: CollapsingListView( title: LocaleKeys.radiologyResult.tr(context: context), - viewImage: () { - if (radiologyViewModel.radiologyImageURL.isNotEmpty) { - Uri uri = Uri.parse(radiologyViewModel.radiologyImageURL); - launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: ""); - } else { - Utils.showToast("Radiology image not available"); - } + downloadReport: () async { + LoaderBottomSheet.showLoader(); + await radiologyViewModel + .getRadiologyPDF( + patientRadiologyResponseModel: widget.patientRadiologyResponseModel, + authenticatedUser: _appState.getAuthenticatedUser()!, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }) + .then((val) async { + LoaderBottomSheet.hideLoader(); + if (radiologyViewModel.patientRadiologyReportPDFBase64.isNotEmpty) { + String path = await Utils.createFileFromString(radiologyViewModel.patientRadiologyReportPDFBase64, "pdf"); + try { + OpenFilex.open(path); + } catch (ex) { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Cannot open file"), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + } + }); }, + // viewImage: () { + // if (radiologyViewModel.radiologyImageURL.isNotEmpty) { + // Uri uri = Uri.parse(radiologyViewModel.radiologyImageURL); + // launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: ""); + // } else { + // Utils.showToast("Radiology image not available"); + // } + // }, child: SingleChildScrollView( child: Padding( padding: EdgeInsets.symmetric(horizontal: 24.h), @@ -124,54 +158,28 @@ class _RadiologyResultPageState extends State { borderRadius: 24.h, hasShadow: true, ), - child: CustomButton( - text: LocaleKeys.downloadReport.tr(context: context), + child: widget.patientRadiologyResponseModel.dIAPACSURL != "" ? CustomButton( + text: LocaleKeys.openRad.tr(context: context), onPressed: () async { - LoaderBottomSheet.showLoader(); - await radiologyViewModel - .getRadiologyPDF( - patientRadiologyResponseModel: widget.patientRadiologyResponseModel, - authenticatedUser: _appState.getAuthenticatedUser()!, - onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: err), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }) - .then((val) async { - LoaderBottomSheet.hideLoader(); - if (radiologyViewModel.patientRadiologyReportPDFBase64.isNotEmpty) { - String path = await Utils.createFileFromString(radiologyViewModel.patientRadiologyReportPDFBase64, "pdf"); - try { - OpenFilex.open(path); - } catch (ex) { - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: "Cannot open file"), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - } - } - }); + if (radiologyViewModel.radiologyImageURL.isNotEmpty) { + Uri uri = Uri.parse(radiologyViewModel.radiologyImageURL); + launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: ""); + } else { + Utils.showToast("Radiology image not available"); + } }, - backgroundColor: AppColors.successColor, - borderColor: AppColors.successColor, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, textColor: Colors.white, fontSize: 16, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 45.h, - icon: AppAssets.download, + icon: AppAssets.imageIcon, iconColor: Colors.white, iconSize: 20.h, - ).paddingSymmetrical(24.h, 24.h), + ).paddingSymmetrical(24.h, 24.h) : SizedBox.shrink(), ), ], ), diff --git a/lib/widgets/appbar/collapsing_list_view.dart b/lib/widgets/appbar/collapsing_list_view.dart index b933e530..4c754b65 100644 --- a/lib/widgets/appbar/collapsing_list_view.dart +++ b/lib/widgets/appbar/collapsing_list_view.dart @@ -27,6 +27,7 @@ class CollapsingListView extends StatelessWidget { VoidCallback? doctorResponse; VoidCallback? downloadReport; VoidCallback? viewImage; + VoidCallback? location; Widget? bottomChild; Widget? trailing; bool isClose; @@ -51,6 +52,7 @@ class CollapsingListView extends StatelessWidget { this.doctorResponse, this.downloadReport, this.viewImage, + this.location, this.isLeading = true, this.trailing, this.leadingCallback, @@ -95,6 +97,7 @@ class CollapsingListView extends StatelessWidget { doctorResponse: doctorResponse, downloadReport: downloadReport, viewImage: viewImage, + location: location, bottomChild: bottomChild, trailing: trailing, aiOverview: aiOverview, @@ -208,6 +211,7 @@ class ScrollAnimatedTitle extends StatefulWidget implements PreferredSizeWidget VoidCallback? doctorResponse; VoidCallback? downloadReport; VoidCallback? viewImage; + VoidCallback? location; Widget? bottomChild; Widget? trailing; @@ -227,6 +231,7 @@ class ScrollAnimatedTitle extends StatefulWidget implements PreferredSizeWidget this.doctorResponse, this.downloadReport, this.viewImage, + this.location, this.bottomChild, this.trailing, }); @@ -307,6 +312,7 @@ class _ScrollAnimatedTitleState extends State { if (widget.aiOverview != null) actionButton(context, t, title: LocaleKeys.aiOverView.tr(context: context), icon: AppAssets.aiOverView, isAiButton: true).onPress(widget.aiOverview!), if (widget.downloadReport != null) actionButton(context, t, title: LocaleKeys.downloadReport.tr(context: context), icon: AppAssets.download).onPress(widget.downloadReport!), if (widget.viewImage != null) actionButton(context, t, title: LocaleKeys.viewRadiologyImage.tr(context: context), icon: AppAssets.download).onPress(widget.viewImage!), + if (widget.location != null) actionButton(context, t, title: LocaleKeys.sortByLocation.tr(context: context), icon: AppAssets.location).onPress(widget.location!), if (widget.trailing != null) widget.trailing!, ] ], diff --git a/lib/widgets/common_bottom_sheet.dart b/lib/widgets/common_bottom_sheet.dart index 5269a8dc..bc52c0cc 100644 --- a/lib/widgets/common_bottom_sheet.dart +++ b/lib/widgets/common_bottom_sheet.dart @@ -2,6 +2,7 @@ import 'dart:io' show Platform; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:get_it/get_it.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/utils/calender_utils_new.dart'; @@ -10,6 +11,7 @@ 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/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_reminder_view.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/services/permission_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -22,19 +24,66 @@ class BottomSheetUtils { _showReminderBottomSheet(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted, onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed); } else { - // Utils.showPermissionConsentDialog(context, TranslationBase.of(context).calendarPermission, () async { - // if (await Permission.calendarFullAccess.request().isGranted) { - // _showReminderDialog(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted, - // onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed); - // } - // }); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: GetIt.instance().navigatorKey.currentContext!), + GetIt.instance().navigatorKey.currentContext!, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.calendarPermissionAlert.tr(), + isShowActionButtons: true, + onCancelTap: () { + GetIt.instance().pop(); + }, + onConfirmTap: () async { + GetIt.instance().pop(); + openAppSettings(); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); } } else { if (await Permission.calendarWriteOnly.request().isGranted) { if (await Permission.calendarFullAccess.request().isGranted) { _showReminderBottomSheet(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted, onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed); + } else { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: GetIt.instance().navigatorKey.currentContext!), + GetIt.instance().navigatorKey.currentContext!, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.calendarPermissionAlert.tr(), + isShowActionButtons: true, + onCancelTap: () { + GetIt.instance().pop(); + }, + onConfirmTap: () async { + GetIt.instance().pop(); + openAppSettings(); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); } + } else { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: GetIt.instance().navigatorKey.currentContext!), + GetIt.instance().navigatorKey.currentContext!, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.calendarPermissionAlert.tr(), + isShowActionButtons: true, + onCancelTap: () { + GetIt.instance().pop(); + }, + onConfirmTap: () async { + GetIt.instance().pop(); + openAppSettings(); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); } } } From fc217466835bae3e1be45939eded9b0d7ae59e9a Mon Sep 17 00:00:00 2001 From: tahaalam Date: Mon, 30 Mar 2026 15:24:20 +0300 Subject: [PATCH 27/33] graph values fix and comparision with the pdf --- lib/features/lab/lab_view_model.dart | 38 +++++++++++----- .../lab/lab_results/lab_result_details.dart | 44 ++++++++++--------- lib/widgets/graph/custom_graph.dart | 2 +- 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index 07cbbde3..a787c6b6 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -377,7 +377,8 @@ class LabViewModel extends ChangeNotifier { LoaderBottomSheet.hideLoader(); if (apiResponse.messageStatus == 2) { } else if (apiResponse.messageStatus == 1) { - var recentThree = sort(apiResponse.data!); + var sortedResult = sort(apiResponse.data!); + var recentThree = sortedResult.take(3).toList(); mainLabResults = recentThree; double highRefrenceValue = double.negativeInfinity; @@ -385,11 +386,12 @@ class LabViewModel extends ChangeNotifier { double lowRefenceValue = double.infinity; String? flagForLowReferenceRange; - recentThree.reversed.forEach((element) { + sortedResult.take(3).toList().reversed.forEach((element) { try { var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!); var resultValue = double.parse(element.resultValue!); - var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); + // var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); + var transformedValue = resultValue; if (resultValue > maxY) { maxY = resultValue; maxX = maxY; @@ -421,9 +423,9 @@ class LabViewModel extends ChangeNotifier { highRefrenceValue = maxY; lowRefenceValue = minY; } - + // if (minY > lowRefenceValue) { - minY = lowRefenceValue - 25; + minY = lowRefenceValue - getInterval(); } this.flagForHighReferenceRange = flagForHighReferenceRange; @@ -432,12 +434,16 @@ class LabViewModel extends ChangeNotifier { lowTransformedReferenceValue = double.parse(transformValueInRange(lowRefenceValue, flagForLowReferenceRange ?? "").toStringAsFixed(1)); this.highRefrenceValue = double.parse(highRefrenceValue.toStringAsFixed(1)); this.lowRefenceValue = double.parse(lowRefenceValue.toStringAsFixed(1)); - - if (maxY < highRefrenceValue) { + if(maxY=1.0 && maxX < 5.0) return .3; + if(maxX >=5.0 && maxX < 10.0) return 1.5; + if(maxX >=10.0 && maxX < 50.0) return 2.5; + if(maxX >=50.0 && maxX < 100.0) return 5; + if(maxX >=100.0 && maxX < 200.0) return 10; + return 15; + } void checkIfGraphShouldBeDisplayed(LabResult recentResult) { shouldShowGraph = recentResult.checkIfGraphShouldBeDisplayed(); @@ -576,7 +593,8 @@ class LabViewModel extends ChangeNotifier { try { var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!); var resultValue = double.parse(element.resultValue!); - var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); + // var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); + var transformedValue = double.parse(element.resultValue!); if (resultValue > maxY) { maxY = resultValue; } diff --git a/lib/presentation/lab/lab_results/lab_result_details.dart b/lib/presentation/lab/lab_results/lab_result_details.dart index d2c1b524..d1ed1470 100644 --- a/lib/presentation/lab/lab_results/lab_result_details.dart +++ b/lib/presentation/lab/lab_results/lab_result_details.dart @@ -326,20 +326,20 @@ class LabResultDetails extends StatelessWidget { }, leftLabelFormatter: (value) { value = double.parse(value.toStringAsFixed(1)); - // return leftLabels(value.toStringAsFixed(2)); - if (value == labmodel.highRefrenceValue) { - return leftLabels(LocaleKeys.high.tr()); - } - - if (value == labmodel.lowRefenceValue) { - return leftLabels(LocaleKeys.low.tr()); - } + return leftLabels(value.toStringAsFixed(2)); + // if (value == labmodel.highRefrenceValue) { + // return leftLabels(LocaleKeys.high.tr()); + // } + // + // if (value == labmodel.lowRefenceValue) { + // return leftLabels(LocaleKeys.low.tr()); + // } return SizedBox.shrink(); // } }, - graphColor: AppColors.blackColor, - graphShadowColor: Colors.transparent, + graphColor: AppColors.graphGridColor, + graphShadowColor: AppColors.graphGridColor.withOpacity(.5), graphGridColor: graphColor.withOpacity(.4), bottomLabelFormatter: (value, data) { if (data.isEmpty) return SizedBox.shrink(); @@ -371,7 +371,7 @@ class LabResultDetails extends StatelessWidget { ranges.add(HorizontalRangeAnnotation( y1: model.minY, y2: model.lowRefenceValue, - color: AppColors.highAndLow.withOpacity(0.05), + color: Colors.transparent, )); ranges.add(HorizontalRangeAnnotation( @@ -383,7 +383,7 @@ class LabResultDetails extends StatelessWidget { ranges.add(HorizontalRangeAnnotation( y1: model.highRefrenceValue, y2: model.maxY, - color: AppColors.criticalLowAndHigh.withOpacity(0.05), + color: Colors.transparent, )); return ranges; } @@ -412,15 +412,17 @@ class LabResultDetails extends StatelessWidget { } double? getInterval(LabViewModel labmodel) { - return .1; - // var maxX = labmodel.maxY; - // if(maxX<1) return .5; - // if(maxX >1 && maxX < 5) return 1; - // if(maxX >5 && maxX < 10) return 5; - // if(maxX >10 && maxX < 50) return 10; - // if(maxX >50 && maxX < 100) return 20; - // if(maxX >100 && maxX < 200) return 30; - // return 50; + // return .1; + var maxX = labmodel.maxY; + if(maxX<1) return .3; + if(maxX >1 && maxX <= 5) return .7; + if(maxX >5 && maxX <= 10) return 2.5; + if(maxX >10 && maxX <= 50) return 5; + if(maxX >50 && maxX <= 100) return 10; + if(maxX >100 && maxX <= 200) return 30; + if(maxX >200 && maxX <= 300) return 50; + if(maxX >300 && maxX <= 400) return 100; + return 200 ; } Widget getLabDescription(BuildContext context) { diff --git a/lib/widgets/graph/custom_graph.dart b/lib/widgets/graph/custom_graph.dart index d9a69a99..3b0629f0 100644 --- a/lib/widgets/graph/custom_graph.dart +++ b/lib/widgets/graph/custom_graph.dart @@ -257,7 +257,7 @@ class CustomGraph extends StatelessWidget { isCurved: true, isStrokeCapRound: true, isStrokeJoinRound: true, - barWidth: 2, + barWidth: 3, gradient: LinearGradient( colors: [resolvedGraphColor, resolvedGraphColor], begin: Alignment.centerLeft, From 1d1c756412d070a6e2480fdb4496def357767241 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Mon, 30 Mar 2026 15:27:54 +0300 Subject: [PATCH 28/33] graph values fix and comparision with the pdf --- lib/features/lab/lab_view_model.dart | 38 +++++++++++----- .../lab/lab_results/lab_result_details.dart | 44 ++++++++++--------- lib/widgets/graph/custom_graph.dart | 2 +- 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index 07cbbde3..a787c6b6 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -377,7 +377,8 @@ class LabViewModel extends ChangeNotifier { LoaderBottomSheet.hideLoader(); if (apiResponse.messageStatus == 2) { } else if (apiResponse.messageStatus == 1) { - var recentThree = sort(apiResponse.data!); + var sortedResult = sort(apiResponse.data!); + var recentThree = sortedResult.take(3).toList(); mainLabResults = recentThree; double highRefrenceValue = double.negativeInfinity; @@ -385,11 +386,12 @@ class LabViewModel extends ChangeNotifier { double lowRefenceValue = double.infinity; String? flagForLowReferenceRange; - recentThree.reversed.forEach((element) { + sortedResult.take(3).toList().reversed.forEach((element) { try { var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!); var resultValue = double.parse(element.resultValue!); - var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); + // var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); + var transformedValue = resultValue; if (resultValue > maxY) { maxY = resultValue; maxX = maxY; @@ -421,9 +423,9 @@ class LabViewModel extends ChangeNotifier { highRefrenceValue = maxY; lowRefenceValue = minY; } - + // if (minY > lowRefenceValue) { - minY = lowRefenceValue - 25; + minY = lowRefenceValue - getInterval(); } this.flagForHighReferenceRange = flagForHighReferenceRange; @@ -432,12 +434,16 @@ class LabViewModel extends ChangeNotifier { lowTransformedReferenceValue = double.parse(transformValueInRange(lowRefenceValue, flagForLowReferenceRange ?? "").toStringAsFixed(1)); this.highRefrenceValue = double.parse(highRefrenceValue.toStringAsFixed(1)); this.lowRefenceValue = double.parse(lowRefenceValue.toStringAsFixed(1)); - - if (maxY < highRefrenceValue) { + if(maxY=1.0 && maxX < 5.0) return .3; + if(maxX >=5.0 && maxX < 10.0) return 1.5; + if(maxX >=10.0 && maxX < 50.0) return 2.5; + if(maxX >=50.0 && maxX < 100.0) return 5; + if(maxX >=100.0 && maxX < 200.0) return 10; + return 15; + } void checkIfGraphShouldBeDisplayed(LabResult recentResult) { shouldShowGraph = recentResult.checkIfGraphShouldBeDisplayed(); @@ -576,7 +593,8 @@ class LabViewModel extends ChangeNotifier { try { var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!); var resultValue = double.parse(element.resultValue!); - var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); + // var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); + var transformedValue = double.parse(element.resultValue!); if (resultValue > maxY) { maxY = resultValue; } diff --git a/lib/presentation/lab/lab_results/lab_result_details.dart b/lib/presentation/lab/lab_results/lab_result_details.dart index d2c1b524..d1ed1470 100644 --- a/lib/presentation/lab/lab_results/lab_result_details.dart +++ b/lib/presentation/lab/lab_results/lab_result_details.dart @@ -326,20 +326,20 @@ class LabResultDetails extends StatelessWidget { }, leftLabelFormatter: (value) { value = double.parse(value.toStringAsFixed(1)); - // return leftLabels(value.toStringAsFixed(2)); - if (value == labmodel.highRefrenceValue) { - return leftLabels(LocaleKeys.high.tr()); - } - - if (value == labmodel.lowRefenceValue) { - return leftLabels(LocaleKeys.low.tr()); - } + return leftLabels(value.toStringAsFixed(2)); + // if (value == labmodel.highRefrenceValue) { + // return leftLabels(LocaleKeys.high.tr()); + // } + // + // if (value == labmodel.lowRefenceValue) { + // return leftLabels(LocaleKeys.low.tr()); + // } return SizedBox.shrink(); // } }, - graphColor: AppColors.blackColor, - graphShadowColor: Colors.transparent, + graphColor: AppColors.graphGridColor, + graphShadowColor: AppColors.graphGridColor.withOpacity(.5), graphGridColor: graphColor.withOpacity(.4), bottomLabelFormatter: (value, data) { if (data.isEmpty) return SizedBox.shrink(); @@ -371,7 +371,7 @@ class LabResultDetails extends StatelessWidget { ranges.add(HorizontalRangeAnnotation( y1: model.minY, y2: model.lowRefenceValue, - color: AppColors.highAndLow.withOpacity(0.05), + color: Colors.transparent, )); ranges.add(HorizontalRangeAnnotation( @@ -383,7 +383,7 @@ class LabResultDetails extends StatelessWidget { ranges.add(HorizontalRangeAnnotation( y1: model.highRefrenceValue, y2: model.maxY, - color: AppColors.criticalLowAndHigh.withOpacity(0.05), + color: Colors.transparent, )); return ranges; } @@ -412,15 +412,17 @@ class LabResultDetails extends StatelessWidget { } double? getInterval(LabViewModel labmodel) { - return .1; - // var maxX = labmodel.maxY; - // if(maxX<1) return .5; - // if(maxX >1 && maxX < 5) return 1; - // if(maxX >5 && maxX < 10) return 5; - // if(maxX >10 && maxX < 50) return 10; - // if(maxX >50 && maxX < 100) return 20; - // if(maxX >100 && maxX < 200) return 30; - // return 50; + // return .1; + var maxX = labmodel.maxY; + if(maxX<1) return .3; + if(maxX >1 && maxX <= 5) return .7; + if(maxX >5 && maxX <= 10) return 2.5; + if(maxX >10 && maxX <= 50) return 5; + if(maxX >50 && maxX <= 100) return 10; + if(maxX >100 && maxX <= 200) return 30; + if(maxX >200 && maxX <= 300) return 50; + if(maxX >300 && maxX <= 400) return 100; + return 200 ; } Widget getLabDescription(BuildContext context) { diff --git a/lib/widgets/graph/custom_graph.dart b/lib/widgets/graph/custom_graph.dart index d9a69a99..3b0629f0 100644 --- a/lib/widgets/graph/custom_graph.dart +++ b/lib/widgets/graph/custom_graph.dart @@ -257,7 +257,7 @@ class CustomGraph extends StatelessWidget { isCurved: true, isStrokeCapRound: true, isStrokeJoinRound: true, - barWidth: 2, + barWidth: 3, gradient: LinearGradient( colors: [resolvedGraphColor, resolvedGraphColor], begin: Alignment.centerLeft, From 4dce062daff4899c7753457d56e8b7fc3925e4c4 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Mon, 30 Mar 2026 15:31:02 +0300 Subject: [PATCH 29/33] Revert "graph values fix and comparision with the pdf" This reverts commit fc217466835bae3e1be45939eded9b0d7ae59e9a. --- lib/features/lab/lab_view_model.dart | 38 +++++----------- .../lab/lab_results/lab_result_details.dart | 44 +++++++++---------- lib/widgets/graph/custom_graph.dart | 2 +- 3 files changed, 32 insertions(+), 52 deletions(-) diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index a787c6b6..07cbbde3 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -377,8 +377,7 @@ class LabViewModel extends ChangeNotifier { LoaderBottomSheet.hideLoader(); if (apiResponse.messageStatus == 2) { } else if (apiResponse.messageStatus == 1) { - var sortedResult = sort(apiResponse.data!); - var recentThree = sortedResult.take(3).toList(); + var recentThree = sort(apiResponse.data!); mainLabResults = recentThree; double highRefrenceValue = double.negativeInfinity; @@ -386,12 +385,11 @@ class LabViewModel extends ChangeNotifier { double lowRefenceValue = double.infinity; String? flagForLowReferenceRange; - sortedResult.take(3).toList().reversed.forEach((element) { + recentThree.reversed.forEach((element) { try { var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!); var resultValue = double.parse(element.resultValue!); - // var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); - var transformedValue = resultValue; + var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); if (resultValue > maxY) { maxY = resultValue; maxX = maxY; @@ -423,9 +421,9 @@ class LabViewModel extends ChangeNotifier { highRefrenceValue = maxY; lowRefenceValue = minY; } - // + if (minY > lowRefenceValue) { - minY = lowRefenceValue - getInterval(); + minY = lowRefenceValue - 25; } this.flagForHighReferenceRange = flagForHighReferenceRange; @@ -434,16 +432,12 @@ class LabViewModel extends ChangeNotifier { lowTransformedReferenceValue = double.parse(transformValueInRange(lowRefenceValue, flagForLowReferenceRange ?? "").toStringAsFixed(1)); this.highRefrenceValue = double.parse(highRefrenceValue.toStringAsFixed(1)); this.lowRefenceValue = double.parse(lowRefenceValue.toStringAsFixed(1)); - if(maxY=1.0 && maxX < 5.0) return .3; - if(maxX >=5.0 && maxX < 10.0) return 1.5; - if(maxX >=10.0 && maxX < 50.0) return 2.5; - if(maxX >=50.0 && maxX < 100.0) return 5; - if(maxX >=100.0 && maxX < 200.0) return 10; - return 15; - } void checkIfGraphShouldBeDisplayed(LabResult recentResult) { shouldShowGraph = recentResult.checkIfGraphShouldBeDisplayed(); @@ -593,8 +576,7 @@ class LabViewModel extends ChangeNotifier { try { var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!); var resultValue = double.parse(element.resultValue!); - // var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); - var transformedValue = double.parse(element.resultValue!); + var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); if (resultValue > maxY) { maxY = resultValue; } diff --git a/lib/presentation/lab/lab_results/lab_result_details.dart b/lib/presentation/lab/lab_results/lab_result_details.dart index d1ed1470..d2c1b524 100644 --- a/lib/presentation/lab/lab_results/lab_result_details.dart +++ b/lib/presentation/lab/lab_results/lab_result_details.dart @@ -326,20 +326,20 @@ class LabResultDetails extends StatelessWidget { }, leftLabelFormatter: (value) { value = double.parse(value.toStringAsFixed(1)); - return leftLabels(value.toStringAsFixed(2)); - // if (value == labmodel.highRefrenceValue) { - // return leftLabels(LocaleKeys.high.tr()); - // } - // - // if (value == labmodel.lowRefenceValue) { - // return leftLabels(LocaleKeys.low.tr()); - // } + // return leftLabels(value.toStringAsFixed(2)); + if (value == labmodel.highRefrenceValue) { + return leftLabels(LocaleKeys.high.tr()); + } + + if (value == labmodel.lowRefenceValue) { + return leftLabels(LocaleKeys.low.tr()); + } return SizedBox.shrink(); // } }, - graphColor: AppColors.graphGridColor, - graphShadowColor: AppColors.graphGridColor.withOpacity(.5), + graphColor: AppColors.blackColor, + graphShadowColor: Colors.transparent, graphGridColor: graphColor.withOpacity(.4), bottomLabelFormatter: (value, data) { if (data.isEmpty) return SizedBox.shrink(); @@ -371,7 +371,7 @@ class LabResultDetails extends StatelessWidget { ranges.add(HorizontalRangeAnnotation( y1: model.minY, y2: model.lowRefenceValue, - color: Colors.transparent, + color: AppColors.highAndLow.withOpacity(0.05), )); ranges.add(HorizontalRangeAnnotation( @@ -383,7 +383,7 @@ class LabResultDetails extends StatelessWidget { ranges.add(HorizontalRangeAnnotation( y1: model.highRefrenceValue, y2: model.maxY, - color: Colors.transparent, + color: AppColors.criticalLowAndHigh.withOpacity(0.05), )); return ranges; } @@ -412,17 +412,15 @@ class LabResultDetails extends StatelessWidget { } double? getInterval(LabViewModel labmodel) { - // return .1; - var maxX = labmodel.maxY; - if(maxX<1) return .3; - if(maxX >1 && maxX <= 5) return .7; - if(maxX >5 && maxX <= 10) return 2.5; - if(maxX >10 && maxX <= 50) return 5; - if(maxX >50 && maxX <= 100) return 10; - if(maxX >100 && maxX <= 200) return 30; - if(maxX >200 && maxX <= 300) return 50; - if(maxX >300 && maxX <= 400) return 100; - return 200 ; + return .1; + // var maxX = labmodel.maxY; + // if(maxX<1) return .5; + // if(maxX >1 && maxX < 5) return 1; + // if(maxX >5 && maxX < 10) return 5; + // if(maxX >10 && maxX < 50) return 10; + // if(maxX >50 && maxX < 100) return 20; + // if(maxX >100 && maxX < 200) return 30; + // return 50; } Widget getLabDescription(BuildContext context) { diff --git a/lib/widgets/graph/custom_graph.dart b/lib/widgets/graph/custom_graph.dart index 3b0629f0..d9a69a99 100644 --- a/lib/widgets/graph/custom_graph.dart +++ b/lib/widgets/graph/custom_graph.dart @@ -257,7 +257,7 @@ class CustomGraph extends StatelessWidget { isCurved: true, isStrokeCapRound: true, isStrokeJoinRound: true, - barWidth: 3, + barWidth: 2, gradient: LinearGradient( colors: [resolvedGraphColor, resolvedGraphColor], begin: Alignment.centerLeft, From d4ed2b47bc178041306be41c5407daa19483e8aa Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 30 Mar 2026 17:01:45 +0300 Subject: [PATCH 30/33] updates --- .../contact_us/contact_us_view_model.dart | 24 +- .../my_invoices/my_invoices_view_model.dart | 3 + .../prescriptions_view_model.dart | 15 +- .../widgets/appointment_card.dart | 4 +- .../book_appointment_page.dart | 4 + lib/presentation/contact_us/find_us_page.dart | 51 +- .../contact_us/widgets/find_us_item_card.dart | 155 ++++-- .../insurance_approval_details_page.dart | 4 +- .../insurance/insurance_approvals_page.dart | 2 +- .../widgets/insurance_approval_card.dart | 37 +- lib/presentation/lab/lab_orders_page.dart | 2 +- .../patient_sickleaves_list_page.dart | 513 ++++++++++++------ .../my_invoices/my_invoices_details_page.dart | 112 ++-- .../my_invoices/my_invoices_list.dart | 2 +- .../widgets/invoice_list_card.dart | 4 +- .../prescription_detail_page.dart | 4 +- .../prescriptions/prescription_item_view.dart | 7 +- .../prescriptions_list_page.dart | 5 +- .../radiology/radiology_orders_page.dart | 6 +- 19 files changed, 636 insertions(+), 318 deletions(-) diff --git a/lib/features/contact_us/contact_us_view_model.dart b/lib/features/contact_us/contact_us_view_model.dart index dba89a51..34657a85 100644 --- a/lib/features/contact_us/contact_us_view_model.dart +++ b/lib/features/contact_us/contact_us_view_model.dart @@ -144,18 +144,7 @@ class ContactUsViewModel extends ChangeNotifier { } } - if (hmgHospitalsLocationsList.first.distanceInKilometers != 0) { - hmgHospitalsLocationsList.sort((a, b) => a.distanceInKilometers.compareTo(b.distanceInKilometers)); - } else { - hmgHospitalsLocationsList.sort((a, b) => a.locationName!.compareTo(b.locationName!)); - } - - if (hmgPharmacyLocationsList.first.distanceInKilometers != 0) { - hmgPharmacyLocationsList.sort((a, b) => a.distanceInKilometers.compareTo(b.distanceInKilometers)); - } else { - hmgPharmacyLocationsList.sort((a, b) => a.locationName!.compareTo(b.locationName!)); - } - + sortHMGLocations(hasLocationEnabled); isHMGLocationsListLoading = false; notifyListeners(); if (onSuccess != null) { @@ -166,6 +155,17 @@ class ContactUsViewModel extends ChangeNotifier { ); } + sortHMGLocations(bool isByLocation) { + if (isByLocation) { + hmgHospitalsLocationsList.sort((a, b) => a.distanceInKilometers.compareTo(b.distanceInKilometers)); + hmgPharmacyLocationsList.sort((a, b) => a.distanceInKilometers.compareTo(b.distanceInKilometers)); + } else { + hmgHospitalsLocationsList.sort((a, b) => a.locationName!.compareTo(b.locationName!)); + hmgPharmacyLocationsList.sort((a, b) => a.locationName!.compareTo(b.locationName!)); + } + notifyListeners(); + } + Future getLiveChatProjectsList({Function(dynamic)? onSuccess, Function(String)? onError}) async { isLiveChatProjectsListLoading = true; liveChatProjectsList.clear(); diff --git a/lib/features/my_invoices/my_invoices_view_model.dart b/lib/features/my_invoices/my_invoices_view_model.dart index 20d7869f..f3c716ae 100644 --- a/lib/features/my_invoices/my_invoices_view_model.dart +++ b/lib/features/my_invoices/my_invoices_view_model.dart @@ -60,6 +60,9 @@ class MyInvoicesViewModel extends ChangeNotifier { (failure) async { isInvoiceDetailsLoading = false; notifyListeners(); + if (onError != null) { + onError(failure.message); + } }, (apiResponse) { if (apiResponse.messageStatus == 2) { diff --git a/lib/features/prescriptions/prescriptions_view_model.dart b/lib/features/prescriptions/prescriptions_view_model.dart index 1fd8a000..4baf6882 100644 --- a/lib/features/prescriptions/prescriptions_view_model.dart +++ b/lib/features/prescriptions/prescriptions_view_model.dart @@ -19,6 +19,7 @@ import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/widgets/map/map_utility_screen.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; +import 'package:permission_handler/permission_handler.dart'; class PrescriptionsViewModel extends ChangeNotifier { bool isPrescriptionsOrdersLoading = false; @@ -68,9 +69,9 @@ class PrescriptionsViewModel extends ChangeNotifier { notifyListeners(); } - - checkIfReminderExistForPrescription(int index) async { + Future checkIfReminderExistForPrescription(int index) async { prescriptionDetailsList[index].hasReminder = await CalenderUtilsNew.instance.checkIfEventExist(prescriptionDetailsList[index].itemID?.toString() ?? ""); + return prescriptionDetailsList[index].hasReminder ?? false; } setPrescriptionsDetailsLoading() { @@ -157,14 +158,16 @@ class PrescriptionsViewModel extends ChangeNotifier { (failure) async { onError!(failure.message); }, - (apiResponse) { + (apiResponse) async { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { prescriptionDetailsList = apiResponse.data!; - prescriptionDetailsList.forEach((element) async { - // await checkIfReminderExistForPrescription(prescriptionDetailsList.indexOf(element)); - }); + if (await Permission.calendarFullAccess.isGranted && await Permission.calendarWriteOnly.isGranted) { + prescriptionDetailsList.forEach((element) async { + await checkIfReminderExistForPrescription(prescriptionDetailsList.indexOf(element)); + }); + } isPrescriptionsDetailsLoading = false; notifyListeners(); if (onSuccess != null) { diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index 44fcfa86..52a1c219 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -104,8 +104,8 @@ class AppointmentCard extends StatelessWidget { AppCustomChipWidget( labelText: isLoading ? 'OutPatient' : (appState.isArabic() ? patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN! : patientAppointmentHistoryResponseModel.isInOutPatientDescription!), - backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1), - textColor: AppColors.primaryRedColor, + backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.1), + textColor: AppColors.warningColorYellow, ).toShimmer2(isShow: isLoading), AppCustomChipWidget( labelText: isLoading ? 'Booked' : AppointmentType.getAppointmentStatusType(patientAppointmentHistoryResponseModel.patientStatusType!), diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index aea34ff0..4a8ada6a 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -59,10 +59,14 @@ class _BookAppointmentPageState extends State { bookAppointmentsViewModel.initBookAppointmentViewModel(); bookAppointmentsViewModel.getLocation(); immediateLiveCareViewModel.initImmediateLiveCare(); + if (appState.isAuthenticated) { + getIt.get().getPatientMyDoctors(); + } }); WidgetsBinding.instance.addPostFrameCallback((_) { if (bookAppointmentsViewModel.selectedTabIndex == 1) { if (appState.isAuthenticated) { + getIt.get().getPatientMyDoctors(); showUnKnownClinicBottomSheet(); } } else { diff --git a/lib/presentation/contact_us/find_us_page.dart b/lib/presentation/contact_us/find_us_page.dart index 7707754a..9091f74d 100644 --- a/lib/presentation/contact_us/find_us_page.dart +++ b/lib/presentation/contact_us/find_us_page.dart @@ -33,15 +33,6 @@ class FindUsPage extends StatelessWidget { backgroundColor: AppColors.bgScaffoldColor, body: CollapsingListView( title: LocaleKeys.location.tr(), - location: contactUsViewModel.hasLocationEnabled - ? null - : () { - locationUtils.getCurrentLocation( - onSuccess: (value) { - contactUsViewModel.initContactUsViewModel(); - }, - onFailure: () {},); - }, child: Consumer(builder: (context, contactUsVM, child) { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -60,8 +51,48 @@ class FindUsPage extends StatelessWidget { contactUsVM.setHMGHospitalsListSelected(index == 0); }, ).paddingSymmetrical(24.h, 0.h), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true), + SizedBox(height: 4.h), + "Sort the locations by nearest to your location".toText11(color: AppColors.textColorLight, weight: FontWeight.w500), + ], + ), + const Spacer(), + Switch( + activeThumbColor: AppColors.successColor, + activeTrackColor: AppColors.successColor.withValues(alpha: .15), + value: contactUsVM.hasLocationEnabled, + onChanged: (newValue) async { + if (newValue) { + locationUtils.getCurrentLocation( + onSuccess: (value) { + // if (contactUsVM.hmgHospitalsLocationsList.isNotEmpty) { + // contactUsVM.sortHMGLocations(true); + // contactUsVM.setHasLocationEnabled(newValue); + // } else { + contactUsVM.initContactUsViewModel(); + contactUsVM.setHasLocationEnabled(newValue); + contactUsVM.sortHMGLocations(true); + // } + }, + onFailure: () {}, + ); + } else { + contactUsVM.sortHMGLocations(false); + contactUsVM.setHasLocationEnabled(newValue); + } + // bookAppointmentsVM.setIsNearestAppointmentSelected(newValue); + }, + ), + ], + ).paddingSymmetrical(24.h, 12.h), ListView.separated( - padding: EdgeInsets.only(top: 16.h), + padding: EdgeInsets.only(top: 4.h), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: contactUsVM.isHMGLocationsListLoading diff --git a/lib/presentation/contact_us/widgets/find_us_item_card.dart b/lib/presentation/contact_us/widgets/find_us_item_card.dart index 063ea153..521775bc 100644 --- a/lib/presentation/contact_us/widgets/find_us_item_card.dart +++ b/lib/presentation/contact_us/widgets/find_us_item_card.dart @@ -6,24 +6,30 @@ import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart'; import 'package:hmg_patient_app_new/features/contact_us/models/resp_models/get_hmg_locations.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:map_launcher/map_launcher.dart'; +import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; class FindUsItemCard extends StatelessWidget { FindUsItemCard({super.key, required this.getHMGLocationsModel}); late AppState appState; + late ContactUsViewModel contactUsViewModel; GetHMGLocationsModel getHMGLocationsModel; @override Widget build(BuildContext context) { appState = getIt.get(); + contactUsViewModel = getIt.get(); return DecoratedBox( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, @@ -45,73 +51,108 @@ class FindUsItemCard extends StatelessWidget { ); } - Widget get hospitalName => Row( + Widget get hospitalName => Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Image.network( - getHMGLocationsModel.projectImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", - width: 40.h, - height: 40.h, - fit: BoxFit.cover, - ).circle(100).toShimmer2(isShow: false).paddingOnly(right: 10), - Expanded( - child: Text( - getHMGLocationsModel.locationName!, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16, - color: AppColors.blackColor, - ), - ), - ) + (getHMGLocationsModel.distanceInKilometers != 0 && contactUsViewModel.hasLocationEnabled) + ? Column( + children: [ + AppCustomChipWidget( + labelText: "${getHMGLocationsModel.distanceInKilometers ?? ""} km", + labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: 8.w), + icon: AppAssets.location_red, + // iconColor: AppColors.primaryRedColor, + // backgroundColor: AppColors.secondaryLightRedColor, + // textColor: AppColors.errorColor, + ), + SizedBox( + height: 16.h, + ), + ], + ) + : SizedBox.shrink(), + Row( + children: [ + Image.network( + getHMGLocationsModel.projectImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", + width: 40.h, + height: 40.h, + fit: BoxFit.cover, + ).circle(100).toShimmer2(isShow: false).paddingOnly(right: 10), + Expanded( + child: Text( + getHMGLocationsModel.locationName!, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: AppColors.blackColor, + ), + ), + ) + ], + ), ], ); Widget get distanceInfo => Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - getHMGLocationsModel.distanceInKilometers != 0 - ? AppCustomChipWidget( - labelText: "${getHMGLocationsModel.distanceInKilometers ?? ""} km", - icon: AppAssets.location_red, - iconColor: AppColors.primaryRedColor, - backgroundColor: AppColors.secondaryLightRedColor, - textColor: AppColors.errorColor, - ) - : SizedBox.shrink(), - Row( - children: [ - AppCustomChipWidget( - labelText: LocaleKeys.getDirections.tr(), - icon: AppAssets.directions_icon, - iconColor: AppColors.whiteColor, - backgroundColor: AppColors.textColor.withValues(alpha: 0.8), - textColor: AppColors.whiteColor, - onChipTap: () async { - await MapLauncher.showMarker( - mapType: MapType.google, + Expanded( + flex: 7, + child: CustomButton( + text: LocaleKeys.getDirections.tr(), + onPressed: () async { + await MapLauncher.showMarker( + mapType: MapType.google, + coords: Coords(double.parse(getHMGLocationsModel.latitude ?? "0.0"), double.parse(getHMGLocationsModel.longitude ?? "0.0")), + title: getHMGLocationsModel.locationName ?? "Hospital", + ).catchError((err) { + MapLauncher.showMarker( + mapType: Platform.isIOS ? MapType.apple : MapType.google, coords: Coords(double.parse(getHMGLocationsModel.latitude ?? "0.0"), double.parse(getHMGLocationsModel.longitude ?? "0.0")), title: getHMGLocationsModel.locationName ?? "Hospital", - ).catchError((err) { - MapLauncher.showMarker( - mapType: Platform.isIOS ? MapType.apple : MapType.google, - coords: Coords(double.parse(getHMGLocationsModel.latitude ?? "0.0"), double.parse(getHMGLocationsModel.longitude ?? "0.0")), - title: getHMGLocationsModel.locationName ?? "Hospital", - ); - }); - }, + ); + }); + }, + backgroundColor: AppColors.transparent, + borderColor: AppColors.textColor, + textColor: AppColors.blackColor, + borderWidth: 1.h, + fontSize: (isFoldable || isTablet) ? 12.f : 14.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: 40.h, + icon: AppAssets.directions_icon, + iconColor: AppColors.blackColor, + iconSize: 16.h, + ), + ), + SizedBox(width: 8.w), + Expanded( + flex: 1, + child: Container( + height: (isFoldable || isTablet) ? 50.h : 40.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.transparent, + borderRadius: 10.h, + side: BorderSide( + color: AppColors.textColor, + width: 1.2, + ), ), - SizedBox(width: 4.w), - AppCustomChipWidget( - labelText: LocaleKeys.callNow.tr(), - icon: AppAssets.call_fill, - iconColor: Colors.white, - backgroundColor: AppColors.primaryRedColor.withValues(alpha: 1.0), - textColor: Colors.white, - onChipTap: () { - launchUrl(Uri.parse("tel://" + "${getHMGLocationsModel.phoneNumber}")); - }, + child: Transform.flip( + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.call_fill, + iconColor: AppColors.textColor, + width: 5.w, + height: 5.h, + fit: BoxFit.scaleDown, + ), ), - ], + ).onPress(() { + launchUrl(Uri.parse("tel://" + "${getHMGLocationsModel.phoneNumber}")); + }), ), ], ); diff --git a/lib/presentation/insurance/insurance_approval_details_page.dart b/lib/presentation/insurance/insurance_approval_details_page.dart index a074a8d8..7a69e088 100644 --- a/lib/presentation/insurance/insurance_approval_details_page.dart +++ b/lib/presentation/insurance/insurance_approval_details_page.dart @@ -63,8 +63,8 @@ class InsuranceApprovalDetailsPage extends StatelessWidget { ), AppCustomChipWidget( labelText: appState.isArabic() ? insuranceApprovalResponseModel.isInOutPatientDescriptionN! : insuranceApprovalResponseModel.isInOutPatientDescription!, - backgroundColor: AppColors.primaryRedColor.withOpacity(0.1), - textColor: AppColors.primaryRedColor, + backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), + textColor: AppColors.warningColorYellow, ), ], ), diff --git a/lib/presentation/insurance/insurance_approvals_page.dart b/lib/presentation/insurance/insurance_approvals_page.dart index 52f8b1f6..feac2e3a 100644 --- a/lib/presentation/insurance/insurance_approvals_page.dart +++ b/lib/presentation/insurance/insurance_approvals_page.dart @@ -51,7 +51,7 @@ class _InsuranceApprovalsPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ ListView.separated( - padding: EdgeInsets.only(top: 24.h), + padding: EdgeInsets.only(top: 12.h), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: insuranceVM.isInsuranceApprovalsLoading diff --git a/lib/presentation/insurance/widgets/insurance_approval_card.dart b/lib/presentation/insurance/widgets/insurance_approval_card.dart index 588f9887..8f5f7cfb 100644 --- a/lib/presentation/insurance/widgets/insurance_approval_card.dart +++ b/lib/presentation/insurance/widgets/insurance_approval_card.dart @@ -9,8 +9,11 @@ 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/models/resp_models/patient_insurance_approval_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/insurance/insurance_approval_details_page.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; class InsuranceApprovalCard extends StatelessWidget { InsuranceApprovalCard({super.key, required this.insuranceApprovalResponseModel, required this.isLoading, required this.appState}); @@ -64,8 +67,8 @@ class InsuranceApprovalCard extends StatelessWidget { : appState.isArabic() ? insuranceApprovalResponseModel.isInOutPatientDescriptionN! : insuranceApprovalResponseModel.isInOutPatientDescription!, - backgroundColor: AppColors.primaryRedColor.withOpacity(0.1), - textColor: AppColors.primaryRedColor, + backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), + textColor: AppColors.warningColorYellow, ).toShimmer2(isShow: isLoading), ], ).toShimmer2(isShow: isLoading), @@ -111,12 +114,30 @@ class InsuranceApprovalCard extends StatelessWidget { ), ], ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Transform.flip( - flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon_small, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor)), - ], + SizedBox( + height: 12.h, + ), + CustomButton( + text: LocaleKeys.viewDetails.tr(context: context), + onPressed: () async { + Navigator.of(context).push( + CustomPageRoute( + page: InsuranceApprovalDetailsPage(insuranceApprovalResponseModel: insuranceApprovalResponseModel), + ), + ); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: (isFoldable || isTablet) ? 12.f : 14.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: isTablet || isFoldable ? 46.h : 40.h, + // height: 40.h, + // icon: AppAssets.insurance, + // iconColor: AppColors.primaryRedColor, + iconSize: 16.h, ).toShimmer2(isShow: isLoading), ], ), diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index bde9d90e..900477e4 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -1 +1 @@ -import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_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/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; import 'dart:ui' as ui; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ // CustomButton( // text: LocaleKeys.byClinic.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(true); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, // borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), // textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, // fontSize: 12.f, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: LocaleKeys.byHospital.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(false); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, // borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, // textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, // fontSize: 12, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrders.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.patientLabOrders.length, itemBuilder: (context, index) { final group = labViewModel.patientLabOrders[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: "${group.testDetails!.length} ${LocaleKeys.tests.tr(context: context)}", backgroundColor: AppColors.successColor.withOpacity(0.1), textColor: AppColors.successColor, ), AppCustomChipWidget( labelText: "${_appState.isArabic() ? group.isInOutPatientDescriptionN : group.isInOutPatientDescription}", backgroundColor: group.isInOutPatient! ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.warningColorYellow.withOpacity(0.1), textColor: group.isInOutPatient! ? AppColors.primaryRedColor : AppColors.warningColorYellow, ) ], ), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (group.doctorName ?? group.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ Directionality( textDirection: ui.TextDirection.ltr, child: AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(group.orderDate ?? ""), false), isEnglishOnly: true, )), AppCustomChipWidget( labelText: (group.projectName ?? ""), ), AppCustomChipWidget( labelText: (group.clinicDescription ?? ""), ), ], ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: Column( children: [ ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "• ${order.testDetails![index].description!}".toText14(weight: FontWeight.w500), SizedBox(height: 4.h), order.testDetails![index].testDescriptionEn!.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), // Row( // mainAxisSize: MainAxisSize.min, // children: [ // Image.network( // order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", // width: 24.w, // height: 24.h, // fit: BoxFit.cover, // ).circle(100), // SizedBox(width: 8.h), // Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), // ], // ), // SizedBox(height: 8.h), // Wrap( // direction: Axis.horizontal, // spacing: 4.h, // runSpacing: 4.h, // children: [ // AppCustomChipWidget( // labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), isEnglishOnly: true, // ), // Directionality( // textDirection: ui.TextDirection.ltr, // child: AppCustomChipWidget( // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // isEnglishOnly: true, // )), // AppCustomChipWidget( // labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), // ), // ], // ), // // Row( // // children: [ // // CustomButton( // // text: ("Order No: ".needTranslation + order.orderNo!), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // SizedBox(width: 8.h), // // CustomButton( // // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // // SizedBox(height: 8.h), // // Row( // // children: [ // // CustomButton( // // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // SizedBox(height: 12.h), // Row( // children: [ // Expanded(flex: 2, child: SizedBox()), // // Expanded( // // flex: 1, // // child: Container( // // height: 40.h, // // width: 40.w, // // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // // color: AppColors.textColor, // // borderRadius: 12, // // ), // // child: Padding( // // padding: EdgeInsets.all(12.h), // // child: Transform.flip( // // flipX: _appState.isArabic(), // // child: Utils.buildSvgWithAssets( // // icon: AppAssets.forward_arrow_icon_small, // // iconColor: AppColors.whiteColor, // // fit: BoxFit.contain, // // ), // // ), // // ), // // ).onPress(() { // // model.currentlySelectedPatientOrder = order; // // labProvider.getPatientLabResultByHospital(order); // // labProvider.getPatientSpecialResult(order); // // Navigator.of(context).push( // // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // // ); // // }), // // ) // // Expanded( // flex: 2, // child: CustomButton( // icon: AppAssets.view_report_icon, // iconColor: AppColors.primaryRedColor, // iconSize: 16.h, // text: LocaleKeys.viewResults.tr(context: context), // onPressed: () { // labViewModel.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }, // backgroundColor: AppColors.secondaryLightRedColor, // borderColor: AppColors.secondaryLightRedColor, // textColor: AppColors.primaryRedColor, // fontSize: 14, // fontWeight: FontWeight.w500, // borderRadius: 12, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // ) // ], // ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.testDetails!.length > 3 ? 3 : group.testDetails!.length), SizedBox(height: 16.h), CustomButton( text: "${LocaleKeys.viewResults.tr()} (${group.testDetails!.length})", onPressed: () { labProvider.currentlySelectedPatientOrder = group; labProvider.getPatientLabResultByHospital(group); labProvider.getPatientSpecialResult(group); Navigator.of(context).push( CustomPageRoute( page: LabResultByClinic(labOrder: group), ), ); }, backgroundColor: AppColors.infoColor.withAlpha(20), borderColor: AppColors.infoColor.withAlpha(0), textColor: AppColors.infoColor, fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontWeight: FontWeight.w500, borderRadius: 12.r, padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), height: 40.h, iconSize: 14.h, icon: AppAssets.view_report_icon, iconColor: AppColors.infoColor, ), SizedBox(height: 16.h), ], ), ) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.indexedCharacterForUniqueTest, details: labViewModel.uniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file +import 'dart:async'; import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_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/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_toolbar.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; import 'alphabeticScroll.dart'; import 'dart:ui' as ui; class LabOrdersPage extends StatefulWidget { const LabOrdersPage({super.key}); @override State createState() => _LabOrdersPageState(); } class _LabOrdersPageState extends State { late LabViewModel labProvider; late DateRangeSelectorRangeViewModel rangeViewModel; late AppState _appState; List?> labSuggestions = []; int? expandedIndex; String? selectedFilterText = ''; int activeIndex = 0; @override void initState() { scheduleMicrotask(() { labProvider.initLabProvider(); }); super.initState(); } @override Widget build(BuildContext context) { labProvider = Provider.of(context, listen: false); rangeViewModel = Provider.of(context); _appState = getIt(); return CollapsingListView( title: LocaleKeys.labResults.tr(context: context), search: () async { if (labProvider.isLabOrdersLoading) { return; } else { String? value = await Navigator.of(context).push( CustomPageRoute( page: SearchLabResultsContent(labSuggestionsList: labProvider.labSuggestions), fullScreenDialog: true, direction: AxisDirection.down, ), ); if (value != null) { selectedFilterText = value; labProvider.filterLabReports(value); } } }, child: Consumer( builder: (context, labViewModel, child) { return SingleChildScrollView( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: CustomTabBar( activeTextColor: Color(0xffED1C2B), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), tabs: [ CustomTabBarModel(null, LocaleKeys.byVisit.tr()), CustomTabBarModel(null, LocaleKeys.byTest.tr()), // CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { activeIndex = index; setState(() {}); }, ), ), ], ), if (activeIndex == 0) Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Row( children: [ // CustomButton( // text: LocaleKeys.byClinic.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(true); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, // borderColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), // textColor: labViewModel.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, // fontSize: 12.f, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // SizedBox(width: 8.h), // CustomButton( // text: LocaleKeys.byHospital.tr(context: context), // onPressed: () { // labViewModel.setIsSortByClinic(false); // }, // backgroundColor: labViewModel.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, // borderColor: labViewModel.isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, // textColor: labViewModel.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, // fontSize: 12, // fontWeight: FontWeight.w500, // borderRadius: 10, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), ], ), ), SizedBox(height: 8.h), selectedFilterText!.isNotEmpty ? Column( children: [ AppCustomChipWidget( labelText: selectedFilterText!, backgroundColor: AppColors.alertColor, textColor: AppColors.whiteColor, deleteIcon: AppAssets.close_bottom_sheet_icon, deleteIconColor: AppColors.whiteColor, deleteIconHasColor: true, onDeleteTap: () { selectedFilterText = ""; labProvider.filterLabReports(""); }, ), SizedBox(height: 8.h), ], ) : SizedBox(), activeIndex == 0 ? // By Visit - show grouped view when available labViewModel.isLabOrdersLoading ? ListView.builder( shrinkWrap: true, physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: 5, itemBuilder: (context, index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, ), ) : (labViewModel.patientLabOrders.isNotEmpty ? ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: labViewModel.patientLabOrders.length, itemBuilder: (context, index) { final group = labViewModel.patientLabOrders[index]; final isExpanded = expandedIndex == index; return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), child: InkWell( onTap: () { setState(() { expandedIndex = isExpanded ? null : index; }); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ AppCustomChipWidget( labelText: "${group.testDetails!.length} ${LocaleKeys.tests.tr(context: context)}", backgroundColor: AppColors.successColor.withOpacity(0.1), textColor: AppColors.successColor, ), AppCustomChipWidget( labelText: "${_appState.isArabic() ? group.isInOutPatientDescriptionN : group.isInOutPatientDescription}", backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), textColor: AppColors.warningColorYellow, ) ], ), Icon(isExpanded ? Icons.expand_less : Icons.expand_more), ], ), SizedBox(height: 8.h), Row( mainAxisSize: MainAxisSize.min, children: [ Image.network( group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", width: 24.w, height: 24.h, fit: BoxFit.cover, ).circle(100), SizedBox(width: 8.h), Expanded(child: (group.doctorName ?? group.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), ], ), SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ Directionality( textDirection: ui.TextDirection.ltr, child: AppCustomChipWidget( labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(group.orderDate ?? ""), false), isEnglishOnly: true, )), AppCustomChipWidget( labelText: (group.projectName ?? ""), ), AppCustomChipWidget( labelText: (group.clinicDescription ?? ""), ), ], ), ], ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), switchInCurve: Curves.easeIn, switchOutCurve: Curves.easeOut, transitionBuilder: (Widget child, Animation animation) { return FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: 0.0, child: child, ), ); }, child: isExpanded ? Container( key: ValueKey(index), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 0.h), child: Column( children: [ ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (cxt, index) { PatientLabOrdersResponseModel order = group; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "• ${order.testDetails![index].description!}".toText14(weight: FontWeight.w500), SizedBox(height: 4.h), order.testDetails![index].testDescriptionEn!.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), // Row( // mainAxisSize: MainAxisSize.min, // children: [ // Image.network( // order.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", // width: 24.w, // height: 24.h, // fit: BoxFit.cover, // ).circle(100), // SizedBox(width: 8.h), // Expanded(child: (order.doctorName ?? order.doctorNameEnglish ?? "").toString().toText14(weight: FontWeight.w500)), // ], // ), // SizedBox(height: 8.h), // Wrap( // direction: Axis.horizontal, // spacing: 4.h, // runSpacing: 4.h, // children: [ // AppCustomChipWidget( // labelText: ("${LocaleKeys.orderNo.tr(context: context)}: ${order.orderNo!}"), isEnglishOnly: true, // ), // Directionality( // textDirection: ui.TextDirection.ltr, // child: AppCustomChipWidget( // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // isEnglishOnly: true, // )), // AppCustomChipWidget( // labelText: labViewModel.isSortByClinic ? (order.projectName ?? "") : (order.clinicDescription ?? ""), // ), // ], // ), // // Row( // // children: [ // // CustomButton( // // text: ("Order No: ".needTranslation + order.orderNo!), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // SizedBox(width: 8.h), // // CustomButton( // // text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(order.orderDate ?? ""), false), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // // SizedBox(height: 8.h), // // Row( // // children: [ // // CustomButton( // // text: model.isSortByClinic ? (order.clinicDescription ?? "") : (order.projectName ?? ""), // // onPressed: () {}, // // backgroundColor: AppColors.greyColor, // // borderColor: AppColors.greyColor, // // textColor: AppColors.blackColor, // // fontSize: 10, // // fontWeight: FontWeight.w500, // // borderRadius: 8, // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // // height: 24.h, // // ), // // ], // // ), // SizedBox(height: 12.h), // Row( // children: [ // Expanded(flex: 2, child: SizedBox()), // // Expanded( // // flex: 1, // // child: Container( // // height: 40.h, // // width: 40.w, // // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // // color: AppColors.textColor, // // borderRadius: 12, // // ), // // child: Padding( // // padding: EdgeInsets.all(12.h), // // child: Transform.flip( // // flipX: _appState.isArabic(), // // child: Utils.buildSvgWithAssets( // // icon: AppAssets.forward_arrow_icon_small, // // iconColor: AppColors.whiteColor, // // fit: BoxFit.contain, // // ), // // ), // // ), // // ).onPress(() { // // model.currentlySelectedPatientOrder = order; // // labProvider.getPatientLabResultByHospital(order); // // labProvider.getPatientSpecialResult(order); // // Navigator.of(context).push( // // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // // ); // // }), // // ) // // Expanded( // flex: 2, // child: CustomButton( // icon: AppAssets.view_report_icon, // iconColor: AppColors.primaryRedColor, // iconSize: 16.h, // text: LocaleKeys.viewResults.tr(context: context), // onPressed: () { // labViewModel.currentlySelectedPatientOrder = order; // labProvider.getPatientLabResultByHospital(order); // labProvider.getPatientSpecialResult(order); // Navigator.of(context).push( // CustomPageRoute(page: LabResultByClinic(labOrder: order)), // ); // }, // backgroundColor: AppColors.secondaryLightRedColor, // borderColor: AppColors.secondaryLightRedColor, // textColor: AppColors.primaryRedColor, // fontSize: 14, // fontWeight: FontWeight.w500, // borderRadius: 12, // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // height: 40.h, // ), // ) // ], // ), // SizedBox(height: 12.h), // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), // SizedBox(height: 12.h), ], ).paddingOnly(top: 16, bottom: 16); }, separatorBuilder: (cxt, index) => Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), itemCount: group.testDetails!.length > 3 ? 3 : group.testDetails!.length), SizedBox(height: 16.h), CustomButton( text: "${LocaleKeys.viewResults.tr()} (${group.testDetails!.length})", onPressed: () { labProvider.currentlySelectedPatientOrder = group; labProvider.getPatientLabResultByHospital(group); labProvider.getPatientSpecialResult(group); Navigator.of(context).push( CustomPageRoute( page: LabResultByClinic(labOrder: group), ), ); }, backgroundColor: AppColors.infoColor.withAlpha(20), borderColor: AppColors.infoColor.withAlpha(0), textColor: AppColors.infoColor, fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontWeight: FontWeight.w500, borderRadius: 12.r, padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), height: 40.h, iconSize: 14.h, icon: AppAssets.view_report_icon, iconColor: AppColors.infoColor, ), SizedBox(height: 16.h), ], ), ) : SizedBox.shrink(), ), ], ), ), ), ), )); }, ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.noLabResults.tr(context: context))) : // By Test or other tabs keep existing behavior (labViewModel.isLabOrdersLoading) ? Column( children: List.generate( 5, (index) => LabResultItemView( onTap: () {}, labOrder: null, index: index, isLoading: true, )), ) : AlphabeticScroll( alpahbetsAvailable: labViewModel.indexedCharacterForUniqueTest, details: labViewModel.uniqueTestsList, labViewModel: labViewModel, rangeViewModel: rangeViewModel, appState: _appState, ) ], )); }, ), ); } Color getLabOrderStatusColor(num status) { switch (status) { case 44: return AppColors.warningColorYellow; case 45: return AppColors.warningColorYellow; case 16: return AppColors.successColor; case 17: return AppColors.successColor; default: return AppColors.greyColor; } } String getLabOrderStatusText(num status) { switch (status) { case 44: return LocaleKeys.resultsPending.tr(context: context); case 45: return LocaleKeys.resultsPending.tr(context: context); case 16: return LocaleKeys.resultsAvailable.tr(context: context); case 17: return LocaleKeys.resultsAvailable.tr(context: context); default: return ""; } } getLabSuggestions(LabViewModel model) { if (model.patientLabOrders.isEmpty) { return []; } return model.patientLabOrders.map((m) => m.testDetails).toList(); } } \ No newline at end of file diff --git a/lib/presentation/medical_file/patient_sickleaves_list_page.dart b/lib/presentation/medical_file/patient_sickleaves_list_page.dart index 93cf17ff..4518eca5 100644 --- a/lib/presentation/medical_file/patient_sickleaves_list_page.dart +++ b/lib/presentation/medical_file/patient_sickleaves_list_page.dart @@ -57,48 +57,48 @@ class _PatientSickleavesListPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 16.h), + // SizedBox(height: 16.h), // Clinic & Hospital Sort - Row( - children: [ - CustomButton( - text: LocaleKeys.byClinic.tr(context: context), - onPressed: () { - model.setIsSickLeavesSortByClinic(true); - }, - backgroundColor: model.isSickLeavesSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, - borderColor: model.isSickLeavesSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), - textColor: model.isSickLeavesSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 10, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - ), - SizedBox(width: 8.h), - CustomButton( - text: LocaleKeys.byHospital.tr(context: context), - onPressed: () { - model.setIsSickLeavesSortByClinic(false); - }, - backgroundColor: model.isSickLeavesSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, - borderColor: model.isSickLeavesSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, - textColor: model.isSickLeavesSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 10, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - ), - ], - ).paddingSymmetrical(24.h, 0.h), - SizedBox(height: 20.h), + // Row( + // children: [ + // CustomButton( + // text: LocaleKeys.byClinic.tr(context: context), + // onPressed: () { + // model.setIsSickLeavesSortByClinic(true); + // }, + // backgroundColor: model.isSickLeavesSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor, + // borderColor: model.isSickLeavesSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), + // textColor: model.isSickLeavesSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, + // fontSize: 12, + // fontWeight: FontWeight.w500, + // borderRadius: 10, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // ), + // SizedBox(width: 8.h), + // CustomButton( + // text: LocaleKeys.byHospital.tr(context: context), + // onPressed: () { + // model.setIsSickLeavesSortByClinic(false); + // }, + // backgroundColor: model.isSickLeavesSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor, + // borderColor: model.isSickLeavesSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, + // textColor: model.isSickLeavesSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, + // fontSize: 12, + // fontWeight: FontWeight.w500, + // borderRadius: 10, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // ), + // ], + // ).paddingSymmetrical(24.h, 0.h), + // SizedBox(height: 20.h), // Expandable list ListView.builder( itemCount: model.isPatientSickLeaveListLoading ? 4 : model.patientSickLeaveList.isNotEmpty - ? model.patientSickLeavesViewList.length + ? model.patientSickLeaveList.length : 1, physics: NeverScrollableScrollPhysics(), shrinkWrap: true, @@ -122,155 +122,322 @@ class _PatientSickleavesListPageState extends State { curve: Curves.easeInOut, margin: EdgeInsets.symmetric(vertical: 8.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), - child: InkWell( - onTap: () { - setState(() { - expandedIndex = isExpanded ? null : index; - }); - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.all(16.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 16.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppCustomChipWidget( + labelText: + "${getIt.get().isArabic() ? model.patientSickLeaveList[index].isInOutPatientDescriptionN : model.patientSickLeaveList[index].isInOutPatientDescription}", + backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), + textColor: AppColors.warningColorYellow, + ), + SizedBox(height: 16.h), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Image.network( + model.patientSickLeaveList[index].doctorImageURL!, + width: 24.h, + height: 24.h, + fit: BoxFit.fill, + ).circle(100), + SizedBox(width: 8.h), + Expanded(child: model.patientSickLeaveList[index].doctorName!.toText14(weight: FontWeight.w500)), + ], + ), + SizedBox(height: 8.h), + Wrap( + direction: Axis.horizontal, + spacing: 6.h, + runSpacing: 6.h, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CustomButton( - text: "${model.patientSickLeavesViewList[index].sickLeavesList!.length} ${LocaleKeys.sickSubtitle.tr(context: context)} Available", - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.w500, - borderRadius: 8, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 30.h, - ), - Icon(isExpanded ? Icons.expand_less : Icons.expand_more), - ], + AppCustomChipWidget( + labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientSickLeaveList[index].appointmentDate), false), + ), + AppCustomChipWidget( + labelText: model.isSickLeavesSortByClinic ? model.patientSickLeaveList[index].projectName! : model.patientSickLeaveList[index].clinicName!, + ), + AppCustomChipWidget( + labelText: "${model.patientSickLeaveList[index].sickLeaveDays} Days", ), - SizedBox(height: 8.h), - model.patientSickLeavesViewList[index].filterName!.toText16(isBold: true) ], ), - ), - AnimatedSwitcher( - duration: Duration(milliseconds: 500), - switchInCurve: Curves.easeIn, - switchOutCurve: Curves.easeOut, - transitionBuilder: (Widget child, Animation animation) { - return FadeTransition( - opacity: animation, - child: SizeTransition( - sizeFactor: animation, - axisAlignment: 0.0, - child: child, + SizedBox(height: 12.h), + Row( + children: [ + Expanded( + flex: 6, + child: CustomButton( + text: LocaleKeys.downloadReport.tr(context: context), + onPressed: () async { + LoaderBottomSheet.showLoader(); + await medicalFileViewModel.getPatientSickLeavePDF(model.patientSickLeaveList[index], appState.getAuthenticatedUser()!).then((val) async { + LoaderBottomSheet.hideLoader(); + if (medicalFileViewModel.patientSickLeavePDFBase64.isNotEmpty) { + String path = await Utils.createFileFromString(medicalFileViewModel.patientSickLeavePDFBase64, "pdf"); + try { + OpenFilex.open(path); + } catch (ex) { + debugPrint("Error opening file: $ex"); + } + } + }); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + icon: AppAssets.download, + iconColor: AppColors.primaryRedColor, + iconSize: 14.h, + ), ), - ); - }, - child: isExpanded - ? Container( - key: ValueKey(index), - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...model.patientSickLeavesViewList[index].sickLeavesList!.map((sickLeave) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.network( - sickLeave.doctorImageURL!, - width: 24.h, - height: 24.h, - fit: BoxFit.fill, - ).circle(100), - SizedBox(width: 8.h), - Expanded(child: sickLeave.doctorName!.toText14(weight: FontWeight.w500)), - ], - ), - SizedBox(height: 8.h), - Wrap( - direction: Axis.horizontal, - spacing: 6.h, - runSpacing: 6.h, - children: [ - AppCustomChipWidget( - labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(sickLeave.appointmentDate), false), - ), - AppCustomChipWidget( - labelText: model.isSickLeavesSortByClinic ? sickLeave.projectName! : sickLeave.clinicName!, - ), - AppCustomChipWidget( - labelText: "${sickLeave.sickLeaveDays} Days", - ), - ], - ), - SizedBox(height: 12.h), - Row( - children: [ - Expanded( - flex: 6, - child: CustomButton( - text: LocaleKeys.downloadReport.tr(context: context), - onPressed: () async { - LoaderBottomSheet.showLoader(); - await medicalFileViewModel.getPatientSickLeavePDF(sickLeave, appState.getAuthenticatedUser()!).then((val) async { - LoaderBottomSheet.hideLoader(); - if (medicalFileViewModel.patientSickLeavePDFBase64.isNotEmpty) { - String path = await Utils.createFileFromString(medicalFileViewModel.patientSickLeavePDFBase64, "pdf"); - try { - OpenFilex.open(path); - } catch (ex) { - debugPrint("Error opening file: $ex"); - } - } - }); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - icon: AppAssets.download, - iconColor: AppColors.primaryRedColor, - iconSize: 14.h, - ), - ), - ], - ), - SizedBox(height: 12.h), - Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), - SizedBox(height: 12.h), - ], - ); - }), - ], - ), - ) - : SizedBox.shrink(), - ), - ], + ], + ), + // SizedBox(height: 12.h), + // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), + // SizedBox(height: 12.h), + ], + ), + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // ...model.patientSickLeaveList[index].sickLeavesList!.map((sickLeave) { + // return Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Image.network( + // sickLeave.doctorImageURL!, + // width: 24.h, + // height: 24.h, + // fit: BoxFit.fill, + // ).circle(100), + // SizedBox(width: 8.h), + // Expanded(child: sickLeave.doctorName!.toText14(weight: FontWeight.w500)), + // ], + // ), + // SizedBox(height: 8.h), + // Wrap( + // direction: Axis.horizontal, + // spacing: 6.h, + // runSpacing: 6.h, + // children: [ + // AppCustomChipWidget( + // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(sickLeave.appointmentDate), false), + // ), + // AppCustomChipWidget( + // labelText: model.isSickLeavesSortByClinic ? sickLeave.projectName! : sickLeave.clinicName!, + // ), + // AppCustomChipWidget( + // labelText: "${sickLeave.sickLeaveDays} Days", + // ), + // ], + // ), + // SizedBox(height: 12.h), + // Row( + // children: [ + // Expanded( + // flex: 6, + // child: CustomButton( + // text: LocaleKeys.downloadReport.tr(context: context), + // onPressed: () async { + // LoaderBottomSheet.showLoader(); + // await medicalFileViewModel.getPatientSickLeavePDF(sickLeave, appState.getAuthenticatedUser()!).then((val) async { + // LoaderBottomSheet.hideLoader(); + // if (medicalFileViewModel.patientSickLeavePDFBase64.isNotEmpty) { + // String path = await Utils.createFileFromString(medicalFileViewModel.patientSickLeavePDFBase64, "pdf"); + // try { + // OpenFilex.open(path); + // } catch (ex) { + // debugPrint("Error opening file: $ex"); + // } + // } + // }); + // }, + // backgroundColor: AppColors.secondaryLightRedColor, + // borderColor: AppColors.secondaryLightRedColor, + // textColor: AppColors.primaryRedColor, + // fontSize: 14, + // fontWeight: FontWeight.w500, + // borderRadius: 12, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40.h, + // icon: AppAssets.download, + // iconColor: AppColors.primaryRedColor, + // iconSize: 14.h, + // ), + // ), + // ], + // ), + // SizedBox(height: 12.h), + // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), + // SizedBox(height: 12.h), + // ], + // ); + // }), + // ], + // ), + ) + // InkWell( + // onTap: () { + // setState(() { + // expandedIndex = isExpanded ? null : index; + // }); + // }, + // child: + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Padding( + // padding: EdgeInsets.all(16.h), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // CustomButton( + // text: "${model.patientSickLeavesViewList[index].sickLeavesList!.length} ${LocaleKeys.sickSubtitle.tr(context: context)} Available", + // onPressed: () {}, + // backgroundColor: AppColors.greyColor, + // borderColor: AppColors.greyColor, + // textColor: AppColors.blackColor, + // fontSize: 10, + // fontWeight: FontWeight.w500, + // borderRadius: 8, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 30.h, + // ), + // Icon(isExpanded ? Icons.expand_less : Icons.expand_more), + // ], + // ), + // SizedBox(height: 8.h), + // model.patientSickLeavesViewList[index].filterName!.toText16(isBold: true) + // ], + // ), + // ), + // // AnimatedSwitcher( + // // duration: Duration(milliseconds: 500), + // // switchInCurve: Curves.easeIn, + // // switchOutCurve: Curves.easeOut, + // // transitionBuilder: (Widget child, Animation animation) { + // // return FadeTransition( + // // opacity: animation, + // // child: SizeTransition( + // // sizeFactor: animation, + // // axisAlignment: 0.0, + // // child: child, + // // ), + // // ); + // // }, + // // child: isExpanded + // // ? Container( + // // key: ValueKey(index), + // // padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), + // // child: Column( + // // crossAxisAlignment: CrossAxisAlignment.start, + // // children: [ + // // ...model.patientSickLeavesViewList[index].sickLeavesList!.map((sickLeave) { + // // return Column( + // // crossAxisAlignment: CrossAxisAlignment.start, + // // children: [ + // // Row( + // // mainAxisSize: MainAxisSize.min, + // // children: [ + // // Image.network( + // // sickLeave.doctorImageURL!, + // // width: 24.h, + // // height: 24.h, + // // fit: BoxFit.fill, + // // ).circle(100), + // // SizedBox(width: 8.h), + // // Expanded(child: sickLeave.doctorName!.toText14(weight: FontWeight.w500)), + // // ], + // // ), + // // SizedBox(height: 8.h), + // // Wrap( + // // direction: Axis.horizontal, + // // spacing: 6.h, + // // runSpacing: 6.h, + // // children: [ + // // AppCustomChipWidget( + // // labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(sickLeave.appointmentDate), false), + // // ), + // // AppCustomChipWidget( + // // labelText: model.isSickLeavesSortByClinic ? sickLeave.projectName! : sickLeave.clinicName!, + // // ), + // // AppCustomChipWidget( + // // labelText: "${sickLeave.sickLeaveDays} Days", + // // ), + // // ], + // // ), + // // SizedBox(height: 12.h), + // // Row( + // // children: [ + // // Expanded( + // // flex: 6, + // // child: CustomButton( + // // text: LocaleKeys.downloadReport.tr(context: context), + // // onPressed: () async { + // // LoaderBottomSheet.showLoader(); + // // await medicalFileViewModel.getPatientSickLeavePDF(sickLeave, appState.getAuthenticatedUser()!).then((val) async { + // // LoaderBottomSheet.hideLoader(); + // // if (medicalFileViewModel.patientSickLeavePDFBase64.isNotEmpty) { + // // String path = await Utils.createFileFromString(medicalFileViewModel.patientSickLeavePDFBase64, "pdf"); + // // try { + // // OpenFilex.open(path); + // // } catch (ex) { + // // debugPrint("Error opening file: $ex"); + // // } + // // } + // // }); + // // }, + // // backgroundColor: AppColors.secondaryLightRedColor, + // // borderColor: AppColors.secondaryLightRedColor, + // // textColor: AppColors.primaryRedColor, + // // fontSize: 14, + // // fontWeight: FontWeight.w500, + // // borderRadius: 12, + // // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // // height: 40.h, + // // icon: AppAssets.download, + // // iconColor: AppColors.primaryRedColor, + // // iconSize: 14.h, + // // ), + // // ), + // // ], + // // ), + // // SizedBox(height: 12.h), + // // Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h), + // // SizedBox(height: 12.h), + // // ], + // // ); + // // }), + // // ], + // // ), + // // ) + // // : SizedBox.shrink(), + // // ), + // ], + // ), + // ), ), - ), - ), ), ), ) : Utils.getNoDataWidget(context, noDataText: LocaleKeys.youDontHaveAnySickLeavesYet.tr(context: context)); }, ).paddingSymmetrical(24.h, 0.h), + SizedBox(height: 24.h), ], ); }), diff --git a/lib/presentation/my_invoices/my_invoices_details_page.dart b/lib/presentation/my_invoices/my_invoices_details_page.dart index a38194fe..79e1adc3 100644 --- a/lib/presentation/my_invoices/my_invoices_details_page.dart +++ b/lib/presentation/my_invoices/my_invoices_details_page.dart @@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoice_details_response_model.dart'; +import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart'; import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; @@ -20,8 +21,9 @@ import 'package:provider/provider.dart'; class MyInvoicesDetailsPage extends StatefulWidget { GetInvoiceDetailsResponseModel getInvoiceDetailsResponseModel; + GetInvoicesListResponseModel getInvoicesListResponseModel; - MyInvoicesDetailsPage({super.key, required this.getInvoiceDetailsResponseModel}); + MyInvoicesDetailsPage({super.key, required this.getInvoiceDetailsResponseModel, required this.getInvoicesListResponseModel}); @override State createState() => _MyInvoicesDetailsPageState(); @@ -82,6 +84,26 @@ class _MyInvoicesDetailsPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Wrap( + alignment: WrapAlignment.start, + direction: Axis.horizontal, + spacing: 6.w, + runSpacing: 6.h, + children: [ + AppCustomChipWidget( + icon: AppAssets.walkin_appointment_icon, + iconColor: AppColors.textColor, + labelText: LocaleKeys.walkin.tr(context: context), + textColor: AppColors.textColor, + ), + AppCustomChipWidget( + labelText: LocaleKeys.outPatient.tr(context: context), + backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.1), + textColor: AppColors.warningColorYellow, + ), + ], + ), + SizedBox(height: 16.h), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -93,6 +115,29 @@ class _MyInvoicesDetailsPageState extends State { height: 63.h, fit: BoxFit.cover, ).circle(100.r), + Transform.translate( + offset: Offset(0.0, -20.h), + child: Container( + width: 40.w, + height: 40.h, + decoration: BoxDecoration( + color: AppColors.whiteColor, + shape: BoxShape.circle, // Makes the container circular + border: Border.all( + color: AppColors.scaffoldBgColor, // Color of the border + width: 1.5.w, // Width of the border + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h, applyThemeColor: false), + SizedBox(height: 2.h), + "${widget.getInvoicesListResponseModel.decimalDoctorRate}".toText11(isBold: true, color: AppColors.textColor), + ], + ), + ).circle(100), + ), ], ), SizedBox(width: 16.w), @@ -138,41 +183,46 @@ class _MyInvoicesDetailsPageState extends State { ), ), SizedBox(height: 16.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.h, - hasShadow: true, - ), - child: Padding( - padding: EdgeInsets.all(14.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - widget.getInvoiceDetailsResponseModel.listConsultation!.first.procedureName!.toText16(isBold: true), - SizedBox(height: 16.h), - Wrap( - direction: Axis.horizontal, - spacing: 6.w, - runSpacing: 6.h, + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: true, + ), + child: Padding( + padding: EdgeInsets.all(14.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - AppCustomChipWidget( - labelText: "${LocaleKeys.quantity.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.quantity!}", - labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w), - ), - AppCustomChipWidget( - labelText: "${LocaleKeys.price.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.price!} ${LocaleKeys.sar.tr()}", - labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w), - ), - AppCustomChipWidget( - labelText: "${LocaleKeys.total.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.total!} ${LocaleKeys.sar.tr()}", - labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w), + widget.getInvoiceDetailsResponseModel.listConsultation!.first.procedureName!.toText16(isBold: true), + SizedBox(height: 16.h), + Wrap( + direction: Axis.horizontal, + spacing: 6.w, + runSpacing: 6.h, + children: [ + AppCustomChipWidget( + labelText: "${LocaleKeys.quantity.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.quantity!}", + labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w), + ), + AppCustomChipWidget( + labelText: "${LocaleKeys.price.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.price!} ${LocaleKeys.sar.tr()}", + labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w), + ), + AppCustomChipWidget( + labelText: "${LocaleKeys.total.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.total!} ${LocaleKeys.sar.tr()}", + labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w), + ), + ], ), ], ), - ], + ), ), - ), + ], ), SizedBox(height: 16.h), Container( diff --git a/lib/presentation/my_invoices/my_invoices_list.dart b/lib/presentation/my_invoices/my_invoices_list.dart index 177dde84..dddb0a15 100644 --- a/lib/presentation/my_invoices/my_invoices_list.dart +++ b/lib/presentation/my_invoices/my_invoices_list.dart @@ -86,7 +86,7 @@ class _MyInvoicesListState extends State { LoaderBottomSheet.hideLoader(); Navigator.of(context).push( CustomPageRoute( - page: MyInvoicesDetailsPage(getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel), + page: MyInvoicesDetailsPage(getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel, getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],), ), ); }, diff --git a/lib/presentation/my_invoices/widgets/invoice_list_card.dart b/lib/presentation/my_invoices/widgets/invoice_list_card.dart index 6e0fa0e4..e5ae7de8 100644 --- a/lib/presentation/my_invoices/widgets/invoice_list_card.dart +++ b/lib/presentation/my_invoices/widgets/invoice_list_card.dart @@ -47,8 +47,8 @@ class InvoiceListCard extends StatelessWidget { ), AppCustomChipWidget( labelText: LocaleKeys.outPatient.tr(context: context), - backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1), - textColor: AppColors.primaryRedColor, + backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.1), + textColor: AppColors.warningColorYellow, ), ], ), diff --git a/lib/presentation/prescriptions/prescription_detail_page.dart b/lib/presentation/prescriptions/prescription_detail_page.dart index 235ad554..0ac9ce40 100644 --- a/lib/presentation/prescriptions/prescription_detail_page.dart +++ b/lib/presentation/prescriptions/prescription_detail_page.dart @@ -114,8 +114,8 @@ class _PrescriptionDetailPageState extends State { AppCustomChipWidget( labelText: "${getIt.get().isArabic() ? widget.prescriptionsResponseModel.isInOutPatientDescriptionN : widget.prescriptionsResponseModel.isInOutPatientDescription}", - backgroundColor: widget.prescriptionsResponseModel.isInOutPatient! ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.warningColorYellow.withOpacity(0.1), - textColor: widget.prescriptionsResponseModel.isInOutPatient! ? AppColors.primaryRedColor : AppColors.warningColorYellow, + backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), + textColor: AppColors.warningColorYellow, ), SizedBox(height: 16.h), Row( diff --git a/lib/presentation/prescriptions/prescription_item_view.dart b/lib/presentation/prescriptions/prescription_item_view.dart index 2b19e3a4..7f969b21 100644 --- a/lib/presentation/prescriptions/prescription_item_view.dart +++ b/lib/presentation/prescriptions/prescription_item_view.dart @@ -103,14 +103,13 @@ class PrescriptionItemView extends StatelessWidget { Switch( activeColor: AppColors.successColor, activeTrackColor: AppColors.successColor.withValues(alpha: .15), - // value: isLoading ? false : prescriptionVM.prescriptionDetailsList[index].hasReminder!, - value: prescriptionVM.prescriptionDetailsList[index].hasReminder!, + value: isLoading ? false : prescriptionVM.prescriptionDetailsList[index].hasReminder!, + // value: prescriptionVM.prescriptionDetailsList[index].hasReminder ?? false, onChanged: (newValue) async { CalenderUtilsNew calender = CalenderUtilsNew.instance; if (await prescriptionVM.checkIfReminderExistForPrescription(index)) { prescriptionVM.prescriptionDetailsList[index].hasReminder = true; - } else { if (prescriptionVM.prescriptionDetailsList[index].hasReminder ?? false) { LoaderBottomSheet.showLoader(loadingText: "Removing Reminders"); bool resultValue = await calender.checkAndRemoveMultipleItems(id: prescriptionVM.prescriptionDetailsList[index].itemID.toString()); @@ -119,7 +118,7 @@ class PrescriptionItemView extends StatelessWidget { LoaderBottomSheet.hideLoader(); return; } - + } else { DateTime startDate = DateTime.now(); DateTime endDate = DateTime(startDate.year, startDate.month, startDate.day + prescriptionVM.prescriptionDetailsList[index].days!.toInt()); BottomSheetUtils().showReminderBottomSheet( diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart index da211f9d..3a54926f 100644 --- a/lib/presentation/prescriptions/prescriptions_list_page.dart +++ b/lib/presentation/prescriptions/prescriptions_list_page.dart @@ -143,9 +143,8 @@ class _PrescriptionsListPageState extends State { AppCustomChipWidget( labelText: "${getIt.get().isArabic() ? model.patientPrescriptionOrders[index].isInOutPatientDescriptionN : model.patientPrescriptionOrders[index].isInOutPatientDescription}", - backgroundColor: - model.patientPrescriptionOrders[index].isInOutPatient! ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.warningColorYellow.withOpacity(0.1), - textColor: model.patientPrescriptionOrders[index].isInOutPatient! ? AppColors.primaryRedColor : AppColors.warningColorYellow, + backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), + textColor: AppColors.warningColorYellow, ), SizedBox(height: 16.h), Row( diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart index e24c3472..1a3ab448 100644 --- a/lib/presentation/radiology/radiology_orders_page.dart +++ b/lib/presentation/radiology/radiology_orders_page.dart @@ -169,7 +169,7 @@ class _RadiologyOrdersPageState extends State { ); } - if (model.patientRadiologyOrdersViewList.isEmpty) { + if (model.patientRadiologyOrders.isEmpty) { return Utils.getNoDataWidget(ctx, noDataText: LocaleKeys.youDontHaveRadiologyOrders.tr(context: context)); } @@ -393,8 +393,8 @@ class _RadiologyOrdersPageState extends State { children: [ AppCustomChipWidget( labelText: "${getIt.get().isArabic() ? group.isInOutPatientDescriptionN : group.isInOutPatientDescription}", - backgroundColor: group.isInOutPatient! ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.warningColorYellow.withOpacity(0.1), - textColor: group.isInOutPatient! ? AppColors.primaryRedColor : AppColors.warningColorYellow, + backgroundColor: AppColors.warningColorYellow.withOpacity(0.1), + textColor: AppColors.warningColorYellow, ), SizedBox(height: 16.h), Row( From 6a4793f122416dc9caf15f7803538b712eb795d5 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 30 Mar 2026 17:02:14 +0300 Subject: [PATCH 31/33] Updates --- ios/Runner.xcodeproj/project.pbxproj | 17 ++++++----------- ios/Runner/Info.plist | 2 +- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 6a81b151..9f1f6de9 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -343,14 +343,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; @@ -364,14 +360,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; @@ -531,10 +523,11 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 14; + CURRENT_PROJECT_VERSION = 15; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Dr. Alhabib"; IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -717,10 +710,11 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 14; + CURRENT_PROJECT_VERSION = 15; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Dr. Alhabib"; IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -746,10 +740,11 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 14; + CURRENT_PROJECT_VERSION = 15; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Dr. Alhabib"; IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index f412b006..bbe54c9a 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -13,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - Dr. Alhabib Beta + Dr. Alhabib CFBundlePackageType APPL CFBundleShortVersionString From f1555c76a37ee42cf4f07c3fd679ec335bece5ea Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Tue, 31 Mar 2026 10:48:25 +0300 Subject: [PATCH 32/33] Invoices Filter --- assets/langs/ar-SA.json | 5 + assets/langs/en-US.json | 5 + .../authentication/authentication_repo.dart | 6 + .../my_invoices/my_invoices_view_model.dart | 141 ++++++++++- lib/generated/locale_keys.g.dart | 5 + .../my_invoices/my_invoices_list.dart | 239 ++++++++++++++---- .../widgets/invoice_filter_bottom_sheet.dart | 133 ++++++++++ 7 files changed, 484 insertions(+), 50 deletions(-) create mode 100644 lib/presentation/my_invoices/widgets/invoice_filter_bottom_sheet.dart diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index b78b8545..765abc78 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -752,6 +752,11 @@ "erConsultation": "تتيح لك هذه الخدمة إجراء استشارة افتراضية عبر الإنترنت عبر مكالمة فيديو مباشرة مع الطبيب من أي مكان وفي أي وقت.", "myInvoice": "القائمة", "invoiceList": "فواتيري", + "allInvoices": "كل الفواتير", + "hospitals": "المستشفيات", + "clinics": "العيادات", + "doctors": "الأطباء", + "selectDoctor": "اختر الطبيب", "thisItemIsNotAvailable": "هذا العنصر غير متوفر", "beforeAfterImages": "صور قبل وبعد", "clinicAcceptLivecare": "لا حاجة للانتظار أو الزيارة يمكنك الآن الحصول على استشارة طبية عبر مكالمة فيديو (لايف كير) في اسم العيادة وسيتصل بك الطبيب على الفور", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index cbea7b94..b0dd38ad 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -744,6 +744,11 @@ "erConsultation": "This service allows you to make an online virtual consultation via video call directly with the doctor from anywhere at any time.", "myInvoice": "List", "invoiceList": "My Invoice", + "allInvoices": "All Invoices", + "hospitals": "Hospitals", + "clinics": "Clinics", + "doctors": "Doctors", + "selectDoctor": "Select Doctor", "thisItemIsNotAvailable": "This item is not available", "beforeAfterImages": "Before & After Images", "clinicAcceptLivecare": "No need to wait or visit You can now get medical consultation via Video call (LiveCare service) in The name of the clinic clinic and the doctor will contact you immediately", diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index f3b14c67..4fc8883f 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -315,7 +315,13 @@ class AuthenticationRepoImp implements AuthenticationRepo { } if (appState.getSuperUserID == responseID) { + // switchRequest['LoginType'] = 0; switchRequest['PatientIdentificationID'] = ""; + // switchRequest["PatientID"] = responseID; + // switchRequest["SuperUser"] = responseID; + // switchRequest["PatientID"] = appState.getAuthenticatedUser()?.patientId ?? 0; + + // switchRequest["PatientMobileNumber"] = newRequest.patientMobileNumber?.toString().startsWith('0') == true ? newRequest.patientMobileNumber.toString() : '0${newRequest.patientMobileNumber}'; switchRequest.removeWhere((key, value) => ['NationalID', 'isDentalAllowedBackend', 'ProjectOutSA', 'ForRegisteration'].contains(key)); } } diff --git a/lib/features/my_invoices/my_invoices_view_model.dart b/lib/features/my_invoices/my_invoices_view_model.dart index f3c716ae..d51ea086 100644 --- a/lib/features/my_invoices/my_invoices_view_model.dart +++ b/lib/features/my_invoices/my_invoices_view_model.dart @@ -5,6 +5,8 @@ import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; +enum InvoiceFilterType { all, hospital, clinic, doctor } + class MyInvoicesViewModel extends ChangeNotifier { bool isInvoicesListLoading = false; bool isInvoiceDetailsLoading = false; @@ -14,13 +16,23 @@ class MyInvoicesViewModel extends ChangeNotifier { NavigationService navServices; List allInvoicesList = []; + List _originalInvoicesList = []; + InvoiceFilterType currentFilter = InvoiceFilterType.all; late GetInvoiceDetailsResponseModel invoiceDetailsResponseModel; + // Filter bottom sheet properties + List filterDisplayList = []; + List _filterOriginalList = []; + TextEditingController filterSearchController = TextEditingController(); + String? selectedFilterItem; + MyInvoicesViewModel({required this.myInvoicesRepo, required this.errorHandlerService, required this.navServices}); setInvoicesListLoading() { isInvoicesListLoading = true; allInvoicesList.clear(); + _originalInvoicesList.clear(); + currentFilter = InvoiceFilterType.all; notifyListeners(); } @@ -41,9 +53,10 @@ class MyInvoicesViewModel extends ChangeNotifier { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { - allInvoicesList = apiResponse.data!; + _originalInvoicesList = apiResponse.data!; + _originalInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!)); + allInvoicesList = List.from(_originalInvoicesList); isInvoicesListLoading = false; - allInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!)); notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); @@ -99,4 +112,128 @@ class MyInvoicesViewModel extends ChangeNotifier { }, ); } + + void filterInvoices(InvoiceFilterType filterType) { + currentFilter = filterType; + + switch (filterType) { + case InvoiceFilterType.all: + allInvoicesList = List.from(_originalInvoicesList); + break; + case InvoiceFilterType.hospital: + allInvoicesList = _originalInvoicesList.where((invoice) { + return invoice.projectName != null && invoice.projectName!.isNotEmpty; + }).toList(); + // Group by hospital (projectName) and sort + allInvoicesList.sort((a, b) { + int projectComparison = (a.projectName ?? '').compareTo(b.projectName ?? ''); + if (projectComparison != 0) return projectComparison; + return b.appointmentDate!.compareTo(a.appointmentDate!); + }); + break; + case InvoiceFilterType.clinic: + allInvoicesList = _originalInvoicesList.where((invoice) { + return invoice.clinicName != null && invoice.clinicName!.isNotEmpty; + }).toList(); + // Group by clinic (clinicName) and sort + allInvoicesList.sort((a, b) { + int clinicComparison = (a.clinicName ?? '').compareTo(b.clinicName ?? ''); + if (clinicComparison != 0) return clinicComparison; + return b.appointmentDate!.compareTo(a.appointmentDate!); + }); + break; + case InvoiceFilterType.doctor: + allInvoicesList = _originalInvoicesList.where((invoice) { + return invoice.doctorName != null && invoice.doctorName!.isNotEmpty; + }).toList(); + // Group by doctor (doctorName) and sort + allInvoicesList.sort((a, b) { + int doctorComparison = (a.doctorName ?? '').compareTo(b.doctorName ?? ''); + if (doctorComparison != 0) return doctorComparison; + return b.appointmentDate!.compareTo(a.appointmentDate!); + }); + break; + } + + notifyListeners(); + } + + void filterInvoicesByHospital(String hospitalName) { + currentFilter = InvoiceFilterType.hospital; + allInvoicesList = _originalInvoicesList + .where((invoice) => invoice.projectName == hospitalName) + .toList(); + allInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!)); + notifyListeners(); + } + + void filterInvoicesByClinic(String clinicName) { + currentFilter = InvoiceFilterType.clinic; + allInvoicesList = _originalInvoicesList + .where((invoice) => invoice.clinicName == clinicName) + .toList(); + allInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!)); + notifyListeners(); + } + + void filterInvoicesByDoctor(String doctorName) { + currentFilter = InvoiceFilterType.doctor; + allInvoicesList = _originalInvoicesList + .where((invoice) => invoice.doctorName == doctorName) + .toList(); + allInvoicesList.sort((a, b) => b.appointmentDate!.compareTo(a.appointmentDate!)); + notifyListeners(); + } + + List getOriginalInvoicesList() { + return _originalInvoicesList; + } + + // Filter bottom sheet methods + void prepareFilterList(InvoiceFilterType filterType) { + Set uniqueItems = {}; + + for (var invoice in _originalInvoicesList) { + String? itemName; + if (filterType == InvoiceFilterType.hospital) { + itemName = invoice.projectName; + } else if (filterType == InvoiceFilterType.clinic) { + itemName = invoice.clinicName; + } else if (filterType == InvoiceFilterType.doctor) { + itemName = invoice.doctorName; + } + + if (itemName != null && itemName.isNotEmpty) { + uniqueItems.add(itemName); + } + } + + _filterOriginalList = uniqueItems.toList()..sort(); + filterDisplayList = List.from(_filterOriginalList); + filterSearchController.clear(); + selectedFilterItem = null; + notifyListeners(); + } + + void searchFilterItems(String query) { + if (query.isEmpty) { + filterDisplayList = List.from(_filterOriginalList); + } else { + filterDisplayList = _filterOriginalList + .where((item) => item.toLowerCase().contains(query.toLowerCase())) + .toList(); + } + notifyListeners(); + } + + void clearFilterSearch() { + filterSearchController.clear(); + filterDisplayList = List.from(_filterOriginalList); + notifyListeners(); + } + + void selectFilterItem(String item) { + selectedFilterItem = item; + notifyListeners(); + } } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 4f66d29c..a28652d9 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -751,6 +751,11 @@ abstract class LocaleKeys { static const erConsultation = 'erConsultation'; static const myInvoice = 'myInvoice'; static const invoiceList = 'invoiceList'; + static const allInvoices = 'allInvoices'; + static const hospitals = 'hospitals'; + static const clinics = 'clinics'; + static const doctors = 'doctors'; + static const selectDoctor = 'selectDoctor'; static const thisItemIsNotAvailable = 'thisItemIsNotAvailable'; static const beforeAfterImages = 'beforeAfterImages'; static const clinicAcceptLivecare = 'clinicAcceptLivecare'; diff --git a/lib/presentation/my_invoices/my_invoices_list.dart b/lib/presentation/my_invoices/my_invoices_list.dart index dddb0a15..054d2fce 100644 --- a/lib/presentation/my_invoices/my_invoices_list.dart +++ b/lib/presentation/my_invoices/my_invoices_list.dart @@ -13,6 +13,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/my_invoices/my_invoices_details_page.dart'; +import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_filter_bottom_sheet.dart'; import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_list_card.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; @@ -21,6 +22,8 @@ import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; +import '../../widgets/buttons/custom_button.dart'; + class MyInvoicesList extends StatefulWidget { const MyInvoicesList({super.key}); @@ -40,6 +43,75 @@ class _MyInvoicesListState extends State { super.initState(); } + void _showHospitalFilterBottomSheet(BuildContext context) { + myInvoicesViewModel.prepareFilterList(InvoiceFilterType.hospital); + + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.selectHospital.tr(context: context), + context, + child: InvoiceFilterBottomSheet( + title: LocaleKeys.hospital.tr(context: context), + onItemSelected: (selectedHospital) { + Navigator.pop(context); + myInvoicesViewModel.filterInvoicesByHospital(selectedHospital); + }, + ), + isFullScreen: false, + isCloseButtonVisible: true, + hasBottomPadding: false, + backgroundColor: AppColors.bottomSheetBgColor, + callBackFunc: () { + myInvoicesViewModel.clearFilterSearch(); + }, + ); + } + + void _showClinicFilterBottomSheet(BuildContext context) { + myInvoicesViewModel.prepareFilterList(InvoiceFilterType.clinic); + + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.selectClinic.tr(context: context), + context, + child: InvoiceFilterBottomSheet( + title: LocaleKeys.clinic.tr(context: context), + onItemSelected: (selectedClinic) { + Navigator.pop(context); + myInvoicesViewModel.filterInvoicesByClinic(selectedClinic); + }, + ), + isFullScreen: false, + isCloseButtonVisible: true, + hasBottomPadding: false, + backgroundColor: AppColors.bottomSheetBgColor, + callBackFunc: () { + myInvoicesViewModel.clearFilterSearch(); + }, + ); + } + + void _showDoctorFilterBottomSheet(BuildContext context) { + myInvoicesViewModel.prepareFilterList(InvoiceFilterType.doctor); + + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.selectDoctor.tr(context: context), + context, + child: InvoiceFilterBottomSheet( + title: LocaleKeys.doctor.tr(context: context), + onItemSelected: (selectedDoctor) { + Navigator.pop(context); + myInvoicesViewModel.filterInvoicesByDoctor(selectedDoctor); + }, + ), + isFullScreen: false, + isCloseButtonVisible: true, + hasBottomPadding: false, + backgroundColor: AppColors.bottomSheetBgColor, + callBackFunc: () { + myInvoicesViewModel.clearFilterSearch(); + }, + ); + } + @override Widget build(BuildContext context) { myInvoicesViewModel = Provider.of(context, listen: false); @@ -50,62 +122,133 @@ class _MyInvoicesListState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 24.h), + SizedBox(height: 16.h), + Row( + children: [ + CustomButton( + text: LocaleKeys.allInvoices.tr(context: context), + onPressed: () { + myInvoicesViewModel.filterInvoices(InvoiceFilterType.all); + }, + backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), + textColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.blackColor, + fontSize: 12, + fontWeight: FontWeight.w500, + borderRadius: 10, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + ), + SizedBox(width: 8.h), + CustomButton( + text: LocaleKeys.hospitals.tr(context: context), + onPressed: () { + if (myInvoicesVM.allInvoicesList.isEmpty) return; + _showHospitalFilterBottomSheet(context); + }, + backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), + textColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.blackColor, + fontSize: 12, + fontWeight: FontWeight.w500, + borderRadius: 10, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + ), + SizedBox(width: 8.h), + CustomButton( + text: LocaleKeys.clinics.tr(context: context), + onPressed: () { + if (myInvoicesVM.allInvoicesList.isEmpty) return; + _showClinicFilterBottomSheet(context); + }, + backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), + textColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.blackColor, + fontSize: 12, + fontWeight: FontWeight.w500, + borderRadius: 10, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + ), + SizedBox(width: 8.h), + CustomButton( + text: LocaleKeys.doctors.tr(context: context), + onPressed: () { + if (myInvoicesVM.allInvoicesList.isEmpty) return; + _showDoctorFilterBottomSheet(context); + }, + backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.bgRedLightColor : AppColors.whiteColor, + borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2), + textColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.blackColor, + fontSize: 12, + fontWeight: FontWeight.w500, + borderRadius: 10, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + ), + ], + ).paddingSymmetrical(24.h, 0.h), + SizedBox(height: 16.h), ListView.builder( - itemCount: myInvoicesVM.isInvoicesListLoading ? 4 : myInvoicesVM.allInvoicesList.isEmpty ? 1 : myInvoicesVM.allInvoicesList.length, + itemCount: myInvoicesVM.isInvoicesListLoading + ? 4 + : myInvoicesVM.allInvoicesList.isEmpty + ? 1 + : myInvoicesVM.allInvoicesList.length, physics: NeverScrollableScrollPhysics(), shrinkWrap: true, padding: EdgeInsetsGeometry.zero, itemBuilder: (context, index) { return myInvoicesVM.isInvoicesListLoading - ? LabResultItemView( - onTap: () {}, - labOrder: null, - index: index, - isLoading: true, - ) - : myInvoicesVM.allInvoicesList.isNotEmpty ? AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 500), - child: SlideAnimation( - verticalOffset: 100.0, - child: FadeInAnimation( - child: AnimatedContainer( - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - child: InvoiceListCard( - getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index], - onTap: () async { - myInvoicesVM.setInvoiceDetailLoading(); - LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingInvoiceDetails.tr(context: context)); - await myInvoicesVM.getInvoiceDetails( - appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!, - invoiceNo: myInvoicesVM.allInvoicesList[index].invoiceNo!, - projectID: myInvoicesVM.allInvoicesList[index].projectID!, - onSuccess: (val) { - LoaderBottomSheet.hideLoader(); - Navigator.of(context).push( - CustomPageRoute( - page: MyInvoicesDetailsPage(getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel, getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],), - ), - ); - }, - onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: err), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); - }, + ? LabResultItemView(onTap: () {}, labOrder: null, index: index, isLoading: true) + : myInvoicesVM.allInvoicesList.isNotEmpty + ? AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 500), + child: SlideAnimation( + verticalOffset: 100.0, + child: FadeInAnimation( + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + child: InvoiceListCard( + getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index], + onTap: () async { + myInvoicesVM.setInvoiceDetailLoading(); + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingInvoiceDetails.tr(context: context)); + await myInvoicesVM.getInvoiceDetails( + appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!, + invoiceNo: myInvoicesVM.allInvoicesList[index].invoiceNo!, + projectID: myInvoicesVM.allInvoicesList[index].projectID!, + onSuccess: (val) { + LoaderBottomSheet.hideLoader(); + Navigator.of(context).push( + CustomPageRoute( + page: MyInvoicesDetailsPage( + getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel, + getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index], + ), + ), + ); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + }, + ), + ), ), ), - ), - ), - ) : Utils.getNoDataWidget(context); + ) + : Utils.getNoDataWidget(context); }).paddingSymmetrical(24.w, 0.h), ], ); diff --git a/lib/presentation/my_invoices/widgets/invoice_filter_bottom_sheet.dart b/lib/presentation/my_invoices/widgets/invoice_filter_bottom_sheet.dart new file mode 100644 index 00000000..340f1020 --- /dev/null +++ b/lib/presentation/my_invoices/widgets/invoice_filter_bottom_sheet.dart @@ -0,0 +1,133 @@ +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_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/debouncer.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/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_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/input_widget.dart'; +import 'package:provider/provider.dart'; + +class InvoiceFilterBottomSheet extends StatelessWidget { + final Function(String) onItemSelected; + final String title; + + const InvoiceFilterBottomSheet({ + super.key, + required this.onItemSelected, + required this.title, + }); + + @override + Widget build(BuildContext context) { + final debouncer = Debouncer(milliseconds: 500); + + return Consumer( + builder: (context, vm, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextInputWidget( + labelText: LocaleKeys.search.tr(context: context), + hintText: "Search $title", + controller: vm.filterSearchController, + onChange: (value) { + debouncer.run(() { + vm.searchFilterItems(value ?? ""); + }); + }, + isEnable: true, + prefix: null, + autoFocus: false, + isBorderAllowed: false, + keyboardType: TextInputType.text, + isAllowLeadingIcon: true, + selectionType: SelectionTypeEnum.search, + padding: EdgeInsets.symmetric( + vertical: ResponsiveExtension(10).h, + horizontal: ResponsiveExtension(15).h, + ), + ), + SizedBox(height: 24.h), + SizedBox( + height: MediaQuery.sizeOf(context).height * 0.4, + child: vm.filterDisplayList.isEmpty + ? Center( + child: Text( + "No $title found", + style: TextStyle( + fontSize: 16, + color: AppColors.greyTextColor, + ), + ), + ) + : ListView.separated( + itemBuilder: (_, index) { + final item = vm.filterDisplayList[index]; + return FilterListItem( + itemName: item, + ).onPress(() { + vm.selectFilterItem(item); + onItemSelected(item); + }); + }, + separatorBuilder: (_, __) => SizedBox(height: 16.h), + itemCount: vm.filterDisplayList.length, + ), + ), + ], + ); + }, + ); + } +} + +class FilterListItem extends StatelessWidget { + final String itemName; + + const FilterListItem({super.key, required this.itemName}); + + AppState get appState => getIt.get(); + + @override + Widget build(BuildContext context) { + return DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: false, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + itemName, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: AppColors.blackColor, + ), + ), + ), + Transform.flip( + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon_small, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ), + ), + ], + ).paddingSymmetrical(16.h, 16.h), + ); + } +} From 8b829b9101d5b64fdcdea9e9201b479ece9f3743 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Tue, 31 Mar 2026 13:32:22 +0300 Subject: [PATCH 33/33] reminder start time added to the prescription --- assets/langs/ar-SA.json | 4 +- assets/langs/en-US.json | 4 +- lib/core/utils/calender_utils_new.dart | 6 +- .../prescriptions_view_model.dart | 8 + lib/generated/locale_keys.g.dart | 2 + .../prescriptions/prescription_item_view.dart | 121 ++++++++---- lib/widgets/scroll_wheel_time_picker.dart | 181 ++++++++++++++++++ 7 files changed, 288 insertions(+), 38 deletions(-) create mode 100644 lib/widgets/scroll_wheel_time_picker.dart diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index b78b8545..e36c8278 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1591,5 +1591,7 @@ "verifyInsurance": "التحقق من التأمين", "tests": "تحليل", "calendarPermissionAlert": "يرجى منح إذن الوصول إلى التقويم من إعدادات التطبيق لضبط تذكير تناول الدواء.", - "sortByLocation": "الترتيب حسب الموقع" + "sortByLocation": "الترتيب حسب الموقع", + "timeForFirstReminder": "وقت التذكير الأول", + "reminderRemovalNote": "يمكنك إزالتها من التقويم الخاص بك لاحقاً عن طريق إيقاف تشغيل التذكير" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index cbea7b94..33091c57 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1585,5 +1585,7 @@ "verifyInsurance": "Verify Insurance", "tests": "tests", "calendarPermissionAlert": "Please grant calendar access permission from app settings to set medication reminder.", - "sortByLocation": "Sort by location" + "sortByLocation": "Sort by location", + "timeForFirstReminder": "Time for 1st reminder", + "reminderRemovalNote": "You can remove it from your calendar later by switching off the reminder" } diff --git a/lib/core/utils/calender_utils_new.dart b/lib/core/utils/calender_utils_new.dart index 331cf6d5..6f043e26 100644 --- a/lib/core/utils/calender_utils_new.dart +++ b/lib/core/utils/calender_utils_new.dart @@ -101,9 +101,11 @@ class CalenderUtilsNew { required String itemDescriptionN, required String route, Function(String)? onFailure, - String? prescriptionNumber}) async { + String? prescriptionNumber, + DateTime? scheduleDateTime, + }) async { DateTime currentDay = DateTime.now(); - DateTime actualDate = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0); + DateTime actualDate = scheduleDateTime??DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0); print("the frequency is $frequencyNumber"); frequencyNumber ??= 2; //Some time frequency number is null so by default will be 2 int interval = calculateIntervalAsPerFrequency(frequencyNumber); diff --git a/lib/features/prescriptions/prescriptions_view_model.dart b/lib/features/prescriptions/prescriptions_view_model.dart index 4baf6882..b9c29072 100644 --- a/lib/features/prescriptions/prescriptions_view_model.dart +++ b/lib/features/prescriptions/prescriptions_view_model.dart @@ -52,6 +52,8 @@ class PrescriptionsViewModel extends ChangeNotifier { bool isPrescriptionsDataNeedsReloading = true; List prescriptionsOrderList = []; + DateTime? selectedReminderTime; + PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService, required this.navServices}); initPrescriptionsViewModel() { @@ -71,6 +73,7 @@ class PrescriptionsViewModel extends ChangeNotifier { Future checkIfReminderExistForPrescription(int index) async { prescriptionDetailsList[index].hasReminder = await CalenderUtilsNew.instance.checkIfEventExist(prescriptionDetailsList[index].itemID?.toString() ?? ""); + notifyListeners(); return prescriptionDetailsList[index].hasReminder ?? false; } @@ -308,4 +311,9 @@ class PrescriptionsViewModel extends ChangeNotifier { }, ); } + + void serSelectedTime(DateTime dateTime) { + selectedReminderTime = dateTime; + notifyListeners(); + } } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 4f66d29c..f8a6c41e 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1586,5 +1586,7 @@ abstract class LocaleKeys { static const tests = 'tests'; static const calendarPermissionAlert = 'calendarPermissionAlert'; static const sortByLocation = 'sortByLocation'; + static const timeForFirstReminder = 'timeForFirstReminder'; + static const reminderRemovalNote = 'reminderRemovalNote'; } diff --git a/lib/presentation/prescriptions/prescription_item_view.dart b/lib/presentation/prescriptions/prescription_item_view.dart index 7f969b21..1c145115 100644 --- a/lib/presentation/prescriptions/prescription_item_view.dart +++ b/lib/presentation/prescriptions/prescription_item_view.dart @@ -13,6 +13,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:hmg_patient_app_new/widgets/scroll_wheel_time_picker.dart'; class PrescriptionItemView extends StatelessWidget { int index; @@ -110,51 +111,60 @@ class PrescriptionItemView extends StatelessWidget { if (await prescriptionVM.checkIfReminderExistForPrescription(index)) { prescriptionVM.prescriptionDetailsList[index].hasReminder = true; - if (prescriptionVM.prescriptionDetailsList[index].hasReminder ?? false) { + LoaderBottomSheet.showLoader(loadingText: "Removing Reminders"); bool resultValue = await calender.checkAndRemoveMultipleItems(id: prescriptionVM.prescriptionDetailsList[index].itemID.toString()); prescriptionVM.setPrescriptionItemReminder(newValue, prescriptionVM.prescriptionDetailsList[index]); LoaderBottomSheet.hideLoader(); return; - } + } else { DateTime startDate = DateTime.now(); + prescriptionVM.serSelectedTime(startDate); DateTime endDate = DateTime(startDate.year, startDate.month, startDate.day + prescriptionVM.prescriptionDetailsList[index].days!.toInt()); - BottomSheetUtils().showReminderBottomSheet( + showCommonBottomSheetWithoutHeight( context, - endDate, - "", - prescriptionVM.prescriptionDetailsList[index].itemID.toString(), - "", - "", - title: "${prescriptionVM.prescriptionDetailsList[index].itemDescription} Prescription Reminder", - description: - "${prescriptionVM.prescriptionDetailsList[index].itemDescription} ${prescriptionVM.prescriptionDetailsList[index].frequency} ${prescriptionVM.prescriptionDetailsList[index].route} ", - onSuccess: () {}, - isMultiAllowed: true, - onMultiDateSuccess: (int selectedIndex) async { - bool isEventAdded = await calender.createMultipleEvents( - reminderMinutes: selectedIndex, - frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), - days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), - orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, - itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, - route: prescriptionVM.prescriptionDetailsList[index].route!, - onFailure: (errorMessage) => prescriptionVM.showError(errorMessage), - prescriptionNumber: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), - ); - prescriptionVM.setPrescriptionItemReminder(isEventAdded, prescriptionVM.prescriptionDetailsList[index]); - // setCalender(context, - // eventId: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), - // selectedMinutes: selectedIndex, - // frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), - // days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), - // orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, - // itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, - // route: prescriptionVM.prescriptionDetailsList[index].route!); - }, + child: bottomSheetContent(context), + title: LocaleKeys.timeForFirstReminder.tr(), + + isCloseButtonVisible: true ); + + // BottomSheetUtils().showReminderBottomSheet( + // context, + // endDate, + // "", + // prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + // "", + // "", + // title: "${prescriptionVM.prescriptionDetailsList[index].itemDescription} Prescription Reminder", + // description: + // "${prescriptionVM.prescriptionDetailsList[index].itemDescription} ${prescriptionVM.prescriptionDetailsList[index].frequency} ${prescriptionVM.prescriptionDetailsList[index].route} ", + // onSuccess: () {}, + // isMultiAllowed: true, + // onMultiDateSuccess: (int selectedIndex) async { + // bool isEventAdded = await calender.createMultipleEvents( + // reminderMinutes: selectedIndex, + // frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), + // days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), + // orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, + // itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, + // route: prescriptionVM.prescriptionDetailsList[index].route!, + // onFailure: (errorMessage) => prescriptionVM.showError(errorMessage), + // prescriptionNumber: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + // ); + // prescriptionVM.setPrescriptionItemReminder(isEventAdded, prescriptionVM.prescriptionDetailsList[index]); + // // setCalender(context, + // // eventId: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + // // selectedMinutes: selectedIndex, + // // frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), + // // days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), + // // orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, + // // itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, + // // route: prescriptionVM.prescriptionDetailsList[index].route!); + // }, + // ); } }, ).toShimmer2(isShow: isLoading), @@ -186,4 +196,47 @@ class PrescriptionItemView extends StatelessWidget { ), ); } + + Widget bottomSheetContent(BuildContext context) { + return Column( + children: [ + SizedBox(height: 4.h), + LocaleKeys.reminderRemovalNote.tr().toText14(isBold: true, color: AppColors.warningColorYellow), + SizedBox(height: 8.h), + ScrollWheelTimePicker( + initialHour: DateTime.now().hour, + initialMinute: DateTime.now().minute, + use24HourFormat: true, + pickerHeight: 120.h, + itemExtent: 100.h, + onTimeChanged: (time) { + // Handle selected time + debugPrint('Selected time: ${time.hour}:${time.minute}'); + prescriptionVM.serSelectedTime(DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, time.hour, time.minute)); + }, + ), + SizedBox(height: 8.h), + CustomButton( + backgroundColor: AppColors.successColor, + borderColor: AppColors.successColor, + text: LocaleKeys.confirm.tr(), onPressed: () async { + CalenderUtilsNew calender = CalenderUtilsNew.instance; + bool isEventAdded = await calender.createMultipleEvents( + reminderMinutes: 10, + frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), + days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), + orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, + itemDescriptionN: prescriptionVM.prescriptionDetailsList[index].itemDescription!, + route: prescriptionVM.prescriptionDetailsList[index].route!, + onFailure: (errorMessage) => prescriptionVM.showError(errorMessage), + prescriptionNumber: prescriptionVM.prescriptionDetailsList[index].itemID.toString(), + scheduleDateTime: prescriptionVM.selectedReminderTime, + ); + prescriptionVM.setPrescriptionItemReminder(isEventAdded, prescriptionVM.prescriptionDetailsList[index]); + Navigator.of(context).pop(); + }) + + ], + ); + } } diff --git a/lib/widgets/scroll_wheel_time_picker.dart b/lib/widgets/scroll_wheel_time_picker.dart new file mode 100644 index 00000000..a6e155bb --- /dev/null +++ b/lib/widgets/scroll_wheel_time_picker.dart @@ -0,0 +1,181 @@ +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 ScrollWheelTimePicker extends StatefulWidget { + final int initialHour; + + final int initialMinute; + + final bool use24HourFormat; + + final ValueChanged? onTimeChanged; + + final double itemExtent; + + final double pickerHeight; + + final TextStyle? digitTextStyle; + + final TextStyle? separatorTextStyle; + + const ScrollWheelTimePicker({ + super.key, + this.initialHour = 8, + this.initialMinute = 15, + this.use24HourFormat = true, + this.onTimeChanged, + this.itemExtent = 60, + this.pickerHeight = 180, + this.digitTextStyle, + this.separatorTextStyle, + }); + + @override + State createState() => _ScrollWheelTimePickerState(); +} + +class _ScrollWheelTimePickerState extends State { + late FixedExtentScrollController _hourController; + late FixedExtentScrollController _minuteController; + late int _selectedHour; + late int _selectedMinute; + + int get _maxHour => widget.use24HourFormat ? 24 : 12; + + @override + void initState() { + super.initState(); + _selectedHour = widget.initialHour; + _selectedMinute = widget.initialMinute; + + final hourIndex = + widget.use24HourFormat ? _selectedHour : (_selectedHour == 0 ? 11 : _selectedHour - 1); + + _hourController = FixedExtentScrollController(initialItem: hourIndex); + _minuteController = FixedExtentScrollController(initialItem: _selectedMinute); + } + + @override + void dispose() { + _hourController.dispose(); + _minuteController.dispose(); + super.dispose(); + } + + void _notifyChange() { + widget.onTimeChanged?.call(TimeOfDay(hour: _selectedHour, minute: _selectedMinute)); + } + + TextStyle get _defaultDigitStyle => TextStyle( + fontSize: 72.f, + fontWeight: FontWeight.w800, + color: AppColors.textColor, + letterSpacing: 0, + ); + + TextStyle get _defaultSeparatorStyle => TextStyle( + fontSize: 40.f, + fontWeight: FontWeight.w800, + color: AppColors.textColor, + letterSpacing: 0, + ); + + @override + Widget build(BuildContext context) { + final digitStyle = widget.digitTextStyle ?? _defaultDigitStyle; + final separatorStyle = widget.separatorTextStyle ?? _defaultSeparatorStyle; + + return SizedBox( + height: widget.pickerHeight, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 150.w, + child: ListWheelScrollView.useDelegate( + controller: _hourController, + itemExtent: widget.itemExtent, + physics: const FixedExtentScrollPhysics(), + perspective: 0.005, + diameterRatio: 1.2, + onSelectedItemChanged: (index) { + setState(() { + _selectedHour = + widget.use24HourFormat ? index : index + 1; + }); + _notifyChange(); + }, + childDelegate: ListWheelChildBuilderDelegate( + childCount: _maxHour, + builder: (context, index) { + final hour = + widget.use24HourFormat ? index : index + 1; + final isSelected = hour == _selectedHour; + return Visibility( + visible: isSelected, + child: Center( + child: AnimatedDefaultTextStyle( + duration: const Duration(milliseconds: 200), + style: digitStyle.copyWith( + color: isSelected + ? AppColors.textColor + : AppColors.textColor.withValues(alpha: 0.3), + ), + child: Text(hour.toString().padLeft(2, '0')), + ), + )); + }, + ), + ), + ), + + Padding( + padding: EdgeInsets.symmetric(horizontal: 2.w), + child: Text(':', style: separatorStyle), + ), + + SizedBox( + width: 150.w, + child: ListWheelScrollView.useDelegate( + controller: _minuteController, + itemExtent: widget.itemExtent, + physics: const FixedExtentScrollPhysics(), + perspective: 0.005, + diameterRatio: 1.2, + onSelectedItemChanged: (index) { + setState(() { + _selectedMinute = index; + }); + _notifyChange(); + }, + childDelegate: ListWheelChildBuilderDelegate( + childCount: 60, + + builder: (context, index) { + final isSelected = index == _selectedMinute; + return Visibility( + visible: isSelected, + child: + Center( + child: AnimatedDefaultTextStyle( + duration: const Duration(milliseconds: 200), + style: digitStyle.copyWith( + color: isSelected + ? AppColors.textColor + : AppColors.transparent.withValues(alpha: 0.3), + ), + child: Text(index.toString().padLeft(2, '0')), + ), + )); + }, + ), + ), + ), + ], + ), + ); + } +}