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: [