From d337e0c94b2f4319cd281b7c47e98f29426c25e4 Mon Sep 17 00:00:00 2001 From: taha Date: Thu, 1 Oct 2026 17:19:10 +0300 Subject: [PATCH 01/15] chore: update analysis options, change app environment to preProd, and update package dependencies --- analysis_options.yaml | 5 + ios/Runner.xcodeproj/project.pbxproj | 42 --------- .../xcshareddata/swiftpm/Package.resolved | 42 +++------ .../xcshareddata/swiftpm/Package.resolved | 38 ++------ ios/Runner/AppDelegate.swift | 44 ++++----- lib/core/api_consts.dart | 2 +- .../authentication_view_model.dart | 4 + pubspec.lock | 94 +++++++++---------- 8 files changed, 101 insertions(+), 170 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 0d290213..0d87f43e 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -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: diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index c0d2bb74..cd11bd9a 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -12,20 +12,8 @@ 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 */; }; 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 +37,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 76B1D2542F91BF8000DBBD1B /* PenguinINRenderer.xcframework in Embed Frameworks */, - 76B1D2522F91BF8000DBBD1B /* Penguin.xcframework in Embed Frameworks */, - 76B1D2562F91BF8000DBBD1B /* PenNavUI.xcframework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -77,19 +62,10 @@ 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 478CFA952E6E20A60064F3D7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 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 = ""; }; - 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = ""; }; - 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = ""; }; - 61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = ""; }; - 61243B452EC5FA3700D46FA0 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = ""; }; - 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = ""; }; 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = ring_30Sec.caf; sourceTree = ""; }; - 76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = ""; }; - 76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenguinINRenderer.xcframework; path = Frameworks/PenguinINRenderer.xcframework; sourceTree = ""; }; - 76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = ""; }; 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 = ""; }; @@ -112,9 +88,6 @@ buildActionMask = 2147483647; files = ( 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 */, ); runOnlyForDeploymentPostprocessing = 0; @@ -133,7 +106,6 @@ 61243B412EC5FA3700D46FA0 /* Helper */ = { isa = PBXGroup; children = ( - 61243B3D2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift */, ); path = Helper; sourceTree = ""; @@ -141,11 +113,6 @@ 61243B472EC5FA3700D46FA0 /* Penguin */ = { isa = PBXGroup; children = ( - 61243B422EC5FA3700D46FA0 /* PenguinModel.swift */, - 61243B432EC5FA3700D46FA0 /* PenguinNavigator.swift */, - 61243B442EC5FA3700D46FA0 /* PenguinPlugin.swift */, - 61243B452EC5FA3700D46FA0 /* PenguinView.swift */, - 61243B462EC5FA3700D46FA0 /* PenguinViewFactory.swift */, ); path = Penguin; sourceTree = ""; @@ -153,9 +120,6 @@ 766D8CB22EC60BE600D05E07 /* Frameworks */ = { isa = PBXGroup; children = ( - 76B1D24E2F91BF8000DBBD1B /* Penguin.xcframework */, - 76B1D24F2F91BF8000DBBD1B /* PenguinINRenderer.xcframework */, - 76B1D2502F91BF8000DBBD1B /* PenNavUI.xcframework */, 76B714CF300E58B1004DE37A /* WidgetKit.framework */, 76B714D1300E58B1004DE37A /* SwiftUI.framework */, 56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */, @@ -444,12 +408,6 @@ buildActionMask = 2147483647; files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 61243B492EC5FA3700D46FA0 /* PenguinModel.swift in Sources */, - 61243B4C2EC5FA3700D46FA0 /* HMGPenguinInPlatformBridge.swift in Sources */, - 61243B502EC5FA3700D46FA0 /* PenguinView.swift in Sources */, - 61243B542EC5FA3700D46FA0 /* PenguinPlugin.swift in Sources */, - 61243B562EC5FA3700D46FA0 /* PenguinNavigator.swift in Sources */, - 61243B572EC5FA3700D46FA0 /* PenguinViewFactory.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6cf27c0f..3b3a47cd 100644 --- a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -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", diff --git a/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6cf27c0f..54619d3b 100644 --- a/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -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", diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 8a0a6208..bdd5af21 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -26,28 +26,28 @@ import GoogleMaps } 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 - .compactMap { $0 as? UIWindowScene } - .flatMap { $0.windows } - .first(where: { $0.isKeyWindow })? - .rootViewController as? FlutterViewController - } - - // 3. Perform initialization once FlutterViewController is available - if let mainViewController = controller { - HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController) - } else { - print("⚠️ FlutterViewController not ready yet for 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 +// .compactMap { $0 as? UIWindowScene } +// .flatMap { $0.windows } +// .first(where: { $0.isKeyWindow })? +// .rootViewController as? FlutterViewController +// } +// +// // 3. Perform initialization once FlutterViewController is available +// if let mainViewController = controller { +// HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController) +// } else { +// print("⚠️ FlutterViewController not ready yet for initializePlatformChannels.") +// } +// } // if let mainViewController = window?.rootViewController as? FlutterViewController{ // platform initialization suppose to be in foreground diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index eb190c13..413c17b4 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -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.preProd; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index b0764941..ebe19c02 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -276,6 +276,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; } @@ -285,6 +286,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; } @@ -295,6 +297,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; } @@ -304,6 +307,7 @@ class AuthenticationViewModel extends ChangeNotifier { } else if (selectedCountrySignup == CountryEnum.unitedArabEmirates) { if (!ValidationUtils.validateUaeNationalId(nationalIdController.text)) { _nationalIdError = LocaleKeys.pleaseEnterAValidNationalID.tr(); + print("the controller is not valid so the error is $_nationalIdError"); notifyListeners(); return false; } diff --git a/pubspec.lock b/pubspec.lock index 70ddfc04..6b0a4d35 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 + sha256: f6966125633a34f82d9be2ee895b755cff3554087b1d00a9eb884e5947f4bca9 url: "https://pub.dev" source: hosted - version: "1.3.59" + version: "1.3.77" adaptive_number: dependency: transitive description: @@ -117,10 +117,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" chewie: dependency: transitive description: @@ -402,114 +402,114 @@ packages: dependency: "direct main" description: name: firebase_analytics - sha256: "4f85b161772e1d54a66893ef131c0a44bd9e552efa78b33d5f4f60d2caa5c8a3" + sha256: b82d2cabf4905a465ac95937037cbab4f2ca80f559cb04abd3da3f2abb9960bb url: "https://pub.dev" source: hosted - version: "11.6.0" + version: "12.6.0" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - sha256: a44b6d1155ed5cae7641e3de7163111cfd9f6f6c954ca916dc6a3bdfa86bf845 + sha256: "5c3ab4b681c837afd71f0abf77c7485f51c7b645d4ae77b96f9ed54779ff4126" url: "https://pub.dev" source: hosted - version: "4.4.3" + version: "6.0.7" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - sha256: c7d1ed1f86ae64215757518af5576ff88341c8ce5741988c05cc3b2e07b0b273 + sha256: "09eb4d0ce4c9a16efbc277ac709a90eb197d5512592215a73c6a302ab1ab6c3a" url: "https://pub.dev" source: hosted - version: "0.5.10+16" + version: "0.6.1+13" firebase_core: dependency: "direct main" description: name: firebase_core - sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" + sha256: "5fbbaa2aeb08a52feee559f92a62f5a6b04c9bdff81c8f608636771cf0d7b680" url: "https://pub.dev" source: hosted - version: "3.15.2" + version: "4.15.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: cccb4f572325dc14904c02fcc7db6323ad62ba02536833dddb5c02cac7341c64 + sha256: "9bfbc85faca09346471ac56fbcee00757ebcfd85887c6f602764eff0001902d8" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "8.1.1" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" + sha256: "8ed84f5001dbd7a0390e2818d46bc858ceebb970edededdfc8d6552c76fc2f6e" url: "https://pub.dev" source: hosted - version: "2.24.1" + version: "3.12.0" firebase_crashlytics: dependency: "direct main" description: name: firebase_crashlytics - sha256: "662ae6443da91bca1fb0be8aeeac026fa2975e8b7ddfca36e4d90ebafa35dde1" + sha256: f37fe0df162f08bd549114b784037c73a093c64d22625632f97dbbddf18669b9 url: "https://pub.dev" source: hosted - version: "4.3.10" + version: "5.4.0" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface - sha256: "7222a8a40077c79f6b8b3f3439241c9f2b34e9ddfde8381ffc512f7b2e61f7eb" + sha256: "8270dcdb1800db3e5f888ce30a2d5e8f92c379c461f022297c83b2c794aa1792" url: "https://pub.dev" source: hosted - version: "3.8.10" + version: "3.9.0" firebase_messaging: dependency: "direct main" description: name: firebase_messaging - sha256: "60be38574f8b5658e2f22b7e311ff2064bea835c248424a383783464e8e02fcc" + sha256: "47a8142a0b897783103b01018ad69f123b819b0120483847bde30d1b2fa89b36" url: "https://pub.dev" source: hosted - version: "15.2.10" + version: "16.7.0" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: "685e1771b3d1f9c8502771ccc9f91485b376ffe16d553533f335b9183ea99754" + sha256: f9707e185b8ce1155d58e7e29348245072d99981f899fa8d3214abb2652c4ccb url: "https://pub.dev" source: hosted - version: "4.6.10" + version: "4.10.0" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: "0d1be17bc89ed3ff5001789c92df678b2e963a51b6fa2bdb467532cc9dbed390" + sha256: "311b16c75fc645c7a70c9ade38908abb12310dfce449fc3d3cee1771f196351e" url: "https://pub.dev" source: hosted - version: "3.10.10" + version: "4.2.5" firebase_remote_config: dependency: "direct main" description: name: firebase_remote_config - sha256: e1635b1e8713f4a823920ec3a56a14034b90ce455d47746ab0da994857f370cf + sha256: fa518445638fa3903e359ac544bd3243e72ada025728c8dbfa4b28ae939e8b38 url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "6.7.0" firebase_remote_config_platform_interface: dependency: transitive description: name: firebase_remote_config_platform_interface - sha256: ce836c5c62056edbe23ef501e6876691ee32476afd12fe95b76e57bba9d25485 + sha256: dc5a9713031f2ca744cb266d96a58609e929db19f3d91a1dd6bb8f8a0d77acad url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "3.0.7" firebase_remote_config_web: dependency: transitive description: name: firebase_remote_config_web - sha256: "9dbd75024bfcd47c05046c95f9cf648a8fc862b096bcf8ea1e4b855d50ea19ad" + sha256: "500abf695c370c76a486ad7480a6df7caf55d2d35ccc5c66b9fc9c1c47f2bc14" url: "https://pub.dev" source: hosted - version: "1.8.9" + version: "1.10.14" fixnum: dependency: transitive description: @@ -821,10 +821,10 @@ packages: dependency: "direct main" description: name: flutter_zoom_videosdk - sha256: "87caad07b994f09b9d8c4b8054c0dff5659029abae38dd6ec223460c3f1bcb7d" + sha256: "46a4dea664b1c969099328a499c198a1755adf9ac333dea28bea5187910b3bf9" url: "https://pub.dev" source: hosted - version: "2.5.10" + version: "2.1.10" fluttertoast: dependency: "direct main" description: @@ -1213,10 +1213,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + sha256: "1ca20c894b1717686a2319b8548763d812bc0aabdac580420a44c5178c57a867" url: "https://pub.dev" source: hosted - version: "0.20.2" + version: "0.20.3" jiffy: dependency: "direct main" description: @@ -1405,26 +1405,26 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd" url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.20" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.19.0" mime: dependency: transitive description: @@ -2018,10 +2018,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.12" time: dependency: transitive description: @@ -2154,10 +2154,10 @@ packages: dependency: transitive description: name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + sha256: "92b9910f66ed1057fd4da7b040ae7c74cafacf885bdc81be496928d5049b032d" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.3" video_player: dependency: transitive description: @@ -2303,5 +2303,5 @@ packages: source: hosted version: "1.2.0" sdks: - dart: ">=3.9.0 <4.0.0" + dart: ">=3.11.0-0 <4.0.0" flutter: ">=3.35.0" From e9968e4592a929561d19c78ee0aa3c855af002e6 Mon Sep 17 00:00:00 2001 From: taha Date: Tue, 13 Oct 2026 14:19:46 +0300 Subject: [PATCH 02/15] feat: update radiology analysis models and integrate specialty handling --- assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 3 +- ios/Runner.xcodeproj/project.pbxproj | 6 +- ios/Runner/AppDelegate.swift | 20 +-- ios/Runner/Info.plist | 21 +++ lib/core/api/api_client.dart | 4 +- lib/core/api_consts.dart | 1 + lib/extensions/string_extensions.dart | 5 + lib/features/lab/lab_view_model.dart | 10 +- .../ai_overview_labresults_by_ai_model.dart | 12 -- ...atient_lab_order_response_by_ai_model.dart | 12 -- .../patient_lab_orders_response_model.dart | 8 +- .../patient_prescriptions_response_model.dart | 8 +- .../prescription_analysis_response_model.dart | 28 +--- .../prescriptions/prescriptions_repo.dart | 2 +- .../prescriptions_view_model.dart | 21 ++- .../patient_radiology_response_model.dart | 7 +- .../radiology_ai_analysis_response_model.dart | 4 - lib/features/radiology/radiology_repo.dart | 10 +- .../radiology/radiology_view_model.dart | 4 +- lib/generated/locale_keys.g.dart | 2 + .../appointment_details_page.dart | 5 +- lib/presentation/home/landing_page.dart | 8 +- .../ai_analysis_widget.dart | 8 +- .../lab_ai_analysis_detailed_page.dart | 142 ++++++++--------- .../lab/lab_results/lab_result_details.dart | 6 +- .../medical_file/medical_file_page.dart | 6 +- ...rescription_ai_analysis_detailed_page.dart | 144 +++++++++--------- .../prescription_detail_page.dart | 6 +- .../prescriptions_list_page.dart | 5 + .../radiology_ai_analysis_detailed_page.dart | 54 +++---- .../radiology_ai_analysis_widget.dart | 14 +- .../radiology/radiology_result_page.dart | 2 +- pubspec.yaml | 1 + 34 files changed, 316 insertions(+), 276 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index f0e3c730..aeac3dd9 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -2070,5 +2070,6 @@ "downloadApp": "حمل التطبيق", "unread": "غير مقروء", "read": "مقروءة", - "pendingMedicalReportRequest": "لديك بالفعل طلب معلّق للحصول على تقرير طبي خاص بهذا الموعد. يرجى الانتظار حتى اكتمال الطلب قبل تقديم طلب جديد." + "pendingMedicalReportRequest": "لديك بالفعل طلب معلّق للحصول على تقرير طبي خاص بهذا الموعد. يرجى الانتظار حتى اكتمال الطلب قبل تقديم طلب جديد.", + "AllergyReactions": "ردود الفعل التحسسية" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 06a2742c..d6929f1b 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -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" } diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index cd11bd9a..783f7639 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -69,6 +69,7 @@ 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 = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -89,6 +90,8 @@ files = ( 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, 5D5A1F80D389375644C4D0DC /* Pods_Runner.framework in Frameworks */, + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + 37D27FAF2C38AC83B852680C /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -123,6 +126,7 @@ 76B714CF300E58B1004DE37A /* WidgetKit.framework */, 76B714D1300E58B1004DE37A /* SwiftUI.framework */, 56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */, + A83C76CFF9D3F92EDE3B22B4 /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -175,7 +179,6 @@ children = ( 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */, 61243B412EC5FA3700D46FA0 /* Helper */, - 61243B472EC5FA3700D46FA0 /* Penguin */, 769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */, 478CFA952E6E20A60064F3D7 /* Runner.entitlements */, 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */, @@ -333,6 +336,7 @@ "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Copy Pods Resources"; outputFileListPaths = ( ); outputPaths = ( diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index bdd5af21..13ac16ec 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -7,13 +7,13 @@ import GoogleMaps @objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { func didInitializeImplicitFlutterEngine(_ engineBridge: any FlutterImplicitEngineBridge) { GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) - + // GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng") // FirebaseApp.configure() // initializePlatformChannels() - + } - + override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? @@ -28,10 +28,10 @@ import GoogleMaps // 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 +40,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 +48,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) // } - + } - + override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken:Data){ // Messaging.messaging().apnsToken = deviceToken super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 85d84646..8bf02667 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,27 @@ + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + Main + + + + CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 1bccb154..317134e2 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -210,7 +210,7 @@ class ApiClientImp implements ApiClient { } // body['TokenID'] = "@dm!n"; - // body['PatientID'] = 1009156; + // body['PatientID'] = 2101020; // 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"); } diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index a98735f0..4145e78f 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -7,6 +7,7 @@ class ApiConsts { static const maxSmallScreen = 660; static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.preProd; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 06d590cf..95ad376c 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -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 = ""; diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index 90ceacfe..64484831 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -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 getAiOverviewSingleLabResult({required int langId, required LabResult recentLabResult, required String loadingText}) async { + Future 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().getAuthenticatedUser()!.patientId, "language_id": langId, "lab_results": results}; + var payload = {"patient_id": getIt.get().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 { diff --git a/lib/features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart b/lib/features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart index 2353cf82..29d9aa38 100644 --- a/lib/features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart +++ b/lib/features/lab/models/resp_models/ai_overview_labresults_by_ai_model.dart @@ -35,21 +35,15 @@ class LabOrdersResponseByAi { class Analysis { List? aiGeneratedAttributes; List? aiPredictions; - List? aiRecommendations; - List? prevention; String? rawMessage; List? riskFactors; - List? 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 json) => Analysis( aiGeneratedAttributes: json["ai_generated_attributes"] == null ? [] : List.from(json["ai_generated_attributes"]!.map((x) => AiGeneratedAttribute.fromJson(x))), aiPredictions: json["ai_predictions"] == null ? [] : List.from(json["ai_predictions"]!.map((x) => x)), - aiRecommendations: json["ai_recommendations"] == null ? [] : List.from(json["ai_recommendations"]!.map((x) => AiRecommendation.fromJson(x))), - prevention: json["prevention"] == null ? [] : List.from(json["prevention"]!.map((x) => x)), rawMessage: json["raw_message"], riskFactors: json["riskFactors"] == null ? [] : List.from(json["riskFactors"]!.map((x) => RiskFactor.fromJson(x))), - suggestedDoctors: json["suggested_doctors"] == null ? [] : List.from(json["suggested_doctors"]!.map((x) => x)), summary: json["summary"], ); Map toJson() => { "ai_generated_attributes": aiGeneratedAttributes == null ? [] : List.from(aiGeneratedAttributes!.map((x) => x.toJson())), "ai_predictions": aiPredictions == null ? [] : List.from(aiPredictions!.map((x) => x)), - "ai_recommendations": aiRecommendations == null ? [] : List.from(aiRecommendations!.map((x) => x.toJson())), - "prevention": prevention == null ? [] : List.from(prevention!.map((x) => x)), "raw_message": rawMessage, "riskFactors": riskFactors == null ? [] : List.from(riskFactors!.map((x) => x.toJson())), - "suggested_doctors": suggestedDoctors == null ? [] : List.from(suggestedDoctors!.map((x) => x)), "summary": summary, }; } diff --git a/lib/features/lab/models/resp_models/patient_lab_order_response_by_ai_model.dart b/lib/features/lab/models/resp_models/patient_lab_order_response_by_ai_model.dart index 7ad3d543..b3dd2900 100644 --- a/lib/features/lab/models/resp_models/patient_lab_order_response_by_ai_model.dart +++ b/lib/features/lab/models/resp_models/patient_lab_order_response_by_ai_model.dart @@ -4,20 +4,14 @@ class LabOrderResponseByAi { String? summary; List? aiGeneratedAttributes; List? aiPredictions; - List? aiRecommendations; List? riskFactors; - List? prevention; - List? 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.from(json["ai_generated_attributes"]!.map((x) => AiGeneratedAttribute.fromJson(x))), aiPredictions: json["ai_predictions"] == null ? [] : List.from(json["ai_predictions"]!.map((x) => x)), - aiRecommendations: json["ai_recommendations"] == null ? [] : List.from(json["ai_recommendations"]!.map((x) => AiRecommendation.fromJson(x))), riskFactors: json["riskFactors"] == null ? [] : List.from(json["riskFactors"]!.map((x) => RiskFactor.fromJson(x))), - prevention: json["prevention"] == null ? [] : List.from(json["prevention"]!.map((x) => x)), - suggestedDoctors: json["suggested_doctors"] == null ? [] : List.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.from(aiGeneratedAttributes!.map((x) => x.toJson())), "ai_predictions": aiPredictions == null ? [] : List.from(aiPredictions!.map((x) => x)), - "ai_recommendations": aiRecommendations == null ? [] : List.from(aiRecommendations!.map((x) => x.toJson())), "riskFactors": riskFactors == null ? [] : List.from(riskFactors!.map((x) => x.toJson())), - "prevention": prevention == null ? [] : List.from(prevention!.map((x) => x)), - "suggested_doctors": suggestedDoctors == null ? [] : List.from(suggestedDoctors!.map((x) => x)), "raw_message": rawMessage, }; } diff --git a/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart b/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart index 1c437a48..8275771d 100644 --- a/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart +++ b/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart @@ -45,7 +45,7 @@ class PatientLabOrdersResponseModel { dynamic? projectNameN; String? qR; String? setupID; - // List? speciality; + List? 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(); + speciality = json['Speciality'] != null ? List.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; diff --git a/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart b/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart index 7b1d879d..0f06af7a 100644 --- a/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart +++ b/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart @@ -36,7 +36,7 @@ class PatientPrescriptionsResponseModel { int? noOfPatientsRate; String? qR; - // List? speciality; + List? 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 json) { @@ -116,7 +116,7 @@ class PatientPrescriptionsResponseModel { nationalityFlagURL = json['NationalityFlagURL']; noOfPatientsRate = json['NoOfPatientsRate']; qR = json['QR']; - // speciality = json['Speciality'].cast(); + speciality = json['Speciality'] != null ? List.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; } diff --git a/lib/features/prescriptions/models/resp_models/prescription_analysis_response_model.dart b/lib/features/prescriptions/models/resp_models/prescription_analysis_response_model.dart index c0c63f40..e3fe80cb 100644 --- a/lib/features/prescriptions/models/resp_models/prescription_analysis_response_model.dart +++ b/lib/features/prescriptions/models/resp_models/prescription_analysis_response_model.dart @@ -1,17 +1,13 @@ class PrescriptionAnalysisResponse { String? prescriptionSummary; List? medicinesAnalysis; - List? importantWarnings; - List? medicineInteractions; - String? followUpNeeded; + List? 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() : []; - medicineInteractions = json['medicine_interactions'] != null ? json['medicine_interactions'].cast() : []; - followUpNeeded = json['follow_up_needed']; + importantNotes = json['important_notes'] != null ? json['important_notes'].cast() : []; 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? commonSideEffects; - List? seriousWarnings; + List? allergyReactions; String? storage; MedicineAnalysis({ this.medicineName, this.benefit, - this.commonSideEffects, - this.seriousWarnings, + this.allergyReactions, this.storage, }); MedicineAnalysis.fromJson(Map json) { medicineName = json['medicine_name']; benefit = json['benefit']; - commonSideEffects = json['common_side_effects'] != null ? json['common_side_effects'].cast() : []; - seriousWarnings = json['serious_warnings'] != null ? json['serious_warnings'].cast() : []; + allergyReactions = json['allergy_reactions'] != null ? json['allergy_reactions'].cast() : []; storage = json['storage']; } @@ -70,8 +59,7 @@ class MedicineAnalysis { final Map data = {}; 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; } diff --git a/lib/features/prescriptions/prescriptions_repo.dart b/lib/features/prescriptions/prescriptions_repo.dart index 2681b2da..588d4417 100644 --- a/lib/features/prescriptions/prescriptions_repo.dart +++ b/lib/features/prescriptions/prescriptions_repo.dart @@ -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; }, diff --git a/lib/features/prescriptions/prescriptions_view_model.dart b/lib/features/prescriptions/prescriptions_view_model.dart index 1e33b509..7ac485e0 100644 --- a/lib/features/prescriptions/prescriptions_view_model.dart +++ b/lib/features/prescriptions/prescriptions_view_model.dart @@ -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 allergies, }) async { LoaderBottomSheet.showLoader( loadingText: loadingText, @@ -424,6 +428,7 @@ class PrescriptionsViewModel extends ChangeNotifier { // Prepare medicines payload List> medicines = []; + List> 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, ); diff --git a/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart b/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart index 740c275f..b79936ec 100644 --- a/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart +++ b/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart @@ -56,6 +56,7 @@ class PatientRadiologyResponseModel { bool? isCVI; bool? isRadMedicalReport; dynamic vida3Id; + List? 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 json) { setupID = json['SetupID']; @@ -170,6 +173,7 @@ class PatientRadiologyResponseModel { isCVI = json['isCVI']; isRadMedicalReport = json['isRadMedicalReport']; vida3Id = json['vida3Id']; + speciality = json['Speciality'] != null ? List.from(json['Speciality']) : []; } Map 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; } } diff --git a/lib/features/radiology/models/resp_models/radiology_ai_analysis_response_model.dart b/lib/features/radiology/models/resp_models/radiology_ai_analysis_response_model.dart index 3f523428..4d9ea2e1 100644 --- a/lib/features/radiology/models/resp_models/radiology_ai_analysis_response_model.dart +++ b/lib/features/radiology/models/resp_models/radiology_ai_analysis_response_model.dart @@ -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, }; } diff --git a/lib/features/radiology/radiology_repo.dart b/lib/features/radiology/radiology_repo.dart index 6e538d3f..34795e0c 100644 --- a/lib/features/radiology/radiology_repo.dart +++ b/lib/features/radiology/radiology_repo.dart @@ -19,7 +19,7 @@ abstract class RadiologyRepo { Future>>> getPatientRadiologyOrderByAppointment({required num appointmentNo, required num projectID}); - Future>> getRadiologyAiAnalysis({required String reportData, required int langId,}); + Future>> getRadiologyAiAnalysis({required PatientRadiologyResponseModel radiologyData, required int langId,}); } class RadiologyRepoImp implements RadiologyRepo { @@ -238,10 +238,12 @@ class RadiologyRepoImp implements RadiologyRepo { } @override - Future>> getRadiologyAiAnalysis({required String reportData, required int langId}) async { + Future>> getRadiologyAiAnalysis({required PatientRadiologyResponseModel radiologyData, required int langId}) async { Map payload = { - "text": reportData, - "language_id": langId + "text": radiologyData.reportData ?? "", + "language_id": langId, + "clinic_name": radiologyData.clinicDescription ?? "", + "specialty_name":radiologyData.speciality?.toString().replaceAll("[", "").replaceAll("]", "") ?? "" }; try { diff --git a/lib/features/radiology/radiology_view_model.dart b/lib/features/radiology/radiology_view_model.dart index 30f9683a..1848f648 100644 --- a/lib/features/radiology/radiology_view_model.dart +++ b/lib/features/radiology/radiology_view_model.dart @@ -229,7 +229,7 @@ class RadiologyViewModel extends ChangeNotifier { } - Future getRadiologyAiAnalysis({required String reportData, required String loadingText, required int langId}) async { + Future 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 { diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 30e3bc0a..65ca9a4c 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -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'; } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 874c97c6..947d3efe 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -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 { Navigator.of(context).push( CustomPageRoute( page: PrescriptionDetailPage( - isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel), + isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel, + allergies: Provider.of(context, listen: false).patientAllergiesList, + ), ), ); } else { diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 9d401fac..8b82d7c0 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -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 { late EmergencyServicesViewModel emergencyServicesViewModel; late TodoSectionViewModel todoSectionViewModel; late NotificationsViewModel notificationsViewModel; + late MedicalFileViewModel medicalFileViewModel; final SwiperController _controller = SwiperController(); @@ -166,6 +170,7 @@ class _LandingPageState extends State { emergencyServicesViewModel.checkPatientERAdvanceBalance(); // myAppointmentsViewModel.getPatientAppointmentQueueDetails(); notificationsViewModel.initNotificationsViewModel(); + medicalFileViewModel.getPatientAllergiesList(); if (Utils.havePrivilege(122)) { insuranceViewModel.initInsuranceProvider(isFromHomePage: true); @@ -215,6 +220,7 @@ class _LandingPageState extends State { emergencyServicesViewModel = Provider.of(context, listen: false); todoSectionViewModel = Provider.of(context, listen: false); notificationsViewModel = Provider.of(context, listen: false); + medicalFileViewModel = Provider.of(context, listen: false); appState = getIt.get(); return PopScope( canPop: false, @@ -280,7 +286,7 @@ class _LandingPageState extends State { myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.initAppointmentsViewModel(); myAppointmentsViewModel.getPatientAppointments(true, false, isForTimeLine: true); - + medicalFileViewModel.getPatientAllergiesList(); // Refresh Appointments Data // habibWalletVM.initHabibWalletProvider(); // habibWalletVM.getPatientBalanceAmount(); diff --git a/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart b/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart index b643515f..48dc302c 100644 --- a/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart +++ b/lib/presentation/lab/lab_result_via_clinic/ai_analysis_widget.dart @@ -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: [ diff --git a/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart b/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart index 4debd41b..44210db1 100644 --- a/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart +++ b/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart @@ -55,7 +55,7 @@ class _LabAiAnalysisDetailedPageState extends State { 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 { ); } - // 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 { ); } - // 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) { diff --git a/lib/presentation/lab/lab_results/lab_result_details.dart b/lib/presentation/lab/lab_results/lab_result_details.dart index 9fbb49a8..4a65d9cf 100644 --- a/lib/presentation/lab/lab_results/lab_result_details.dart +++ b/lib/presentation/lab/lab_results/lab_result_details.dart @@ -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 createState() => _LabResultDetailsState(); @@ -197,7 +199,7 @@ class _LabResultDetailsState extends State { 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(); diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index add423d8..bd69fb7e 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -972,7 +972,11 @@ class _MedicalFilePageState extends State { 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(context, listen: false).patientAllergiesList, + ), ), ); }), diff --git a/lib/presentation/prescriptions/prescription_ai_analysis_detailed_page.dart b/lib/presentation/prescriptions/prescription_ai_analysis_detailed_page.dart index 82a5d9de..cf83bcca 100644 --- a/lib/presentation/prescriptions/prescription_ai_analysis_detailed_page.dart +++ b/lib/presentation/prescriptions/prescription_ai_analysis_detailed_page.dart @@ -89,12 +89,12 @@ class _PrescriptionAiAnalysisDetailedPageState extends State allergies; @override State createState() => _PrescriptionDetailPageState(); @@ -318,6 +320,8 @@ class _PrescriptionDetailPageState extends State { prescriptionsViewModel.setIsPrescriptionAIAnalysisNeedsToBeShown(true); prescriptionsViewModel.getPrescriptionAiAnalysis( prescriptions: prescriptionsViewModel.prescriptionDetailsList, + prescriptionResponseModel: widget.prescriptionsResponseModel, + allergies: widget.allergies, langId: getIt.get().getLanguageID(), loadingText: LocaleKeys.loadingAIAnalysisPrescription.tr(context: context), onNavigate: (data) { diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart index 071cce87..e4562545 100644 --- a/lib/presentation/prescriptions/prescriptions_list_page.dart +++ b/lib/presentation/prescriptions/prescriptions_list_page.dart @@ -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 { int? expandedIndex; late PrescriptionsViewModel prescriptionsViewModel; + late MedicalFileViewModel medicalFileViewModel; @override void initState() { @@ -50,6 +52,7 @@ class _PrescriptionsListPageState extends State { Widget build(BuildContext context) { AppState appState = getIt.get(); prescriptionsViewModel = Provider.of(context, listen: false); + medicalFileViewModel = Provider.of(context, listen: false); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: CollapsingListView( @@ -243,6 +246,7 @@ class _PrescriptionsListPageState extends State { page: PrescriptionDetailPage( prescriptionsResponseModel: model.patientPrescriptionOrders[index], isFromAppointments: false, + allergies: Provider.of(context, listen: false).patientAllergiesList, ), ), ); @@ -550,6 +554,7 @@ class _PrescriptionsListPageState extends State { CustomPageRoute( page: PrescriptionDetailPage( prescriptionsResponseModel: model.patientPrescriptionOrders[index], + allergies: medicalFileViewModel.patientAllergiesList, isFromAppointments: false, ), ), diff --git a/lib/presentation/radiology/radiology_ai_analysis_detailed_page.dart b/lib/presentation/radiology/radiology_ai_analysis_detailed_page.dart index a3e00e79..eaebd34e 100644 --- a/lib/presentation/radiology/radiology_ai_analysis_detailed_page.dart +++ b/lib/presentation/radiology/radiology_ai_analysis_detailed_page.dart @@ -45,7 +45,7 @@ class _RadiologyAiAnalysisDetailedPageState extends State _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: [ diff --git a/lib/presentation/radiology/radiology_ai_analysis_widget.dart b/lib/presentation/radiology/radiology_ai_analysis_widget.dart index f22bcbd0..0fc1887e 100644 --- a/lib/presentation/radiology/radiology_ai_analysis_widget.dart +++ b/lib/presentation/radiology/radiology_ai_analysis_widget.dart @@ -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: [ diff --git a/lib/presentation/radiology/radiology_result_page.dart b/lib/presentation/radiology/radiology_result_page.dart index 5b7072e6..b7f94261 100644 --- a/lib/presentation/radiology/radiology_result_page.dart +++ b/lib/presentation/radiology/radiology_result_page.dart @@ -232,7 +232,7 @@ class _RadiologyResultPageState extends State { onOkPressed: () { context.pop(); radiologyViewModel.getRadiologyAiAnalysis( - reportData: widget.patientRadiologyResponseModel.reportData ?? "", + radiologyData: widget.patientRadiologyResponseModel, loadingText: LocaleKeys.loadingAIAnalysis.tr(context: context), langId: _appState.getLanguageID(), ); diff --git a/pubspec.yaml b/pubspec.yaml index c6bc2c93..144fa923 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -116,6 +116,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: From f0b08a4116e3b7081821e121f9e648c2521a4e77 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 25 Oct 2026 11:53:49 +0300 Subject: [PATCH 03/15] Update to stores, VersionID 21.7 --- lib/core/api_consts.dart | 3 +-- lib/presentation/my_family/widget/family_cards.dart | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index aa265931..00161451 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -6,7 +6,6 @@ import 'package:myfatoorah_flutter/myfatoorah_flutter.dart'; class ApiConsts { static const maxSmallScreen = 660; - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.preProd; static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT @@ -317,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"; diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart index de8c3d83..e34a12aa 100644 --- a/lib/presentation/my_family/widget/family_cards.dart +++ b/lib/presentation/my_family/widget/family_cards.dart @@ -476,7 +476,7 @@ class _FamilyCardsState extends State { 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( From 78204474124b760dcae7be2811215b75e1f90522 Mon Sep 17 00:00:00 2001 From: taha Date: Mon, 26 Oct 2026 09:25:51 +0300 Subject: [PATCH 04/15] chore: add Package.resolved to .gitignore for Swift package management --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 79c113f9..8c149701 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release +/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved From 0697a76b54a3d7f3861263519b29c4d29d86abb6 Mon Sep 17 00:00:00 2001 From: taha Date: Mon, 26 Oct 2026 11:12:36 +0300 Subject: [PATCH 05/15] feat: enhance doctor appointment filtering and sorting by adding English region names --- lib/core/utils/doctor_response_mapper.dart | 41 +++++++++++++++++-- .../resp_models/doctor_list_api_response.dart | 5 ++- pubspec.yaml | 8 ++-- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/lib/core/utils/doctor_response_mapper.dart b/lib/core/utils/doctor_response_mapper.dart index 05ed2fdc..9675cdee 100644 --- a/lib/core/utils/doctor_response_mapper.dart +++ b/lib/core/utils/doctor_response_mapper.dart @@ -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? 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 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 getMappedHospitals( List 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; diff --git a/lib/features/my_appointments/models/resp_models/doctor_list_api_response.dart b/lib/features/my_appointments/models/resp_models/doctor_list_api_response.dart index c2b9add7..87d4d8ca 100644 --- a/lib/features/my_appointments/models/resp_models/doctor_list_api_response.dart +++ b/lib/features/my_appointments/models/resp_models/doctor_list_api_response.dart @@ -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? 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? registeredDoctorMap = {}; + Map? regionNameMap = {}; } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 144fa923..602108cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -94,7 +94,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 @@ -108,9 +108,9 @@ dependencies: flutter_paytabs_bridge: ^2.7.14 clarity_flutter: ^1.10.0 -# flutter_amazonpaymentservices: ^0.0.13 - flutter_amazonpaymentservices: - path: ./package/flutter_amazonpaymentservices + flutter_amazonpaymentservices: ^0.0.13 +# flutter_amazonpaymentservices: +# path: ./package/flutter_amazonpaymentservices screen_brightness: ^1.0.1 flutter_screenshot_blocker: ^1.0.4 cloudflare_turnstile: ^3.7.2 From 23918738ae021a7d25fe30f2bb7030e2d95a414a Mon Sep 17 00:00:00 2001 From: taha Date: Mon, 26 Oct 2026 11:15:14 +0300 Subject: [PATCH 06/15] REVERETED THE YAMAL TO LOCAL PAYMENT SERVICE --- pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 602108cf..35a5c50f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -108,9 +108,9 @@ dependencies: flutter_paytabs_bridge: ^2.7.14 clarity_flutter: ^1.10.0 - flutter_amazonpaymentservices: ^0.0.13 -# flutter_amazonpaymentservices: -# path: ./package/flutter_amazonpaymentservices +# flutter_amazonpaymentservices: ^0.0.13 + flutter_amazonpaymentservices: + path: ./package/flutter_amazonpaymentservices screen_brightness: ^1.0.1 flutter_screenshot_blocker: ^1.0.4 cloudflare_turnstile: ^3.7.2 From 89393c9b21a2a3a6133f9bce53a6b1d26fee3d72 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 26 Oct 2026 11:58:07 +0300 Subject: [PATCH 07/15] updates --- .gitignore | 5 + ios/Runner.xcodeproj/project.pbxproj | 157 ++++++++--- ios/Runner/AppDelegate.swift | 54 ++-- ios/Runner/Helper/FlutterConstants.swift | 58 ++-- ios/Runner/Helper/HMGPlatformBridge.swift | 266 +++++++++--------- ios/Runner/Helper/LocalizedFromFlutter.swift | 18 +- ios/Runner/Helper/OpenTokPlatformBridge.swift | 108 +++---- ios/Runner/Info.plist | 21 -- 8 files changed, 377 insertions(+), 310 deletions(-) diff --git a/.gitignore b/.gitignore index 79c113f9..3c4ac508 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,8 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +/ios/ +/ios/Penguin.xcframework/ +/ios/PenguinINRenderer.xcframework/ +/ios/PenNavUI.xcframework/ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 783f7639..c1045afb 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -11,13 +11,34 @@ 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 */; }; 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 */; }; 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 */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + E770DD0A01C1858ADA957540 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09A5B486A6530B3BB024E598 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -37,6 +58,9 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 7676C2C8308F3D03004CF793 /* PenguinINRenderer.xcframework in Embed Frameworks */, + 7676C2C6308F3D02004CF793 /* Penguin.xcframework in Embed Frameworks */, + 7676C2CA308F3D04004CF793 /* PenNavUI.xcframework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -54,23 +78,43 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 09A5B486A6530B3BB024E598 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 21DDD86357889D25E534D20D /* 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 = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 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 = ""; }; 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 478CFA952E6E20A60064F3D7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; - 56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7676C28D308F37EA004CF793 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = ""; }; + 7676C28E308F37EA004CF793 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = ""; }; + 7676C28F308F37EA004CF793 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = ""; }; + 7676C290308F37EA004CF793 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = ""; }; + 7676C291308F37EA004CF793 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = ""; }; + 7676C29E308F394F004CF793 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; + 7676C29F308F394F004CF793 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; + 7676C2A0308F394F004CF793 /* FlutterConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterConstants.swift; sourceTree = ""; }; + 7676C2A1308F394F004CF793 /* GeoZoneModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoZoneModel.swift; sourceTree = ""; }; + 7676C2A2308F394F004CF793 /* GlobalHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalHelper.swift; sourceTree = ""; }; + 7676C2A3308F394F004CF793 /* HMG_Geofence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMG_Geofence.swift; sourceTree = ""; }; + 7676C2A4308F394F004CF793 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = ""; }; + 7676C2A5308F394F004CF793 /* HMGPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPlatformBridge.swift; sourceTree = ""; }; + 7676C2A6308F394F004CF793 /* LocalizedFromFlutter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedFromFlutter.swift; sourceTree = ""; }; + 7676C2A7308F394F004CF793 /* OpenTokPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokPlatformBridge.swift; sourceTree = ""; }; + 7676C2BF308F3C52004CF793 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Penguin.xcframework; sourceTree = ""; }; + 7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenguinINRenderer.xcframework; sourceTree = ""; }; + 7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PenNavUI.xcframework; sourceTree = ""; }; 769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = ""; }; 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = ring_30Sec.caf; sourceTree = ""; }; 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 = ""; }; - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7E7114E2A230EE71FB6D6D7C /* 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 = ""; }; + 9616FEAD6BEF8328D85974DF /* 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 = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -78,9 +122,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 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 = ""; }; - 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 = ""; }; - 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -88,10 +129,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 7676C2C5308F3D02004CF793 /* Penguin.xcframework in Frameworks */, 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, - 5D5A1F80D389375644C4D0DC /* Pods_Runner.framework in Frameworks */, 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, - 37D27FAF2C38AC83B852680C /* Pods_Runner.framework in Frameworks */, + 7676C2C7308F3D03004CF793 /* PenguinINRenderer.xcframework in Frameworks */, + E770DD0A01C1858ADA957540 /* Pods_Runner.framework in Frameworks */, + 7676C2C9308F3D04004CF793 /* PenNavUI.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -113,30 +156,54 @@ path = Helper; sourceTree = ""; }; - 61243B472EC5FA3700D46FA0 /* Penguin */ = { + 766D8CB22EC60BE600D05E07 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 7676C2BF308F3C52004CF793 /* Penguin.xcframework */, + 7676C2C0308F3C52004CF793 /* PenguinINRenderer.xcframework */, + 7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */, + 76B714CF300E58B1004DE37A /* WidgetKit.framework */, + 76B714D1300E58B1004DE37A /* SwiftUI.framework */, + 09A5B486A6530B3BB024E598 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 7676C292308F37EA004CF793 /* Penguin */ = { isa = PBXGroup; children = ( + 7676C28D308F37EA004CF793 /* PenguinModel.swift */, + 7676C28E308F37EA004CF793 /* PenguinNavigator.swift */, + 7676C28F308F37EA004CF793 /* PenguinPlugin.swift */, + 7676C290308F37EA004CF793 /* PenguinView.swift */, + 7676C291308F37EA004CF793 /* PenguinViewFactory.swift */, ); path = Penguin; sourceTree = ""; }; - 766D8CB22EC60BE600D05E07 /* Frameworks */ = { + 7676C2A8308F394F004CF793 /* Helper */ = { isa = PBXGroup; children = ( - 76B714CF300E58B1004DE37A /* WidgetKit.framework */, - 76B714D1300E58B1004DE37A /* SwiftUI.framework */, - 56E413AB2A2E9765749CACD1 /* Pods_Runner.framework */, - A83C76CFF9D3F92EDE3B22B4 /* 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 = ""; }; 79DD2093A1D9674C94359FC8 /* Pods */ = { isa = PBXGroup; children = ( - BCE5BC40273DCC009E2FACB7 /* Pods-Runner.debug.xcconfig */, - C6416282AC56269448D7DA99 /* Pods-Runner.release.xcconfig */, - C6FD350374F47AFA34911C58 /* Pods-Runner.profile.xcconfig */, + 21DDD86357889D25E534D20D /* Pods-Runner.debug.xcconfig */, + 9616FEAD6BEF8328D85974DF /* Pods-Runner.release.xcconfig */, + 7E7114E2A230EE71FB6D6D7C /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -177,6 +244,8 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 7676C2A8308F394F004CF793 /* Helper */, + 7676C292308F37EA004CF793 /* Penguin */, 76AA18AC2F3B2A4D00DC8DFC /* ring_30Sec.caf */, 61243B412EC5FA3700D46FA0 /* Helper */, 769C9BF82E6F106D009F68A9 /* RunnerDebug.entitlements */, @@ -218,7 +287,7 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 511FFA76807DE636962DBF91 /* [CP] Check Pods Manifest.lock */, + E08B80DF84B0E0D872D7D950 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, @@ -226,8 +295,8 @@ 765A5A922F35CD8B0003FF7D /* Embed Frameworks */, 76B714E4300E58B2004DE37A /* Embed Foundation Extensions */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - C7E5B2C65EE0A4D64ECC826B /* [CP] Embed Pods Frameworks */, - DF2C78ED8C8F648520DF8C43 /* [CP] Copy Pods Resources */, + CD8EB7D84DD1FEE84642007B /* [CP] Embed Pods Frameworks */, + 592872084F2202E73671D38F /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -324,27 +393,21 @@ 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 */ = { + 592872084F2202E73671D38F /* [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 = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); 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 */ = { @@ -362,7 +425,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; - C7E5B2C65EE0A4D64ECC826B /* [CP] Embed Pods Frameworks */ = { + CD8EB7D84DD1FEE84642007B /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -379,21 +442,26 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - DF2C78ED8C8F648520DF8C43 /* [CP] Copy Pods Resources */ = { + E08B80DF84B0E0D872D7D950 /* [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 */ @@ -413,6 +481,21 @@ files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.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; }; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 13ac16ec..c7a41a18 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -26,33 +26,33 @@ import GoogleMaps } 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 -// .compactMap { $0 as? UIWindowScene } -// .flatMap { $0.windows } -// .first(where: { $0.isKeyWindow })? -// .rootViewController as? FlutterViewController -// } -// -// // 3. Perform initialization once FlutterViewController is available -// if let mainViewController = controller { -// HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController) -// } else { -// 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) -// } + 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 + .compactMap { $0 as? UIWindowScene } + .flatMap { $0.windows } + .first(where: { $0.isKeyWindow })? + .rootViewController as? FlutterViewController + } + + // 3. Perform initialization once FlutterViewController is available + if let mainViewController = controller { + HMGPenguinInPlatformBridge.initialize(flutterViewController: mainViewController) + } else { + 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) + } } diff --git a/ios/Runner/Helper/FlutterConstants.swift b/ios/Runner/Helper/FlutterConstants.swift index f1b3f098..10dfa4ff 100644 --- a/ios/Runner/Helper/FlutterConstants.swift +++ b/ios/Runner/Helper/FlutterConstants.swift @@ -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 +// } +// } +// +// } +// } +//} diff --git a/ios/Runner/Helper/HMGPlatformBridge.swift b/ios/Runner/Helper/HMGPlatformBridge.swift index fd9fb401..709767e6 100644 --- a/ios/Runner/Helper/HMGPlatformBridge.swift +++ b/ios/Runner/Helper/HMGPlatformBridge.swift @@ -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) +// } +// +//} diff --git a/ios/Runner/Helper/LocalizedFromFlutter.swift b/ios/Runner/Helper/LocalizedFromFlutter.swift index 88530649..0fa4b0bd 100644 --- a/ios/Runner/Helper/LocalizedFromFlutter.swift +++ b/ios/Runner/Helper/LocalizedFromFlutter.swift @@ -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) +// } +// }) +// } } diff --git a/ios/Runner/Helper/OpenTokPlatformBridge.swift b/ios/Runner/Helper/OpenTokPlatformBridge.swift index 4da39dc4..b2c46b3a 100644 --- a/ios/Runner/Helper/OpenTokPlatformBridge.swift +++ b/ios/Runner/Helper/OpenTokPlatformBridge.swift @@ -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("") +// } +// } +//} diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 8bf02667..85d84646 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,27 +2,6 @@ - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneClassName - UIWindowScene - UISceneDelegateClassName - FlutterSceneDelegate - UISceneConfigurationName - flutter - UISceneStoryboardFile - Main - - - - CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion From fb874379597ed50f3f6dcdb11bb9e752adf7251c Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 27 Oct 2026 16:43:02 +0300 Subject: [PATCH 08/15] Fixed Firebase issue with iOS UIScene delegate --- ios/Runner.xcodeproj/project.pbxproj | 58 +++++++++---------- .../xcshareddata/xcschemes/Runner.xcscheme | 5 +- ios/Runner/AppDelegate.swift | 24 +++++--- pubspec.yaml | 16 +++-- 4 files changed, 56 insertions(+), 47 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index c1045afb..3686ba52 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ 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 */; }; @@ -38,7 +39,6 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - E770DD0A01C1858ADA957540 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09A5B486A6530B3BB024E598 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -78,15 +78,15 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 09A5B486A6530B3BB024E598 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 21DDD86357889D25E534D20D /* 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 = ""; }; + 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 = ""; }; 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 = ""; }; 478CFA932E638C8E0064F3D7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 478CFA952E6E20A60064F3D7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + 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 = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7676C28D308F37EA004CF793 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = ""; }; @@ -113,8 +113,7 @@ 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 = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7E7114E2A230EE71FB6D6D7C /* 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 = ""; }; - 9616FEAD6BEF8328D85974DF /* 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 = ""; }; + 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 = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -122,6 +121,7 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -133,8 +133,8 @@ 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, 7676C2C7308F3D03004CF793 /* PenguinINRenderer.xcframework in Frameworks */, - E770DD0A01C1858ADA957540 /* Pods_Runner.framework in Frameworks */, 7676C2C9308F3D04004CF793 /* PenNavUI.xcframework in Frameworks */, + 094EF77E011152A3DF3536B2 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -164,7 +164,7 @@ 7676C2C1308F3C52004CF793 /* PenNavUI.xcframework */, 76B714CF300E58B1004DE37A /* WidgetKit.framework */, 76B714D1300E58B1004DE37A /* SwiftUI.framework */, - 09A5B486A6530B3BB024E598 /* Pods_Runner.framework */, + 30E602807D9C203A2FA83417 /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -201,9 +201,9 @@ 79DD2093A1D9674C94359FC8 /* Pods */ = { isa = PBXGroup; children = ( - 21DDD86357889D25E534D20D /* Pods-Runner.debug.xcconfig */, - 9616FEAD6BEF8328D85974DF /* Pods-Runner.release.xcconfig */, - 7E7114E2A230EE71FB6D6D7C /* Pods-Runner.profile.xcconfig */, + 8522EA4C54B9CA21B71F91CC /* Pods-Runner.debug.xcconfig */, + 9C0E63FC9D84AA7D3BB0A547 /* Pods-Runner.release.xcconfig */, + 4D6281A38B453C42FAC24BD5 /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -287,7 +287,7 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - E08B80DF84B0E0D872D7D950 /* [CP] Check Pods Manifest.lock */, + DE4E6538EB74D09D8F3A8FE7 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, @@ -295,8 +295,8 @@ 765A5A922F35CD8B0003FF7D /* Embed Frameworks */, 76B714E4300E58B2004DE37A /* Embed Foundation Extensions */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - CD8EB7D84DD1FEE84642007B /* [CP] Embed Pods Frameworks */, - 592872084F2202E73671D38F /* [CP] Copy Pods Resources */, + 824B1289AE3D15AB765B1BBF /* [CP] Embed Pods Frameworks */, + 6F08875CF9A6CF013C44F482 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -393,7 +393,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; }; - 592872084F2202E73671D38F /* [CP] Copy Pods Resources */ = { + 6F08875CF9A6CF013C44F482 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -410,39 +410,39 @@ 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 = ( ); - inputPaths = ( + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "Run Script"; - outputPaths = ( + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); 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; }; - CD8EB7D84DD1FEE84642007B /* [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"; }; - E08B80DF84B0E0D872D7D950 /* [CP] Check Pods Manifest.lock */ = { + DE4E6538EB74D09D8F3A8FE7 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c3fedb29..78f3f325 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,7 +1,7 @@ + version = "1.7"> @@ -91,6 +91,9 @@ ReferencedContainer = "container:Runner.xcodeproj"> + + 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 diff --git a/pubspec.yaml b/pubspec.yaml index 35a5c50f..64d4d22c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,8 +2,8 @@ name: hmg_patient_app_new description: "New HMG Patient App" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -#version: 4.6.046+1 -version: 4.6.1004+40501004 +version: 4.6.046+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 @@ -68,9 +69,6 @@ dependencies: 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 From e584533d9fb1fa46f9c8fa7a7cbac56d7bbb0615 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 27 Oct 2026 17:23:53 +0300 Subject: [PATCH 09/15] VoIP Kit implemented --- ios/Runner/AppDelegate.swift | 7 +------ lib/core/utils/push_notification_handler.dart | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 6d7cec86..be34fd68 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -10,15 +10,10 @@ import firebase_messaging 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() - - // Diagnostic only: who owns the delegate once everything has settled? - DispatchQueue.main.asyncAfter(deadline: .now() + 3) { - print("🔔 UNC delegate: \(String(describing: UNUserNotificationCenter.current().delegate))") - } } override func application( diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart index 30e251e1..6c3e38cf 100644 --- a/lib/core/utils/push_notification_handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -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; @@ -408,8 +414,22 @@ class PushNotificationHandler { _currentCallId = null; await Future.delayed(Duration(seconds: 2)).then((val) async { await voIPKit.endCall(); + await FlutterCallkitIncoming.endAllCalls(); }); + await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, callerId); + + Utils.removeFromPrefs(CacheConst.isAppOpenedFromCall); + Navigator.of(GetIt.instance().navigatorKey.currentContext!).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: LandingNavigation()))); + Navigator.pushReplacementNamed( + // context, + GetIt.instance().navigatorKey.currentContext!, + AppRoutes.zoomCallPage, + // arguments: CallArguments(appointmentID, "111", "Patient", "40", "1", true, 1), + arguments: CallArguments(callerId, "123", "Patient", "40", "0", true, int.parse("1")), + // arguments: CallArguments("SmallDailyStandup9875", "123", "Patient", "40", "0", false, int.parse(widget.incomingCallData!.appointmentNo!)), + ); + // Navigator.pushNamed( // locator().navigatorKey.currentContext!, // "zoom_call_page", From e1084028d68a28689d5aebaaf808fdcbe0c5630b Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 28 Oct 2026 11:52:32 +0300 Subject: [PATCH 10/15] LiveCare & iOS 27.1 updates --- ios/Podfile | 2 +- ios/Runner.xcodeproj/project.pbxproj | 3 +++ lib/core/api_consts.dart | 2 +- lib/core/utils/push_notification_handler.dart | 20 ++++++------------- .../book_appointments_repo.dart | 5 +++++ .../immediate_livecare_view_model.dart | 2 +- pubspec.yaml | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index e0283052..9ea6dc53 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -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 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 3686ba52..526f2efb 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -593,6 +593,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; @@ -780,6 +781,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; @@ -810,6 +812,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; diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 00161451..5aee1311 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -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 diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart index 6c3e38cf..57efe7c6 100644 --- a/lib/core/utils/push_notification_handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -404,6 +404,9 @@ class PushNotificationHandler { String callerId, ) async { log('🎈 example: onDidAcceptIncomingCall $uuid - $callerId'); + + String zoomSessionID = callerId.split("*")[0]; + await voIPKit.acceptIncomingCall(callerState: CallStateType.calling); await voIPKit.callConnected(); @@ -414,10 +417,11 @@ class PushNotificationHandler { _currentCallId = null; await Future.delayed(Duration(seconds: 2)).then((val) async { await voIPKit.endCall(); + await voIPKit.dispose(); await FlutterCallkitIncoming.endAllCalls(); }); - await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, callerId); + await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, zoomSessionID); Utils.removeFromPrefs(CacheConst.isAppOpenedFromCall); Navigator.of(GetIt.instance().navigatorKey.currentContext!).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: LandingNavigation()))); @@ -426,21 +430,9 @@ class PushNotificationHandler { GetIt.instance().navigatorKey.currentContext!, AppRoutes.zoomCallPage, // arguments: CallArguments(appointmentID, "111", "Patient", "40", "1", true, 1), - arguments: CallArguments(callerId, "123", "Patient", "40", "0", true, int.parse("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!)), ); - - // Navigator.pushNamed( - // locator().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(); }; } diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart index caf97cb8..c4bd08d0 100644 --- a/lib/features/book_appointments/book_appointments_repo.dart +++ b/lib/features/book_appointments/book_appointments_repo.dart @@ -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,8 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo { "InitialSlotDuration": initialSlotDuration, "StrAppointmentDate": selectedDate, "IsVirtual": false, + "DeviceType": Platform.isIOS ? 'iOS' : 'Android', + "DeviceToken": await Utils.getStringFromPrefs(CacheConst.pushToken), "BookedBy": 102, "VisitType": 1, "VisitFor": 1, diff --git a/lib/features/immediate_livecare/immediate_livecare_view_model.dart b/lib/features/immediate_livecare/immediate_livecare_view_model.dart index 57bf6553..3fce9d22 100644 --- a/lib/features/immediate_livecare/immediate_livecare_view_model.dart +++ b/lib/features/immediate_livecare/immediate_livecare_view_model.dart @@ -236,7 +236,7 @@ class ImmediateLiveCareViewModel extends ChangeNotifier { Future 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 { diff --git a/pubspec.yaml b/pubspec.yaml index 64d4d22c..96a92965 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -64,7 +64,7 @@ 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 From 2175ff07845cd29d1a2cac9bbab087f08c63fb43 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 28 Oct 2026 16:05:52 +0300 Subject: [PATCH 11/15] updates --- lib/core/utils/push_notification_handler.dart | 2 +- lib/features/book_appointments/book_appointments_repo.dart | 2 ++ lib/features/my_appointments/my_appointments_repo.dart | 2 +- lib/presentation/medical_report/medical_reports_page.dart | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart index 57efe7c6..7c8c402e 100644 --- a/lib/core/utils/push_notification_handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -405,7 +405,7 @@ class PushNotificationHandler { ) async { log('🎈 example: onDidAcceptIncomingCall $uuid - $callerId'); - String zoomSessionID = callerId.split("*")[0]; + String zoomSessionID = callerId.split("_").sublist(0, callerId.split("_").length - 1).join("_"); await voIPKit.acceptIncomingCall(callerState: CallStateType.calling); await voIPKit.callConnected(); diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart index c4bd08d0..3707ab6f 100644 --- a/lib/features/book_appointments/book_appointments_repo.dart +++ b/lib/features/book_appointments/book_appointments_repo.dart @@ -762,6 +762,8 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo { "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, diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index 313fe56a..46d24eb7 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -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 }; diff --git a/lib/presentation/medical_report/medical_reports_page.dart b/lib/presentation/medical_report/medical_reports_page.dart index 33f9e6e3..8fdae4df 100644 --- a/lib/presentation/medical_report/medical_reports_page.dart +++ b/lib/presentation/medical_report/medical_reports_page.dart @@ -159,7 +159,8 @@ class _MedicalReportsPageState extends State { 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, From a0c907b39ce98d7073c943a47def7359cc53feb2 Mon Sep 17 00:00:00 2001 From: FaizHashmi Date: Sun, 1 Nov 2026 12:14:51 +0300 Subject: [PATCH 12/15] Added Arabic banner support and onTap support --- .../occasion_theme/occasion_config_model.dart | 40 +++++++++++++++---- .../occasion_theme_view_model.dart | 12 +++++- .../home/data/landing_page_data.dart | 4 +- lib/presentation/home/landing_page.dart | 5 ++- .../home/widgets/occasion_banner_widget.dart | 23 +++++++---- .../profile_settings/profile_settings.dart | 2 +- 6 files changed, 66 insertions(+), 20 deletions(-) diff --git a/lib/features/occasion_theme/occasion_config_model.dart b/lib/features/occasion_theme/occasion_config_model.dart index 26ddf733..53f8701d 100644 --- a/lib/features/occasion_theme/occasion_config_model.dart +++ b/lib/features/occasion_theme/occasion_config_model.dart @@ -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 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, }; } diff --git a/lib/features/occasion_theme/occasion_theme_view_model.dart b/lib/features/occasion_theme/occasion_theme_view_model.dart index 73f94ec7..210a6882 100644 --- a/lib/features/occasion_theme/occasion_theme_view_model.dart +++ b/lib/features/occasion_theme/occasion_theme_view_model.dart @@ -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. } } diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart index 026c1725..b9069bd6 100644 --- a/lib/presentation/home/data/landing_page_data.dart +++ b/lib/presentation/home/data/landing_page_data.dart @@ -14,7 +14,7 @@ class LandingPageData { icon: AppAssets.emergency_services_icon, title: getIt.get().isArabic() ? LocaleKeys.services3 : LocaleKeys.emergency2, subtitle: getIt.get().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().isArabic() ? LocaleKeys.services3 : LocaleKeys.emergency2, subtitle: getIt.get().isArabic() ? LocaleKeys.emergency2 : LocaleKeys.services3, - backgroundColor: AppColors.primaryRedColorBase, + backgroundColor: AppColors.primaryRedColor, iconColor: Colors.white, textColor: Colors.white, isBold: true, diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index b8cb01a5..d2e2737e 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -234,9 +234,12 @@ class _LandingPageState extends State { // (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().headerImage?.isNotEmpty ?? false; + final occasionThemeVmForBanner = context.watch(); + 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. diff --git a/lib/presentation/home/widgets/occasion_banner_widget.dart b/lib/presentation/home/widgets/occasion_banner_widget.dart index 1f19b826..89429d35 100644 --- a/lib/presentation/home/widgets/occasion_banner_widget.dart +++ b/lib/presentation/home/widgets/occasion_banner_widget.dart @@ -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( 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), + ); }, ); } diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index ce300c9b..9e5d12b5 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -758,7 +758,7 @@ class _FamilyCardWidgetState extends State { 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; From f4b019f8228251a4ae0f8678777af890e7d4e8c5 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 1 Nov 2026 12:16:22 +0300 Subject: [PATCH 13/15] updates --- lib/core/utils/push_notification_handler.dart | 7 +++++-- lib/services/remote_config_service.dart | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart index 7c8c402e..85643902 100644 --- a/lib/core/utils/push_notification_handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -389,6 +389,9 @@ class PushNotificationHandler { ) async { try { log('🎈 example: onDidRejectIncomingCall $uuid - $callerId'); + await voIPKit.endCall(); + await voIPKit.dispose(); + await FlutterCallkitIncoming.endAllCalls(); timeOutTimer.cancel(); // Cleanup on reject with API call if (_currentCallId != null) { @@ -407,7 +410,7 @@ class PushNotificationHandler { String zoomSessionID = callerId.split("_").sublist(0, callerId.split("_").length - 1).join("_"); - await voIPKit.acceptIncomingCall(callerState: CallStateType.calling); + await voIPKit.acceptIncomingCall(callerState: CallStateType.idle); await voIPKit.callConnected(); // Cleanup on accept - cancel timer and reset flags @@ -415,7 +418,7 @@ class PushNotificationHandler { _callTimeoutTimer = null; _isCallInProgress = false; _currentCallId = null; - await Future.delayed(Duration(seconds: 2)).then((val) async { + await Future.delayed(Duration(milliseconds: 1500)).then((val) async { await voIPKit.endCall(); await voIPKit.dispose(); await FlutterCallkitIncoming.endAllCalls(); diff --git a/lib/services/remote_config_service.dart b/lib/services/remote_config_service.dart index d39a7fbe..81f57026 100644 --- a/lib/services/remote_config_service.dart +++ b/lib/services/remote_config_service.dart @@ -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), ), ); From 1398fe362e6efa035b21e2fd4b123807bf057676 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 1 Nov 2026 12:17:17 +0300 Subject: [PATCH 14/15] updates --- ios/Runner.xcodeproj/project.pbxproj | 18 +++++++++++++----- pubspec.yaml | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 526f2efb..ccc93210 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -341,7 +341,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -401,10 +401,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; @@ -418,10 +422,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; @@ -601,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 = ""; @@ -789,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 = ""; @@ -820,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 = ""; @@ -866,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; }; diff --git a/pubspec.yaml b/pubspec.yaml index 96a92965..d7b449bf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ 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.050+1 #version: 4.6.1004+40501004 environment: From a974a8711a8dcbbe621b1511bd5b121d97e519ea Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 2 Nov 2026 15:15:25 +0300 Subject: [PATCH 15/15] updates --- lib/core/api/api_client.dart | 2 +- lib/core/utils/push_notification_handler.dart | 10 +++------- lib/presentation/home/landing_page.dart | 5 +++-- .../tele_consultation/zoom/call_screen.dart | 8 +++++++- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 317134e2..911d3c9a 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -210,7 +210,7 @@ class ApiClientImp implements ApiClient { } // body['TokenID'] = "@dm!n"; - // body['PatientID'] = 2101020; + // body['PatientID'] = 1018977; // body['PatientID'] = 53320; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart index 85643902..c8311e15 100644 --- a/lib/core/utils/push_notification_handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -317,7 +317,6 @@ class PushNotificationHandler { final voIPKit = FlutterIOSVoIPKit.instance; - late Timer timeOutTimer; bool isTalking = false; var data = { @@ -390,9 +389,7 @@ class PushNotificationHandler { try { log('🎈 example: onDidRejectIncomingCall $uuid - $callerId'); await voIPKit.endCall(); - await voIPKit.dispose(); await FlutterCallkitIncoming.endAllCalls(); - timeOutTimer.cancel(); // Cleanup on reject with API call if (_currentCallId != null) { await _endCallAndCleanup(_currentCallId!, isDeclined: true); @@ -410,7 +407,7 @@ class PushNotificationHandler { String zoomSessionID = callerId.split("_").sublist(0, callerId.split("_").length - 1).join("_"); - await voIPKit.acceptIncomingCall(callerState: CallStateType.idle); + await voIPKit.acceptIncomingCall(callerState: CallStateType.calling); await voIPKit.callConnected(); // Cleanup on accept - cancel timer and reset flags @@ -418,16 +415,15 @@ class PushNotificationHandler { _callTimeoutTimer = null; _isCallInProgress = false; _currentCallId = null; - await Future.delayed(Duration(milliseconds: 1500)).then((val) async { + await Future.delayed(Duration(milliseconds: 2000)).then((val) async { await voIPKit.endCall(); - await voIPKit.dispose(); await FlutterCallkitIncoming.endAllCalls(); }); await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, zoomSessionID); Utils.removeFromPrefs(CacheConst.isAppOpenedFromCall); - Navigator.of(GetIt.instance().navigatorKey.currentContext!).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: LandingNavigation()))); + // Navigator.of(GetIt.instance().navigatorKey.currentContext!).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: LandingNavigation()))); Navigator.pushReplacementNamed( // context, GetIt.instance().navigatorKey.currentContext!, diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index d2e2737e..a11bd611 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -170,7 +170,7 @@ class _LandingPageState extends State { emergencyServicesViewModel.checkPatientERAdvanceBalance(); // myAppointmentsViewModel.getPatientAppointmentQueueDetails(); notificationsViewModel.initNotificationsViewModel(); - medicalFileViewModel.getPatientAllergiesList(); + // medicalFileViewModel.getPatientAllergiesList(); if (Utils.havePrivilege(122)) { insuranceViewModel.initInsuranceProvider(isFromHomePage: true); @@ -292,7 +292,7 @@ class _LandingPageState extends State { myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.initAppointmentsViewModel(); myAppointmentsViewModel.getPatientAppointments(true, false, isForTimeLine: true); - medicalFileViewModel.getPatientAllergiesList(); + medicalFileViewModel.getPatientAllergiesList(); // Refresh Appointments Data // habibWalletVM.initHabibWalletProvider(); // habibWalletVM.getPatientBalanceAmount(); @@ -312,6 +312,7 @@ class _LandingPageState extends State { // 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)); diff --git a/lib/presentation/tele_consultation/zoom/call_screen.dart b/lib/presentation/tele_consultation/zoom/call_screen.dart index 1c9db67a..cf46e765 100644 --- a/lib/presentation/tele_consultation/zoom/call_screen.dart +++ b/lib/presentation/tele_consultation/zoom/call_screen.dart @@ -327,6 +327,9 @@ class _CallScreenState extends State { // 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().navigatorKey.currentContext; if (navContext != null && Navigator.canPop(navContext)) { @@ -1297,6 +1300,9 @@ class _CallScreenState extends State { // } 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 { multiCameraIndex: "0", videoAspect: VideoAspect.Original, fullScreen: false, - resolution: VideoResolution.Resolution180, + resolution: VideoResolution.Resolution720, ), ), );