From 693f57a13e95f2f2d312dc18a2e1da49aab9860e Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Wed, 9 Jun 2021 12:53:40 +0300 Subject: [PATCH 1/6] Merge branch 'development' into ZohaibKambrani * development: (102 commits) prescription changes pescription changes fix imports project refactoring working on feature medical profile prescription changes hot fix hot fix hot fix refactoring hot fix hot fix add prescription form changes Add Medical Report Page hot fix hot fix add prescription changes fix in note and AddReplayOnReferralPatient Add Prescription changes prescription changes ... # Conflicts: # lib/screens/patients/DischargedPatientPage.dart # lib/screens/patients/ReferralDischargedPatientDetails.dart # lib/screens/patients/insurance_approvals_details.dart # lib/screens/patients/patients_screen.dart # lib/screens/patients/profile/note/progress_note_screen.dart # lib/screens/patients/profile/referral/referral_patient_detail_in-paint.dart # lib/screens/prescription/update_prescription_form.dart # lib/screens/sick-leave/add-sickleave.dart # lib/widgets/patients/PatientCard.dart # pubspec.lock --- ios/Podfile.lock | 327 ----------- ios/Runner.xcodeproj/project.pbxproj | 44 +- ios/Runner/AppDelegate.swift | 31 +- ios/Runner/Assets.xcassets/Contents.json | 6 +- .../end_call.imageset/Contents.json | 21 + .../end_call.imageset/end_call.png | Bin 0 -> 21324 bytes .../expand_video.imageset/Contents.json | 21 + .../expand_video.imageset/expand.png | Bin 0 -> 5366 bytes .../float_video.imageset/Contents.json | 21 + .../float_video.imageset/Group 8024.png | Bin 0 -> 4953 bytes .../mic_mute.imageset/Contents.json | 21 + .../mic_mute.imageset/mic_mute.png | Bin 0 -> 6537 bytes .../mic_unmute.imageset/Contents.json | 21 + .../mic_unmute.imageset/Group 8020.png | Bin 0 -> 5904 bytes .../video_mute.imageset/Contents.json | 21 + .../video_mute.imageset/video_mute.png | Bin 0 -> 6438 bytes .../video_unmute.imageset/Contents.json | 21 + .../video_unmute.imageset/Group 8022.png | Bin 0 -> 5715 bytes ios/Runner/Base.lproj/Main.storyboard | 515 ++++++++++++------ ios/Runner/MainAppViewController.swift | 142 +++++ ios/Runner/VCEmbeder.swift | 71 +++ ios/Runner/VideoCallRequestParameters.swift | 27 + ...er.swift => VideoCallViewController.swift} | 177 +++--- lib/client/base_app_client.dart | 2 +- .../patient_profile_screen.dart | 102 ++-- pubspec.lock | 6 +- 26 files changed, 950 insertions(+), 647 deletions(-) delete mode 100644 ios/Podfile.lock create mode 100644 ios/Runner/Assets.xcassets/end_call.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/end_call.imageset/end_call.png create mode 100644 ios/Runner/Assets.xcassets/expand_video.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/expand_video.imageset/expand.png create mode 100644 ios/Runner/Assets.xcassets/float_video.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/float_video.imageset/Group 8024.png create mode 100644 ios/Runner/Assets.xcassets/mic_mute.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/mic_mute.imageset/mic_mute.png create mode 100644 ios/Runner/Assets.xcassets/mic_unmute.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/mic_unmute.imageset/Group 8020.png create mode 100644 ios/Runner/Assets.xcassets/video_mute.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/video_mute.imageset/video_mute.png create mode 100644 ios/Runner/Assets.xcassets/video_unmute.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/video_unmute.imageset/Group 8022.png create mode 100644 ios/Runner/MainAppViewController.swift create mode 100644 ios/Runner/VCEmbeder.swift create mode 100644 ios/Runner/VideoCallRequestParameters.swift rename ios/Runner/{VideoViewController.swift => VideoCallViewController.swift} (84%) diff --git a/ios/Podfile.lock b/ios/Podfile.lock deleted file mode 100644 index 44151727..00000000 --- a/ios/Podfile.lock +++ /dev/null @@ -1,327 +0,0 @@ -PODS: - - Alamofire (5.4.3) - - barcode_scan_fix (0.0.1): - - Flutter - - MTBBarcodeScanner - - connectivity (0.0.1): - - Flutter - - Reachability - - connectivity_for_web (0.1.0): - - Flutter - - connectivity_macos (0.0.1): - - Flutter - - device_info (0.0.1): - - Flutter - - Firebase/CoreOnly (6.33.0): - - FirebaseCore (= 6.10.3) - - Firebase/Messaging (6.33.0): - - Firebase/CoreOnly - - FirebaseMessaging (~> 4.7.0) - - firebase_core (0.5.3): - - Firebase/CoreOnly (~> 6.33.0) - - Flutter - - firebase_core_web (0.1.0): - - Flutter - - firebase_messaging (7.0.3): - - Firebase/CoreOnly (~> 6.33.0) - - Firebase/Messaging (~> 6.33.0) - - firebase_core - - Flutter - - FirebaseCore (6.10.3): - - FirebaseCoreDiagnostics (~> 1.6) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/Logger (~> 6.7) - - FirebaseCoreDiagnostics (1.7.0): - - GoogleDataTransport (~> 7.4) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/Logger (~> 6.7) - - nanopb (~> 1.30906.0) - - FirebaseInstallations (1.7.0): - - FirebaseCore (~> 6.10) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/UserDefaults (~> 6.7) - - PromisesObjC (~> 1.2) - - FirebaseInstanceID (4.8.0): - - FirebaseCore (~> 6.10) - - FirebaseInstallations (~> 1.6) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/UserDefaults (~> 6.7) - - FirebaseMessaging (4.7.1): - - FirebaseCore (~> 6.10) - - FirebaseInstanceID (~> 4.7) - - GoogleUtilities/AppDelegateSwizzler (~> 6.7) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/Reachability (~> 6.7) - - GoogleUtilities/UserDefaults (~> 6.7) - - Protobuf (>= 3.9.2, ~> 3.9) - - Flutter (1.0.0) - - flutter_flexible_toast (0.0.1): - - Flutter - - flutter_inappwebview (0.0.1): - - Flutter - - flutter_plugin_android_lifecycle (0.0.1): - - Flutter - - GoogleDataTransport (7.5.1): - - nanopb (~> 1.30906.0) - - GoogleUtilities/AppDelegateSwizzler (6.7.2): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Environment (6.7.2): - - PromisesObjC (~> 1.2) - - GoogleUtilities/Logger (6.7.2): - - GoogleUtilities/Environment - - GoogleUtilities/Network (6.7.2): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (6.7.2)" - - GoogleUtilities/Reachability (6.7.2): - - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (6.7.2): - - GoogleUtilities/Logger - - hexcolor (0.0.1): - - Flutter - - imei_plugin (0.0.1): - - Flutter - - local_auth (0.0.1): - - Flutter - - maps_launcher (0.0.1): - - Flutter - - MTBBarcodeScanner (5.0.11) - - nanopb (1.30906.0): - - nanopb/decode (= 1.30906.0) - - nanopb/encode (= 1.30906.0) - - nanopb/decode (1.30906.0) - - nanopb/encode (1.30906.0) - - OpenTok (2.15.3) - - path_provider_linux (0.0.1): - - Flutter - - path_provider_windows (0.0.1): - - Flutter - - "permission_handler (5.1.0+2)": - - Flutter - - PromisesObjC (1.2.12) - - Protobuf (3.17.0) - - Reachability (3.2) - - screen (0.0.1): - - Flutter - - shared_preferences (0.0.1): - - Flutter - - shared_preferences_linux (0.0.1): - - Flutter - - shared_preferences_macos (0.0.1): - - Flutter - - shared_preferences_web (0.0.1): - - Flutter - - shared_preferences_windows (0.0.1): - - Flutter - - speech_to_text (0.0.1): - - Flutter - - Try - - Try (2.1.1) - - url_launcher (0.0.1): - - Flutter - - url_launcher_linux (0.0.1): - - Flutter - - url_launcher_macos (0.0.1): - - Flutter - - url_launcher_web (0.0.1): - - Flutter - - url_launcher_windows (0.0.1): - - Flutter - - video_player (0.0.1): - - Flutter - - video_player_web (0.0.1): - - Flutter - - wakelock (0.0.1): - - Flutter - - webview_flutter (0.0.1): - - Flutter - -DEPENDENCIES: - - Alamofire (~> 5.2) - - barcode_scan_fix (from `.symlinks/plugins/barcode_scan_fix/ios`) - - connectivity (from `.symlinks/plugins/connectivity/ios`) - - connectivity_for_web (from `.symlinks/plugins/connectivity_for_web/ios`) - - connectivity_macos (from `.symlinks/plugins/connectivity_macos/ios`) - - device_info (from `.symlinks/plugins/device_info/ios`) - - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - - firebase_core_web (from `.symlinks/plugins/firebase_core_web/ios`) - - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - - Flutter (from `Flutter`) - - flutter_flexible_toast (from `.symlinks/plugins/flutter_flexible_toast/ios`) - - flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`) - - flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`) - - hexcolor (from `.symlinks/plugins/hexcolor/ios`) - - imei_plugin (from `.symlinks/plugins/imei_plugin/ios`) - - local_auth (from `.symlinks/plugins/local_auth/ios`) - - maps_launcher (from `.symlinks/plugins/maps_launcher/ios`) - - OpenTok - - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`) - - path_provider_windows (from `.symlinks/plugins/path_provider_windows/ios`) - - permission_handler (from `.symlinks/plugins/permission_handler/ios`) - - screen (from `.symlinks/plugins/screen/ios`) - - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - - shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`) - - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) - - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) - - shared_preferences_windows (from `.symlinks/plugins/shared_preferences_windows/ios`) - - speech_to_text (from `.symlinks/plugins/speech_to_text/ios`) - - url_launcher (from `.symlinks/plugins/url_launcher/ios`) - - url_launcher_linux (from `.symlinks/plugins/url_launcher_linux/ios`) - - url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`) - - url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`) - - url_launcher_windows (from `.symlinks/plugins/url_launcher_windows/ios`) - - video_player (from `.symlinks/plugins/video_player/ios`) - - video_player_web (from `.symlinks/plugins/video_player_web/ios`) - - wakelock (from `.symlinks/plugins/wakelock/ios`) - - webview_flutter (from `.symlinks/plugins/webview_flutter/ios`) - -SPEC REPOS: - trunk: - - Alamofire - - Firebase - - FirebaseCore - - FirebaseCoreDiagnostics - - FirebaseInstallations - - FirebaseInstanceID - - FirebaseMessaging - - GoogleDataTransport - - GoogleUtilities - - MTBBarcodeScanner - - nanopb - - OpenTok - - PromisesObjC - - Protobuf - - Reachability - - Try - -EXTERNAL SOURCES: - barcode_scan_fix: - :path: ".symlinks/plugins/barcode_scan_fix/ios" - connectivity: - :path: ".symlinks/plugins/connectivity/ios" - connectivity_for_web: - :path: ".symlinks/plugins/connectivity_for_web/ios" - connectivity_macos: - :path: ".symlinks/plugins/connectivity_macos/ios" - device_info: - :path: ".symlinks/plugins/device_info/ios" - firebase_core: - :path: ".symlinks/plugins/firebase_core/ios" - firebase_core_web: - :path: ".symlinks/plugins/firebase_core_web/ios" - firebase_messaging: - :path: ".symlinks/plugins/firebase_messaging/ios" - Flutter: - :path: Flutter - flutter_flexible_toast: - :path: ".symlinks/plugins/flutter_flexible_toast/ios" - flutter_inappwebview: - :path: ".symlinks/plugins/flutter_inappwebview/ios" - flutter_plugin_android_lifecycle: - :path: ".symlinks/plugins/flutter_plugin_android_lifecycle/ios" - hexcolor: - :path: ".symlinks/plugins/hexcolor/ios" - imei_plugin: - :path: ".symlinks/plugins/imei_plugin/ios" - local_auth: - :path: ".symlinks/plugins/local_auth/ios" - maps_launcher: - :path: ".symlinks/plugins/maps_launcher/ios" - path_provider_linux: - :path: ".symlinks/plugins/path_provider_linux/ios" - path_provider_windows: - :path: ".symlinks/plugins/path_provider_windows/ios" - permission_handler: - :path: ".symlinks/plugins/permission_handler/ios" - screen: - :path: ".symlinks/plugins/screen/ios" - shared_preferences: - :path: ".symlinks/plugins/shared_preferences/ios" - shared_preferences_linux: - :path: ".symlinks/plugins/shared_preferences_linux/ios" - shared_preferences_macos: - :path: ".symlinks/plugins/shared_preferences_macos/ios" - shared_preferences_web: - :path: ".symlinks/plugins/shared_preferences_web/ios" - shared_preferences_windows: - :path: ".symlinks/plugins/shared_preferences_windows/ios" - speech_to_text: - :path: ".symlinks/plugins/speech_to_text/ios" - url_launcher: - :path: ".symlinks/plugins/url_launcher/ios" - url_launcher_linux: - :path: ".symlinks/plugins/url_launcher_linux/ios" - url_launcher_macos: - :path: ".symlinks/plugins/url_launcher_macos/ios" - url_launcher_web: - :path: ".symlinks/plugins/url_launcher_web/ios" - url_launcher_windows: - :path: ".symlinks/plugins/url_launcher_windows/ios" - video_player: - :path: ".symlinks/plugins/video_player/ios" - video_player_web: - :path: ".symlinks/plugins/video_player_web/ios" - wakelock: - :path: ".symlinks/plugins/wakelock/ios" - webview_flutter: - :path: ".symlinks/plugins/webview_flutter/ios" - -SPEC CHECKSUMS: - Alamofire: e447a2774a40c996748296fa2c55112fdbbc42f9 - barcode_scan_fix: 80dd65de55f27eec6591dd077c8b85f2b79e31f1 - connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 - connectivity_for_web: 2b8584556930d4bd490d82b836bcf45067ce345b - connectivity_macos: e2e9731b6b22dda39eb1b128f6969d574460e191 - device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 - Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659 - firebase_core_web: d501d8b946b60c8af265428ce483b0fff5ad52d1 - firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 - FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd - FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 - FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2 - FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1 - FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a - Flutter: 0e3d915762c693b495b44d77113d4970485de6ec - flutter_flexible_toast: 0547e740cae0c33bb7c51bcd931233f4584e1143 - flutter_inappwebview: 69dfbac46157b336ffbec19ca6dfd4638c7bf189 - flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35 - GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 - GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 - hexcolor: fdfb9c4258ad96e949c2dbcdf790a62194b8aa89 - imei_plugin: cb1af7c223ac2d82dcd1457a7137d93d65d2a3cd - local_auth: 25938960984c3a7f6e3253e3f8d962fdd16852bd - maps_launcher: eae38ee13a9c3f210fa04e04bb4c073fa4c6ed92 - MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb - nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc - OpenTok: fde03ecc5ea31fe0a453242847c4ee1f47e1d735 - path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 - path_provider_windows: a2b81600c677ac1959367280991971cb9a1edb3b - permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0 - PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97 - Protobuf: 7327d4444215b5f18e560a97f879ff5503c4581c - Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 - screen: abd91ca7bf3426e1cc3646d27e9b2358d6bf07b0 - shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d - shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78 - shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 - shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 - shared_preferences_windows: 36b76d6f54e76ead957e60b49e2f124b4cd3e6ae - speech_to_text: b43a7d99aef037bd758ed8e45d79bbac035d2dfe - Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96 - url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef - url_launcher_linux: ac237cb7a8058736e4aae38bdbcc748a4b394cc0 - url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313 - url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c - url_launcher_windows: 683d7c283894db8d1914d3ab2223b20cc1ad95d5 - video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e - video_player_web: da8cadb8274ed4f8dbee8d7171b420dedd437ce7 - wakelock: 0d4a70faf8950410735e3f61fb15d517c8a6efc4 - webview_flutter: d2b4d6c66968ad042ad94cbb791f5b72b4678a96 - -PODFILE CHECKSUM: d0a3789a37635365b4345e456835ed9d30398217 - -COCOAPODS: 1.10.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index f0784432..0e446318 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -9,12 +9,15 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 29211E4225C172B700DD740D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 29211E4125C172B700DD740D /* GoogleService-Info.plist */; }; + 300790FA266FB14B0052174C /* VCEmbeder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 300790F9266FB14B0052174C /* VCEmbeder.swift */; }; + 30F70E6C266F56FD005D8F8E /* MainAppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */; }; + 30F70E6F266F6509005D8F8E /* VideoCallRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 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 */; }; - 9CE61EBD24AB366E008D68DD /* VideoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE61EBC24AB366E008D68DD /* VideoViewController.swift */; }; + 9CE61EBD24AB366E008D68DD /* VideoCallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE61EBC24AB366E008D68DD /* VideoCallViewController.swift */; }; 9CE61ECD24ADBB4C008D68DD /* ICallProtocoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */; }; B650DC3076E9D70CB188286A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93A5F83B23AB032D1E096663 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ @@ -37,6 +40,9 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 29211CD725C165D600DD740D /* RunnerRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerRelease.entitlements; sourceTree = ""; }; 29211E4125C172B700DD740D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 300790F9266FB14B0052174C /* VCEmbeder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCEmbeder.swift; sourceTree = ""; }; + 30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainAppViewController.swift; sourceTree = ""; }; + 30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallRequestParameters.swift; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; 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 = ""; }; @@ -50,7 +56,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 = ""; }; - 9CE61EBC24AB366E008D68DD /* VideoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoViewController.swift; sourceTree = ""; }; + 9CE61EBC24AB366E008D68DD /* VideoCallViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallViewController.swift; sourceTree = ""; }; 9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ICallProtocoll.swift; sourceTree = ""; }; 9D4B7DB43C6A6C849D2387CE /* 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 = ""; }; E698D7B14B12DF768FE47A1A /* 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 = ""; }; @@ -68,6 +74,30 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 300790F8266FB0F10052174C /* helpers */ = { + isa = PBXGroup; + children = ( + 300790F9266FB14B0052174C /* VCEmbeder.swift */, + ); + name = helpers; + sourceTree = ""; + }; + 30F70E6A266F56C9005D8F8E /* controllers */ = { + isa = PBXGroup; + children = ( + 30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */, + ); + name = controllers; + sourceTree = ""; + }; + 30F70E6D266F64F8005D8F8E /* Models */ = { + isa = PBXGroup; + children = ( + 30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */, + ); + name = Models; + sourceTree = ""; + }; 7D66D387293CE5376A07EC5F /* Pods */ = { isa = PBXGroup; children = ( @@ -111,6 +141,9 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 300790F8266FB0F10052174C /* helpers */, + 30F70E6D266F64F8005D8F8E /* Models */, + 30F70E6A266F56C9005D8F8E /* controllers */, 29211E4125C172B700DD740D /* GoogleService-Info.plist */, 29211CD725C165D600DD740D /* RunnerRelease.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, @@ -122,7 +155,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - 9CE61EBC24AB366E008D68DD /* VideoViewController.swift */, + 9CE61EBC24AB366E008D68DD /* VideoCallViewController.swift */, 9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */, ); path = Runner; @@ -290,10 +323,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 300790FA266FB14B0052174C /* VCEmbeder.swift in Sources */, + 30F70E6F266F6509005D8F8E /* VideoCallRequestParameters.swift in Sources */, 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 9CE61EBD24AB366E008D68DD /* VideoViewController.swift in Sources */, + 9CE61EBD24AB366E008D68DD /* VideoCallViewController.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 9CE61ECD24ADBB4C008D68DD /* ICallProtocoll.swift in Sources */, + 30F70E6C266F56FD005D8F8E /* MainAppViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index b97c7000..dc938e36 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -22,34 +22,8 @@ import OpenTok _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - let controller : FlutterViewController = window?.rootViewController as! FlutterViewController - let videoCallChannel = FlutterMethodChannel(name: "Dr.cloudSolution/videoCall", - binaryMessenger: controller.binaryMessenger) - videoCallChannel.setMethodCallHandler({ - (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in - self.result = result - switch call.method { - case "openVideoCall": - do { - let arguments = call.arguments as? NSDictionary - let kApiKey = arguments!["kApiKey"] as? String - let kSessionId = arguments!["kSessionId"] as? String - let kToken = arguments!["kToken"] as? String - let appLang = arguments!["appLang"] as? String - let vC_ID = arguments!["VC_ID"] as? Int - let tokenID = arguments!["TokenID"] as? String - let generalId = arguments!["generalId"] as? String - let doctorId = arguments!["DoctorId"] as? Int - let baseUrl = arguments!["baseUrl"] as? String - - self.openVideoChat(result: result,kApiKey: kApiKey!,kSessionId:kSessionId!,kToken: kToken!, appLang: appLang!, vC_ID: vC_ID!,tokenID: tokenID!,generalId: generalId!,doctorId: doctorId!, baseUrl: baseUrl!) - } - default: - result(FlutterMethodNotImplemented) - } - }) - GeneratedPluginRegistrant.register(with: self) + GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } @@ -61,7 +35,7 @@ import OpenTok let storyboard = UIStoryboard(name: "Main", bundle: nil) let identifier = "ViewControllerNav" let navVC = storyboard.instantiateViewController(withIdentifier: identifier) as! UINavigationController - let videoVC = navVC.viewControllers.first as! ViewController + let videoVC = navVC.viewControllers.first as! VideoCallViewController videoVC.kApiKey=kApiKey videoVC.kSessionId=kSessionId videoVC.kToken=kToken @@ -78,3 +52,4 @@ import OpenTok } } + diff --git a/ios/Runner/Assets.xcassets/Contents.json b/ios/Runner/Assets.xcassets/Contents.json index da4a164c..73c00596 100755 --- a/ios/Runner/Assets.xcassets/Contents.json +++ b/ios/Runner/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/ios/Runner/Assets.xcassets/end_call.imageset/Contents.json b/ios/Runner/Assets.xcassets/end_call.imageset/Contents.json new file mode 100644 index 00000000..3762a5af --- /dev/null +++ b/ios/Runner/Assets.xcassets/end_call.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "end_call.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/end_call.imageset/end_call.png b/ios/Runner/Assets.xcassets/end_call.imageset/end_call.png new file mode 100644 index 0000000000000000000000000000000000000000..52f8e267234d686e31be8a6e1b44287ab98364db GIT binary patch literal 21324 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 F@_+AV*hT;V literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/expand_video.imageset/Contents.json b/ios/Runner/Assets.xcassets/expand_video.imageset/Contents.json new file mode 100644 index 00000000..1ecfeae9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/expand_video.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "expand.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/expand_video.imageset/expand.png b/ios/Runner/Assets.xcassets/expand_video.imageset/expand.png new file mode 100644 index 0000000000000000000000000000000000000000..7020dc2ef8e2f6f35465c65c06836422cda0fd91 GIT binary patch literal 5366 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 PzPNO?j5Ob>+lTxQOg$37 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/mic_mute.imageset/Contents.json b/ios/Runner/Assets.xcassets/mic_mute.imageset/Contents.json new file mode 100644 index 00000000..2a0f4d2e --- /dev/null +++ b/ios/Runner/Assets.xcassets/mic_mute.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "mic_mute.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/mic_mute.imageset/mic_mute.png b/ios/Runner/Assets.xcassets/mic_mute.imageset/mic_mute.png new file mode 100644 index 0000000000000000000000000000000000000000..266cb6c72418b5aba18b32c421c2b4e75f05e47e GIT binary patch literal 6537 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 Becu28 literal 0 HcmV?d00001 diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard index 73e18f76..17833007 100755 --- a/ios/Runner/Base.lproj/Main.storyboard +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -1,16 +1,16 @@ - + - + - + - + @@ -23,12 +23,12 @@ - + - + - + @@ -37,252 +37,451 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - + - + + + + - + + @@ -292,5 +491,7 @@ + + diff --git a/ios/Runner/MainAppViewController.swift b/ios/Runner/MainAppViewController.swift new file mode 100644 index 00000000..c6466343 --- /dev/null +++ b/ios/Runner/MainAppViewController.swift @@ -0,0 +1,142 @@ +// +// MainAppViewController.swift +// Runner +// +// Created by Zohaib Iqbal Kambrani on 08/06/2021. +// Copyright © 2021 The Chromium Authors. All rights reserved. +// + +import Foundation + +class MainAppViewController: FlutterViewController{ + var videoCallContainer:UIView! + var videoCallViewController:VideoCallViewController! + var videoCallFlutterResult:FlutterResult? + var vdoCallViewMinConstraint:[NSLayoutConstraint]! + var vdoCallViewMaxConstraint:[NSLayoutConstraint]! + + + override func viewDidLoad() { + super.viewDidLoad() + initFlutterBridge() + prepareVideoCallView() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } + + private func initFlutterBridge(){ + let videoCallChannel = FlutterMethodChannel(name: "Dr.cloudSolution/videoCall", binaryMessenger: binaryMessenger) + videoCallChannel.setMethodCallHandler({ + (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + switch call.method { + case "openVideoCall": + self.startVideoCall(result: result, call: call) + default: + result(FlutterMethodNotImplemented) + } + }) + } + +} + + +// Video Call Functions +extension MainAppViewController : ICallProtocol{ + + func prepareVideoCallView(){ + videoCallContainer = UIView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height)) + videoCallContainer.alpha = 0.0 + videoCallContainer.backgroundColor = UIColor.black + view.addSubview(videoCallContainer) + setVideoViewConstrints() + NSLayoutConstraint.activate(vdoCallViewMaxConstraint) + NSLayoutConstraint.deactivate(vdoCallViewMinConstraint) + + ViewEmbedder.embed( + withIdentifier: "videoCall", // Storyboard ID + parent: self, + container: self.videoCallContainer){ vc in + self.videoCallViewController = vc as? VideoCallViewController + + } + } + + private func startVideoCall(result: @escaping FlutterResult, call:FlutterMethodCall) { + videoCallFlutterResult = result + + if let arguments = call.arguments as? NSDictionary{ + showVideoCallView(true) + + videoCallViewController.onMinimize = { min in + self.minimizeVideoCall(min) + } + videoCallViewController.onClose = videoCallClosed + videoCallViewController.callBack = self + videoCallViewController.start(params: VideoCallRequestParameters(dictionary: arguments)) + } + + + } + + private func minimizeVideoCall(_ value:Bool){ + UIView.animate(withDuration: 0.5) { + if(value){ + NSLayoutConstraint.deactivate(self.vdoCallViewMaxConstraint) + NSLayoutConstraint.activate(self.vdoCallViewMinConstraint) + }else{ + NSLayoutConstraint.deactivate(self.vdoCallViewMinConstraint) + NSLayoutConstraint.activate(self.vdoCallViewMaxConstraint) + } + self.videoCallContainer.layer.cornerRadius = value ? 10 : 0 + self.videoCallContainer.layer.borderColor = value ? UIColor.white.cgColor : nil + self.videoCallContainer.layer.borderWidth = value ? 2 : 0 + self.view.layoutIfNeeded() + } + } + + private func showVideoCallView(_ value:Bool){ + UIView.animate(withDuration: 0.5) { + self.videoCallContainer.alpha = value ? 1.0 : 0.0 + } completion: { complete in + if(value == false){ + self.videoCallContainer.removeFromSuperview() + } + } + } + + private func videoCallClosed(){ + showVideoCallView(false) + } + + func sessionDone(res: Any) { + videoCallFlutterResult?(res) + } + + func sessionNotResponded(res: Any) { + videoCallFlutterResult?(res) + } + + + func setVideoViewConstrints(){ + let screen = UIScreen.main.bounds + + + videoCallContainer.translatesAutoresizingMaskIntoConstraints = false + + vdoCallViewMinConstraint = [ + videoCallContainer.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), + videoCallContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + videoCallContainer.widthAnchor.constraint(equalToConstant: screen.width/3), + videoCallContainer.heightAnchor.constraint(equalToConstant: screen.height/3.5) + ] + vdoCallViewMaxConstraint = [ + videoCallContainer.topAnchor.constraint(equalTo: view.topAnchor), + videoCallContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor), + videoCallContainer.widthAnchor.constraint(equalToConstant: screen.width), + videoCallContainer.heightAnchor.constraint(equalToConstant: screen.height) + ] + } + +} diff --git a/ios/Runner/VCEmbeder.swift b/ios/Runner/VCEmbeder.swift new file mode 100644 index 00000000..e86dde75 --- /dev/null +++ b/ios/Runner/VCEmbeder.swift @@ -0,0 +1,71 @@ +// +// VCEmbeder.swift +// Runner +// +// Created by Zohaib Iqbal Kambrani on 08/06/2021. +// Copyright © 2021 The Chromium Authors. All rights reserved. +// + +import Foundation + +extension UIView { + func fill(to parent: UIView) { + topAnchor.constraint(equalTo: parent.topAnchor).isActive = true + leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true + bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true + trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true + } + + func fillToParent() { + if let parent = self.superview{ + topAnchor.constraint(equalTo: parent.topAnchor).isActive = true + leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true + bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true + trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true + } + } + + func fillTo(view:UIView) { + view.addSubview(self) + fill(to: view) + } +} + +class ViewEmbedder { + class func embed( + parent:UIViewController, + container:UIView, + child:UIViewController, + previous:UIViewController?){ + + if let previous = previous { + removeFromParent(vc: previous) + } + child.willMove(toParent: parent) + parent.addChild(child) + container.addSubview(child.view) + child.didMove(toParent: parent) + let w = container.frame.size.width; + let h = container.frame.size.height; + child.view.frame = CGRect(x: 0, y: 0, width: w, height: h) + + child.view.fill(to: container) + } + + class func removeFromParent(vc:UIViewController){ + vc.willMove(toParent: nil) + vc.view.removeFromSuperview() + vc.removeFromParent() + } + + class func embed(withIdentifier id:String, parent:UIViewController, container:UIView, completion:((UIViewController)->Void)? = nil){ + let vc = parent.storyboard!.instantiateViewController(withIdentifier: id) + embed( + parent: parent, + container: container, + child: vc, + previous: parent.children.first + ) + completion?(vc) + } +} diff --git a/ios/Runner/VideoCallRequestParameters.swift b/ios/Runner/VideoCallRequestParameters.swift new file mode 100644 index 00000000..2366c562 --- /dev/null +++ b/ios/Runner/VideoCallRequestParameters.swift @@ -0,0 +1,27 @@ + + +import Foundation + +class VideoCallRequestParameters{ + var apiKey:String? + var sessionId:String? + var token:String? + var lang:String? + var vcId:Int? + var tokenId:String? + var generalId:String? + var doctorId:Int? + var baseUrl:String? + + init(dictionary:NSDictionary){ + self.apiKey = dictionary["kApiKey"] as? String + self.sessionId = dictionary["kSessionId"] as? String + self.token = dictionary["kToken"] as? String + self.lang = dictionary["appLang"] as? String + self.vcId = dictionary["VC_ID"] as? Int + self.tokenId = dictionary["TokenID"] as? String + self.generalId = dictionary["generalId"] as? String + self.doctorId = dictionary["DoctorId"] as? Int + self.baseUrl = dictionary["baseUrl"] as? String + } +} diff --git a/ios/Runner/VideoViewController.swift b/ios/Runner/VideoCallViewController.swift similarity index 84% rename from ios/Runner/VideoViewController.swift rename to ios/Runner/VideoCallViewController.swift index 44e45f3a..a05957c9 100644 --- a/ios/Runner/VideoViewController.swift +++ b/ios/Runner/VideoCallViewController.swift @@ -11,7 +11,7 @@ import OpenTok import Alamofire -class ViewController: UIViewController { +class VideoCallViewController: UIViewController { var session: OTSession? var publisher: OTPublisher? @@ -34,18 +34,104 @@ class ViewController: UIViewController { var seconds = 30 var isUserConnect : Bool = false + var onMinimize:((Bool)->Void)? = nil + var onClose:(()->Void)? = nil + + // Bottom Actions + @IBOutlet weak var actionsHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var videoMuteBtn: UIButton! + @IBOutlet weak var micMuteBtn: UIButton! + + @IBOutlet weak var localvideoTopMargin: NSLayoutConstraint! + @IBOutlet weak var localVideo: UIView! + @IBOutlet weak var remoteVideo: UIView! + @IBOutlet weak var controlButtons: UIView! + @IBOutlet weak var remoteVideoMutedIndicator: UIImageView! + @IBOutlet weak var localVideoMutedBg: UIView! override func viewDidLoad() { - super.viewDidLoad() + super.viewDidLoad() + localVideo.layer.borderColor = UIColor.white.cgColor + } + + @IBAction func didClickMuteButton(_ sender: UIButton) { + sender.isSelected = !sender.isSelected + publisher!.publishAudio = !sender.isSelected - setupButtons() - askForMicrophonePermission() - requestCameraPermissionsIfNeeded() - hideVideoMuted() - setupSession() - - } + } + @IBAction func didClickSpeakerButton(_ sender: UIButton) { + sender.isSelected = !sender.isSelected + subscriber?.subscribeToAudio = !sender.isSelected + // resetHideButtonsTimer() + } + + @IBAction func didClickVideoMuteButton(_ sender: UIButton) { + sender.isSelected = !sender.isSelected + if publisher!.publishVideo { + publisher!.publishVideo = false + } else { + publisher!.publishVideo = true + } + localVideo.isHidden = sender.isSelected + localVideoMutedBg.isHidden = !sender.isSelected + // resetHideButtonsTimer() + + } + + + @IBAction func didClickSwitchCameraButton(_ sender: UIButton) { + sender.isSelected = !sender.isSelected + if sender.isSelected { + publisher!.cameraPosition = AVCaptureDevice.Position.front + } else { + publisher!.cameraPosition = AVCaptureDevice.Position.back + } + /// resetHideButtonsTimer() + } + + @IBAction func hangUp(_ sender: UIButton) { + callBack?.sessionDone(res:["callResponse":"CallEnd"]) + sessionDisconnect() + } + + var minimized = false + @IBAction func onMinimize(_ sender: UIButton) { + minimized = !minimized + sender.isSelected = minimized + onMinimize?(minimized) + + self.videoMuteBtn.isHidden = minimized + self.micMuteBtn.isHidden = minimized + + let min_ = minimized + UIView.animate(withDuration: 1) { + self.actionsHeightConstraint.constant = min_ ? 30 : 60 + self.localvideoTopMargin.constant = min_ ? 20 : 40 + + let vdoBound = self.localVideo.bounds + self.publisher?.view?.frame = CGRect(x: 0, y: 0, width: vdoBound.size.width, height: vdoBound.size.height) + self.publisher?.view?.layoutIfNeeded() + } + } + + func start(params:VideoCallRequestParameters){ + + self.kApiKey = params.apiKey ?? "" + self.kSessionId = params.sessionId ?? "" + self.kToken = params.token ?? "" + self.VC_ID = params.vcId ?? 0 + self.generalid = params.generalId ?? "" + self.TokenID = params.tokenId ?? "" + self.DoctorId = params.doctorId ?? 0 + self.baseUrl = params.baseUrl ?? "" + + setupButtons() + askForMicrophonePermission() + requestCameraPermissionsIfNeeded() + hideVideoMuted() + setupSession() + } private func changeCallStatus(callStatus:Int){ let URL_USER_REGISTER = baseUrl+"LiveCareApi/DoctorApp/ChangeCallStatus" @@ -137,59 +223,15 @@ class ViewController: UIViewController { // display a useful message asking the user to grant permissions from within Settings > Privacy > Camera } - - @IBAction func didClickMuteButton(_ sender: UIButton) { - sender.isSelected = !sender.isSelected - publisher!.publishAudio = !sender.isSelected - - } - - @IBAction func didClickSpeakerButton(_ sender: UIButton) { - sender.isSelected = !sender.isSelected - subscriber?.subscribeToAudio = !sender.isSelected - // resetHideButtonsTimer() - } - - @IBAction func didClickVideoMuteButton(_ sender: UIButton) { - sender.isSelected = !sender.isSelected - if publisher!.publishVideo { - publisher!.publishVideo = false - } else { - publisher!.publishVideo = true - } - localVideo.isHidden = sender.isSelected - localVideoMutedBg.isHidden = !sender.isSelected - localVideoMutedIndicator.isHidden = !sender.isSelected - // resetHideButtonsTimer() - - } - - - @IBAction func didClickSwitchCameraButton(_ sender: UIButton) { - sender.isSelected = !sender.isSelected - if sender.isSelected { - publisher!.cameraPosition = AVCaptureDevice.Position.front - } else { - publisher!.cameraPosition = AVCaptureDevice.Position.back - } - /// resetHideButtonsTimer() - } - - @IBAction func hangUp(_ sender: UIButton) { - callBack?.sessionDone(res:["callResponse":"CallEnd"]) - sessionDisconnect() - } - - func sessionDisconnect() { changeCallStatus(callStatus: 16) if (session != nil) { print("disconnecting....") session!.disconnect(nil) dismiss(animated: true) - return } dismiss(animated: true) + onClose?() } func requestCameraPermissionsIfNeeded() { @@ -226,7 +268,6 @@ class ViewController: UIViewController { func hideVideoMuted() { remoteVideoMutedIndicator.isHidden = true localVideoMutedBg.isHidden = true - localVideoMutedIndicator.isHidden = true } func setupSession() { @@ -267,19 +308,6 @@ class ViewController: UIViewController { - @IBOutlet weak var localVideo: UIView! - - @IBOutlet weak var remoteVideo: UIView! - - @IBOutlet weak var controlButtons: UIView! - - @IBOutlet weak var remoteVideoMutedIndicator: UIImageView! - - @IBOutlet weak var localVideoMutedBg: UIImageView! - - - @IBOutlet weak var localVideoMutedIndicator: UIImageView! - @objc func updateTimer(){ seconds -= 1 //This will decrement(count down)the seconds. print(seconds) @@ -293,7 +321,7 @@ class ViewController: UIViewController { } -extension ViewController: OTSessionDelegate { +extension VideoCallViewController: OTSessionDelegate { func sessionDidConnect(_ session: OTSession) { print("The client connected to the OpenTok session.") @@ -301,7 +329,7 @@ extension ViewController: OTSessionDelegate { - timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true) + timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(VideoCallViewController.updateTimer)), userInfo: nil, repeats: true) setupPublisher() @@ -318,9 +346,8 @@ extension ViewController: OTSessionDelegate { if error != nil { showAlert(error?.localizedDescription) } - - publisher?.view!.frame = CGRect(x: localVideo.bounds.origin.x, y: localVideo.bounds.origin.y, width: localVideo.bounds.size.width, height: localVideo.bounds.size.height) - + + publisher?.view!.frame = CGRect(x: 0, y: 0, width: localVideo.bounds.size.width, height: localVideo.bounds.size.height) localVideo.addSubview((publisher?.view)!) } @@ -408,7 +435,7 @@ extension ViewController: OTSessionDelegate { } -extension ViewController: OTPublisherDelegate { +extension VideoCallViewController: OTPublisherDelegate { func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) { print("The publisher failed: \(error)") } @@ -420,7 +447,7 @@ extension ViewController: OTPublisherDelegate { } } -extension ViewController: OTSubscriberDelegate { +extension VideoCallViewController: OTSubscriberDelegate { public func subscriberDidConnect(toStream subscriber: OTSubscriberKit) { print("The subscriber did connect to the stream.") } diff --git a/lib/client/base_app_client.dart b/lib/client/base_app_client.dart index 10181bf4..c011a4e1 100644 --- a/lib/client/base_app_client.dart +++ b/lib/client/base_app_client.dart @@ -109,7 +109,7 @@ class BaseAppClient { parsed['AndroidLink'], parsed['IOSLink']); } - if (!parsed['IsAuthenticated']) { + if (parsed['IsAuthenticated'] != null && !parsed['IsAuthenticated']) { if (body['OTP_SendType'] != null) { onFailure(getError(parsed), statusCode); } else if (!isAllowAny) { diff --git a/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart b/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart index 55b2d6f9..30f53a0b 100644 --- a/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart +++ b/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart @@ -289,60 +289,64 @@ class _PatientProfileScreenState extends State EndCallScreen(patient:patient))); } else { GifLoaderDialogUtils.showMyDialog(context); - await model.startCall( isReCall : false, vCID: patient.vcId); + // await model.startCall( isReCall : false, vCID: patient.vcId); - if(model.state == ViewState.ErrorLocal) { - GifLoaderDialogUtils.hideDialog(context); - Helpers.showErrorToast(model.error); - } else { - await model.getDoctorProfile(); - patient.appointmentNo = model.startCallRes.appointmentNo; - patient.episodeNo = 0; + if(model.state == ViewState.ErrorLocal) { + GifLoaderDialogUtils.hideDialog(context); + Helpers.showErrorToast(model.error); + } else { + await model.getDoctorProfile(); + // patient.appointmentNo = model.startCallRes.appointmentNo; + patient.episodeNo = 0; - GifLoaderDialogUtils.hideDialog(context); - await VideoChannel.openVideoCallScreen( - kToken: model.startCallRes.openTokenID, - kSessionId: model.startCallRes.openSessionID, - kApiKey: '46209962', - vcId: patient.vcId, - tokenID: await model.getToken(), - generalId: GENERAL_ID, - doctorId: model.doctorProfile.doctorID, - onFailure: (String error) { - DrAppToastMsg.showErrorToast(error); - }, - onCallEnd: () { - WidgetsBinding.instance.addPostFrameCallback((_) { - GifLoaderDialogUtils.showMyDialog(context); - model.endCall(patient.vcId, false,).then((value) { - GifLoaderDialogUtils.hideDialog(context); - if (model.state == ViewState.ErrorLocal) { - DrAppToastMsg.showErrorToast(model.error); - } - setState(() { - isCallFinished = true; - }); - }); - }); - }, - onCallNotRespond: (SessionStatusModel sessionStatusModel) { - WidgetsBinding.instance.addPostFrameCallback((_) { - GifLoaderDialogUtils.showMyDialog(context); - model.endCall(patient.vcId, sessionStatusModel.sessionStatus == 3,).then((value) { - GifLoaderDialogUtils.hideDialog(context); - if (model.state == ViewState.ErrorLocal) { - DrAppToastMsg.showErrorToast(model.error); - } - setState(() { - isCallFinished = true; - }); - }); + GifLoaderDialogUtils.hideDialog(context); + await VideoChannel.openVideoCallScreen( + kToken: "T1==cGFydG5lcl9pZD00NzI0Nzk1NCZzaWc9NGIyZDljOTY3YjFiNWU1YzUzNzFmMjIyNjJmNmEzY2Y5NzZjOTdlYzpzZXNzaW9uX2lkPTFfTVg0ME56STBOemsxTkg1LU1UWXlNekEyTlRRMU9EVXhObjVrVFRoMFlVdFJXaXRYTWpadFZGZHFhSGxZVGpOdE1UVi1mZyZjcmVhdGVfdGltZT0xNjIzMDY1NDk1Jm5vbmNlPTAuMjM2Mjk0NTIwMTkyOTA4OTcmcm9sZT1wdWJsaXNoZXImZXhwaXJlX3RpbWU9MTYyNTY1NzQ5NCZpbml0aWFsX2xheW91dF9jbGFzc19saXN0PQ==",//model.startCallRes.openTokenID, + kSessionId:"1_MX40NzI0Nzk1NH5-MTYyMzA2NTQ1ODUxNn5kTTh0YUtRWitXMjZtVFdqaHlYTjNtMTV-fg",// model.startCallRes.openSessionID, + kApiKey: '47247954',//46209962 + vcId: patient.vcId, + tokenID: await model.getToken(), + generalId: GENERAL_ID, + doctorId: model.doctorProfile.doctorID, + onFailure: (String error) { + DrAppToastMsg.showErrorToast(error); + }, + onCallEnd: () { + var asd=""; + // WidgetsBinding.instance.addPostFrameCallback((_) { + // GifLoaderDialogUtils.showMyDialog(context); + // model.endCall(patient.vcId, false,).then((value) { + // GifLoaderDialogUtils.hideDialog(context); + // if (model.state == ViewState.ErrorLocal) { + // DrAppToastMsg.showErrorToast(model.error); + // } + // setState(() { + // isCallFinished = true; + // }); + // }); + // }); + }, + onCallNotRespond: (SessionStatusModel sessionStatusModel) { + var asd=""; + // WidgetsBinding.instance.addPostFrameCallback((_) { + // GifLoaderDialogUtils.showMyDialog(context); + // model.endCall(patient.vcId, sessionStatusModel.sessionStatus == 3,).then((value) { + // GifLoaderDialogUtils.hideDialog(context); + // if (model.state == ViewState.ErrorLocal) { + // DrAppToastMsg.showErrorToast(model.error); + // } + // setState(() { + // isCallFinished = true; + // }); + // }); + // + // }); + }); - }); - }); - } + } } + }, ), ), diff --git a/pubspec.lock b/pubspec.lock index 25596d43..77df9848 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -629,7 +629,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.4" + version: "1.3.0-nullsafety.3" mime: dependency: transitive description: @@ -921,7 +921,7 @@ packages: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.2" + version: "1.10.0-nullsafety.1" sticky_headers: dependency: "direct main" description: @@ -1119,5 +1119,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=2.10.0 <=2.11.0-213.1.beta" + dart: ">=2.10.0 <2.11.0" flutter: ">=1.22.0 <2.0.0" From 1a158f49bb7de67116f40b932619c35a5576b9d2 Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Wed, 9 Jun 2021 16:23:18 +0300 Subject: [PATCH 2/6] no message --- ios/Runner/Base.lproj/Main.storyboard | 21 ++++++--- ios/Runner/MainAppViewController.swift | 11 +++-- ios/Runner/VCEmbeder.swift | 30 +++++++----- ios/Runner/VideoCallViewController.swift | 58 ++++++++++-------------- 4 files changed, 64 insertions(+), 56 deletions(-) diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard index 17833007..9f1b5e1a 100755 --- a/ios/Runner/Base.lproj/Main.storyboard +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -39,6 +39,7 @@ + @@ -50,7 +51,7 @@ - + @@ -78,6 +79,11 @@ + + + + + @@ -134,6 +140,7 @@ + @@ -150,6 +157,7 @@ + @@ -160,20 +168,19 @@ + - - + + - - + + - - diff --git a/ios/Runner/MainAppViewController.swift b/ios/Runner/MainAppViewController.swift index c6466343..9a59b862 100644 --- a/ios/Runner/MainAppViewController.swift +++ b/ios/Runner/MainAppViewController.swift @@ -47,8 +47,10 @@ extension MainAppViewController : ICallProtocol{ func prepareVideoCallView(){ videoCallContainer = UIView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height)) - videoCallContainer.alpha = 0.0 videoCallContainer.backgroundColor = UIColor.black + videoCallContainer.isHidden = true + videoCallContainer.clipsToBounds = true + view.addSubview(videoCallContainer) setVideoViewConstrints() NSLayoutConstraint.activate(vdoCallViewMaxConstraint) @@ -97,12 +99,13 @@ extension MainAppViewController : ICallProtocol{ } private func showVideoCallView(_ value:Bool){ + videoCallContainer.alpha = value ? 0.0 : 1 + self.videoCallContainer.isHidden = !value + UIView.animate(withDuration: 0.5) { self.videoCallContainer.alpha = value ? 1.0 : 0.0 } completion: { complete in - if(value == false){ - self.videoCallContainer.removeFromSuperview() - } + self.videoCallContainer.isHidden = !value } } diff --git a/ios/Runner/VCEmbeder.swift b/ios/Runner/VCEmbeder.swift index e86dde75..7e2ea0fd 100644 --- a/ios/Runner/VCEmbeder.swift +++ b/ios/Runner/VCEmbeder.swift @@ -9,25 +9,31 @@ import Foundation extension UIView { - func fill(to parent: UIView) { - topAnchor.constraint(equalTo: parent.topAnchor).isActive = true - leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true - bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true - trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true + func fill(to parent: UIView, animateDuration:Double = 0.5) { + self.topAnchor.constraint(equalTo: parent.topAnchor).isActive = true + self.leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true + self.bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true + self.trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true + UIView.animate(withDuration: animateDuration) { + parent.layoutIfNeeded() + } } - func fillToParent() { + func fillToParent(animateDuration:Double = 0.5) { if let parent = self.superview{ - topAnchor.constraint(equalTo: parent.topAnchor).isActive = true - leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true - bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true - trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true + self.topAnchor.constraint(equalTo: parent.topAnchor).isActive = true + self.leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true + self.bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true + self.trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true + UIView.animate(withDuration: animateDuration) { + parent.layoutIfNeeded() + } } } - func fillTo(view:UIView) { + func fillInTo(view:UIView) { view.addSubview(self) - fill(to: view) + fillToParent() } } diff --git a/ios/Runner/VideoCallViewController.swift b/ios/Runner/VideoCallViewController.swift index a05957c9..689c9f63 100644 --- a/ios/Runner/VideoCallViewController.swift +++ b/ios/Runner/VideoCallViewController.swift @@ -101,17 +101,19 @@ class VideoCallViewController: UIViewController { sender.isSelected = minimized onMinimize?(minimized) - self.videoMuteBtn.isHidden = minimized - self.micMuteBtn.isHidden = minimized - let min_ = minimized - UIView.animate(withDuration: 1) { + UIView.animate(withDuration: 0.5) { self.actionsHeightConstraint.constant = min_ ? 30 : 60 self.localvideoTopMargin.constant = min_ ? 20 : 40 + self.videoMuteBtn.isHidden = min_ + self.micMuteBtn.isHidden = min_ - let vdoBound = self.localVideo.bounds - self.publisher?.view?.frame = CGRect(x: 0, y: 0, width: vdoBound.size.width, height: vdoBound.size.height) + let localVdoSize = self.localVideo.bounds.size + let remoteVdoSize = self.remoteVideo.bounds.size + self.publisher?.view?.frame = CGRect(x: 0, y: 0, width: localVdoSize.width, height: localVdoSize.height) + self.subscriber?.view?.frame = CGRect(x: 0, y: 0, width: remoteVdoSize.width, height: remoteVdoSize.height) self.publisher?.view?.layoutIfNeeded() + self.subscriber?.view?.layoutIfNeeded() } } @@ -324,14 +326,8 @@ class VideoCallViewController: UIViewController { extension VideoCallViewController: OTSessionDelegate { func sessionDidConnect(_ session: OTSession) { - print("The client connected to the OpenTok session.") - - - - - timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(VideoCallViewController.updateTimer)), userInfo: nil, repeats: true) - - + print("The client connected to the OpenTok session.") + timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(VideoCallViewController.updateTimer)), userInfo: nil, repeats: true) setupPublisher() } @@ -373,27 +369,23 @@ extension VideoCallViewController: OTSessionDelegate { func session(_ session: OTSession, streamCreated stream: OTStream) { - subscriber = OTSubscriber(stream: stream, delegate: self) - guard let subscriber = subscriber else { - return - } + subscriber = OTSubscriber(stream: stream, delegate: self) + guard let subscriber = subscriber else { + return + } - var error: OTError? - session.subscribe(subscriber, error: &error) - guard error == nil else { - print(error!) - return - } + var error: OTError? + session.subscribe(subscriber, error: &error) + guard error == nil else { + print(error!) + return + } - guard let subscriberView = subscriber.view else { - return - } - subscriberView.frame = UIScreen.main.bounds - view.insertSubview(subscriberView, at: 0) - -// if nil == subscriber { -// setupSubscribe(stream) -// } + guard let subscriberView = subscriber.view else { + return + } + subscriberView.frame = CGRect(x: 0, y: 0, width: remoteVideo.bounds.width, height: remoteVideo.bounds.height) + remoteVideo.addSubview(subscriberView) } func setupSubscribe(_ stream: OTStream?) { From 42a4f9330ac5819f6f763b2c84ea9570af2dd16f Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Thu, 10 Jun 2021 10:12:58 +0300 Subject: [PATCH 3/6] no message --- ios/Podfile | 1 + ios/Runner.xcodeproj/project.pbxproj | 4 ++++ ios/Runner/Base.lproj/Main.storyboard | 16 +++++++++++++--- ios/Runner/Extensions.swift | 20 ++++++++++++++++++++ ios/Runner/MainAppViewController.swift | 10 ++++++++-- ios/Runner/VideoCallViewController.swift | 18 +++++++++++++----- 6 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 ios/Runner/Extensions.swift diff --git a/ios/Podfile b/ios/Podfile index 62207805..c2335042 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -65,6 +65,7 @@ target 'Runner' do pod 'Flutter', :path => 'Flutter' pod 'OpenTok' pod 'Alamofire', '~> 5.2' + pod 'AADraggableView' # Plugin Pods # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 0e446318..66be39bf 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 29211E4225C172B700DD740D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 29211E4125C172B700DD740D /* GoogleService-Info.plist */; }; 300790FA266FB14B0052174C /* VCEmbeder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 300790F9266FB14B0052174C /* VCEmbeder.swift */; }; + 300790FC26710CAB0052174C /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 300790FB26710CAB0052174C /* Extensions.swift */; }; 30F70E6C266F56FD005D8F8E /* MainAppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */; }; 30F70E6F266F6509005D8F8E /* VideoCallRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; @@ -41,6 +42,7 @@ 29211CD725C165D600DD740D /* RunnerRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerRelease.entitlements; sourceTree = ""; }; 29211E4125C172B700DD740D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 300790F9266FB14B0052174C /* VCEmbeder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCEmbeder.swift; sourceTree = ""; }; + 300790FB26710CAB0052174C /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainAppViewController.swift; sourceTree = ""; }; 30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallRequestParameters.swift; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; @@ -78,6 +80,7 @@ isa = PBXGroup; children = ( 300790F9266FB14B0052174C /* VCEmbeder.swift */, + 300790FB26710CAB0052174C /* Extensions.swift */, ); name = helpers; sourceTree = ""; @@ -326,6 +329,7 @@ 300790FA266FB14B0052174C /* VCEmbeder.swift in Sources */, 30F70E6F266F6509005D8F8E /* VideoCallRequestParameters.swift in Sources */, 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 300790FC26710CAB0052174C /* Extensions.swift in Sources */, 9CE61EBD24AB366E008D68DD /* VideoCallViewController.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 9CE61ECD24ADBB4C008D68DD /* ICallProtocoll.swift in Sources */, diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard index 9f1b5e1a..12e173a7 100755 --- a/ios/Runner/Base.lproj/Main.storyboard +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -48,7 +48,7 @@ - + @@ -63,7 +63,7 @@ - + @@ -98,6 +98,11 @@ + + + + + @@ -237,7 +242,7 @@ - + @@ -282,6 +287,11 @@ + + + + + + + + + - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - + + - + - + + + + - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + - - - - - - - - diff --git a/ios/Runner/MainAppViewController.swift b/ios/Runner/MainAppViewController.swift index 35ef4e1b..a6e4bcea 100644 --- a/ios/Runner/MainAppViewController.swift +++ b/ios/Runner/MainAppViewController.swift @@ -32,8 +32,10 @@ class MainAppViewController: FlutterViewController{ videoCallChannel.setMethodCallHandler({ (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in switch call.method { - case "openVideoCall": - self.startVideoCall(result: result, call: call) + case "openVideoCall": + self.startVideoCall(result: result, call: call) + case "showVideo": + self.showVideo() default: result(FlutterMethodNotImplemented) } @@ -69,6 +71,10 @@ extension MainAppViewController : ICallProtocol{ } } + private func showVideo(){ + videoCallContainer.isHidden = false + } + private func startVideoCall(result: @escaping FlutterResult, call:FlutterMethodCall) { videoCallFlutterResult = result @@ -78,6 +84,9 @@ extension MainAppViewController : ICallProtocol{ videoCallViewController.onMinimize = { min in self.minimizeVideoCall(min) } + videoCallViewController.onHide = { + self.videoCallContainer.isHidden = true + } videoCallViewController.onClose = videoCallClosed videoCallViewController.callBack = self videoCallViewController.start(params: VideoCallRequestParameters(dictionary: arguments)) diff --git a/ios/Runner/VideoCallViewController.swift b/ios/Runner/VideoCallViewController.swift index 69d65fb3..3e8b612c 100644 --- a/ios/Runner/VideoCallViewController.swift +++ b/ios/Runner/VideoCallViewController.swift @@ -35,23 +35,30 @@ class VideoCallViewController: UIViewController { var isUserConnect : Bool = false var onMinimize:((Bool)->Void)? = nil + var onHide:(()->Void)? = nil var onClose:(()->Void)? = nil + + @IBOutlet weak var lblRemoteUsername: UILabel! + // Bottom Actions - @IBOutlet weak var actionsHeightConstraint: NSLayoutConstraint! @IBOutlet weak var videoMuteBtn: UIButton! @IBOutlet weak var micMuteBtn: UIButton! - @IBOutlet weak var localvideoTopMargin: NSLayoutConstraint! + @IBOutlet var minimizeConstraint: [NSLayoutConstraint]! + @IBOutlet var maximisedConstraint: [NSLayoutConstraint]! + + @IBOutlet weak var hideVideoBtn: UIButton! + @IBOutlet weak var draggableBoundryDefiner: UIView! var localVideoDraggable:AADraggableView? @IBOutlet weak var controlButtons: UIView! @IBOutlet weak var remoteVideoMutedIndicator: UIImageView! @IBOutlet weak var localVideoMutedBg: UIView! + @IBOutlet weak var lblCallDuration: UILabel! @IBOutlet weak var remoteVideo: UIView! @IBOutlet weak var localVideo: UIView!{ didSet{ - localVideo.layer.borderColor = UIColor.white.cgColor localVideoDraggable = localVideo?.superview as? AADraggableView localVideoDraggable?.reposition = .edgesOnly } @@ -59,6 +66,7 @@ class VideoCallViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + localVideoDraggable?.respectedView = draggableBoundryDefiner } @IBAction func didClickMuteButton(_ sender: UIButton) { @@ -107,12 +115,16 @@ class VideoCallViewController: UIViewController { minimized = !minimized onMinimize?(minimized) sender.isSelected = minimized + + NSLayoutConstraint.activate(minimized ? minimizeConstraint : maximisedConstraint) + NSLayoutConstraint.deactivate(minimized ? maximisedConstraint : minimizeConstraint) localVideoDraggable?.enable(!minimized) + lblRemoteUsername.isHidden = minimized + hideVideoBtn.isHidden = !minimized + let min_ = minimized UIView.animate(withDuration: 0.5) { - self.actionsHeightConstraint.constant = min_ ? 30 : 60 - self.localvideoTopMargin.constant = min_ ? 20 : 40 self.videoMuteBtn.isHidden = min_ self.micMuteBtn.isHidden = min_ @@ -125,6 +137,10 @@ class VideoCallViewController: UIViewController { } } + @IBAction func hideVideoBtnTapped(_ sender: Any) { + onHide?() + } + func start(params:VideoCallRequestParameters){ self.kApiKey = params.apiKey ?? "" @@ -352,6 +368,8 @@ extension VideoCallViewController: OTSessionDelegate { } publisher?.view!.frame = CGRect(x: 0, y: 0, width: localVideo.bounds.size.width, height: localVideo.bounds.size.height) + publisher?.view?.layer.cornerRadius = 5 + publisher?.view?.clipsToBounds = true localVideo.addSubview((publisher?.view)!) } From 1b4988e5f05a9da553ecce811844f7a351999b45 Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Sun, 13 Jun 2021 14:45:46 +0300 Subject: [PATCH 5/6] no message --- .../xcshareddata/xcschemes/Runner.xcscheme | 8 ++- ios/Runner/Base.lproj/Main.storyboard | 70 ++++++++++++------- ios/Runner/MainAppViewController.swift | 9 ++- ios/Runner/VideoCallViewController.swift | 29 +++++++- .../patient_profile_screen.dart | 34 ++++++--- lib/util/VideoChannel.dart | 24 ++++++- ...ent-profile-header-new-design-app-bar.dart | 24 ++++++- 7 files changed, 153 insertions(+), 45 deletions(-) diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index fb2dffc4..a28140cf 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -27,6 +27,8 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + - - + + + + - + + + + + + - + + + @@ -200,6 +207,21 @@ + @@ -209,22 +231,11 @@ - - @@ -281,6 +294,7 @@ + @@ -288,18 +302,24 @@ - + - - - - - - - - + + + + + + + + + + + + + + diff --git a/ios/Runner/MainAppViewController.swift b/ios/Runner/MainAppViewController.swift index a6e4bcea..3849635e 100644 --- a/ios/Runner/MainAppViewController.swift +++ b/ios/Runner/MainAppViewController.swift @@ -27,9 +27,10 @@ class MainAppViewController: FlutterViewController{ super.viewDidAppear(animated) } + var videoCallChannel:FlutterMethodChannel? private func initFlutterBridge(){ - let videoCallChannel = FlutterMethodChannel(name: "Dr.cloudSolution/videoCall", binaryMessenger: binaryMessenger) - videoCallChannel.setMethodCallHandler({ + videoCallChannel = FlutterMethodChannel(name: "Dr.cloudSolution/videoCall", binaryMessenger: binaryMessenger) + videoCallChannel?.setMethodCallHandler({ (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in switch call.method { case "openVideoCall": @@ -86,6 +87,10 @@ extension MainAppViewController : ICallProtocol{ } videoCallViewController.onHide = { self.videoCallContainer.isHidden = true + self.videoCallChannel?.invokeMethod("onHide", arguments: nil) + } + videoCallViewController.onVideoDuration = { duration in + self.videoCallChannel?.invokeMethod("onVideoDuration", arguments: duration) } videoCallViewController.onClose = videoCallClosed videoCallViewController.callBack = self diff --git a/ios/Runner/VideoCallViewController.swift b/ios/Runner/VideoCallViewController.swift index 3e8b612c..fd25541b 100644 --- a/ios/Runner/VideoCallViewController.swift +++ b/ios/Runner/VideoCallViewController.swift @@ -36,6 +36,7 @@ class VideoCallViewController: UIViewController { var onMinimize:((Bool)->Void)? = nil var onHide:(()->Void)? = nil + var onVideoDuration:((String)->Void)? = nil var onClose:(()->Void)? = nil @@ -44,6 +45,7 @@ class VideoCallViewController: UIViewController { // Bottom Actions @IBOutlet weak var videoMuteBtn: UIButton! @IBOutlet weak var micMuteBtn: UIButton! + @IBOutlet weak var camSwitchBtn: UIButton! @IBOutlet var minimizeConstraint: [NSLayoutConstraint]! @IBOutlet var maximisedConstraint: [NSLayoutConstraint]! @@ -109,6 +111,10 @@ class VideoCallViewController: UIViewController { callBack?.sessionDone(res:["callResponse":"CallEnd"]) sessionDisconnect() } + + @IBAction func hideVideoBtnTapped(_ sender: Any) { + onHide?() + } var minimized = false @IBAction func onMinimize(_ sender: UIButton) { @@ -122,11 +128,13 @@ class VideoCallViewController: UIViewController { lblRemoteUsername.isHidden = minimized hideVideoBtn.isHidden = !minimized + lblCallDuration.superview?.isHidden = !hideVideoBtn.isHidden let min_ = minimized UIView.animate(withDuration: 0.5) { self.videoMuteBtn.isHidden = min_ self.micMuteBtn.isHidden = min_ + self.camSwitchBtn.isHidden = min_ let localVdoSize = self.localVideo.bounds.size let remoteVdoSize = self.remoteVideo.bounds.size @@ -137,8 +145,20 @@ class VideoCallViewController: UIViewController { } } - @IBAction func hideVideoBtnTapped(_ sender: Any) { - onHide?() + var durationTimer:Timer?; + func startUpdateCallDuration(){ + var seconds = 0 + durationTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in + seconds = seconds+1 + let durationSegments = (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) + let hours = String(format: "%02d", durationSegments.0) + let mins = String(format: "%02d", durationSegments.1) + let secs = String(format: "%02d", durationSegments.2) + let durationString = "\(mins):\(secs)" + + self.lblCallDuration.text = durationString + self.onVideoDuration?(durationString) + } } func start(params:VideoCallRequestParameters){ @@ -410,8 +430,11 @@ extension VideoCallViewController: OTSessionDelegate { guard let subscriberView = subscriber.view else { return } + subscriberView.frame = CGRect(x: 0, y: 0, width: remoteVideo.bounds.width, height: remoteVideo.bounds.height) remoteVideo.addSubview(subscriberView) + + startUpdateCallDuration() } func setupSubscribe(_ stream: OTStream?) { @@ -474,7 +497,7 @@ extension VideoCallViewController: OTSubscriberDelegate { print("The subscriber failed to connect to the stream.") } @objc func hideControlButtons() { - controlButtons.isHidden = true +// controlButtons.isHidden = true } } diff --git a/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart b/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart index 30f53a0b..f2a52411 100644 --- a/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart +++ b/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:doctor_app_flutter/config/config.dart'; import 'package:doctor_app_flutter/core/enum/viewstate.dart'; import 'package:doctor_app_flutter/core/viewModel/LiveCarePatientViewModel.dart'; @@ -46,10 +48,15 @@ class _PatientProfileScreenState extends State TabController _tabController; int index = 0; int _activeTab = 0; + + StreamController videoCallDurationStreamController; + Stream videoCallDurationStream = (() async*{})(); @override void initState() { _tabController = TabController(length: 2, vsync: this); super.initState(); + videoCallDurationStreamController = StreamController(); + videoCallDurationStream = videoCallDurationStreamController.stream; } @override @@ -103,16 +110,20 @@ class _PatientProfileScreenState extends State Column( children: [ PatientProfileHeaderNewDesignAppBar( - patient, arrivalType ?? '0', patientType, - isInpatient: isInpatient, - isFromLiveCare: isFromLiveCare, - height: (patient.patientStatusType != null && - patient.patientStatusType == 43) - ? 210 - : isDischargedPatient - ? 240 - : 0, - isDischargedPatient: isDischargedPatient), + patient, arrivalType ?? '0', patientType, + videoCallDurationStream: videoCallDurationStream, + onVideoDurationTap: (){ + VideoChannel.show(); + }, + isInpatient: isInpatient, + isFromLiveCare: isFromLiveCare, + height: (patient.patientStatusType != null && + patient.patientStatusType == 43) + ? 210 + : isDischargedPatient + ? 240 + : 0, + isDischargedPatient: isDischargedPatient), Container( height: !isSearchAndOut ? isDischargedPatient @@ -311,6 +322,9 @@ class _PatientProfileScreenState extends State onFailure: (String error) { DrAppToastMsg.showErrorToast(error); }, + onVideoDuration: (duration){ + videoCallDurationStreamController.sink.add(duration); + }, onCallEnd: () { var asd=""; // WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/lib/util/VideoChannel.dart b/lib/util/VideoChannel.dart index a0962010..a9c2b5e2 100644 --- a/lib/util/VideoChannel.dart +++ b/lib/util/VideoChannel.dart @@ -4,15 +4,30 @@ import 'dart:io' show Platform; import 'package:doctor_app_flutter/config/config.dart'; import 'package:doctor_app_flutter/models/livecare/session_status_model.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class VideoChannel{ /// channel name static const _channel = const MethodChannel("Dr.cloudSolution/videoCall"); - static openVideoCallScreen( - {kApiKey, kSessionId, kToken, callDuration, warningDuration,int vcId,String tokenID,String generalId,int doctorId, Function() onCallEnd , Function(SessionStatusModel sessionStatusModel) onCallNotRespond ,Function(String error) onFailure}) async { + static openVideoCallScreen({kApiKey, kSessionId, kToken, callDuration, warningDuration,int vcId,String tokenID, + String generalId,int doctorId, Function() onCallEnd , + Function(SessionStatusModel sessionStatusModel) onCallNotRespond ,Function(String error) onFailure, VoidCallback onHide, Function(String) onVideoDuration}) async { + + onHide = onHide ?? (){}; + onVideoDuration = onVideoDuration ?? (v){}; + var result; try { + _channel.setMethodCallHandler((call) { + if(call.method == 'onHide'){ + onHide(); + }else if(call.method == 'onVideoDuration'){ + onVideoDuration(call.arguments); + } + return true as dynamic; + }); + result = await _channel.invokeMethod( 'openVideoCall', { @@ -29,6 +44,7 @@ class VideoChannel{ ); if(result['callResponse'] == 'CallEnd') { onCallEnd(); + onVideoDuration(null); } else { SessionStatusModel sessionStatusModel = SessionStatusModel.fromJson(Platform.isIOS ?result['sessionStatus'] :json.decode(result['sessionStatus'])); @@ -40,6 +56,10 @@ class VideoChannel{ } } + + static show(){ + _channel.invokeMethod("showVideo"); + } } \ No newline at end of file diff --git a/lib/widgets/patients/profile/patient-profile-header-new-design-app-bar.dart b/lib/widgets/patients/profile/patient-profile-header-new-design-app-bar.dart index 995ac57a..69bb9758 100644 --- a/lib/widgets/patients/profile/patient-profile-header-new-design-app-bar.dart +++ b/lib/widgets/patients/profile/patient-profile-header-new-design-app-bar.dart @@ -21,8 +21,11 @@ class PatientProfileHeaderNewDesignAppBar extends StatelessWidget final bool isDischargedPatient; final bool isFromLiveCare; + final Stream videoCallDurationStream; + final VoidCallback onVideoDurationTap; + PatientProfileHeaderNewDesignAppBar( - this.patient, this.patientType, this.arrivalType, {this.height = 0.0, this.isInpatient=false, this.isDischargedPatient=false, this.isFromLiveCare = false}); + this.patient, this.patientType, this.arrivalType, {this.height = 0.0, this.isInpatient=false, this.isDischargedPatient=false, this.isFromLiveCare = false, this.videoCallDurationStream, this.onVideoDurationTap}); @override Widget build(BuildContext context) { @@ -88,6 +91,25 @@ class PatientProfileHeaderNewDesignAppBar extends StatelessWidget ), ), ), + StreamBuilder( + stream: videoCallDurationStream, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if(snapshot.hasData) + return InkWell( + onTap: (){ + if(onVideoDurationTap != null) + onVideoDurationTap(); + }, + child: Container( + decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(20)), + padding: EdgeInsets.symmetric(vertical: 2, horizontal: 10), + child: Text(snapshot.data, style: TextStyle(color: Colors.white),), + ), + ); + else + return Container(); + }, + ), ]), ), Row(children: [ From f60ff85e319e8d325b0dc9383d8523cd1a994a03 Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Mon, 14 Jun 2021 10:54:51 +0300 Subject: [PATCH 6/6] no message --- ios/Runner/AppDelegate.swift | 1 - .../hide_video_icon.png | Bin 175 -> 906 bytes ios/Runner/Base.lproj/Main.storyboard | 16 +++---- ios/Runner/MainAppViewController.swift | 35 ++++++---------- ios/Runner/VCEmbeder.swift | 1 + ios/Runner/VideoCallViewController.swift | 39 +++++++++--------- .../patient_profile_screen.dart | 25 ++++++++--- lib/util/VideoChannel.dart | 20 ++++----- lib/util/helpers.dart | 7 ++++ ...ent-profile-header-new-design-app-bar.dart | 7 +--- pubspec.lock | 2 +- pubspec.yaml | 2 +- 12 files changed, 79 insertions(+), 76 deletions(-) diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index dc938e36..8ebd4235 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -49,7 +49,6 @@ import OpenTok navVC.modalPresentationStyle = .fullScreen window.rootViewController?.present(navVC, animated: true, completion: nil) - } } diff --git a/ios/Runner/Assets.xcassets/hide_video_icon.imageset/hide_video_icon.png b/ios/Runner/Assets.xcassets/hide_video_icon.imageset/hide_video_icon.png index 8dea84b1de80408985f9dc89728ab042c7750a7c..40889f7710b0615cba211a52f145ae817ecad67b 100644 GIT binary patch literal 906 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lxRtf@J#ddWzYh$IT%O>_%)r1c48n{Iv*t)JFfcJ@hD4M^`1)8S=jZArrsOB3 z>Q&?xfOIj~R9FF-xv3?I3Kh9IdBs*0wn|_XRzNmLSYJs2tfVB{Rw=?aK*2e`C{@8s z&p^*W$&O1wLBXadCCw_x#SN+*$g@?-C@Cqh($_C9FV`zK*2^zS*Eh7ZwA42+(l;{F z1**_3uFNY*tkBIXR)!b?Gsh*hIJqdZpd>RtPXT0ZVp4u-iLH_n$Rap^xU(cP4PjGW zG1OZ?59)(t^bPe4^s#A6t;oco4I~562KE=kIvbE-R{lkqsXzyVoMmTd1GWG~4Bd9J*EaW`dB5fYK%l^v_RH}Bo5VQqYnxsq(Fnj2v`&tC3ajk z`tazr<7$5V$ORbV$(}BbAsMW1FB)<&DDbcteEnY^W`4X(Q{<#C7yH!`9z}-+21X_p z4gm!iqk}aqrn0y8bKckGm6PXg+H~}tt^CVv3-iq`@m{M&QU}%G#mXmkiG{0r - - - - - - - @@ -114,6 +107,13 @@ + + + + + + + @@ -333,7 +333,7 @@ - + diff --git a/ios/Runner/MainAppViewController.swift b/ios/Runner/MainAppViewController.swift index 3849635e..87610042 100644 --- a/ios/Runner/MainAppViewController.swift +++ b/ios/Runner/MainAppViewController.swift @@ -35,8 +35,6 @@ class MainAppViewController: FlutterViewController{ switch call.method { case "openVideoCall": self.startVideoCall(result: result, call: call) - case "showVideo": - self.showVideo() default: result(FlutterMethodNotImplemented) } @@ -72,8 +70,10 @@ extension MainAppViewController : ICallProtocol{ } } - private func showVideo(){ - videoCallContainer.isHidden = false + private func showVideo(show:Bool){ + UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: { + self.videoCallContainer.isHidden = !show + }) } private func startVideoCall(result: @escaping FlutterResult, call:FlutterMethodCall) { @@ -82,17 +82,16 @@ extension MainAppViewController : ICallProtocol{ if let arguments = call.arguments as? NSDictionary{ showVideoCallView(true) - videoCallViewController.onMinimize = { min in - self.minimizeVideoCall(min) + videoCallViewController.onFloat = { min in + self.floatVideoCallView(min) } - videoCallViewController.onHide = { - self.videoCallContainer.isHidden = true - self.videoCallChannel?.invokeMethod("onHide", arguments: nil) + videoCallViewController.onCallConnect = { + self.videoCallChannel?.invokeMethod("onCallConnected",arguments: nil) } - videoCallViewController.onVideoDuration = { duration in - self.videoCallChannel?.invokeMethod("onVideoDuration", arguments: duration) + videoCallViewController.onCallDisconnect = { + self.showVideoCallView(false) + self.videoCallChannel?.invokeMethod("onCallDisconnected",arguments: nil) } - videoCallViewController.onClose = videoCallClosed videoCallViewController.callBack = self videoCallViewController.start(params: VideoCallRequestParameters(dictionary: arguments)) } @@ -100,7 +99,7 @@ extension MainAppViewController : ICallProtocol{ } - private func minimizeVideoCall(_ value:Bool){ + private func floatVideoCallView(_ value:Bool){ videoCallContainer.enable(value) UIView.animate(withDuration: 0.5) { @@ -119,20 +118,11 @@ extension MainAppViewController : ICallProtocol{ } private func showVideoCallView(_ value:Bool){ - videoCallContainer.alpha = value ? 0.0 : 1 - self.videoCallContainer.isHidden = !value - UIView.animate(withDuration: 0.5) { - self.videoCallContainer.alpha = value ? 1.0 : 0.0 - } completion: { complete in self.videoCallContainer.isHidden = !value } } - private func videoCallClosed(){ - showVideoCallView(false) - } - func sessionDone(res: Any) { videoCallFlutterResult?(res) } @@ -144,7 +134,6 @@ extension MainAppViewController : ICallProtocol{ func setVideoViewConstrints(){ let screen = UIScreen.main.bounds - videoCallContainer.translatesAutoresizingMaskIntoConstraints = false diff --git a/ios/Runner/VCEmbeder.swift b/ios/Runner/VCEmbeder.swift index 7e2ea0fd..9617a247 100644 --- a/ios/Runner/VCEmbeder.swift +++ b/ios/Runner/VCEmbeder.swift @@ -54,6 +54,7 @@ class ViewEmbedder { let w = container.frame.size.width; let h = container.frame.size.height; child.view.frame = CGRect(x: 0, y: 0, width: w, height: h) + child.view.backgroundColor = UIColor.black child.view.fill(to: container) } diff --git a/ios/Runner/VideoCallViewController.swift b/ios/Runner/VideoCallViewController.swift index fd25541b..27268128 100644 --- a/ios/Runner/VideoCallViewController.swift +++ b/ios/Runner/VideoCallViewController.swift @@ -34,11 +34,11 @@ class VideoCallViewController: UIViewController { var seconds = 30 var isUserConnect : Bool = false - var onMinimize:((Bool)->Void)? = nil - var onHide:(()->Void)? = nil - var onVideoDuration:((String)->Void)? = nil - var onClose:(()->Void)? = nil - + var onFloat:((Bool)->Void)? = nil + var onMinimize:(()->Void)? = nil + var onCallConnect:(()->Void)? = nil + var onCallDisconnect:(()->Void)? = nil + @IBOutlet weak var lblRemoteUsername: UILabel! @@ -61,6 +61,7 @@ class VideoCallViewController: UIViewController { @IBOutlet weak var remoteVideo: UIView! @IBOutlet weak var localVideo: UIView!{ didSet{ + localVideo.layer.borderColor = UIColor.white.cgColor localVideoDraggable = localVideo?.superview as? AADraggableView localVideoDraggable?.reposition = .edgesOnly } @@ -74,7 +75,6 @@ class VideoCallViewController: UIViewController { @IBAction func didClickMuteButton(_ sender: UIButton) { sender.isSelected = !sender.isSelected publisher!.publishAudio = !sender.isSelected - } @IBAction func didClickSpeakerButton(_ sender: UIButton) { @@ -113,24 +113,24 @@ class VideoCallViewController: UIViewController { } @IBAction func hideVideoBtnTapped(_ sender: Any) { - onHide?() + onMinimize?() } - var minimized = false + var floated = false @IBAction func onMinimize(_ sender: UIButton) { - minimized = !minimized - onMinimize?(minimized) - sender.isSelected = minimized + floated = !floated + onFloat?(floated) + sender.isSelected = floated - NSLayoutConstraint.activate(minimized ? minimizeConstraint : maximisedConstraint) - NSLayoutConstraint.deactivate(minimized ? maximisedConstraint : minimizeConstraint) - localVideoDraggable?.enable(!minimized) + NSLayoutConstraint.activate(floated ? minimizeConstraint : maximisedConstraint) + NSLayoutConstraint.deactivate(floated ? maximisedConstraint : minimizeConstraint) + localVideoDraggable?.enable(!floated) - lblRemoteUsername.isHidden = minimized - hideVideoBtn.isHidden = !minimized + lblRemoteUsername.isHidden = floated + hideVideoBtn.isHidden = !floated lblCallDuration.superview?.isHidden = !hideVideoBtn.isHidden - let min_ = minimized + let min_ = floated UIView.animate(withDuration: 0.5) { self.videoMuteBtn.isHidden = min_ self.micMuteBtn.isHidden = min_ @@ -157,7 +157,6 @@ class VideoCallViewController: UIViewController { let durationString = "\(mins):\(secs)" self.lblCallDuration.text = durationString - self.onVideoDuration?(durationString) } } @@ -277,7 +276,8 @@ class VideoCallViewController: UIViewController { dismiss(animated: true) } dismiss(animated: true) - onClose?() + onCallDisconnect?() + durationTimer?.invalidate() } func requestCameraPermissionsIfNeeded() { @@ -435,6 +435,7 @@ extension VideoCallViewController: OTSessionDelegate { remoteVideo.addSubview(subscriberView) startUpdateCallDuration() + onCallConnect?() } func setupSubscribe(_ stream: OTStream?) { diff --git a/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart b/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart index f2a52411..5212df0c 100644 --- a/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart +++ b/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart @@ -22,6 +22,7 @@ import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dar import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart'; import 'package:flutter/material.dart'; import 'package:hexcolor/hexcolor.dart'; +import 'package:quiver/async.dart'; import '../../../../routes.dart'; @@ -95,6 +96,23 @@ class _PatientProfileScreenState extends State _activeTab = 1; } + StreamSubscription callTimer; + callConnected(){ + callTimer = CountdownTimer(Duration(minutes: 1), Duration(seconds: 1)).listen(null) + ..onDone(() { + callTimer.cancel(); + }) + ..onData((data) { + var t = Helpers.timeFrom(duration: data.elapsed); + videoCallDurationStreamController.sink.add(t); + }); + } + + callDisconnected(){ + callTimer.cancel(); + videoCallDurationStreamController.sink.add(null); + } + @override Widget build(BuildContext context) { final screenSize = MediaQuery.of(context).size; @@ -112,9 +130,6 @@ class _PatientProfileScreenState extends State PatientProfileHeaderNewDesignAppBar( patient, arrivalType ?? '0', patientType, videoCallDurationStream: videoCallDurationStream, - onVideoDurationTap: (){ - VideoChannel.show(); - }, isInpatient: isInpatient, isFromLiveCare: isFromLiveCare, height: (patient.patientStatusType != null && @@ -322,9 +337,7 @@ class _PatientProfileScreenState extends State onFailure: (String error) { DrAppToastMsg.showErrorToast(error); }, - onVideoDuration: (duration){ - videoCallDurationStreamController.sink.add(duration); - }, + onCallConnected: callConnected, onCallEnd: () { var asd=""; // WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/lib/util/VideoChannel.dart b/lib/util/VideoChannel.dart index a9c2b5e2..94e79b7e 100644 --- a/lib/util/VideoChannel.dart +++ b/lib/util/VideoChannel.dart @@ -12,18 +12,19 @@ class VideoChannel{ static const _channel = const MethodChannel("Dr.cloudSolution/videoCall"); static openVideoCallScreen({kApiKey, kSessionId, kToken, callDuration, warningDuration,int vcId,String tokenID, String generalId,int doctorId, Function() onCallEnd , - Function(SessionStatusModel sessionStatusModel) onCallNotRespond ,Function(String error) onFailure, VoidCallback onHide, Function(String) onVideoDuration}) async { + Function(SessionStatusModel sessionStatusModel) onCallNotRespond ,Function(String error) onFailure, VoidCallback onCallConnected, VoidCallback onCallDisconnected}) async { - onHide = onHide ?? (){}; - onVideoDuration = onVideoDuration ?? (v){}; + onCallConnected = onCallConnected ?? (){}; + onCallDisconnected = onCallDisconnected ?? (){}; var result; try { _channel.setMethodCallHandler((call) { - if(call.method == 'onHide'){ - onHide(); - }else if(call.method == 'onVideoDuration'){ - onVideoDuration(call.arguments); + if(call.method == 'onCallConnected'){ + onCallConnected(); + } + if(call.method == 'onCallDisconnected'){ + onCallDisconnected(); } return true as dynamic; }); @@ -44,7 +45,6 @@ class VideoChannel{ ); if(result['callResponse'] == 'CallEnd') { onCallEnd(); - onVideoDuration(null); } else { SessionStatusModel sessionStatusModel = SessionStatusModel.fromJson(Platform.isIOS ?result['sessionStatus'] :json.decode(result['sessionStatus'])); @@ -56,10 +56,6 @@ class VideoChannel{ } } - - static show(){ - _channel.invokeMethod("showVideo"); - } } \ No newline at end of file diff --git a/lib/util/helpers.dart b/lib/util/helpers.dart index 634abd02..7232f0c9 100644 --- a/lib/util/helpers.dart +++ b/lib/util/helpers.dart @@ -270,4 +270,11 @@ class Helpers { var htmlRegex = RegExp("<(“[^”]*”|'[^’]*’|[^'”>])*>"); return htmlRegex.hasMatch(text); } + + static String timeFrom({Duration duration}) { + String twoDigits(int n) => n.toString().padLeft(2, "0"); + String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60)); + String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60)); + return "$twoDigitMinutes:$twoDigitSeconds"; + } } diff --git a/lib/widgets/patients/profile/patient-profile-header-new-design-app-bar.dart b/lib/widgets/patients/profile/patient-profile-header-new-design-app-bar.dart index 69bb9758..f2a32e63 100644 --- a/lib/widgets/patients/profile/patient-profile-header-new-design-app-bar.dart +++ b/lib/widgets/patients/profile/patient-profile-header-new-design-app-bar.dart @@ -22,10 +22,9 @@ class PatientProfileHeaderNewDesignAppBar extends StatelessWidget final bool isFromLiveCare; final Stream videoCallDurationStream; - final VoidCallback onVideoDurationTap; PatientProfileHeaderNewDesignAppBar( - this.patient, this.patientType, this.arrivalType, {this.height = 0.0, this.isInpatient=false, this.isDischargedPatient=false, this.isFromLiveCare = false, this.videoCallDurationStream, this.onVideoDurationTap}); + this.patient, this.patientType, this.arrivalType, {this.height = 0.0, this.isInpatient=false, this.isDischargedPatient=false, this.isFromLiveCare = false, this.videoCallDurationStream}); @override Widget build(BuildContext context) { @@ -94,11 +93,9 @@ class PatientProfileHeaderNewDesignAppBar extends StatelessWidget StreamBuilder( stream: videoCallDurationStream, builder: (BuildContext context, AsyncSnapshot snapshot) { - if(snapshot.hasData) + if(snapshot.hasData && snapshot.data != null) return InkWell( onTap: (){ - if(onVideoDurationTap != null) - onVideoDurationTap(); }, child: Container( decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(20)), diff --git a/pubspec.lock b/pubspec.lock index 77df9848..cac3f27b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -813,7 +813,7 @@ packages: source: hosted version: "0.1.8" quiver: - dependency: transitive + dependency: "direct main" description: name: quiver url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index 973e8800..1429bc3e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -90,7 +90,7 @@ dependencies: speech_to_text: path: speech_to_text - + quiver: ^2.1.5 # Html Editor Enhanced html_editor_enhanced: ^1.3.0