From 385820fdce9afb8a05eace1e5a3e33afd03ea6ee Mon Sep 17 00:00:00 2001 From: mosazaid Date: Wed, 23 Jun 2021 17:12:13 +0300 Subject: [PATCH] video stream add record icon and change button disable --- .../main/kotlin/com/hmg/hmgDr/MainActivity.kt | 3 +- .../hmgDr/Model/GetSessionStatusModel.java | 16 +- .../hmgDr/ui/fragment/VideoCallFragment.kt | 233 ++++++++++++------ .../app/src/main/res/drawable/ic_record.xml | 5 + .../main/res/layout/activity_video_call.xml | 17 ++ lib/core/service/VideoCallService.dart | 81 +++--- lib/models/livecare/start_call_res.dart | 7 +- lib/screens/live_care/end_call_screen.dart | 1 + lib/screens/live_care/video_call.dart | 1 + .../patient_profile_screen.dart | 7 +- lib/util/VideoChannel.dart | 3 +- 11 files changed, 263 insertions(+), 111 deletions(-) create mode 100644 android/app/src/main/res/drawable/ic_record.xml diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt index fcc3f2e3..52807251 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt @@ -54,8 +54,9 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler, val generalId = call.argument("generalId") val doctorId = call.argument("DoctorId") val patientName = call.argument("patientName") + val isRecording = call.argument("isRecording") - val sessionStatusModel = GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId, patientName) + val sessionStatusModel = GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId, patientName, isRecording!!) openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel) diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/Model/GetSessionStatusModel.java b/android/app/src/main/kotlin/com/hmg/hmgDr/Model/GetSessionStatusModel.java index 60350539..9e2e1cf4 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/Model/GetSessionStatusModel.java +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/Model/GetSessionStatusModel.java @@ -23,16 +23,20 @@ public class GetSessionStatusModel implements Parcelable { @SerializedName("PatientName") @Expose private String patientName; + @SerializedName("isRecording") + @Expose + private boolean isRecording; public GetSessionStatusModel() { } - public GetSessionStatusModel(Integer vCID, String tokenID, String generalid, Integer doctorId, String patientName) { + public GetSessionStatusModel(Integer vCID, String tokenID, String generalid, Integer doctorId, String patientName, boolean isRecording) { this.vCID = vCID; this.tokenID = tokenID; this.generalid = generalid; this.doctorId = doctorId; this.patientName = patientName; + this.isRecording = isRecording; } protected GetSessionStatusModel(Parcel in) { @@ -49,6 +53,7 @@ public class GetSessionStatusModel implements Parcelable { doctorId = in.readInt(); } patientName = in.readString(); + isRecording = in.readInt() == 1; } public static final Creator CREATOR = new Creator() { @@ -105,6 +110,14 @@ public class GetSessionStatusModel implements Parcelable { this.patientName = patientName; } + public boolean isRecording() { + return isRecording; + } + + public void setRecording(boolean recording) { + isRecording = recording; + } + @Override public int describeContents() { return 0; @@ -127,5 +140,6 @@ public class GetSessionStatusModel implements Parcelable { dest.writeInt(doctorId); } dest.writeString(patientName); + dest.writeInt(isRecording ? 1 : 0); } } diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt index 7a66f80b..1d1e420a 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt @@ -38,8 +38,9 @@ import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks import kotlin.math.ceil -class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.SessionListener, PublisherListener, - SubscriberKit.VideoListener, VideoCallView { +class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.SessionListener, + PublisherListener, + SubscriberKit.VideoListener, VideoCallView { private var isFullScreen: Boolean = true private var isCircle: Boolean = false @@ -62,6 +63,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session private var mVolRunnable: Runnable? = null private var mConnectedRunnable: Runnable? = null + private lateinit var recordContainer: FrameLayout private lateinit var thumbnail_container: FrameLayout private lateinit var mPublisherViewContainer: FrameLayout private lateinit var mPublisherViewIcon: View @@ -74,6 +76,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session private var token: String? = null private var appLang: String? = null private var baseUrl: String? = null + private var isRecording: Boolean = true private var isSwitchCameraClicked = false private var isCameraClicked = false @@ -117,8 +120,8 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session super.onStart() dialog?.window?.setLayout( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT ) } @@ -156,8 +159,8 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session // Make the dialog possible to be outside touch dialogWindow!!.setFlags( - WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, - WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL ) dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) requireView().invalidate() @@ -168,8 +171,10 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session this.videoCallResponseListener = videoCallResponseListener } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View { + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { parentView = inflater.inflate(R.layout.activity_video_call, container, false) @@ -181,12 +186,17 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session appLang = getString("appLang") baseUrl = getString("baseUrl") sessionStatusModel = getParcelable("sessionStatusModel") + if (sessionStatusModel != null) + isRecording = sessionStatusModel!!.isRecording } initUI(parentView) requestPermissions() handleDragDialog() - mDetector = GestureDetectorCompat(context, MyGestureListener({ showControlPanelTemporarily() }, { miniCircleDoubleTap() })) + mDetector = GestureDetectorCompat( + context, + MyGestureListener({ showControlPanelTemporarily() }, { miniCircleDoubleTap() }) + ) return parentView } @@ -223,6 +233,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session layoutName = view.findViewById(R.id.layout_name) layoutMini = view.findViewById(R.id.layout_mini) icMini = view.findViewById(R.id.ic_mini) + recordContainer = view.findViewById(R.id.record_container) thumbnail_container = view.findViewById(R.id.thumbnail_container) mPublisherViewContainer = view.findViewById(R.id.local_video_view_container) mPublisherViewIcon = view.findViewById(R.id.local_video_view_icon) @@ -232,23 +243,30 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session patientName = view.findViewById(R.id.patient_name) patientName.text = sessionStatusModel!!.patientName + if (isRecording) { + recordContainer.visibility = View.VISIBLE + } else { + recordContainer.visibility = View.GONE + } + cmTimer = view.findViewById(R.id.cmTimer) cmTimer.format = "mm:ss" - cmTimer.onChronometerTickListener = Chronometer.OnChronometerTickListener { arg0: Chronometer? -> - val minutes: Long - val seconds: Long - if (!resume) { - minutes = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 / 60 - seconds = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 % 60 - elapsedTime = SystemClock.elapsedRealtime() - } else { - minutes = (elapsedTime - cmTimer.base) / 1000 / 60 - seconds = (elapsedTime - cmTimer.base) / 1000 % 60 - elapsedTime += 1000 + cmTimer.onChronometerTickListener = + Chronometer.OnChronometerTickListener { arg0: Chronometer? -> + val minutes: Long + val seconds: Long + if (!resume) { + minutes = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 / 60 + seconds = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 % 60 + elapsedTime = SystemClock.elapsedRealtime() + } else { + minutes = (elapsedTime - cmTimer.base) / 1000 / 60 + seconds = (elapsedTime - cmTimer.base) / 1000 % 60 + elapsedTime += 1000 + } + arg0?.text = "$minutes:$seconds" + Log.d(VideoCallFragment.TAG, "onChronometerTick: $minutes : $seconds") } - arg0?.text = "$minutes:$seconds" - Log.d(VideoCallFragment.TAG, "onChronometerTick: $minutes : $seconds") - } icMini.setOnClickListener { onMiniCircleClicked() @@ -310,7 +328,11 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong()) } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this) } @@ -323,19 +345,25 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size) if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { AppSettingsDialog.Builder(this) - .setTitle(getString(R.string.title_settings_dialog)) - .setRationale(getString(R.string.rationale_ask_again)) - .setPositiveButton(getString(R.string.setting)) - .setNegativeButton(getString(R.string.cancel)) - .setRequestCode(RC_SETTINGS_SCREEN_PERM) - .build() - .show() + .setTitle(getString(R.string.title_settings_dialog)) + .setRationale(getString(R.string.rationale_ask_again)) + .setPositiveButton(getString(R.string.setting)) + .setNegativeButton(getString(R.string.cancel)) + .setRequestCode(RC_SETTINGS_SCREEN_PERM) + .build() + .show() } } @AfterPermissionGranted(RC_VIDEO_APP_PERM) private fun requestPermissions() { - val perms = arrayOf(Manifest.permission.INTERNET, Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.CALL_PHONE) + val perms = arrayOf( + Manifest.permission.INTERNET, + Manifest.permission.CAMERA, + Manifest.permission.RECORD_AUDIO, + Manifest.permission.MODIFY_AUDIO_SETTINGS, + Manifest.permission.CALL_PHONE + ) if (EasyPermissions.hasPermissions(requireContext(), *perms)) { try { mSession = Session.Builder(context, apiKey, sessionId).build() @@ -345,7 +373,12 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session e.printStackTrace() } } else { - EasyPermissions.requestPermissions(this, getString(R.string.remaining_ar), RC_VIDEO_APP_PERM, *perms) + EasyPermissions.requestPermissions( + this, + getString(R.string.remaining_ar), + RC_VIDEO_APP_PERM, + *perms + ) } } @@ -354,7 +387,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session mPublisher = Publisher.Builder(requireContext()) // .name("publisher") // .renderer(ThumbnailCircleVideoRenderer(requireContext())) - .build() + .build() mPublisher!!.setPublisherListener(this) if (mPublisher!!.view is GLSurfaceView) { (mPublisher!!.view as GLSurfaceView).setZOrderOnTop(true) @@ -387,7 +420,10 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session } override fun onStreamReceived(session: Session, stream: Stream) { - Log.d(TAG, "onStreamReceived: New stream " + stream.streamId + " in session " + session.sessionId) + Log.d( + TAG, + "onStreamReceived: New stream " + stream.streamId + " in session " + session.sessionId + ) if (mSubscriber != null) { isConnected = true return @@ -396,11 +432,22 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session subscribeToStream(stream) if (mConnectedHandler != null && mConnectedRunnable != null) mConnectedHandler!!.removeCallbacks(mConnectedRunnable!!) - videoCallPresenter.callChangeCallStatus(ChangeCallStatusRequestModel(3, sessionStatusModel!!.doctorId, sessionStatusModel!!.generalid, token, sessionStatusModel!!.vcid)) + videoCallPresenter.callChangeCallStatus( + ChangeCallStatusRequestModel( + 3, + sessionStatusModel!!.doctorId, + sessionStatusModel!!.generalid, + token, + sessionStatusModel!!.vcid + ) + ) } override fun onStreamDropped(session: Session, stream: Stream) { - Log.d(TAG, "onStreamDropped: Stream " + stream.streamId + " dropped from session " + session.sessionId) + Log.d( + TAG, + "onStreamDropped: Stream " + stream.streamId + " dropped from session " + session.sessionId + ) if (mSubscriber == null) { return } @@ -427,7 +474,10 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session } override fun onVideoDataReceived(subscriberKit: SubscriberKit?) { - mSubscriber!!.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL) + mSubscriber!!.setStyle( + BaseVideoRenderer.STYLE_VIDEO_SCALE, + BaseVideoRenderer.STYLE_VIDEO_FILL + ) (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(false) mSubscriberViewContainer.addView(mSubscriber!!.view) // switchToThumbnailCircle() @@ -477,8 +527,8 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session private fun subscribeToStream(stream: Stream) { mSubscriber = Subscriber.Builder(requireContext(), stream) - .renderer(DynamicVideoRenderer(requireContext())) - .build() + .renderer(DynamicVideoRenderer(requireContext())) + .build() mSubscriber!!.setVideoListener(this) mSession!!.subscribe(mSubscriber) } @@ -506,7 +556,15 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session mSession!!.disconnect() countDownTimer?.cancel() - videoCallPresenter.callChangeCallStatus(ChangeCallStatusRequestModel(16, sessionStatusModel!!.doctorId, sessionStatusModel!!.generalid, token, sessionStatusModel!!.vcid)) + videoCallPresenter.callChangeCallStatus( + ChangeCallStatusRequestModel( + 16, + sessionStatusModel!!.doctorId, + sessionStatusModel!!.generalid, + token, + sessionStatusModel!!.vcid + ) + ) dialog?.dismiss() } @@ -546,13 +604,13 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session private fun onMiniCircleClicked() { if (isCircle) { dialog?.window?.setLayout( - 400, - 600 + 400, + 600 ) } else { dialog?.window?.setLayout( - 300, - 300 + 300, + 300 ) } isCircle = !isCircle @@ -561,11 +619,23 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(isCircle) } else { if (isCircle) { - videoCallContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape) - mSubscriberViewContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape) + videoCallContainer.background = + ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape) + mSubscriberViewContainer.background = + ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape) } else { - videoCallContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color)) - mSubscriberViewContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.remoteBackground)) + videoCallContainer.setBackgroundColor( + ContextCompat.getColor( + requireContext(), + R.color.text_color + ) + ) + mSubscriberViewContainer.setBackgroundColor( + ContextCompat.getColor( + requireContext(), + R.color.remoteBackground + ) + ) } } @@ -582,13 +652,13 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session private fun onMinimizedClicked(view: View?) { if (isFullScreen) { dialog?.window?.setLayout( - 400, - 600 + 400, + 600 ) } else { dialog?.window?.setLayout( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT ) } isFullScreen = !isFullScreen @@ -602,24 +672,34 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session private fun setViewsVisibility() { val iconSize: Int = context!!.resources.getDimension(R.dimen.video_icon_size).toInt() - val iconSizeSmall: Int = context!!.resources.getDimension(R.dimen.video_icon_size_small).toInt() - val btnMinimizeLayoutParam: ConstraintLayout.LayoutParams = btnMinimize.layoutParams as ConstraintLayout.LayoutParams - val mCallBtnLayoutParam: ConstraintLayout.LayoutParams = mCallBtn.layoutParams as ConstraintLayout.LayoutParams - - val localPreviewMargin: Int = context!!.resources.getDimension(R.dimen.local_preview_margin_top).toInt() - val localPreviewWidth: Int = context!!.resources.getDimension(R.dimen.local_preview_width).toInt() - val localPreviewHeight: Int = context!!.resources.getDimension(R.dimen.local_preview_height).toInt() + val iconSizeSmall: Int = + context!!.resources.getDimension(R.dimen.video_icon_size_small).toInt() + val btnMinimizeLayoutParam: ConstraintLayout.LayoutParams = + btnMinimize.layoutParams as ConstraintLayout.LayoutParams + val mCallBtnLayoutParam: ConstraintLayout.LayoutParams = + mCallBtn.layoutParams as ConstraintLayout.LayoutParams + + val localPreviewMargin: Int = + context!!.resources.getDimension(R.dimen.local_preview_margin_top).toInt() + val localPreviewWidth: Int = + context!!.resources.getDimension(R.dimen.local_preview_width).toInt() + val localPreviewHeight: Int = + context!!.resources.getDimension(R.dimen.local_preview_height).toInt() // val localPreviewIconSize: Int = context!!.resources.getDimension(R.dimen.local_back_icon_size).toInt() // val localPreviewMarginSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_margin_small).toInt() // val localPreviewWidthSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_width_small).toInt() // val localPreviewHeightSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_height_small).toInt() // val localPreviewIconSmall: Int = context!!.resources.getDimension(R.dimen.local_back_icon_size_small).toInt() // val localPreviewLayoutIconParam : FrameLayout.LayoutParams - val localPreviewLayoutParam: RelativeLayout.LayoutParams = mPublisherViewContainer.layoutParams as RelativeLayout.LayoutParams + val localPreviewLayoutParam: RelativeLayout.LayoutParams = + mPublisherViewContainer.layoutParams as RelativeLayout.LayoutParams - val remotePreviewIconSize: Int = context!!.resources.getDimension(R.dimen.remote_back_icon_size).toInt() - val remotePreviewIconSizeSmall: Int = context!!.resources.getDimension(R.dimen.remote_back_icon_size_small).toInt() - val remotePreviewLayoutParam: FrameLayout.LayoutParams = mSubscriberViewIcon.layoutParams as FrameLayout.LayoutParams + val remotePreviewIconSize: Int = + context!!.resources.getDimension(R.dimen.remote_back_icon_size).toInt() + val remotePreviewIconSizeSmall: Int = + context!!.resources.getDimension(R.dimen.remote_back_icon_size_small).toInt() + val remotePreviewLayoutParam: FrameLayout.LayoutParams = + mSubscriberViewIcon.layoutParams as FrameLayout.LayoutParams if (isFullScreen) { layoutName.visibility = View.VISIBLE @@ -638,7 +718,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session localPreviewLayoutParam.width = localPreviewWidth localPreviewLayoutParam.height = localPreviewHeight localPreviewLayoutParam.setMargins(0, localPreviewMargin, localPreviewMargin, 0) - if (mPublisher != null && mPublisher!!.view.parent == null){ + if (mPublisher != null && mPublisher!!.view.parent == null) { mPublisherViewContainer.addView(mPublisher!!.view) } mPublisherViewContainer.visibility = View.VISIBLE @@ -666,7 +746,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session localPreviewLayoutParam.height = 0 localPreviewLayoutParam.setMargins(0, localPreviewMargin / 2, localPreviewMargin / 2, 0) - if (mPublisher != null){ + if (mPublisher != null) { mPublisherViewContainer.removeView(mPublisher!!.view) } mPublisherViewContainer.visibility = View.GONE @@ -814,7 +894,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session var mParams: WindowManager.LayoutParams = dialog!!.window!!.attributes mParams.x = - (szWindow.x - current_x_cord * current_x_cord - videoCallContainer.width).toInt() + (szWindow.x - current_x_cord * current_x_cord - videoCallContainer.width).toInt() dialog!!.window!!.attributes = mParams val x = szWindow.x - current_x_cord @@ -825,7 +905,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session val step = (500 - t) / 5 // mParams.x = 0 - (current_x_cord * current_x_cord * step).toInt() mParams.x = - (szWindow.x - current_x_cord * current_x_cord * step - videoCallContainer.width).toInt() + (szWindow.x - current_x_cord * current_x_cord * step - videoCallContainer.width).toInt() dialog!!.window!!.attributes = mParams } @@ -851,7 +931,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session override fun onTick(t: Long) { val step = (500 - t) / 5 mParams.x = - (szWindow.x + current_x_cord * current_x_cord * step - videoCallContainer.width).toInt() + (szWindow.x + current_x_cord * current_x_cord * step - videoCallContainer.width).toInt() dialog!!.window!!.attributes = mParams } @@ -866,17 +946,20 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session private fun getWindowManagerDefaultDisplay() { mWindowManager.getDefaultDisplay() - .getSize(szWindow) + .getSize(szWindow) } /* return status bar height on basis of device display metrics */ private fun getStatusBarHeight(): Int { return ceil( - (25 * requireActivity().applicationContext.resources.displayMetrics.density).toDouble() + (25 * requireActivity().applicationContext.resources.displayMetrics.density).toDouble() ).toInt() } - private class MyGestureListener(val onTabCall: () -> Unit, val miniCircleDoubleTap: () -> Unit) : GestureDetector.SimpleOnGestureListener() { + private class MyGestureListener( + val onTabCall: () -> Unit, + val miniCircleDoubleTap: () -> Unit + ) : GestureDetector.SimpleOnGestureListener() { override fun onSingleTapConfirmed(event: MotionEvent): Boolean { // onTabCall() @@ -893,9 +976,9 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session companion object { @JvmStatic fun newInstance(args: Bundle) = - VideoCallFragment().apply { - arguments = args - } + VideoCallFragment().apply { + arguments = args + } private val TAG = VideoCallFragment::class.java.simpleName diff --git a/android/app/src/main/res/drawable/ic_record.xml b/android/app/src/main/res/drawable/ic_record.xml new file mode 100644 index 00000000..ffc49a08 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_record.xml @@ -0,0 +1,5 @@ + + + diff --git a/android/app/src/main/res/layout/activity_video_call.xml b/android/app/src/main/res/layout/activity_video_call.xml index a54e57b3..c492acb5 100644 --- a/android/app/src/main/res/layout/activity_video_call.xml +++ b/android/app/src/main/res/layout/activity_video_call.xml @@ -108,6 +108,23 @@ android:src="@drawable/video_off_fill" /> + + + + + (); + LiveCarePatientServices _liveCarePatientServices = + locator(); - openVideo(StartCallRes startModel,PatiantInformtion patientModel,VoidCallback onCallConnected, VoidCallback onCallDisconnected)async{ + openVideo( + StartCallRes startModel, + PatiantInformtion patientModel, + bool isRecording, + VoidCallback onCallConnected, + VoidCallback onCallDisconnected) async { this.startCallRes = startModel; this.patient = patientModel; - DoctorProfileModel doctorProfile = await getDoctorProfile(isGetProfile: true); + DoctorProfileModel doctorProfile = + await getDoctorProfile(isGetProfile: true); await VideoChannel.openVideoCallScreen( - kToken: startCallRes.openTokenID, - kSessionId:startCallRes.openSessionID, - kApiKey: '46209962' ,//'46209962' + kToken: startCallRes.openTokenID, + kSessionId: startCallRes.openSessionID, + kApiKey: '46209962', vcId: patient.vcId, - patientName: patient.fullName ?? (patient.firstName != null ? "${patient.firstName} ${patient.lastName}" : "-"), + isRecording: isRecording, + patientName: patient.fullName ?? + (patient.firstName != null + ? "${patient.firstName} ${patient.lastName}" + : "-"), tokenID: await sharedPref.getString(TOKEN), generalId: GENERAL_ID, doctorId: doctorProfile.doctorID, onFailure: (String error) { DrAppToastMsg.showErrorToast(error); - },onCallConnected: onCallConnected, + }, + onCallConnected: onCallConnected, onCallEnd: () { WidgetsBinding.instance.addPostFrameCallback((_) async { - GifLoaderDialogUtils.showMyDialog(locator().navigatorKey.currentContext); - endCall(patient.vcId, false,).then((value) { - GifLoaderDialogUtils.hideDialog(locator().navigatorKey.currentContext); - if (hasError) { - DrAppToastMsg.showErrorToast(error); - }else - locator().navigateTo(PATIENTS_END_Call,arguments: { - "patient": patient, - }); - - }); + GifLoaderDialogUtils.showMyDialog( + locator().navigatorKey.currentContext); + endCall( + patient.vcId, + false, + ).then((value) { + GifLoaderDialogUtils.hideDialog( + locator().navigatorKey.currentContext); + if (hasError) { + DrAppToastMsg.showErrorToast(error); + } else + locator() + .navigateTo(PATIENTS_END_Call, arguments: { + "patient": patient, + }); + }); }); }, onCallNotRespond: (SessionStatusModel sessionStatusModel) { WidgetsBinding.instance.addPostFrameCallback((_) { - GifLoaderDialogUtils.showMyDialog(locator().navigatorKey.currentContext); - endCall(patient.vcId, sessionStatusModel.sessionStatus == 3,).then((value) { - GifLoaderDialogUtils.hideDialog(locator().navigatorKey.currentContext); + GifLoaderDialogUtils.showMyDialog( + locator().navigatorKey.currentContext); + endCall( + patient.vcId, + sessionStatusModel.sessionStatus == 3, + ).then((value) { + GifLoaderDialogUtils.hideDialog( + locator().navigatorKey.currentContext); if (hasError) { DrAppToastMsg.showErrorToast(error); } else { - locator().navigateTo(PATIENTS_END_Call,arguments: { + locator() + .navigateTo(PATIENTS_END_Call, arguments: { "patient": patient, }); } - }); - - }); + }); }); - } + Future endCall(int vCID, bool isPatient) async { hasError = false; await getDoctorProfile(isGetProfile: true); @@ -85,5 +105,4 @@ class VideoCallService extends BaseService{ error = _liveCarePatientServices.error; } } - -} \ No newline at end of file +} diff --git a/lib/models/livecare/start_call_res.dart b/lib/models/livecare/start_call_res.dart index 67259996..e3c1a54f 100644 --- a/lib/models/livecare/start_call_res.dart +++ b/lib/models/livecare/start_call_res.dart @@ -5,6 +5,7 @@ class StartCallRes { bool isAuthenticated; int messageStatus; String appointmentNo; + bool isRecording; StartCallRes( {this.result, @@ -12,7 +13,9 @@ class StartCallRes { this.openTokenID, this.isAuthenticated, this.appointmentNo, - this.messageStatus}); + this.messageStatus, + this.isRecording = true, + }); StartCallRes.fromJson(Map json) { result = json['Result']; @@ -21,6 +24,7 @@ class StartCallRes { isAuthenticated = json['IsAuthenticated']; messageStatus = json['MessageStatus']; appointmentNo = json['AppointmentNo']; + isRecording = json['isRecording']; } Map toJson() { @@ -31,6 +35,7 @@ class StartCallRes { data['IsAuthenticated'] = this.isAuthenticated; data['MessageStatus'] = this.messageStatus; data['AppointmentNo'] = this.appointmentNo; + data['isRecording'] = this.isRecording; return data; } } diff --git a/lib/screens/live_care/end_call_screen.dart b/lib/screens/live_care/end_call_screen.dart index d3db12b6..0e65182b 100644 --- a/lib/screens/live_care/end_call_screen.dart +++ b/lib/screens/live_care/end_call_screen.dart @@ -79,6 +79,7 @@ class _EndCallScreenState extends State { kSessionId: liveCareModel.startCallRes.openSessionID, kApiKey: '46209962', vcId: patient.vcId, + isRecording: liveCareModel.startCallRes != null ? liveCareModel.startCallRes.isRecording: false, patientName: patient.fullName ?? (patient.firstName != null ? "${patient.firstName} ${patient.lastName}" : "-"), tokenID: await liveCareModel.getToken(), generalId: GENERAL_ID, diff --git a/lib/screens/live_care/video_call.dart b/lib/screens/live_care/video_call.dart index 07de1943..e024624a 100644 --- a/lib/screens/live_care/video_call.dart +++ b/lib/screens/live_care/video_call.dart @@ -66,6 +66,7 @@ class _VideoCallPageState extends State { //'1_MX40NjgwMzIyNH5-MTU5MzY4MzYzODYwM35ucExWYVRVSm5Hcy9uWGZmM1lOa3czZHV-fg', kApiKey: '46209962', vcId: widget.patientData.vcId, + isRecording: tokenData != null ? tokenData.isRecording: false, patientName: widget.patientData.fullName ?? widget.patientData.firstName != null ? "${widget.patientData.firstName} ${widget.patientData.lastName}" : "-", tokenID: token, //"hfkjshdf347r8743", generalId: "Cs2020@2016\$2958", 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 e11c1abf..4ad8e71d 100644 --- a/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart +++ b/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart @@ -57,6 +57,7 @@ class _PatientProfileScreenState extends State StreamController videoCallDurationStreamController; Stream videoCallDurationStream = (() async*{})(); + @override void initState() { _tabController = TabController(length: 2, vsync: this); @@ -119,6 +120,10 @@ class _PatientProfileScreenState extends State callDisconnected(){ callTimer.cancel(); videoCallDurationStreamController.sink.add(null); + + setState(() { + isCallStarted = false; + }); } @override @@ -350,7 +355,7 @@ class _PatientProfileScreenState extends State }); GifLoaderDialogUtils.hideDialog(context); AppPermissionsUtils.requestVideoCallPermission(context: context,onTapGrant: (){ - locator().openVideo(model.startCallRes, patient, callConnected, callDisconnected); + locator().openVideo(model.startCallRes, patient, model.startCallRes.isRecording, callConnected, callDisconnected); }); } } diff --git a/lib/util/VideoChannel.dart b/lib/util/VideoChannel.dart index 832749cf..94035d7d 100644 --- a/lib/util/VideoChannel.dart +++ b/lib/util/VideoChannel.dart @@ -11,7 +11,7 @@ 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, String patientName, Function() onCallEnd , + String generalId,int doctorId, String patientName, bool isRecording = false, Function() onCallEnd , Function(SessionStatusModel sessionStatusModel) onCallNotRespond ,Function(String error) onFailure, VoidCallback onCallConnected, VoidCallback onCallDisconnected}) async { onCallConnected = onCallConnected ?? (){}; @@ -41,6 +41,7 @@ class VideoChannel{ "generalId": generalId, "DoctorId": doctorId , "patientName": patientName, + "isRecording": isRecording, }, ); if(result['callResponse'] == 'CallEnd') {