* 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New:
  updates
  updates
  updates
  Added Arabic banner support and onTap support
  updates
  LiveCare & iOS 27.1 updates
  VoIP Kit implemented
  Fixed Firebase issue with iOS UIScene delegate
  updates
  REVERETED  THE YAMAL TO LOCAL PAYMENT SERVICE
  feat: enhance doctor appointment filtering and sorting by adding English region names
  chore: add Package.resolved to .gitignore for Swift package management
  Update to stores, VersionID 21.7
  feat: update radiology analysis models and integrate specialty handling
  chore: update analysis options, change app environment to preProd, and update package dependencies
dev_sultan
Sultan khan 1 day ago
commit dc23372048

6
.gitignore vendored

@ -43,3 +43,9 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
/ios/
/ios/Penguin.xcframework/
/ios/PenguinINRenderer.xcframework/
/ios/PenNavUI.xcframework/

@ -7,6 +7,11 @@
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
analyzer:
exclude:
- build/**
- android/**
- ios/**
include: package:flutter_lints/flutter.yaml
linter:

@ -2070,5 +2070,6 @@
"downloadApp": "حمل التطبيق",
"unread": "غير مقروء",
"read": "مقروءة",
"pendingMedicalReportRequest": "لديك بالفعل طلب معلّق للحصول على تقرير طبي خاص بهذا الموعد. يرجى الانتظار حتى اكتمال الطلب قبل تقديم طلب جديد."
"pendingMedicalReportRequest": "لديك بالفعل طلب معلّق للحصول على تقرير طبي خاص بهذا الموعد. يرجى الانتظار حتى اكتمال الطلب قبل تقديم طلب جديد.",
"AllergyReactions": "ردود الفعل التحسسية"
}

@ -2060,7 +2060,8 @@
"downloadApp": "Download App",
"unread": "Unread",
"read": "Read",
"pendingMedicalReportRequest": "You already have a pending medical report request for this appointment. Please wait for the request to be completed before submitting a new one."
"pendingMedicalReportRequest": "You already have a pending medical report request for this appointment. Please wait for the request to be completed before submitting a new one.",
"allergyReactions": "Allergy Reactions"
}

@ -58,7 +58,7 @@ post_install do |installer|
## dart: PermissionGroup.notification
'PERMISSION_NOTIFICATIONS=1',
]
build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64 i386'
build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'i386 x86_64'
build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
build_configuration.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
xcconfig_path = build_configuration.base_configuration_reference.real_path

@ -7,25 +7,34 @@
objects = {
/* Begin PBXBuildFile section */
094EF77E011152A3DF3536B2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30E602807D9C203A2FA83417 /* Pods_Runner.framework */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
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 */; };
5D5A1F80D389375644C4D0DC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */; };
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 */; };
7676C293308F37EA004CF793 /* PenguinViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C291308F37EA004CF793 /* PenguinViewFactory.swift */; };
7676C294308F37EA004CF793 /* PenguinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C290308F37EA004CF793 /* PenguinView.swift */; };
7676C295308F37EA004CF793 /* PenguinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C28D308F37EA004CF793 /* PenguinModel.swift */; };
7676C296308F37EA004CF793 /* PenguinNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C28E308F37EA004CF793 /* PenguinNavigator.swift */; };
7676C297308F37EA004CF793 /* PenguinPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C28F308F37EA004CF793 /* PenguinPlugin.swift */; };
7676C2A9308F394F004CF793 /* HMGPenguinInPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A4308F394F004CF793 /* HMGPenguinInPlatformBridge.swift */; };
7676C2AA308F394F004CF793 /* HMG_Geofence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A3308F394F004CF793 /* HMG_Geofence.swift */; };
7676C2AB308F394F004CF793 /* LocalizedFromFlutter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A6308F394F004CF793 /* LocalizedFromFlutter.swift */; };
7676C2AC308F394F004CF793 /* GlobalHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A2308F394F004CF793 /* GlobalHelper.swift */; };
7676C2AD308F394F004CF793 /* HMGPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A5308F394F004CF793 /* HMGPlatformBridge.swift */; };
7676C2AE308F394F004CF793 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C29E308F394F004CF793 /* API.swift */; };
7676C2AF308F394F004CF793 /* FlutterConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A0308F394F004CF793 /* FlutterConstants.swift */; };
7676C2B0308F394F004CF793 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C29F308F394F004CF793 /* Extensions.swift */; };
7676C2B1308F394F004CF793 /* GeoZoneModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A1308F394F004CF793 /* GeoZoneModel.swift */; };
7676C2B2308F394F004CF793 /* OpenTokPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7676C2A7308F394F004CF793 /* OpenTokPlatformBridge.swift */; };
7676C2C5308F3D02004CF793 /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2BF308F3C52004CF793 /* Penguin.xcframework */; };
7676C2C6308F3D02004CF793 /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2BF308F3C52004CF793 /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
7676C2C7308F3D03004CF793 /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */; };
7676C2C8308F3D03004CF793 /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
7676C2C9308F3D04004CF793 /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */; };
7676C2CA308F3D04004CF793 /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
76AA18AE2F3B2A4D00DC8DFC /* ring_30Sec.caf in Resources */ = {isa = PBXBuildFile; fileRef = 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */; };
76B1D2512F91BF8000DBBD1B /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */; };
76B1D2522F91BF8000DBBD1B /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
76B1D2532F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */; };
76B1D2542F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
76B1D2552F91BF8000DBBD1B /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */; };
76B1D2562F91BF8000DBBD1B /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
@ -49,9 +58,9 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
76B1D2542F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Embed Frameworks */,
76B1D2522F91BF8000DBBD1B /* Penguin.xcframework in Embed Frameworks */,
76B1D2562F91BF8000DBBD1B /* PenNavUI.xcframework in Embed Frameworks */,
7676C2C8308F3D03004CF793 /* PenguinINRenderer.xcframework in Embed Frameworks */,
7676C2C6308F3D02004CF793 /* Penguin.xcframework in Embed Frameworks */,
7676C2CA308F3D04004CF793 /* PenNavUI.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@ -71,29 +80,40 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
30E602807D9C203A2FA83417 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
478CFA952E6E20A60064F3D7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = "<group>"; };
61243B422EC5FA3700D46FA0 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = "<group>"; };
61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = "<group>"; };
61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = "<group>"; };
61243B452EC5FA3700D46FA0 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = "<group>"; };
61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = "<group>"; };
4D6281A38B453C42FAC24BD5 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7676C28D308F37EA004CF793 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = "<group>"; };
7676C28E308F37EA004CF793 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = "<group>"; };
7676C28F308F37EA004CF793 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = "<group>"; };
7676C290308F37EA004CF793 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = "<group>"; };
7676C291308F37EA004CF793 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = "<group>"; };
7676C29E308F394F004CF793 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = "<group>"; };
7676C29F308F394F004CF793 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
7676C2A0308F394F004CF793 /* FlutterConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterConstants.swift; sourceTree = "<group>"; };
7676C2A1308F394F004CF793 /* GeoZoneModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoZoneModel.swift; sourceTree = "<group>"; };
7676C2A2308F394F004CF793 /* GlobalHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalHelper.swift; sourceTree = "<group>"; };
7676C2A3308F394F004CF793 /* HMG_Geofence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMG_Geofence.swift; sourceTree = "<group>"; };
7676C2A4308F394F004CF793 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = "<group>"; };
7676C2A5308F394F004CF793 /* HMGPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPlatformBridge.swift; sourceTree = "<group>"; };
7676C2A6308F394F004CF793 /* LocalizedFromFlutter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedFromFlutter.swift; sourceTree = "<group>"; };
7676C2A7308F394F004CF793 /* OpenTokPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokPlatformBridge.swift; sourceTree = "<group>"; };
7676C2BF308F3C52004CF793 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Penguin.xcframework; sourceTree = "<group>"; };
7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenguinINRenderer.xcframework; sourceTree = "<group>"; };
7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenNavUI.xcframework; sourceTree = "<group>"; };
769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = "<group>"; };
76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = ring_30Sec.caf; sourceTree = "<group>"; };
76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = "<group>"; };
76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenguinINRenderer.xcframework; path = Frameworks/PenguinINRenderer.xcframework; sourceTree = "<group>"; };
76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = "<group>"; };
76B714CF300E58B1004DE37A /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
76B714D1300E58B1004DE37A /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
8522EA4C54B9CA21B71F91CC /* 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 = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -101,9 +121,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BCE5BC40273DCC009E2FACB7 /* 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 = "<group>"; };
C6416282AC56269448D7DA99 /* 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 = "<group>"; };
C6FD350374F47AFA34911C58 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
9C0E63FC9D84AA7D3BB0A547 /* 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 = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -111,11 +129,12 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7676C2C5308F3D02004CF793 /* Penguin.xcframework in Frameworks */,
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
76B1D2512F91BF8000DBBD1B /* Penguin.xcframework in Frameworks */,
76B1D2552F91BF8000DBBD1B /* PenNavUI.xcframework in Frameworks */,
76B1D2532F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Frameworks */,
5D5A1F80D389375644C4D0DC /* Pods_Runner.framework in Frameworks */,
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
7676C2C7308F3D03004CF793 /* PenguinINRenderer.xcframework in Frameworks */,
7676C2C9308F3D04004CF793 /* PenNavUI.xcframework in Frameworks */,
094EF77E011152A3DF3536B2 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -133,42 +152,58 @@
61243B412EC5FA3700D46FA0 /* Helper */ = {
isa = PBXGroup;
children = (
61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */,
);
path = Helper;
sourceTree = "<group>";
};
61243B472EC5FA3700D46FA0 /* Penguin */ = {
766D8CB22EC60BE600D05E07 /* Frameworks */ = {
isa = PBXGroup;
children = (
7676C2BF308F3C52004CF793 /* Penguin.xcframework */,
7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */,
7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */,
76B714CF300E58B1004DE37A /* WidgetKit.framework */,
76B714D1300E58B1004DE37A /* SwiftUI.framework */,
30E602807D9C203A2FA83417 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
7676C292308F37EA004CF793 /* Penguin */ = {
isa = PBXGroup;
children = (
61243B422EC5FA3700D46FA0 /* PenguinModel.swift */,
61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */,
61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */,
61243B452EC5FA3700D46FA0 /* PenguinView.swift */,
61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */,
7676C28D308F37EA004CF793 /* PenguinModel.swift */,
7676C28E308F37EA004CF793 /* PenguinNavigator.swift */,
7676C28F308F37EA004CF793 /* PenguinPlugin.swift */,
7676C290308F37EA004CF793 /* PenguinView.swift */,
7676C291308F37EA004CF793 /* PenguinViewFactory.swift */,
);
path = Penguin;
sourceTree = "<group>";
};
766D8CB22EC60BE600D05E07 /* Frameworks */ = {
7676C2A8308F394F004CF793 /* Helper */ = {
isa = PBXGroup;
children = (
76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */,
76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */,
76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */,
76B714CF300E58B1004DE37A /* WidgetKit.framework */,
76B714D1300E58B1004DE37A /* SwiftUI.framework */,
56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */,
7676C29E308F394F004CF793 /* API.swift */,
7676C29F308F394F004CF793 /* Extensions.swift */,
7676C2A0308F394F004CF793 /* FlutterConstants.swift */,
7676C2A1308F394F004CF793 /* GeoZoneModel.swift */,
7676C2A2308F394F004CF793 /* GlobalHelper.swift */,
7676C2A3308F394F004CF793 /* HMG_Geofence.swift */,
7676C2A4308F394F004CF793 /* HMGPenguinInPlatformBridge.swift */,
7676C2A5308F394F004CF793 /* HMGPlatformBridge.swift */,
7676C2A6308F394F004CF793 /* LocalizedFromFlutter.swift */,
7676C2A7308F394F004CF793 /* OpenTokPlatformBridge.swift */,
);
name = Frameworks;
path = Helper;
sourceTree = "<group>";
};
79DD2093A1D9674C94359FC8 /* Pods */ = {
isa = PBXGroup;
children = (
BCE5BC40273DCC009E2FACB7 /* Pods-Runner.debug.xcconfig */,
C6416282AC56269448D7DA99 /* Pods-Runner.release.xcconfig */,
C6FD350374F47AFA34911C58 /* Pods-Runner.profile.xcconfig */,
8522EA4C54B9CA21B71F91CC /* Pods-Runner.debug.xcconfig */,
9C0E63FC9D84AA7D3BB0A547 /* Pods-Runner.release.xcconfig */,
4D6281A38B453C42FAC24BD5 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -209,9 +244,10 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
7676C2A8308F394F004CF793 /* Helper */,
7676C292308F37EA004CF793 /* Penguin */,
76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */,
61243B412EC5FA3700D46FA0 /* Helper */,
61243B472EC5FA3700D46FA0 /* Penguin */,
769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */,
478CFA952E6E20A60064F3D7 /* Runner.entitlements */,
478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */,
@ -251,7 +287,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
511FFA76807DE636962DBF91 /* [CP] Check Pods Manifest.lock */,
DE4E6538EB74D09D8F3A8FE7 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
@ -259,8 +295,8 @@
765A5A922F35CD8B0003FF7D /* Embed Frameworks */,
76B714E4300E58B2004DE37A /* Embed Foundation Extensions */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
C7E5B2C65EE0A4D64ECC826B /* [CP] Embed Pods Frameworks */,
DF2C78ED8C8F648520DF8C43 /* [CP] Copy Pods Resources */,
824B1289AE3D15AB765B1BBF /* [CP] Embed Pods Frameworks */,
6F08875CF9A6CF013C44F482 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -305,7 +341,7 @@
);
mainGroup = 97C146E51CF9000F007C117D;
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
@ -357,75 +393,83 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
};
511FFA76807DE636962DBF91 /* [CP] Check Pods Manifest.lock */ = {
6F08875CF9A6CF013C44F482 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
824B1289AE3D15AB765B1BBF /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "Run Script";
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 = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
C7E5B2C65EE0A4D64ECC826B /* [CP] Embed Pods Frameworks */ = {
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
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",
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
DF2C78ED8C8F648520DF8C43 /* [CP] Copy Pods Resources */ = {
DE4E6538EB74D09D8F3A8FE7 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@ -444,13 +488,22 @@
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 */,
7676C293308F37EA004CF793 /* PenguinViewFactory.swift in Sources */,
7676C294308F37EA004CF793 /* PenguinView.swift in Sources */,
7676C295308F37EA004CF793 /* PenguinModel.swift in Sources */,
7676C296308F37EA004CF793 /* PenguinNavigator.swift in Sources */,
7676C2A9308F394F004CF793 /* HMGPenguinInPlatformBridge.swift in Sources */,
7676C2AA308F394F004CF793 /* HMG_Geofence.swift in Sources */,
7676C2AB308F394F004CF793 /* LocalizedFromFlutter.swift in Sources */,
7676C2AC308F394F004CF793 /* GlobalHelper.swift in Sources */,
7676C2AD308F394F004CF793 /* HMGPlatformBridge.swift in Sources */,
7676C2AE308F394F004CF793 /* API.swift in Sources */,
7676C2AF308F394F004CF793 /* FlutterConstants.swift in Sources */,
7676C2B0308F394F004CF793 /* Extensions.swift in Sources */,
7676C2B1308F394F004CF793 /* GeoZoneModel.swift in Sources */,
7676C2B2308F394F004CF793 /* OpenTokPlatformBridge.swift in Sources */,
7676C297308F37EA004CF793 /* PenguinPlugin.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -548,6 +601,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Dr. Alhabib";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
@ -555,7 +609,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 4.6.044;
MARKETING_VERSION = 4.6.050;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -735,6 +789,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Dr. Alhabib";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
@ -742,7 +797,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 4.6.044;
MARKETING_VERSION = 4.6.050;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -765,6 +820,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Dr. Alhabib";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
@ -772,7 +828,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 4.6.044;
MARKETING_VERSION = 4.6.050;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -818,7 +874,7 @@
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};

@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/app-check.git",
"state" : {
"revision" : "3e33dd27dd4c69bd81c7c81fe61d8ccf58846902",
"version" : "11.3.1"
"revision" : "97f7d74dd0e8f3d0fe5fc75cc8957aa73bdc948a",
"version" : "11.3.2"
}
},
{
@ -50,17 +50,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "fdc352fabaf5916e7faa1f96ad02b1957e93e5a5",
"version" : "11.15.0"
}
},
{
"identity" : "flutterfire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/flutterfire",
"state" : {
"revision" : "dadb0fd27bc9afe4dee4f23326a4a9ba238258ac",
"version" : "3.15.2-firebase-core-swift"
"revision" : "27eaab3918e0bf78711cf1abf240577176326432",
"version" : "12.19.0"
}
},
{
@ -68,8 +59,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
"state" : {
"revision" : "a2d0f1f1666de591eb1a811f40b1706f5c63a2ed",
"version" : "2.3.0"
"revision" : "0208e2681ec81f8a9c81084696f60fcce26cb7ee",
"version" : "3.7.0"
}
},
{
@ -77,8 +68,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "45ce435e9406d3c674dd249a042b932bee006f60",
"version" : "11.15.0"
"revision" : "b8455dd2ff55cc269fda7a4f9eac6c1e3588c53f",
"version" : "12.19.2"
}
},
{
@ -95,8 +86,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "9f183ae842be978784f2963a343682e0c46d8fb3",
"version" : "8.1.2"
"revision" : "cc31f5ed464b111f877ce8554cbef4455d410d91",
"version" : "8.1.4"
}
},
{
@ -113,8 +104,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "c756a29784521063b6a1202907e2cc47f41b667c",
"version" : "4.5.0"
"revision" : "724a52eea6329b7e12d3ad8300d76ca9f3895fcc",
"version" : "5.3.1"
}
},
{
@ -162,15 +153,6 @@
"version" : "5.21.7"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "55d7a1cc5666b85c13464aea1c4b4a90feccb4c8",
"version" : "1.38.1"
}
},
{
"identity" : "swiftygif",
"kind" : "remoteSourceControl",

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
@ -91,6 +91,9 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<MetalAPIValidationSettings
isEnabled = "No">
</MetalAPIValidationSettings>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"

@ -50,17 +50,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "fdc352fabaf5916e7faa1f96ad02b1957e93e5a5",
"version" : "11.15.0"
}
},
{
"identity" : "flutterfire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/flutterfire",
"state" : {
"revision" : "dadb0fd27bc9afe4dee4f23326a4a9ba238258ac",
"version" : "3.15.2-firebase-core-swift"
"revision" : "27eaab3918e0bf78711cf1abf240577176326432",
"version" : "12.19.0"
}
},
{
@ -68,8 +59,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
"state" : {
"revision" : "a2d0f1f1666de591eb1a811f40b1706f5c63a2ed",
"version" : "2.3.0"
"revision" : "0208e2681ec81f8a9c81084696f60fcce26cb7ee",
"version" : "3.7.0"
}
},
{
@ -77,8 +68,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "45ce435e9406d3c674dd249a042b932bee006f60",
"version" : "11.15.0"
"revision" : "b8455dd2ff55cc269fda7a4f9eac6c1e3588c53f",
"version" : "12.19.2"
}
},
{
@ -95,8 +86,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "9f183ae842be978784f2963a343682e0c46d8fb3",
"version" : "8.1.2"
"revision" : "cc31f5ed464b111f877ce8554cbef4455d410d91",
"version" : "8.1.4"
}
},
{
@ -113,8 +104,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "c756a29784521063b6a1202907e2cc47f41b667c",
"version" : "4.5.0"
"revision" : "724a52eea6329b7e12d3ad8300d76ca9f3895fcc",
"version" : "5.3.1"
}
},
{
@ -162,15 +153,6 @@
"version" : "5.21.7"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "55d7a1cc5666b85c13464aea1c4b4a90feccb4c8",
"version" : "1.38.1"
}
},
{
"identity" : "swiftygif",
"kind" : "remoteSourceControl",

@ -1,37 +1,40 @@
import Flutter
import UIKit
import UserNotifications
import FirebaseCore
import FirebaseMessaging
import GoogleMaps
import firebase_messaging
@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
func didInitializeImplicitFlutterEngine(_ engineBridge: any FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
// GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng")
// FirebaseApp.configure()
// initializePlatformChannels()
}
func didInitializeImplicitFlutterEngine(_ engineBridge: any FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
// Run AFTER all plugins registered so Firebase sits in front of the VoIP plugin
FLTFirebaseMessagingPlugin.configureNotificationCenterDelegate()
}
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
application.registerForRemoteNotifications()
GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng")
// FirebaseApp.configure()
initializePlatformChannels()
// GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func initializePlatformChannels(){
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
// 1. Try accessing window via AppDelegate (legacy/single-window setup)
var controller = self.window?.rootViewController as? FlutterViewController
// 2. Fallback to UIWindowScene active window (modern iOS architecture)
if controller == nil {
controller = UIApplication.shared.connectedScenes
@ -40,7 +43,7 @@ import GoogleMaps
.first(where: { $0.isKeyWindow })?
.rootViewController as? FlutterViewController
}
// 3. Perform initialization once FlutterViewController is available
if let mainViewController = controller {
HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController)
@ -48,14 +51,14 @@ import GoogleMaps
print("⚠️ FlutterViewController not ready yet for 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
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)

@ -5,32 +5,32 @@
// Created by ZiKambrani on 22/12/2020.
//
import UIKit
class FlutterConstants{
static var LOG_GEOFENCE_URL:String?
static var WIFI_CREDENTIALS_URL:String?
static var DEFAULT_HTTP_PARAMS:[String:Any?]?
class func set(){
// (FiX) Take a start with FlutterMethodChannel (kikstart)
/* First call to flutter method is not returning the correct value (Always returning 'NSObject') then after it wroking fine and returning correct value*/
FlutterText.with(key: "test") { (test) in
flutterMethodChannel?.invokeMethod("getDefaultHttpParameters", arguments: nil){ (response) in
if let defaultHTTPParams = response as? [String:Any?]{
DEFAULT_HTTP_PARAMS = defaultHTTPParams
}
}
flutterMethodChannel?.invokeMethod("getLogGeofenceFullUrl", arguments:nil){ (response) in
if let url = response as? String{
LOG_GEOFENCE_URL = url
}
}
}
}
}
//import UIKit
//
//class FlutterConstants{
// static var LOG_GEOFENCE_URL:String?
// static var WIFI_CREDENTIALS_URL:String?
// static var DEFAULT_HTTP_PARAMS:[String:Any?]?
//
// class func set(){
//
// // (FiX) Take a start with FlutterMethodChannel (kikstart)
// /* First call to flutter method is not returning the correct value (Always returning 'NSObject') then after it wroking fine and returning correct value*/
// FlutterText.with(key: "test") { (test) in
//
// flutterMethodChannel?.invokeMethod("getDefaultHttpParameters", arguments: nil){ (response) in
// if let defaultHTTPParams = response as? [String:Any?]{
// DEFAULT_HTTP_PARAMS = defaultHTTPParams
// }
//
// }
//
// flutterMethodChannel?.invokeMethod("getLogGeofenceFullUrl", arguments:nil){ (response) in
// if let url = response as? String{
// LOG_GEOFENCE_URL = url
// }
// }
//
// }
// }
//}

@ -5,136 +5,136 @@
// Created by ZiKambrani on 14/12/2020.
//
import UIKit
import NetworkExtension
import SystemConfiguration.CaptiveNetwork
var flutterMethodChannel:FlutterMethodChannel? = nil
fileprivate var mainViewController:MainFlutterVC!
class HMGPlatformBridge{
private let channelName = "HMG-Platform-Bridge"
private static var shared_:HMGPlatformBridge?
class func initialize(flutterViewController:MainFlutterVC){
shared_ = HMGPlatformBridge()
mainViewController = flutterViewController
shared_?.openChannel()
}
func shared() -> HMGPlatformBridge{
assert((HMGPlatformBridge.shared_ != nil), "HMGPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
return HMGPlatformBridge.shared_!
}
private func openChannel(){
flutterMethodChannel = FlutterMethodChannel(name: channelName, binaryMessenger: mainViewController.binaryMessenger)
flutterMethodChannel?.setMethodCallHandler { (methodCall, result) in
print("Called function \(methodCall.method)")
if methodCall.method == "connectHMGInternetWifi"{
self.connectHMGInternetWifi(methodCall:methodCall, result: result)
}else if methodCall.method == "connectHMGGuestWifi"{
self.connectHMGGuestWifi(methodCall:methodCall, result: result)
}else if methodCall.method == "isHMGNetworkAvailable"{
self.isHMGNetworkAvailable(methodCall:methodCall, result: result)
}else if methodCall.method == "registerHmgGeofences"{
self.registerHmgGeofences(result: result)
}else if methodCall.method == "unRegisterHmgGeofences"{
self.unRegisterHmgGeofences(result: result)
}
print("")
}
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { (timer) in
FlutterConstants.set()
}
}
// Connect HMG Wifi and Internet
func connectHMGInternetWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
guard let pateintId = (methodCall.arguments as? [Any])?.first as? String
else { return assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'") }
HMG_Internet.shared.connect(patientId: pateintId) { (status, message) in
result(status ? 1 : 0)
if status{
self.showMessage(title:"Congratulations", message:message)
}else{
self.showMessage(title:"Ooops,", message:message)
}
}
}
// Connect HMG-Guest for App Access
func connectHMGGuestWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
HMG_GUEST.shared.connect() { (status, message) in
result(status ? 1 : 0)
if status{
self.showMessage(title:"Congratulations", message:message)
}else{
self.showMessage(title:"Ooops,", message:message)
}
}
}
func isHMGNetworkAvailable(methodCall:FlutterMethodCall ,result: @escaping FlutterResult) -> Bool{
guard let ssid = methodCall.arguments as? String else {
assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'")
return false
}
let queue = DispatchQueue.init(label: "com.hmg.wifilist")
NEHotspotHelper.register(options: nil, queue: queue) { (command) in
print(command)
if(command.commandType == NEHotspotHelperCommandType.filterScanList) {
if let networkList = command.networkList{
for network in networkList{
print(network.ssid)
}
}
}
}
return false
}
// Message Dailog
func showMessage(title:String, message:String){
DispatchQueue.main.async {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert )
alert.addAction(UIAlertAction(title: "OK", style: .destructive, handler: nil))
mainViewController.present(alert, animated: true) {
}
}
}
// Register Geofence
func registerHmgGeofences(result: @escaping FlutterResult){
flutterMethodChannel?.invokeMethod("getGeoZones", arguments: nil){ geoFencesJsonString in
if let jsonString = geoFencesJsonString as? String{
let allZones = GeoZoneModel.list(from: jsonString)
HMG_Geofence.shared().register(geoZones: allZones)
result(true)
}else{
}
}
}
// Register Geofence
func unRegisterHmgGeofences(result: @escaping FlutterResult){
HMG_Geofence.shared().unRegisterAll()
result(true)
}
}
//import UIKit
//import NetworkExtension
//import SystemConfiguration.CaptiveNetwork
//
//var flutterMethodChannel:FlutterMethodChannel? = nil
//fileprivate var mainViewController:MainFlutterVC!
//
//class HMGPlatformBridge{
// private let channelName = "HMG-Platform-Bridge"
// private static var shared_:HMGPlatformBridge?
//
// class func initialize(flutterViewController:MainFlutterVC){
// shared_ = HMGPlatformBridge()
// mainViewController = flutterViewController
// shared_?.openChannel()
// }
//
// func shared() -> HMGPlatformBridge{
// assert((HMGPlatformBridge.shared_ != nil), "HMGPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
// return HMGPlatformBridge.shared_!
// }
//
// private func openChannel(){
// flutterMethodChannel = FlutterMethodChannel(name: channelName, binaryMessenger: mainViewController.binaryMessenger)
// flutterMethodChannel?.setMethodCallHandler { (methodCall, result) in
// print("Called function \(methodCall.method)")
// if methodCall.method == "connectHMGInternetWifi"{
// self.connectHMGInternetWifi(methodCall:methodCall, result: result)
//
// }else if methodCall.method == "connectHMGGuestWifi"{
// self.connectHMGGuestWifi(methodCall:methodCall, result: result)
//
// }else if methodCall.method == "isHMGNetworkAvailable"{
// self.isHMGNetworkAvailable(methodCall:methodCall, result: result)
//
// }else if methodCall.method == "registerHmgGeofences"{
// self.registerHmgGeofences(result: result)
//
// }else if methodCall.method == "unRegisterHmgGeofences"{
// self.unRegisterHmgGeofences(result: result)
// }
//
// print("")
// }
// Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { (timer) in
// FlutterConstants.set()
// }
// }
//
//
//
// // Connect HMG Wifi and Internet
// func connectHMGInternetWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
//
// guard let pateintId = (methodCall.arguments as? [Any])?.first as? String
// else { return assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'") }
//
//
// HMG_Internet.shared.connect(patientId: pateintId) { (status, message) in
// result(status ? 1 : 0)
// if status{
// self.showMessage(title:"Congratulations", message:message)
// }else{
// self.showMessage(title:"Ooops,", message:message)
// }
// }
// }
//
// // Connect HMG-Guest for App Access
// func connectHMGGuestWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
// HMG_GUEST.shared.connect() { (status, message) in
// result(status ? 1 : 0)
// if status{
// self.showMessage(title:"Congratulations", message:message)
// }else{
// self.showMessage(title:"Ooops,", message:message)
// }
// }
// }
//
// func isHMGNetworkAvailable(methodCall:FlutterMethodCall ,result: @escaping FlutterResult) -> Bool{
// guard let ssid = methodCall.arguments as? String else {
// assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'")
// return false
// }
//
// let queue = DispatchQueue.init(label: "com.hmg.wifilist")
// NEHotspotHelper.register(options: nil, queue: queue) { (command) in
// print(command)
//
// if(command.commandType == NEHotspotHelperCommandType.filterScanList) {
// if let networkList = command.networkList{
// for network in networkList{
// print(network.ssid)
// }
// }
// }
// }
// return false
//
// }
//
//
// // Message Dailog
// func showMessage(title:String, message:String){
// DispatchQueue.main.async {
// let alert = UIAlertController(title: title, message: message, preferredStyle: .alert )
// alert.addAction(UIAlertAction(title: "OK", style: .destructive, handler: nil))
// mainViewController.present(alert, animated: true) {
//
// }
// }
// }
//
// // Register Geofence
// func registerHmgGeofences(result: @escaping FlutterResult){
// flutterMethodChannel?.invokeMethod("getGeoZones", arguments: nil){ geoFencesJsonString in
// if let jsonString = geoFencesJsonString as? String{
// let allZones = GeoZoneModel.list(from: jsonString)
// HMG_Geofence.shared().register(geoZones: allZones)
// result(true)
// }else{
// }
// }
// }
//
// // Register Geofence
// func unRegisterHmgGeofences(result: @escaping FlutterResult){
// HMG_Geofence.shared().unRegisterAll()
// result(true)
// }
//
//}

@ -9,14 +9,14 @@ import UIKit
class FlutterText{
class func with(key:String,completion: @escaping (String)->Void){
flutterMethodChannel?.invokeMethod("localizedValue", arguments: key, result: { (result) in
if let localized = result as? String{
completion(localized)
}else{
completion(key)
}
})
}
// class func with(key:String,completion: @escaping (String)->Void){
// flutterMethodChannel?.invokeMethod("localizedValue", arguments: key, result: { (result) in
// if let localized = result as? String{
// completion(localized)
// }else{
// completion(key)
// }
// })
// }
}

@ -5,57 +5,57 @@
// Created by ZiKambrani on 14/12/2020.
//
import UIKit
import NetworkExtension
import SystemConfiguration.CaptiveNetwork
fileprivate var openTok:OpenTok?
class OpenTokPlatformBridge : NSObject{
private var methodChannel:FlutterMethodChannel? = nil
private var mainViewController:MainFlutterVC!
private static var shared_:OpenTokPlatformBridge?
class func initialize(flutterViewController:MainFlutterVC, registrar:FlutterPluginRegistrar?){
shared_ = OpenTokPlatformBridge()
shared_?.mainViewController = flutterViewController
shared_?.openChannel()
openTok = OpenTok(mainViewController: flutterViewController, registrar: registrar)
}
func shared() -> OpenTokPlatformBridge{
assert((OpenTokPlatformBridge.shared_ != nil), "OpenTokPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
return OpenTokPlatformBridge.shared_!
}
private func openChannel(){
methodChannel = FlutterMethodChannel(name: "OpenTok-Platform-Bridge", binaryMessenger: mainViewController.binaryMessenger)
methodChannel?.setMethodCallHandler { (call, result) in
print("Called function \(call.method)")
switch(call.method) {
case "initSession":
openTok?.initSession(call: call, result: result)
case "swapCamera":
openTok?.swapCamera(call: call, result: result)
case "toggleAudio":
openTok?.toggleAudio(call: call, result: result)
case "toggleVideo":
openTok?.toggleVideo(call: call, result: result)
case "hangupCall":
openTok?.hangupCall(call: call, result: result)
default:
result(FlutterMethodNotImplemented)
}
print("")
}
}
}
//import UIKit
//import NetworkExtension
//import SystemConfiguration.CaptiveNetwork
//
//
//fileprivate var openTok:OpenTok?
//
//class OpenTokPlatformBridge : NSObject{
// private var methodChannel:FlutterMethodChannel? = nil
// private var mainViewController:MainFlutterVC!
// private static var shared_:OpenTokPlatformBridge?
//
// class func initialize(flutterViewController:MainFlutterVC, registrar:FlutterPluginRegistrar?){
// shared_ = OpenTokPlatformBridge()
// shared_?.mainViewController = flutterViewController
//
// shared_?.openChannel()
// openTok = OpenTok(mainViewController: flutterViewController, registrar: registrar)
// }
//
// func shared() -> OpenTokPlatformBridge{
// assert((OpenTokPlatformBridge.shared_ != nil), "OpenTokPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
// return OpenTokPlatformBridge.shared_!
// }
//
// private func openChannel(){
// methodChannel = FlutterMethodChannel(name: "OpenTok-Platform-Bridge", binaryMessenger: mainViewController.binaryMessenger)
// methodChannel?.setMethodCallHandler { (call, result) in
// print("Called function \(call.method)")
//
// switch(call.method) {
// case "initSession":
// openTok?.initSession(call: call, result: result)
//
// case "swapCamera":
// openTok?.swapCamera(call: call, result: result)
//
// case "toggleAudio":
// openTok?.toggleAudio(call: call, result: result)
//
// case "toggleVideo":
// openTok?.toggleVideo(call: call, result: result)
//
// case "hangupCall":
// openTok?.hangupCall(call: call, result: result)
//
// default:
// result(FlutterMethodNotImplemented)
// }
//
// print("")
// }
// }
//}

@ -210,7 +210,7 @@ class ApiClientImp implements ApiClient {
}
// body['TokenID'] = "@dm!n";
// body['PatientID'] = 1009156;
// body['PatientID'] = 1018977;
// body['PatientID'] = 53320;
// body['PatientTypeID'] = 1;
// body['PatientOutSA'] = 0;
@ -248,7 +248,7 @@ class ApiClientImp implements ApiClient {
if (kDebugMode) {
debugPrint("uri: ${Uri.parse(url.trim())}");
var requestBodyJSON = json.encode(body);
debugPrint("body: $requestBodyJSON", wrapWidth: 2048);
debugPrint("body: $requestBodyJSON", wrapWidth: 10000);
// log("body: $requestBodyJSON");
}

@ -6,7 +6,7 @@ import 'package:myfatoorah_flutter/myfatoorah_flutter.dart';
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
@ -316,7 +316,7 @@ class ApiConsts {
static String googleCloudStorageENTranslationFileBaseURL = "https://storage.googleapis.com/hmg-patientapp-translations";
// ************ static values for Api ****************
static final double appVersionID = 21.6;
static final double appVersionID = 21.7;
static final int appChannelId = 3;
static final String appIpAddress = "10.20.10.20";

@ -12,6 +12,7 @@ class DoctorMapper{
for (var element in doctorList) {
String? region = element.getRegionName(isArabic);
String? regionEng = element.getRegionName(false);
if (region == null) continue;
var regionDoctorList = regionList.registeredDoctorMap?.putIfAbsent(region, () => PatientDoctorAppointmentListByRegion());
@ -33,6 +34,8 @@ class DoctorMapper{
var newAppointment = PatientDoctorAppointmentList(
filterName:
element.getProjectCompleteNameWithLocale(isArabic: isArabic),
filterNameEng:
element.getProjectCompleteNameWithLocale(isArabic: false),
distanceInKMs: element.projectDistanceInKiloMeters.toString(),
projectTopName: element.projectTopName,
projectBottomName: element.projectBottomName,
@ -82,6 +85,7 @@ class DoctorMapper{
regionDoctorList?.hmgSize = regionDoctorList.hmgDoctorList?.length ?? 0;
regionList.registeredDoctorMap?[region] = regionDoctorList;
regionList.regionNameMap?[regionEng??""] = region;
}
return regionList;
@ -110,10 +114,19 @@ class DoctorMapper{
}
List<String>? keys = unsorted.registeredDoctorMap?.keys.toList();
keys?.sort();
final keys = unsorted.registeredDoctorMap?.keys.toList() ?? [];
if (keys.isEmpty) return unsorted;
keys.sort((a, b) {
final priorityA = _getRegionSortPriority(a);
final priorityB = _getRegionSortPriority(b);
if (priorityA != priorityB) return priorityA.compareTo(priorityB);
final aValue = a.toLowerCase();
final bValue = b.toLowerCase();
return aValue.compareTo(bValue);
});
if (keys == null) return unsorted;
Map<String, PatientDoctorAppointmentListByRegion> sortedMap = {};
for (var key in keys) {
sortedMap[key] = unsorted.registeredDoctorMap![key]!;
@ -122,6 +135,25 @@ class DoctorMapper{
return unsorted;
}
static int _getRegionSortPriority(String regionKey) {
final key = regionKey.trim().toLowerCase();
if (key.isEmpty) return 999;
if (key.startsWith('c') || key.contains('وسط') || key.contains('الوسط') || key.contains('المنطقة الوسطى')) {
return 0;
}
if (key.startsWith('w') || key.contains('غرب') || key.contains('الغربي') || key.contains('الغربية')) {
return 1;
}
if (key.startsWith('e') || key.contains('شرق') || key.contains('الشرقي') || key.contains('الشرقية')) {
return 2;
}
if (key.startsWith("u") || key.contains('الإمارات') || key.contains('امارات')) {
return 3;
}
return 999;
}
static Future<RegionList> getMappedHospitals(
List<HospitalsModel> hospitalList, {
bool isArabic = false, double lat = 0.0,double lng = 0.0
@ -129,6 +161,7 @@ class DoctorMapper{
final regionList = RegionList();
for (final hospital in hospitalList) {
final region = hospital.getRegionName(isArabic);
final regionEng = hospital.getRegionName(false);
if (region == null) continue;
final regionData = regionList.registeredDoctorMap?.putIfAbsent(
@ -152,6 +185,7 @@ class DoctorMapper{
} else {
final newEntry = PatientDoctorAppointmentList(
filterName: hospital.name,
filterNameEng: hospital.getName(false),
distanceInKMs: hospital.distanceInKilometers?.toString(),
projectTopName: hospital.name,
projectBottomName: hospital.name,
@ -196,6 +230,7 @@ class DoctorMapper{
regionData?.hmcSize = regionData.hmcDoctorList?.length ?? 0;
regionData?.hmgSize = regionData.hmgDoctorList?.length ?? 0;
regionList.registeredDoctorMap?[region] = regionData;
regionList.regionNameMap?[regionEng??""] = region;
}
return regionList;

@ -15,6 +15,7 @@ import 'package:flutter_callkit_incoming/entities/notification_params.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_ios_voip_kit_karmm/call_state_type.dart';
import 'package:flutter_ios_voip_kit_karmm/flutter_ios_voip_kit.dart';
import 'package:get_it/get_it.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/cache_consts.dart';
@ -22,9 +23,14 @@ 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/utils.dart';
import 'package:hmg_patient_app_new/features/notifications/models/resp_models/notification_response_model.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/notifications/notification_details_page.dart';
import 'package:hmg_patient_app_new/presentation/onboarding/splash_animation_screen.dart';
import 'package:hmg_patient_app_new/presentation/tele_consultation/zoom/call_screen.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
import 'package:huawei_push/huawei_push.dart' as h_push;
@ -311,7 +317,6 @@ class PushNotificationHandler {
final voIPKit = FlutterIOSVoIPKit.instance;
late Timer timeOutTimer;
bool isTalking = false;
var data = {
@ -383,7 +388,8 @@ class PushNotificationHandler {
) async {
try {
log('🎈 example: onDidRejectIncomingCall $uuid - $callerId');
timeOutTimer.cancel();
await voIPKit.endCall();
await FlutterCallkitIncoming.endAllCalls();
// Cleanup on reject with API call
if (_currentCallId != null) {
await _endCallAndCleanup(_currentCallId!, isDeclined: true);
@ -398,6 +404,9 @@ class PushNotificationHandler {
String callerId,
) async {
log('🎈 example: onDidAcceptIncomingCall $uuid - $callerId');
String zoomSessionID = callerId.split("_").sublist(0, callerId.split("_").length - 1).join("_");
await voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
await voIPKit.callConnected();
@ -406,21 +415,23 @@ class PushNotificationHandler {
_callTimeoutTimer = null;
_isCallInProgress = false;
_currentCallId = null;
await Future.delayed(Duration(seconds: 2)).then((val) async {
await Future.delayed(Duration(milliseconds: 2000)).then((val) async {
await voIPKit.endCall();
await FlutterCallkitIncoming.endAllCalls();
});
// Navigator.pushNamed(
// locator<NavigationService>().navigatorKey.currentContext!,
// "zoom_call_page",
// arguments: CallArguments("hoover-dam", "123", "Patient", "40", "1", false),
// );
// Navigator.pushNamed(navigatorKey.currentContext!, VIDEO_CALL_SCREEN,
// arguments: VideoArgus(
// reservationId: int.parse(callerId), token: null, isVideo: true));
// timeOutTimer.cancel();
await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, zoomSessionID);
Utils.removeFromPrefs(CacheConst.isAppOpenedFromCall);
// Navigator.of(GetIt.instance<NavigationService>().navigatorKey.currentContext!).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: LandingNavigation())));
Navigator.pushReplacementNamed(
// context,
GetIt.instance<NavigationService>().navigatorKey.currentContext!,
AppRoutes.zoomCallPage,
// arguments: CallArguments(appointmentID, "111", "Patient", "40", "1", true, 1),
arguments: CallArguments(zoomSessionID, "123", "Patient", "40", "0", true, int.parse("1")),
// arguments: CallArguments("SmallDailyStandup9875", "123", "Patient", "40", "0", false, int.parse(widget.incomingCallData!.appointmentNo!)),
);
};
}

@ -1,5 +1,6 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_markdown_plus/flutter_markdown_plus.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';
@ -486,6 +487,10 @@ extension EmailValidator on String {
: 'Poppins'),
),
);
Widget toText14Markdown() =>
MarkdownBody(
data: this,
);
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
String upper = "";

@ -277,6 +277,7 @@ class AuthenticationViewModel extends ChangeNotifier {
// Check if field is empty
if (nationalIdController.text.isEmpty) {
_nationalIdError = LocaleKeys.pleaseEnterAnationalID.tr();
print("the controller is emtpy so the error is $_nationalIdError");
notifyListeners();
return false;
}
@ -286,6 +287,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (cleanedId.length == 10) {
if (!Utils.isSAUDIIDValid(cleanedId)) {
_nationalIdError = LocaleKeys.enterValidNationalId.tr();
print("the controller is not valid so the error is $_nationalIdError");
notifyListeners();
return false;
}
@ -296,6 +298,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (cleanedId.length == 10) {
if (!ValidationUtils.validateIqama(nationalIdController.text)) {
_nationalIdError = LocaleKeys.pleaseEnterAValidIqamaID.tr();
print("the controller is not valid so the error is $_nationalIdError");
notifyListeners();
return false;
}
@ -305,6 +308,7 @@ class AuthenticationViewModel extends ChangeNotifier {
} else if (selectedCountrySignup == CountryEnum.unitedArabEmirates) {
if (!ValidationUtils.validateUaeNationalId(nationalIdController.text) && cleanedId.length == 15) {
_nationalIdError = LocaleKeys.pleaseEnterAValidNationalID.tr();
print("the controller is not valid so the error is $_nationalIdError");
notifyListeners();
return false;
}

@ -1,12 +1,15 @@
import 'dart:io';
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/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.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/features/book_appointments/models/resp_models/appointment_nearest_gate_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/dental_chief_complaints_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctor_profile_response_model.dart';
@ -757,6 +760,10 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
"InitialSlotDuration": initialSlotDuration,
"StrAppointmentDate": selectedDate,
"IsVirtual": false,
"DeviceType": Platform.isIOS ? 'iOS' : 'Android',
"DeviceToken": await Utils.getStringFromPrefs(CacheConst.pushToken),
"VoipToken": await Utils.getStringFromPrefs(CacheConst.voipToken),
"IsVoip": Platform.isIOS ? true : false,
"BookedBy": 102,
"VisitType": 1,
"VisitFor": 1,

@ -236,7 +236,7 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
Future<void> addNewCallRequestForImmediateLiveCare(String transID, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await immediateLiveCareRepo.addNewCallRequestForImmediateLiveCare(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!,
immediateLiveCareSelectedClinic.serviceID!, transID, liveCareSelectedCallType, false, _appState.deviceToken, await Utils.getStringFromPrefs(CacheConst.voipToken));
immediateLiveCareSelectedClinic.serviceID!, transID, liveCareSelectedCallType, false, await Utils.getStringFromPrefs(CacheConst.pushToken), await Utils.getStringFromPrefs(CacheConst.voipToken));
result.fold(
(failure) async {

@ -522,7 +522,7 @@ class LabViewModel extends ChangeNotifier {
labOrderResponseByAi = null;
navigationService.push(
MaterialPageRoute(
builder: (_) => LabResultDetails(recentLabResult: recentResult, testDescription: testDescription),
builder: (_) => LabResultDetails(recentLabResult: recentResult, testDescription: testDescription, labOrder: laborder),
),
);
notifyListeners();
@ -897,6 +897,8 @@ class LabViewModel extends ChangeNotifier {
}
// }
orderData["results"] = testResults;
orderData["clinic_name"] = labOrder.clinicDescription ?? "";
orderData["specialty_name"] = labOrder.speciality?.toString().replaceAll("[", "").replaceAll("]", "") ?? "";
results.add(orderData);
final result = await labRepo.getPatientAiOverViewLabOrders(payload: results, langId: langId);
@ -927,7 +929,7 @@ class LabViewModel extends ChangeNotifier {
// LoadingUtils.hideFullScreenLoader();
}
Future<void> getAiOverviewSingleLabResult({required int langId, required LabResult recentLabResult, required String loadingText}) async {
Future<void> getAiOverviewSingleLabResult({required int langId, required LabResult recentLabResult, required String loadingText, required PatientLabOrdersResponseModel labOrder}) async {
LoaderBottomSheet.showLoader(
loadingText: loadingText,
showCloseButton: true,
@ -942,9 +944,9 @@ class LabViewModel extends ChangeNotifier {
"UOM": recentLabResult.uOM ?? '',
"ReferanceRange": recentLabResult.referanceRange ?? '',
});
var speciality = labOrder.speciality?.toString().replaceAll("[", "").replaceAll("]", "") ?? "";
// var payload = {"patient_id": currentlySelectedPatientOrder!.patientID, "language_id": langId, "lab_results": results};
var payload = {"patient_id": getIt.get<AppState>().getAuthenticatedUser()!.patientId, "language_id": langId, "lab_results": results};
var payload = {"patient_id": getIt.get<AppState>().getAuthenticatedUser()!.patientId, "language_id": langId, "lab_results": results, "specialty_name": speciality, "clinic_name": labOrder.clinicDescription ?? ""};
final result = await labRepo.getPatientAiOverViewLabOrder(payload);
result.fold(
(failure) async {

@ -35,21 +35,15 @@ class LabOrdersResponseByAi {
class Analysis {
List<AiGeneratedAttribute>? aiGeneratedAttributes;
List<String>? aiPredictions;
List<AiRecommendation>? aiRecommendations;
List<String>? prevention;
String? rawMessage;
List<RiskFactor>? riskFactors;
List<dynamic>? suggestedDoctors;
String? summary;
Analysis({
this.aiGeneratedAttributes,
this.aiPredictions,
this.aiRecommendations,
this.prevention,
this.rawMessage,
this.riskFactors,
this.suggestedDoctors,
this.summary,
});
@ -60,22 +54,16 @@ class Analysis {
factory Analysis.fromJson(Map<String, dynamic> json) => Analysis(
aiGeneratedAttributes: json["ai_generated_attributes"] == null ? [] : List<AiGeneratedAttribute>.from(json["ai_generated_attributes"]!.map((x) => AiGeneratedAttribute.fromJson(x))),
aiPredictions: json["ai_predictions"] == null ? [] : List<String>.from(json["ai_predictions"]!.map((x) => x)),
aiRecommendations: json["ai_recommendations"] == null ? [] : List<AiRecommendation>.from(json["ai_recommendations"]!.map((x) => AiRecommendation.fromJson(x))),
prevention: json["prevention"] == null ? [] : List<String>.from(json["prevention"]!.map((x) => x)),
rawMessage: json["raw_message"],
riskFactors: json["riskFactors"] == null ? [] : List<RiskFactor>.from(json["riskFactors"]!.map((x) => RiskFactor.fromJson(x))),
suggestedDoctors: json["suggested_doctors"] == null ? [] : List<dynamic>.from(json["suggested_doctors"]!.map((x) => x)),
summary: json["summary"],
);
Map<String, dynamic> toJson() => {
"ai_generated_attributes": aiGeneratedAttributes == null ? [] : List<dynamic>.from(aiGeneratedAttributes!.map((x) => x.toJson())),
"ai_predictions": aiPredictions == null ? [] : List<dynamic>.from(aiPredictions!.map((x) => x)),
"ai_recommendations": aiRecommendations == null ? [] : List<dynamic>.from(aiRecommendations!.map((x) => x.toJson())),
"prevention": prevention == null ? [] : List<dynamic>.from(prevention!.map((x) => x)),
"raw_message": rawMessage,
"riskFactors": riskFactors == null ? [] : List<dynamic>.from(riskFactors!.map((x) => x.toJson())),
"suggested_doctors": suggestedDoctors == null ? [] : List<dynamic>.from(suggestedDoctors!.map((x) => x)),
"summary": summary,
};
}

@ -4,20 +4,14 @@ class LabOrderResponseByAi {
String? summary;
List<AiGeneratedAttribute>? aiGeneratedAttributes;
List<String>? aiPredictions;
List<AiRecommendation>? aiRecommendations;
List<RiskFactor>? riskFactors;
List<String>? prevention;
List<dynamic>? suggestedDoctors;
String? rawMessage;
LabOrderResponseByAi({
this.summary,
this.aiGeneratedAttributes,
this.aiPredictions,
this.aiRecommendations,
this.riskFactors,
this.prevention,
this.suggestedDoctors,
this.rawMessage,
});
@ -29,10 +23,7 @@ class LabOrderResponseByAi {
summary: json["summary"],
aiGeneratedAttributes: json["ai_generated_attributes"] == null ? [] : List<AiGeneratedAttribute>.from(json["ai_generated_attributes"]!.map((x) => AiGeneratedAttribute.fromJson(x))),
aiPredictions: json["ai_predictions"] == null ? [] : List<String>.from(json["ai_predictions"]!.map((x) => x)),
aiRecommendations: json["ai_recommendations"] == null ? [] : List<AiRecommendation>.from(json["ai_recommendations"]!.map((x) => AiRecommendation.fromJson(x))),
riskFactors: json["riskFactors"] == null ? [] : List<RiskFactor>.from(json["riskFactors"]!.map((x) => RiskFactor.fromJson(x))),
prevention: json["prevention"] == null ? [] : List<String>.from(json["prevention"]!.map((x) => x)),
suggestedDoctors: json["suggested_doctors"] == null ? [] : List<dynamic>.from(json["suggested_doctors"]!.map((x) => x)),
rawMessage: json["raw_message"],
);
@ -40,10 +31,7 @@ class LabOrderResponseByAi {
"summary": summary,
"ai_generated_attributes": aiGeneratedAttributes == null ? [] : List<dynamic>.from(aiGeneratedAttributes!.map((x) => x.toJson())),
"ai_predictions": aiPredictions == null ? [] : List<dynamic>.from(aiPredictions!.map((x) => x)),
"ai_recommendations": aiRecommendations == null ? [] : List<dynamic>.from(aiRecommendations!.map((x) => x.toJson())),
"riskFactors": riskFactors == null ? [] : List<dynamic>.from(riskFactors!.map((x) => x.toJson())),
"prevention": prevention == null ? [] : List<dynamic>.from(prevention!.map((x) => x)),
"suggested_doctors": suggestedDoctors == null ? [] : List<dynamic>.from(suggestedDoctors!.map((x) => x)),
"raw_message": rawMessage,
};
}

@ -45,7 +45,7 @@ class PatientLabOrdersResponseModel {
dynamic? projectNameN;
String? qR;
String? setupID;
// List<String>? speciality;
List<String>? speciality;
int? status;
String? statusDesc;
String? strOrderDate;
@ -98,7 +98,7 @@ class PatientLabOrdersResponseModel {
this.projectNameN,
this.qR,
this.setupID,
// this.speciality,
this.speciality,
this.status,
this.statusDesc,
this.strOrderDate,
@ -151,7 +151,7 @@ class PatientLabOrdersResponseModel {
projectNameN = json['ProjectNameN'];
qR = json['QR'];
setupID = json['SetupID'];
// speciality = json['Speciality'].cast<String>();
speciality = json['Speciality'] != null ? List<String>.from(json['Speciality']) : null;
status = json['Status'];
statusDesc = json['StatusDesc'];
strOrderDate = json['StrOrderDate'];
@ -211,7 +211,7 @@ class PatientLabOrdersResponseModel {
data['ProjectNameN'] = this.projectNameN;
data['QR'] = this.qR;
data['SetupID'] = this.setupID;
// data['Speciality'] = this.speciality;
data['Speciality'] = this.speciality;
data['Status'] = this.status;
data['StatusDesc'] = this.statusDesc;
data['StrOrderDate'] = this.strOrderDate;

@ -1,4 +1,3 @@
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
@ -236,6 +235,7 @@ class DoctorList {
class PatientDoctorAppointmentList {
String? filterName = "";
String? filterNameEng = "";
String? distanceInKMs = "";
List<DoctorsListResponseModel>? patientDoctorAppointmentList = [];
String? projectTopName = "";
@ -245,12 +245,14 @@ class PatientDoctorAppointmentList {
PatientDoctorAppointmentList(
{this.filterName,
this.filterNameEng,
this.distanceInKMs,
this.projectTopName,
this.projectBottomName,
DoctorsListResponseModel? patientDoctorAppointment,
HospitalsModel? model,
this.isHMC = false}) {
filterNameEng ??= filterName;
if (model != null) {
hospitalList.add(model);
}
@ -272,4 +274,5 @@ class PatientDoctorAppointmentListByRegion {
class RegionList {
Map<String, PatientDoctorAppointmentListByRegion?>? registeredDoctorMap = {};
Map<String, String>? regionNameMap = {};
}

@ -622,7 +622,7 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
"AcceptedBy": patientAppointmentHistoryResponseModel.doctorID,
"IsFlutter": true,
"DeviceToken": await Utils.getStringFromPrefs(CacheConst.pushToken),
"VoipToken": "", // TODO: Add VoIP Token functionality
"VoipToken": await Utils.getStringFromPrefs(CacheConst.voipToken),
"IsVoip": Platform.isIOS ? true : false
};

@ -39,8 +39,21 @@ class OccasionConfigModel {
/// Remote (or bundled asset path) image rendered as the occasion's main
/// header/banner (e.g. the National Day greeting banner), drawn at full
/// opacity on top of [backgroundOpacityImage].
final String? headerImage;
/// opacity on top of [backgroundOpacityImage]. Language-specific — pick
/// [headerImageEn] or [headerImageAr] based on the app's current locale
/// (the model itself doesn't know about locale).
///
/// Note: the remote JSON also still publishes a legacy `header_image` key
/// (mirrored to the English image) purely so old app versions that only
/// know that single key keep showing *a* banner until they update — this
/// model intentionally does not read that legacy key at all.
final String? headerImageEn;
final String? headerImageAr;
/// Redirection link opened when the corresponding header banner is
/// tapped. Null/empty means "do nothing" — the tap has no effect.
final String? headerImageLinkEn;
final String? headerImageLinkAr;
const OccasionConfigModel({
required this.key,
@ -50,7 +63,10 @@ class OccasionConfigModel {
this.primaryColorHex,
this.backgroundOpacityImage,
this.backgroundImageOpacity = 1.0,
this.headerImage,
this.headerImageEn,
this.headerImageAr,
this.headerImageLinkEn,
this.headerImageLinkAr,
});
/// Fully inert config — identical to the app's current/default look.
@ -62,20 +78,25 @@ class OccasionConfigModel {
primaryColorHex: null,
backgroundOpacityImage: null,
backgroundImageOpacity: 1.0,
headerImage: null,
headerImageEn: null,
headerImageAr: null,
headerImageLinkEn: null,
headerImageLinkAr: null,
);
factory OccasionConfigModel.fromJson(Map<String, dynamic> json) {
return OccasionConfigModel(
key: (json['key'] as String?) ?? 'none',
enabled: (json['enabled'] as bool?) ?? false,
// enabled: true,
startDate: _parseDate(json['start_date']),
endDate: _parseDate(json['end_date']),
primaryColorHex: json['primary_color'] as String?,
backgroundOpacityImage: json['background_opacity_image'] as String?,
backgroundImageOpacity: (json['background_image_opacity'] as num?)?.toDouble() ?? 1.0,
headerImage: json['header_image'] as String?,
headerImageEn: json['header_image_en'] as String?,
headerImageAr: json['header_image_ar'] as String?,
headerImageLinkEn: json['header_image_link_en'] as String?,
headerImageLinkAr: json['header_image_link_ar'] as String?,
);
}
@ -142,6 +163,11 @@ class OccasionConfigModel {
'primary_color': primaryColorHex,
'background_opacity_image': backgroundOpacityImage,
'background_image_opacity': backgroundImageOpacity,
'header_image': headerImage,
// Legacy key for old app versions — see [headerImageEn] doc comment.
'header_image': headerImageEn,
'header_image_en': headerImageEn,
'header_image_ar': headerImageAr,
'header_image_link_en': headerImageLinkEn,
'header_image_link_ar': headerImageLinkAr,
};
}

@ -53,7 +53,15 @@ class OccasionThemeViewModel extends ChangeNotifier {
/// The occasion's main header/banner image (e.g. National Day greeting
/// banner), rendered at full opacity. Null unless an occasion is active.
String? get headerImage => isOccasionActive ? _config.headerImage : null;
/// Language-specific — the widget picks [headerImageEn] or
/// [headerImageAr] based on the app's current locale.
String? get headerImageEn => isOccasionActive ? _config.headerImageEn : null;
String? get headerImageAr => isOccasionActive ? _config.headerImageAr : null;
/// Redirection link for the corresponding header banner — null/empty
/// means tapping the banner does nothing.
String? get headerImageLinkEn => isOccasionActive ? _config.headerImageLinkEn : null;
String? get headerImageLinkAr => isOccasionActive ? _config.headerImageLinkAr : null;
/// Lighter/translucent variant of the active occasion's primary color
/// (11% opacity) — e.g. for chip/badge backgrounds. Null unless an
@ -94,7 +102,7 @@ class OccasionThemeViewModel extends ChangeNotifier {
notifyListeners();
} catch (ex) {
_loggerService.logError('OccasionThemeViewModel.refresh error: $ex');
// Keep whatever config was already applied (cached/disabled) — never
// Keep whatever coFnfig was already applied (cached/disabled) — never
// let a remote-config failure change the app's appearance unexpectedly.
}
}

@ -36,7 +36,7 @@ class PatientPrescriptionsResponseModel {
int? noOfPatientsRate;
String? qR;
// List<String>? speciality;
List<String>? speciality;
String? strAppointmentDate;
PatientPrescriptionsResponseModel(
@ -76,7 +76,7 @@ class PatientPrescriptionsResponseModel {
this.nationalityFlagURL,
this.noOfPatientsRate,
this.qR,
// this.speciality,
this.speciality,
this.strAppointmentDate});
PatientPrescriptionsResponseModel.fromJson(Map<String, dynamic> json) {
@ -116,7 +116,7 @@ class PatientPrescriptionsResponseModel {
nationalityFlagURL = json['NationalityFlagURL'];
noOfPatientsRate = json['NoOfPatientsRate'];
qR = json['QR'];
// speciality = json['Speciality'].cast<String>();
speciality = json['Speciality'] != null ? List<String>.from(json['Speciality']) : null;
strAppointmentDate = json['StrAppointmentDate'];
}
@ -158,7 +158,7 @@ class PatientPrescriptionsResponseModel {
data['NationalityFlagURL'] = this.nationalityFlagURL;
data['NoOfPatientsRate'] = this.noOfPatientsRate;
data['QR'] = this.qR;
// data['Speciality'] = this.speciality;
data['Speciality'] = this.speciality;
data['StrAppointmentDate'] = this.strAppointmentDate;
return data;
}

@ -1,17 +1,13 @@
class PrescriptionAnalysisResponse {
String? prescriptionSummary;
List<MedicineAnalysis>? medicinesAnalysis;
List<String>? importantWarnings;
List<String>? medicineInteractions;
String? followUpNeeded;
List<String>? importantNotes;
int? languageId;
PrescriptionAnalysisResponse({
this.prescriptionSummary,
this.medicinesAnalysis,
this.importantWarnings,
this.medicineInteractions,
this.followUpNeeded,
this.importantNotes,
this.languageId,
});
@ -23,9 +19,7 @@ class PrescriptionAnalysisResponse {
medicinesAnalysis!.add(MedicineAnalysis.fromJson(v));
});
}
importantWarnings = json['important_warnings'] != null ? json['important_warnings'].cast<String>() : [];
medicineInteractions = json['medicine_interactions'] != null ? json['medicine_interactions'].cast<String>() : [];
followUpNeeded = json['follow_up_needed'];
importantNotes = json['important_notes'] != null ? json['important_notes'].cast<String>() : [];
languageId = json['language_id'];
}
@ -35,9 +29,7 @@ class PrescriptionAnalysisResponse {
if (medicinesAnalysis != null) {
data['medicines_analysis'] = medicinesAnalysis!.map((v) => v.toJson()).toList();
}
data['important_warnings'] = importantWarnings;
data['medicine_interactions'] = medicineInteractions;
data['follow_up_needed'] = followUpNeeded;
data['important_notes'] = importantNotes;
data['language_id'] = languageId;
return data;
}
@ -46,23 +38,20 @@ class PrescriptionAnalysisResponse {
class MedicineAnalysis {
String? medicineName;
String? benefit;
List<String>? commonSideEffects;
List<String>? seriousWarnings;
List<String>? allergyReactions;
String? storage;
MedicineAnalysis({
this.medicineName,
this.benefit,
this.commonSideEffects,
this.seriousWarnings,
this.allergyReactions,
this.storage,
});
MedicineAnalysis.fromJson(Map<String, dynamic> json) {
medicineName = json['medicine_name'];
benefit = json['benefit'];
commonSideEffects = json['common_side_effects'] != null ? json['common_side_effects'].cast<String>() : [];
seriousWarnings = json['serious_warnings'] != null ? json['serious_warnings'].cast<String>() : [];
allergyReactions = json['allergy_reactions'] != null ? json['allergy_reactions'].cast<String>() : [];
storage = json['storage'];
}
@ -70,8 +59,7 @@ class MedicineAnalysis {
final Map<String, dynamic> data = <String, dynamic>{};
data['medicine_name'] = medicineName;
data['benefit'] = benefit;
data['common_side_effects'] = commonSideEffects;
data['serious_warnings'] = seriousWarnings;
data['allergy_reactions'] = allergyReactions;
data['storage'] = storage;
return data;
}

@ -334,7 +334,7 @@ class PrescriptionsRepoImp implements PrescriptionsRepo {
'X-API-KEY': '9d9d2ac4c1fc302299dbb0fbb1b7fea1',
'accept': 'application/json',
},
body: {"medicines": payload, "language_id": langId},
body: payload,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},

@ -4,6 +4,7 @@ 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/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_allergies_response_model.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
@ -64,6 +65,7 @@ class PrescriptionsViewModel extends ChangeNotifier {
PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService, required this.navServices});
initPrescriptionsViewModel() {
isPrescriptionsDataNeedsReloading = true; // todo remove this
if (isPrescriptionsDataNeedsReloading) {
patientPrescriptionOrders.clear();
patientPrescriptionOrdersByClinic.clear();
@ -413,6 +415,8 @@ class PrescriptionsViewModel extends ChangeNotifier {
required int langId,
required String loadingText,
required Function(dynamic) onNavigate,
required PatientPrescriptionsResponseModel prescriptionResponseModel,
required List<GetAllergiesResponseModel> allergies,
}) async {
LoaderBottomSheet.showLoader(
loadingText: loadingText,
@ -424,6 +428,7 @@ class PrescriptionsViewModel extends ChangeNotifier {
// Prepare medicines payload
List<Map<String, dynamic>> medicines = [];
List<Map<String, dynamic>> allergiesForanalysis = [];
for (var prescription in prescriptions) {
if (prescription.itemDescription != null && prescription.itemDescription!.isNotEmpty) {
medicines.add({
@ -434,8 +439,22 @@ class PrescriptionsViewModel extends ChangeNotifier {
}
}
for (var allergy in allergies) {
allergiesForanalysis.add({
"description": allergy.description ?? "",
"remarks": allergy.remarks ?? "",
});
}
var payload = {
"medicines": medicines,
"patient_allergies": allergiesForanalysis,
"langId": langId,
"clinic_name": prescriptionResponseModel.clinicDescription ?? "",
"specialty_name": prescriptionResponseModel.speciality?.toString().replaceAll("[", "").replaceAll("]", "") ?? ""
};
final result = await prescriptionsRepo.getPrescriptionAiAnalysis(
payload: medicines,
payload: payload,
langId: langId,
);

@ -56,6 +56,7 @@ class PatientRadiologyResponseModel {
bool? isCVI;
bool? isRadMedicalReport;
dynamic vida3Id;
List<String>? speciality;
PatientRadiologyResponseModel(
{this.setupID,
@ -112,7 +113,9 @@ class PatientRadiologyResponseModel {
this.strOrderDate,
this.isCVI,
this.isRadMedicalReport,
this.vida3Id});
this.vida3Id,
this.speciality,
});
PatientRadiologyResponseModel.fromJson(Map<String, dynamic> json) {
setupID = json['SetupID'];
@ -170,6 +173,7 @@ class PatientRadiologyResponseModel {
isCVI = json['isCVI'];
isRadMedicalReport = json['isRadMedicalReport'];
vida3Id = json['vida3Id'];
speciality = json['Speciality'] != null ? List<String>.from(json['Speciality']) : [];
}
Map<String, dynamic> toJson() {
@ -229,6 +233,7 @@ class PatientRadiologyResponseModel {
data['isCVI'] = this.isCVI;
data['isRadMedicalReport'] = this.isRadMedicalReport;
data['vida3Id'] = this.vida3Id;
data['Speciality'] = this.speciality;
return data;
}
}

@ -5,7 +5,6 @@ class RadiologyAiAnalysisResponse {
String? labResults;
String? aiPredictions;
String? riskFactors;
String? prevention;
int? languageId;
RadiologyAiAnalysisResponse({
@ -13,7 +12,6 @@ class RadiologyAiAnalysisResponse {
this.labResults,
this.aiPredictions,
this.riskFactors,
this.prevention,
this.languageId,
});
@ -26,7 +24,6 @@ class RadiologyAiAnalysisResponse {
labResults: json["lab_results"],
aiPredictions: json["ai_predictions"],
riskFactors: json["riskFactors"],
prevention: json["prevention"],
languageId: json["language_id"],
);
@ -35,7 +32,6 @@ class RadiologyAiAnalysisResponse {
"lab_results": labResults,
"ai_predictions": aiPredictions,
"riskFactors": riskFactors,
"prevention": prevention,
"language_id": languageId,
};
}

@ -19,7 +19,7 @@ abstract class RadiologyRepo {
Future<Either<Failure, GenericApiModel<List<PatientRadiologyResponseModel>>>> getPatientRadiologyOrderByAppointment({required num appointmentNo, required num projectID});
Future<Either<Failure, GenericApiModel<RadiologyAiAnalysisResponse>>> getRadiologyAiAnalysis({required String reportData, required int langId,});
Future<Either<Failure, GenericApiModel<RadiologyAiAnalysisResponse>>> getRadiologyAiAnalysis({required PatientRadiologyResponseModel radiologyData, required int langId,});
}
class RadiologyRepoImp implements RadiologyRepo {
@ -238,10 +238,12 @@ class RadiologyRepoImp implements RadiologyRepo {
}
@override
Future<Either<Failure, GenericApiModel<RadiologyAiAnalysisResponse>>> getRadiologyAiAnalysis({required String reportData, required int langId}) async {
Future<Either<Failure, GenericApiModel<RadiologyAiAnalysisResponse>>> getRadiologyAiAnalysis({required PatientRadiologyResponseModel radiologyData, required int langId}) async {
Map<String, dynamic> payload = {
"text": reportData,
"language_id": langId
"text": radiologyData.reportData ?? "",
"language_id": langId,
"clinic_name": radiologyData.clinicDescription ?? "",
"specialty_name":radiologyData.speciality?.toString().replaceAll("[", "").replaceAll("]", "") ?? ""
};
try {

@ -229,7 +229,7 @@ class RadiologyViewModel extends ChangeNotifier {
}
Future<void> getRadiologyAiAnalysis({required String reportData, required String loadingText, required int langId}) async {
Future<void> getRadiologyAiAnalysis({required PatientRadiologyResponseModel radiologyData, required String loadingText, required int langId}) async {
LoaderBottomSheet.showLoader(
loadingText: loadingText,
showCloseButton: true,
@ -237,7 +237,7 @@ class RadiologyViewModel extends ChangeNotifier {
},
);
final result = await radiologyRepo.getRadiologyAiAnalysis(reportData: reportData, langId: langId);
final result = await radiologyRepo.getRadiologyAiAnalysis(radiologyData: radiologyData, langId: langId);
result.fold(
(failure) async {

@ -2039,5 +2039,7 @@ abstract class LocaleKeys {
static const unread = 'unread';
static const read = 'read';
static const pendingMedicalReportRequest = 'pendingMedicalReportRequest';
static const viewAttachment = 'viewAttachment';
static const AllergyReactions = 'AllergyReactions';
}

@ -26,6 +26,7 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_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/vital_sign_respo_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_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/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart';
@ -835,7 +836,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Navigator.of(context).push(
CustomPageRoute(
page: PrescriptionDetailPage(
isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel),
isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel,
allergies: Provider.of<MedicalFileViewModel>(context, listen: false).patientAllergiesList,
),
),
);
} else {

@ -14,7 +14,7 @@ class LandingPageData {
icon: AppAssets.emergency_services_icon,
title: getIt.get<AppState>().isArabic() ? LocaleKeys.services3 : LocaleKeys.emergency2,
subtitle: getIt.get<AppState>().isArabic() ? LocaleKeys.emergency2 : LocaleKeys.services3,
backgroundColor: AppColors.primaryRedColorBase,
backgroundColor: AppColors.primaryRedColor,
iconColor: Colors.white,
textColor: Colors.white,
isBold: true,
@ -77,7 +77,7 @@ class LandingPageData {
icon: AppAssets.emergency_services_icon,
title: getIt.get<AppState>().isArabic() ? LocaleKeys.services3 : LocaleKeys.emergency2,
subtitle: getIt.get<AppState>().isArabic() ? LocaleKeys.emergency2 : LocaleKeys.services3,
backgroundColor: AppColors.primaryRedColorBase,
backgroundColor: AppColors.primaryRedColor,
iconColor: Colors.white,
textColor: Colors.white,
isBold: true,

@ -27,6 +27,7 @@ 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/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/models/resp_models/patient_queue_details_response_model.dart';
@ -34,11 +35,13 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_vie
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/occasion_theme/occasion_theme_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_queue_page.dart';
import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
import 'package:hmg_patient_app_new/presentation/authentication/quick_login.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart';
@ -97,6 +100,7 @@ class _LandingPageState extends State<LandingPage> {
late EmergencyServicesViewModel emergencyServicesViewModel;
late TodoSectionViewModel todoSectionViewModel;
late NotificationsViewModel notificationsViewModel;
late MedicalFileViewModel medicalFileViewModel;
final SwiperController _controller = SwiperController();
@ -178,6 +182,7 @@ class _LandingPageState extends State<LandingPage> {
emergencyServicesViewModel.checkPatientERAdvanceBalance();
// myAppointmentsViewModel.getPatientAppointmentQueueDetails();
notificationsViewModel.initNotificationsViewModel();
// medicalFileViewModel.getPatientAllergiesList();
if (Utils.havePrivilege(122)) {
insuranceViewModel.initInsuranceProvider(isFromHomePage: true);
@ -229,6 +234,7 @@ class _LandingPageState extends State<LandingPage> {
emergencyServicesViewModel = Provider.of<EmergencyServicesViewModel>(context, listen: false);
todoSectionViewModel = Provider.of<TodoSectionViewModel>(context, listen: false);
notificationsViewModel = Provider.of<NotificationsViewModel>(context, listen: false);
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
appState = getIt.get<AppState>();
return PopScope(
canPop: false,
@ -240,9 +246,12 @@ class _LandingPageState extends State<LandingPage> {
// (no occasion, or occasion active but no banner configured) the
// page behaves exactly as it always has — banner (if any) scrolls
// inline with the rest of the content.
final hasStickyBanner = context.watch<OccasionThemeViewModel>().headerImage?.isNotEmpty ?? false;
final occasionThemeVmForBanner = context.watch<OccasionThemeViewModel>();
final hasStickyBanner =
(occasionThemeVmForBanner.headerImageEn?.isNotEmpty ?? false) || (occasionThemeVmForBanner.headerImageAr?.isNotEmpty ?? false);
log("hasStickyBanner: $hasStickyBanner");
log("occasionThemeVmForBanner.headerImageAr?.isNotEmpty: ${occasionThemeVmForBanner.headerImageAr?.isNotEmpty}");
return Stack(
children: [
// Renders nothing unless a remote-config occasion theme (e.g.
@ -295,7 +304,7 @@ class _LandingPageState extends State<LandingPage> {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false, isForTimeLine: true);
medicalFileViewModel.getPatientAllergiesList();
// Refresh Appointments Data
// habibWalletVM.initHabibWalletProvider();
// habibWalletVM.getPatientBalanceAmount();
@ -315,6 +324,7 @@ class _LandingPageState extends State<LandingPage> {
// appointmentRatingViewModel.getAppointmentDetails(
// appointmentRatingViewModel.appointmentRatedList.last.appointmentNo!,
// appointmentRatingViewModel.appointmentRatedList.last.projectID!,
// appointmentRatingViewModel.appointmentRatedList.last.clinicID!,
// onSuccess: ((response) {
// appointmentRatingViewModel.setClinicOrDoctor(false);
// appointmentRatingViewModel.setTitle(LocaleKeys.rateDoctor.tr(context: context));

@ -1,16 +1,20 @@
import 'dart:developer';
import 'package:cached_network_image/cached_network_image.dart';
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/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/occasion_theme/occasion_theme_view_model.dart';
import 'package:provider/provider.dart';
/// Renders the occasion's main header/banner (`header_image`, e.g. the
/// National Day greeting banner) inline at the top of the landing page's
/// scrollable content, drawn at full opacity.
/// Renders the occasion's main header/banner (`header_image_en`/
/// `header_image_ar`, e.g. the National Day greeting banner) inline at the
/// top of the landing page's scrollable content, drawn at full opacity.
/// Picks the English or Arabic image based on the app's current locale.
/// Tapping it opens `header_image_link_en`/`header_image_link_ar` (the
/// matching language's link) via [Utils.openWebView] — if that link is
/// null/empty, the tap does nothing.
///
/// Fully data-driven: when no occasion is active (the default), this widget
/// renders nothing and takes zero space — the existing layout/UI is
@ -25,14 +29,19 @@ class OccasionBannerWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Consumer<OccasionThemeViewModel>(
builder: (context, occasionThemeVm, _) {
final headerImageUrl = occasionThemeVm.headerImage;
final isArabic = context.locale.languageCode == 'ar';
final headerImageUrl = isArabic ? occasionThemeVm.headerImageAr : occasionThemeVm.headerImageEn;
final headerLinkUrl = isArabic ? occasionThemeVm.headerImageLinkAr : occasionThemeVm.headerImageLinkEn;
final hasHeaderImage = occasionThemeVm.isOccasionActive && (headerImageUrl?.isNotEmpty ?? false);
if (!hasHeaderImage) {
return const SizedBox(height: 0);
}
return buildOccasionImage(headerImageUrl!).paddingOnly(bottom: 16.h);
return GestureDetector(
onTap: (headerLinkUrl?.isNotEmpty ?? false) ? () => Utils.openWebView(url: headerLinkUrl!) : null,
child: buildOccasionImage(headerImageUrl!).paddingOnly(bottom: 16.h),
);
},
);
}

@ -51,7 +51,7 @@ class AiAnalysisWidget extends StatelessWidget {
if (data.summary != null && data.summary!.isNotEmpty) ...[
LocaleKeys.suggestion.tr().toText16(weight: FontWeight.w700, color: AppColors.blackColor),
SizedBox(height: 8.h),
data.summary!.toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
data.summary!.toText14Markdown(),
SizedBox(height: 16.h),
Divider(color: AppColors.dividerColor, thickness: 1),
SizedBox(height: 16.h),
@ -64,12 +64,6 @@ class AiAnalysisWidget extends StatelessWidget {
Divider(color: AppColors.dividerColor, thickness: 1),
SizedBox(height: 16.h),
],
if (data.prevention != null && data.prevention!.isNotEmpty) ...[
LocaleKeys.prevention.tr().toText16(weight: FontWeight.w700, color: AppColors.blackColor),
SizedBox(height: 12.h),
...data.prevention!.map((item) => _buildBulletItem(item)),
SizedBox(height: 20.h),
],
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

@ -55,7 +55,7 @@ class _LabAiAnalysisDetailedPageState extends State<LabAiAnalysisDetailedPage> {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r, side: BorderSide(width: 1, color: Color(0xFF0B85F7))),
padding: EdgeInsets.all(16.r),
child: (analysis.summary ?? "").toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
child: (analysis.summary ?? "").toText14Markdown(),
),
SizedBox(height: 8.h),
],
@ -109,54 +109,54 @@ class _LabAiAnalysisDetailedPageState extends State<LabAiAnalysisDetailedPage> {
);
}
// AI Recommendations Section
if (analysis.aiRecommendations != null && analysis.aiRecommendations!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor:Colors.transparent ,
title: LocaleKeys.suggestions.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r),
padding: EdgeInsets.all(16.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: analysis.aiRecommendations!.asMap().entries.map((entry) {
final rec = entry.value;
final isLast = entry.key == analysis.aiRecommendations!.length - 1;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (rec.priority != null) ...[
Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration(color: _getPriorityColor(rec.priority), borderRadius: BorderRadius.circular(4.r)),
child: rec.priority!.toText12(isBold: true, color: _getPriorityTextColor(rec.priority)),
),
SizedBox(height: 8.h),
],
(rec.recommendation ?? "").toText14(
color: AppColors.textColorLight,
height: 1.5,
weight: FontWeight.w400,
),
if (!isLast) ...[
SizedBox(height: 12.h),
Divider(color: AppColors.dividerColor, thickness: 1),
SizedBox(height: 12.h),
],
],
);
}).toList(),
),
),
SizedBox(height: 8.h),
],
),
);
}
// // AI Recommendations Section
// if (analysis.aiRecommendations != null && analysis.aiRecommendations!.isNotEmpty) {
// expandableItems.add(
// ExpandableListItem(
// backgroundColor: Colors.transparent,
// expandedBackgroundColor:Colors.transparent ,
// title: LocaleKeys.suggestions.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
// children: [
// SizedBox(height: 10.h),
// Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r),
// padding: EdgeInsets.all(16.r),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: analysis.aiRecommendations!.asMap().entries.map((entry) {
// final rec = entry.value;
// final isLast = entry.key == analysis.aiRecommendations!.length - 1;
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// if (rec.priority != null) ...[
// Container(
// padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
// decoration: BoxDecoration(color: _getPriorityColor(rec.priority), borderRadius: BorderRadius.circular(4.r)),
// child: rec.priority!.toText12(isBold: true, color: _getPriorityTextColor(rec.priority)),
// ),
// SizedBox(height: 8.h),
// ],
// (rec.recommendation ?? "").toText14(
// color: AppColors.textColorLight,
// height: 1.5,
// weight: FontWeight.w400,
// ),
// if (!isLast) ...[
// SizedBox(height: 12.h),
// Divider(color: AppColors.dividerColor, thickness: 1),
// SizedBox(height: 12.h),
// ],
// ],
// );
// }).toList(),
// ),
// ),
// SizedBox(height: 8.h),
// ],
// ),
// );
// }
// Risk Factors Section
if (analysis.riskFactors != null && analysis.riskFactors!.isNotEmpty) {
@ -229,28 +229,28 @@ class _LabAiAnalysisDetailedPageState extends State<LabAiAnalysisDetailedPage> {
);
}
// Prevention Section
if (analysis.prevention != null && analysis.prevention!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor:Colors.transparent ,
title: LocaleKeys.prevention.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r, side: BorderSide(width: 1, color: Color(0xFF18C273))),
padding: EdgeInsets.all(16.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: analysis.prevention!.map((prevention) => _buildBulletItem(prevention)).toList(),
),
),
SizedBox(height: 8.h),
],
),
);
}
// // Prevention Section
// if (analysis.prevention != null && analysis.prevention!.isNotEmpty) {
// expandableItems.add(
// ExpandableListItem(
// backgroundColor: Colors.transparent,
// expandedBackgroundColor:Colors.transparent ,
// title: LocaleKeys.prevention.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
// children: [
// SizedBox(height: 10.h),
// Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r, side: BorderSide(width: 1, color: Color(0xFF18C273))),
// padding: EdgeInsets.all(16.r),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: analysis.prevention!.map((prevention) => _buildBulletItem(prevention)).toList(),
// ),
// ),
// SizedBox(height: 8.h),
// ],
// ),
// );
// }
// // Suggested Doctors Section
// if (analysis.suggestedDoctors != null && analysis.suggestedDoctors!.isNotEmpty) {

@ -25,14 +25,16 @@ import 'package:hmg_patient_app_new/widgets/graph/custom_graph.dart';
import 'package:provider/provider.dart' show Consumer, Provider, ReadContext, Selector;
import '../../../core/common_models/data_points.dart';
import '../../../features/lab/models/resp_models/patient_lab_orders_response_model.dart';
import '../../../widgets/common_bottom_sheet.dart' show showCommonBottomSheetWithoutHeight;
import 'dart:ui' as ui;
class LabResultDetails extends StatefulWidget {
final LabResult recentLabResult;
final String? testDescription;
final PatientLabOrdersResponseModel labOrder;
const LabResultDetails({super.key, required this.recentLabResult, required this.testDescription});
const LabResultDetails({super.key, required this.recentLabResult, required this.testDescription, required this.labOrder});
@override
State<LabResultDetails> createState() => _LabResultDetailsState();
@ -197,7 +199,7 @@ class _LabResultDetailsState extends State<LabResultDetails> {
onOkPressed: () {
context.pop();
labViewModel.getAiOverviewSingleLabResult(
langId: appState.getLanguageID(), recentLabResult: recentLabResult, loadingText: LocaleKeys.loadingAIAnalysis.tr(context: context));
langId: appState.getLanguageID(), recentLabResult: recentLabResult, loadingText: LocaleKeys.loadingAIAnalysis.tr(context: context), labOrder: widget.labOrder);
},
onCancelPressed: () {
context.pop();

@ -972,7 +972,11 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
prescriptionVM.setPrescriptionsDetailsLoading();
Navigator.of(context).push(
CustomPageRoute(
page: PrescriptionDetailPage(isFromAppointments: false, prescriptionsResponseModel: prescriptionVM.patientPrescriptionOrders[index]),
page: PrescriptionDetailPage(
isFromAppointments: false,
prescriptionsResponseModel: prescriptionVM.patientPrescriptionOrders[index],
allergies: Provider.of<MedicalFileViewModel>(context, listen: false).patientAllergiesList,
),
),
);
}),

@ -159,7 +159,8 @@ class _MedicalReportsPageState extends State<MedicalReportsPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomButton(
text: "${medicalFileVM.patientMedicalReportsViewList[index].medicalReportsList!.length} Reports Available",
text:
"${medicalFileVM.patientMedicalReportsViewList[index].medicalReportsList!.length} ${medicalFileVM.patientMedicalReportsViewList[index].medicalReportsList!.length > 1 ? 'Reports' : 'Report'}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,

@ -476,7 +476,7 @@ class _FamilyCardsState extends State<FamilyCards> {
AppCustomChipWidget(
icon: AppAssets.file_icon,
richText: "${profile.responseId}".toText10(isBold: true),
labelPadding: EdgeInsetsDirectional.only(start: -10.w, end: 5.w),
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 5.w),
),
SizedBox(width: 5.h,),
AppCustomChipWidget(

@ -89,12 +89,12 @@ class _PrescriptionAiAnalysisDetailedPageState extends State<PrescriptionAiAnaly
}
// Important Warnings Section
if (analysis.importantWarnings != null && analysis.importantWarnings!.isNotEmpty) {
if (analysis.importantNotes != null && analysis.importantNotes!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor: Colors.transparent,
title: LocaleKeys.importantWarnings.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
title: LocaleKeys.notes.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
SizedBox(
@ -108,14 +108,12 @@ class _PrescriptionAiAnalysisDetailedPageState extends State<PrescriptionAiAnaly
padding: EdgeInsets.all(16.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: analysis.importantWarnings!.map((warning) {
children: analysis.importantNotes!.map((warning) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.warning_amber_rounded, color: Color(0xFFFF5252), size: 18.w),
SizedBox(width: 8.w),
Expanded(child: warning.toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400)),
],
),
@ -130,73 +128,73 @@ class _PrescriptionAiAnalysisDetailedPageState extends State<PrescriptionAiAnaly
);
}
// Medicine Interactions Section
if (analysis.medicineInteractions != null && analysis.medicineInteractions!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor: Colors.transparent,
title: LocaleKeys.medicineInteractions.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
SizedBox(
width: double.infinity,
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
side: BorderSide(width: 1, color: Color(0xFFFFAF15)),
),
padding: EdgeInsets.all(16.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: analysis.medicineInteractions!.map((interaction) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.info_outline, color: Color(0xFFFFAF15), size: 18.w),
SizedBox(width: 8.w),
Expanded(child: interaction.toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400)),
],
),
);
}).toList(),
),
),
),
SizedBox(height: 8.h),
],
),
);
}
// if (analysis.medicineInteractions != null && analysis.medicineInteractions!.isNotEmpty) {
// expandableItems.add(
// ExpandableListItem(
// backgroundColor: Colors.transparent,
// expandedBackgroundColor: Colors.transparent,
// title: LocaleKeys.medicineInteractions.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
// children: [
// SizedBox(height: 10.h),
// SizedBox(
// width: double.infinity,
// child: Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
// color: AppColors.whiteColor,
// borderRadius: 12.r,
// side: BorderSide(width: 1, color: Color(0xFFFFAF15)),
// ),
// padding: EdgeInsets.all(16.r),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: analysis.medicineInteractions!.map((interaction) {
// return Padding(
// padding: EdgeInsets.only(bottom: 8.h),
// child: Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Icon(Icons.info_outline, color: Color(0xFFFFAF15), size: 18.w),
// SizedBox(width: 8.w),
// Expanded(child: interaction.toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400)),
// ],
// ),
// );
// }).toList(),
// ),
// ),
// ),
// SizedBox(height: 8.h),
// ],
// ),
// );
// }
// Follow-up Needed Section
if (analysis.followUpNeeded != null && analysis.followUpNeeded!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor: Colors.transparent,
title: LocaleKeys.followUpNeeded.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
SizedBox(
width: double.infinity,
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
side: BorderSide(width: 1, color: AppColors.primaryRedColor),
),
padding: EdgeInsets.all(16.r),
child: (analysis.followUpNeeded ?? "").toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
),
),
SizedBox(height: 8.h),
],
),
);
}
// if (analysis.followUpNeeded != null && analysis.followUpNeeded!.isNotEmpty) {
// expandableItems.add(
// ExpandableListItem(
// backgroundColor: Colors.transparent,
// expandedBackgroundColor: Colors.transparent,
// title: LocaleKeys.followUpNeeded.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
// children: [
// SizedBox(height: 10.h),
// SizedBox(
// width: double.infinity,
// child: Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
// color: AppColors.whiteColor,
// borderRadius: 12.r,
// side: BorderSide(width: 1, color: AppColors.primaryRedColor),
// ),
// padding: EdgeInsets.all(16.r),
// child: (analysis.followUpNeeded ?? "").toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
// ),
// ),
// SizedBox(height: 8.h),
// ],
// ),
// );
// }
return Column(
children: [
@ -263,12 +261,12 @@ class _PrescriptionAiAnalysisDetailedPageState extends State<PrescriptionAiAnaly
],
// Common Side Effects
if (medicine.commonSideEffects != null && medicine.commonSideEffects!.isNotEmpty) ...[
if (medicine.allergyReactions != null && medicine.allergyReactions!.isNotEmpty) ...[
_buildInfoRow(
icon: Icons.warning_amber_rounded,
iconColor: Color(0xFFFFAF15),
title: LocaleKeys.commonSideEffects.tr(context: context),
content: medicine.commonSideEffects!.join(', '),
title: LocaleKeys.AllergyReactions.tr(context: context),
content: medicine.allergyReactions!.join(', '),
),
SizedBox(height: 12.h),
],

@ -12,6 +12,7 @@ import 'package:hmg_patient_app_new/core/utils/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/book_appointments/models/resp_models/get_allergies_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
@ -32,10 +33,11 @@ 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});
PrescriptionDetailPage({super.key, required this.prescriptionsResponseModel, required this.isFromAppointments, required this.allergies});
PatientPrescriptionsResponseModel prescriptionsResponseModel;
bool isFromAppointments = false;
List<GetAllergiesResponseModel> allergies;
@override
State<PrescriptionDetailPage> createState() => _PrescriptionDetailPageState();
@ -318,6 +320,8 @@ class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> {
prescriptionsViewModel.setIsPrescriptionAIAnalysisNeedsToBeShown(true);
prescriptionsViewModel.getPrescriptionAiAnalysis(
prescriptions: prescriptionsViewModel.prescriptionDetailsList,
prescriptionResponseModel: widget.prescriptionsResponseModel,
allergies: widget.allergies,
langId: getIt.get<AppState>().getLanguageID(),
loadingText: LocaleKeys.loadingAIAnalysisPrescription.tr(context: context),
onNavigate: (data) {

@ -11,6 +11,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/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_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';
@ -37,6 +38,7 @@ class _PrescriptionsListPageState extends State<PrescriptionsListPage> {
int? expandedIndex;
late PrescriptionsViewModel prescriptionsViewModel;
late MedicalFileViewModel medicalFileViewModel;
@override
void initState() {
@ -50,6 +52,7 @@ class _PrescriptionsListPageState extends State<PrescriptionsListPage> {
Widget build(BuildContext context) {
AppState appState = getIt.get<AppState>();
prescriptionsViewModel = Provider.of<PrescriptionsViewModel>(context, listen: false);
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
@ -243,6 +246,7 @@ class _PrescriptionsListPageState extends State<PrescriptionsListPage> {
page: PrescriptionDetailPage(
prescriptionsResponseModel: model.patientPrescriptionOrders[index],
isFromAppointments: false,
allergies: Provider.of<MedicalFileViewModel>(context, listen: false).patientAllergiesList,
),
),
);
@ -550,6 +554,7 @@ class _PrescriptionsListPageState extends State<PrescriptionsListPage> {
CustomPageRoute(
page: PrescriptionDetailPage(
prescriptionsResponseModel: model.patientPrescriptionOrders[index],
allergies: medicalFileViewModel.patientAllergiesList,
isFromAppointments: false,
),
),

@ -758,7 +758,7 @@ class _FamilyCardWidgetState extends State<FamilyCardWidget> {
height: isFoldable ? 50.h : 45.h,
fontSize: 14.f,
).paddingOnly(top: 12.h, right: 16.w, left: 16.w, bottom: 16.h);
}
}
Widget _buildNonParentUserButton(int? superUserId) {
final canSwitchBack = superUserId != null && superUserId == widget.profile.responseId;

@ -45,7 +45,7 @@ class _RadiologyAiAnalysisDetailedPageState extends State<RadiologyAiAnalysisDet
// Parse string fields into lists
final predictions = _parseStringToList(analysis.aiPredictions);
final preventions = _parseStringToList(analysis.prevention);
// final preventions = _parseStringToList(analysis.prevention);
final riskFactorsText = _parseStringToList(analysis.riskFactors);
// Summary Section
@ -174,32 +174,32 @@ class _RadiologyAiAnalysisDetailedPageState extends State<RadiologyAiAnalysisDet
);
}
// Prevention Section
if (preventions.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor: Colors.transparent,
title: LocaleKeys.prevention.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
side: BorderSide(width: 1, color: Color(0xFF18C273)),
),
padding: EdgeInsets.all(16.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: preventions.map((prevention) => _buildBulletItem(prevention)).toList(),
),
),
SizedBox(height: 8.h),
],
),
);
}
// // Prevention Section
// if (preventions.isNotEmpty) {
// expandableItems.add(
// ExpandableListItem(
// backgroundColor: Colors.transparent,
// expandedBackgroundColor: Colors.transparent,
// title: LocaleKeys.prevention.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
// children: [
// SizedBox(height: 10.h),
// Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
// color: AppColors.whiteColor,
// borderRadius: 12.r,
// side: BorderSide(width: 1, color: Color(0xFF18C273)),
// ),
// padding: EdgeInsets.all(16.r),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: preventions.map((prevention) => _buildBulletItem(prevention)).toList(),
// ),
// ),
// SizedBox(height: 8.h),
// ],
// ),
// );
// }
return Column(
children: [

@ -27,7 +27,7 @@ class RadiologyAiAnalysisWidget extends StatelessWidget {
Widget build(BuildContext context) {
// Parse the string fields into lists
final predictions = _parseStringToList(data.aiPredictions);
final preventions = _parseStringToList(data.prevention);
// final preventions = _parseStringToList(data.prevention);
return Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(24.r), gradient: AppColors.aiLinearGradient),
@ -69,12 +69,12 @@ class RadiologyAiAnalysisWidget extends StatelessWidget {
Divider(color: AppColors.dividerColor, thickness: 1),
SizedBox(height: 16.h),
],
if (preventions.isNotEmpty) ...[
LocaleKeys.prevention.tr().toText16(weight: FontWeight.w700, color: AppColors.blackColor),
SizedBox(height: 12.h),
...preventions.map((item) => _buildBulletItem(item)),
SizedBox(height: 20.h),
],
// if (preventions.isNotEmpty) ...[
// LocaleKeys.prevention.tr().toText16(weight: FontWeight.w700, color: AppColors.blackColor),
// SizedBox(height: 12.h),
// ...preventions.map((item) => _buildBulletItem(item)),
// SizedBox(height: 20.h),
// ],
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

@ -232,7 +232,7 @@ class _RadiologyResultPageState extends State<RadiologyResultPage> {
onOkPressed: () {
context.pop();
radiologyViewModel.getRadiologyAiAnalysis(
reportData: widget.patientRadiologyResponseModel.reportData ?? "",
radiologyData: widget.patientRadiologyResponseModel,
loadingText: LocaleKeys.loadingAIAnalysis.tr(context: context),
langId: _appState.getLanguageID(),
);

@ -327,6 +327,9 @@ class _CallScreenState extends State<CallScreen> {
// If no remote users remain, the other participant has left — end the session
if (remoteUserList == null || remoteUserList.isEmpty) {
if (Platform.isIOS) {
await voIPKit.endCall();
}
await zoom.leaveSession(true);
final navContext = GetIt.instance<NavigationService>().navigatorKey.currentContext;
if (navContext != null && Navigator.canPop(navContext)) {
@ -1297,6 +1300,9 @@ class _CallScreenState extends State<CallScreen> {
// }
void onLeaveSession(bool isEndSession) async {
if (Platform.isIOS) {
await voIPKit.endCall();
}
await zoom.leaveSession(isEndSession);
Navigator.pushAndRemoveUntil(
context,
@ -1547,7 +1553,7 @@ class _CallScreenState extends State<CallScreen> {
multiCameraIndex: "0",
videoAspect: VideoAspect.Original,
fullScreen: false,
resolution: VideoResolution.Resolution180,
resolution: VideoResolution.Resolution720,
),
),
);

@ -45,7 +45,7 @@ class RemoteConfigServiceImp implements RemoteConfigService {
// Release/profile builds keep a 1-hour minimum interval —
// balances timely occasion-theme rollout against not hammering
// Remote Config across the whole user base.
minimumFetchInterval: kDebugMode ? Duration.zero : const Duration(hours: 1),
minimumFetchInterval: kDebugMode ? Duration.zero : const Duration(minutes: 15),
),
);

@ -1404,10 +1404,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.19"
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:

@ -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: 4.6.046+1
version: 4.6.1004+40501004
version: 4.6.050+1
#version: 4.6.1004+40501004
environment:
sdk: ">=3.6.0 <4.0.0"
@ -25,10 +25,11 @@ dependencies:
easy_localization: ^3.0.8
fluttertoast: ^8.2.12
flutter_rating_bar: ^4.0.1
firebase_messaging: ^16.7.0
# firebase_messaging: any
firebase_core: ^4.15.0
# firebase_core: ^3.13.1
firebase_messaging: 17.0.0
firebase_core: 5.0.0
firebase_analytics: 13.0.0
firebase_crashlytics: 6.0.0
firebase_remote_config: 7.0.0
permission_handler: ^12.0.1
flutter_local_notifications: ^19.4.1
timezone: ^0.10.0
@ -63,14 +64,11 @@ dependencies:
geolocator: ^14.0.2
dropdown_search: ^6.0.2
google_maps_flutter: ^2.13.1
flutter_zoom_videosdk: 2.1.10
flutter_zoom_videosdk: 2.6.0
dart_jsonwebtoken: ^3.2.0
dartz: ^0.10.1
equatable: ^2.0.7
google_api_availability: ^5.0.1
firebase_analytics: ^12.6.0
firebase_crashlytics: ^5.4.0
firebase_remote_config: ^6.7.0
jiffy: ^6.4.3
# hijri_gregorian_calendar:
# path: /Users/aamir/StudioProjects/hijri_gregorian_calendar
@ -94,7 +92,7 @@ dependencies:
image_picker_android: ^0.8.13+16
image_picker_platform_interface: ^2.10.0
location: ^8.0.1
location: ^10.0.2
gms_check: ^1.0.4
huawei_location: ^6.14.2+301
huawei_health: ^6.15.0+300
@ -116,6 +114,7 @@ dependencies:
cloudflare_turnstile: ^3.7.2
freerasp: ^8.2.1
safe_device: ^1.4.1
flutter_markdown_plus: ^1.0.12
myfatoorah_flutter: ^3.3.2
dev_dependencies:

Loading…
Cancel
Save