Compare commits

..

3 Commits

Author SHA1 Message Date
Zohaib Iqbal Kambrani 157fc6fc29 Merge branch 'development' into videocall_popup
* development: (72 commits)
  Enable iOS AirPlay
  fix the end call
  fix timer issue
  fix timer issue
  fix disconected stream
  fix circle video stream
  Add App Permissions Utils
  add video call permissions
  fix drop video call issue
  circle screen fix bug, and mini screen design
  video fix bugs
  fix header from lab
  fix header from lab result details
  fix header
  fix the video call issues
  Add video call service
  video fix bugs
  video fix bugs
  add loader
  video fix bugs
  ...
5 years ago
Zohaib Iqbal Kambrani 6853173d93 Enable iOS AirPlay 5 years ago
Zohaib Iqbal Kambrani 9c3bfb7aa6 no message 5 years ago

@ -28,15 +28,6 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android { android {
compileSdkVersion 30 compileSdkVersion 30
signingConfigs {
release {
storeFile file('/Users/nextwo/Desktop/Elham/keys/doctor app key')
storePassword 'Hmgdoctor1234'
keyAlias 'hmgdoctor'
keyPassword 'Hmgdoctor1234'
}
}
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
} }
@ -59,26 +50,10 @@ android {
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. // TODO: Add your own signing config for the release build.
signingConfig signingConfigs.release
}
debug {
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
} }
} }
// flavorDimensions 'environment'
// productFlavors {
// production {
// dimension 'environment'
// }
// }
//
// configurations {
// productionDebugImplementation
// productionReleaseImplementation
// }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
@ -109,8 +84,6 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
implementation 'com.google.firebase:firebase-analytics:17.4.1'
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'

@ -1,77 +1,34 @@
{ {
"project_info": { "project_info": {
"project_number": "934365232760", "project_number": "157373154094",
"project_id": "hmg-dr-app", "project_id": "hmg-doctor-app-1553688619744",
"storage_bucket": "hmg-dr-app.appspot.com" "storage_bucket": "hmg-doctor-app-1553688619744.appspot.com"
}, },
"client": [ "client": [
{ {
"client_info": { "client_info": {
"mobilesdk_app_id": "1:934365232760:android:024b3569972f1c09f9778d", "mobilesdk_app_id": "1:157373154094:android:daeea3a4e1f4462a1bf0bf",
"android_client_info": {
"package_name": "COM.HMG.HMGDR"
}
},
"oauth_client": [
{
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCpYwrmuntOBdZv6GV6KEnLj8nQRvEnZ6I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "934365232760-57v2ld1qqulc4nt4o5pgjfbpc47fj3qf.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "COM.HMG.HMGDR"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:934365232760:android:e0e185e68c0d7690f9778d",
"android_client_info": { "android_client_info": {
"package_name": "com.hmg.hmgDr" "package_name": "com.hmg.hmgDr"
} }
}, },
"oauth_client": [ "oauth_client": [
{ {
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com", "client_id": "157373154094-egrhbfr861l7k722g3v2gd4a0opi3r1u.apps.googleusercontent.com",
"client_type": 3 "client_type": 3
} }
], ],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyCpYwrmuntOBdZv6GV6KEnLj8nQRvEnZ6I" "current_key": "AIzaSyDX8RPwu00MyrpqC-T2zXtrUQvTQGRv1mM"
} }
], ],
"services": { "services": {
"appinvite_service": { "appinvite_service": {
"other_platform_oauth_client": [ "other_platform_oauth_client": [
{ {
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com", "client_id": "157373154094-egrhbfr861l7k722g3v2gd4a0opi3r1u.apps.googleusercontent.com",
"client_type": 3 "client_type": 3
},
{
"client_id": "934365232760-57v2ld1qqulc4nt4o5pgjfbpc47fj3qf.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "COM.HMG.HMGDR"
}
} }
] ]
} }

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hmg.hmgDr">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

@ -10,30 +10,22 @@
FlutterApplication and put your custom class here. FlutterApplication and put your custom class here.
--> -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.CALL_PHONE" />
<!-- Permission required to draw floating widget over other apps -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" /> <uses-feature android:name="android.hardware.camera.autofocus" />
<application <application
android:name=".AppApplication" android:name="io.flutter.app.FlutterApplication"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
tools:replace="android:name"
android:label="HMG Doctor"> android:label="HMG Doctor">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
@ -48,11 +40,6 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<service android:name = ".Service.VideoStreamFloatingWidgetService"
android:enabled="true"
android:exported="false"/>
<!-- <!--
Don't delete the meta-data below. Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java This is used by the Flutter tool to generate GeneratedPluginRegistrant.java
@ -60,22 +47,6 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<activity
android:name="com.hmg.hmgDr.globalErrorHandler.UCEDefaultActivity"
android:process=":error_activity" />
<provider
android:name="com.hmg.hmgDr.globalErrorHandler.UCEFileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application> </application>
</manifest> </manifest>

@ -1,12 +0,0 @@
package com.hmg.hmgDr
import com.hmg.hmgDr.globalErrorHandler.LoggingExceptionHandler
import io.flutter.app.FlutterApplication
class AppApplication : FlutterApplication() {
override fun onCreate() {
super.onCreate()
// LoggingExceptionHandler(this, "ErrorFile")
}
}

@ -1,40 +1,24 @@
package com.hmg.hmgDr package com.hmg.hmgDr
import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.IBinder
import android.provider.Settings
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.annotation.NonNull import androidx.annotation.NonNull
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.hmg.hmgDr.Service.VideoStreamFloatingWidgetService import com.hmg.hmgDr.Model.GetSessionStatusModel
import com.hmg.hmgDr.model.GetSessionStatusModel import com.hmg.hmgDr.Model.SessionStatusModel
import com.hmg.hmgDr.model.SessionStatusModel
import com.hmg.hmgDr.ui.VideoCallResponseListener import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.ui.fragment.VideoCallFragment
import io.flutter.embedding.android.FlutterFragmentActivity import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant import io.flutter.plugins.GeneratedPluginRegistrant
import pub.devrel.easypermissions.AfterPermissionGranted
import pub.devrel.easypermissions.AppSettingsDialog
import pub.devrel.easypermissions.EasyPermissions
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler, class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler, VideoCallResponseListener {
VideoCallResponseListener {
/* Permission request code to draw over other apps */
private val DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE = 1222
private val CHANNEL = "Dr.cloudSolution/videoCall" private val CHANNEL = "Dr.cloudSolution/videoCall"
private lateinit var methodChannel: MethodChannel private lateinit var methodChannel: MethodChannel
@ -42,13 +26,7 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
private var call: MethodCall? = null private var call: MethodCall? = null
private val LAUNCH_VIDEO: Int = 1 private val LAUNCH_VIDEO: Int = 1
private var serviceIntent: Intent? = null private var dialogFragment: VideoCallFragment? = null
private var videoStreamService: VideoStreamFloatingWidgetService? = null
private var bound = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine) GeneratedPluginRegistrant.registerWith(flutterEngine)
@ -76,24 +54,18 @@ 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 = val sessionStatusModel = GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId, patientName)
GetSessionStatusModel(
VC_ID,
tokenID,
generalId,
doctorId,
patientName,
isRecording!!
)
openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel) openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel)
} }
"closeVideoCall" -> { "closeVideoCall" -> {
videoStreamService?.closeVideoCall() dialogFragment?.onCallClicked()
}
"onCallConnected" -> {
} }
else -> { else -> {
result.notImplemented() result.notImplemented()
@ -101,15 +73,8 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
} }
} }
private fun openVideoCall( private fun openVideoCall(apiKey: String?, sessionId: String?, token: String?, appLang: String?, baseUrl: String?, sessionStatusModel: GetSessionStatusModel) {
apiKey: String?, if (dialogFragment == null) {
sessionId: String?,
token: String?,
appLang: String?,
baseUrl: String?,
sessionStatusModel: GetSessionStatusModel
) {
val arguments = Bundle() val arguments = Bundle()
arguments.putString("apiKey", apiKey) arguments.putString("apiKey", apiKey)
arguments.putString("sessionId", sessionId) arguments.putString("sessionId", sessionId)
@ -118,70 +83,55 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
arguments.putString("baseUrl", baseUrl) arguments.putString("baseUrl", baseUrl)
arguments.putParcelable("sessionStatusModel", sessionStatusModel) arguments.putParcelable("sessionStatusModel", sessionStatusModel)
// start service val transaction = supportFragmentManager.beginTransaction()
// serviceIntent = Intent(this@MainActivity, VideoStreamContainerService::class.java) dialogFragment = VideoCallFragment.newInstance(arguments)
if (videoStreamService == null || videoStreamService?.serviceRunning == false) { dialogFragment?.let {
serviceIntent = Intent(this@MainActivity, VideoStreamFloatingWidgetService::class.java) it.setCallListener(this)
serviceIntent?.run { it.isCancelable = true
putExtras(arguments) if (it.isAdded){
action = VideoStreamFloatingWidgetService.ACTION_START_CALL it.dismiss()
} }else {
checkFloatingWidgetPermission() it.show(transaction, "dialog")
}
} }
private fun checkFloatingWidgetPermission() {
// Check if the application has draw over other apps permission or not?
// This permission is by default available for API<23. But for API > 23
// you have to ask for the permission in runtime.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
//If the draw over permission is not available open the settings screen
//to grant the permission.
val intent = Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:$packageName")
)
startActivityForResult(intent, DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE)
} else { //If permission is granted start floating widget service
startFloatingWidgetService()
}
}
private fun startFloatingWidgetService() {
startService(serviceIntent)
bindService()
} }
} else if (!dialogFragment!!.isVisible) {
override fun onDestroy() { val transaction = supportFragmentManager.beginTransaction()
super.onDestroy() dialogFragment!!.show(transaction, "dialog")
if (bound) {
unbindService()
} }
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE) { /* override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
//Check if the permission is granted or not.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.canDrawOverlays(this)) {
startFloatingWidgetService()
} else {
//Permission is not available then display toast
Toast.makeText(
this,
"Draw over other app permission not available. App won\\'t work without permission. Please try again.",
Toast.LENGTH_SHORT
).show()
}
} else {
startFloatingWidgetService()
}
} else {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
var asd = "";
if (requestCode == LAUNCH_VIDEO) {
if (resultCode == Activity.RESULT_OK) {
val result : SessionStatusModel? = data?.getParcelableExtra("sessionStatusNotRespond")
val callResponse : HashMap<String, String> = HashMap()
val sessionStatus : HashMap<String, String> = HashMap()
val gson = GsonBuilder().serializeNulls().create()
callResponse["callResponse"] = "CallNotRespond"
val jsonRes = gson.toJson(result)
callResponse["sessionStatus"] = jsonRes
this.result?.success(callResponse)
}
if (resultCode == Activity.RESULT_CANCELED) {
val callResponse : HashMap<String, String> = HashMap()
callResponse["callResponse"] = "CallEnd"
result?.success(callResponse)
} }
} }
}*/
override fun onCallFinished(resultCode: Int, intent: Intent?) { override fun onCallFinished(resultCode: Int, intent: Intent?) {
dialogFragment = null
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
val result: SessionStatusModel? = intent?.getParcelableExtra("sessionStatusNotRespond") val result: SessionStatusModel? = intent?.getParcelableExtra("sessionStatusNotRespond")
val callResponse: HashMap<String, String> = HashMap() val callResponse: HashMap<String, String> = HashMap()
@ -207,78 +157,22 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
Log.e("onVideoCallFinished", "${e.message}.") Log.e("onVideoCallFinished", "${e.message}.")
} }
} }
}
stopService(serviceIntent) override fun errorHandle(message: String) {
dialogFragment = null
// Toast.makeText(this, message, Toast.LENGTH_LONG).show()
} }
override fun minimizeVideoEvent(isMinimize: Boolean) { override fun minimizeVideoEvent(isMinimize: Boolean) {
if (isMinimize) if (isMinimize)
methodChannel.invokeMethod("onCallConnected", null) methodChannel.invokeMethod("onCallConnected", null)
else { else
methodChannel.invokeMethod("onCallDisconnected", null) methodChannel.invokeMethod("onCallDisconnected", null)
unbindService()
videoStreamService?.serviceRunning = false
videoStreamService = null
}
} }
override fun onBackPressed() { override fun onBackPressed() {
if (videoStreamService != null && videoStreamService?.serviceRunning == true && videoStreamService?.isFullScreen!!) {
videoStreamService!!.onMinimizedClicked()
} else {
super.onBackPressed() super.onBackPressed()
} }
}
override fun onPause() {
if (videoStreamService != null && videoStreamService?.serviceRunning == true && videoStreamService?.isFullScreen!!) {
videoStreamService!!.onMinimizedClicked()
}
super.onPause()
}
// override fun onStart() {
// super.onStart()
// bindService()
// }
//
// override fun onStop() {
// super.onStop()
// unbindService()
// }
private fun bindService() {
serviceIntent?.run {
if (videoStreamService != null && !videoStreamService!!.serviceRunning) {
startService(this)
}
bindService(this, serviceConnection, Context.BIND_AUTO_CREATE)
}
}
private fun unbindService() {
if (bound) {
videoStreamService?.videoCallResponseListener = null // unregister
unbindService(serviceConnection)
bound = false
}
}
private val serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
// val binder: VideoStreamContainerService.VideoStreamBinder =
// service as VideoStreamContainerService.VideoStreamBinder
val binder: VideoStreamFloatingWidgetService.VideoStreamBinder =
service as VideoStreamFloatingWidgetService.VideoStreamBinder
videoStreamService = binder.service
bound = true
videoStreamService!!.videoCallResponseListener = this@MainActivity // register
videoStreamService?.serviceRunning = true
}
override fun onServiceDisconnected(name: ComponentName?) {
bound = false
}
}
} }

@ -1,4 +1,4 @@
package com.hmg.hmgDr.model; package com.hmg.hmgDr.Model;
import android.os.Parcel; import android.os.Parcel;

@ -1,4 +1,4 @@
package com.hmg.hmgDr.model; package com.hmg.hmgDr.Model;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
@ -23,20 +23,16 @@ 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, boolean isRecording) { public GetSessionStatusModel(Integer vCID, String tokenID, String generalid, Integer doctorId, String patientName) {
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) {
@ -53,7 +49,6 @@ 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>() {
@ -110,14 +105,6 @@ 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;
@ -140,6 +127,5 @@ public class GetSessionStatusModel implements Parcelable {
dest.writeInt(doctorId); dest.writeInt(doctorId);
} }
dest.writeString(patientName); dest.writeString(patientName);
dest.writeInt(isRecording ? 1 : 0);
} }
} }

@ -1,4 +1,4 @@
package com.hmg.hmgDr.model; package com.hmg.hmgDr.Model;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;

@ -1,234 +0,0 @@
package com.hmg.hmgDr.Service
import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.Point
import android.os.Build
import android.os.CountDownTimer
import android.util.Log
import android.view.*
import androidx.core.view.GestureDetectorCompat
import com.hmg.hmgDr.R
import com.hmg.hmgDr.util.ViewsUtil
abstract class BaseMovingFloatingWidget : Service() {
val szWindow = Point()
lateinit var windowManagerParams: WindowManager.LayoutParams
var mWindowManager: WindowManager? = null
var floatingWidgetView: View? = null
lateinit var floatingViewContainer: View
lateinit var mDetector: GestureDetectorCompat
private var xInitCord = 0
private var yInitCord: Int = 0
private var xInitMargin: Int = 0
private var yInitMargin: Int = 0
/* Add Floating Widget View to Window Manager */
open fun addFloatingWidgetView() {
mWindowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
//Init LayoutInflater
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
//Inflate the removing view layout we created
floatingWidgetView = inflater.inflate(R.layout.activity_video_call, null)
//Add the view to the window.
windowManagerParams =
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
} else {
WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
}
//Specify the view position
windowManagerParams.gravity = Gravity.TOP or Gravity.START
}
@SuppressLint("ClickableViewAccessibility")
val dragListener: View.OnTouchListener = View.OnTouchListener { _, event ->
mDetector.onTouchEvent(event)
//Get Floating widget view params
val layoutParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
//get the touch location coordinates
val x_cord = event.rawX.toInt()
val y_cord = event.rawY.toInt()
val x_cord_Destination: Int
var y_cord_Destination: Int
when (event.action) {
MotionEvent.ACTION_DOWN -> {
xInitCord = x_cord
yInitCord = y_cord
//remember the initial position.
xInitMargin = layoutParams.x
yInitMargin = layoutParams.y
}
MotionEvent.ACTION_UP -> {
//Get the difference between initial coordinate and current coordinate
val x_diff: Int = x_cord - xInitCord
val y_diff: Int = y_cord - yInitCord
y_cord_Destination = yInitMargin + y_diff
val barHeight: Int = ViewsUtil.getStatusBarHeight(applicationContext)
if (y_cord_Destination < 0) {
y_cord_Destination = 0
// y_cord_Destination =
// -(szWindow.y - (videoCallContainer.height /*+ barHeight*/))
// y_cord_Destination = -(szWindow.y / 2)
} else if (y_cord_Destination + (floatingViewContainer.height + barHeight) > szWindow.y) {
y_cord_Destination = szWindow.y - (floatingViewContainer.height + barHeight)
// y_cord_Destination = (szWindow.y / 2)
}
layoutParams.y = y_cord_Destination
//reset position if user drags the floating view
resetPosition(x_cord)
}
MotionEvent.ACTION_MOVE -> {
val x_diff_move: Int = x_cord - xInitCord
val y_diff_move: Int = y_cord - yInitCord
x_cord_Destination = xInitMargin + x_diff_move
y_cord_Destination = yInitMargin + y_diff_move
layoutParams.x = x_cord_Destination
layoutParams.y = y_cord_Destination
//Update the layout with new X & Y coordinate
mWindowManager?.updateViewLayout(floatingWidgetView, layoutParams)
}
}
true
}
/**
* OnTouch actions
*/
class MyGestureListener(
val onTabCall: () -> Unit,
val miniCircleDoubleTap: () -> Unit
) : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
// onTabCall()
return true
}
override fun onDoubleTap(e: MotionEvent?): Boolean {
miniCircleDoubleTap()
return super.onDoubleTap(e)
}
}
/* Reset position of Floating Widget view on dragging */
fun resetPosition(x_cord_now: Int) {
if (x_cord_now <= szWindow.x / 2) {
moveToLeft(x_cord_now)
} else {
moveToRight(x_cord_now)
}
}
/* Method to move the Floating widget view to Left */
private fun moveToLeft(current_x_cord: Int) {
val mParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
mParams.x =
(szWindow.x - current_x_cord * current_x_cord - floatingViewContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
val x = szWindow.x - current_x_cord
object : CountDownTimer(500, 5) {
//get params of Floating Widget view
val mParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
override fun onTick(t: Long) {
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 - floatingViewContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
override fun onFinish() {
mParams.x = -(szWindow.x - floatingViewContainer.width)
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
}.start()
}
/* Method to move the Floating widget view to Right */
private fun moveToRight(current_x_cord: Int) {
object : CountDownTimer(500, 5) {
//get params of Floating Widget view
val mParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
override fun onTick(t: Long) {
val step = (500 - t) / 5
mParams.x =
(szWindow.x + current_x_cord * current_x_cord * step - floatingViewContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
override fun onFinish() {
mParams.x = szWindow.x - floatingViewContainer.width
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
}
}.start()
}
/***
* Utils
*/
fun getWindowManagerDefaultDisplay() {
val w = mWindowManager!!.defaultDisplay.width
val h = mWindowManager!!.defaultDisplay.height
szWindow[w] = h
}
}

@ -1,8 +1,8 @@
package com.hmg.hmgDr.Service; package com.hmg.hmgDr.Service;
import com.hmg.hmgDr.model.ChangeCallStatusRequestModel; import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel;
import com.hmg.hmgDr.model.GetSessionStatusModel; import com.hmg.hmgDr.Model.GetSessionStatusModel;
import com.hmg.hmgDr.model.SessionStatusModel; import com.hmg.hmgDr.Model.SessionStatusModel;
import retrofit2.Call; import retrofit2.Call;

@ -1,91 +0,0 @@
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 com.hmg.hmgDr.MainActivity
import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.ui.fragment.VideoCallFragment
class VideoStreamContainerService : Service(), VideoCallResponseListener {
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 serviceBinder
}
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()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
// 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)
}
}

@ -1,39 +0,0 @@
package com.hmg.hmgDr.globalErrorHandler
import android.os.Environment
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
object FileUtil {
val sdf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS")
fun pushLog(body: String?) {
try {
val date = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
val time = SimpleDateFormat("HH:MM:SS", Locale.getDefault()).format(Date())
val root =
File(Environment.getExternalStorageDirectory(),"error_log_dir")
// if external memory exists and folder with name Notes
if (!root.exists()) {
root.mkdirs() // this will create folder.
}
val oldFile = File(root, "error" + sdf.format(Date()).toString() + ".txt") // old file
if (oldFile.exists()) oldFile.delete()
val filepath = File(root, "error$date.txt") // file path to save
val bufferedWriter = BufferedWriter(FileWriter(filepath, true))
bufferedWriter.append("\r\n")
bufferedWriter.append("\r\n").append(body).append(" Time : ").append(time)
bufferedWriter.flush()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}
}

@ -1,39 +0,0 @@
package com.hmg.hmgDr.globalErrorHandler
import android.content.Context
import android.content.Intent
import com.hmg.hmgDr.MainActivity
import com.hmg.hmgDr.globalErrorHandler.FileUtil.pushLog
class LoggingExceptionHandler(private val context: Context, ErrorFile: String) :
Thread.UncaughtExceptionHandler {
private val rootHandler: Thread.UncaughtExceptionHandler
override fun uncaughtException(t: Thread, e: Throwable) {
object : Thread() {
override fun run() {
pushLog("UnCaught Exception is thrown in $error$e")
try {
sleep(500)
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
context.startActivity(intent)
} catch (e1: Exception) {
e1.printStackTrace()
}
}
}.start()
rootHandler.uncaughtException(t, e)
}
companion object {
private val TAG = LoggingExceptionHandler::class.java.simpleName
lateinit var error: String
}
init {
error = "$ErrorFile.error "
rootHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler(this)
}
}

@ -1,6 +0,0 @@
package com.hmg.hmgDr.globalErrorHandler
import androidx.appcompat.app.AppCompatActivity
class UCEDefaultActivity : AppCompatActivity() {
}

@ -1,6 +0,0 @@
package com.hmg.hmgDr.globalErrorHandler
import androidx.core.content.FileProvider
class UCEFileProvider : FileProvider() {
}

@ -1,280 +0,0 @@
package com.hmg.hmgDr.globalErrorHandler
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
import java.util.Date;
import java.util.Deque;
import java.util.Locale;
import kotlin.system.exitProcess
class UCEHandler(val builder: Builder) {
val EXTRA_STACK_TRACE = "EXTRA_STACK_TRACE"
val EXTRA_ACTIVITY_LOG = "EXTRA_ACTIVITY_LOG"
private val TAG = "UCEHandler"
private val UCE_HANDLER_PACKAGE_NAME = "com.rohitss.uceh"
private val DEFAULT_HANDLER_PACKAGE_NAME = "com.android.internal.os"
private val MAX_STACK_TRACE_SIZE = 131071 //128 KB - 1
private val MAX_ACTIVITIES_IN_LOG = 50
private val SHARED_PREFERENCES_FILE = "uceh_preferences"
private val SHARED_PREFERENCES_FIELD_TIMESTAMP = "last_crash_timestamp"
private val activityLog: Deque<String> = ArrayDeque(MAX_ACTIVITIES_IN_LOG)
var COMMA_SEPARATED_EMAIL_ADDRESSES: String? = null
@SuppressLint("StaticFieldLeak")
private var application: Application? = null
private var isInBackground = true
private var isBackgroundMode = false
private var isUCEHEnabled = false
private var isTrackActivitiesEnabled = false
private var lastActivityCreated: WeakReference<Activity?> = WeakReference(null)
fun UCEHandler(builder: Builder) {
isUCEHEnabled = builder.isUCEHEnabled
isTrackActivitiesEnabled = builder.isTrackActivitiesEnabled
isBackgroundMode = builder.isBackgroundModeEnabled
COMMA_SEPARATED_EMAIL_ADDRESSES = builder.commaSeparatedEmailAddresses
setUCEHandler(builder.context)
}
private fun setUCEHandler(context: Context?) {
try {
if (context != null) {
val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
if (oldHandler != null && oldHandler.javaClass.name.startsWith(
UCE_HANDLER_PACKAGE_NAME
)
) {
Log.e(TAG, "UCEHandler was already installed, doing nothing!")
} else {
if (oldHandler != null && !oldHandler.javaClass.name.startsWith(
DEFAULT_HANDLER_PACKAGE_NAME
)
) {
Log.e(
TAG,
"You already have an UncaughtExceptionHandler. If you use a custom UncaughtExceptionHandler, it should be initialized after UCEHandler! Installing anyway, but your original handler will not be called."
)
}
application = context.getApplicationContext() as Application
//Setup UCE Handler.
Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler { thread, throwable ->
if (isUCEHEnabled) {
Log.e(
TAG,
"App crashed, executing UCEHandler's UncaughtExceptionHandler",
throwable
)
if (hasCrashedInTheLastSeconds(application!!)) {
Log.e(
TAG,
"App already crashed recently, not starting custom error activity because we could enter a restart loop. Are you sure that your app does not crash directly on init?",
throwable
)
if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable)
return@UncaughtExceptionHandler
}
} else {
setLastCrashTimestamp(application!!, Date().getTime())
if (!isInBackground || isBackgroundMode) {
val intent = Intent(application, UCEDefaultActivity::class.java)
val sw = StringWriter()
val pw = PrintWriter(sw)
throwable.printStackTrace(pw)
var stackTraceString: String = sw.toString()
if (stackTraceString.length > MAX_STACK_TRACE_SIZE) {
val disclaimer = " [stack trace too large]"
stackTraceString = stackTraceString.substring(
0,
MAX_STACK_TRACE_SIZE - disclaimer.length
) + disclaimer
}
intent.putExtra(EXTRA_STACK_TRACE, stackTraceString)
if (isTrackActivitiesEnabled) {
val activityLogStringBuilder = StringBuilder()
while (!activityLog.isEmpty()) {
activityLogStringBuilder.append(activityLog.poll())
}
intent.putExtra(
EXTRA_ACTIVITY_LOG,
activityLogStringBuilder.toString()
)
}
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
application!!.startActivity(intent)
} else {
if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable)
return@UncaughtExceptionHandler
}
//If it is null (should not be), we let it continue and kill the process or it will be stuck
}
}
val lastActivity: Activity? = lastActivityCreated.get()
if (lastActivity != null) {
lastActivity.finish()
lastActivityCreated.clear()
}
killCurrentProcess()
} else oldHandler?.uncaughtException(thread, throwable)
})
application!!.registerActivityLifecycleCallbacks(object :
Application.ActivityLifecycleCallbacks {
val dateFormat: DateFormat =
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US)
var currentlyStartedActivities = 0
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
if (activity.javaClass !== UCEDefaultActivity::class.java) {
lastActivityCreated = WeakReference(activity)
}
if (isTrackActivitiesEnabled) {
activityLog.add(
dateFormat.format(Date())
.toString() + ": " + activity.javaClass
.getSimpleName() + " created\n"
)
}
}
override fun onActivityStarted(activity: Activity) {
currentlyStartedActivities++
isInBackground = currentlyStartedActivities == 0
}
override fun onActivityResumed(activity: Activity) {
if (isTrackActivitiesEnabled) {
activityLog.add(
dateFormat.format(Date())
.toString() + ": " + activity.javaClass
.simpleName + " resumed\n"
)
}
}
override fun onActivityPaused(activity: Activity) {
if (isTrackActivitiesEnabled) {
activityLog.add(
dateFormat.format(Date())
.toString() + ": " + activity.javaClass
.simpleName + " paused\n"
)
}
}
override fun onActivityStopped(activity: Activity) {
currentlyStartedActivities--
isInBackground = currentlyStartedActivities == 0
}
override fun onActivitySaveInstanceState(
activity: Activity,
outState: Bundle
) {}
override fun onActivityDestroyed(activity: Activity) {
if (isTrackActivitiesEnabled) {
activityLog.add(
dateFormat.format(Date())
.toString() + ": " + activity.javaClass
.simpleName + " destroyed\n"
)
}
}
})
}
Log.i(TAG, "UCEHandler has been installed.")
} else {
Log.e(TAG, "Context can not be null")
}
} catch (throwable: Throwable) {
Log.e(
TAG,
"UCEHandler can not be initialized. Help making it better by reporting this as a bug.",
throwable
)
}
}
/**
* INTERNAL method that tells if the app has crashed in the last seconds.
* This is used to avoid restart loops.
*
* @return true if the app has crashed in the last seconds, false otherwise.
*/
private fun hasCrashedInTheLastSeconds(context: Context): Boolean {
val lastTimestamp = getLastCrashTimestamp(context)
val currentTimestamp: Long = Date().getTime()
return lastTimestamp <= currentTimestamp && currentTimestamp - lastTimestamp < 3000
}
@SuppressLint("ApplySharedPref")
private fun setLastCrashTimestamp(context: Context, timestamp: Long) {
context.getSharedPreferences(SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE).edit()
.putLong(SHARED_PREFERENCES_FIELD_TIMESTAMP, timestamp).commit()
}
private fun killCurrentProcess() {
// Process.killProcess(Process.myPid())
exitProcess(10)
}
private fun getLastCrashTimestamp(context: Context): Long {
return context.getSharedPreferences(SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE)
.getLong(SHARED_PREFERENCES_FIELD_TIMESTAMP, -1)
}
fun closeApplication(activity: Activity) {
activity.finish()
killCurrentProcess()
}
inner class Builder(context: Context) {
val context: Context
var isUCEHEnabled = true
var commaSeparatedEmailAddresses: String? = null
var isTrackActivitiesEnabled = false
var isBackgroundModeEnabled = true
fun setUCEHEnabled(isUCEHEnabled: Boolean): Builder {
this.isUCEHEnabled = isUCEHEnabled
return this
}
fun setTrackActivitiesEnabled(isTrackActivitiesEnabled: Boolean): Builder {
this.isTrackActivitiesEnabled = isTrackActivitiesEnabled
return this
}
fun setBackgroundModeEnabled(isBackgroundModeEnabled: Boolean): Builder {
this.isBackgroundModeEnabled = isBackgroundModeEnabled
return this
}
fun addCommaSeparatedEmailAddresses(commaSeparatedEmailAddresses: String?): Builder {
this.commaSeparatedEmailAddresses = commaSeparatedEmailAddresses ?: ""
return this
}
fun build() {
return UCEHandler(this)
}
init {
this.context = context
}
}
}

@ -1,16 +0,0 @@
package com.hmg.hmgDr.model
/** Represents standard data needed for a Notification. */
open class NotificationDataModel(
// Standard notification values:
var mContentTitle: String,
var mContentText: String,
var mPriority: Int ,
// Notification channel values (O and above):
var mChannelId: String,
var mChannelName: CharSequence,
var mChannelDescription: String,
var mChannelImportance: Int ,
var mChannelEnableVibrate: Boolean ,
var mChannelLockscreenVisibility: Int
)

@ -1,35 +0,0 @@
package com.hmg.hmgDr.model
import android.app.Notification
import android.app.NotificationManager
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
class NotificationVideoModel constructor(
mContentTitle: String,
mContentText: String,
mChannelId: String,
mChannelName: CharSequence,
mChannelDescription: String,
mPriority: Int = Notification.PRIORITY_MAX,
mChannelImportance: Int = NotificationManager.IMPORTANCE_LOW,
mChannelEnableVibrate: Boolean = true,
mChannelLockscreenVisibility: Int = NotificationCompat.VISIBILITY_PUBLIC,
// Unique data for this Notification.Style:
var mBigContentTitle: String = mContentTitle,
val mBigText: String = mContentText,
var mSummaryText: String
) : NotificationDataModel(
mContentTitle,
mContentText,
mPriority,
mChannelId,
mChannelName,
mChannelDescription,
mChannelImportance,
mChannelEnableVibrate,
mChannelLockscreenVisibility
) {
}

@ -1,8 +1,8 @@
package com.hmg.hmgDr.ui; package com.hmg.hmgDr.ui;
import com.hmg.hmgDr.model.ChangeCallStatusRequestModel; import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel;
import com.hmg.hmgDr.model.GetSessionStatusModel; import com.hmg.hmgDr.Model.GetSessionStatusModel;
import com.hmg.hmgDr.model.SessionStatusModel; import com.hmg.hmgDr.Model.SessionStatusModel;
public interface VideoCallContract { public interface VideoCallContract {
@ -13,7 +13,6 @@ public interface VideoCallContract {
void onCallChangeCallStatusSuccessful(SessionStatusModel sessionStatusModel); void onCallChangeCallStatusSuccessful(SessionStatusModel sessionStatusModel);
void onFailure(); void onFailure();
} }
interface VideoCallPresenter { interface VideoCallPresenter {

@ -1,8 +1,8 @@
package com.hmg.hmgDr.ui; package com.hmg.hmgDr.ui;
import com.hmg.hmgDr.model.ChangeCallStatusRequestModel; import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel;
import com.hmg.hmgDr.model.GetSessionStatusModel; import com.hmg.hmgDr.Model.GetSessionStatusModel;
import com.hmg.hmgDr.model.SessionStatusModel; import com.hmg.hmgDr.Model.SessionStatusModel;
import com.hmg.hmgDr.Service.AppRetrofit; import com.hmg.hmgDr.Service.AppRetrofit;
import com.hmg.hmgDr.Service.SessionStatusAPI; import com.hmg.hmgDr.Service.SessionStatusAPI;
@ -59,6 +59,7 @@ public class VideoCallPresenterImpl implements VideoCallContract.VideoCallPresen
public void onResponse(@NotNull Call<SessionStatusModel> call, @NotNull Response<SessionStatusModel> response) { public void onResponse(@NotNull Call<SessionStatusModel> call, @NotNull Response<SessionStatusModel> response) {
if (!response.isSuccessful()) if (!response.isSuccessful())
view.onFailure(); view.onFailure();
} }
@Override @Override

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

@ -15,21 +15,20 @@ import android.util.Log
import android.view.* import android.view.*
import android.widget.* import android.widget.*
import androidx.annotation.Nullable import androidx.annotation.Nullable
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat import androidx.core.view.GestureDetectorCompat
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.hmg.hmgDr.model.ChangeCallStatusRequestModel import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel
import com.hmg.hmgDr.model.GetSessionStatusModel import com.hmg.hmgDr.Model.GetSessionStatusModel
import com.hmg.hmgDr.model.SessionStatusModel import com.hmg.hmgDr.Model.SessionStatusModel
import com.hmg.hmgDr.R import com.hmg.hmgDr.R
import com.hmg.hmgDr.ui.VideoCallContract.VideoCallPresenter import com.hmg.hmgDr.ui.VideoCallContract.VideoCallPresenter
import com.hmg.hmgDr.ui.VideoCallContract.VideoCallView import com.hmg.hmgDr.ui.VideoCallContract.VideoCallView
import com.hmg.hmgDr.ui.VideoCallPresenterImpl import com.hmg.hmgDr.ui.VideoCallPresenterImpl
import com.hmg.hmgDr.ui.VideoCallResponseListener import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.util.opentok.DynamicVideoRenderer import com.hmg.hmgDr.util.DynamicVideoRenderer
import com.hmg.hmgDr.util.ViewsUtil import com.hmg.hmgDr.util.ThumbnailCircleVideoRenderer
import com.opentok.android.* import com.opentok.android.*
import com.opentok.android.PublisherKit.PublisherListener import com.opentok.android.PublisherKit.PublisherListener
import pub.devrel.easypermissions.AfterPermissionGranted import pub.devrel.easypermissions.AfterPermissionGranted
@ -38,10 +37,8 @@ import pub.devrel.easypermissions.EasyPermissions
import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
import kotlin.math.ceil 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,
class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.SessionListener,
PublisherListener,
SubscriberKit.VideoListener, VideoCallView { SubscriberKit.VideoListener, VideoCallView {
private var isFullScreen: Boolean = true private var isFullScreen: Boolean = true
@ -65,9 +62,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 activity_clingo_video_call: RelativeLayout
private lateinit var mPublisherViewContainer: FrameLayout private lateinit var mPublisherViewContainer: FrameLayout
private lateinit var mPublisherViewIcon: View private lateinit var mPublisherViewIcon: View
private lateinit var mSubscriberViewContainer: FrameLayout private lateinit var mSubscriberViewContainer: FrameLayout
@ -79,7 +74,6 @@ 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
@ -97,17 +91,16 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
private lateinit var mSwitchCameraBtn: ImageView private lateinit var mSwitchCameraBtn: ImageView
private lateinit var mspeckerBtn: ImageView private lateinit var mspeckerBtn: ImageView
private lateinit var mMicBtn: ImageView private lateinit var mMicBtn: ImageView
private lateinit var patientName: TextView private lateinit var patientName: TextView
private lateinit var cmTimer: Chronometer private lateinit var cmTimer: Chronometer
private var elapsedTime: Long = 0 private var elapsedTime: Long = 0
private var resume = false private var resume = false
private val progressBar: ProgressBar? = null private val progressBar: ProgressBar? = null
private val countDownTimer: CountDownTimer? = null private val countDownTimer: CountDownTimer? = null
private val progressBarTextView: TextView? = null private val progressBarTextView: TextView? = null
private val private val progressBarLayout: RelativeLayout? = null
progressBarLayout: RelativeLayout? = null
private var isConnected = false private var isConnected = false
@ -123,47 +116,20 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
// val params: ViewGroup.LayoutParams = dialog!!.window!!.attributes
// params.width = WindowManager.LayoutParams.MATCH_PARENT
// params.height = WindowManager.LayoutParams.MATCH_PARENT
// dialog!!.window!!.attributes = params as WindowManager.LayoutParams
dialog?.window?.setLayout( dialog?.window?.setLayout(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT,
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 { override fun getTheme(): Int {
return R.style.dialogTheme return R.style.dialogTheme
} }
override fun onCreateDialog(@Nullable savedInstanceState: Bundle?): Dialog {// FullScreenVideoTheme override fun onCreateDialog(@Nullable savedInstanceState: Bundle?): Dialog {
val layoutInflater = activity!!.layoutInflater
this.parentView = onCreateView(layoutInflater, null)
val alertDialogBuilder: AlertDialog.Builder =
AlertDialog.Builder(requireContext(), R.style.dialogTheme)
// .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()
/*
val dialog: Dialog = super.onCreateDialog(savedInstanceState) val dialog: Dialog = super.onCreateDialog(savedInstanceState)
// Add back button listener
// Add back button listener // Add back button listener
dialog.setOnKeyListener { _, keyCode, keyEvent -> dialog.setOnKeyListener { _, keyCode, keyEvent ->
// getAction to make sure this doesn't double fire // getAction to make sure this doesn't double fire
@ -175,7 +141,6 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
} }
return dialog return dialog
*/
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -199,21 +164,15 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
} }
} }
fun setCallListener(videoCallResponseListener: VideoCallResponseListener) { fun setCallListener(videoCallResponseListener: VideoCallResponseListener) {
this.videoCallResponseListener = videoCallResponseListener this.videoCallResponseListener = videoCallResponseListener
} }
private fun onCreateView( override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
inflater: LayoutInflater, container: ViewGroup? savedInstanceState: Bundle?): View {
): View {
val view = inflater.inflate(R.layout.activity_video_call, container, false) parentView = 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() // Objects.requireNonNull(requireActivity().actionBar)!!.hide()
arguments?.run { arguments?.run {
apiKey = getString("apiKey") apiKey = getString("apiKey")
@ -222,27 +181,16 @@ 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(view) initUI(parentView)
requestPermissions() requestPermissions()
handleDragDialog() handleDragDialog()
mDetector = GestureDetectorCompat( mDetector = GestureDetectorCompat(context, MyGestureListener({ showControlPanelTemporarily() }, { miniCircleDoubleTap() }))
context,
MyGestureListener({ showControlPanelTemporarily() }, { miniCircleDoubleTap() })
)
return view return parentView
} }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return this.parentView
}
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
@ -272,13 +220,9 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
private fun initUI(view: View) { private fun initUI(view: View) {
videoCallContainer = view.findViewById(R.id.video_call_ll) videoCallContainer = view.findViewById(R.id.video_call_ll)
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)
activity_clingo_video_call = view.findViewById(R.id.activity_clingo_video_call)
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)
@ -288,18 +232,9 @@ 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) { cmTimer = view.findViewById<Chronometer>(R.id.cmTimer)
recordContainer.visibility = View.VISIBLE
} else {
recordContainer.visibility = View.GONE
}
// cmTimer = view.findViewById(R.id.cmTimer)
cmTimer.format = "mm:ss" cmTimer.format = "mm:ss"
cmTimer.onChronometerTickListener = cmTimer.onChronometerTickListener = Chronometer.OnChronometerTickListener { arg0: Chronometer? ->
Chronometer.OnChronometerTickListener { arg0: Chronometer? ->
// val f: NumberFormat = DecimalFormat("00")
// f.format(minutes)
val minutes: Long val minutes: Long
val seconds: Long val seconds: Long
if (!resume) { if (!resume) {
@ -311,10 +246,8 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
seconds = (elapsedTime - cmTimer.base) / 1000 % 60 seconds = (elapsedTime - cmTimer.base) / 1000 % 60
elapsedTime += 1000 elapsedTime += 1000
} }
val format = "%1$02d:%2$02d" // two digits arg0?.text = "$minutes:$seconds"
Log.d(VideoCallFragment.TAG, "onChronometerTick: $minutes : $seconds")
arg0?.text = String.format(format, minutes, seconds)
Log.d(TAG, "onChronometerTick: $minutes : $seconds")
} }
icMini.setOnClickListener { icMini.setOnClickListener {
@ -351,11 +284,8 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
// progressBar=findViewById(R.id.progress_bar); // progressBar=findViewById(R.id.progress_bar);
// progressBarTextView=findViewById(R.id.progress_bar_text); // progressBarTextView=findViewById(R.id.progress_bar_text);
// progressBar.setVisibility(View.GONE); // progressBar.setVisibility(View.GONE);
// hiddenButtons() hiddenButtons()
checkClientConnected() checkClientConnected()
handleVideoViewHeight(true)
if (appLang == "ar") { if (appLang == "ar") {
progressBarLayout!!.layoutDirection = View.LAYOUT_DIRECTION_RTL progressBarLayout!!.layoutDirection = View.LAYOUT_DIRECTION_RTL
@ -378,11 +308,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong()) mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong())
} }
override fun onRequestPermissionsResult( override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) {
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)
} }
@ -407,42 +333,17 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
@AfterPermissionGranted(RC_VIDEO_APP_PERM) @AfterPermissionGranted(RC_VIDEO_APP_PERM)
private fun requestPermissions() { private fun requestPermissions() {
val perms = arrayOf( val perms = arrayOf(Manifest.permission.INTERNET, Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.CALL_PHONE)
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()
mSession!!.setSessionListener(this) mSession!!.setSessionListener(this)
mSession!!.connect(token) mSession!!.connect(token)
mSession!!.setReconnectionListener(object :Session.ReconnectionListener{
override fun onReconnecting(p0: Session?) {
}
override fun onReconnected(session: Session?) {
session?.connect(token)
}
})
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
} else { } else {
EasyPermissions.requestPermissions( EasyPermissions.requestPermissions(this, getString(R.string.remaining_ar), RC_VIDEO_APP_PERM, *perms)
this,
getString(R.string.remaining_ar),
RC_VIDEO_APP_PERM,
*perms
)
} }
} }
@ -458,7 +359,6 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
} }
mPublisherViewContainer.addView(mPublisher!!.view) mPublisherViewContainer.addView(mPublisher!!.view)
mSession!!.publish(mPublisher) mSession!!.publish(mPublisher)
if (!resume) { if (!resume) {
@ -470,10 +370,10 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
override fun onDisconnected(session: Session) { override fun onDisconnected(session: Session) {
Log.d(TAG, "onDisconnected: disconnected from session " + session.sessionId) Log.d(TAG, "onDisconnected: disconnected from session " + session.sessionId)
// mSession = null mSession = null
// cmTimer.stop() cmTimer.stop()
// disconnectSession() disconnectSession()
// videoCallResponseListener?.minimizeVideoEvent(false) videoCallResponseListener?.minimizeVideoEvent(false)
} }
override fun onError(session: Session, opentokError: OpentokError) { override fun onError(session: Session, opentokError: OpentokError) {
@ -493,22 +393,11 @@ 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( videoCallPresenter.callChangeCallStatus(ChangeCallStatusRequestModel(3, sessionStatusModel!!.doctorId, sessionStatusModel!!.generalid, token, sessionStatusModel!!.vcid))
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( Log.d(TAG, "onStreamDropped: Stream " + stream.streamId + " dropped from session " + session.sessionId)
TAG,
"onStreamDropped: Stream " + stream.streamId + " dropped from session " + session.sessionId
)
if (mSubscriber == null) { if (mSubscriber == null) {
return return
} }
@ -517,7 +406,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
mSubscriber!!.destroy() mSubscriber!!.destroy()
mSubscriber = null mSubscriber = null
} }
//disconnectSession() disconnectSession()
} }
override fun onStreamCreated(publisherKit: PublisherKit?, stream: Stream) { override fun onStreamCreated(publisherKit: PublisherKit?, stream: Stream) {
@ -535,10 +424,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
} }
override fun onVideoDataReceived(subscriberKit: SubscriberKit?) { override fun onVideoDataReceived(subscriberKit: SubscriberKit?) {
mSubscriber!!.setStyle( mSubscriber!!.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL)
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()
@ -578,25 +464,9 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
}, 4000) }, 4000)
} }
override fun onVideoDisabled(subscriberKit: SubscriberKit?, s: String?) { override fun onVideoDisabled(subscriberKit: SubscriberKit?, s: String?) {}
Log.d(VideoCallFragment.TAG, "onVideoDisabled: Error ($s)")
// if (isCircle) {
// 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))
// }
}
override fun onVideoEnabled(subscriberKit: SubscriberKit?, s: String?) { override fun onVideoEnabled(subscriberKit: SubscriberKit?, s: String?) {}
Log.d(VideoCallFragment.TAG, "onVideoEnabled: Error ($s)")
// if (mSubscriber != null) {
// (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(isCircle)
// }
}
override fun onVideoDisableWarning(subscriberKit: SubscriberKit?) {} override fun onVideoDisableWarning(subscriberKit: SubscriberKit?) {}
@ -633,25 +503,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
mSession!!.disconnect() mSession!!.disconnect()
countDownTimer?.cancel() countDownTimer?.cancel()
videoCallPresenter.callChangeCallStatus( videoCallPresenter.callChangeCallStatus(ChangeCallStatusRequestModel(16, sessionStatusModel!!.doctorId, sessionStatusModel!!.generalid, token, sessionStatusModel!!.vcid))
ChangeCallStatusRequestModel(
16,
sessionStatusModel!!.doctorId,
sessionStatusModel!!.generalid,
token,
sessionStatusModel!!.vcid
)
)
// if(isDismiss)
// dialog?.dismiss()
// else
onCallChangeCallStatusSuccessful()
}
fun onCallChangeCallStatusSuccessful(){
val returnIntent = Intent()
returnIntent.putExtra("CallEnd", sessionStatusModel)
videoCallResponseListener?.onCallFinished(Activity.RESULT_CANCELED, returnIntent)
dialog?.dismiss() dialog?.dismiss()
} }
@ -694,7 +546,6 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
400, 400,
600 600
) )
} else { } else {
dialog?.window?.setLayout( dialog?.window?.setLayout(
300, 300,
@ -703,29 +554,17 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
} }
isCircle = !isCircle isCircle = !isCircle
if (mSubscriber != null) { if (mSubscriber != null) {
(mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(isCircle) (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(isCircle)
} else { } else {
if (isCircle) { if (isCircle) {
videoCallContainer.background = videoCallContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape) mSubscriberViewContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
mSubscriberViewContainer.background =
ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
} else { } else {
videoCallContainer.setBackgroundColor( videoCallContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color))
ContextCompat.getColor( mSubscriberViewContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color))
requireContext(),
R.color.text_color
)
)
mSubscriberViewContainer.setBackgroundColor(
ContextCompat.getColor(
requireContext(),
R.color.remoteBackground
)
)
} }
} }
if (isCircle) { if (isCircle) {
@ -735,8 +574,6 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
controlPanel.visibility = View.VISIBLE controlPanel.visibility = View.VISIBLE
layoutMini.visibility = View.VISIBLE layoutMini.visibility = View.VISIBLE
} }
handleVideoViewHeight(isFullScreen)
} }
private fun onMinimizedClicked(view: View?) { private fun onMinimizedClicked(view: View?) {
@ -745,17 +582,11 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
400, 400,
600 600
) )
recordContainer.visibility = View.GONE
} else { } else {
dialog?.window?.setLayout( dialog?.window?.setLayout(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT LinearLayout.LayoutParams.MATCH_PARENT
) )
if (isRecording) {
recordContainer.visibility = View.VISIBLE
} else {
recordContainer.visibility = View.GONE
}
} }
isFullScreen = !isFullScreen isFullScreen = !isFullScreen
@ -767,36 +598,25 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
} }
private fun setViewsVisibility() { private fun setViewsVisibility() {
val btnMinimizeLayoutParam: ConstraintLayout.LayoutParams =
btnMinimize.layoutParams as ConstraintLayout.LayoutParams
val mCallBtnLayoutParam: ConstraintLayout.LayoutParams =
mCallBtn.layoutParams as ConstraintLayout.LayoutParams
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 = val iconSizeSmall: Int = context!!.resources.getDimension(R.dimen.video_icon_size_small).toInt()
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 localPreviewMargin: Int = context!!.resources.getDimension(R.dimen.local_preview_margin_top).toInt()
val localPreviewWidth: Int = val localPreviewWidth: Int = context!!.resources.getDimension(R.dimen.local_preview_width).toInt()
context!!.resources.getDimension(R.dimen.local_preview_width).toInt() val localPreviewHeight: Int = context!!.resources.getDimension(R.dimen.local_preview_height).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 = val localPreviewLayoutParam: RelativeLayout.LayoutParams = mPublisherViewContainer.layoutParams as RelativeLayout.LayoutParams
mPublisherViewContainer.layoutParams as RelativeLayout.LayoutParams
val remotePreviewIconSize: Int = val remotePreviewIconSize: Int = context!!.resources.getDimension(R.dimen.remote_back_icon_size).toInt()
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 remotePreviewIconSizeSmall: Int = val remotePreviewLayoutParam: FrameLayout.LayoutParams = mSubscriberViewIcon.layoutParams as FrameLayout.LayoutParams
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
@ -815,11 +635,6 @@ 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) {
mPublisherViewContainer.addView(mPublisher!!.view)
}
mPublisherViewContainer.visibility = View.VISIBLE
// remotePreviewLayoutParam = FrameLayout.LayoutParams(remotePreviewIconSize, remotePreviewIconSize) // remotePreviewLayoutParam = FrameLayout.LayoutParams(remotePreviewIconSize, remotePreviewIconSize)
remotePreviewLayoutParam.width = remotePreviewIconSize remotePreviewLayoutParam.width = remotePreviewIconSize
remotePreviewLayoutParam.height = remotePreviewIconSize remotePreviewLayoutParam.height = remotePreviewIconSize
@ -842,11 +657,6 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
localPreviewLayoutParam.width = 0 localPreviewLayoutParam.width = 0
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) {
mPublisherViewContainer.removeView(mPublisher!!.view)
}
mPublisherViewContainer.visibility = View.GONE
// localPreviewLayoutIconParam = FrameLayout.LayoutParams(localPreviewIconSmall, localPreviewIconSmall) // localPreviewLayoutIconParam = FrameLayout.LayoutParams(localPreviewIconSmall, localPreviewIconSmall)
//// localPreviewLayoutParam = RelativeLayout.LayoutParams(localPreviewWidthSmall, localPreviewHeightSmall) //// localPreviewLayoutParam = RelativeLayout.LayoutParams(localPreviewWidthSmall, localPreviewHeightSmall)
// localPreviewLayoutParam.width = localPreviewWidthSmall // localPreviewLayoutParam.width = localPreviewWidthSmall
@ -871,87 +681,6 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
btnMinimize.layoutParams = btnMinimizeLayoutParam btnMinimize.layoutParams = btnMinimizeLayoutParam
mCallBtn.layoutParams = mCallBtnLayoutParam mCallBtn.layoutParams = mCallBtnLayoutParam
handleVideoViewHeight(isFullScreen)
}
private fun handleVideoViewHeight(isFullScreen: Boolean) {
val layoutNameParam: ConstraintLayout.LayoutParams =
layoutName.layoutParams as ConstraintLayout.LayoutParams
val layoutMiniParam: ConstraintLayout.LayoutParams =
layoutMini.layoutParams as ConstraintLayout.LayoutParams
val controlPanelParam: ConstraintLayout.LayoutParams =
controlPanel.layoutParams as ConstraintLayout.LayoutParams
val layoutNameHeight: Int =
context!!.resources.getDimension(R.dimen.layout_name_height).toInt()
val layoutMiniHeight: Int =
context!!.resources.getDimension(R.dimen.layout_mini_height).toInt()
val panelHeight: Int = context!!.resources.getDimension(R.dimen.layout_panel_height).toInt()
val panelHeightSmall: Int =
context!!.resources.getDimension(R.dimen.layout_panel_height_small).toInt()
val panelPadding: Int =
context!!.resources.getDimension(R.dimen.padding_space_big).toInt()
val panelPaddingMedium: Int =
context!!.resources.getDimension(R.dimen.padding_space_medium).toInt()
val temp = getStatusBarHeight() / 2
val screenWidth: Float
val screenHeight: Float
if (isFullScreen) {
screenWidth = ViewsUtil.getWidthDp(requireContext())
screenHeight = ViewsUtil.getHeightDp(requireContext())
layoutNameParam.height = layoutNameHeight + temp
layoutMiniParam.height = 0
controlPanelParam.height = panelHeight + temp
controlPanel.setPadding(panelPadding, panelPadding, panelPadding, panelPadding)
} else {
if (isCircle) {
screenWidth = 300F
screenHeight = 300F
layoutNameParam.height = 0
layoutMiniParam.height = 0
controlPanelParam.height = 0
} else {
screenWidth = 400F
screenHeight = 600F
layoutNameParam.height = 0
layoutMiniParam.height = layoutMiniHeight
controlPanelParam.height = panelHeightSmall
}
controlPanel.setPadding(
panelPaddingMedium,
panelPaddingMedium,
panelPaddingMedium,
panelPaddingMedium
)
}
layoutName.layoutParams = layoutNameParam
layoutMini.layoutParams = layoutMiniParam
controlPanel.layoutParams = controlPanelParam
var videoStreamHeight =
screenHeight - controlPanelParam.height - layoutNameParam.height - layoutMiniParam.height
if (isFullScreen) {
// videoStreamHeight -= getStatusBarHeight() / 2
}
val callLayoutParam: ConstraintLayout.LayoutParams =
activity_clingo_video_call.layoutParams as ConstraintLayout.LayoutParams
callLayoutParam.height = videoStreamHeight.toInt()
callLayoutParam.width = screenWidth.toInt()
} }
private fun onCameraClicked(view: View?) { private fun onCameraClicked(view: View?) {
@ -959,15 +688,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
isCameraClicked = !isCameraClicked isCameraClicked = !isCameraClicked
mPublisher!!.publishVideo = !isCameraClicked mPublisher!!.publishVideo = !isCameraClicked
val res = if (isCameraClicked) R.drawable.video_disabled else R.drawable.video_enabled val res = if (isCameraClicked) R.drawable.video_disabled else R.drawable.video_enabled
mCameraBtn.setImageResource(res) mCameraBtn!!.setImageResource(res)
// if (!isCameraClicked) {
// 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))
// }
} }
} }
@ -1093,13 +814,13 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
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
} }
override fun onFinish() { override fun onFinish() {
mParams.x = -(szWindow.x - videoCallContainer.width) mParams.x = -(szWindow.x - videoCallContainer.width)
dialog?.window!!.attributes = mParams dialog!!.window!!.attributes = mParams
} }
}.start() }.start()
} }
@ -1125,7 +846,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
override fun onFinish() { override fun onFinish() {
mParams.x = szWindow.x - videoCallContainer.width mParams.x = szWindow.x - videoCallContainer.width
dialog?.window!!.attributes = mParams dialog!!.window!!.attributes = mParams
} }
}.start() }.start()
} }
@ -1142,13 +863,10 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
).toInt() ).toInt()
} }
private class MyGestureListener( private class MyGestureListener(val onTabCall: () -> Unit, val miniCircleDoubleTap: () -> Unit) : GestureDetector.SimpleOnGestureListener() {
val onTabCall: () -> Unit,
val miniCircleDoubleTap: () -> Unit
) : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(event: MotionEvent): Boolean { override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
// onTabCall() onTabCall()
return true return true
} }

@ -1,38 +0,0 @@
package com.hmg.hmgDr.util
import java.text.SimpleDateFormat
import java.util.*
object DateUtils {
var simpleDateFormat: SimpleDateFormat = SimpleDateFormat("hh:mm:ss", Locale.ENGLISH)
fun differentDateTimeBetweenDateAndNow(firstDate: Date): String {
val now: Date = Calendar.getInstance().time
//1 minute = 60 seconds
//1 hour = 60 x 60 = 3600
//1 day = 3600 x 24 = 86400
var different: Long = now.time - firstDate.time
val secondsInMilli: Long = 1000
val minutesInMilli = secondsInMilli * 60
val hoursInMilli = minutesInMilli * 60
val daysInMilli = hoursInMilli * 24
val elapsedDays = different / daysInMilli
different %= daysInMilli
val elapsedHours = different / hoursInMilli
different %= hoursInMilli
val elapsedMinutes = different / minutesInMilli
different %= minutesInMilli
val elapsedSeconds = different / secondsInMilli
val format = "%1$02d:%2$02d" // two digits
return String.format(format, elapsedMinutes, elapsedSeconds)
}
}

@ -1,4 +1,4 @@
package com.hmg.hmgDr.util.opentok package com.hmg.hmgDr.util
import android.content.Context import android.content.Context
import android.content.res.Resources import android.content.res.Resources

@ -1,77 +0,0 @@
package com.hmg.hmgDr.util
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import androidx.core.app.NotificationCompat
import com.hmg.hmgDr.model.NotificationDataModel
import com.hmg.hmgDr.model.NotificationVideoModel
object NotificationUtil {
fun createNotificationChannel(
context: Context,
notificationDataModel: NotificationDataModel
): String {
// The id of the channel.
val channelId: String = notificationDataModel.mChannelId
// NotificationChannels are required for Notifications on O (API 26) and above.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// The user-visible name of the channel.
val channelName: CharSequence = notificationDataModel.mChannelName
// The user-visible description of the channel.
val channelDescription: String = notificationDataModel.mChannelDescription
val channelImportance: Int = notificationDataModel.mChannelImportance
val channelEnableVibrate: Boolean = notificationDataModel.mChannelEnableVibrate
val channelLockscreenVisibility: Int =
notificationDataModel.mChannelLockscreenVisibility
// Initializes NotificationChannel.
val notificationChannel = NotificationChannel(channelId, channelName, channelImportance)
notificationChannel.description = channelDescription
notificationChannel.lightColor = Color.BLUE
notificationChannel.lockscreenVisibility = channelLockscreenVisibility
// no vibration
notificationChannel.vibrationPattern = longArrayOf(0)
notificationChannel.enableVibration(channelEnableVibrate)
// Adds NotificationChannel to system. Attempting to create an existing notification
// channel with its original values performs no operation, so it's safe to perform the
// below sequence.
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(notificationChannel)
}
return channelId
}
fun setNotificationBigStyle(notificationData : NotificationVideoModel): NotificationCompat.BigTextStyle {
return NotificationCompat.BigTextStyle() // Overrides ContentText in the big form of the template.
.bigText(notificationData.mBigText) // Overrides ContentTitle in the big form of the template.
.setBigContentTitle(notificationData.mBigContentTitle) // Summary line after the detail section in the big form of the template.
// Note: To improve readability, don't overload the user with info. If Summary Text
// doesn't add critical information, you should skip it.
.setSummaryText(notificationData.mSummaryText)
}
/**
* IMPORTANT NOTE: You should not do this action unless the user takes an action to see your
* Notifications like this sample demonstrates. Spamming users to re-enable your notifications
* is a bad idea.
*/
fun openNotificationSettingsForApp(context: Context) {
// Links to this app's notification settings.
val intent = Intent()
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
intent.putExtra("app_package", context.packageName)
intent.putExtra("app_uid", context.applicationInfo.uid)
// for Android 8 and above
intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName)
context.startActivity(intent)
}
}

@ -1,4 +1,4 @@
package com.hmg.hmgDr.util.opentok package com.hmg.hmgDr.util
import android.content.Context import android.content.Context
import android.content.res.Resources import android.content.res.Resources

@ -1,467 +0,0 @@
package com.hmg.hmgDr.util.audio
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioRecord
import android.media.AudioTrack
import android.media.MediaRecorder.AudioSource
import android.os.Process
import android.util.Log
import com.opentok.android.BaseAudioDevice
import java.nio.ByteBuffer
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock
class CustomAudioDevice(context: Context) : BaseAudioDevice() {
private val m_context: Context = context
private var m_audioTrack: AudioTrack? = null
private var m_audioRecord: AudioRecord? = null
// Capture & render buffers
private var m_playBuffer: ByteBuffer? = null
private var m_recBuffer: ByteBuffer? = null
private val m_tempBufPlay: ByteArray
private val m_tempBufRec: ByteArray
private val m_rendererLock: ReentrantLock = ReentrantLock(true)
private val m_renderEvent: Condition = m_rendererLock.newCondition()
@Volatile
private var m_isRendering = false
@Volatile
private var m_shutdownRenderThread = false
private val m_captureLock: ReentrantLock = ReentrantLock(true)
private val m_captureEvent: Condition = m_captureLock.newCondition()
@Volatile
private var m_isCapturing = false
@Volatile
private var m_shutdownCaptureThread = false
private val m_captureSettings: AudioSettings
private val m_rendererSettings: AudioSettings
// Capturing delay estimation
private var m_estimatedCaptureDelay = 0
// Rendering delay estimation
private var m_bufferedPlaySamples = 0
private var m_playPosition = 0
private var m_estimatedRenderDelay = 0
private val m_audioManager: AudioManager
private var isRendererMuted = false
companion object {
private const val LOG_TAG = "opentok-defaultaudio"
private const val SAMPLING_RATE = 44100
private const val NUM_CHANNELS_CAPTURING = 1
private const val NUM_CHANNELS_RENDERING = 1
private const val MAX_SAMPLES = 2 * 480 * 2 // Max 10 ms @ 48 kHz
}
init {
try {
m_playBuffer = ByteBuffer.allocateDirect(MAX_SAMPLES)
m_recBuffer = ByteBuffer.allocateDirect(MAX_SAMPLES)
} catch (e: Exception) {
Log.e(LOG_TAG, "${e.message}.")
}
m_tempBufPlay = ByteArray(MAX_SAMPLES)
m_tempBufRec = ByteArray(MAX_SAMPLES)
m_captureSettings = AudioSettings(
SAMPLING_RATE,
NUM_CHANNELS_CAPTURING
)
m_rendererSettings = AudioSettings(
SAMPLING_RATE,
NUM_CHANNELS_RENDERING
)
m_audioManager = m_context
.getSystemService(Context.AUDIO_SERVICE) as AudioManager
m_audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
}
override fun initCapturer(): Boolean {
// get the minimum buffer size that can be used
val minRecBufSize: Int = AudioRecord.getMinBufferSize(
m_captureSettings
.sampleRate,
if (NUM_CHANNELS_CAPTURING == 1) AudioFormat.CHANNEL_IN_MONO else AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT
)
// double size to be more safe
val recBufSize = minRecBufSize * 2
// release the object
if (m_audioRecord != null) {
m_audioRecord!!.release()
m_audioRecord = null
}
try {
m_audioRecord = AudioRecord(
AudioSource.VOICE_COMMUNICATION,
m_captureSettings.sampleRate,
if (NUM_CHANNELS_CAPTURING == 1) AudioFormat.CHANNEL_IN_MONO else AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT, recBufSize
)
} catch (e: Exception) {
Log.e(LOG_TAG, "${e.message}.")
return false
}
// check that the audioRecord is ready to be used
if (m_audioRecord!!.state != AudioRecord.STATE_INITIALIZED) {
Log.i(
LOG_TAG, "Audio capture is not initialized "
+ m_captureSettings.sampleRate
)
return false
}
m_shutdownCaptureThread = false
Thread(m_captureThread).start()
return true
}
override fun destroyCapturer(): Boolean {
m_captureLock.lock()
// release the object
m_audioRecord?.release()
m_audioRecord = null
m_shutdownCaptureThread = true
m_captureEvent.signal()
m_captureLock.unlock()
return true
}
override fun getEstimatedCaptureDelay(): Int {
return m_estimatedCaptureDelay
}
override fun startCapturer(): Boolean {
// start recording
try {
m_audioRecord!!.startRecording()
} catch (e: IllegalStateException) {
e.printStackTrace()
return false
}
m_captureLock.lock()
m_isCapturing = true
m_captureEvent.signal()
m_captureLock.unlock()
return true
}
override fun stopCapturer(): Boolean {
m_captureLock.lock()
try {
// only stop if we are recording
if (m_audioRecord!!.recordingState == AudioRecord.RECORDSTATE_RECORDING) {
// stop recording
try {
m_audioRecord!!.stop()
} catch (e: IllegalStateException) {
e.printStackTrace()
return false
}
}
} finally {
// Ensure we always unlock
m_isCapturing = false
m_captureLock.unlock()
}
return true
}
private val m_captureThread = Runnable {
val samplesToRec = SAMPLING_RATE / 100
var samplesRead = 0
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO)
} catch (e: Exception) {
e.printStackTrace()
}
while (!m_shutdownCaptureThread) {
m_captureLock.lock()
samplesRead = try {
if (!m_isCapturing) {
m_captureEvent.await()
continue
} else {
if (m_audioRecord == null) {
continue
}
val lengthInBytes = ((samplesToRec shl 1)
* NUM_CHANNELS_CAPTURING)
val readBytes: Int = m_audioRecord!!.read(
m_tempBufRec, 0,
lengthInBytes
)
m_recBuffer!!.rewind()
m_recBuffer!!.put(m_tempBufRec)
(readBytes shr 1) / NUM_CHANNELS_CAPTURING
}
} catch (e: Exception) {
Log.e(LOG_TAG, "RecordAudio try failed: " + e.message)
continue
} finally {
// Ensure we always unlock
m_captureLock.unlock()
}
audioBus.writeCaptureData(m_recBuffer, samplesRead)
m_estimatedCaptureDelay = samplesRead * 1000 / SAMPLING_RATE
}
}
override fun initRenderer(): Boolean {
// get the minimum buffer size that can be used
val minPlayBufSize: Int = AudioTrack.getMinBufferSize(
m_rendererSettings
.sampleRate,
if (NUM_CHANNELS_RENDERING == 1) AudioFormat.CHANNEL_OUT_MONO else AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT
)
var playBufSize = minPlayBufSize
if (playBufSize < 6000) {
playBufSize *= 2
}
// release the object
if (m_audioTrack != null) {
m_audioTrack!!.release()
m_audioTrack = null
}
try {
m_audioTrack = AudioTrack(
AudioManager.STREAM_VOICE_CALL,
m_rendererSettings.sampleRate,
if (NUM_CHANNELS_RENDERING == 1) AudioFormat.CHANNEL_OUT_MONO else AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, playBufSize,
AudioTrack.MODE_STREAM
)
} catch (e: Exception) {
Log.e(LOG_TAG, "${e.message}.")
return false
}
// check that the audioRecord is ready to be used
if (m_audioTrack!!.state != AudioTrack.STATE_INITIALIZED) {
Log.i(
LOG_TAG, "Audio renderer not initialized "
+ m_rendererSettings.sampleRate
)
return false
}
m_bufferedPlaySamples = 0
outputMode = OutputMode.SpeakerPhone
m_shutdownRenderThread = false
Thread(m_renderThread).start()
return true
}
override fun destroyRenderer(): Boolean {
m_rendererLock.lock()
// release the object
m_audioTrack!!.release()
m_audioTrack = null
m_shutdownRenderThread = true
m_renderEvent.signal()
m_rendererLock.unlock()
unregisterHeadsetReceiver()
m_audioManager.isSpeakerphoneOn = false
m_audioManager.mode = AudioManager.MODE_NORMAL
return true
}
override fun getEstimatedRenderDelay(): Int {
return m_estimatedRenderDelay
}
override fun startRenderer(): Boolean {
// start playout
try {
m_audioTrack!!.play()
} catch (e: IllegalStateException) {
e.printStackTrace()
return false
}
m_rendererLock.lock()
m_isRendering = true
m_renderEvent.signal()
m_rendererLock.unlock()
return true
}
override fun stopRenderer(): Boolean {
m_rendererLock.lock()
try {
// only stop if we are playing
if (m_audioTrack!!.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
// stop playout
try {
m_audioTrack!!.stop()
} catch (e: IllegalStateException) {
e.printStackTrace()
return false
}
// flush the buffers
m_audioTrack!!.flush()
}
} finally {
// Ensure we always unlock, both for success, exception or error
// return.
m_isRendering = false
m_rendererLock.unlock()
}
return true
}
private val m_renderThread = Runnable {
val samplesToPlay = SAMPLING_RATE / 100
try {
Process
.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO)
} catch (e: Exception) {
e.printStackTrace()
}
while (!m_shutdownRenderThread) {
m_rendererLock.lock()
try {
if (!m_isRendering) {
m_renderEvent.await()
continue
} else {
m_rendererLock.unlock()
// Don't lock on audioBus calls
m_playBuffer!!.clear()
val samplesRead: Int = audioBus.readRenderData(
m_playBuffer, samplesToPlay
)
// Log.d(LOG_TAG, "Samples read: " + samplesRead);
m_rendererLock.lock()
if (!isRendererMuted) {
// After acquiring the lock again
// we must check if we are still playing
if (m_audioTrack == null
|| !m_isRendering
) {
continue
}
val bytesRead = ((samplesRead shl 1)
* NUM_CHANNELS_RENDERING)
m_playBuffer!!.get(m_tempBufPlay, 0, bytesRead)
val bytesWritten: Int = m_audioTrack!!.write(
m_tempBufPlay, 0,
bytesRead
)
// increase by number of written samples
m_bufferedPlaySamples += ((bytesWritten shr 1)
/ NUM_CHANNELS_RENDERING)
// decrease by number of played samples
val pos: Int = m_audioTrack!!.getPlaybackHeadPosition()
if (pos < m_playPosition) {
// wrap or reset by driver
m_playPosition = 0
}
m_bufferedPlaySamples -= pos - m_playPosition
m_playPosition = pos
// we calculate the estimated delay based on the
// buffered samples
m_estimatedRenderDelay = (m_bufferedPlaySamples * 1000
/ SAMPLING_RATE)
}
}
} catch (e: Exception) {
Log.e(LOG_TAG, "Exception: " + e.message)
e.printStackTrace()
} finally {
m_rendererLock.unlock()
}
}
}
override fun getCaptureSettings(): AudioSettings {
return m_captureSettings
}
override fun getRenderSettings(): AudioSettings {
return m_rendererSettings
}
/**
* Communication modes handling
*/
override fun setOutputMode(mode: OutputMode): Boolean {
super.setOutputMode(mode)
if (mode == OutputMode.Handset) {
unregisterHeadsetReceiver()
m_audioManager.isSpeakerphoneOn = false
} else {
m_audioManager.isSpeakerphoneOn = true
registerHeadsetReceiver()
}
return true
}
private val m_headsetReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
if (intent.action!!.compareTo(Intent.ACTION_HEADSET_PLUG) == 0) {
val state: Int = intent.getIntExtra("state", 0)
m_audioManager.isSpeakerphoneOn = state == 0
}
}
}
private var m_receiverRegistered = false
private fun registerHeadsetReceiver() {
if (!m_receiverRegistered) {
val receiverFilter = IntentFilter(
Intent.ACTION_HEADSET_PLUG
)
m_context.registerReceiver(m_headsetReceiver, receiverFilter)
m_receiverRegistered = true
}
}
private fun unregisterHeadsetReceiver() {
if (m_receiverRegistered) {
try {
m_context.unregisterReceiver(m_headsetReceiver)
} catch (e: IllegalArgumentException) {
e.printStackTrace()
}
m_receiverRegistered = false
}
}
override fun onPause() {
if (outputMode == OutputMode.SpeakerPhone) {
unregisterHeadsetReceiver()
}
}
override fun onResume() {
if (outputMode == OutputMode.SpeakerPhone) {
registerHeadsetReceiver()
}
}
fun setRendererMute(isRendererMuted: Boolean) {
this.isRendererMuted = isRendererMuted
}
}

@ -1,58 +0,0 @@
package com.hmg.hmgDr.util
import android.content.Context
import android.util.DisplayMetrics
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import io.flutter.embedding.android.FlutterFragmentActivity
import kotlin.math.ceil
object ViewsUtil {
/* return status bar height on basis of device display metrics */
fun getStatusBarHeight(context: Context): Int {
return ceil(
(25 * context.resources.displayMetrics.density).toDouble()
).toInt()
}
/**
* @param context
* @return the Screen height in DP
*/
fun getHeightDp(context: Context, isInDp: Boolean = false): Float {
val displayMetrics: DisplayMetrics = context.resources.displayMetrics
return if (isInDp) {
displayMetrics.heightPixels / displayMetrics.density
} else {
displayMetrics.heightPixels.toFloat()
}
}
/**
* @param context
* @return the screnn width in dp
*/
fun getWidthDp(context: Context, isInDp: Boolean = false): Float {
val displayMetrics: DisplayMetrics = context.resources.displayMetrics
return if (isInDp) {
displayMetrics.widthPixels / displayMetrics.density
} else {
displayMetrics.widthPixels.toFloat()
}
}
// code to hide soft keyboard
fun hideSoftKeyBoard(context: Context, editBox: EditText?) {
val imm = context.getSystemService(FlutterFragmentActivity.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editBox?.windowToken, 0)
}
// code to show soft keyboard
private fun showSoftKeyBoard(context: Context, editBox: EditText?) {
val inputMethodManager = context.getSystemService(FlutterFragmentActivity.INPUT_METHOD_SERVICE) as InputMethodManager
editBox?.requestFocus()
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
}
}

@ -1,5 +0,0 @@
<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="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z"/>
</vector>

@ -1,5 +0,0 @@
<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="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z"/>
</vector>

@ -1,5 +0,0 @@
<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="M12,9c-1.6,0 -3.15,0.25 -4.6,0.72v3.1c0,0.39 -0.23,0.74 -0.56,0.9 -0.98,0.49 -1.87,1.12 -2.66,1.85 -0.18,0.18 -0.43,0.28 -0.7,0.28 -0.28,0 -0.53,-0.11 -0.71,-0.29L0.29,13.08c-0.18,-0.17 -0.29,-0.42 -0.29,-0.7 0,-0.28 0.11,-0.53 0.29,-0.71C3.34,8.78 7.46,7 12,7s8.66,1.78 11.71,4.67c0.18,0.18 0.29,0.43 0.29,0.71 0,0.28 -0.11,0.53 -0.29,0.71l-2.48,2.48c-0.18,0.18 -0.43,0.29 -0.71,0.29 -0.27,0 -0.52,-0.11 -0.7,-0.28 -0.79,-0.74 -1.69,-1.36 -2.67,-1.85 -0.33,-0.16 -0.56,-0.5 -0.56,-0.9v-3.1C15.15,9.25 13.6,9 12,9z"/>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

@ -11,7 +11,7 @@
<RelativeLayout <RelativeLayout
android:id="@+id/layout_name" android:id="@+id/layout_name"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/layout_name_height" android:layout_height="wrap_content"
android:padding="@dimen/padding_space_medium" android:padding="@dimen/padding_space_medium"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
@ -33,29 +33,34 @@
android:background="@drawable/shape_capsule" android:background="@drawable/shape_capsule"
android:padding="@dimen/padding_space_small"> android:padding="@dimen/padding_space_small">
<TextView <Chronometer
android:id="@+id/tv_timer" android:id="@+id/cmTimer"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="4dp" android:padding="4dp"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/text_size_medium" android:textSize="16sp"
android:textStyle="bold" android:textStyle="bold"
android:text="00:00" /> tools:text="25:45" />
</FrameLayout> </FrameLayout>
</RelativeLayout> </RelativeLayout>
<RelativeLayout
android:id="@+id/activity_clingo_video_call"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/control_panel"
app:layout_constraintTop_toBottomOf="@+id/layout_name">
<RelativeLayout <RelativeLayout
android:id="@+id/layout_mini" android:id="@+id/layout_mini"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/layout_mini_height" android:layout_height="wrap_content"
android:background="@color/remoteBackground" android:background="@color/remoteBackground"
app:layout_constraintTop_toBottomOf="@+id/layout_name"
android:alpha="0.5" android:alpha="0.5"
android:visibility="gone" android:visibility="gone">
tools:visibility="visible">
<ImageButton <ImageButton
android:id="@+id/ic_mini" android:id="@+id/ic_mini"
@ -69,17 +74,11 @@
android:src="@drawable/ic_mini" /> android:src="@drawable/ic_mini" />
</RelativeLayout> </RelativeLayout>
<RelativeLayout
android:id="@+id/activity_clingo_video_call"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/control_panel"
app:layout_constraintTop_toBottomOf="@+id/layout_mini">
<FrameLayout <FrameLayout
android:id="@+id/remote_video_view_container" android:id="@+id/remote_video_view_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@+id/layout_mini"
android:background="@color/remoteBackground"> android:background="@color/remoteBackground">
<ImageView <ImageView
@ -109,23 +108,6 @@
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:scaleType="centerCrop"
android:layout_margin="5dp"
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"
@ -141,7 +123,7 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/control_panel" android:id="@+id/control_panel"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/layout_panel_height" android:layout_height="wrap_content"
android:padding="@dimen/padding_space_big" android:padding="@dimen/padding_space_big"
app:layout_constraintBottom_toBottomOf="parent"> app:layout_constraintBottom_toBottomOf="parent">
@ -149,7 +131,7 @@
android:id="@+id/btn_call" android:id="@+id/btn_call"
android:layout_width="@dimen/video_icon_size" android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size"
android:scaleType="centerInside" android:scaleType="centerCrop"
android:src="@drawable/call" android:src="@drawable/call"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -159,7 +141,7 @@
android:id="@+id/btn_minimize" android:id="@+id/btn_minimize"
android:layout_width="@dimen/video_icon_size" android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size"
android:scaleType="centerInside" android:scaleType="centerCrop"
android:src="@drawable/reducing" android:src="@drawable/reducing"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -170,7 +152,7 @@
android:layout_width="@dimen/video_icon_size" android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size"
android:layout_marginStart="@dimen/padding_space_medium" android:layout_marginStart="@dimen/padding_space_medium"
android:scaleType="centerInside" android:scaleType="centerCrop"
android:src="@drawable/video_enabled" android:src="@drawable/video_enabled"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_minimize" app:layout_constraintStart_toEndOf="@id/btn_minimize"
@ -181,7 +163,7 @@
android:layout_width="@dimen/video_icon_size" android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size"
android:layout_marginStart="@dimen/padding_space_medium" android:layout_marginStart="@dimen/padding_space_medium"
android:scaleType="centerInside" android:scaleType="centerCrop"
android:src="@drawable/mic_enabled" android:src="@drawable/mic_enabled"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_camera" app:layout_constraintStart_toEndOf="@id/btn_camera"
@ -192,7 +174,7 @@
android:layout_width="@dimen/video_icon_size" android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size"
android:layout_marginStart="@dimen/padding_space_medium" android:layout_marginStart="@dimen/padding_space_medium"
android:scaleType="centerInside" android:scaleType="centerCrop"
android:src="@drawable/camera_back" android:src="@drawable/camera_back"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_mic" app:layout_constraintStart_toEndOf="@id/btn_mic"
@ -203,7 +185,7 @@
android:layout_width="@dimen/video_icon_size" android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size"
android:layout_marginStart="@dimen/padding_space_medium" android:layout_marginStart="@dimen/padding_space_medium"
android:scaleType="centerInside" android:scaleType="centerCrop"
android:src="@drawable/audio_enabled" android:src="@drawable/audio_enabled"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"

@ -1,81 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fadeScrollbars="false"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/ask_for_error_log"
android:textColor="#212121"
android:textSize="18sp"/>
<Button
android:id="@+id/button_view_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="View Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_copy_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Copy Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_share_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Share Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_email_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Email Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_save_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Save Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_close_app"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Close App"
android:textColor="#212121"/>
</LinearLayout>
</ScrollView>
</LinearLayout>

@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="88dp"
android:background="@android:color/holo_blue_dark"
android:orientation="vertical"
android:padding="@dimen/padding_space_medium">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@mipmap/ic_launcher" />
<TextView
style="@style/TextAppearance.Compat.Notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="@dimen/padding_space_small"
android:paddingEnd="@dimen/padding_space_small"
android:text="HMG Doctor"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small" />
<Chronometer
android:id="@+id/notify_timer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
style="@style/TextAppearance.Compat.Notification"
android:paddingStart="@dimen/padding_space_small"
android:paddingEnd="@dimen/padding_space_small"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small"
android:format="MM:SS"
tools:text="25:45" />
<ImageView
android:id="@+id/iv_Arrow"
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@drawable/ic_arrow_bottom" />
</LinearLayout>
<TextView
android:id="@+id/notify_title"
style="@style/TextAppearance.Compat.Notification.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_space_medium"
android:paddingStart="@dimen/padding_space_small"
android:paddingEnd="@dimen/padding_space_small"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small"
android:textStyle="bold"
tools:text="Mosa zaid mosa abuzaid" />
<TextView
android:id="@+id/notify_content"
style="@style/TextAppearance.Compat.Notification.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/padding_space_small"
android:paddingEnd="@dimen/padding_space_small"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small"
android:text="Tap to return to call" />
</LinearLayout>

@ -1,94 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_dark"
android:orientation="vertical"
android:padding="@dimen/padding_space_medium">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@mipmap/ic_launcher" />
<TextView
style="@style/TextAppearance.Compat.Notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="@dimen/padding_space_small"
android:paddingEnd="@dimen/padding_space_small"
android:text="HMG Doctor"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small" />
<Chronometer
android:id="@+id/notify_timer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
style="@style/TextAppearance.Compat.Notification"
android:paddingStart="@dimen/padding_space_small"
android:paddingEnd="@dimen/padding_space_small"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small"
android:format="MM:SS"
tools:text="25:45" />
<ImageView
android:id="@+id/iv_Arrow"
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@drawable/ic_arrow_top" />
</LinearLayout>
<TextView
android:id="@+id/notify_title"
style="@style/TextAppearance.Compat.Notification.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_space_big"
android:paddingStart="@dimen/padding_space_small"
android:paddingEnd="@dimen/padding_space_small"
android:textColor="@color/white"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
tools:text="Mosa zaid mosa abuzaid" />
<TextView
android:id="@+id/notify_content"
style="@style/TextAppearance.Compat.Notification.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/padding_space_small"
android:paddingEnd="@dimen/padding_space_small"
android:textColor="@color/white"
android:textSize="@dimen/text_size_medium"
android:text="Tap to return to call" />
<TextView
android:id="@+id/btn_end"
style="@style/TextAppearance.Compat.Notification.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_space_medium"
android:layout_marginBottom="@dimen/padding_space_medium"
android:paddingStart="@dimen/padding_space_small"
android:paddingEnd="@dimen/padding_space_small"
android:textColor="@color/white"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:text="End call" />
</LinearLayout>

@ -9,7 +9,7 @@
<!-- buttons --> <!-- buttons -->
<dimen name="call_button_size">60dp</dimen> <dimen name="call_button_size">60dp</dimen>
<dimen name="other_button_size">54dp</dimen> <dimen name="other_button_size">54dp</dimen>
<dimen name="video_icon_size">48dp</dimen> <dimen name="video_icon_size">52dp</dimen>
<dimen name="video_icon_size_small">24dp</dimen> <dimen name="video_icon_size_small">24dp</dimen>
<!-- buttons --> <!-- buttons -->
@ -33,15 +33,9 @@
<!-- padding/margin--> <!-- padding/margin-->
<dimen name="padding_space_small">4dp</dimen> <dimen name="padding_space_small">4dp</dimen>
<dimen name="padding_space_medium">8dp</dimen> <dimen name="padding_space_medium">8sp</dimen>
<dimen name="padding_space_big">16dp</dimen> <dimen name="padding_space_big">16dp</dimen>
<dimen name="padding_space_big_2">24dp</dimen> <dimen name="padding_space_big_2">24dp</dimen>
<dimen name="layout_mini_height">36dp</dimen>
<dimen name="layout_name_height">60dp</dimen>
<dimen name="layout_panel_height">80dp</dimen>
<dimen name="layout_panel_height_small">40dp</dimen>
</resources> </resources>

@ -4,6 +4,7 @@
<string name="remaining_ar">الوقت المتبقي بالثانيه: </string> <string name="remaining_ar">الوقت المتبقي بالثانيه: </string>
<string name="setting">Settings</string> <string name="setting">Settings</string>
<string name="cancel">Cancel</string> <string name="cancel">Cancel</string>
<string name="ask_for_error_log">An unexpected error has occurred.\nHelp developers by providing error details.\nThank you for your support.</string> <!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
</resources> </resources>

@ -1,12 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<style name="LaunchTheme" parent="Theme.AppCompat.NoActionBar">
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame --> Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
</style> </style>
<style name="AppTheme" parent="Theme.AppCompat"> <style name="AppTheme" parent="Theme.AppCompat">
</style> </style>
@ -27,17 +25,12 @@
<!-- turn off any drawable used to draw a frame on the window --> <!-- turn off any drawable used to draw a frame on the window -->
<item name="android:windowIsFloating">true</item> <item name="android:windowIsFloating">true</item>
<!-- float the window so it does not fill the screen --> <!-- float the window so it does not fill the screen -->
<item name="windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
<item name="windowActionBar">true</item>
<item name="android:windowFullscreen">false</item>
<!-- remove the title bar we make our own--> <!-- remove the title bar we make our own-->
<item name="android:windowContentOverlay">@null</item> <item name="android:windowContentOverlay">@null</item>
<!-- remove the shadow from under the title bar --> <!-- remove the shadow from under the title bar -->
<item name="android:layout_width">match_parent</item> <item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item> <item name="android:layout_height">match_parent</item>
<!-- smooth animation-->
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
</style> </style>
</resources> </resources>

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>

@ -6,9 +6,9 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.0.3' classpath 'com.android.tools.build:gradle:3.5.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.3' classpath 'com.google.gms:google-services:4.3.2'
} }
} }
@ -17,8 +17,7 @@ allprojects {
google() google()
jcenter() jcenter()
mavenCentral() mavenCentral()
maven { url 'https://developer.huawei.com/repo/' } maven { url 'https://tokbox.bintray.com/maven' }
// maven { url 'https://tokbox.bintray.com/maven' }
} }
} }

@ -1,77 +1,34 @@
{ {
"project_info": { "project_info": {
"project_number": "934365232760", "project_number": "157373154094",
"project_id": "hmg-dr-app", "project_id": "hmg-doctor-app-1553688619744",
"storage_bucket": "hmg-dr-app.appspot.com" "storage_bucket": "hmg-doctor-app-1553688619744.appspot.com"
}, },
"client": [ "client": [
{ {
"client_info": { "client_info": {
"mobilesdk_app_id": "1:934365232760:android:024b3569972f1c09f9778d", "mobilesdk_app_id": "1:157373154094:android:daeea3a4e1f4462a1bf0bf",
"android_client_info": {
"package_name": "COM.HMG.HMGDR"
}
},
"oauth_client": [
{
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCpYwrmuntOBdZv6GV6KEnLj8nQRvEnZ6I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "934365232760-57v2ld1qqulc4nt4o5pgjfbpc47fj3qf.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "COM.HMG.HMGDR"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:934365232760:android:e0e185e68c0d7690f9778d",
"android_client_info": { "android_client_info": {
"package_name": "com.hmg.hmgDr" "package_name": "com.hmg.hmgDr"
} }
}, },
"oauth_client": [ "oauth_client": [
{ {
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com", "client_id": "157373154094-egrhbfr861l7k722g3v2gd4a0opi3r1u.apps.googleusercontent.com",
"client_type": 3 "client_type": 3
} }
], ],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyCpYwrmuntOBdZv6GV6KEnLj8nQRvEnZ6I" "current_key": "AIzaSyDX8RPwu00MyrpqC-T2zXtrUQvTQGRv1mM"
} }
], ],
"services": { "services": {
"appinvite_service": { "appinvite_service": {
"other_platform_oauth_client": [ "other_platform_oauth_client": [
{ {
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com", "client_id": "157373154094-egrhbfr861l7k722g3v2gd4a0opi3r1u.apps.googleusercontent.com",
"client_type": 3 "client_type": 3
},
{
"client_id": "934365232760-57v2ld1qqulc4nt4o5pgjfbpc47fj3qf.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "COM.HMG.HMGDR"
}
} }
] ]
} }

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip

@ -1 +0,0 @@
include ':app'

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 KiB

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 73 74" style="enable-background:new 0 0 73 74;" xml:space="preserve">
<style type="text/css">
.st0{fill:#E3E3E3;}
.st1{fill:none;stroke:#CCCCCC;}
.st2{fill:#B4B4B4;}
</style>
<g id="Ellipse_123-2" transform="translate(2933 475)">
<circle class="st0" cx="-2896.5" cy="-437.5" r="35"/>
<circle class="st1" cx="-2896.5" cy="-437.5" r="34.5"/>
</g>
<path class="st2" d="M40.25,43.44c-0.02-0.24-0.04-0.63-0.05-1.04c3.94-0.38,6.7-1.26,6.7-2.29c-0.01,0-0.01-0.04-0.01-0.06
c-2.94-2.48,2.55-20.09-7.68-19.73c-0.64-0.51-1.77-0.96-3.38-0.96c-13.86,0.98-7.73,17.61-10.89,20.75c0,0,0,0-0.01,0
c0,0,0,0,0,0.01c0,0,0,0,0,0s0,0,0,0c0.01,1.01,2.68,1.87,6.51,2.26c-0.01,0.25-0.03,0.55-0.08,1.06
c-1.59,3.99-12.3,2.87-12.8,10.56H53C52.51,46.31,41.84,47.43,40.25,43.44z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,7 @@
<svg id="enter" xmlns="http://www.w3.org/2000/svg" width="42" height="42" viewBox="0 0 42 42">
<path id="Path_1146" data-name="Path 1146" d="M17.938,210.625H1.313a1.313,1.313,0,1,1,0-2.625H17.938a1.313,1.313,0,1,1,0,2.625Zm0,0" transform="translate(22.749 -190.938)"/>
<path id="Path_1147" data-name="Path 1147" d="M123.984,143.736a1.313,1.313,0,0,1-.928-2.242l5.635-5.635-5.635-5.633a1.313,1.313,0,0,1,1.857-1.857l6.563,6.562a1.313,1.313,0,0,1,0,1.857l-6.562,6.562A1.31,1.31,0,0,1,123.984,143.736Zm0,0" transform="translate(-89.86 -117.486)"/>
<path id="Path_1148" data-name="Path 1148" d="M312.668,42.076a3.5,3.5,0,0,0,3.5-3.5V7.076A3.522,3.522,0,0,0,313.8,3.753L303.284.248a3.537,3.537,0,0,0-4.616,3.329v31.5a3.524,3.524,0,0,0,2.368,3.321L311.553,41.9A3.662,3.662,0,0,0,312.668,42.076ZM302.168,2.7a1.03,1.03,0,0,1,.313.046l10.47,3.491a.9.9,0,0,1,.592.838v31.5a.922.922,0,0,1-1.188.83l-10.47-3.491a.905.905,0,0,1-.591-.838V3.576A.876.876,0,0,1,302.168,2.7Zm0,0" transform="translate(-298.668 -0.076)"/>
<path id="Path_1149" data-name="Path 1149" d="M195.168,8.75a1.313,1.313,0,0,0,1.313-1.312V4.813A4.816,4.816,0,0,0,191.668,0H171.98a1.313,1.313,0,0,0,0,2.625h19.688a2.19,2.19,0,0,1,2.187,2.188V7.438A1.313,1.313,0,0,0,195.168,8.75Zm0,0" transform="translate(-168.48)"/>
<path id="Path_1150" data-name="Path 1150" d="M171.98,350.082h7a4.816,4.816,0,0,0,4.812-4.813v-2.625a1.313,1.313,0,0,0-2.625,0v2.625a2.19,2.19,0,0,1-2.187,2.188h-7a1.313,1.313,0,0,0,0,2.625Zm0,0" transform="translate(-155.793 -313.332)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 940 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 969 B

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 73 74" style="enable-background:new 0 0 73 74;" xml:space="preserve">
<style type="text/css">
.st0{fill:#E3E3E3;}
.st1{fill:none;stroke:#CCCCCC;}
.st2{fill:#B4B4B4;}
</style>
<g id="Ellipse_123-2" transform="translate(2933 475)">
<circle class="st0" cx="-2896.5" cy="-437.5" r="35"/>
<circle class="st1" cx="-2896.5" cy="-437.5" r="34.5"/>
</g>
<path id="Icon_awesome-user-alt" class="st2" d="M36.5,39.75c5.59,0,10.13-4.53,10.13-10.13S42.09,19.5,36.5,19.5
s-10.13,4.53-10.13,10.13C26.38,35.22,30.91,39.75,36.5,39.75z M45.5,42h-3.87c-3.25,1.5-7,1.5-10.25,0H27.5c-4.97,0-9,4.03-9,9
v1.13c0,1.86,1.51,3.37,3.38,3.38h29.25c1.86,0,3.37-1.51,3.38-3.38V51C54.5,46.03,50.47,42,45.5,42z"/>
</svg>

After

Width:  |  Height:  |  Size: 970 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="28.123" height="26.245" viewBox="0 0 28.123 26.245">
<path id="XMLID_219_" d="M28.984,15.637A2.077,2.077,0,0,1,27.025,17h-.716V27.309a.938.938,0,0,1-.937.937H19.748V21.685a4.687,4.687,0,0,0-9.374,0v6.562H4.749a.938.938,0,0,1-.937-.937V17H3.095a2.1,2.1,0,0,1-1.378-3.675L12.665,2.955a3.486,3.486,0,0,1,4.792,0L28.431,13.347A2.066,2.066,0,0,1,28.984,15.637Z" transform="translate(-0.999 -2.001)" fill="#2e303a"/>
</svg>

Before

Width:  |  Height:  |  Size: 467 B

@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24.899" height="24.899" viewBox="0 0 24.899 24.899">
<g id="Layer_76" data-name="Layer 76" transform="translate(-2 -2)">
<path id="Path_4380" data-name="Path 4380" d="M3.245,11.96A1.245,1.245,0,0,0,4.49,10.715V5.735A1.245,1.245,0,0,1,5.735,4.49h4.98a1.245,1.245,0,1,0,0-2.49H5.735A3.735,3.735,0,0,0,2,5.735v4.98A1.245,1.245,0,0,0,3.245,11.96Z" transform="translate(0 0)" fill="#2e303a"/>
<path id="Path_4381" data-name="Path 4381" d="M20.225,2h-4.98a1.245,1.245,0,0,0,0,2.49h4.98A1.245,1.245,0,0,1,21.47,5.735v4.98a1.245,1.245,0,1,0,2.49,0V5.735A3.735,3.735,0,0,0,20.225,2Z" transform="translate(2.94 0)" fill="#2e303a"/>
<path id="Path_4382" data-name="Path 4382" d="M22.715,14a1.245,1.245,0,0,0-1.245,1.245v4.98a1.245,1.245,0,0,1-1.245,1.245h-4.98a1.245,1.245,0,0,0,0,2.49h4.98a3.735,3.735,0,0,0,3.735-3.735v-4.98A1.245,1.245,0,0,0,22.715,14Z" transform="translate(2.94 2.94)" fill="#2e303a"/>
<path id="Path_4383" data-name="Path 4383" d="M10.715,21.47H5.735A1.245,1.245,0,0,1,4.49,20.225v-4.98a1.245,1.245,0,0,0-2.49,0v4.98A3.735,3.735,0,0,0,5.735,23.96h4.98a1.245,1.245,0,1,0,0-2.49Z" transform="translate(0 2.94)" fill="#2e303a"/>
<rect id="Rectangle_17370" data-name="Rectangle 17370" width="15" height="15" rx="2" transform="translate(7 6.899)" fill="#2e303a"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="26.552" height="20.755" viewBox="0 0 26.552 20.755">
<g id="mail-reply" transform="translate(0 -40.338)">
<path id="Path_4384" data-name="Path 4384" d="M21.236,51.705h.129a1.8,1.8,0,0,1,2.761-2.272l.788.788V42.437a2.1,2.1,0,0,0-2.1-2.1H2.1a2.1,2.1,0,0,0-2.1,2.1V56.921a2.1,2.1,0,0,0,2.1,2.1H16.575a5.14,5.14,0,0,1,4.66-7.314ZM5.213,43.167H19.7l-7.244,5.312Z" fill="#2e303a"/>
<path id="Path_4385" data-name="Path 4385" d="M245.767,175.159l-2.8-2.8a.9.9,0,1,0-1.27,1.27l1.265,1.265h-2.25a4.245,4.245,0,0,0,0,8.489.9.9,0,1,0,0-1.8,2.448,2.448,0,0,1,0-4.9h2.25l-1.265,1.265a.9.9,0,0,0,1.27,1.27l2.8-2.8a.9.9,0,0,0,0-1.27Z" transform="translate(-219.478 -122.292)" fill="#2e303a"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 749 B

@ -1,3 +0,0 @@
<svg id="weekly-calendar-page-symbol" xmlns="http://www.w3.org/2000/svg" width="25.034" height="25.034" viewBox="0 0 25.034 25.034">
<path id="Path_4379" data-name="Path 4379" d="M22.53,0H2.5A2.511,2.511,0,0,0,0,2.5V22.53a2.512,2.512,0,0,0,2.5,2.5H22.53a2.512,2.512,0,0,0,2.5-2.5V2.5A2.511,2.511,0,0,0,22.53,0ZM6.756,22.031H2.921V18.62H6.756v3.411Zm0-4.555H2.921v-3.41H6.756v3.41ZM6.467,3.794A1.063,1.063,0,1,1,7.529,2.731,1.062,1.062,0,0,1,6.467,3.794Zm5.406,18.237H8.039V18.62h3.834Zm0-4.555H8.039v-3.41h3.834Zm0-4.552H8.039V9.514h3.834ZM11.455,2.731a1.062,1.062,0,1,1,1.062,1.062A1.062,1.062,0,0,1,11.455,2.731Zm5.54,14.745H13.159v-3.41H17v3.41Zm0-4.552H13.159V9.514H17v3.41ZM17.5,2.731a1.062,1.062,0,1,1,1.062,1.062A1.062,1.062,0,0,1,17.5,2.731Zm4.609,14.745H18.278v-3.41h3.835Zm0-4.552H18.278V9.514h3.835Z" fill="#2e303a"/>
</svg>

Before

Width:  |  Height:  |  Size: 838 B

@ -1,57 +0,0 @@
<svg id="woman_2_" data-name="woman (2)" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
<g id="Group_7145" data-name="Group 7145">
<g id="Group_7144" data-name="Group 7144">
<g id="Group_7143" data-name="Group 7143">
<g id="Group_7142" data-name="Group 7142">
<g id="XMLID_2114_">
<g id="XMLID_2115_">
<g id="XMLID_2116_">
<g id="XMLID_2117_">
<g id="XMLID_2118_">
<g id="XMLID_2119_">
<g id="XMLID_2120_">
<g id="XMLID_2121_">
<g id="XMLID_2122_">
<g id="XMLID_2123_">
<g id="XMLID_2124_">
<g id="XMLID_2125_">
<g id="XMLID_2126_">
<g id="XMLID_2127_">
<g id="Group_7141" data-name="Group 7141">
<path id="Path_4450" data-name="Path 4450" d="M48,24a23.928,23.928,0,0,1-6.947,16.887C36.7,45.279,30.669,42.776,24,42.776s-12.7,2.5-17.053-1.889A24,24,0,1,1,48,24Z" fill="#e2e2e2"/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
<path id="Path_4451" data-name="Path 4451" d="M48,24q0-1.087-.1-2.151L33.541,7.485,14.75,23.632,31.62,40.5l1.688,2.974c2.921.089,5.548-.37,7.745-2.589A23.928,23.928,0,0,0,48,24Z" fill="#c4c4c4"/>
<path id="Path_4452" data-name="Path 4452" d="M24,3.287C20.723,2.9,8.986,6.052,12.5,19.837c.924,3.622,4.646,5.913,6.284,6.51,2.5.913,2.742-.517,5.214-2.007,2.472,1.49,2.71,2.919,5.214,2.007,1.638-.6,5.36-2.888,6.284-6.51C39.014,6.052,27.277,2.9,24,3.287Z" fill="#515151"/>
<path id="Path_4453" data-name="Path 4453" d="M35.5,19.838c-.924,3.622-4.646,5.913-6.284,6.51-2.5.913-2.742-.517-5.213-2.007V3.287C27.277,2.9,39.014,6.052,35.5,19.837Z" fill="#3d3d3d"/>
<path id="Path_4454" data-name="Path 4454" d="M18.747,23.459H29.253V34.6H18.747Z" fill="#eaa678"/>
<path id="Path_4455" data-name="Path 4455" d="M24,23.46h5.253V34.6H24Z" fill="#d38c5b"/>
<path id="Path_4456" data-name="Path 4456" d="M18.747,30.452H29.253V41.593H18.747Z" fill="#ffc397"/>
<path id="Path_4457" data-name="Path 4457" d="M24,30.452h5.253V41.593H24Z" fill="#eaa678"/>
<path id="Path_4458" data-name="Path 4458" d="M41.053,35.918v4.969a24,24,0,0,1-34.106,0V35.918a5.466,5.466,0,0,1,5.466-5.467h6.335L24,37.18l5.253-6.728h6.335A5.466,5.466,0,0,1,41.053,35.918Z" fill="#d02127"/>
<path id="Path_4459" data-name="Path 4459" d="M41.053,35.918v4.969A23.925,23.925,0,0,1,24,48V37.18l5.253-6.728h6.335A5.466,5.466,0,0,1,41.053,35.918Z" fill="#aa191e"/>
<path id="Path_4460" data-name="Path 4460" d="M28.256,39.447a2.908,2.908,0,0,0-1.3,2.649c.172,1.751,2.3,3.292,2.3,3.292s3.4-3.062,2.069-5.94l-1.446-.556Z" fill="#3d3d3d"/>
<path id="Path_4461" data-name="Path 4461" d="M32.274,14.271C31.924,8.965,27.632,7,24,7s-7.924,1.961-8.274,7.267a2.285,2.285,0,0,0-1.5,2.409l.161,2.267a1.875,1.875,0,0,0,2.043,1.7l.175-.019c2.076,5.573,5.33,6.154,7.4,6.48,2.066-.326,5.321-.907,7.4-6.48l.175.019a1.875,1.875,0,0,0,2.043-1.7l.161-2.267A2.285,2.285,0,0,0,32.274,14.271Z" fill="#ffc397"/>
<path id="Path_4462" data-name="Path 4462" d="M33.775,16.681l-.161,2.267a1.875,1.875,0,0,1-2.043,1.7l-.175-.019a11.863,11.863,0,0,1-2.445,4.151A7.942,7.942,0,0,1,24,27.1V7c3.632,0,7.924,1.961,8.274,7.267a2.285,2.285,0,0,1,1.5,2.409Z" fill="#eaa678"/>
<path id="Path_4463" data-name="Path 4463" d="M24,4.977c-5.521-1.2-9.452,2.277-9.539,6.282a10.3,10.3,0,0,0,3.027,6.969c-.053-3.326,1-4.7,3.062-5.438A8.7,8.7,0,0,0,24,9.96a8.7,8.7,0,0,0,3.45,2.83c2.059.739,3.115,2.112,3.062,5.438a10.3,10.3,0,0,0,3.027-6.969C33.452,7.253,29.521,3.772,24,4.977Z" fill="#515151"/>
<path id="Path_4464" data-name="Path 4464" d="M33.539,11.259a10.305,10.305,0,0,1-3.027,6.968c.052-3.326-1-4.7-3.062-5.437A8.7,8.7,0,0,1,24,9.96V4.976C29.521,3.772,33.452,7.253,33.539,11.259Z" fill="#3d3d3d"/>
<path id="Path_4465" data-name="Path 4465" d="M33.389,27.8a6.76,6.76,0,0,0-.026-5.35l-3.618,2.514a2.626,2.626,0,0,0-.524.48,2.882,2.882,0,0,0-.2,3.919,3.365,3.365,0,0,0-.367.422,2.833,2.833,0,0,0,.006,3.69c-.043.042-.085.086-.124.132-2.549,2.97.917,5.083.917,5.083a5.421,5.421,0,0,0,3.554-6.78A6.03,6.03,0,0,0,33.389,27.8Z" fill="#3d3d3d"/>
<path id="Path_4466" data-name="Path 4466" d="M31.27,39.657H28.377a.7.7,0,0,1-.7-.7V37.87a.7.7,0,0,1,.7-.7H31.27a.7.7,0,0,1,.7.7v1.087A.7.7,0,0,1,31.27,39.657Z" fill="#d02127"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.9 KiB

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12.179" height="12.188" viewBox="0 0 12.179 12.188">
<path id="Path_4406" data-name="Path 4406" d="M12.039,10.586c1.24-1.24,1.644-1.48,1.348-1.776L12.38,7.8a.3.3,0,0,0-.427,0L10.6,9.152l-.976-.976A4.378,4.378,0,1,0,8.2,9.615l.973.972c-1.24,1.24-1.644,1.48-1.348,1.776L8.828,13.37a.3.3,0,0,0,.427,0L10.6,12.022c1.457,1.457,1.679,1.847,1.977,1.55.97-.97,1.1-1.02,1.1-1.222s-.058-.183-1.638-1.764ZM5.892,8.77a2.9,2.9,0,1,1,2.9-2.9A2.9,2.9,0,0,1,5.892,8.77Z" transform="translate(-1.498 -1.476)" fill="#f0448d"/>
</svg>

Before

Width:  |  Height:  |  Size: 565 B

@ -1,4 +0,0 @@
<svg id="hospital_3_" data-name="hospital (3)" xmlns="http://www.w3.org/2000/svg" width="20.5" height="20.5" viewBox="0 0 20.5 20.5">
<path id="Path_4585" data-name="Path 4585" d="M19.9,182.442a.6.6,0,0,0-.6.6v3H18a2.982,2.982,0,0,0-2.921-2.4H8.648v.578L7.413,184.2a3.059,3.059,0,0,0-2.577-.643,1.8,1.8,0,1,0-3.512-.652l-.123-.077V180.6a.6.6,0,0,0-1.2,0v12.092a.6.6,0,0,0,1.2,0v-3H19.3v3a.6.6,0,0,0,1.2,0v-9.649A.6.6,0,0,0,19.9,182.442Zm-18.7,3.6v-1.8l2.853,1.8Z" transform="translate(0 -172.793)" fill="#28323a"/>
<path id="Path_4586" data-name="Path 4586" d="M136.6,1.842h1.2v1.2h-.6a.6.6,0,0,0-.6.6v1.2a1.8,1.8,0,0,0,3.6,0v-1.2a.6.6,0,0,0-.6-.6H139v-1.2h2.4V9.649h1.2V.6a.6.6,0,1,0-1.2.04h-4.8a.6.6,0,0,0,0,1.2Z" transform="translate(-130.555)" fill="#28323a"/>
</svg>

Before

Width:  |  Height:  |  Size: 776 B

@ -1,56 +0,0 @@
<svg id="man_5_" data-name="man (5)" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
<g id="Group_7139" data-name="Group 7139">
<g id="Group_7138" data-name="Group 7138">
<g id="Group_7137" data-name="Group 7137">
<g id="Group_7136" data-name="Group 7136">
<g id="XMLID_2211_">
<g id="XMLID_2212_">
<g id="XMLID_2213_">
<g id="XMLID_2214_">
<g id="XMLID_2215_">
<g id="XMLID_2216_">
<g id="XMLID_2217_">
<g id="XMLID_2218_">
<g id="XMLID_2219_">
<g id="XMLID_2220_">
<g id="XMLID_2221_">
<g id="XMLID_2222_">
<g id="XMLID_2223_">
<g id="XMLID_2224_">
<g id="XMLID_2225_">
<path id="Path_4436" data-name="Path 4436" d="M0,24A24,24,0,1,1,42.887,38.81c-4.394,5.6-11.221,3.983-18.887,3.983S9.507,44.405,5.113,38.81A23.9,23.9,0,0,1,0,24Z" fill="#e2e2e2"/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
<path id="Path_4437" data-name="Path 4437" d="M42.887,38.81A23.9,23.9,0,0,0,48,24q0-.493-.02-.982L34.651,9.689C26.856,6.362,15.212,20.337,15.212,20.337l9.778,9.778,4.217,12.829C34.718,43.153,39.518,43.1,42.887,38.81Z" fill="#c4c4c4"/>
<g id="Group_7140" data-name="Group 7140">
<path id="Path_4438" data-name="Path 4438" d="M18.747,23.459H29.253V34.6H18.747Z" fill="#eaa678"/>
<path id="Path_4439" data-name="Path 4439" d="M24,23.46h5.253V34.6H24Z" fill="#d38c5b"/>
<path id="Path_4440" data-name="Path 4440" d="M32.43,46.477a23.683,23.683,0,0,1-3.177.946,24.178,24.178,0,0,1-10.506,0,23.683,23.683,0,0,1-3.177-.946l3.177-16.024L24,33.857l5.253-3.4Z" fill="#d02127"/>
<path id="Path_4441" data-name="Path 4441" d="M32.43,46.477a23.683,23.683,0,0,1-3.177.946A24,24,0,0,1,24,48V33.857l5.253-3.4Z" fill="#aa191e"/>
<path id="Path_4442" data-name="Path 4442" d="M18.747,30.452V47.423A24,24,0,0,1,5.113,38.81V35.741A5.289,5.289,0,0,1,10.4,30.452Z" fill="#2b353e"/>
<path id="Path_4443" data-name="Path 4443" d="M42.887,35.741V38.81a24,24,0,0,1-13.634,8.613V30.452H37.6A5.289,5.289,0,0,1,42.887,35.741Z" fill="#2b353e"/>
<path id="Path_4444" data-name="Path 4444" d="M13.7,39.923v5.761a23.726,23.726,0,0,1-3.023-1.717V39.923Z" fill="#989898"/>
<path id="Path_4445" data-name="Path 4445" d="M37.362,39.923v4.016a23.888,23.888,0,0,1-3.023,1.725V39.923Z" fill="#989898"/>
<path id="Path_4446" data-name="Path 4446" d="M32.274,14.271C31.924,8.965,27.632,7,24,7s-7.924,1.961-8.274,7.267a2.285,2.285,0,0,0-1.5,2.409l.161,2.267a1.875,1.875,0,0,0,2.043,1.7l.175-.019c2.075,5.573,5.33,6.154,7.4,6.48,2.066-.326,5.321-.907,7.4-6.48l.175.019a1.875,1.875,0,0,0,2.043-1.7l.161-2.267A2.285,2.285,0,0,0,32.274,14.271Z" fill="#ffc397"/>
<path id="Path_4447" data-name="Path 4447" d="M33.775,16.681l-.161,2.267a1.875,1.875,0,0,1-2.043,1.7l-.175-.019a11.863,11.863,0,0,1-2.445,4.151A7.942,7.942,0,0,1,24,27.1V7c3.632,0,7.924,1.961,8.274,7.267a2.285,2.285,0,0,1,1.5,2.409Z" fill="#eaa678"/>
<path id="Path_4448" data-name="Path 4448" d="M34.651,9.689A13.957,13.957,0,0,0,24,4.41a8.424,8.424,0,0,0-4.772,1.436c-.026,0-3.178-.265-4.44,1.943s-.107,6.613,1.16,8.619L17.426,17.7l.68-4.473a17.48,17.48,0,0,0,11.514-.762l.8,5.234,1.478-1.294A12.875,12.875,0,0,0,33.6,10.422C34.277,9.986,34.651,9.689,34.651,9.689Z" fill="#515151"/>
<path id="Path_4449" data-name="Path 4449" d="M29.619,12.467l.8,5.234,1.478-1.294A12.875,12.875,0,0,0,33.6,10.422c.677-.436,1.051-.733,1.051-.733A13.956,13.956,0,0,0,24,4.41v9.415A19.77,19.77,0,0,0,29.619,12.467Z" fill="#3d3d3d"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

@ -1,3 +0,0 @@
<svg id="_14._Men_sign" data-name="14. Men sign" xmlns="http://www.w3.org/2000/svg" width="12.739" height="12.739" viewBox="0 0 12.739 12.739">
<path id="Path_4403" data-name="Path 4403" d="M13.928,1.5H8.757a.313.313,0,0,0-.313.313V3.2a.313.313,0,0,0,.313.313h1.988l-2.3,2.3A4.553,4.553,0,1,0,9.93,7.3l2.3-2.3V6.984a.313.313,0,0,0,.313.313h1.383a.313.313,0,0,0,.313-.313V1.813a.313.313,0,0,0-.313-.313ZM6.057,12.687a3,3,0,1,1,3-3,3,3,0,0,1-3,3Z" transform="translate(-1.502 -1.5)" fill="#1474d5"/>
</svg>

Before

Width:  |  Height:  |  Size: 507 B

@ -1,19 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22.631" height="6.466" viewBox="0 0 22.631 6.466">
<g id="more_1_" data-name="more (1)" transform="translate(0 -170.666)">
<g id="Group_7031" data-name="Group 7031" transform="translate(0 170.666)">
<g id="Group_7030" data-name="Group 7030" transform="translate(0 0)">
<circle id="Ellipse_145" data-name="Ellipse 145" cx="3.233" cy="3.233" r="3.233"/>
</g>
</g>
<g id="Group_7033" data-name="Group 7033" transform="translate(8.082 170.666)">
<g id="Group_7032" data-name="Group 7032" transform="translate(0 0)">
<circle id="Ellipse_146" data-name="Ellipse 146" cx="3.233" cy="3.233" r="3.233"/>
</g>
</g>
<g id="Group_7035" data-name="Group 7035" transform="translate(16.165 170.666)">
<g id="Group_7034" data-name="Group 7034" transform="translate(0 0)">
<circle id="Ellipse_147" data-name="Ellipse 147" cx="3.233" cy="3.233" r="3.233"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 996 B

@ -1,69 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="118.141" height="107.644" viewBox="0 0 118.141 107.644">
<g id="content" transform="translate(0 -22.748)">
<g id="Group_7442" data-name="Group 7442" transform="translate(1.731 28.436)">
<g id="Group_7439" data-name="Group 7439" transform="translate(0 8.932)">
<g id="Group_7438" data-name="Group 7438">
<g id="Group_7434" data-name="Group 7434" transform="translate(0 21.014)">
<g id="Group_7430" data-name="Group 7430" transform="translate(63.164)">
<g id="Group_7429" data-name="Group 7429">
<path id="Path_4552" data-name="Path 4552" d="M332.756,179.321v66a2.139,2.139,0,0,1-2.141,2.139H283.381a2.141,2.141,0,0,1-2.141-2.139v-66a2.143,2.143,0,0,1,2.141-2.141h47.233a2.141,2.141,0,0,1,2.141,2.141Z" transform="translate(-281.24 -177.18)" fill="#fff"/>
<g id="Group_7428" data-name="Group 7428">
<path id="Path_4553" data-name="Path 4553" d="M304.644,177.18v63.254a2.475,2.475,0,0,1-2.476,2.476H281.24V179.321a2.143,2.143,0,0,1,2.141-2.141Z" transform="translate(-281.24 -177.18)" fill="#dbdbdb"/>
<path id="Path_4554" data-name="Path 4554" d="M332.758,195.96V179.322a2.141,2.141,0,0,0-2.141-2.141H283.384a2.141,2.141,0,0,0-2.141,2.141V195.96Z" transform="translate(-281.242 -177.18)" fill="#dbdbdb"/>
<path id="Path_4555" data-name="Path 4555" d="M473.157,179.319v66a2.14,2.14,0,0,1-2.141,2.141h-7.26a2.14,2.14,0,0,0,2.141-2.141v-66a2.141,2.141,0,0,0-2.141-2.141h7.26A2.141,2.141,0,0,1,473.157,179.319Z" transform="translate(-421.642 -177.178)" fill="#dbdbdb"/>
</g>
<path id="Path_4556" data-name="Path 4556" d="M332.756,179.321V189.4H281.24V179.321a2.143,2.143,0,0,1,2.141-2.141h47.233A2.141,2.141,0,0,1,332.756,179.321Z" transform="translate(-281.24 -177.18)" fill="#d02127"/>
<path id="Path_4557" data-name="Path 4557" d="M371.453,179.57a6.171,6.171,0,1,1-11.863-2.391h11.383A6.141,6.141,0,0,1,371.453,179.57Z" transform="translate(-341.142 -177.18)" fill="#d02127"/>
<path id="Path_4558" data-name="Path 4558" d="M473.157,179.319v10.075H465.9V179.319a2.141,2.141,0,0,0-2.141-2.141h7.26A2.141,2.141,0,0,1,473.157,179.319Z" transform="translate(-421.642 -177.178)" fill="#d02127"/>
</g>
</g>
<g id="Group_7433" data-name="Group 7433">
<g id="Group_7432" data-name="Group 7432">
<path id="Path_4559" data-name="Path 4559" d="M59.016,179.321v66a2.141,2.141,0,0,1-2.141,2.139H9.641A2.139,2.139,0,0,1,7.5,245.319v-66a2.141,2.141,0,0,1,2.141-2.141H56.875a2.143,2.143,0,0,1,2.141,2.141Z" transform="translate(-7.5 -177.18)" fill="#fff"/>
<g id="Group_7431" data-name="Group 7431" transform="translate(0)">
<path id="Path_4560" data-name="Path 4560" d="M148.988,179.321V242.91H126.936a2.476,2.476,0,0,1-2.476-2.476V177.18h22.387a2.143,2.143,0,0,1,2.141,2.141Z" transform="translate(-97.472 -177.18)" fill="#dbdbdb"/>
<path id="Path_4561" data-name="Path 4561" d="M59.015,195.96V179.322a2.141,2.141,0,0,0-2.141-2.141H9.641A2.141,2.141,0,0,0,7.5,179.322V195.96Z" transform="translate(-7.5 -177.18)" fill="#dbdbdb"/>
<path id="Path_4562" data-name="Path 4562" d="M199.413,179.319v66a2.14,2.14,0,0,1-2.141,2.141h-7.26a2.14,2.14,0,0,0,2.141-2.141v-66a2.141,2.141,0,0,0-2.141-2.141h7.26A2.141,2.141,0,0,1,199.413,179.319Z" transform="translate(-147.898 -177.178)" fill="#dbdbdb"/>
</g>
<path id="Path_4563" data-name="Path 4563" d="M59.015,189.4H7.5V179.323a2.141,2.141,0,0,1,2.141-2.141H56.875a2.141,2.141,0,0,1,2.141,2.141Z" transform="translate(-7.5 -177.181)" fill="#d02127"/>
<path id="Path_4564" data-name="Path 4564" d="M199.413,179.319v10.075h-7.26V179.319a2.141,2.141,0,0,0-2.141-2.141h7.26A2.141,2.141,0,0,1,199.413,179.319Z" transform="translate(-147.898 -177.178)" fill="#20bfd5"/>
</g>
</g>
</g>
<g id="Group_7437" data-name="Group 7437" transform="translate(26.988)">
<g id="Group_7436" data-name="Group 7436">
<path id="Path_4565" data-name="Path 4565" d="M181.569,167.391H126.94a2.476,2.476,0,0,1-2.476-2.476V88.586a2.476,2.476,0,0,1,2.476-2.476h54.629a2.476,2.476,0,0,1,2.476,2.476v76.329A2.476,2.476,0,0,1,181.569,167.391Z" transform="translate(-124.463 -86.109)" fill="#fff"/>
<path id="Path_4566" data-name="Path 4566" d="M184.044,106.725V88.586a2.476,2.476,0,0,0-2.476-2.476H126.94a2.476,2.476,0,0,0-2.476,2.476v18.14Z" transform="translate(-124.463 -86.109)" fill="#dbdbdb"/>
<path id="Path_4567" data-name="Path 4567" d="M346.423,88.582v76.33a2.475,2.475,0,0,1-2.476,2.476h-8.4a2.475,2.475,0,0,0,2.476-2.476V88.582a2.476,2.476,0,0,0-2.476-2.476h8.4A2.476,2.476,0,0,1,346.423,88.582Z" transform="translate(-286.842 -86.106)" fill="#dbdbdb"/>
<path id="Path_4568" data-name="Path 4568" d="M184.041,88.586v11.653H124.46V88.586a2.476,2.476,0,0,1,2.476-2.476h54.629A2.475,2.475,0,0,1,184.041,88.586Z" transform="translate(-124.46 -86.109)" fill="#d02127"/>
<g id="Group_7435" data-name="Group 7435" transform="translate(37.747)">
<path id="Path_4569" data-name="Path 4569" d="M299.01,88.138a5.48,5.48,0,1,1-10.57-2.028h10.18A5.435,5.435,0,0,1,299.01,88.138Z" transform="translate(-288.05 -86.109)" fill="#d02127"/>
<path id="Path_4570" data-name="Path 4570" d="M346.423,88.582v11.653h-8.4V88.582a2.476,2.476,0,0,0-2.476-2.476h8.4A2.476,2.476,0,0,1,346.423,88.582Z" transform="translate(-324.59 -86.106)" fill="#d02127"/>
</g>
</g>
</g>
</g>
</g>
<g id="Group_7440" data-name="Group 7440" transform="translate(81.132 21.147)">
<path id="Path_4571" data-name="Path 4571" d="M359.11,145.215a6.171,6.171,0,1,1,6.171,6.171,6.171,6.171,0,0,1-6.171-6.171" transform="translate(-359.11 -139.044)" fill="#d02127"/>
<path id="Path_4572" data-name="Path 4572" d="M372.29,150.533a5.46,5.46,0,0,0,0-10.638,6.173,6.173,0,1,1,0,10.638" transform="translate(-369.249 -139.044)" fill="#d02127"/>
</g>
<g id="Group_7441" data-name="Group 7441" transform="translate(64.735)">
<path id="Path_4573" data-name="Path 4573" d="M288.05,52.878a5.48,5.48,0,1,1,5.48,5.48,5.48,5.48,0,0,1-5.48-5.48" transform="translate(-288.05 -47.398)" fill="#d02127"/>
<path id="Path_4574" data-name="Path 4574" d="M299.754,57.6a4.849,4.849,0,0,0,0-9.446,5.481,5.481,0,1,1,0,9.446" transform="translate(-297.053 -47.397)" fill="#d02127"/>
</g>
</g>
<g id="Group_7443" data-name="Group 7443" transform="translate(0 22.748)">
<path id="Path_4575" data-name="Path 4575" d="M114.27,69.844H96.883a7.887,7.887,0,0,0-6.853-8.735V53.036a4.211,4.211,0,0,0-4.206-4.206H78.948a7.211,7.211,0,1,0-14,0H31.2a4.211,4.211,0,0,0-4.206,4.206V69.844H21.93a1.731,1.731,0,0,0,0,3.461h5.058V82.06H3.461V73.716a.411.411,0,0,1,.41-.41h9.515a1.731,1.731,0,0,0,0-3.461H3.871A3.876,3.876,0,0,0,0,73.716v66a3.876,3.876,0,0,0,3.871,3.871H51.105a3.876,3.876,0,0,0,3.871-3.871v-6.14h8.188v6.14a3.876,3.876,0,0,0,3.871,3.871H81.123a1.731,1.731,0,0,0,0-3.461H67.036a.41.41,0,0,1-.41-.41v-6.14h19.2a4.211,4.211,0,0,0,4.206-4.206V85.521h24.65v54.191a.41.41,0,0,1-.41.41h-24.6a1.731,1.731,0,0,0,0,3.461h24.6a3.876,3.876,0,0,0,3.871-3.871v-66a3.876,3.876,0,0,0-3.871-3.871Zm-20.8-.9a4.441,4.441,0,1,1-4.441-4.441A4.446,4.446,0,0,1,93.475,68.946ZM71.946,43.358a3.75,3.75,0,1,1-3.75,3.75A3.754,3.754,0,0,1,71.946,43.358ZM31.2,52.291H66.941a7.192,7.192,0,0,0,10.011,0h8.873a.746.746,0,0,1,.745.745v8.4a7.9,7.9,0,0,0-2.683,1.519H30.45V53.036a.746.746,0,0,1,.745-.745Zm54.629,77.82H31.2a.746.746,0,0,1-.745-.745V109.979a1.731,1.731,0,0,0-3.461,0v19.386a4.211,4.211,0,0,0,4.206,4.206h20.32v6.14a.41.41,0,0,1-.41.41H3.871a.41.41,0,0,1-.41-.41V85.521H26.989v15.915a1.731,1.731,0,1,0,3.461,0V66.419h51.1a7.895,7.895,0,0,0,5.021,10.033v52.913A.746.746,0,0,1,85.824,130.111ZM90.03,82.06V76.783a7.909,7.909,0,0,0,5.59-3.478h18.65a.41.41,0,0,1,.41.41V82.06H90.03Z" transform="translate(0 -35.94)" fill="#2e303a"/>
<path id="Path_4576" data-name="Path 4576" d="M238.224,296.64a8.143,8.143,0,0,0-5.276-1.877h-.027a8.138,8.138,0,0,0-5.261,1.846,1.73,1.73,0,1,0,2.231,2.646,4.746,4.746,0,0,1,3.03-1.03h.015a4.75,4.75,0,0,1,3.04,1.048,1.731,1.731,0,0,0,2.247-2.633Z" transform="translate(-174.656 -231.997)"/>
<path id="Path_4577" data-name="Path 4577" d="M288.664,267.015l-.045,0h-.03a1.73,1.73,0,0,0-.156,3.452l.039,0c.042,0,.085.007.128.007h.01a1.73,1.73,0,0,0,.054-3.459Z" transform="translate(-220.675 -210.65)"/>
<path id="Path_4578" data-name="Path 4578" d="M207.009,267.012h-.03a1.731,1.731,0,0,0,.011,3.461H207a1.731,1.731,0,0,0,.009-3.461Z" transform="translate(-157.897 -210.65)"/>
<path id="Path_4579" data-name="Path 4579" d="M156.674,112.612h.009c.038,0,.077,0,.115.006l.062,0h.009a1.73,1.73,0,0,0,.346-3.426h-.007c-.053-.011-.108-.019-.162-.025-.02,0-.04,0-.06,0-.036,0-.072-.006-.109-.006h-.031a1.721,1.721,0,0,0-1.722,1.731,1.738,1.738,0,0,0,1.549,1.719Z" transform="translate(-119.331 -89.223)"/>
<path id="Path_4580" data-name="Path 4580" d="M179.553,112.623a1.731,1.731,0,0,0,0-3.461h-.021a1.722,1.722,0,0,0-1.72,1.731A1.74,1.74,0,0,0,179.553,112.623Z" transform="translate(-136.783 -89.223)"/>
<path id="Path_4581" data-name="Path 4581" d="M202.243,112.623a1.731,1.731,0,0,0,0-3.461h-.021a1.722,1.722,0,0,0-1.72,1.731A1.74,1.74,0,0,0,202.243,112.623Z" transform="translate(-154.237 -89.223)"/>
<path id="Path_4582" data-name="Path 4582" d="M53.4,116.408a1.73,1.73,0,0,0,2.447,0l.922-.922.922.922a1.73,1.73,0,0,0,2.447-2.447l-.922-.922.922-.922A1.73,1.73,0,0,0,57.7,109.67l-.922.922-.922-.922a1.73,1.73,0,0,0-2.447,2.447l.922.922-.922.922A1.73,1.73,0,0,0,53.4,116.408Z" transform="translate(-40.692 -89.223)"/>
<path id="Path_4583" data-name="Path 4583" d="M428.867,107.109a1.73,1.73,0,0,0,2.447,0l.922-.922.922.922a1.73,1.73,0,0,0,2.447-2.447l-.922-.922.922-.922a1.73,1.73,0,0,0-2.447-2.447l-.922.922-.922-.922a1.73,1.73,0,1,0-2.447,2.447l.922.922-.922.922A1.73,1.73,0,0,0,428.867,107.109Z" transform="translate(-329.518 -82.07)"/>
<path id="Path_4584" data-name="Path 4584" d="M237.941,29.993a1.73,1.73,0,0,0,2.447,0l.922-.922.922.922a1.73,1.73,0,0,0,2.447-2.447l-.922-.922.922-.922a1.73,1.73,0,0,0-2.447-2.447l-.922.922-.922-.922a1.73,1.73,0,1,0-2.447,2.447l.922.922-.922.922A1.73,1.73,0,0,0,237.941,29.993Z" transform="translate(-182.648 -22.748)"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="25.347" height="25.347" viewBox="0 0 25.347 25.347">
<path id="ekg-monitor" d="M.878,0H24.471a.878.878,0,0,1,.877.877V11.77l-7.647,0a.906.906,0,0,0-.845.582l-1.678,4.393L10.98,5.741a.9.9,0,0,0-.846-.583h0a.9.9,0,0,0-.846.582L6.982,11.774,0,11.77V.878A.878.878,0,0,1,.878,0ZM24.471,25.348a.878.878,0,0,0,.877-.877V13.58l-7.023,0-2.3,6.026a.905.905,0,0,1-1.692,0L10.133,8.6,8.451,13a.906.906,0,0,1-.846.582h0l-7.6,0V24.471a.878.878,0,0,0,.877.877H24.471Z" transform="translate(-0.001 -0.001)" fill="#28323a" fill-rule="evenodd"/>
</svg>

Before

Width:  |  Height:  |  Size: 584 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save