video stream keyboard changing

merge-requests/759/head
mosazaid 3 years ago
parent 7fed1c58f3
commit c9d7df01e3

@ -2,18 +2,20 @@ package com.hmg.hmgDr
import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.annotation.NonNull
import com.google.gson.GsonBuilder
import com.hmg.hmgDr.Model.GetSessionStatusModel
import com.hmg.hmgDr.Model.SessionStatusModel
import com.hmg.hmgDr.Service.VideoStreamContainerService
import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.ui.fragment.VideoCallFragment
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
@ -21,7 +23,8 @@ import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler, VideoCallResponseListener {
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
VideoCallResponseListener {
private val CHANNEL = "Dr.cloudSolution/videoCall"
private lateinit var methodChannel: MethodChannel
@ -33,8 +36,6 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
private var videoStreamService: VideoStreamContainerService? = null
private var bound = false
private var dialogFragment: VideoCallFragment? = null
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
@ -62,14 +63,15 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
val doctorId = call.argument<Int>("DoctorId")
val patientName = call.argument<String>("patientName")
val sessionStatusModel = GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId, patientName)
val sessionStatusModel =
GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId, patientName)
openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel)
}
"closeVideoCall" -> {
dialogFragment?.onCallClicked()
videoStreamService?.closeVideoCall()
}
"onCallConnected" -> {
@ -80,7 +82,14 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
}
}
private fun openVideoCall(apiKey: String?, sessionId: String?, token: String?, appLang: String?, baseUrl: String?, sessionStatusModel: GetSessionStatusModel) {
private fun openVideoCall(
apiKey: String?,
sessionId: String?,
token: String?,
appLang: String?,
baseUrl: String?,
sessionStatusModel: GetSessionStatusModel
) {
val arguments = Bundle()
arguments.putString("apiKey", apiKey)
arguments.putString("sessionId", sessionId)
@ -89,31 +98,14 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
arguments.putString("baseUrl", baseUrl)
arguments.putParcelable("sessionStatusModel", sessionStatusModel)
// showSoftKeyBoard(null)
// start service
serviceIntent = Intent(this@MainActivity, VideoStreamContainerService::class.java)
serviceIntent?.run {
putExtras(arguments)
startService(this)
}
VideoStreamContainerService.videoCallResponseListener = this
if (dialogFragment == null) {
val transaction = supportFragmentManager.beginTransaction()
dialogFragment = VideoCallFragment.newInstance(arguments)
dialogFragment?.let {
it.setCallListener(this)
it.isCancelable = true
if (it.isAdded){
it.dismiss()
}else {
it.show(transaction, "dialog")
}
}
} else if (!dialogFragment!!.isVisible) {
val transaction = supportFragmentManager.beginTransaction()
dialogFragment!!.show(transaction, "dialog")
}
bindService()
}
/* override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -143,9 +135,9 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
}*/
override fun onCallFinished(resultCode: Int, intent: Intent?) {
dialogFragment = null
// TODO uncomment it
if (resultCode == Activity.RESULT_OK) {
/*if (resultCode == Activity.RESULT_OK) {
val result: SessionStatusModel? = intent?.getParcelableExtra("sessionStatusNotRespond")
val callResponse: HashMap<String, String> = HashMap()
@ -158,7 +150,7 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
try {
this.result?.success(callResponse)
} catch (e : Exception){
} catch (e: Exception) {
Log.e("onVideoCallFinished", "${e.message}.")
}
} else if (resultCode == Activity.RESULT_CANCELED) {
@ -166,15 +158,14 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
callResponse["callResponse"] = "CallEnd"
try {
result?.success(callResponse)
} catch (e : Exception){
} catch (e: Exception) {
Log.e("onVideoCallFinished", "${e.message}.")
}
}
}
override fun errorHandle(message: String) {
dialogFragment = null
// Toast.makeText(this, message, Toast.LENGTH_LONG).show()
*/
stopService(serviceIntent)
unbindService()
videoStreamService!!.serviceRunning = false
}
override fun minimizeVideoEvent(isMinimize: Boolean) {
@ -188,23 +179,30 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
super.onBackPressed()
}
override fun onStart() {
super.onStart()
bindService()
}
override fun onStop() {
super.onStop()
unbindService()
}
// override fun onStart() {
// super.onStart()
// bindService()
// }
//
// override fun onStop() {
// super.onStop()
// unbindService()
// }
private fun bindService() {
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
serviceIntent?.run {
if (videoStreamService != null && !videoStreamService!!.serviceRunning){
startService(this)
}
bindService(this, serviceConnection, Context.BIND_AUTO_CREATE)
videoStreamService?.serviceRunning = true
}
}
private fun unbindService() {
if (bound) {
gpsService.registerCallBack(null) // unregister
videoStreamService!!.videoCallResponseListener = null // unregister
videoStreamService!!.mActivity = null
unbindService(serviceConnection)
bound = false
}
@ -212,10 +210,12 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
private val serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val binder: VideoStreamContainerService.GPSBinder = service as GPSService.GPSBinder
gpsService = binder.getService()
val binder: VideoStreamContainerService.VideoStreamBinder =
service as VideoStreamContainerService.VideoStreamBinder
videoStreamService = binder.service
bound = true
gpsService.registerCallBack(this@YourActivity) // register
videoStreamService!!.videoCallResponseListener = this@MainActivity // register
videoStreamService!!.mActivity = this@MainActivity // register
}
override fun onServiceDisconnected(name: ComponentName?) {
@ -224,4 +224,18 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
}
// code to hide soft keyboard
fun hideSoftKeyBoard(editBox: EditText?) {
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editBox?.windowToken, 0)
}
// code to show soft keyboard
private fun showSoftKeyBoard(editBox: EditText?) {
val inputMethodManager = this.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
editBox?.requestFocus()
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
}
}

@ -2,29 +2,90 @@ package com.hmg.hmgDr.Service
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.Bundle
import android.os.IBinder
import android.widget.Toast
import com.hmg.hmgDr.MainActivity
import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.ui.fragment.VideoCallFragment
object VideoStreamContainerService : Service() {
class VideoStreamContainerService : Service(), VideoCallResponseListener {
// https://stackoverflow.com/questions/2463175/how-to-have-android-service-communicate-with-activity
var videoCallResponseListener: VideoCallResponseListener? = null
var mActivity: MainActivity? = null
set(value) {
field = value
if (field != null) {
setDialogFragment()
}
}
var arguments: Bundle? = null
var serviceRunning: Boolean = false
private val serviceBinder: IBinder = VideoStreamBinder()
private var dialogFragment: VideoCallFragment? = null
override fun onBind(intent: Intent?): IBinder? {
return null
override fun onBind(intent: Intent?): IBinder {
return serviceBinder
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null){
private fun setDialogFragment() {
mActivity?.run {
if (dialogFragment == null) {
val transaction = supportFragmentManager.beginTransaction()
dialogFragment = VideoCallFragment.newInstance(arguments!!)
dialogFragment?.let {
it.setCallListener(this@VideoStreamContainerService)
it.isCancelable = true
if (it.isAdded) {
it.dismiss()
} else {
it.show(transaction, "dialog")
}
}
} else if (!dialogFragment!!.isVisible) {
val transaction = supportFragmentManager.beginTransaction()
dialogFragment!!.show(transaction, "dialog")
} else {
// don't do anything
}
}
}
fun closeVideoCall(){
dialogFragment?.onCallClicked()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null && intent.extras != null) {
arguments = intent.extras
}
Toast.makeText(this, "Service started by user.", Toast.LENGTH_LONG).show()
// Toast.makeText(this, "Service started by user.", Toast.LENGTH_LONG).show()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
Toast.makeText(this, "Service destroyed by user.", Toast.LENGTH_LONG).show()
// Toast.makeText(this, "Service destroyed by user.", Toast.LENGTH_LONG).show()
}
inner class VideoStreamBinder : Binder() {
val service: VideoStreamContainerService
get() = this@VideoStreamContainerService
}
override fun onCallFinished(resultCode: Int, intent: Intent?) {
dialogFragment = null
videoCallResponseListener?.onCallFinished(resultCode, intent)
}
override fun errorHandle(message: String) {
dialogFragment = null
// Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
override fun minimizeVideoEvent(isMinimize: Boolean) {
videoCallResponseListener?.minimizeVideoEvent(isMinimize)
}
}

@ -6,7 +6,7 @@ interface VideoCallResponseListener {
fun onCallFinished(resultCode : Int, intent: Intent? = null)
fun errorHandle(message: String)
fun errorHandle(message: String){}
fun minimizeVideoEvent(isMinimize : Boolean)

@ -15,6 +15,7 @@ import android.util.Log
import android.view.*
import android.widget.*
import androidx.annotation.Nullable
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat
@ -28,16 +29,18 @@ import com.hmg.hmgDr.ui.VideoCallContract.VideoCallView
import com.hmg.hmgDr.ui.VideoCallPresenterImpl
import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.util.DynamicVideoRenderer
import com.hmg.hmgDr.util.ThumbnailCircleVideoRenderer
import com.opentok.android.*
import com.opentok.android.PublisherKit.PublisherListener
import pub.devrel.easypermissions.AfterPermissionGranted
import pub.devrel.easypermissions.AppSettingsDialog
import pub.devrel.easypermissions.EasyPermissions
import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
import java.text.DecimalFormat
import java.text.NumberFormat
import kotlin.math.ceil
// check this if it works to solve keyboard not work when dialog is opened
// https://stackoverflow.com/questions/55066977/how-to-prevent-custom-dialogfragment-from-hiding-keyboard-when-being-shown
class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.SessionListener, PublisherListener,
SubscriberKit.VideoListener, VideoCallView {
@ -120,6 +123,11 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
val parentLayoutParam: FrameLayout.LayoutParams = /*parentView.layoutParams as*/ FrameLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
parentView.layoutParams = parentLayoutParam
}
override fun getTheme(): Int {
@ -127,9 +135,25 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
}
override fun onCreateDialog(@Nullable savedInstanceState: Bundle?): Dialog {
val dialog: Dialog = super.onCreateDialog(savedInstanceState)
val layoutInflater = activity!!.layoutInflater
this.parentView = onCreateView(layoutInflater, null)
val alertDialogBuilder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
// .setTitle(android.R.string.select_a_color)
.setView(this.parentView)
// .setPositiveButton(android.R.string.ok, { dialogInterface, i -> })
alertDialogBuilder.setOnKeyListener{ _, keyCode, keyEvent ->
// getAction to make sure this doesn't double fire
if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
videoCallResponseListener?.onBackHandle()
false // Capture onKey
} else true
// Don't capture
}
return alertDialogBuilder.create()
/*
// Add back button listener
val dialog: Dialog = super.onCreateDialog(savedInstanceState)
// Add back button listener
dialog.setOnKeyListener { _, keyCode, keyEvent ->
// getAction to make sure this doesn't double fire
@ -141,6 +165,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
}
return dialog
*/
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -168,11 +193,14 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
this.videoCallResponseListener = videoCallResponseListener
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
parentView = inflater.inflate(R.layout.activity_video_call, container, false)
private fun onCreateView(inflater: LayoutInflater, container: ViewGroup?): View {
val view = inflater.inflate(R.layout.activity_video_call, container, false)
// val parentViewLayoutParam: ConstraintLayout.LayoutParams = ConstraintLayout.LayoutParams(
// ConstraintLayout.LayoutParams.MATCH_PARENT,
// ConstraintLayout.LayoutParams.MATCH_PARENT
// )
// parentView.layoutParams = parentViewLayoutParam
// Objects.requireNonNull(requireActivity().actionBar)!!.hide()
arguments?.run {
apiKey = getString("apiKey")
@ -182,15 +210,19 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
baseUrl = getString("baseUrl")
sessionStatusModel = getParcelable("sessionStatusModel")
}
initUI(parentView)
initUI(view)
requestPermissions()
handleDragDialog()
mDetector = GestureDetectorCompat(context, MyGestureListener({ showControlPanelTemporarily() }, { miniCircleDoubleTap() }))
return parentView
return view
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return this.parentView
}
override fun onPause() {
super.onPause()
@ -232,9 +264,11 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
patientName = view.findViewById<TextView>(R.id.patient_name)
patientName.text = sessionStatusModel!!.patientName
cmTimer = view.findViewById<Chronometer>(R.id.cmTimer)
cmTimer = view.findViewById(R.id.cmTimer)
cmTimer.format = "mm:ss"
cmTimer.onChronometerTickListener = Chronometer.OnChronometerTickListener { arg0: Chronometer? ->
// val f: NumberFormat = DecimalFormat("00")
// f.format(minutes)
val minutes: Long
val seconds: Long
if (!resume) {
@ -246,8 +280,10 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
seconds = (elapsedTime - cmTimer.base) / 1000 % 60
elapsedTime += 1000
}
arg0?.text = "$minutes:$seconds"
Log.d(VideoCallFragment.TAG, "onChronometerTick: $minutes : $seconds")
val format = "%1$02d:%2$02d" // two digits
arg0?.text = String.format(format, minutes, seconds)
Log.d(TAG, "onChronometerTick: $minutes : $seconds")
}
icMini.setOnClickListener {
@ -284,7 +320,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
// progressBar=findViewById(R.id.progress_bar);
// progressBarTextView=findViewById(R.id.progress_bar_text);
// progressBar.setVisibility(View.GONE);
hiddenButtons()
// hiddenButtons()
checkClientConnected()
if (appLang == "ar") {
@ -628,6 +664,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
// 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 miniLayoutParam: ConstraintLayout.LayoutParams = layoutMini.layoutParams as ConstraintLayout.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()
@ -889,7 +926,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
private class MyGestureListener(val onTabCall: () -> Unit, val miniCircleDoubleTap: () -> Unit) : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
onTabCall()
// onTabCall()
return true
}

@ -47,38 +47,38 @@
</RelativeLayout>
<RelativeLayout
android:id="@+id/layout_mini"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/remoteBackground"
app:layout_constraintTop_toBottomOf="@+id/layout_name"
android:alpha="0.5"
android:visibility="visible">
<ImageButton
android:id="@+id/ic_mini"
style="@style/Widget.MaterialComponents.Button.Icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_margin="@dimen/padding_space_medium"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@null"
android:src="@drawable/ic_mini" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/activity_clingo_video_call"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_height="100dp"
app:layout_constraintBottom_toTopOf="@id/control_panel"
app:layout_constraintTop_toBottomOf="@+id/layout_name">
<RelativeLayout
android:id="@+id/layout_mini"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/remoteBackground"
android:alpha="0.5"
android:visibility="gone">
<ImageButton
android:id="@+id/ic_mini"
style="@style/Widget.MaterialComponents.Button.Icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_margin="@dimen/padding_space_medium"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@null"
android:src="@drawable/ic_mini" />
</RelativeLayout>
app:layout_constraintTop_toBottomOf="@+id/layout_mini">
<FrameLayout
android:id="@+id/remote_video_view_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/layout_mini"
android:background="@color/remoteBackground">
<ImageView

@ -5,8 +5,8 @@ const ONLY_NUMBERS = "[0-9]";
const ONLY_LETTERS = "[a-zA-Z &'\"]";
const ONLY_DATE = "[0-9/]";
const BASE_URL_LIVE_CARE = 'https://livecare.hmg.com/';
// const BASE_URL = 'https://hmgwebservices.com/';
const BASE_URL = 'https://uat.hmgwebservices.com/';
const BASE_URL = 'https://hmgwebservices.com/';
// const BASE_URL = 'https://uat.hmgwebservices.com/';
const PHARMACY_ITEMS_URL = "Services/Lists.svc/REST/GetPharmcyItems_Region_enh";
const PHARMACY_LIST_URL = "Services/Patients.svc/REST/GetPharmcyList";
const PATIENT_PROGRESS_NOTE_URL = "Services/DoctorApplication.svc/REST/GetProgressNoteForInPatient";

@ -2,18 +2,23 @@ import 'dart:async';
import 'package:doctor_app_flutter/config/size_config.dart';
import 'package:doctor_app_flutter/core/enum/viewstate.dart';
import 'package:doctor_app_flutter/core/service/VideoCallService.dart';
import 'package:doctor_app_flutter/core/viewModel/LiveCarePatientViewModel.dart';
import 'package:doctor_app_flutter/icons_app/doctor_app_icons.dart';
import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/screens/base/base_view.dart';
import 'package:doctor_app_flutter/util/NotificationPermissionUtils.dart';
import 'package:doctor_app_flutter/util/translations_delegate_base.dart';
import 'package:doctor_app_flutter/widgets/patients/patient_card/PatientCard.dart';
import 'package:doctor_app_flutter/widgets/shared/app_loader_widget.dart';
import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart';
import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart';
import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart';
import 'package:doctor_app_flutter/widgets/shared/errors/error_message.dart';
import 'package:doctor_app_flutter/widgets/shared/text_fields/app_text_form_field.dart';
import 'package:flutter/material.dart';
import '../../locator.dart';
import '../../routes.dart';
class LiveCarePatientScreen extends StatefulWidget {
@ -168,9 +173,31 @@ class _LiveCarePatientScreenState extends State<LiveCarePatientScreen> {
child: AppLoaderWidget(
containerColor: Colors.transparent,
)),
AppButton(
fontWeight: FontWeight.w700,
color:Colors.green[600],
title: TranslationBase.of(context).initiateCall,
disabled: model.state == ViewState.BusyLocal,
onPressed: () async {
AppPermissionsUtils.requestVideoCallPermission(context: context,onTapGrant: (){
locator<VideoCallService>().openVideo(model.startCallRes, PatiantInformtion(
vcId: 454353,
fullName: "test mosa"
), callConnected, callDisconnected);
});
},
),
],
),
),
);
}
callConnected(){
}
callDisconnected(){
}
}

Loading…
Cancel
Save