Compare commits

..

No commits in common. 'development' and 'video-stream-floating' have entirely different histories.

@ -28,14 +28,14 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 30
signingConfigs {
release {
storeFile file('/Users/nextwo/Desktop/Elham/keys/doctor app key')
storePassword 'Hmgdoctor1234'
keyAlias 'hmgdoctor'
keyPassword 'Hmgdoctor1234'
}
}
// signingConfigs {
// release {
// storeFile file('C:\\Users\\admin\\Downloads\\DQKey.jks')
// storePassword 'HmGsa123'
// keyAlias 'key'
// keyPassword 'HmGsa123'
// }
// }
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@ -59,8 +59,7 @@ android {
buildTypes {
release {
// TODO: Add your own signing config for the release build.
signingConfig signingConfigs.release
signingConfig signingConfigs.debug
}
debug {
// Signing with the debug keys for now, so `flutter run --release` works.
@ -111,6 +110,5 @@ dependencies {
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'

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

@ -30,7 +30,7 @@
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:name=".AppApplication"
android:name="AppApplication"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
tools:replace="android:name"

@ -7,6 +7,6 @@ class AppApplication : FlutterApplication() {
override fun onCreate() {
super.onCreate()
// LoggingExceptionHandler(this, "ErrorFile")
LoggingExceptionHandler(this, "ErrorFile")
}
}

@ -6,7 +6,6 @@ import android.content.ComponentName
import android.content.Context
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
@ -16,10 +15,14 @@ import android.util.Log
import android.widget.Toast
import androidx.annotation.NonNull
import com.google.gson.GsonBuilder
import com.hmg.hmgDr.Service.VideoStreamFloatingWidgetService
import com.hmg.hmgDr.model.GetSessionStatusModel
import com.hmg.hmgDr.model.SessionStatusModel
import com.hmg.hmgDr.Service.VideoStreamFloatingWidgetService
import com.hmg.hmgDr.globalErrorHandler.FileUtil
import com.hmg.hmgDr.globalErrorHandler.LoggingExceptionHandler
import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.ui.fragment.VideoCallFragment
import com.opentok.android.Session
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
@ -31,7 +34,7 @@ import pub.devrel.easypermissions.EasyPermissions
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
VideoCallResponseListener {
VideoCallResponseListener, EasyPermissions.PermissionCallbacks {
/* Permission request code to draw over other apps */
private val DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE = 1222
@ -131,9 +134,15 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
}
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.
requestPermissions()
//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.
//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.
@ -160,7 +169,27 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE) {
/*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)
}
} else*/ if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE) {
//Check if the permission is granted or not.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.canDrawOverlays(this)) {
@ -259,6 +288,7 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
private fun unbindService() {
if (bound) {
videoStreamService?.videoCallResponseListener = null // unregister
// videoStreamService!!.mActivity = null
unbindService(serviceConnection)
bound = false
}
@ -274,6 +304,7 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
bound = true
videoStreamService!!.videoCallResponseListener = this@MainActivity // register
videoStreamService?.serviceRunning = true
// videoStreamService!!.mActivity = this@MainActivity // register
}
override fun onServiceDisconnected(name: ComponentName?) {
@ -281,4 +312,52 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
}
}
@AfterPermissionGranted(RC_READ_WRITE)
private fun requestPermissions() {
val perms = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
if (EasyPermissions.hasPermissions(this, *perms)) {
} else {
EasyPermissions.requestPermissions(
this,
getString(R.string.remaining_ar),
RC_READ_WRITE,
*perms
)
}
}
override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>?) {
}
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
if (EasyPermissions.somePermissionPermanentlyDenied(this@MainActivity, perms)) {
AppSettingsDialog.Builder(this)
.setTitle(getString(R.string.title_settings_dialog))
.setRationale(getString(R.string.rationale_ask_again))
.setPositiveButton(getString(R.string.setting))
.setNegativeButton(getString(R.string.cancel))
.setRequestCode(RC_SETTINGS_SCREEN_PERM)
.build()
.show()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
}
companion object{
private const val RC_READ_WRITE = 1
private const val RC_SETTINGS_SCREEN_PERM = 123
}
}

@ -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
}
}

@ -22,17 +22,15 @@ import com.hmg.hmgDr.model.*
import com.hmg.hmgDr.ui.VideoCallContract
import com.hmg.hmgDr.ui.VideoCallPresenterImpl
import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.util.DateUtils
import com.hmg.hmgDr.util.opentok.DynamicVideoRenderer
import com.hmg.hmgDr.util.DynamicVideoRenderer
import com.hmg.hmgDr.util.NotificationUtil
import com.hmg.hmgDr.util.ViewsUtil
import com.hmg.hmgDr.util.audio.CustomAudioDevice
import com.opentok.android.*
import java.util.*
import kotlin.math.ceil
class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.SessionListener,
class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
PublisherKit.PublisherListener,
SubscriberKit.VideoListener, VideoCallContract.VideoCallView {
@ -41,24 +39,31 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
private val TAG = VideoStreamFloatingWidgetService::class.java.simpleName
private const val RC_SETTINGS_SCREEN_PERM = 123
private const val RC_VIDEO_APP_PERM = 124
const val CHANNEL_DEFAULT_IMPORTANCE = "Video_stream_channel"
const val CHANNEL_DEFAULT_NAME = "Video cAll"
const val ONGOING_NOTIFICATION_ID = 1
private const val TEST_DURATION = 20 //test quality duration in seconds
private const val TIME_WINDOW = 3 //3 seconds
private const val TIME_VIDEO_TEST = 15 //time interval to check the video quality in seconds
const val ACTION_START_CALL = "com.hmg.hmgDr.Service.action.startCall"
const val ACTION_MINIMIZE_CALL = "com.hmg.hmgDr.Service.action.minimizeCall"
const val ACTION_END_CALL = "com.hmg.hmgDr.Service.action.endCall"
const val ACTION_CHANGE_EXPANDED_COLLAPSED =
"com.hmg.hmgDr.Service.action.changeExpandedCollapsed"
const val NOTIFICATION_IS_EXPANDED = "is_expanded"
}
var arguments: Bundle? = null
var serviceRunning: Boolean = false
private lateinit var windowManagerParams: WindowManager.LayoutParams
private var mWindowManager: WindowManager? = null
private val szWindow = Point()
private var floatingWidgetView: View? = null
private val serviceBinder: IBinder = VideoStreamBinder()
private lateinit var videoCallPresenter: VideoCallContract.VideoCallPresenter
var videoCallResponseListener: VideoCallResponseListener? = null
private var x_init_cord = 0
private var y_init_cord: Int = 0
private var x_init_margin: Int = 0
private var y_init_margin: Int = 0
private lateinit var recordContainer: FrameLayout
private lateinit var thumbnail_container: FrameLayout
@ -81,8 +86,10 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
private lateinit var mspeckerBtn: ImageView
private lateinit var mMicBtn: ImageView
private lateinit var patientName: TextView
private lateinit var tvTimer: TextView
// private lateinit var cmTimer: Chronometer
private lateinit var cmTimer: Chronometer
private lateinit var videoCallPresenter: VideoCallContract.VideoCallPresenter
var videoCallResponseListener: VideoCallResponseListener? = null
private var mSession: Session? = null
private var mPublisher: Publisher? = null
@ -94,11 +101,8 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
private var mConnectedRunnable: Runnable? = null
private var isConnected = false
private var mCallTimerHandler: Handler? = null
private var mCallTimerRunnable: Runnable? = null
private var mCallFirstTime: Date = Date()
private var sessionStatusModel: GetSessionStatusModel? = null
private lateinit var mDetector: GestureDetectorCompat
private var apiKey: String? = null
private var sessionId: String? = null
@ -115,9 +119,30 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
private var formattedCallTime: String = "00:00"
private lateinit var notificationData: NotificationVideoModel
private val mVideoPLRatio = 0.0
private val mVideoBw: Long = 0
private val mAudioPLRatio = 0.0
private val mAudioBw: Long = 0
private val mPrevVideoPacketsLost: Long = 0
private val mPrevVideoPacketsRcvd: Long = 0
private val mPrevVideoTimestamp = 0.0
private val mPrevVideoBytes: Long = 0
private val mPrevAudioPacketsLost: Long = 0
private val mPrevAudioPacketsRcvd: Long = 0
private val mPrevAudioTimestamp = 0.0
private val mPrevAudioBytes: Long = 0
private val mStartTestTime: Long = 0
private val audioOnly = false
private var resume = false
var isFullScreen: Boolean = true
private var isCircle: Boolean = false
lateinit var customAudioDevice: CustomAudioDevice
var arguments: Bundle? = null
var serviceRunning: Boolean = false
private val serviceBinder: IBinder = VideoStreamBinder()
// Notification variables
private var mNotificationManagerCompat: NotificationManagerCompat? = null
@ -146,8 +171,17 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
isRecording = sessionStatusModel!!.isRecording
}
addFloatingWidgetView()
//init WindowManager
mWindowManager = getSystemService(WINDOW_SERVICE) as WindowManager
getWindowManagerDefaultDisplay()
//Init LayoutInflater
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
addFloatingWidgetView(inflater)
handleDragDialog()
addForegroundService()
}
} else if (action == ACTION_END_CALL) {
@ -155,29 +189,10 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
} else if (action == ACTION_MINIMIZE_CALL) {
if (!isFullScreen)
onMinimizedClicked()
} else if (action == ACTION_CHANGE_EXPANDED_COLLAPSED) {
val isExpanded = intent.extras!!.getBoolean(NOTIFICATION_IS_EXPANDED)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// No use channel importance
if (isExpanded) {
notificationCompatBuilder.priority = Notification.PRIORITY_LOW
} else {
notificationCompatBuilder.priority = Notification.PRIORITY_HIGH
}
} else {
if (isExpanded) {
notificationCompatBuilder.priority = Notification.PRIORITY_LOW
} else {
notificationCompatBuilder.priority = Notification.PRIORITY_HIGH
}
}
mNotificationManagerCompat?.notify(
ONGOING_NOTIFICATION_ID,
notificationCompatBuilder.build()
)
}
}
// Toast.makeText(this, "Service started by user.", Toast.LENGTH_LONG).show()
return START_STICKY
}
@ -196,20 +211,14 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
} catch (e: Exception) {
Log.e("onDestroyService", "${e.localizedMessage}.")
}
// disconnectSession()
super.onDestroy()
}
private fun stopService() {
AudioDeviceManager.getAudioDevice().onPause()
mCallTimerRunnable?.let {
mCallTimerHandler?.removeCallbacks(it)
mCallTimerHandler = null
mCallTimerRunnable = null
}
// because problem that timer still continue longer a bit than service so notification called again
mNotificationManagerCompat = null
cmTimer.stop()
stopForeground(true)
stopSelf()
videoCallResponseListener?.minimizeVideoEvent(false)
@ -220,8 +229,36 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
}
}
override fun addFloatingWidgetView() {
super.addFloatingWidgetView()
/* Add Floating Widget View to Window Manager */
private fun addFloatingWidgetView(inflater: 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
//Initially the Removing widget view is not visible, so set visibility to GONE
// floatingWidgetView!!.visibility = View.GONE
init(floatingWidgetView!!)
@ -230,9 +267,33 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
}
@SuppressLint("ClickableViewAccessibility", "RestrictedApi")
private fun init(view: View) {
private fun init(view: View) {
initUI(view)
mCallBtn.setOnClickListener {
onCallClicked()
}
btnMinimize.setOnClickListener {
onMinimizedClicked()
}
mCameraBtn.setOnClickListener {
onCameraClicked(it)
}
mSwitchCameraBtn.setOnClickListener {
onSwitchCameraClicked(it)
}
mspeckerBtn.setOnClickListener {
onSpeckerClicked(it)
}
mMicBtn.setOnClickListener {
onMicClicked(it)
}
icMini.setOnClickListener {
onMiniCircleClicked()
}
// hiddenButtons()
patientName.text = sessionStatusModel!!.patientName
if (isRecording) {
@ -241,10 +302,57 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
recordContainer.visibility = View.GONE
}
cmTimer.format = "mm:ss"
cmTimer.onChronometerTickListener =
Chronometer.OnChronometerTickListener { arg0: Chronometer? ->
// val f: NumberFormat = DecimalFormat("00")
// f.format(minutes)
val minutes: Long
val seconds: Long
if (!resume) {
minutes = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 / 60
seconds = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 % 60
elapsedTime = SystemClock.elapsedRealtime()
} else {
minutes = (elapsedTime - cmTimer.base) / 1000 / 60
seconds = (elapsedTime - cmTimer.base) / 1000 % 60
elapsedTime += 1000
}
val format = "%1$02d:%2$02d" // two digits
formattedCallTime = String.format(format, minutes, seconds)
arg0?.text = formattedCallTime
try {
notificationCompatBuilder.contentView.setChronometer(
R.id.notify_timer,
cmTimer.base,
null,
true
)
notificationCompatBuilder.bigContentView.setChronometer(
R.id.notify_timer,
cmTimer.base,
null,
true
)
} catch (e: Exception) {
}
// for change notification timer
if (mNotificationManagerCompat != null) {
val bigTextStyle = setNotificationBigStyle()
notificationCompatBuilder.setStyle(bigTextStyle)
mNotificationManagerCompat?.notify(
ONGOING_NOTIFICATION_ID,
notificationCompatBuilder.build()
)
}
}
videoCallPresenter = VideoCallPresenterImpl(this, baseUrl)
checkClientConnected()
setCallStartTimer()
handleVideoViewHeight()
mDetector = GestureDetectorCompat(
@ -254,19 +362,19 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
{ miniCircleDoubleTap() })
)
try {
// Add a custom audio device before session initialization,
// so when the service is destroyed it will not be errors that receivers is still in memory
customAudioDevice = CustomAudioDevice(this)
customAudioDevice.setRendererMute(false)
if (AudioDeviceManager.getAudioDevice() == null) {
AudioDeviceManager.setAudioDevice(customAudioDevice)
} else {
AudioDeviceManager.getAudioDevice().onResume()
}
// Add a custom audio device before session initialization
// Add a custom audio device before session initialization
val customAudioDevice = CustomAudioDevice(
this
)
customAudioDevice.setRendererMute(true)
AudioDeviceManager.setAudioDevice(customAudioDevice)
mSession = Session.Builder(this, apiKey, sessionId).build()
mSession!!.setSessionListener(this)
mSession!!.connect(token)
mSession!!.setReconnectionListener(object : Session.ReconnectionListener {
override fun onReconnecting(session: Session?) {
@ -284,7 +392,6 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
private fun initUI(view: View) {
videoCallContainer = view.findViewById(R.id.video_call_ll)
floatingViewContainer = videoCallContainer
layoutName = view.findViewById<View>(R.id.layout_name) as RelativeLayout
layoutMini = view.findViewById(R.id.layout_mini)
@ -299,7 +406,7 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
mSubscriberViewContainer = view.findViewById(R.id.remote_video_view_container)
patientName = view.findViewById(R.id.patient_name)
tvTimer = view.findViewById(R.id.tv_timer)
cmTimer = view.findViewById(R.id.cmTimer)
controlPanel = view.findViewById(R.id.control_panel)
mCallBtn = view.findViewById(R.id.btn_call)
@ -308,28 +415,6 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
mSwitchCameraBtn = view.findViewById(R.id.btn_switch_camera)
mspeckerBtn = view.findViewById(R.id.btn_specker)
mMicBtn = view.findViewById(R.id.btn_mic)
mCallBtn.setOnClickListener {
onCallClicked()
}
btnMinimize.setOnClickListener {
onMinimizedClicked()
}
mCameraBtn.setOnClickListener {
onCameraClicked(it)
}
mSwitchCameraBtn.setOnClickListener {
onSwitchCameraClicked(it)
}
mspeckerBtn.setOnClickListener {
onSpeckerClicked(it)
}
mMicBtn.setOnClickListener {
onMicClicked(it)
}
icMini.setOnClickListener {
onMiniCircleClicked()
}
}
private fun checkClientConnected() {
@ -345,27 +430,6 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
)
}
private fun setCallStartTimer() {
mCallTimerHandler = Handler((Looper.getMainLooper()))
mCallTimerRunnable = Runnable {
formattedCallTime = DateUtils.differentDateTimeBetweenDateAndNow(mCallFirstTime)
tvTimer.text = formattedCallTime
// for change notification timer
if (mNotificationManagerCompat != null) {
notificationData.mSummaryText = formattedCallTime
val bigTextStyle = NotificationUtil.setNotificationBigStyle(notificationData)
notificationCompatBuilder.setStyle(bigTextStyle)
mNotificationManagerCompat?.notify(
ONGOING_NOTIFICATION_ID,
notificationCompatBuilder.build()
)
}
mCallTimerHandler!!.postDelayed(mCallTimerRunnable!!, 1000L)
}
}
private fun handleVideoViewHeight() {
val layoutNameParam: ConstraintLayout.LayoutParams =
layoutName.layoutParams as ConstraintLayout.LayoutParams
@ -387,7 +451,7 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
val panelPaddingMedium: Int =
resources.getDimension(R.dimen.padding_space_medium).toInt()
val temp = ViewsUtil.getStatusBarHeight(applicationContext) / 2
val temp = getStatusBarHeight() / 2
val screenWidth: Float
val screenHeight: Float
@ -548,13 +612,6 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
handleVideoViewHeight()
}
@SuppressLint("ClickableViewAccessibility")
private fun handleDragDialog() {
getWindowManagerDefaultDisplay()
videoCallContainer.setOnTouchListener(dragListener)
mSubscriberViewContainer.setOnTouchListener(dragListener)
}
/***
* Click Listener
@ -607,6 +664,14 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
mPublisher!!.publishVideo = !isCameraClicked
val res = if (isCameraClicked) R.drawable.video_disabled else R.drawable.video_enabled
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))
// }
}
}
@ -633,7 +698,7 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
isMicClicked = !isMicClicked
mPublisher!!.publishAudio = !isMicClicked
val res = if (isMicClicked) R.drawable.mic_disabled else R.drawable.mic_enabled
mMicBtn.setImageResource(res)
mMicBtn!!.setImageResource(res)
}
}
@ -731,10 +796,10 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
mSession!!.publish(mPublisher)
// start call timer to show on top
mCallFirstTime = Date()
mCallTimerHandler!!.postDelayed(mCallTimerRunnable!!, 1000L)
if (!resume) {
cmTimer.base = SystemClock.elapsedRealtime()
}
cmTimer.start()
videoCallResponseListener?.minimizeVideoEvent(true)
}
@ -748,6 +813,9 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
override fun onError(session: Session, opentokError: OpentokError) {
Log.d(TAG, "onError: Error (" + opentokError.message + ") in session " + session.sessionId)
// videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in session ")
// dialog?.dismiss()
}
override fun onStreamReceived(session: Session, stream: Stream) {
@ -755,7 +823,6 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
TAG,
"onStreamReceived: New stream " + stream.streamId + " in session " + session.sessionId
)
if (mSubscriber != null) {
isConnected = true
return
@ -940,7 +1007,7 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
}
}
private fun onCallChangeCallStatusSuccessful() {
fun onCallChangeCallStatusSuccessful() {
val returnIntent = Intent()
returnIntent.putExtra("CallEnd", sessionStatusModel)
videoCallResponseListener?.onCallFinished(Activity.RESULT_CANCELED, returnIntent)
@ -952,9 +1019,22 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
override fun onFailure() {}
/***
* Notification methods
* Utils
*/
private fun getWindowManagerDefaultDisplay() {
val w = mWindowManager!!.defaultDisplay.width
val h = mWindowManager!!.defaultDisplay.height
szWindow[w] = h
}
/* return status bar height on basis of device display metrics */
private fun getStatusBarHeight(): Int {
return ceil(
(25 * applicationContext.resources.displayMetrics.density).toDouble()
).toInt()
}
private fun addForegroundService() {
mNotificationManagerCompat = NotificationManagerCompat.from(applicationContext)
val areNotificationsEnabled = mNotificationManagerCompat!!.areNotificationsEnabled()
@ -965,12 +1045,23 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
Toast.LENGTH_SHORT
).show()
// Links to this app's notification settings
NotificationUtil.openNotificationSettingsForApp(applicationContext)
openNotificationSettingsForApp()
return
}
generateBigTextStyleNotification()
}
private fun setNotificationBigStyle(): NotificationCompat.BigTextStyle {
notificationData.mSummaryText = formattedCallTime
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)
}
private fun generateBigTextStyleNotification() {
notificationData =
NotificationVideoModel(
@ -986,7 +1077,7 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
NotificationUtil.createNotificationChannel(this, notificationData)
// 2. Build the BIG_TEXT_STYLE.
val bigTextStyle = NotificationUtil.setNotificationBigStyle(notificationData)
val bigTextStyle = setNotificationBigStyle()
// 3. Set up main Intent for notification.
val pendingIntent: PendingIntent =
@ -1020,6 +1111,25 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
)
}
// notification's layout
val mRemoteViews = RemoteViews(packageName, R.layout.notifi_video_view)
mRemoteViews.setImageViewResource(R.id.iv_icon, R.mipmap.ic_launcher)
// notification's title
mRemoteViews.setTextViewText(R.id.notify_title, notificationData.mContentTitle)
// notification's content
mRemoteViews.setTextViewText(R.id.notify_content, notificationData.mContentText)
val mRemoteViewsExpand = RemoteViews(packageName, R.layout.notifi_video_view_expand)
mRemoteViewsExpand.setImageViewResource(R.id.iv_icon, R.mipmap.ic_launcher)
mRemoteViewsExpand.setTextViewText(R.id.notify_title, notificationData.mContentTitle)
mRemoteViewsExpand.setTextViewText(R.id.notify_content, notificationData.mContentText)
mRemoteViewsExpand.setOnClickPendingIntent(R.id.btn_end, endCallPendingIntent)
mRemoteViewsExpand.setChronometer(
R.id.notify_timer,
SystemClock.elapsedRealtime(),
null,
false
)
notificationCompatBuilder
// BIG_TEXT_STYLE sets title and content for API 16 (4.1 and after).
.setStyle(bigTextStyle)
@ -1034,8 +1144,8 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
R.mipmap.ic_launcher
)
)
/*.setCustomContentView(mRemoteViews)
.setCustomBigContentView(mRemoteViewsExpand)*/
.setCustomContentView(mRemoteViews)
.setCustomBigContentView(mRemoteViewsExpand)
.setContentIntent(pendingIntent)
// .setDefaults(NotificationCompat.DEFAULT_ALL)
// Set primary color (important for Wear 2.0 Notifications).
@ -1043,21 +1153,235 @@ class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.Ses
.setCategory(Notification.CATEGORY_SERVICE)
.setPriority(notificationData.mPriority)
.setVisibility(notificationData.mChannelLockscreenVisibility)
.addAction(endCallAction) // for version code < O, or for all versions if RemoteViews not used
// .addAction(endCallAction)
.setUsesChronometer(true)
.setWhen(elapsedTime)
.setOnlyAlertOnce(true) // This will ensure that updates to an existing notification won't sound/vibrate https://stackoverflow.com/a/52349466/6246772
.setSound(null)
.setOngoing(true)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setColorized(true)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) //to show content in lock screen
val notification = notificationCompatBuilder
.build()
mNotificationManagerCompat!!.notify(ONGOING_NOTIFICATION_ID, notification)
startForeground(ONGOING_NOTIFICATION_ID, notification)
/*val notification: Notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder(this, CHANNEL_DEFAULT_IMPORTANCE)
.setContentTitle("")
.setContentText("")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build()
} else {
Notification.Builder(this)
.setContentTitle("")
.setContentText("")
.setSmallIcon(R.mipmap.ic_launcher)
.setOngoing(true)
.setContentIntent(pendingIntent)
.build()
}
// Notification ID cannot be 0.
*/
}
/**
* 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.
*/
private fun openNotificationSettingsForApp() {
// Links to this app's notification settings.
val intent = Intent()
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
intent.putExtra("app_package", packageName)
intent.putExtra("app_uid", applicationInfo.uid)
// for Android 8 and above
intent.putExtra("android.provider.extra.APP_PACKAGE", packageName)
startActivity(intent)
}
/**
* OnTouch actions
*/
private 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)
}
}
@SuppressLint("ClickableViewAccessibility")
private fun handleDragDialog() {
mWindowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
getWindowManagerDefaultDisplay()
videoCallContainer.setOnTouchListener(dragListener)
mSubscriberViewContainer.setOnTouchListener(dragListener)
}
@SuppressLint("ClickableViewAccessibility")
private val dragListener: View.OnTouchListener = View.OnTouchListener { _, event ->
mDetector.onTouchEvent(event)
if (floatingWidgetView!!.layoutParams is WindowManager.LayoutParams) {
var asd = "";
}
//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 -> {
x_init_cord = x_cord
y_init_cord = y_cord
//remember the initial position.
x_init_margin = layoutParams.x
y_init_margin = layoutParams.y
}
MotionEvent.ACTION_UP -> {
//Get the difference between initial coordinate and current coordinate
val x_diff: Int = x_cord - x_init_cord
val y_diff: Int = y_cord - y_init_cord
y_cord_Destination = y_init_margin + y_diff
val barHeight: Int = getStatusBarHeight()
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 + (videoCallContainer.height + barHeight) > szWindow.y) {
y_cord_Destination = szWindow.y - (videoCallContainer.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 - x_init_cord
val y_diff_move: Int = y_cord - y_init_cord
x_cord_Destination = x_init_margin + x_diff_move
y_cord_Destination = y_init_margin + 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
}
/* Reset position of Floating Widget view on dragging */
private 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 - videoCallContainer.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 - videoCallContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
override fun onFinish() {
mParams.x = -(szWindow.x - videoCallContainer.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) {
// var mParams : WindowManager.LayoutParams = dialog!!.window!!.attributes
// mParams.x =
// (szWindow.x + current_x_cord * current_x_cord - videoCallContainer.width).toInt()
//
// dialog!!.window!!.attributes = mParams
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 - videoCallContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
override fun onFinish() {
mParams.x = szWindow.x - videoCallContainer.width
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
}
}.start()
}
}

@ -0,0 +1,7 @@
package com.hmg.hmgDr.errorhandler
/**
* A functional interface representing an action that gets executed
* upon an error by an [ErrorHandler].
*/
typealias Action = (Throwable, ErrorHandler) -> Unit

@ -0,0 +1,34 @@
package com.hmg.hmgDr.errorhandler
/**
* Container to ease passing around a tuple of two objects. This object provides a sensible
* implementation of equals(), returning true if equals() is true on each of the contained
* objects.
*/
class ActionEntry
/**
* Constructor for an ActionEntry.
*
* @param matcher the matcher object in the ActionEntry
* @param action the action object in the ActionEntry
*/(
val matcher: Matcher,
val action: Action
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
val that = other as ActionEntry
return if (matcher != that.matcher) false else action == that.action
}
/**
* Compute a hash code using the hash codes of the underlying objects
*
* @return a hashcode of the ActionEntry
*/
override fun hashCode(): Int {
return matcher.hashCode() xor action.hashCode()
}
}

@ -0,0 +1,505 @@
package com.hmg.hmgDr.errorhandler
import java.util.HashMap
import kotlin.reflect.KClass
/**
* https://github.com/mgray88/kotlin-error-handler
* An ErrorHandler is responsible for handling an error by executing one or more actions,
* instances of [Action], that are found to match the error.
*/
class ErrorHandler private constructor() {
private val errorCodeMap = mutableMapOf<ErrorCodeIdentifier<*>, MatcherFactory<*>>()
private val actions = mutableListOf<ActionEntry>()
private val otherwiseActions= mutableListOf<Action>()
private val alwaysActions = mutableListOf<Action>()
private var localContext: ThreadLocal<Context> = object : ThreadLocal<Context>() {
override fun initialValue(): Context {
return Context()
}
}
private var parentErrorHandler: ErrorHandler? = null
/**
* Create a new ErrorHandler with the given one as parent.
*
* @param parentErrorHandler the parent @{link ErrorHandler}
*/
private constructor(parentErrorHandler: ErrorHandler) : this() {
this.parentErrorHandler = parentErrorHandler
}
/**
* Register `action` to be executed by [.handle],
* if the thrown error matches the `matcher`.
*
* @param matcher a matcher to match the thrown error
* @param action the associated action
* @return the current `ErrorHandler` instance - to use in command chains
*/
fun on(
matcher: Matcher,
action: Action
): ErrorHandler {
actions.add(ActionEntry(matcher, action))
return this
}
/**
* Kotlin <1.4 lambda compatibility for `[.on(Matcher, Action)]`
*/
fun on(
matcher: (Throwable) -> Boolean,
action: Action
): ErrorHandler {
return on(object : Matcher {
override fun matches(throwable: Throwable): Boolean {
return matcher(throwable)
}
}, action)
}
/**
* Register `action` to be executed by [.handle],
* if the thrown error is an instance of `exceptionClass`.
*
* @param exceptionClass the class of the error
* @param action the associated action
* @return the current `ErrorHandler` instance - to use in command chains
*/
fun on(
exceptionClass: KClass<out Throwable>,
action: Action
): ErrorHandler {
actions.add(ActionEntry(ExceptionMatcher(exceptionClass), action))
return this
}
/**
* Register `action` to be executed by [.handle],
* if the thrown error is bound (associated) to `errorCode`.
*
*
* See [.bindClass] and [.bind]
* on how to associate arbitrary error codes with actual Throwables via [Matcher].
*
* @param <T> the error code type
* @param errorCode the error code
* @param action the associated action
* @return the current `ErrorHandler` instance - to use in command chains
</T> */
fun <T : Any> on(
errorCode: T,
action: Action
): ErrorHandler {
val matcherFactory: MatcherFactory<T> =
getMatcherFactoryForErrorCode(errorCode)
?: throw UnknownErrorCodeException(errorCode)
actions.add(ActionEntry(matcherFactory.build(errorCode), action))
return this
}
/**
* Register `action` to be executed in case no other *conditional*
* action gets executed.
*
* @param action the action
* @return the current `ErrorHandler` instance - to use in command chains
*/
fun otherwise(action: Action): ErrorHandler {
otherwiseActions.add(action)
return this
}
/**
* Register `action` to be executed on all errors.
*
* @param action the action
* @return the current `ErrorHandler` instance - to use in command chains
*/
fun always(action: Action): ErrorHandler {
alwaysActions.add(action)
return this
}
/**
* Skip all following actions registered via an `on` method
* @return the current `ErrorHandler` instance - to use in command chains
*/
fun skipFollowing(): ErrorHandler {
localContext.get().skipFollowing = true
return this
}
/**
* Skip all actions registered via [.always]
* @return the current `ErrorHandler` instance - to use in command chains
*/
fun skipAlways(): ErrorHandler {
localContext.get().skipAlways = true
return this
}
/**
* Skip the default matching actions if any
* @return the current `ErrorHandler` instance - to use in command chains
*/
fun skipDefaults(): ErrorHandler {
localContext.get().skipDefaults = true
return this
}
private fun handle(
error: Throwable,
context: ThreadLocal<Context>
) {
localContext = context
val ctx = localContext.get()
for (actionEntry in actions) {
if (ctx.skipFollowing) break
if (actionEntry.matcher.matches(error)) {
actionEntry.action(error, this)
ctx.handled = true
}
}
if (!ctx.handled && otherwiseActions.isNotEmpty()) {
for (action in otherwiseActions) {
action(error, this)
ctx.handled = true
}
}
if (!ctx.skipAlways) {
for (action in alwaysActions) {
action(error, this)
ctx.handled = true
}
}
if (!ctx.skipDefaults) {
parentErrorHandler?.handle(error, localContext)
}
}
/**
* Run a custom code block and assign current ErrorHandler instance
* to handle a possible exception throw in 'catch'.
*
* @param closure functional interface containing Exception prone code
*/
fun runHandling(closure: () -> Unit) {
try {
closure()
} catch (throwable: Throwable) {
handle(throwable, localContext)
}
}
/**
* Handle `error` by executing all matching actions.
*
* @param error the error as a [Throwable]
*/
fun handle(error: Throwable) {
this.handle(error, localContext)
}
/**
* Bind an `errorCode` to a `Matcher`, using a `MatcherFactory`.
*
*
*
* For example, when we need to catch a network timeout it's better to just write "timeout"
* instead of a train-wreck expression. So we need to bind this "timeout" error code to an actual
* condition that will check the actual error when it occurs to see if its a network timeout or not.
*
*
* <pre>
* ```
* ErrorHandler
* .defaultErrorHandler()
* .bind("timeout") { errorCode ->
* Matcher { throwable ->
* return (throwable is SocketTimeoutException) && throwable.message.contains("Read timed out")
* }
* }
*
* // ...
*
* ErrorHandler
* .create()
* .on("timeout") { throwable, handler ->
* showOfflineScreen()
* }
* ```
* </pre>
*
*
* @param <T> the error code type
* @param errorCode the errorCode value, can use a primitive for clarity and let it be autoboxed
* @param matcherFactory a factory that given an error code, provides a matcher to match the error against it
* @return the current `ErrorHandler` instance - to use in command chains
*/
fun <T : Any> bind(
errorCode: T,
matcherFactory: MatcherFactory<T>
): ErrorHandler {
errorCodeMap[ErrorCodeIdentifier(errorCode)] = matcherFactory
return this
}
/**
* Kotlin <1.4 lambda compatibility for `[.bind(T, MatcherFactory<T>)]`
*/
fun <T : Any> bind(
errorCode: T,
matcherFactory: (T) -> (Throwable) -> Boolean
): ErrorHandler {
return bind(errorCode, object : MatcherFactory<T> {
override fun build(errorCode: T): Matcher {
val matcher = matcherFactory(errorCode)
return object : Matcher {
override fun matches(throwable: Throwable): Boolean {
return matcher(throwable)
}
}
}
})
}
/**
* Bind an `errorCode` `Class` to a `Matcher`, using a `MatcherFactory`.
*
*
*
* For example, when we prefer using plain integers to refer to HTTP errors instead of
* checking the HTTPException status code every time.
*
*
* <pre>
* ```
* ErrorHandler
* .defaultErrorHandler()
* .bindClass(Integer::class) { errorCode ->
* Matcher { throwable ->
* return throwable is HttpException && throwable.code() == errorCode
* }
* }
*
* // ...
*
* ErrorHandler
* .create()
* .on(404) { throwable, handler ->
* showResourceNotFoundError()
* }
* .on(500) { throwable, handler ->
* showServerError()
* }
* ````
* </pre>
*
* @param <T> the error code type
* @param errorCodeClass the errorCode class
* @param matcherFactory a factory that given an error code, provides a matcher to match the error against it
* @return the current `ErrorHandler` instance - to use in command chains
*/
fun <T : Any> bindClass(
errorCodeClass: KClass<T>,
matcherFactory: MatcherFactory<T>
): ErrorHandler {
errorCodeMap[ErrorCodeIdentifier(errorCodeClass)] = matcherFactory
return this
}
/**
* Kotlin <1.4 lambda compatibility for `[.bindClass(KClass<T>, MatcherFactory<T>)]`
*/
fun <T : Any> bindClass(
errorCodeClass: KClass<T>,
matcherFactory: (T) -> (Throwable) -> Boolean
): ErrorHandler {
return bindClass(errorCodeClass, object : MatcherFactory<T> {
override fun build(errorCode: T): Matcher {
val matcher = matcherFactory(errorCode)
return object : Matcher {
override fun matches(throwable: Throwable): Boolean {
return matcher(throwable)
}
}
}
})
}
@Suppress("UNCHECKED_CAST")
protected fun <T : Any> getMatcherFactoryForErrorCode(errorCode: T): MatcherFactory<T>? {
var matcherFactory: MatcherFactory<T>?
matcherFactory = errorCodeMap[ErrorCodeIdentifier(errorCode)] as? MatcherFactory<T>
if (matcherFactory != null) {
return matcherFactory
}
matcherFactory = errorCodeMap[ErrorCodeIdentifier(errorCode::class)] as? MatcherFactory<T>
if (matcherFactory != null) {
return matcherFactory
}
return if (parentErrorHandler != null) {
parentErrorHandler?.getMatcherFactoryForErrorCode(errorCode)
} else null
}
/**
* Clear ErrorHandler instance from all its registered Actions and Matchers.
*/
fun clear() {
actions.clear()
errorCodeMap.clear()
otherwiseActions.clear()
alwaysActions.clear()
localContext.get().clear()
}
private class Context {
private val keys = HashMap<String, Any>()
var handled = false
var skipDefaults = false
var skipFollowing = false
var skipAlways = false
operator fun get(key: Any?): Any? {
return keys[key]
}
fun put(key: String, value: Any): Any? {
return keys.put(key, value)
}
fun remove(key: Any?): Any? {
return keys.remove(key)
}
fun clear() {
keys.clear()
skipDefaults = false
skipFollowing = false
skipAlways = false
}
}
/**
* Used to identify an error code either by its "literal" value
* or by its Class.
*
*
* When using custom objects as error codes,
* make sure you implement [Object.equals] to allow ErrorHandler
* perform equality comparisons between instances.
*/
private class ErrorCodeIdentifier<out T : Any> {
private val errorCode: T?
private val errorCodeClass: KClass<out T>?
internal constructor(errorCode: T) {
this.errorCode = errorCode
this.errorCodeClass = null
}
internal constructor(errorCodeClass: KClass<out T>) {
this.errorCode = null
this.errorCodeClass = errorCodeClass
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
val that = other as ErrorCodeIdentifier<*>
if (if (errorCode != null) errorCode != that.errorCode else that.errorCode != null) return false
return if (errorCodeClass != null) errorCodeClass == that.errorCodeClass else that.errorCodeClass == null
}
override fun hashCode(): Int {
var result = errorCode?.hashCode() ?: 0
result = 31 * result + (errorCodeClass?.hashCode() ?: 0)
return result
}
}
companion object {
private var defaultInstance: ErrorHandler? = null
/**
* Create a new @{link ErrorHandler}, isolated from the default one.
*
*
* In other words, designed to handle all errors by itself without delegating
* to the default error handler.
*
* @return returns a new `ErrorHandler` instance
*/
@JvmStatic
fun createIsolated(): ErrorHandler {
return ErrorHandler()
}
/**
* Create a new @{link ErrorHandler}, that delegates to the default one, or the
* parent @{link ErrorHandler} passed in
*
* Any default actions, are always executed after the ones registered on this one.
*
* @param parentErrorHandler `ErrorHandler` to use as the parent
* @return returns a new `ErrorHandler` instance
*/
@JvmStatic
fun create(parentErrorHandler: ErrorHandler? = null): ErrorHandler {
return ErrorHandler(parentErrorHandler ?: defaultErrorHandler())
}
/**
* Get the default @{link ErrorHandler}, a singleton object
* to which all other instances by default delegate to.
*
* @return the default @{link ErrorHandler} instance
*/
@JvmStatic
@Synchronized
fun defaultErrorHandler(): ErrorHandler {
if (defaultInstance == null) {
defaultInstance =
ErrorHandler()
}
return defaultInstance!!
}
}
}
/**
* Wrapper around `[.on(KClass, Action)]` to allow action's `Throwable` parameter
* to be typed to the `Throwable` expected
*/
inline fun <reified T : Throwable> ErrorHandler.on(
noinline action: (T, ErrorHandler) -> Unit
): ErrorHandler {
return on(T::class) { throwable, errorHandler ->
action(throwable as T, errorHandler)
}
}
/**
* Lazy `ErrorHandler` initializer which delegates to a parent, or the `defaultErrorHandler`
* if the parent is not supplied. Uses optional lambda function to add actions and bindings to
* the new `ErrorHandler`
*
* @param parentErrorHandler (optional) error handler to delegate default actions to
* @param apply (optional) apply function for adding actions and binding
* @return lazy initialized `ErrorHandler`
*/
inline fun errorHandler(
parentErrorHandler: ErrorHandler? = null,
noinline apply: (ErrorHandler.() -> Unit)? = null
) = lazy {
val eh = ErrorHandler.create(parentErrorHandler)
apply?.invoke(eh)
return@lazy eh
}

@ -0,0 +1,9 @@
package com.hmg.hmgDr.errorhandler
import kotlin.reflect.KClass
class ExceptionMatcher(private val errorClass: KClass<out Throwable>) : Matcher {
override fun matches(throwable: Throwable): Boolean {
return errorClass.isInstance(throwable)
}
}

@ -0,0 +1,5 @@
package com.hmg.hmgDr.errorhandler
interface Matcher {
fun matches(throwable: Throwable): Boolean
}

@ -0,0 +1,11 @@
package com.hmg.hmgDr.errorhandler
interface MatcherFactory<in T : Any> {
/**
* Build a [Matcher] to match the given error code against an error
*
* @param errorCode the error code
* @return a new [Matcher]
*/
fun build(errorCode: T): Matcher
}

@ -0,0 +1,3 @@
package com.hmg.hmgDr.errorhandler
class UnknownErrorCodeException(val errorCode: Any) : RuntimeException()

@ -0,0 +1,45 @@
package com.hmg.hmgDr.errorhandler.retrofit
/**
* Range class for HTTP status codes
*/
class Range private constructor(val lowerBound: Int, val upperBound: Int) {
/**
* Checks if the passed httpStatusCode is contained in given range
*
* @param httpStatusCode the status code to check
* @return true if contains, otherwise false
*/
operator fun contains(httpStatusCode: Int): Boolean {
return httpStatusCode in lowerBound..upperBound
}
override fun equals(o: Any?): Boolean {
if (this === o) return true
if (o == null || javaClass != o.javaClass) return false
val range =
o as Range
return if (lowerBound != range.lowerBound) false else upperBound == range.upperBound
}
override fun hashCode(): Int {
var result = lowerBound
result = 31 * result + upperBound
return result
}
companion object {
/**
* Creates a Range object with lower and upper bound
* @param lowerBound lower limit of Range
* @param upperBound upper limit of Range
*
* @return a Range instance
*/
@JvmStatic
fun of(lowerBound: Int, upperBound: Int): Range {
return Range(lowerBound, upperBound)
}
}
}

@ -0,0 +1,48 @@
package com.hmg.hmgDr.errorhandler.retrofit
import com.hmg.hmgDr.errorhandler.Matcher
import com.hmg.hmgDr.errorhandler.MatcherFactory
import retrofit2.adapter.rxjava.HttpException
object RetrofitMatcherFactory {
/**
* Creates a [MatcherFactory] that checks HTTP statuses
*
* @return new MatcherFactory for Retrofit Rx HttpException that works with Integer
*/
@JvmStatic
fun create(): MatcherFactory<Int> {
return object : MatcherFactory<Int> {
override fun build(errorCode: Int): Matcher {
return object : Matcher {
override fun matches(throwable: Throwable): Boolean {
return throwable is HttpException &&
throwable.code() == errorCode
}
}
}
}
}
/**
* Creates a [MatcherFactory] that checks if HTTP status is in given [Range]
*
* @return new MatcherFactory for Retrofit Rx HttpException that works with Range
*/
@JvmStatic
fun createRange(): MatcherFactory<Range> {
return object : MatcherFactory<Range> {
override fun build(errorCode: Range): Matcher {
return object : Matcher {
override fun matches(throwable: Throwable): Boolean {
return throwable is HttpException &&
errorCode.contains(throwable.code())
}
}
}
}
}
}

@ -32,8 +32,6 @@ object FileUtil {
bufferedWriter.flush()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}
}

@ -1,6 +1,5 @@
package com.hmg.hmgDr.model
import android.app.Notification
import android.app.NotificationManager
import android.os.Build
import androidx.annotation.RequiresApi
@ -12,7 +11,7 @@ class NotificationVideoModel constructor(
mChannelId: String,
mChannelName: CharSequence,
mChannelDescription: String,
mPriority: Int = Notification.PRIORITY_MAX,
mPriority: Int = NotificationCompat.PRIORITY_DEFAULT,
mChannelImportance: Int = NotificationManager.IMPORTANCE_LOW,
mChannelEnableVibrate: Boolean = true,
mChannelLockscreenVisibility: Int = NotificationCompat.VISIBILITY_PUBLIC,
@ -20,6 +19,7 @@ class NotificationVideoModel constructor(
var mBigContentTitle: String = mContentTitle,
val mBigText: String = mContentText,
var mSummaryText: String
) : NotificationDataModel(
mContentTitle,
mContentText,

@ -28,7 +28,7 @@ import com.hmg.hmgDr.ui.VideoCallContract.VideoCallPresenter
import com.hmg.hmgDr.ui.VideoCallContract.VideoCallView
import com.hmg.hmgDr.ui.VideoCallPresenterImpl
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.opentok.android.*
import com.opentok.android.PublisherKit.PublisherListener
@ -294,7 +294,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
recordContainer.visibility = View.GONE
}
// cmTimer = view.findViewById(R.id.cmTimer)
cmTimer = view.findViewById(R.id.cmTimer)
cmTimer.format = "mm:ss"
cmTimer.onChronometerTickListener =
Chronometer.OnChronometerTickListener { arg0: Chronometer? ->

@ -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.res.Resources

@ -3,19 +3,13 @@ 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 {
fun createNotificationChannel(context: Context, notificationDataModel: NotificationDataModel): String{
// The id of the channel.
val channelId: String = notificationDataModel.mChannelId
@ -27,8 +21,7 @@ object NotificationUtil {
val channelDescription: String = notificationDataModel.mChannelDescription
val channelImportance: Int = notificationDataModel.mChannelImportance
val channelEnableVibrate: Boolean = notificationDataModel.mChannelEnableVibrate
val channelLockscreenVisibility: Int =
notificationDataModel.mChannelLockscreenVisibility
val channelLockscreenVisibility: Int = notificationDataModel.mChannelLockscreenVisibility
// Initializes NotificationChannel.
val notificationChannel = NotificationChannel(channelId, channelName, channelImportance)
@ -48,30 +41,4 @@ object NotificationUtil {
}
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.res.Resources

@ -263,7 +263,7 @@ class CustomAudioDevice(context: Context) : BaseAudioDevice() {
return false
}
m_bufferedPlaySamples = 0
outputMode = OutputMode.SpeakerPhone
setOutputMode(OutputMode.SpeakerPhone)
m_shutdownRenderThread = false
Thread(m_renderThread).start()
return true

@ -5,17 +5,9 @@ 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

@ -33,15 +33,15 @@
android:background="@drawable/shape_capsule"
android:padding="@dimen/padding_space_small">
<TextView
android:id="@+id/tv_timer"
<Chronometer
android:id="@+id/cmTimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:textColor="@color/white"
android:textSize="@dimen/text_size_medium"
android:textSize="16sp"
android:textStyle="bold"
android:text="00:00" />
tools:text="25:45" />
</FrameLayout>

@ -46,7 +46,6 @@
tools:text="25:45" />
<ImageView
android:id="@+id/iv_Arrow"
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@drawable/ic_arrow_bottom" />

@ -46,7 +46,6 @@
tools:text="25:45" />
<ImageView
android:id="@+id/iv_Arrow"
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@drawable/ic_arrow_top" />

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="Theme.AppCompat.NoActionBar">
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>

@ -6,9 +6,9 @@ buildscript {
}
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 'com.google.gms:google-services:4.3.3'
classpath 'com.google.gms:google-services:4.3.2'
}
}
@ -17,8 +17,7 @@ allprojects {
google()
jcenter()
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_number": "934365232760",
"project_id": "hmg-dr-app",
"storage_bucket": "hmg-dr-app.appspot.com"
"project_number": "1095694324958",
"project_id": "mobapp-bb272",
"storage_bucket": "mobapp-bb272.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:934365232760:android:024b3569972f1c09f9778d",
"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",
"mobilesdk_app_id": "1:1095694324958:android:70a42e30fcc98ea33fde4f",
"android_client_info": {
"package_name": "com.hmg.hmgDr"
}
},
"oauth_client": [
{
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com",
"client_id": "1095694324958-5psabq8tpbti0uqo8bt46atjtbas9uhr.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCpYwrmuntOBdZv6GV6KEnLj8nQRvEnZ6I"
"current_key": "AIzaSyCuPtf1hTikWXrp5OQIVfqO-TJWubI-Vd8"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "934365232760-bobv1r1sn222le020jeni6u1bdbjdu1v.apps.googleusercontent.com",
"client_id": "1095694324958-5psabq8tpbti0uqo8bt46atjtbas9uhr.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "934365232760-57v2ld1qqulc4nt4o5pgjfbpc47fj3qf.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "COM.HMG.HMGDR"
}
}
]
}
@ -79,4 +36,4 @@
}
],
"configuration_version": "1"
}
}

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
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

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="33.043" height="27.106" viewBox="0 0 33.043 27.106">
<path id="process" d="M28.2,19.555,27.042,21.1l1.549,1.162H25.1a3.868,3.868,0,0,0-3.735-2.9H11.681a3.868,3.868,0,0,0-3.735,2.9H5.808a3.872,3.872,0,0,1,0-7.744H7.946a3.868,3.868,0,0,0,3.735,2.9h9.681a3.868,3.868,0,0,0,3.735-2.9h2.138a5.808,5.808,0,1,0,0-11.617H25.1A3.868,3.868,0,0,0,21.362,0H11.681A3.868,3.868,0,0,0,7.946,2.9H7.1L3.485.194,2.324,1.742,3.872,2.9H0V4.84H3.872L2.324,6,3.485,7.551,7.1,4.84h.847a3.868,3.868,0,0,0,3.735,2.9h9.681A3.868,3.868,0,0,0,25.1,4.84h2.138a3.872,3.872,0,1,1,0,7.744H25.1a3.868,3.868,0,0,0-3.735-2.9H11.681a3.868,3.868,0,0,0-3.735,2.9H5.808a5.808,5.808,0,1,0,0,11.617H7.946a3.868,3.868,0,0,0,3.735,2.9h9.681A3.868,3.868,0,0,0,25.1,24.2h3.494l-1.549,1.162L28.2,26.912l4.84-3.678Zm0,0" fill="#28323a"/>
</svg>

Before

Width:  |  Height:  |  Size: 847 B

@ -1,13 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="31.83" height="27.976" viewBox="0 0 31.83 27.976">
<g id="sticky-note" transform="translate(0 -31.001)">
<g id="Group_7171" data-name="Group 7171" transform="translate(11.19 31.001)">
<path id="Path_4476" data-name="Path 4476" d="M180,38.461V31.934a.933.933,0,0,1,1.865,0v6.528Z" transform="translate(-180 -31.001)" fill="#28323a"/>
</g>
<g id="Group_7172" data-name="Group 7172" transform="translate(0 46.403)">
<path id="Path_4477" data-name="Path 4477" d="M8.393,289.46a2.779,2.779,0,0,1-1.978-.819A28.3,28.3,0,0,1,0,278.751v11.641a.933.933,0,0,0,.933.933H23.313a.933.933,0,0,0,.933-.933v-.933Z" transform="translate(0 -278.751)" fill="#28323a"/>
</g>
<g id="Group_7173" data-name="Group 7173" transform="translate(0 34.731)">
<path id="Path_4478" data-name="Path 4478" d="M31.557,109.924a24.777,24.777,0,0,1-7.312-17.351v-.64A.933.933,0,0,0,23.313,91H14.92v4.663a.933.933,0,0,1-.933.933h-3.73a.933.933,0,0,1-.933-.933V91H.933A.933.933,0,0,0,0,91.934v.64a26.393,26.393,0,0,0,7.733,18.67.934.934,0,0,0,.66.273H30.9a.933.933,0,0,0,.66-1.592ZM12.123,98.461h7.46a.933.933,0,0,1,0,1.865h-7.46a.933.933,0,0,1,0-1.865Zm7.46,9.325H10.258a.933.933,0,0,1,0-1.865h9.325a.933.933,0,0,1,0,1.865Zm1.865-3.73H8.393a.933.933,0,1,1,0-1.865H21.448a.933.933,0,1,1,0,1.865Z" transform="translate(0 -91.001)" fill="#28323a"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="35.842" height="28.675" viewBox="0 0 35.842 28.675">
<path id="Path_4336" data-name="Path 4336" d="M38.948,34.883H29.987V31.3c5.825,0,5.771.134,6.12-.4l1.559-2.285A2.688,2.688,0,0,0,38,23.422a5.377,5.377,0,0,0-5.323-4.669H28.956A12.545,12.545,0,0,0,16.545,8C4.3,8-.668,23.843,9.377,30.823v4.059H6.688a.9.9,0,1,0,0,1.792H38.948a.9.9,0,1,0,0-1.792ZM8.561,21.656a8.065,8.065,0,0,1,14.92-5.224,7.832,7.832,0,0,1,.9,2.321c-2.1,0-1.577.806-1.792.054.161.484.09.224-.367.627a3.584,3.584,0,0,0-6.066,3.8,2.689,2.689,0,0,0,.134,5.377,8.065,8.065,0,0,1-7.724-6.954Zm28.594,3.369a.9.9,0,0,1,.618,1.532c-.367.385,1.174.26-21.228.26a.9.9,0,0,1-.618-1.532C16.286,24.9,14.825,25.026,37.155,25.026Zm-16.542,4.48-.6-.9h4.749a2.841,2.841,0,0,0-.152.9Zm-3.172-8.065a1.792,1.792,0,1,1,1.792,1.792A1.792,1.792,0,0,1,17.442,21.441ZM23.714,31.3h.9v3.584h-.9Zm11.165-1.792H29.987a2.688,2.688,0,0,0-.152-.9H35.48Zm1.263-6.273c-12.993,0-12.249.09-12.706-.215a1.335,1.335,0,0,1-.224-2.079c.5-.565.547-.394,9.463-.394a3.584,3.584,0,0,1,3.468,2.688ZM15.649,32.194h1.792v2.688H15.649Z" transform="translate(-4.002 -8)" fill="#28323a"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30">
<path id="Path_4487" data-name="Path 4487" d="M15.879,1.8V0H14.121V1.8C6.047,2.2,0,8.143,0,15.879V17.3l1.27-.629a8.69,8.69,0,0,1,3.182-.787,5.156,5.156,0,0,1,2.9,1.5l.621.615.62-.615a5.156,5.156,0,0,1,2.9-1.5,4.774,4.774,0,0,1,2.637,1.267V27.363a2.637,2.637,0,0,0,5.273,0V25.605H17.637v1.758a.879.879,0,0,1-1.758,0V17.146a4.774,4.774,0,0,1,2.637-1.267,5.156,5.156,0,0,1,2.9,1.5l.621.615.62-.615a5.344,5.344,0,0,1,2.954-1.5,8.222,8.222,0,0,1,3.123.787L30,17.3V15.879C30,8.143,23.953,2.2,15.879,1.8Z" fill="#28323a"/>
</svg>

Before

Width:  |  Height:  |  Size: 609 B

@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="33.112" height="30.051" viewBox="0 0 33.112 30.051">
<g id="reception" transform="translate(0 -23.667)">
<path id="Path_4479" data-name="Path 4479" d="M0,313.745H33.112V301.673H0Zm15.586-9.318h1.94v2.183h2.183v1.94H17.526v2.183h-1.94V308.55H13.4v-1.94h2.183Z" transform="translate(0 -260.027)" fill="#28323a"/>
<path id="Path_4480" data-name="Path 4480" d="M30,236.668H59.234v2.264H30Z" transform="translate(-28.062 -199.226)" fill="#28323a"/>
<path id="Path_4481" data-name="Path 4481" d="M108.058,103.919c0-.057,0-.113-.005-.169h-6.1c0,.056-.005.112-.005.169a3.057,3.057,0,0,0,2.717,3.034h.672A3.057,3.057,0,0,0,108.058,103.919Z" transform="translate(-95.358 -74.904)" fill="#28323a"/>
<path id="Path_4482" data-name="Path 4482" d="M65.158,153.293h-.911a3.888,3.888,0,0,0-3.86,3.452h4.771v-3.452Z" transform="translate(-56.482 -121.243)" fill="#28323a"/>
<path id="Path_4483" data-name="Path 4483" d="M165.076,153.293h-.911v3.452h4.771a3.888,3.888,0,0,0-3.86-3.452Z" transform="translate(-153.548 -121.243)" fill="#28323a"/>
<path id="Path_4484" data-name="Path 4484" d="M98.828,26.906,99.4,24.35a10.351,10.351,0,0,0-7.394,0l.569,2.556Z" transform="translate(-86.054)" fill="#28323a"/>
<path id="Path_4485" data-name="Path 4485" d="M296.991,135.98h10.025v4.572H296.991Z" transform="translate(-277.784 -105.049)" fill="#28323a"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="17.016" height="15.893" viewBox="0 0 17.016 15.893">
<g id="Layer_2" data-name="Layer 2" transform="translate(-1 -1.98)">
<path id="Path_4511" data-name="Path 4511" d="M15.429,21.777H3.586A2.592,2.592,0,0,1,1,19.2V11H18.016v8.2a2.592,2.592,0,0,1-2.586,2.581ZM2.134,12.134V19.2a1.458,1.458,0,0,0,1.452,1.446H15.429A1.458,1.458,0,0,0,16.881,19.2V12.134Z" transform="translate(0 -3.904)" fill="#28323a"/>
<path id="Path_4512" data-name="Path 4512" d="M18.016,9.1H1V6.6A2.592,2.592,0,0,1,3.586,4H15.429a2.592,2.592,0,0,1,2.586,2.6ZM2.134,7.97H16.881V6.6a1.458,1.458,0,0,0-1.452-1.463H3.586A1.458,1.458,0,0,0,2.134,6.6Z" transform="translate(0 -0.874)" fill="#28323a"/>
<rect id="Rectangle_17397" data-name="Rectangle 17397" width="1.134" height="3.437" rx="0.567" transform="translate(4.369 1.98)" fill="#28323a"/>
<rect id="Rectangle_17398" data-name="Rectangle 17398" width="1.134" height="3.437" rx="0.567" transform="translate(13.512 1.98)" fill="#28323a"/>
<rect id="Rectangle_17399" data-name="Rectangle 17399" width="1.134" height="3.437" rx="0.567" transform="translate(8.941 1.98)" fill="#28323a"/>
<path id="Path_4513" data-name="Path 4513" d="M2.31,12v9.217H17.732V12Zm4.929,5.717a.567.567,0,1,1,.567-.567A.567.567,0,0,1,7.239,17.717Zm2.836,0a.567.567,0,1,1,.567-.567A.567.567,0,0,1,10.075,17.717Zm2.836,0a.567.567,0,1,1,.567-.567A.567.567,0,0,1,12.911,17.717Z" transform="translate(-0.567 -4.337)" fill="#28323a"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

@ -1,4 +0,0 @@
<svg id="add_3_" data-name="add (3)" xmlns="http://www.w3.org/2000/svg" width="25.027" height="25.027" viewBox="0 0 25.027 25.027">
<path id="Path_4468" data-name="Path 4468" d="M20.668,2.086A3.128,3.128,0,0,0,17.728,0H3.128A3.138,3.138,0,0,0,0,3.128v14.6a3.128,3.128,0,0,0,2.086,2.941V7.3A5.214,5.214,0,0,1,7.3,2.086Z" fill="#fff"/>
<path id="Path_4469" data-name="Path 4469" d="M21.728,4H7.128A3.138,3.138,0,0,0,4,7.128v14.6a3.138,3.138,0,0,0,3.128,3.128h14.6a3.138,3.138,0,0,0,3.128-3.128V7.128A3.138,3.138,0,0,0,21.728,4ZM18.6,15.471H15.471V18.6a1.043,1.043,0,0,1-2.086,0V15.471H10.257a1.043,1.043,0,1,1,0-2.086h3.128V10.257a1.043,1.043,0,1,1,2.086,0v3.128H18.6a1.043,1.043,0,0,1,0,2.086Z" transform="translate(0.171 0.171)" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 754 B

@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="18.824" height="29.092" viewBox="0 0 18.824 29.092">
<g id="sugar-blood-level_1_" data-name="sugar-blood-level (1)" transform="translate(-90)">
<path id="Path_4645" data-name="Path 4645" d="M106.257,0H92.567A2.57,2.57,0,0,0,90,2.567V12.835h18.824V2.567A2.57,2.57,0,0,0,106.257,0ZM99.412,11.123a2.57,2.57,0,0,1-2.567-2.567,5.241,5.241,0,0,1,.971-2.5c.44-.758.873-1.387.892-1.414l.7-1.019.7,1.019c.018.026.452.656.892,1.414a5.241,5.241,0,0,1,.971,2.5,2.57,2.57,0,0,1-2.567,2.567Z" fill="#28323a"/>
<path id="Path_4646" data-name="Path 4646" d="M240,119.644a.856.856,0,0,0,1.711,0,6.4,6.4,0,0,0-.856-1.837,6.393,6.393,0,0,0-.856,1.837Z" transform="translate(-141.444 -111.087)" fill="#28323a"/>
<path id="Path_4647" data-name="Path 4647" d="M195,315h6.845v2.567H195Z" transform="translate(-99.01 -297.031)" fill="#28323a"/>
<path id="Path_4648" data-name="Path 4648" d="M223,390h3.537v1.711H223Z" transform="translate(-125.413 -367.753)" fill="#28323a"/>
<path id="Path_4649" data-name="Path 4649" d="M90,256.711a5.142,5.142,0,0,0,4.278,5.062v-5.062h10.268v5.062a5.142,5.142,0,0,0,4.278-5.062V255H90Z" transform="translate(0 -240.454)" fill="#28323a"/>
<path id="Path_4650" data-name="Path 4650" d="M223,450h3.537v3.423H223Z" transform="translate(-125.413 -424.331)" fill="#28323a"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="25.47" height="29.309" viewBox="0 0 25.47 29.309">
<path id="diagnose" d="M59.073,10.053a.6.6,0,0,1,.174.123L63.268,14.2a.6.6,0,0,1,.123.174H59.669a.6.6,0,0,1-.6-.6V10.053ZM55.566,20.885A6.3,6.3,0,0,1,60.6,30.972l1.51,1.51a.811.811,0,0,1,.976.128l4.371,4.371a.81.81,0,0,1,0,1.143l-.951.951a.81.81,0,0,1-1.143,0L60.992,34.7a.811.811,0,0,1-.128-.976l-1.51-1.51a6.3,6.3,0,1,1-3.788-11.332Zm0,1.749a4.55,4.55,0,1,0,4.55,4.55A4.55,4.55,0,0,0,55.566,22.634Zm5.91,14.239-1.327-1.327a1.993,1.993,0,0,1-.584-1.433l-.373-.373a7.487,7.487,0,1,1,2.93-2.93l.373.373a2,2,0,0,1,.948.227V15.562H59.669a1.789,1.789,0,0,1-1.787-1.787V10H42.818a.6.6,0,0,0-.6.6v25.68a.6.6,0,0,0,.6.6H61.476ZM49.529,13.8a.3.3,0,0,1,.3.3v1.67H51.5a.3.3,0,0,1,.3.3V18.09a.3.3,0,0,1-.3.3h-1.67v1.67a.3.3,0,0,1-.3.3H47.508a.3.3,0,0,1-.3-.3v-1.67H45.54a.3.3,0,0,1-.3-.3V16.069a.3.3,0,0,1,.3-.3h1.67V14.1a.3.3,0,0,1,.3-.3Z" transform="translate(-42.222 -10.001)" fill="#28323a" fill-rule="evenodd"/>
</svg>

Before

Width:  |  Height:  |  Size: 1013 B

@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27.001" viewBox="0 0 27 27.001">
<g id="direction_1_" data-name="direction (1)" transform="translate(-0.007 0)">
<g id="Group_7454" data-name="Group 7454" transform="translate(0.007 0)">
<path id="Path_4587" data-name="Path 4587" d="M26.606,12.545h0L14.456.395a1.344,1.344,0,0,0-1.9,0L.4,12.545a1.353,1.353,0,0,0,0,1.91L12.552,26.6v.007a1.353,1.353,0,0,0,1.91,0l12.15-12.15A1.347,1.347,0,0,0,26.606,12.545ZM16.2,16.872V13.5H10.8v4.05H8.1v-5.4a1.345,1.345,0,0,1,1.35-1.35H16.2V7.422l4.725,4.725Z" transform="translate(-0.007 0)" fill="#28323a"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 639 B

@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="26.278" height="28.04" viewBox="0 0 26.278 28.04">
<g id="report_4_" data-name="report (4)" transform="translate(0.918)">
<path id="Path_4470" data-name="Path 4470" d="M19.105,70.875H3.19A2.721,2.721,0,0,1,.412,68.217V46.281A1.766,1.766,0,0,0-.918,47.911V70.394A1.753,1.753,0,0,0,.895,72.084H17.363A1.774,1.774,0,0,0,19.105,70.875Zm0,0" transform="translate(0 -44.044)" fill="#28323a"/>
<path id="Path_4471" data-name="Path 4471" d="M66.516,24.173V12.207H52.852l-.007.748c0,.007,0-.023,0,.038h5.816a.483.483,0,1,1,0,.967h-5.87a.9.9,0,0,1-.626-.282,1.066,1.066,0,0,1-.289-.745l.007-.725H50.863a.473.473,0,0,1-.483-.473v-.071H48.927a.483.483,0,0,1-.483-.479l-.015-2.1a.5.5,0,0,1,.483-.5h0l1.464.029V8.548a.506.506,0,0,1,.482-.511H66.516V5.862H62.423a1.577,1.577,0,0,1-1.588-1.586V0H48.2a1.769,1.769,0,0,0-1.821,1.629.471.471,0,0,1,.013.063c0,.025,0,.05,0,.075V24.173A1.754,1.754,0,0,0,48.2,25.864H64.672A1.783,1.783,0,0,0,66.516,24.173ZM48.933,15.228h7.948a.483.483,0,1,1,0,.967H48.933a.483.483,0,0,1,0-.967Zm13.833,8.037H48.933a.483.483,0,0,1,0-.967H62.766a.483.483,0,0,1,0,.967Zm0-2.357H48.933a.483.483,0,0,1,0-.967H62.766a.483.483,0,1,1,0,.967Zm0-2.357H48.933a.483.483,0,0,1,0-.967H62.766a.483.483,0,1,1,0,.967Zm0,0" transform="translate(-45.014)" fill="#28323a"/>
<path id="Path_4472" data-name="Path 4472" d="M369.314,20.14l-3.983-4.12v3.5a.61.61,0,0,0,.621.619Zm0,0" transform="translate(-348.543 -15.245)" fill="#28323a"/>
<path id="Path_4473" data-name="Path 4473" d="M520.332,195.25v1.4l1.079-.7Zm0,0" transform="translate(-496.051 -185.811)" fill="#28323a"/>
<path id="Path_4474" data-name="Path 4474" d="M149.082,186.25h16.981v2.236H149.082Zm0,0" transform="translate(-142.748 -177.246)" fill="#28323a"/>
<path id="Path_4475" data-name="Path 4475" d="M109.77,198.986v-1.12l-.981-.011.008,1.131Zm0,0" transform="translate(-104.403 -188.29)" fill="#28323a"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="23.812" height="29.735" viewBox="0 0 23.812 29.735">
<g id="insurance_4_" data-name="insurance (4)" transform="translate(-51)">
<path id="Path_4536" data-name="Path 4536" d="M64.94,5.227H60.871a11.918,11.918,0,0,1-4.644,3.251v5.33a11.389,11.389,0,0,0,6.679,10.4,11.389,11.389,0,0,0,6.679-10.4V8.479A11.909,11.909,0,0,1,64.94,5.227Zm2.647,7.494-5.421,5.42a.87.87,0,0,1-1.232,0l-2.71-2.71A.871.871,0,0,1,59.457,14.2l2.094,2.094,4.8-4.8a.871.871,0,0,1,1.232,1.232Zm6.348-8.655a6.734,6.734,0,0,1-5.97-3.6A.871.871,0,0,0,67.195,0H58.617a.872.872,0,0,0-.771.465,6.734,6.734,0,0,1-5.975,3.6A.871.871,0,0,0,51,4.937v8.871A16.66,16.66,0,0,0,62.643,29.695a.868.868,0,0,0,.525,0A16.66,16.66,0,0,0,74.812,13.808V4.937a.876.876,0,0,0-.876-.871Zm-2.608,9.7a13.128,13.128,0,0,1-8.086,12.154.874.874,0,0,1-.67,0,13.128,13.128,0,0,1-8.086-12.154V7.826a.871.871,0,0,1,.6-.828,10.18,10.18,0,0,0,4.709-3.233.871.871,0,0,1,.675-.32h4.876a1.072,1.072,0,0,1,.675.32A10.18,10.18,0,0,0,70.727,7a.869.869,0,0,1,.542.518l0,.008a.881.881,0,0,1,.047.187c0,.006,0,.013,0,.02a.855.855,0,0,1,.006.1Z" fill="#28323a"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="27.217" height="28.675" viewBox="0 0 27.217 28.675">
<path id="path2299" d="M18.879,280.47l-2.477.665-.665,2.477,1.812,1.813,2.477-.665c.229-.823.444-1.649.665-2.474Zm-12.249.576v.968h.962c.012,2.559,0,5.112,0,7.667-.06.132-4.81,10.572-6.755,16.407a2.947,2.947,0,0,0,.057,1.826,2.166,2.166,0,0,0,.462.815,1.276,1.276,0,0,0,.912.415h16.46a1.276,1.276,0,0,0,.912-.415,2.165,2.165,0,0,0,.462-.815,2.947,2.947,0,0,0,.057-1.826c-1.945-5.835-6.7-16.274-6.755-16.407.01-2.556.007-5.111.007-7.667h.969v-.968Zm17.457.918-2.477.661-.662,2.478,1.813,1.816,2.477-.665c.217-.827.442-1.652.665-2.478Zm-11.65.05v4.844l-3.875.011,0-4.841Zm7.9,3.531-2.477.665-.665,2.477,1.816,1.813,2.477-.665q.331-1.239.661-2.478Zm.819,6.152v.968h.968v12.106a10.237,10.237,0,0,0,.183,2.884,2.009,2.009,0,0,0,.754,1.084,2.554,2.554,0,0,0,1.484.389,2.552,2.552,0,0,0,1.483-.389,2,2,0,0,0,.751-1.084,10.232,10.232,0,0,0,.185-2.884V292.666h.968V291.7Zm1.933.968H26v3.875H23.09Zm-9.053,5.342a1.321,1.321,0,0,1-.883,1.654,1.305,1.305,0,0,1-.484.05l-.532,1.228a1.877,1.877,0,0,1,.595,1.923l1.211.682a1.3,1.3,0,0,1,.43-.229,1.328,1.328,0,1,1-.886,1.655,1.3,1.3,0,0,1-.034-.591l-1.193-.672a1.908,1.908,0,0,1-.832.526,1.936,1.936,0,0,1-2.408-1.285,1.912,1.912,0,0,1-.009-1.072l-.831-.468a1.3,1.3,0,0,1-.5.29,1.326,1.326,0,1,1,.882-1.655,1.3,1.3,0,0,1,.049.5l.887.5a1.843,1.843,0,0,1,1.769-.531l.528-1.216a1.3,1.3,0,0,1-.3-.51,1.4,1.4,0,0,1,1.226-1.692,1.236,1.236,0,0,1,1.315.919Z" transform="translate(-0.716 -280.47)" fill="#28323a"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

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

Loading…
Cancel
Save