video stream add record icon and change button disable

merge-requests/755/head
mosazaid 4 years ago
parent db4501bd14
commit 385820fdce

@ -54,8 +54,9 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
val generalId = call.argument<String>("generalId") val generalId = call.argument<String>("generalId")
val doctorId = call.argument<Int>("DoctorId") val doctorId = call.argument<Int>("DoctorId")
val patientName = call.argument<String>("patientName") val patientName = call.argument<String>("patientName")
val isRecording = call.argument<Boolean>("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) openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel)

@ -23,16 +23,20 @@ public class GetSessionStatusModel implements Parcelable {
@SerializedName("PatientName") @SerializedName("PatientName")
@Expose @Expose
private String patientName; private String patientName;
@SerializedName("isRecording")
@Expose
private boolean isRecording;
public GetSessionStatusModel() { 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.vCID = vCID;
this.tokenID = tokenID; this.tokenID = tokenID;
this.generalid = generalid; this.generalid = generalid;
this.doctorId = doctorId; this.doctorId = doctorId;
this.patientName = patientName; this.patientName = patientName;
this.isRecording = isRecording;
} }
protected GetSessionStatusModel(Parcel in) { protected GetSessionStatusModel(Parcel in) {
@ -49,6 +53,7 @@ public class GetSessionStatusModel implements Parcelable {
doctorId = in.readInt(); doctorId = in.readInt();
} }
patientName = in.readString(); patientName = in.readString();
isRecording = in.readInt() == 1;
} }
public static final Creator<GetSessionStatusModel> CREATOR = new Creator<GetSessionStatusModel>() { public static final Creator<GetSessionStatusModel> CREATOR = new Creator<GetSessionStatusModel>() {
@ -105,6 +110,14 @@ public class GetSessionStatusModel implements Parcelable {
this.patientName = patientName; this.patientName = patientName;
} }
public boolean isRecording() {
return isRecording;
}
public void setRecording(boolean recording) {
isRecording = recording;
}
@Override @Override
public int describeContents() { public int describeContents() {
return 0; return 0;
@ -127,5 +140,6 @@ public class GetSessionStatusModel implements Parcelable {
dest.writeInt(doctorId); dest.writeInt(doctorId);
} }
dest.writeString(patientName); dest.writeString(patientName);
dest.writeInt(isRecording ? 1 : 0);
} }
} }

@ -38,8 +38,9 @@ import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
import kotlin.math.ceil import kotlin.math.ceil
class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.SessionListener, PublisherListener, class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.SessionListener,
SubscriberKit.VideoListener, VideoCallView { PublisherListener,
SubscriberKit.VideoListener, VideoCallView {
private var isFullScreen: Boolean = true private var isFullScreen: Boolean = true
private var isCircle: Boolean = false private var isCircle: Boolean = false
@ -62,6 +63,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
private var mVolRunnable: Runnable? = null private var mVolRunnable: Runnable? = null
private var mConnectedRunnable: Runnable? = null private var mConnectedRunnable: Runnable? = null
private lateinit var recordContainer: FrameLayout
private lateinit var thumbnail_container: FrameLayout private lateinit var thumbnail_container: FrameLayout
private lateinit var mPublisherViewContainer: FrameLayout private lateinit var mPublisherViewContainer: FrameLayout
private lateinit var mPublisherViewIcon: View private lateinit var mPublisherViewIcon: View
@ -74,6 +76,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
private var token: String? = null private var token: String? = null
private var appLang: String? = null private var appLang: String? = null
private var baseUrl: String? = null private var baseUrl: String? = null
private var isRecording: Boolean = true
private var isSwitchCameraClicked = false private var isSwitchCameraClicked = false
private var isCameraClicked = false private var isCameraClicked = false
@ -117,8 +120,8 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
super.onStart() super.onStart()
dialog?.window?.setLayout( 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 // Make the dialog possible to be outside touch
dialogWindow!!.setFlags( 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) dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
requireView().invalidate() requireView().invalidate()
@ -168,8 +171,10 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
this.videoCallResponseListener = videoCallResponseListener this.videoCallResponseListener = videoCallResponseListener
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(
savedInstanceState: Bundle?): View { inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
parentView = inflater.inflate(R.layout.activity_video_call, container, false) parentView = inflater.inflate(R.layout.activity_video_call, container, false)
@ -181,12 +186,17 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
appLang = getString("appLang") appLang = getString("appLang")
baseUrl = getString("baseUrl") baseUrl = getString("baseUrl")
sessionStatusModel = getParcelable("sessionStatusModel") sessionStatusModel = getParcelable("sessionStatusModel")
if (sessionStatusModel != null)
isRecording = sessionStatusModel!!.isRecording
} }
initUI(parentView) initUI(parentView)
requestPermissions() requestPermissions()
handleDragDialog() handleDragDialog()
mDetector = GestureDetectorCompat(context, MyGestureListener({ showControlPanelTemporarily() }, { miniCircleDoubleTap() })) mDetector = GestureDetectorCompat(
context,
MyGestureListener({ showControlPanelTemporarily() }, { miniCircleDoubleTap() })
)
return parentView return parentView
} }
@ -223,6 +233,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
layoutName = view.findViewById(R.id.layout_name) layoutName = view.findViewById(R.id.layout_name)
layoutMini = view.findViewById(R.id.layout_mini) layoutMini = view.findViewById(R.id.layout_mini)
icMini = view.findViewById(R.id.ic_mini) icMini = view.findViewById(R.id.ic_mini)
recordContainer = view.findViewById(R.id.record_container)
thumbnail_container = view.findViewById(R.id.thumbnail_container) thumbnail_container = view.findViewById(R.id.thumbnail_container)
mPublisherViewContainer = view.findViewById(R.id.local_video_view_container) mPublisherViewContainer = view.findViewById(R.id.local_video_view_container)
mPublisherViewIcon = view.findViewById(R.id.local_video_view_icon) mPublisherViewIcon = view.findViewById(R.id.local_video_view_icon)
@ -232,23 +243,30 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
patientName = view.findViewById<TextView>(R.id.patient_name) patientName = view.findViewById<TextView>(R.id.patient_name)
patientName.text = sessionStatusModel!!.patientName patientName.text = sessionStatusModel!!.patientName
if (isRecording) {
recordContainer.visibility = View.VISIBLE
} else {
recordContainer.visibility = View.GONE
}
cmTimer = view.findViewById<Chronometer>(R.id.cmTimer) cmTimer = view.findViewById<Chronometer>(R.id.cmTimer)
cmTimer.format = "mm:ss" cmTimer.format = "mm:ss"
cmTimer.onChronometerTickListener = Chronometer.OnChronometerTickListener { arg0: Chronometer? -> cmTimer.onChronometerTickListener =
val minutes: Long Chronometer.OnChronometerTickListener { arg0: Chronometer? ->
val seconds: Long val minutes: Long
if (!resume) { val seconds: Long
minutes = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 / 60 if (!resume) {
seconds = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 % 60 minutes = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 / 60
elapsedTime = SystemClock.elapsedRealtime() seconds = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 % 60
} else { elapsedTime = SystemClock.elapsedRealtime()
minutes = (elapsedTime - cmTimer.base) / 1000 / 60 } else {
seconds = (elapsedTime - cmTimer.base) / 1000 % 60 minutes = (elapsedTime - cmTimer.base) / 1000 / 60
elapsedTime += 1000 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 { icMini.setOnClickListener {
onMiniCircleClicked() onMiniCircleClicked()
@ -310,7 +328,11 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong()) mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong())
} }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) { override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this) EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
} }
@ -323,19 +345,25 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size) Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size)
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
AppSettingsDialog.Builder(this) AppSettingsDialog.Builder(this)
.setTitle(getString(R.string.title_settings_dialog)) .setTitle(getString(R.string.title_settings_dialog))
.setRationale(getString(R.string.rationale_ask_again)) .setRationale(getString(R.string.rationale_ask_again))
.setPositiveButton(getString(R.string.setting)) .setPositiveButton(getString(R.string.setting))
.setNegativeButton(getString(R.string.cancel)) .setNegativeButton(getString(R.string.cancel))
.setRequestCode(RC_SETTINGS_SCREEN_PERM) .setRequestCode(RC_SETTINGS_SCREEN_PERM)
.build() .build()
.show() .show()
} }
} }
@AfterPermissionGranted(RC_VIDEO_APP_PERM) @AfterPermissionGranted(RC_VIDEO_APP_PERM)
private fun requestPermissions() { 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)) { if (EasyPermissions.hasPermissions(requireContext(), *perms)) {
try { try {
mSession = Session.Builder(context, apiKey, sessionId).build() mSession = Session.Builder(context, apiKey, sessionId).build()
@ -345,7 +373,12 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
e.printStackTrace() e.printStackTrace()
} }
} else { } 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()) mPublisher = Publisher.Builder(requireContext())
// .name("publisher") // .name("publisher")
// .renderer(ThumbnailCircleVideoRenderer(requireContext())) // .renderer(ThumbnailCircleVideoRenderer(requireContext()))
.build() .build()
mPublisher!!.setPublisherListener(this) mPublisher!!.setPublisherListener(this)
if (mPublisher!!.view is GLSurfaceView) { if (mPublisher!!.view is GLSurfaceView) {
(mPublisher!!.view as GLSurfaceView).setZOrderOnTop(true) (mPublisher!!.view as GLSurfaceView).setZOrderOnTop(true)
@ -387,7 +420,10 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
} }
override fun onStreamReceived(session: Session, stream: Stream) { 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) { if (mSubscriber != null) {
isConnected = true isConnected = true
return return
@ -396,11 +432,22 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
subscribeToStream(stream) subscribeToStream(stream)
if (mConnectedHandler != null && mConnectedRunnable != null) if (mConnectedHandler != null && mConnectedRunnable != null)
mConnectedHandler!!.removeCallbacks(mConnectedRunnable!!) 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) { 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) { if (mSubscriber == null) {
return return
} }
@ -427,7 +474,10 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
} }
override fun onVideoDataReceived(subscriberKit: SubscriberKit?) { 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) (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(false)
mSubscriberViewContainer.addView(mSubscriber!!.view) mSubscriberViewContainer.addView(mSubscriber!!.view)
// switchToThumbnailCircle() // switchToThumbnailCircle()
@ -477,8 +527,8 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
private fun subscribeToStream(stream: Stream) { private fun subscribeToStream(stream: Stream) {
mSubscriber = Subscriber.Builder(requireContext(), stream) mSubscriber = Subscriber.Builder(requireContext(), stream)
.renderer(DynamicVideoRenderer(requireContext())) .renderer(DynamicVideoRenderer(requireContext()))
.build() .build()
mSubscriber!!.setVideoListener(this) mSubscriber!!.setVideoListener(this)
mSession!!.subscribe(mSubscriber) mSession!!.subscribe(mSubscriber)
} }
@ -506,7 +556,15 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
mSession!!.disconnect() mSession!!.disconnect()
countDownTimer?.cancel() 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() dialog?.dismiss()
} }
@ -546,13 +604,13 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
private fun onMiniCircleClicked() { private fun onMiniCircleClicked() {
if (isCircle) { if (isCircle) {
dialog?.window?.setLayout( dialog?.window?.setLayout(
400, 400,
600 600
) )
} else { } else {
dialog?.window?.setLayout( dialog?.window?.setLayout(
300, 300,
300 300
) )
} }
isCircle = !isCircle isCircle = !isCircle
@ -561,11 +619,23 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
(mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(isCircle) (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(isCircle)
} else { } else {
if (isCircle) { if (isCircle) {
videoCallContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape) videoCallContainer.background =
mSubscriberViewContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape) ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
mSubscriberViewContainer.background =
ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
} else { } else {
videoCallContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color)) videoCallContainer.setBackgroundColor(
mSubscriberViewContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.remoteBackground)) 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?) { private fun onMinimizedClicked(view: View?) {
if (isFullScreen) { if (isFullScreen) {
dialog?.window?.setLayout( dialog?.window?.setLayout(
400, 400,
600 600
) )
} else { } else {
dialog?.window?.setLayout( dialog?.window?.setLayout(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT LinearLayout.LayoutParams.MATCH_PARENT
) )
} }
isFullScreen = !isFullScreen isFullScreen = !isFullScreen
@ -602,24 +672,34 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
private fun setViewsVisibility() { private fun setViewsVisibility() {
val iconSize: Int = context!!.resources.getDimension(R.dimen.video_icon_size).toInt() 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 iconSizeSmall: Int =
val btnMinimizeLayoutParam: ConstraintLayout.LayoutParams = btnMinimize.layoutParams as ConstraintLayout.LayoutParams context!!.resources.getDimension(R.dimen.video_icon_size_small).toInt()
val mCallBtnLayoutParam: ConstraintLayout.LayoutParams = mCallBtn.layoutParams as ConstraintLayout.LayoutParams val btnMinimizeLayoutParam: ConstraintLayout.LayoutParams =
btnMinimize.layoutParams as ConstraintLayout.LayoutParams
val localPreviewMargin: Int = context!!.resources.getDimension(R.dimen.local_preview_margin_top).toInt() val mCallBtnLayoutParam: ConstraintLayout.LayoutParams =
val localPreviewWidth: Int = context!!.resources.getDimension(R.dimen.local_preview_width).toInt() mCallBtn.layoutParams as ConstraintLayout.LayoutParams
val localPreviewHeight: Int = context!!.resources.getDimension(R.dimen.local_preview_height).toInt()
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 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 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 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 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 localPreviewIconSmall: Int = context!!.resources.getDimension(R.dimen.local_back_icon_size_small).toInt()
// val localPreviewLayoutIconParam : FrameLayout.LayoutParams // 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 remotePreviewIconSize: Int =
val remotePreviewIconSizeSmall: Int = context!!.resources.getDimension(R.dimen.remote_back_icon_size_small).toInt() context!!.resources.getDimension(R.dimen.remote_back_icon_size).toInt()
val remotePreviewLayoutParam: FrameLayout.LayoutParams = mSubscriberViewIcon.layoutParams as FrameLayout.LayoutParams 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) { if (isFullScreen) {
layoutName.visibility = View.VISIBLE layoutName.visibility = View.VISIBLE
@ -638,7 +718,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
localPreviewLayoutParam.width = localPreviewWidth localPreviewLayoutParam.width = localPreviewWidth
localPreviewLayoutParam.height = localPreviewHeight localPreviewLayoutParam.height = localPreviewHeight
localPreviewLayoutParam.setMargins(0, localPreviewMargin, localPreviewMargin, 0) 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.addView(mPublisher!!.view)
} }
mPublisherViewContainer.visibility = View.VISIBLE mPublisherViewContainer.visibility = View.VISIBLE
@ -666,7 +746,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
localPreviewLayoutParam.height = 0 localPreviewLayoutParam.height = 0
localPreviewLayoutParam.setMargins(0, localPreviewMargin / 2, localPreviewMargin / 2, 0) localPreviewLayoutParam.setMargins(0, localPreviewMargin / 2, localPreviewMargin / 2, 0)
if (mPublisher != null){ if (mPublisher != null) {
mPublisherViewContainer.removeView(mPublisher!!.view) mPublisherViewContainer.removeView(mPublisher!!.view)
} }
mPublisherViewContainer.visibility = View.GONE mPublisherViewContainer.visibility = View.GONE
@ -814,7 +894,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
var mParams: WindowManager.LayoutParams = dialog!!.window!!.attributes var mParams: WindowManager.LayoutParams = dialog!!.window!!.attributes
mParams.x = 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 dialog!!.window!!.attributes = mParams
val x = szWindow.x - current_x_cord val x = szWindow.x - current_x_cord
@ -825,7 +905,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
val step = (500 - t) / 5 val step = (500 - t) / 5
// mParams.x = 0 - (current_x_cord * current_x_cord * step).toInt() // mParams.x = 0 - (current_x_cord * current_x_cord * step).toInt()
mParams.x = 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 dialog!!.window!!.attributes = mParams
} }
@ -851,7 +931,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
override fun onTick(t: Long) { override fun onTick(t: Long) {
val step = (500 - t) / 5 val step = (500 - t) / 5
mParams.x = 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 dialog!!.window!!.attributes = mParams
} }
@ -866,17 +946,20 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
private fun getWindowManagerDefaultDisplay() { private fun getWindowManagerDefaultDisplay() {
mWindowManager.getDefaultDisplay() mWindowManager.getDefaultDisplay()
.getSize(szWindow) .getSize(szWindow)
} }
/* return status bar height on basis of device display metrics */ /* return status bar height on basis of device display metrics */
private fun getStatusBarHeight(): Int { private fun getStatusBarHeight(): Int {
return ceil( return ceil(
(25 * requireActivity().applicationContext.resources.displayMetrics.density).toDouble() (25 * requireActivity().applicationContext.resources.displayMetrics.density).toDouble()
).toInt() ).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 { override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
// onTabCall() // onTabCall()
@ -893,9 +976,9 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
companion object { companion object {
@JvmStatic @JvmStatic
fun newInstance(args: Bundle) = fun newInstance(args: Bundle) =
VideoCallFragment().apply { VideoCallFragment().apply {
arguments = args arguments = args
} }
private val TAG = VideoCallFragment::class.java.simpleName private val TAG = VideoCallFragment::class.java.simpleName

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M13.05,9.79L10,7.5v9l3.05,-2.29L16,12zM13.05,9.79L10,7.5v9l3.05,-2.29L16,12zM13.05,9.79L10,7.5v9l3.05,-2.29L16,12zM11,4.07L11,2.05c-2.01,0.2 -3.84,1 -5.32,2.21L7.1,5.69c1.11,-0.86 2.44,-1.44 3.9,-1.62zM5.69,7.1L4.26,5.68C3.05,7.16 2.25,8.99 2.05,11h2.02c0.18,-1.46 0.76,-2.79 1.62,-3.9zM4.07,13L2.05,13c0.2,2.01 1,3.84 2.21,5.32l1.43,-1.43c-0.86,-1.1 -1.44,-2.43 -1.62,-3.89zM5.68,19.74C7.16,20.95 9,21.75 11,21.95v-2.02c-1.46,-0.18 -2.79,-0.76 -3.9,-1.62l-1.42,1.43zM22,12c0,5.16 -3.92,9.42 -8.95,9.95v-2.02C16.97,19.41 20,16.05 20,12s-3.03,-7.41 -6.95,-7.93L13.05,2.05C18.08,2.58 22,6.84 22,12z"/>
</vector>

@ -108,6 +108,23 @@
android:src="@drawable/video_off_fill" /> android:src="@drawable/video_off_fill" />
</FrameLayout> </FrameLayout>
<FrameLayout
android:id="@+id/record_container"
android:layout_width="@dimen/local_preview_width"
android:layout_height="@dimen/local_preview_height"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:visibility="visible">
<ImageView
android:id="@+id/record_icon"
android:layout_width="@dimen/local_back_icon_size"
android:layout_height="@dimen/local_back_icon_size"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/ic_record" />
</FrameLayout>
<FrameLayout <FrameLayout
android:id="@+id/thumbnail_container" android:id="@+id/thumbnail_container"
android:layout_width="90dp" android:layout_width="90dp"

@ -16,62 +16,82 @@ import '../../locator.dart';
import '../../routes.dart'; import '../../routes.dart';
import 'NavigationService.dart'; import 'NavigationService.dart';
class VideoCallService extends BaseService{ class VideoCallService extends BaseService {
StartCallRes startCallRes; StartCallRes startCallRes;
PatiantInformtion patient; PatiantInformtion patient;
LiveCarePatientServices _liveCarePatientServices = locator<LiveCarePatientServices>(); LiveCarePatientServices _liveCarePatientServices =
locator<LiveCarePatientServices>();
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.startCallRes = startModel;
this.patient = patientModel; this.patient = patientModel;
DoctorProfileModel doctorProfile = await getDoctorProfile(isGetProfile: true); DoctorProfileModel doctorProfile =
await getDoctorProfile(isGetProfile: true);
await VideoChannel.openVideoCallScreen( await VideoChannel.openVideoCallScreen(
kToken: startCallRes.openTokenID, kToken: startCallRes.openTokenID,
kSessionId:startCallRes.openSessionID, kSessionId: startCallRes.openSessionID,
kApiKey: '46209962' ,//'46209962' kApiKey: '46209962',
vcId: patient.vcId, 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), tokenID: await sharedPref.getString(TOKEN),
generalId: GENERAL_ID, generalId: GENERAL_ID,
doctorId: doctorProfile.doctorID, doctorId: doctorProfile.doctorID,
onFailure: (String error) { onFailure: (String error) {
DrAppToastMsg.showErrorToast(error); DrAppToastMsg.showErrorToast(error);
},onCallConnected: onCallConnected, },
onCallConnected: onCallConnected,
onCallEnd: () { onCallEnd: () {
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
GifLoaderDialogUtils.showMyDialog(locator<NavigationService>().navigatorKey.currentContext); GifLoaderDialogUtils.showMyDialog(
endCall(patient.vcId, false,).then((value) { locator<NavigationService>().navigatorKey.currentContext);
GifLoaderDialogUtils.hideDialog(locator<NavigationService>().navigatorKey.currentContext); endCall(
if (hasError) { patient.vcId,
DrAppToastMsg.showErrorToast(error); false,
}else ).then((value) {
locator<NavigationService>().navigateTo(PATIENTS_END_Call,arguments: { GifLoaderDialogUtils.hideDialog(
"patient": patient, locator<NavigationService>().navigatorKey.currentContext);
}); if (hasError) {
DrAppToastMsg.showErrorToast(error);
}); } else
locator<NavigationService>()
.navigateTo(PATIENTS_END_Call, arguments: {
"patient": patient,
});
});
}); });
}, },
onCallNotRespond: (SessionStatusModel sessionStatusModel) { onCallNotRespond: (SessionStatusModel sessionStatusModel) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
GifLoaderDialogUtils.showMyDialog(locator<NavigationService>().navigatorKey.currentContext); GifLoaderDialogUtils.showMyDialog(
endCall(patient.vcId, sessionStatusModel.sessionStatus == 3,).then((value) { locator<NavigationService>().navigatorKey.currentContext);
GifLoaderDialogUtils.hideDialog(locator<NavigationService>().navigatorKey.currentContext); endCall(
patient.vcId,
sessionStatusModel.sessionStatus == 3,
).then((value) {
GifLoaderDialogUtils.hideDialog(
locator<NavigationService>().navigatorKey.currentContext);
if (hasError) { if (hasError) {
DrAppToastMsg.showErrorToast(error); DrAppToastMsg.showErrorToast(error);
} else { } else {
locator<NavigationService>().navigateTo(PATIENTS_END_Call,arguments: { locator<NavigationService>()
.navigateTo(PATIENTS_END_Call, arguments: {
"patient": patient, "patient": patient,
}); });
} }
}); });
});
});
}); });
} }
Future endCall(int vCID, bool isPatient) async { Future endCall(int vCID, bool isPatient) async {
hasError = false; hasError = false;
await getDoctorProfile(isGetProfile: true); await getDoctorProfile(isGetProfile: true);
@ -85,5 +105,4 @@ class VideoCallService extends BaseService{
error = _liveCarePatientServices.error; error = _liveCarePatientServices.error;
} }
} }
}
}

@ -5,6 +5,7 @@ class StartCallRes {
bool isAuthenticated; bool isAuthenticated;
int messageStatus; int messageStatus;
String appointmentNo; String appointmentNo;
bool isRecording;
StartCallRes( StartCallRes(
{this.result, {this.result,
@ -12,7 +13,9 @@ class StartCallRes {
this.openTokenID, this.openTokenID,
this.isAuthenticated, this.isAuthenticated,
this.appointmentNo, this.appointmentNo,
this.messageStatus}); this.messageStatus,
this.isRecording = true,
});
StartCallRes.fromJson(Map<String, dynamic> json) { StartCallRes.fromJson(Map<String, dynamic> json) {
result = json['Result']; result = json['Result'];
@ -21,6 +24,7 @@ class StartCallRes {
isAuthenticated = json['IsAuthenticated']; isAuthenticated = json['IsAuthenticated'];
messageStatus = json['MessageStatus']; messageStatus = json['MessageStatus'];
appointmentNo = json['AppointmentNo']; appointmentNo = json['AppointmentNo'];
isRecording = json['isRecording'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -31,6 +35,7 @@ class StartCallRes {
data['IsAuthenticated'] = this.isAuthenticated; data['IsAuthenticated'] = this.isAuthenticated;
data['MessageStatus'] = this.messageStatus; data['MessageStatus'] = this.messageStatus;
data['AppointmentNo'] = this.appointmentNo; data['AppointmentNo'] = this.appointmentNo;
data['isRecording'] = this.isRecording;
return data; return data;
} }
} }

@ -79,6 +79,7 @@ class _EndCallScreenState extends State<EndCallScreen> {
kSessionId: liveCareModel.startCallRes.openSessionID, kSessionId: liveCareModel.startCallRes.openSessionID,
kApiKey: '46209962', kApiKey: '46209962',
vcId: patient.vcId, vcId: patient.vcId,
isRecording: liveCareModel.startCallRes != null ? liveCareModel.startCallRes.isRecording: false,
patientName: patient.fullName ?? (patient.firstName != null ? "${patient.firstName} ${patient.lastName}" : "-"), patientName: patient.fullName ?? (patient.firstName != null ? "${patient.firstName} ${patient.lastName}" : "-"),
tokenID: await liveCareModel.getToken(), tokenID: await liveCareModel.getToken(),
generalId: GENERAL_ID, generalId: GENERAL_ID,

@ -66,6 +66,7 @@ class _VideoCallPageState extends State<VideoCallPage> {
//'1_MX40NjgwMzIyNH5-MTU5MzY4MzYzODYwM35ucExWYVRVSm5Hcy9uWGZmM1lOa3czZHV-fg', //'1_MX40NjgwMzIyNH5-MTU5MzY4MzYzODYwM35ucExWYVRVSm5Hcy9uWGZmM1lOa3czZHV-fg',
kApiKey: '46209962', kApiKey: '46209962',
vcId: widget.patientData.vcId, vcId: widget.patientData.vcId,
isRecording: tokenData != null ? tokenData.isRecording: false,
patientName: widget.patientData.fullName ?? widget.patientData.firstName != null ? "${widget.patientData.firstName} ${widget.patientData.lastName}" : "-", patientName: widget.patientData.fullName ?? widget.patientData.firstName != null ? "${widget.patientData.firstName} ${widget.patientData.lastName}" : "-",
tokenID: token, //"hfkjshdf347r8743", tokenID: token, //"hfkjshdf347r8743",
generalId: "Cs2020@2016\$2958", generalId: "Cs2020@2016\$2958",

@ -57,6 +57,7 @@ class _PatientProfileScreenState extends State<PatientProfileScreen>
StreamController<String> videoCallDurationStreamController; StreamController<String> videoCallDurationStreamController;
Stream<String> videoCallDurationStream = (() async*{})(); Stream<String> videoCallDurationStream = (() async*{})();
@override @override
void initState() { void initState() {
_tabController = TabController(length: 2, vsync: this); _tabController = TabController(length: 2, vsync: this);
@ -119,6 +120,10 @@ class _PatientProfileScreenState extends State<PatientProfileScreen>
callDisconnected(){ callDisconnected(){
callTimer.cancel(); callTimer.cancel();
videoCallDurationStreamController.sink.add(null); videoCallDurationStreamController.sink.add(null);
setState(() {
isCallStarted = false;
});
} }
@override @override
@ -350,7 +355,7 @@ class _PatientProfileScreenState extends State<PatientProfileScreen>
}); });
GifLoaderDialogUtils.hideDialog(context); GifLoaderDialogUtils.hideDialog(context);
AppPermissionsUtils.requestVideoCallPermission(context: context,onTapGrant: (){ AppPermissionsUtils.requestVideoCallPermission(context: context,onTapGrant: (){
locator<VideoCallService>().openVideo(model.startCallRes, patient, callConnected, callDisconnected); locator<VideoCallService>().openVideo(model.startCallRes, patient, model.startCallRes.isRecording, callConnected, callDisconnected);
}); });
} }
} }

@ -11,7 +11,7 @@ class VideoChannel{
/// channel name /// channel name
static const _channel = const MethodChannel("Dr.cloudSolution/videoCall"); static const _channel = const MethodChannel("Dr.cloudSolution/videoCall");
static openVideoCallScreen({kApiKey, kSessionId, kToken, callDuration, warningDuration,int vcId,String tokenID, 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 { Function(SessionStatusModel sessionStatusModel) onCallNotRespond ,Function(String error) onFailure, VoidCallback onCallConnected, VoidCallback onCallDisconnected}) async {
onCallConnected = onCallConnected ?? (){}; onCallConnected = onCallConnected ?? (){};
@ -41,6 +41,7 @@ class VideoChannel{
"generalId": generalId, "generalId": generalId,
"DoctorId": doctorId , "DoctorId": doctorId ,
"patientName": patientName, "patientName": patientName,
"isRecording": isRecording,
}, },
); );
if(result['callResponse'] == 'CallEnd') { if(result['callResponse'] == 'CallEnd') {

Loading…
Cancel
Save