Compare commits
17 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
690174c79a | 1 week ago |
|
|
70eb84d182 | 4 weeks ago |
|
|
c44c8dac15 | 1 month ago |
|
|
618f967073 | 1 month ago |
|
|
2d4b93d264 | 2 months ago |
|
|
e54ff2ed5a | 2 months ago |
|
|
bc71be6753 | 2 months ago |
|
|
034ab30229 | 2 months ago |
|
|
3f05a1fb46 | 2 months ago |
|
|
92018c0963 | 2 months ago |
|
|
18b56d6496 | 3 months ago |
|
|
936ae7b131 | 3 months ago |
|
|
bb7e9e5a7b | 4 months ago |
|
|
3558e4231f | 4 months ago |
|
|
8f8769d99a | 4 months ago |
|
|
a0ef3cec36 | 4 months ago |
|
|
5fb40a7c5f | 4 months ago |
@ -0,0 +1,74 @@
|
||||
{
|
||||
"agcgw":{
|
||||
"backurl":"connect-drcn.hispace.hicloud.com",
|
||||
"url":"connect-drcn.dbankcloud.cn",
|
||||
"websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com",
|
||||
"websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn"
|
||||
},
|
||||
"agcgw_all":{
|
||||
"CN":"connect-drcn.dbankcloud.cn",
|
||||
"CN_back":"connect-drcn.hispace.hicloud.com",
|
||||
"DE":"connect-dre.dbankcloud.cn",
|
||||
"DE_back":"connect-dre.hispace.hicloud.com",
|
||||
"RU":"connect-drru.dbankcloud.cn",
|
||||
"RU_back":"connect-drru.hispace.hicloud.com",
|
||||
"SG":"connect-dra.dbankcloud.cn",
|
||||
"SG_back":"connect-dra.hispace.hicloud.com"
|
||||
},
|
||||
"client":{
|
||||
"cp_id":"2640966000002322881",
|
||||
"product_id":"736430079244816567",
|
||||
"client_id":"563735388191982656",
|
||||
"client_secret":"650C7C799812AFFD53A10C7756CF05FB9F215A7E49032ABA8EBF3E14B77535CF",
|
||||
"project_id":"736430079244816567",
|
||||
"app_id":"102857389",
|
||||
"api_key":"CgB6e3x9DJzMgRCmnT6dyUEkp6UsIfddb6l3w0ZEXzeiRMHEFi3400Z5fJ5qaHneU0OrAI/JRpk+DMGVs3QpUxlI",
|
||||
"package_name":"com.ejada.hmg"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_id":"102857389",
|
||||
"client_type":1
|
||||
},
|
||||
"app_info":{
|
||||
"app_id":"102857389",
|
||||
"package_name":"com.ejada.hmg"
|
||||
},
|
||||
"service":{
|
||||
"analytics":{
|
||||
"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
|
||||
"collector_url_ru":"datacollector-drru.dt.hicloud.com,datacollector-drru.dt.dbankcloud.cn",
|
||||
"collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn",
|
||||
"collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
||||
"collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
|
||||
"resource_id":"p1",
|
||||
"channel_id":""
|
||||
},
|
||||
"search":{
|
||||
"url":"https://search-drcn.cloud.huawei.com"
|
||||
},
|
||||
"cloudstorage":{
|
||||
"storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn"
|
||||
},
|
||||
"ml":{
|
||||
"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"
|
||||
}
|
||||
},
|
||||
"region":"CN",
|
||||
"configuration_version":"3.0",
|
||||
"appInfos":[
|
||||
{
|
||||
"package_name":"com.ejada.hmg",
|
||||
"client":{
|
||||
"app_id":"102857389"
|
||||
},
|
||||
"app_info":{
|
||||
"package_name":"com.ejada.hmg",
|
||||
"app_id":"102857389"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_type":1,
|
||||
"client_id":"102857389"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package io.flutter.plugins.firebasemessaging;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
|
||||
//public class CustomFlutterFirebaseMessagingService extends FlutterFirebaseMessagingService {
|
||||
// @Override
|
||||
// public void onMessageReceived(RemoteMessage remoteMessage) {
|
||||
// if (remoteMessage.getData().containsKey("is_call")) {
|
||||
// Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
|
||||
// startActivity(intent);
|
||||
// super.onMessageReceived(remoteMessage);
|
||||
// } else
|
||||
// super.onMessageReceived(remoteMessage);
|
||||
// }
|
||||
//}
|
||||
|
||||
public class CustomFlutterFirebaseMessagingService extends FlutterFirebaseMessagingService {
|
||||
@Override
|
||||
public void onMessageReceived(RemoteMessage remoteMessage) {
|
||||
if (remoteMessage.getData().containsKey("is_call")) {
|
||||
Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivity(intent);
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(5);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
super.onMessageReceived(remoteMessage);
|
||||
} else
|
||||
super.onMessageReceived(remoteMessage);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package io.flutter.plugins.firebase.messaging;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FlutterFirebaseMessagingReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = "FLTFireMsgReceiver";
|
||||
static HashMap<String, RemoteMessage> notifications = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "broadcast received for message");
|
||||
if (ContextHolder.getApplicationContext() == null) {
|
||||
ContextHolder.setApplicationContext(context.getApplicationContext());
|
||||
}
|
||||
|
||||
if (intent.getExtras() == null) {
|
||||
Log.d(
|
||||
TAG,
|
||||
"broadcast received but intent contained no extras to process RemoteMessage. Operation cancelled.");
|
||||
return;
|
||||
}
|
||||
|
||||
RemoteMessage remoteMessage = new RemoteMessage(intent.getExtras());
|
||||
|
||||
// Store the RemoteMessage if the message contains a notification payload.
|
||||
if (remoteMessage.getNotification() != null) {
|
||||
notifications.put(remoteMessage.getMessageId(), remoteMessage);
|
||||
FlutterFirebaseMessagingStore.getInstance().storeFirebaseMessage(remoteMessage);
|
||||
}
|
||||
|
||||
// |-> ---------------------
|
||||
// App in Foreground
|
||||
// ------------------------
|
||||
if (FlutterFirebaseMessagingUtils.isApplicationForeground(context)) {
|
||||
Intent onMessageIntent = new Intent(FlutterFirebaseMessagingUtils.ACTION_REMOTE_MESSAGE);
|
||||
onMessageIntent.putExtra(FlutterFirebaseMessagingUtils.EXTRA_REMOTE_MESSAGE, remoteMessage);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(onMessageIntent);
|
||||
return;
|
||||
}
|
||||
|
||||
// |-> ---------------------
|
||||
// App in Background/Quit
|
||||
// ------------------------
|
||||
|
||||
|
||||
if (remoteMessage.getData().containsKey("is_call")) {
|
||||
Intent intent12 = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
context.startActivity(intent12);
|
||||
try {
|
||||
new Timer().schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Intent onMessageIntent = new Intent(FlutterFirebaseMessagingUtils.ACTION_REMOTE_MESSAGE);
|
||||
onMessageIntent.putExtra(FlutterFirebaseMessagingUtils.EXTRA_REMOTE_MESSAGE, remoteMessage);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(onMessageIntent);
|
||||
}
|
||||
}, 5000);
|
||||
} catch (Exception e) {
|
||||
Log.e("AppCallingException", e.getMessage());
|
||||
}
|
||||
// super.onMessageReceived(remoteMessage);
|
||||
} //else
|
||||
// super.onMessageReceived(remoteMessage);
|
||||
//
|
||||
// if (remoteMessage.getData().containsKey("is_call")) {
|
||||
// Log.e("AppCalling", "started...");
|
||||
// Intent intent12 = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
|
||||
// intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
// context.startActivity(intent12);
|
||||
// try {
|
||||
// Log.e("AppCalling", "going to sleep...");
|
||||
// TimeUnit.SECONDS.sleep(10);
|
||||
// Log.e("AppCalling", "sendig to broadcast receiver...");
|
||||
// Log.e("AppCalling:DAta", remoteMessage.getData().containsKey("is_call") + "");
|
||||
// Intent onBackgroundMessageIntent =
|
||||
// new Intent(context, FlutterFirebaseMessagingBackgroundService.class);
|
||||
// onBackgroundMessageIntent.putExtra(
|
||||
// FlutterFirebaseMessagingUtils.EXTRA_REMOTE_MESSAGE, remoteMessage);
|
||||
// FlutterFirebaseMessagingBackgroundService.enqueueMessageProcessing(
|
||||
// context, onBackgroundMessageIntent);
|
||||
// //return;
|
||||
// } catch (Exception e) {
|
||||
// Log.e("AppCallingException", e.getMessage());
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
Intent onBackgroundMessageIntent =
|
||||
new Intent(context, FlutterFirebaseMessagingBackgroundService.class);
|
||||
onBackgroundMessageIntent.putExtra(
|
||||
FlutterFirebaseMessagingUtils.EXTRA_REMOTE_MESSAGE, remoteMessage);
|
||||
FlutterFirebaseMessagingBackgroundService.enqueueMessageProcessing(
|
||||
context, onBackgroundMessageIntent);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
{
|
||||
"agcgw":{
|
||||
"backurl":"connect-drcn.hispace.hicloud.com",
|
||||
"url":"connect-drcn.dbankcloud.cn",
|
||||
"websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com",
|
||||
"websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn"
|
||||
},
|
||||
"agcgw_all":{
|
||||
"CN":"connect-drcn.dbankcloud.cn",
|
||||
"CN_back":"connect-drcn.hispace.hicloud.com",
|
||||
"DE":"connect-dre.dbankcloud.cn",
|
||||
"DE_back":"connect-dre.hispace.hicloud.com",
|
||||
"RU":"connect-drru.dbankcloud.cn",
|
||||
"RU_back":"connect-drru.hispace.hicloud.com",
|
||||
"SG":"connect-dra.dbankcloud.cn",
|
||||
"SG_back":"connect-dra.hispace.hicloud.com"
|
||||
},
|
||||
"client":{
|
||||
"cp_id":"2640966000002322881",
|
||||
"product_id":"736430079244816567",
|
||||
"client_id":"563735388191982656",
|
||||
"client_secret":"650C7C799812AFFD53A10C7756CF05FB9F215A7E49032ABA8EBF3E14B77535CF",
|
||||
"project_id":"736430079244816567",
|
||||
"app_id":"102857389",
|
||||
"api_key":"CgB6e3x9DJzMgRCmnT6dyUEkp6UsIfddb6l3w0ZEXzeiRMHEFi3400Z5fJ5qaHneU0OrAI/JRpk+DMGVs3QpUxlI",
|
||||
"package_name":"com.ejada.hmg"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_id":"102857389",
|
||||
"client_type":1
|
||||
},
|
||||
"app_info":{
|
||||
"app_id":"102857389",
|
||||
"package_name":"com.ejada.hmg"
|
||||
},
|
||||
"service":{
|
||||
"analytics":{
|
||||
"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
|
||||
"collector_url_ru":"datacollector-drru.dt.hicloud.com,datacollector-drru.dt.dbankcloud.cn",
|
||||
"collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn",
|
||||
"collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
||||
"collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
|
||||
"resource_id":"p1",
|
||||
"channel_id":""
|
||||
},
|
||||
"search":{
|
||||
"url":"https://search-drcn.cloud.huawei.com"
|
||||
},
|
||||
"cloudstorage":{
|
||||
"storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn"
|
||||
},
|
||||
"ml":{
|
||||
"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"
|
||||
}
|
||||
},
|
||||
"region":"CN",
|
||||
"configuration_version":"3.0",
|
||||
"appInfos":[
|
||||
{
|
||||
"package_name":"com.ejada.hmg",
|
||||
"client":{
|
||||
"app_id":"102857389"
|
||||
},
|
||||
"app_info":{
|
||||
"package_name":"com.ejada.hmg",
|
||||
"app_id":"102857389"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_type":1,
|
||||
"client_id":"102857389"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
{
|
||||
"agcgw":{
|
||||
"backurl":"connect-drcn.hispace.hicloud.com",
|
||||
"url":"connect-drcn.dbankcloud.cn",
|
||||
"websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com",
|
||||
"websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn"
|
||||
},
|
||||
"agcgw_all":{
|
||||
"CN":"connect-drcn.dbankcloud.cn",
|
||||
"CN_back":"connect-drcn.hispace.hicloud.com",
|
||||
"DE":"connect-dre.dbankcloud.cn",
|
||||
"DE_back":"connect-dre.hispace.hicloud.com",
|
||||
"RU":"connect-drru.dbankcloud.cn",
|
||||
"RU_back":"connect-drru.hispace.hicloud.com",
|
||||
"SG":"connect-dra.dbankcloud.cn",
|
||||
"SG_back":"connect-dra.hispace.hicloud.com"
|
||||
},
|
||||
"client":{
|
||||
"cp_id":"2640966000002322881",
|
||||
"product_id":"736430079244816567",
|
||||
"client_id":"563735388191982656",
|
||||
"client_secret":"650C7C799812AFFD53A10C7756CF05FB9F215A7E49032ABA8EBF3E14B77535CF",
|
||||
"project_id":"736430079244816567",
|
||||
"app_id":"102857389",
|
||||
"api_key":"CgB6e3x9DJzMgRCmnT6dyUEkp6UsIfddb6l3w0ZEXzeiRMHEFi3400Z5fJ5qaHneU0OrAI/JRpk+DMGVs3QpUxlI",
|
||||
"package_name":"com.ejada.hmg"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_id":"102857389",
|
||||
"client_type":1
|
||||
},
|
||||
"app_info":{
|
||||
"app_id":"102857389",
|
||||
"package_name":"com.ejada.hmg"
|
||||
},
|
||||
"service":{
|
||||
"analytics":{
|
||||
"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
|
||||
"collector_url_ru":"datacollector-drru.dt.hicloud.com,datacollector-drru.dt.dbankcloud.cn",
|
||||
"collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn",
|
||||
"collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
||||
"collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
|
||||
"resource_id":"p1",
|
||||
"channel_id":""
|
||||
},
|
||||
"search":{
|
||||
"url":"https://search-drcn.cloud.huawei.com"
|
||||
},
|
||||
"cloudstorage":{
|
||||
"storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn"
|
||||
},
|
||||
"ml":{
|
||||
"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"
|
||||
}
|
||||
},
|
||||
"region":"CN",
|
||||
"configuration_version":"3.0",
|
||||
"appInfos":[
|
||||
{
|
||||
"package_name":"com.ejada.hmg",
|
||||
"client":{
|
||||
"app_id":"102857389"
|
||||
},
|
||||
"app_info":{
|
||||
"package_name":"com.ejada.hmg",
|
||||
"app_id":"102857389"
|
||||
},
|
||||
"oauth_client":{
|
||||
"client_type":1,
|
||||
"client_id":"102857389"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,176 @@
|
||||
plugins {
|
||||
id "com.android.application"
|
||||
id "kotlin-android"
|
||||
id "com.google.gms.google-services"
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
id "com.google.firebase.crashlytics"
|
||||
id "com.huawei.agconnect"
|
||||
// id("com.mapbox.gradle.application")
|
||||
// id("com.mapbox.gradle.plugins.ndk")
|
||||
}
|
||||
|
||||
|
||||
def keystoreProperties = new Properties()
|
||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
|
||||
android {
|
||||
namespace 'com.ejada.hmg'
|
||||
compileSdk 36
|
||||
ndkVersion '28.2.13676358'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.ejada.hmg"
|
||||
// minSdk 24
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 35
|
||||
compileSdkVersion 35
|
||||
// targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
dataBinding true
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDirs += 'src/main/kotlin'
|
||||
jniLibs.srcDir 'src/main/libs'
|
||||
jni.srcDirs = [] // disables automatic ndk-build
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
debuggable true
|
||||
signingConfig signingConfigs.debug
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
}
|
||||
release {
|
||||
debuggable false
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
staging {
|
||||
matchingFallbacks = ['debug', 'qa', 'release']
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
pickFirsts += ['lib/x86/libc++_shared.so', 'lib/x86_64/libc++_shared.so', 'lib/armeabi-v7a/libc++_shared.so', 'lib/arm64-v8a/libc++_shared.so', '**/*.so']
|
||||
useLegacyPackaging true
|
||||
}
|
||||
resources {
|
||||
excludes += ['META-INF/proguard/androidx-annotations.pro']
|
||||
}
|
||||
}
|
||||
|
||||
// Enable core library desugaring
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
targetCompatibility JavaVersion.VERSION_21
|
||||
coreLibraryDesugaringEnabled true
|
||||
}
|
||||
|
||||
// kotlinOptions {
|
||||
// jvmTarget = '17'
|
||||
// }
|
||||
|
||||
lint {
|
||||
disable 'MissingTranslation'
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20"
|
||||
implementation "com.google.firebase:firebase-messaging:24.1.2"
|
||||
implementation 'pub.devrel:easypermissions:3.0.0'
|
||||
implementation 'com.google.guava:guava:33.4.0-android'
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'], exclude: ['bcprov-jdk16-1.46.jar'])
|
||||
|
||||
implementation 'com.google.code.gson:gson:2.12.0'
|
||||
|
||||
// Zoom SDKs
|
||||
implementation "us.zoom.videosdk:zoomvideosdk-core:1.12.10"
|
||||
implementation "us.zoom.videosdk:zoomvideosdk-annotation:1.12.10"
|
||||
implementation "us.zoom.videosdk:zoomvideosdk-videoeffects:1.12.10"
|
||||
|
||||
// Networking
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.11'
|
||||
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.11'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.11.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.11.0'
|
||||
implementation 'com.squareup.retrofit2:adapter-java8:2.11.0'
|
||||
|
||||
// Google Services
|
||||
implementation 'com.google.android.gms:play-services-location:21.3.0'
|
||||
implementation 'com.google.android.gms:play-services-basement:18.7.0'
|
||||
|
||||
implementation 'com.android.volley:volley:1.2.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.9.0'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.9.0'
|
||||
implementation 'androidx.activity:activity-ktx:1.10.1'
|
||||
|
||||
def room_version = "2.6.1"
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
annotationProcessor "androidx.room:room-compiler:$room_version"
|
||||
|
||||
implementation 'net.zetetic:android-database-sqlcipher:4.5.4'
|
||||
implementation 'com.intuit.ssp:ssp-android:1.1.0'
|
||||
implementation 'com.intuit.sdp:sdp-android:1.1.0'
|
||||
|
||||
implementation 'com.github.bumptech.glide:glide:4.16.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
|
||||
|
||||
implementation 'com.mapbox.maps:android:11.5.0'
|
||||
// implementation 'com.mapbox.maps:android:11.4.0'
|
||||
|
||||
// AARs
|
||||
implementation files('libs/PenNavUI.aar')
|
||||
implementation files('libs/Penguin.aar')
|
||||
implementation files('libs/PenguinRenderer.aar')
|
||||
|
||||
implementation 'com.github.kittinunf.fuel:fuel:2.3.1'
|
||||
implementation 'com.github.kittinunf.fuel:fuel-android:2.3.1'
|
||||
|
||||
implementation "com.opentok.android:opentok-android-sdk:2.25.2"
|
||||
|
||||
implementation 'com.facebook.stetho:stetho:1.6.0'
|
||||
implementation 'com.facebook.stetho:stetho-urlconnection:1.6.0'
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.16.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.1'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
|
||||
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.25'
|
||||
|
||||
androidTestImplementation "androidx.test:core:1.6.1"
|
||||
implementation 'com.whatsapp.otp:whatsapp-otp-android-sdk:0.1.0'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
||||
// implementation project(':vitalSignEngine')
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "815750722565",
|
||||
"firebase_url": "https://api-project-815750722565.firebaseio.com",
|
||||
"project_id": "api-project-815750722565",
|
||||
"storage_bucket": "api-project-815750722565.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:815750722565:android:62281cd3e5df4063",
|
||||
"android_client_info": {
|
||||
"package_name": "com.ejada.hmg"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "815750722565-3a0gc7neins0eoahdrimrfksk0sqice8.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDZDeWcBlRE3YfJWYt_DCiToVnANfaj8qg"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "815750722565-3a0gc7neins0eoahdrimrfksk0sqice8.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "815750722565-0cq9366orvsk5ipivq6lijcj56u03fr7.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.void.demo"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
#Sun Sep 20 09:53:06 EEST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
||||
#distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@ -0,0 +1,8 @@
|
||||
## This file must *NOT* be checked into Version Control Systems,
|
||||
# as it contains information specific to your local configuration.
|
||||
#
|
||||
# Location of the SDK. This is only used by Gradle.
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
#Sun Sep 20 09:53:03 EEST 2020
|
||||
sdk.dir=/Users/erababah/Library/Android/sdk
|
||||
@ -0,0 +1,72 @@
|
||||
-keep class tvi.webrtc.** { *; }
|
||||
-keep class com.twilio.video.** { *; }
|
||||
-keep class com.twilio.common.** { *; }
|
||||
-keepattributes InnerClasses
|
||||
|
||||
-keep class com.ejada.** { *; }
|
||||
-keep class org.webrtc.** { *; }
|
||||
|
||||
-keep class com.builttoroam.devicecalendar.** { *; }
|
||||
|
||||
-ignorewarnings
|
||||
-keepattributes *Annotation*
|
||||
-keepattributes Exceptions
|
||||
-keepattributes InnerClasses
|
||||
-keepattributes Signature
|
||||
-keep class com.hianalytics.android.**{*;}
|
||||
-keep class com.huawei.updatesdk.**{*;}
|
||||
-keep class com.huawei.hms.**{*;}
|
||||
|
||||
## Flutter wrapper
|
||||
-keep class io.flutter.app.** { *; }
|
||||
-keep class io.flutter.plugin.** { *; }
|
||||
-keep class io.flutter.util.** { *; }
|
||||
-keep class io.flutter.view.** { *; }
|
||||
-keep class io.flutter.** { *; }
|
||||
-keep class io.flutter.plugins.** { *; }
|
||||
-dontwarn io.flutter.embedding.**
|
||||
-keep class com.huawei.hms.flutter.** { *; }
|
||||
-repackageclasses
|
||||
|
||||
## Flutter WebRTC
|
||||
-keep class com.cloudwebrtc.webrtc.** { *; }
|
||||
-keep class org.webrtc.** { *; }
|
||||
|
||||
## Flutter OpenTok
|
||||
-keep class com.opentok.android.** { *; }
|
||||
-keep class com.opentok.otc.** { *; }
|
||||
-keep class org.otwebrtc.** { *; }
|
||||
|
||||
|
||||
##Flutter Zoom
|
||||
-keep class us.zoom**{
|
||||
*;
|
||||
}
|
||||
-keep interface us.zoom**{
|
||||
*;
|
||||
}
|
||||
-keep class org.webrtc**{
|
||||
*;
|
||||
}
|
||||
-keep class com.zipow**{
|
||||
*;
|
||||
}
|
||||
|
||||
-dontwarn com.opentok.android.**
|
||||
-dontwarn com.opentok.otc.**
|
||||
|
||||
-dontwarn penguin.com.pennav.Model.Navigation.NearLandmark
|
||||
|
||||
-keep,includedescriptorclasses class net.sqlcipher.** { *; }
|
||||
-keep,includedescriptorclasses interface net.sqlcipher.** { *; }
|
||||
|
||||
-keep class retrofit2.** { *; }
|
||||
-keep class okhttp3.** { *; }
|
||||
-dontwarn retrofit2.**
|
||||
|
||||
-keep class com.google.gson.** { *; }
|
||||
-dontwarn com.google.gson.**
|
||||
|
||||
# Penguin classes
|
||||
-keep class com.peng.pennavmap.models.** { *; }
|
||||
-keep class com.peng.pennavmap.db.** { *; }
|
||||
@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.ejada.hmg">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
@ -0,0 +1,260 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.ejada.hmg">
|
||||
<!--
|
||||
io.flutter.app.FlutterApplication is an android.app.Application that
|
||||
calls FlutterMain.startInitialization(this); in its onCreate method.
|
||||
In most cases you can leave this as-is, but you if you want to provide
|
||||
additional functionality it is fine to subclass or reimplement
|
||||
FlutterApplication and put your custom class here.
|
||||
-->
|
||||
<uses-permission
|
||||
android:name="android.permission.ACTIVITY_RECOGNITION"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_PHONE_STATE"
|
||||
tools:node="remove" /> <!-- <uses-permission android:name="android.permission.BLUETOOTH" tools:node="remove"/> -->
|
||||
<!-- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" tools:node="remove"/> -->
|
||||
<!-- <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" tools:node="remove"/> -->
|
||||
<!-- <uses-permission android:name="android.permission.BLUETOOTH_SCAN" tools:node="remove"/> -->
|
||||
<uses-permission
|
||||
android:name="android.permission.BROADCAST_STICKY"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="com.google.android.gms.permission.AD_ID"
|
||||
tools:node="remove" /> <!-- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> -->
|
||||
<uses-permission
|
||||
android:name="android.permission.FOREGROUND_SERVICE"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"
|
||||
tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
|
||||
|
||||
<!-- Added by open_filex -->
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" tools:node="remove" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
|
||||
tools:node="remove" /> <!-- <uses-permission android:name="android.permission.INTERNET" /> -->
|
||||
<!-- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> -->
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.sensor.stepcounter"
|
||||
android:required="false"
|
||||
tools:node="replace" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.sensor.stepdetector"
|
||||
android:required="false"
|
||||
tools:node="replace" />
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="true" />
|
||||
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.location.network"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.location.gps"
|
||||
android:required="false" />
|
||||
|
||||
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA" /> <!-- <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" /> -->
|
||||
<!-- Wifi Permissions -->
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> -->
|
||||
<!-- Detect Reboot Permission -->
|
||||
<!-- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.speech.RecognitionService" />
|
||||
</intent>
|
||||
|
||||
<package android:name="com.whatsapp" />
|
||||
<package android:name="com.whatsapp.w4b" />
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:name=".Application"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher_local"
|
||||
android:label="Dr. Alhabib"
|
||||
android:screenOrientation="sensorPortrait"
|
||||
android:showOnLockScreen="true"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:replace="android:label">
|
||||
<activity
|
||||
android:name="com.cloud.hmg_patient_app.whatsapp.WhatsAppCodeActivity"
|
||||
android:exported="true"
|
||||
android:enabled="true"
|
||||
android:launchMode="standard"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="com.whatsapp.otp.OTP_RETRIEVED" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<meta-data
|
||||
android:name="push_kit_auto_init_enabled"
|
||||
android:value="true" />
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleTop"
|
||||
android:showOnLockScreen="true"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
tools:node="merge">
|
||||
|
||||
<!--
|
||||
Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI.
|
||||
-->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme" />
|
||||
<!--
|
||||
Displays an Android View that continues showing the launch screen
|
||||
Drawable until Flutter paints its first frame, then this splash
|
||||
screen fades out. A splash screen is useful to avoid any visual
|
||||
gap between the end of Android's launch screen and the painting of
|
||||
Flutter's first frame.
|
||||
-->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||
android:resource="@drawable/launch_background" />
|
||||
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity> <!-- <receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver" android:exported="true"> -->
|
||||
<!-- <intent-filter> -->
|
||||
<!-- <action android:name="android.intent.action.BOOT_COMPLETED"/> -->
|
||||
<!-- <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/> -->
|
||||
<!-- </intent-filter> -->
|
||||
<!-- </receiver> -->
|
||||
<!-- Geofencing -->
|
||||
<service
|
||||
android:name=".geofence.intent_receivers.GeofenceTransitionsJobIntentService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
<receiver
|
||||
android:name=".geofence.intent_receivers.GeofenceBroadcastReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
<receiver
|
||||
android:name=".geofence.intent_receivers.GeofencingRebootBroadcastReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".geofence.intent_receivers.LocationProviderChangeReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.location.PROVIDERS_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".geofence.intent_receivers.ReregisterGeofenceJobService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" /> <!-- Geofencing -->
|
||||
<!--
|
||||
Huawei Push Notifications
|
||||
Set push kit auto enable to true (for obtaining the token on initialize)
|
||||
-->
|
||||
<!-- <meta-data -->
|
||||
<!-- android:name="push_kit_auto_init_enabled" -->
|
||||
<!-- android:value="true" /> -->
|
||||
<!-- These receivers are for sending scheduled local notifications -->
|
||||
<receiver
|
||||
android:name="com.huawei.hms.flutter.push.receiver.local.HmsLocalNotificationBootEventReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name="com.huawei.hms.flutter.push.receiver.local.HmsLocalNotificationScheduledPublisher"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
<receiver
|
||||
android:name="com.huawei.hms.flutter.push.receiver.BackgroundMessageBroadcastReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.huawei.hms.flutter.push.receiver.BACKGROUND_REMOTE_MESSAGE" />
|
||||
</intent-filter>
|
||||
</receiver> <!-- Huawei Push Notifications -->
|
||||
<meta-data
|
||||
android:name="com.google.android.geo.API_KEY"
|
||||
android:value="AIzaSyCyDbWUM9d_sBUGIE8PcuShzPaqO08NSC8" />
|
||||
<!--
|
||||
Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java
|
||||
-->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -0,0 +1,51 @@
|
||||
//package com.cloud.diplomaticquarterapp
|
||||
package com.ejada.hmg
|
||||
|
||||
import com.facebook.stetho.Stetho
|
||||
import io.flutter.app.FlutterApplication
|
||||
|
||||
class Application : FlutterApplication() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
// Stetho.initializeWithDefaults(this);
|
||||
// Create an InitializerBuilder
|
||||
// Create an InitializerBuilder
|
||||
val initializerBuilder = Stetho.newInitializerBuilder(this)
|
||||
|
||||
|
||||
// Enable Chrome DevTools
|
||||
initializerBuilder.enableWebKitInspector(
|
||||
Stetho.defaultInspectorModulesProvider(this)
|
||||
)
|
||||
|
||||
// Enable command line interface
|
||||
initializerBuilder.enableDumpapp(
|
||||
Stetho.defaultDumperPluginsProvider(this)
|
||||
)
|
||||
|
||||
|
||||
// Use the InitializerBuilder to generate an Initializer
|
||||
val initializer = initializerBuilder.build()
|
||||
|
||||
|
||||
// Initialize Stetho with the Initializer
|
||||
Stetho.initialize(initializer)
|
||||
}
|
||||
}
|
||||
|
||||
//import io.flutter.app.FlutterApplication
|
||||
//import io.flutter.plugin.common.PluginRegistry
|
||||
//import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
|
||||
//import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService
|
||||
//
|
||||
//class Application : FlutterApplication(), PluginRegistrantCallback {
|
||||
// override fun onCreate() {
|
||||
// super.onCreate()
|
||||
// FlutterFirebaseMessagingService.setPluginRegistrant(this)
|
||||
// }
|
||||
//
|
||||
// override fun registerWith(registry: PluginRegistry?) {
|
||||
// FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,8 @@
|
||||
//package com.cloud.diplomaticquarterapp
|
||||
package com.ejada.hmg
|
||||
|
||||
object FirebaseCloudMessagingPluginRegistrant {
|
||||
fun registerWith(registry: Any?) {
|
||||
// No-op: v1 plugin registration is not supported in recent Flutter versions.
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.ejada.hmg
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.cloud.hmg_patient_app.PenguinInPlatformBridge
|
||||
import com.cloud.hmg_patient_app.whatsapp.AppSignatureRetriever
|
||||
import com.ejada.hmg.utils.*
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||
import com.cloud.hmg_patient_app.whatsapp.WhatsApp
|
||||
import com.cloud.hmg_patient_app.whatsapp.WhatsAppOtpPlatformBridge
|
||||
|
||||
|
||||
class MainActivity: FlutterFragmentActivity() {
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
// Create Flutter Platform Bridge
|
||||
this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON)
|
||||
|
||||
PlatformBridge(flutterEngine, this).create()
|
||||
OpenTokPlatformBridge(flutterEngine, this).create()
|
||||
PenguinInPlatformBridge(flutterEngine, this).create()
|
||||
WhatsAppOtpPlatformBridge(flutterEngine, this).invoke()
|
||||
AppSignatureRetriever().logSignatures(this)
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {x
|
||||
// val mChannel = NotificationChannel("video_call_noti", "video call", NotificationManager.IMPORTANCE_HIGH)
|
||||
// val soundUri = Uri.parse("android.resource://" + getApplicationContext()
|
||||
// .getPackageName() + "/" + R.raw.alert)
|
||||
// System.out.println("soundUri");
|
||||
// System.out.println("soundUri: $soundUri");
|
||||
// System.out.println("soundUri : ${soundUri.path}");
|
||||
// val att = AudioAttributes.Builder()
|
||||
// .setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
||||
// .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
|
||||
// .build();
|
||||
// mChannel.setSound(soundUri , att)
|
||||
// mChannel.description = "Video Call Notifications"
|
||||
// val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
// notificationManager.createNotificationChannel(mChannel)
|
||||
// }
|
||||
|
||||
// val time = timeToMillis("04:00:00", "HH:mm:ss")
|
||||
|
||||
}
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
|
||||
val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
|
||||
val intent = Intent("PERMISSION_RESULT_ACTION").apply {
|
||||
putExtra("PERMISSION_GRANTED", granted)
|
||||
}
|
||||
sendBroadcast(intent)
|
||||
|
||||
// Log the request code and permission results
|
||||
Log.d("PermissionsResult", "Request Code: $requestCode")
|
||||
Log.d("PermissionsResult", "Permissions: ${permissions.joinToString()}")
|
||||
Log.d("PermissionsResult", "Grant Results: ${grantResults.joinToString()}")
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.cloud.hmg_patient_app
|
||||
|
||||
import com.ejada.hmg.MainActivity
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.cloud.hmg_patient_app.penguin.PenguinView
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
class PenguinInPlatformBridge(
|
||||
private var flutterEngine: FlutterEngine,
|
||||
private var mainActivity: MainActivity
|
||||
) {
|
||||
|
||||
private lateinit var channel: MethodChannel
|
||||
|
||||
companion object {
|
||||
private const val CHANNEL = "launch_penguin_ui"
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun create() {
|
||||
// openTok = OpenTok(mainActivity, flutterEngine)
|
||||
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
|
||||
channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
|
||||
when (call.method) {
|
||||
"launchPenguin" -> {
|
||||
print("the platform channel is being called")
|
||||
val args = call.arguments as Map<String, Any>?
|
||||
Log.d("TAG", "configureFlutterEngine: $args")
|
||||
println("args")
|
||||
args?.let {
|
||||
PenguinView(
|
||||
mainActivity,
|
||||
100,
|
||||
args,
|
||||
flutterEngine.dartExecutor.binaryMessenger,
|
||||
activity = mainActivity,
|
||||
channel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
result.notImplemented()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.cloud.hmg_patient_app.PermissionManager
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
|
||||
object PermissionHelper {
|
||||
|
||||
fun getRequiredPermissions(): Array<String> {
|
||||
val permissions = mutableListOf(
|
||||
Manifest.permission.INTERNET,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
Manifest.permission.ACCESS_NETWORK_STATE,
|
||||
Manifest.permission.BLUETOOTH,
|
||||
Manifest.permission.BLUETOOTH_ADMIN,
|
||||
// Manifest.permission.ACTIVITY_RECOGNITION
|
||||
)
|
||||
|
||||
// For Android 12 (API level 31) and above, add specific permissions
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12 (API 31) and above
|
||||
permissions.add(Manifest.permission.BLUETOOTH_SCAN)
|
||||
permissions.add(Manifest.permission.BLUETOOTH_CONNECT)
|
||||
permissions.add(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS)
|
||||
}
|
||||
|
||||
return permissions.toTypedArray()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package com.cloud.hmg_patient_app.PermissionManager
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
class PermissionManager(
|
||||
private val context: Context,
|
||||
val listener: PermissionListener,
|
||||
private val requestCode: Int,
|
||||
vararg permissions: String
|
||||
) {
|
||||
|
||||
private val permissionsArray = permissions
|
||||
|
||||
interface PermissionListener {
|
||||
fun onPermissionGranted()
|
||||
fun onPermissionDenied()
|
||||
}
|
||||
|
||||
fun arePermissionsGranted(): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
permissionsArray.all {
|
||||
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun requestPermissions(activity: Activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
ActivityCompat.requestPermissions(activity, permissionsArray, requestCode)
|
||||
}
|
||||
}
|
||||
|
||||
fun handlePermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
if (this.requestCode == requestCode) {
|
||||
val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
|
||||
if (allGranted) {
|
||||
listener.onPermissionGranted()
|
||||
} else {
|
||||
listener.onPermissionDenied()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.cloud.hmg_patient_app.PermissionManager
|
||||
|
||||
// PermissionResultReceiver.kt
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
class PermissionResultReceiver(
|
||||
private val callback: (Boolean) -> Unit
|
||||
) : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
val granted = intent?.getBooleanExtra("PERMISSION_GRANTED", false) ?: false
|
||||
callback(granted)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* ---------------
|
||||
* Note: Todo
|
||||
* ---------------
|
||||
* Need to be place in huawei_push (package com.huawei.hms.flutter.push.hms) and define in huawei_push manifest.xml
|
||||
* */
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import com.huawei.hms.flutter.push.hms.FlutterHmsMessageService;
|
||||
import com.huawei.hms.flutter.push.utils.ApplicationUtils;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
//package com.huawei.hms.flutter.push.hms
|
||||
//
|
||||
//
|
||||
//import android.content.Context;
|
||||
//import android.content.Intent;
|
||||
//import android.content.SharedPreferences;
|
||||
//
|
||||
//import com.huawei.hms.flutter.push.hms.FlutterHmsMessageService;
|
||||
//import com.huawei.hms.flutter.push.utils.ApplicationUtils;
|
||||
//import com.huawei.hms.push.RemoteMessage;
|
||||
//
|
||||
//import org.json.JSONObject;
|
||||
//
|
||||
//public class CustomFlutterHmsMessageService extends FlutterHmsMessageService {
|
||||
// @Override
|
||||
// public void onMessageReceived(RemoteMessage remoteMessage) {
|
||||
// super.onMessageReceived(remoteMessage);
|
||||
// try {
|
||||
// String jsonStr = remoteMessage.getData();
|
||||
// JSONObject json_data = new JSONObject(jsonStr);
|
||||
// JSONObject json_data_data = new JSONObject(json_data.getString("data"));
|
||||
// if(json_data_data.getString("is_call").equalsIgnoreCase("true")){
|
||||
// boolean isApplicationInForeground = ApplicationUtils.isApplicationInForeground(this);
|
||||
// if(!isApplicationInForeground){
|
||||
// SharedPreferences preferences = getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
|
||||
// preferences.edit().putString("flutter.call_data", json_data.getString("data")).apply();
|
||||
//
|
||||
// Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
|
||||
// intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
// startActivity(intent);
|
||||
// Log.v("onMessageReceived", "startActivity(intent) called");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.ejada.hmg.geofence
|
||||
|
||||
import com.google.android.gms.location.Geofence
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
|
||||
class GeoZoneModel {
|
||||
var GEOF_ID:Int = 0
|
||||
var Radius:Int = 0
|
||||
var Type:Int = 0
|
||||
var ProjectID:Int = 0
|
||||
|
||||
var Description:String? = null
|
||||
var DescriptionN:String? = null
|
||||
var Latitude:String? = null
|
||||
var Longitude:String? = null
|
||||
var ImageURL:String? = null
|
||||
var IsCity:String? = null
|
||||
|
||||
fun identifier():String{
|
||||
return "$GEOF_ID" + "_hmg"
|
||||
}
|
||||
|
||||
fun message():String{
|
||||
return Description ?: "nil"
|
||||
}
|
||||
|
||||
fun listFrom(jsonString: String) : List<GeoZoneModel>{
|
||||
val type = object : TypeToken<List<GeoZoneModel?>?>() {}.getType()
|
||||
return Gson().fromJson(jsonString, type)
|
||||
}
|
||||
|
||||
fun toGeofence() : Geofence?{
|
||||
if (!Latitude.isNullOrEmpty() && !Longitude.isNullOrEmpty() && Radius > 50) {
|
||||
val lat = Latitude!!.trim().toDoubleOrNull()
|
||||
val long = Longitude!!.trim().toDoubleOrNull()
|
||||
val rad = Radius.toFloat()
|
||||
if(lat != null && long != null){
|
||||
|
||||
val loiteringDelayMinutes:Int = 2 // in Minutes
|
||||
return Geofence.Builder()
|
||||
.setRequestId(identifier())
|
||||
.setCircularRegion(
|
||||
lat,
|
||||
long,
|
||||
rad
|
||||
)
|
||||
.setTransitionTypes(GeofenceTransition.ENTER_EXIT.value)
|
||||
.setNotificationResponsiveness(0)
|
||||
.setLoiteringDelay(loiteringDelayMinutes * 60 * 1000)
|
||||
.setExpirationDuration(Geofence.NEVER_EXPIRE)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,291 @@
|
||||
package com.ejada.hmg.geofence
|
||||
|
||||
import android.Manifest
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.PackageManager
|
||||
import android.location.Location
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.ejada.hmg.geofence.intent_receivers.GeofenceBroadcastReceiver
|
||||
import com.ejada.hmg.geofence.intent_receivers.ReregisterGeofenceJobService
|
||||
import com.ejada.hmg.utils.*
|
||||
import com.google.android.gms.location.Geofence
|
||||
import com.google.android.gms.location.GeofencingClient
|
||||
import com.google.android.gms.location.GeofencingRequest
|
||||
import com.google.android.gms.location.LocationServices
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
|
||||
enum class GeofenceTransition(val value: Int) {
|
||||
ENTER(1),
|
||||
EXIT(2),
|
||||
DWELL(4),
|
||||
|
||||
ENTER_EXIT((ENTER.value or EXIT.value)),
|
||||
DWELL_EXIT((DWELL.value or EXIT.value));
|
||||
|
||||
companion object {
|
||||
fun fromInt(value: Int) = GeofenceTransition.values().first { it.value == value }
|
||||
}
|
||||
|
||||
fun named(): String {
|
||||
if (value == 1) return "Enter"
|
||||
if (value == 2) return "Exit"
|
||||
if (value == 4) return "dWell"
|
||||
if (value == (ENTER.value or EXIT.value)) return "Enter or Exit"
|
||||
if (value == (DWELL.value or EXIT.value)) return "DWell or Exit"
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
class HMG_Geofence {
|
||||
// https://developer.android.com/training/location/geofencing#java
|
||||
|
||||
private lateinit var context: Context
|
||||
private lateinit var preferences: SharedPreferences
|
||||
private val gson = Gson()
|
||||
|
||||
private lateinit var geofencingClient: GeofencingClient
|
||||
private val geofencePendingIntent: PendingIntent by lazy {
|
||||
val intent = Intent(context, GeofenceBroadcastReceiver::class.java)
|
||||
PendingIntent.getBroadcast(
|
||||
context,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
var instance: HMG_Geofence? = null
|
||||
fun shared(context: Context): HMG_Geofence {
|
||||
if (instance == null) {
|
||||
instance = HMG_Geofence()
|
||||
instance?.context = context
|
||||
instance?.geofencingClient = LocationServices.getGeofencingClient(context)
|
||||
instance?.preferences =
|
||||
context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||
}
|
||||
return instance!!
|
||||
}
|
||||
}
|
||||
|
||||
private fun limitize(zones: List<GeoZoneModel>): List<GeoZoneModel> {
|
||||
var geoZones_ = zones
|
||||
if (zones.size > 100)
|
||||
geoZones_ = zones.subList(0, 99)
|
||||
return geoZones_
|
||||
}
|
||||
|
||||
|
||||
fun register(completion: ((Boolean, java.lang.Exception?) -> Unit)) {
|
||||
unRegisterAll { status, exception ->
|
||||
val geoZones = getGeoZonesFromPreference(context)
|
||||
doRegister(geoZones) { status_, error ->
|
||||
completion.let { it(status_, error) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun unRegisterAll(completion: (status: Boolean, exception: Exception?) -> Unit) {
|
||||
getActiveGeofences({ success ->
|
||||
removeActiveGeofences()
|
||||
if (success.isNotEmpty())
|
||||
geofencingClient
|
||||
.removeGeofences(success)
|
||||
.addOnSuccessListener {
|
||||
completion(true, null)
|
||||
}
|
||||
.addOnFailureListener {
|
||||
completion(false, it)
|
||||
saveLog(context, "error:REMOVE_GEOFENCES", it.localizedMessage)
|
||||
}
|
||||
else
|
||||
completion(true, null)
|
||||
|
||||
}, { failed ->
|
||||
// Nothing to do with failed geofences.
|
||||
})
|
||||
}
|
||||
|
||||
private fun doRegister(
|
||||
geoZones: List<GeoZoneModel>,
|
||||
completion: ((Boolean, java.lang.Exception?) -> Unit)? = null
|
||||
) {
|
||||
if (geoZones.isEmpty())
|
||||
return
|
||||
|
||||
val geoZones_ = limitize(geoZones)
|
||||
|
||||
fun buildGeofencingRequest(geofences: List<Geofence>): GeofencingRequest {
|
||||
return GeofencingRequest.Builder()
|
||||
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL)
|
||||
.addGeofences(geofences)
|
||||
.build()
|
||||
}
|
||||
|
||||
getActiveGeofences({ active ->
|
||||
|
||||
val geofences = mutableListOf<Geofence>()
|
||||
geoZones_.forEach {
|
||||
it.toGeofence()?.let { geof ->
|
||||
if (!active.contains(geof.requestId)) { // if not already registered then register
|
||||
geofences.add(geof)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkPermission() && geofences.isNotEmpty()) {
|
||||
geofencingClient
|
||||
.addGeofences(buildGeofencingRequest(geofences), geofencePendingIntent)
|
||||
.addOnSuccessListener {
|
||||
Logs.RegisterGeofence.save(
|
||||
context,
|
||||
"SUCCESS",
|
||||
"Successfuly registered the geofences",
|
||||
Logs.STATUS.SUCCESS
|
||||
)
|
||||
saveActiveGeofence(geofences.map { it.requestId }, listOf())
|
||||
completion?.let { it(true, null) }
|
||||
}
|
||||
.addOnFailureListener { exc ->
|
||||
Logs.RegisterGeofence.save(
|
||||
context,
|
||||
"FAILED_TO_REGISTER",
|
||||
"Failed to register geofence",
|
||||
Logs.STATUS.ERROR
|
||||
)
|
||||
completion?.let { it(false, exc) }
|
||||
}
|
||||
|
||||
// Schedule the job to register after specified duration (due to: events not calling after long period.. days or days [Needs to register fences again])
|
||||
HMGUtils.scheduleJob(
|
||||
context,
|
||||
ReregisterGeofenceJobService::class.java,
|
||||
ReregisterGeofenceJobService.JobID,
|
||||
ReregisterGeofenceJobService.TriggerIntervalDuration
|
||||
)
|
||||
}
|
||||
|
||||
}, null)
|
||||
|
||||
}
|
||||
|
||||
fun getGeoZonesFromPreference(context: Context): List<GeoZoneModel> {
|
||||
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||
val json = pref.getString(PREF_KEY_HMG_ZONES, "[]")
|
||||
|
||||
val geoZones = GeoZoneModel().listFrom(json!!)
|
||||
return geoZones
|
||||
}
|
||||
|
||||
fun saveActiveGeofence(success: List<String>, failed: List<String>) {
|
||||
val jsonSuccess = gson.toJson(success)
|
||||
val jsonFailure = gson.toJson(failed)
|
||||
preferences.edit().putString(PREF_KEY_SUCCESS, jsonSuccess).apply()
|
||||
preferences.edit().putString(PREF_KEY_FAILED, jsonFailure).apply()
|
||||
}
|
||||
|
||||
fun removeActiveGeofences() {
|
||||
preferences.edit().putString(PREF_KEY_SUCCESS, "[]").apply()
|
||||
preferences.edit().putString(PREF_KEY_FAILED, "[]").apply()
|
||||
}
|
||||
|
||||
fun getActiveGeofences(
|
||||
success: (success: List<String>) -> Unit,
|
||||
failure: ((failed: List<String>) -> Unit)?
|
||||
) {
|
||||
val type = object : TypeToken<List<String?>?>() {}.type
|
||||
|
||||
val jsonSuccess = preferences.getString(PREF_KEY_SUCCESS, "[]")
|
||||
val success = gson.fromJson<List<String>>(jsonSuccess, type)
|
||||
success(success)
|
||||
|
||||
if (failure != null) {
|
||||
val jsonFailure = preferences.getString(PREF_KEY_FAILED, "[]")
|
||||
val failed = gson.fromJson<List<String>>(jsonFailure, type)
|
||||
failure(failed)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun checkPermission(): Boolean {
|
||||
return ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
fun getPatientID(): Int? {
|
||||
var profileJson = preferences.getString("flutter.imei-user-data", null)
|
||||
if (profileJson == null)
|
||||
profileJson = preferences.getString("flutter.user-profile", null)
|
||||
|
||||
val type = object : TypeToken<Map<String?, Any?>?>() {}.type
|
||||
return gson.fromJson<Map<String?, Any?>?>(profileJson, type)
|
||||
?.get("PatientID")
|
||||
.toString()
|
||||
.toDoubleOrNull()
|
||||
?.toInt()
|
||||
}
|
||||
|
||||
|
||||
fun handleEvent(
|
||||
triggerGeofences: List<Geofence>,
|
||||
location: Location,
|
||||
transition: GeofenceTransition
|
||||
) {
|
||||
getPatientID()?.let { patientId ->
|
||||
getActiveGeofences({ activeGeofences ->
|
||||
|
||||
triggerGeofences.forEach { geofence ->
|
||||
// Extract PointID from 'geofence.requestId' and find from active geofences
|
||||
val pointID =
|
||||
activeGeofences.firstOrNull { it == geofence.requestId }?.split('_')
|
||||
?.first()
|
||||
if (!pointID.isNullOrEmpty() && pointID.toIntOrNull() != null) {
|
||||
|
||||
val body = mutableMapOf<String, Any?>(
|
||||
"PointsID" to pointID.toIntOrNull(),
|
||||
"GeoType" to transition.value,
|
||||
"PatientID" to patientId
|
||||
)
|
||||
body.putAll(HMGUtils.defaultHTTPParams(context))
|
||||
|
||||
httpPost<Map<String, Any>>(API.LOG_GEOFENCE, body, { response ->
|
||||
saveLog(
|
||||
context,
|
||||
"HMG_GEOFENCE_NOTIFY",
|
||||
"Success: Notified to server\uD83D\uDE0E."
|
||||
)
|
||||
sendNotification(
|
||||
context,
|
||||
transition.named(),
|
||||
geofence.requestId,
|
||||
"Notified to server.😎"
|
||||
)
|
||||
}, { exception ->
|
||||
val errorMessage = "${transition.named()}, ${geofence.requestId}"
|
||||
saveLog(
|
||||
context,
|
||||
"HMG_GEOFENCE_NOTIFY",
|
||||
"failed: $errorMessage | error: ${exception.localizedMessage}"
|
||||
)
|
||||
sendNotification(
|
||||
context,
|
||||
transition.named(),
|
||||
geofence.requestId,
|
||||
"Failed to notify server😔 -> ${exception.localizedMessage}"
|
||||
)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package com.ejada.hmg.geofence.intent_receivers
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.ejada.hmg.geofence.GeofenceTransition
|
||||
import com.ejada.hmg.geofence.HMG_Geofence
|
||||
import com.ejada.hmg.utils.Logs
|
||||
import com.google.android.gms.location.GeofenceStatusCodes
|
||||
import com.google.android.gms.location.GeofencingEvent
|
||||
|
||||
class GeofenceBroadcastReceiver : BroadcastReceiver() {
|
||||
private val LOG_TAG = "GeofenceBroadcastReceiver"
|
||||
|
||||
@SuppressLint("LongLogTag")
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
|
||||
val geofencingEvent = GeofencingEvent.fromIntent(intent)
|
||||
if (geofencingEvent != null) {
|
||||
if (geofencingEvent.hasError()) {
|
||||
val errorMessage =
|
||||
GeofenceErrorMessages.getErrorString(context, geofencingEvent.errorCode)
|
||||
Log.e(LOG_TAG, errorMessage)
|
||||
|
||||
Logs.GeofenceEvent.save(
|
||||
context,
|
||||
LOG_TAG,
|
||||
"Error while triggering geofence event",
|
||||
Logs.STATUS.ERROR
|
||||
)
|
||||
doReRegisterIfRequired(context, geofencingEvent.errorCode)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
if (geofencingEvent != null) {
|
||||
Logs.GeofenceEvent.save(
|
||||
context,
|
||||
LOG_TAG,
|
||||
"Geofence event triggered: ${GeofenceTransition.fromInt(geofencingEvent.geofenceTransition).value} for ${geofencingEvent.triggeringGeofences?.map { it.requestId }}",
|
||||
Logs.STATUS.SUCCESS
|
||||
)
|
||||
geofencingEvent.triggeringLocation?.let {
|
||||
geofencingEvent.triggeringGeofences?.let { it1 ->
|
||||
HMG_Geofence.shared(context).handleEvent(
|
||||
it1,
|
||||
it, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition)
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
fun doReRegisterIfRequired(context: Context, errorCode: Int) {
|
||||
val errorRequiredReregister = listOf(
|
||||
GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE,
|
||||
GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES,
|
||||
GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS,
|
||||
GeofenceStatusCodes.GEOFENCE_REQUEST_TOO_FREQUENT
|
||||
)
|
||||
|
||||
if (errorRequiredReregister.contains(errorCode))
|
||||
HMG_Geofence.shared(context).register() { status, error ->
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
package com.ejada.hmg.geofence.intent_receivers
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.ejada.hmg.geofence.HMG_Geofence
|
||||
import com.google.android.gms.location.GeofenceStatusCodes
|
||||
|
||||
class GeofenceBroadcastReceiverWithJobService : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
GeofenceTransitionsJobIntentService.enqueueWork(context, intent)
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
package com.ejada.hmg.geofence.intent_receivers
|
||||
|
||||
import android.content.Context
|
||||
import com.ejada.hmg.R
|
||||
import com.ejada.hmg.geofence.HMG_Geofence
|
||||
import com.google.android.gms.common.api.ApiException
|
||||
import com.google.android.gms.location.GeofenceStatusCodes
|
||||
|
||||
object GeofenceErrorMessages {
|
||||
fun getErrorString(context: Context, e: Exception): String {
|
||||
return if (e is ApiException) {
|
||||
getErrorString(context, e.statusCode)
|
||||
} else {
|
||||
context.resources.getString(R.string.geofence_unknown_error)
|
||||
}
|
||||
}
|
||||
|
||||
fun getErrorString(context: Context, errorCode: Int): String {
|
||||
val resources = context.resources
|
||||
val errorMessage = when (errorCode) {
|
||||
GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE ->
|
||||
resources.getString(R.string.geofence_not_available)
|
||||
|
||||
GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES ->
|
||||
resources.getString(R.string.geofence_too_many_geofences)
|
||||
|
||||
GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS ->
|
||||
resources.getString(R.string.geofence_too_many_pending_intents)
|
||||
|
||||
GeofenceStatusCodes.GEOFENCE_INSUFFICIENT_LOCATION_PERMISSION ->
|
||||
resources.getString(R.string.GEOFENCE_INSUFFICIENT_LOCATION_PERMISSION)
|
||||
|
||||
GeofenceStatusCodes.GEOFENCE_REQUEST_TOO_FREQUENT ->
|
||||
resources.getString(R.string.GEOFENCE_REQUEST_TOO_FREQUENT)
|
||||
|
||||
else -> resources.getString(R.string.geofence_unknown_error)
|
||||
}
|
||||
|
||||
return errorMessage
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Razeware LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* Notwithstanding the foregoing, you may not use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, create a derivative work, and/or sell copies of the
|
||||
* Software in any work that is designed, intended, or marketed for pedagogical or
|
||||
* instructional purposes related to programming, coding, application development,
|
||||
* or information technology. Permission for such use, copying, modification,
|
||||
* merger, publication, distribution, sublicensing, creation of derivative works,
|
||||
* or sale is expressly withheld.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package com.ejada.hmg.geofence.intent_receivers
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.core.app.JobIntentService
|
||||
import com.ejada.hmg.geofence.GeofenceTransition
|
||||
import com.ejada.hmg.geofence.HMG_Geofence
|
||||
import com.ejada.hmg.utils.saveLog
|
||||
import com.google.android.gms.location.GeofenceStatusCodes
|
||||
import com.google.android.gms.location.GeofencingEvent
|
||||
|
||||
class GeofenceTransitionsJobIntentService : JobIntentService() {
|
||||
|
||||
companion object {
|
||||
private const val LOG_TAG = "GeoTrIntentService"
|
||||
|
||||
private const val JOB_ID = 95902
|
||||
var context_: Context? = null
|
||||
fun enqueueWork(context: Context, intent: Intent) {
|
||||
context_ = context
|
||||
enqueueWork(
|
||||
context,
|
||||
GeofenceTransitionsJobIntentService::class.java, JOB_ID,
|
||||
intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHandleWork(intent: Intent) {
|
||||
val geofencingEvent = GeofencingEvent.fromIntent(intent)
|
||||
if (geofencingEvent != null) {
|
||||
if (geofencingEvent.hasError()) {
|
||||
val errorMessage = GeofenceErrorMessages.getErrorString(context_!!, geofencingEvent.errorCode)
|
||||
Log.e(LOG_TAG, errorMessage)
|
||||
|
||||
|
||||
saveLog(context_!!,LOG_TAG,errorMessage)
|
||||
doReRegisterIfRequired(context_!!, geofencingEvent.errorCode)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (geofencingEvent != null) {
|
||||
geofencingEvent.triggeringGeofences?.let { geofencingEvent.triggeringLocation?.let { it1 ->
|
||||
HMG_Geofence.shared(context_!!).handleEvent(it,
|
||||
it1, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition))
|
||||
} }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun doReRegisterIfRequired(context: Context, errorCode: Int){
|
||||
val errorRequiredReregister = listOf(
|
||||
GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE,
|
||||
GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES,
|
||||
GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS,
|
||||
GeofenceStatusCodes.GEOFENCE_REQUEST_TOO_FREQUENT
|
||||
)
|
||||
|
||||
if(errorRequiredReregister.contains(errorCode))
|
||||
HMG_Geofence.shared(context).register(){ status, exc -> }
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
package com.ejada.hmg.geofence.intent_receivers
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.ejada.hmg.geofence.HMG_Geofence
|
||||
import com.ejada.hmg.utils.PREFS_STORAGE
|
||||
|
||||
class GeofencingRebootBroadcastReceiver : BroadcastReceiver(){
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.action)) {
|
||||
// if (intent.action.equals("android.intent.action.BOOT_COMPLETE")) {
|
||||
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||
pref.edit().putString("REBOOT_DETECTED","YES").apply()
|
||||
|
||||
HMG_Geofence.shared(context).register(){ status, error -> }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
|
||||
|
||||
package com.ejada.hmg.geofence.intent_receivers
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.location.LocationManager
|
||||
import com.ejada.hmg.geofence.HMG_Geofence
|
||||
import com.ejada.hmg.utils.HMGUtils
|
||||
import com.ejada.hmg.utils.PREFS_STORAGE
|
||||
|
||||
class LocationProviderChangeReceiver : BroadcastReceiver() {
|
||||
private val LOG_TAG = "LocationProviderChangeReceiver"
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
|
||||
if (LocationManager.PROVIDERS_CHANGED_ACTION.equals(intent.action)) {
|
||||
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||
pref.edit().putString("LOCATION_PROVIDER_CHANGE","YES").apply()
|
||||
|
||||
HMG_Geofence.shared(context).register(){ s, e -> }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.ejada.hmg.geofence.intent_receivers
|
||||
|
||||
import android.app.job.JobParameters
|
||||
import android.app.job.JobService
|
||||
import com.ejada.hmg.geofence.HMG_Geofence
|
||||
import com.ejada.hmg.utils.Logs
|
||||
|
||||
class ReregisterGeofenceJobService : JobService(){
|
||||
companion object{
|
||||
val TriggerIntervalDuration:String = "06:00:00"
|
||||
val JobID = 918273
|
||||
}
|
||||
override fun onStartJob(params: JobParameters?): Boolean {
|
||||
Logs.save(applicationContext,"ReregisterGeofenceJobService.onStartJob", "triggered to re-register the geofences after $TriggerIntervalDuration >> [HH:mm:ss]")
|
||||
HMG_Geofence.shared(applicationContext).register(){ status, error ->
|
||||
jobFinished(params, true)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onStopJob(params: JobParameters?): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,257 @@
|
||||
package com.ejada.hmg.hmgwifi
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.*
|
||||
import android.net.wifi.*
|
||||
import android.os.Build
|
||||
import android.os.PatternMatcher
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.ejada.hmg.MainActivity
|
||||
import com.ejada.hmg.utils.HMGUtils
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class HMG_Guest(private var context: MainActivity, ssid: String) {
|
||||
private val TAG = "HMG_Guest"
|
||||
private val TEST = false
|
||||
private var SSID = ssid
|
||||
// private var SSID = "HMG-MOHEMM"
|
||||
|
||||
val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager?
|
||||
|
||||
private lateinit var completionListener: ((status: Boolean, message: String) -> Unit)
|
||||
|
||||
fun completionOnUiThread(status: Boolean, message: String){
|
||||
completionListener(status, message)
|
||||
}
|
||||
|
||||
fun enableWifi(){
|
||||
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
|
||||
wifiManager?.setWifiEnabled(true)
|
||||
HMGUtils.popFlutterText(context,"enablingWifi");
|
||||
HMGUtils.timer(2000,false){
|
||||
connectApiLessThen29()
|
||||
}
|
||||
}else {
|
||||
val panelIntent = Intent(Settings.Panel.ACTION_WIFI)
|
||||
context.startActivityForResult(panelIntent, 1)
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Helpful:
|
||||
* http://stackoverflow.com/questions/8818290/how-to-connect-to-a-specific-wifi-network-in-android-programmatically
|
||||
*/
|
||||
fun connectToHMGGuestNetwork(completion: (status: Boolean, message: String) -> Unit) {
|
||||
completionListener = completion
|
||||
wifiManager?.let { wm ->
|
||||
if (!wm.isWifiEnabled){
|
||||
enableWifi()
|
||||
}else{
|
||||
connectWifi()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun errorConnecting(){
|
||||
completionOnUiThread(false, "errorConnectingHmgNetwork")
|
||||
}
|
||||
|
||||
fun connectWifi(){
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
|
||||
connectApiGreaterThen28()
|
||||
}else {
|
||||
connectApiLessThen29()
|
||||
}
|
||||
}
|
||||
|
||||
// I }else{f CompileSDK is greater and equals to APILevel 29
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
private fun connectApiGreaterThen28(){
|
||||
Log.e(TAG, "connection wifi with Android Q+")
|
||||
|
||||
val networkRequest: NetworkRequest = NetworkRequest.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) //removeCapability added for hotspots without internet
|
||||
.setNetworkSpecifier(
|
||||
WifiNetworkSpecifier.Builder()
|
||||
.setSsid(SSID)
|
||||
.build()
|
||||
|
||||
).build()
|
||||
|
||||
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
super.onAvailable(network)
|
||||
connectivityManager.bindProcessToNetwork(network)
|
||||
HMGUtils.timer(2000,false){
|
||||
completionListener(true, "Success")
|
||||
}
|
||||
Log.e(TAG, "onAvailable")
|
||||
}
|
||||
|
||||
override fun onLosing(network: Network, maxMsToLive: Int) {
|
||||
super.onLosing(network, maxMsToLive)
|
||||
Log.e(TAG, "onLosing")
|
||||
completionListener(false, "fail")
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
super.onLost(network)
|
||||
Log.e(TAG, "onLosing")
|
||||
Log.e(TAG, "losing active connection")
|
||||
completionListener(false, "fail")
|
||||
}
|
||||
|
||||
override fun onUnavailable() {
|
||||
super.onUnavailable()
|
||||
Log.e(TAG, "onUnavailable")
|
||||
completionListener(false, "fail")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//timeout add because "No devices found" wasn't handled correct and doesn't throw Unavailable
|
||||
connectivityManager.requestNetwork(networkRequest, networkCallback, 30000)
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun connectApiLessThen29(){
|
||||
val wifi = WifiConfiguration()
|
||||
wifi.SSID = """"$SSID""""
|
||||
wifi.status = WifiConfiguration.Status.ENABLED
|
||||
wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
|
||||
|
||||
wifi.networkId = ssidToNetworkId(wifi.SSID)
|
||||
if (wifi.networkId == -1) {
|
||||
wifiManager?.addNetwork(wifi)
|
||||
} else {
|
||||
Log.v(TAG, "WiFi found - updating it.\n")
|
||||
wifiManager?.updateNetwork(wifi)
|
||||
}
|
||||
|
||||
Log.v(TAG, "saving config.\n")
|
||||
wifiManager?.saveConfiguration()
|
||||
|
||||
wifi.networkId = ssidToNetworkId(wifi.SSID)
|
||||
|
||||
Log.v(TAG, "wifi ID in device = " + wifi.networkId)
|
||||
|
||||
var supState: SupplicantState
|
||||
val networkIdToConnect = wifi.networkId
|
||||
if (networkIdToConnect >= 0) {
|
||||
Log.v(TAG, "Start connecting...\n")
|
||||
|
||||
// We disable the network before connecting, because if this was the last connection before
|
||||
// a disconnect(), this will not reconnect.
|
||||
wifiManager?.disableNetwork(networkIdToConnect)
|
||||
wifiManager?.enableNetwork(networkIdToConnect, true)
|
||||
|
||||
val wifiInfo: WifiInfo = wifiManager!!.connectionInfo
|
||||
|
||||
HMGUtils.timer(5000,false){
|
||||
supState = wifiInfo.supplicantState
|
||||
Log.i(TAG, "Done connect to network : status = $supState")
|
||||
val successStates = listOf(SupplicantState.COMPLETED, SupplicantState.ASSOCIATED)
|
||||
if (successStates.contains(supState))
|
||||
completionListener(true,"Connected to internet Wifi")
|
||||
else
|
||||
completionListener(false,"errorConnectingHmgNetwork")
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.v(TAG, "WifiWizard: cannot connect to network")
|
||||
completionListener(false,"errorConnectingHmgNetwork")
|
||||
}
|
||||
|
||||
// val wifi = WifiConfiguration()
|
||||
// wifi.SSID = SSID
|
||||
// wifi.status = WifiConfiguration.Status.ENABLED
|
||||
// wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
|
||||
//
|
||||
// wifi.networkId = ssidToNetworkId(SSID)
|
||||
//
|
||||
// // Set network to highest priority (deprecated in API >= 26)
|
||||
// if(Build.VERSION.SDK_INT < 26) {
|
||||
// wifi.priority = getMaxWifiPriority(wifiManager!!) + 1;
|
||||
// }
|
||||
//
|
||||
// // After processing authentication types, add or update network
|
||||
// if(wifi.networkId == -1) { // -1 means SSID configuration does not exist yet
|
||||
//
|
||||
// val newNetId = wifiManager?.addNetwork(wifi)!!
|
||||
// if( newNetId > -1 ){
|
||||
// completionListener(true,"Success")
|
||||
// } else {
|
||||
// completionListener(false, "ERROR_ADDING_NETWORK" )
|
||||
// }
|
||||
//
|
||||
// } else {
|
||||
//
|
||||
// var updatedNetID = wifiManager?.updateNetwork(wifi)
|
||||
//
|
||||
// if(updatedNetID == -1)
|
||||
// updatedNetID = wifiManager?.addNetwork(wifi)
|
||||
//
|
||||
// if(updatedNetID > -1) {
|
||||
// callbackContext.success( updatedNetID )
|
||||
// } else {
|
||||
// callbackContext.error("ERROR_UPDATING_NETWORK")
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// // WifiManager configurations are presistent for API 26+
|
||||
// if(Build.VERSION.SDK_INT < 26) {
|
||||
// wifiManager?.saveConfiguration(); // Call saveConfiguration for older < 26 API
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method takes a given String, searches the current list of configured WiFi
|
||||
* networks, and returns the networkId for the network if the SSID matches. If not,
|
||||
* it returns -1.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun ssidToNetworkId(ssid: String): Int {
|
||||
val currentNetworks = wifiManager!!.configuredNetworks
|
||||
var networkId = -1
|
||||
|
||||
// For each network in the list, compare the SSID with the given one
|
||||
for (test in currentNetworks) {
|
||||
if (test.SSID == ssid) {
|
||||
networkId = test.networkId
|
||||
break
|
||||
}
|
||||
}
|
||||
return networkId
|
||||
}
|
||||
|
||||
companion object{
|
||||
|
||||
/**
|
||||
* Figure out what the highest priority network in the network list is and return that priority
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.S)
|
||||
fun getMaxWifiPriority(wifiManager:WifiManager) : Int {
|
||||
val configurations = wifiManager.callerConfiguredNetworks
|
||||
var maxPriority = 0
|
||||
configurations.forEach {
|
||||
if (it.priority > maxPriority) {
|
||||
maxPriority = it.priority;
|
||||
}
|
||||
}
|
||||
return maxPriority;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
package com.ejada.hmg.hmgwifi
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import com.ejada.hmg.utils.API
|
||||
import com.ejada.hmg.MainActivity
|
||||
import com.github.kittinunf.fuel.core.extensions.jsonBody
|
||||
import com.github.kittinunf.fuel.httpGet
|
||||
import com.github.kittinunf.fuel.httpPost
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
class HMG_Internet(flutterMainActivity: MainActivity) {
|
||||
private val TAG = "HMG_Wifi"
|
||||
private val TEST = true
|
||||
|
||||
private var context = flutterMainActivity;
|
||||
|
||||
private lateinit var completionListener: ((status: Boolean, message: String) -> Unit)
|
||||
|
||||
private var SSID = "GUEST-POC"
|
||||
|
||||
fun completionOnUiThread(status: Boolean, message: String){
|
||||
completionListener(status, message)
|
||||
// context.runOnUiThread {
|
||||
// .with(message){localized ->
|
||||
// completionListener(status, localized)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpful:
|
||||
* http://stackoverflow.com/questions/8818290/how-to-connect-to-a-specific-wifi-network-in-android-programmatically
|
||||
*/
|
||||
fun connectToHMGGuestNetwork(username: String, password: String, completion: (status: Boolean, message: String) -> Unit): HMG_Internet {
|
||||
completionListener = completion
|
||||
WpaEnterprise(context,SSID).connect(username,username) { status, message ->
|
||||
completionOnUiThread(status,message)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun haveInternet(completion: ((status: Boolean) -> Unit)){
|
||||
if (TEST)
|
||||
completion(true)
|
||||
|
||||
"https://captive.apple.com".httpGet().response { request, response, result ->
|
||||
result.fold(success = {
|
||||
val html = String(it).lowercase(Locale.ENGLISH)
|
||||
.replace(" ", "", ignoreCase = true)
|
||||
.replace("\n","",ignoreCase = true)
|
||||
val have = html.contains("<title>success</title>", ignoreCase = true)
|
||||
completion(have)
|
||||
|
||||
},failure = {
|
||||
completion(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun getWifiCredentials(patientId:String, success: ((String?,String?) -> Unit)){
|
||||
if (TEST){
|
||||
SSID = "GUEST-POC"
|
||||
success("2300", "0000")
|
||||
return
|
||||
}
|
||||
|
||||
val jsonBody = """{
|
||||
"PatientID":$patientId
|
||||
"VersionID": 8.8,
|
||||
"Channel": 3,
|
||||
"LanguageID": 2,
|
||||
"IPAdress": "10.20.10.20",
|
||||
"generalid": "Cs2020@2016$2958",
|
||||
"PatientOutSA": 0,
|
||||
"SessionID": "@admin",
|
||||
"isDentalAllowedBackend": false,
|
||||
"DeviceTypeID": 2,
|
||||
"TokenID": "@admin",
|
||||
"PatientTypeID": 1,
|
||||
"PatientType": 1
|
||||
}""".trimMargin()
|
||||
API.WIFI_CREDENTIALS.
|
||||
httpPost()
|
||||
.jsonBody(jsonBody, Charsets.UTF_8)
|
||||
.response { request, response, result ->
|
||||
|
||||
result.fold(success = { data ->
|
||||
val jsonString = String(data)
|
||||
val jsonObject = JSONObject(jsonString)
|
||||
if(!jsonObject.getString("ErrorMessage").equals("null")){
|
||||
val errorMsg = jsonObject.getString("ErrorMessage")
|
||||
completionOnUiThread(false, errorMsg)
|
||||
|
||||
}else{
|
||||
jsonObject.getJSONArray("Hmg_SMS_Get_By_ProjectID_And_PatientIDList").let { array ->
|
||||
array.getJSONObject(0).let { object_ ->
|
||||
if (object_.has("UserName") && object_.has("UserName")){
|
||||
try {
|
||||
val userName = object_.getString("UserName")
|
||||
val password = object_.getString("Password")
|
||||
success(userName, password)
|
||||
}catch (e:Exception){
|
||||
success(null, null)
|
||||
}
|
||||
}else{
|
||||
completionOnUiThread(false, "somethingWentWrong")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},failure = { error ->
|
||||
completionOnUiThread(false, "somethingWentWrong" )
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
package com.ejada.hmg.hmgwifi
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.wifi.*
|
||||
import android.net.wifi.SupplicantState.ASSOCIATED
|
||||
import android.net.wifi.SupplicantState.COMPLETED
|
||||
import android.util.Log
|
||||
import com.ejada.hmg.MainActivity
|
||||
import com.ejada.hmg.utils.HMGUtils
|
||||
|
||||
class WPA(mainActivity: MainActivity, SSID:String) {
|
||||
private var TAG = "WPA"
|
||||
private var SSID = "GUEST-POC"
|
||||
private var wifiManager_: WifiManager? = null
|
||||
private var connectivityManager_: ConnectivityManager? = null
|
||||
|
||||
init {
|
||||
wifiManager_ = mainActivity.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager?
|
||||
connectivityManager_ = mainActivity.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
|
||||
}
|
||||
|
||||
fun connect(identity:String, password:String, completion: (status: Boolean, message: String) -> Unit) {
|
||||
if(wifiManager_ == null || connectivityManager_ == null){
|
||||
completion(false,"errorConnectingHmgNetwork")
|
||||
return
|
||||
}
|
||||
|
||||
val wifiManager = wifiManager_!!
|
||||
val connectivityManager = connectivityManager_!!
|
||||
|
||||
// Initialize the WifiConfiguration object
|
||||
val enterpriseConfig = WifiEnterpriseConfig()
|
||||
val wifi = WifiConfiguration()
|
||||
wifi.SSID = """"$SSID""""
|
||||
wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP)
|
||||
wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X)
|
||||
enterpriseConfig.eapMethod = WifiEnterpriseConfig.Eap.PEAP
|
||||
enterpriseConfig.identity = identity
|
||||
enterpriseConfig.password = password
|
||||
wifi.enterpriseConfig = enterpriseConfig
|
||||
wifi.networkId = ssidToNetworkId(wifi.SSID)
|
||||
if (wifi.networkId == -1) {
|
||||
wifiManager.addNetwork(wifi)
|
||||
} else {
|
||||
Log.v(TAG, "WiFi found - updating it.\n")
|
||||
wifiManager.updateNetwork(wifi)
|
||||
}
|
||||
Log.v(TAG, "saving config.\n")
|
||||
wifiManager.saveConfiguration()
|
||||
wifi.networkId = ssidToNetworkId(wifi.SSID)
|
||||
|
||||
Log.v(TAG, "wifi ID in device = " + wifi.networkId)
|
||||
|
||||
var supState: SupplicantState
|
||||
val networkIdToConnect = wifi.networkId
|
||||
if (networkIdToConnect >= 0) {
|
||||
Log.v(TAG, "Start connecting...\n")
|
||||
|
||||
// We disable the network before connecting, because if this was the last connection before
|
||||
// a disconnect(), this will not reconnect.
|
||||
wifiManager.disableNetwork(networkIdToConnect)
|
||||
wifiManager.enableNetwork(networkIdToConnect, true)
|
||||
|
||||
val wifiInfo: WifiInfo = wifiManager.connectionInfo
|
||||
|
||||
HMGUtils.timer(5000,false){
|
||||
supState = wifiInfo.supplicantState
|
||||
Log.i(TAG, "WifiWizard: Done connect to network : status = $supState")
|
||||
val successStates = listOf(COMPLETED, ASSOCIATED)
|
||||
if (successStates.contains(COMPLETED /*supState*/))
|
||||
|
||||
completion(true,"Connected to internet Wifi")
|
||||
|
||||
else
|
||||
completion(false,"errorConnectingHmgNetwork")
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.v(TAG, "WifiWizard: cannot connect to network")
|
||||
completion(false,"errorConnectingHmgNetwork")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes a given String, searches the current list of configured WiFi
|
||||
* networks, and returns the networkId for the network if the SSID matches. If not,
|
||||
* it returns -1.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun ssidToNetworkId(ssid: String): Int {
|
||||
val currentNetworks = wifiManager_!!.configuredNetworks
|
||||
var networkId = -1
|
||||
|
||||
// For each network in the list, compare the SSID with the given one
|
||||
for (test in currentNetworks) {
|
||||
if (test.SSID == ssid) {
|
||||
networkId = test.networkId
|
||||
break
|
||||
}
|
||||
}
|
||||
return networkId
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
package com.ejada.hmg.hmgwifi
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import android.net.wifi.*
|
||||
import android.net.wifi.SupplicantState.ASSOCIATED
|
||||
import android.net.wifi.SupplicantState.COMPLETED
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.ejada.hmg.MainActivity
|
||||
import com.ejada.hmg.utils.HMGUtils
|
||||
import java.security.cert.X509Certificate
|
||||
|
||||
class WpaEnterprise(private val mainActivity: MainActivity, private var SSID: String) {
|
||||
private var TAG = "WpaEnterprise"
|
||||
|
||||
private lateinit var identity:String
|
||||
private lateinit var password:String
|
||||
private lateinit var completion:((status: Boolean, message: String) -> Unit)
|
||||
|
||||
fun connect(identity:String, password:String, completion: (status: Boolean, message: String) -> Unit) {
|
||||
this.password = password
|
||||
this.identity = identity
|
||||
this.completion = completion
|
||||
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
|
||||
apiGreaterThen28()
|
||||
}else if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
|
||||
apiLessThen29()
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
fun apiLessThen29(){
|
||||
val wifiManager = mainActivity.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
|
||||
val wifi = WifiConfiguration()
|
||||
wifi.SSID = """"$SSID""""
|
||||
wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP)
|
||||
wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X)
|
||||
wifi.enterpriseConfig = enterpriseConfig()
|
||||
wifi.networkId = ssidToNetworkId(wifi.SSID, wifiManager)
|
||||
if (wifi.networkId == -1) {
|
||||
wifiManager.addNetwork(wifi)
|
||||
} else {
|
||||
Log.v(TAG, "WiFi found - updating it.\n")
|
||||
wifiManager.updateNetwork(wifi)
|
||||
}
|
||||
Log.v(TAG, "saving config.\n")
|
||||
wifiManager.saveConfiguration()
|
||||
wifi.networkId = ssidToNetworkId(wifi.SSID, wifiManager)
|
||||
|
||||
Log.v(TAG, "wifi ID in device = " + wifi.networkId)
|
||||
|
||||
var supState: SupplicantState
|
||||
val networkIdToConnect = wifi.networkId
|
||||
if (networkIdToConnect >= 0) {
|
||||
Log.v(TAG, "Start connecting...\n")
|
||||
|
||||
// We disable the network before connecting, because if this was the last connection before
|
||||
// a disconnect(), this will not reconnect.
|
||||
wifiManager.disableNetwork(networkIdToConnect)
|
||||
wifiManager.enableNetwork(networkIdToConnect, true)
|
||||
|
||||
val wifiInfo: WifiInfo = wifiManager.connectionInfo
|
||||
|
||||
HMGUtils.timer(5000,false){
|
||||
supState = wifiInfo.supplicantState
|
||||
Log.i(TAG, "Done connect to network : status = $supState")
|
||||
val successStates = listOf(COMPLETED, ASSOCIATED)
|
||||
if (successStates.contains(supState))
|
||||
completion(true,"Connected to internet Wifi")
|
||||
else
|
||||
completion(false,"errorConnectingHmgNetwork")
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.v(TAG, "WifiWizard: cannot connect to network")
|
||||
completion(false,"errorConnectingHmgNetwork")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes a given String, searches the current list of configured WiFi
|
||||
* networks, and returns the networkId for the network if the SSID matches. If not,
|
||||
* it returns -1.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun ssidToNetworkId(ssid: String, wifiManager: WifiManager): Int {
|
||||
val currentNetworks = wifiManager.configuredNetworks
|
||||
var networkId = -1
|
||||
// For each network in the list, compare the SSID with the given one
|
||||
for (test in currentNetworks) {
|
||||
if (test.SSID == ssid) {
|
||||
networkId = test.networkId
|
||||
break
|
||||
}
|
||||
}
|
||||
return networkId
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
fun apiGreaterThen28(){
|
||||
val connectivityManager = mainActivity.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
|
||||
Log.e(TAG, "connection wifi with Android Q+")
|
||||
val wifiNetworkSpecifier: WifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
|
||||
.setSsid(SSID)
|
||||
.setWpa2EnterpriseConfig(enterpriseConfig())
|
||||
.build()
|
||||
|
||||
val networkRequest: NetworkRequest = NetworkRequest.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.setNetworkSpecifier(wifiNetworkSpecifier)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) //removeCapability added for hotspots without internet
|
||||
.build()
|
||||
|
||||
val networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
super.onAvailable(network)
|
||||
connectivityManager.bindProcessToNetwork(network)
|
||||
completion(true, "200")
|
||||
Log.e(TAG, "onAvailable")
|
||||
}
|
||||
|
||||
override fun onLosing(network: Network, maxMsToLive: Int) {
|
||||
super.onLosing(network, maxMsToLive)
|
||||
Log.e(TAG, "onLosing")
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
super.onLost(network)
|
||||
Log.e(TAG, "onLosing")
|
||||
Log.e(TAG, "losing active connection")
|
||||
}
|
||||
|
||||
override fun onUnavailable() {
|
||||
super.onUnavailable()
|
||||
completion(false, "401")
|
||||
Log.e(TAG, "onUnavailable")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//timeout add because "No devices found" wasn't handled correct and doesn't throw Unavailable
|
||||
connectivityManager.requestNetwork(networkRequest, networkCallback, 30000)
|
||||
}
|
||||
|
||||
fun enterpriseConfig() : WifiEnterpriseConfig{
|
||||
// Initialize the WifiConfiguration object
|
||||
val enterpriseConfig = WifiEnterpriseConfig()
|
||||
enterpriseConfig.eapMethod = WifiEnterpriseConfig.Eap.PEAP
|
||||
enterpriseConfig.identity = identity
|
||||
enterpriseConfig.password = password
|
||||
enterpriseConfig.phase2Method = WifiEnterpriseConfig.Phase2.NONE
|
||||
// enterpriseConfig.caCertificates = WifiEnterpriseConfig.Phase2.
|
||||
return enterpriseConfig;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.ejada.hmg.opentok
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import com.ejada.hmg.R
|
||||
import io.flutter.plugin.common.StandardMessageCodec
|
||||
import io.flutter.plugin.platform.PlatformView
|
||||
import io.flutter.plugin.platform.PlatformViewFactory
|
||||
|
||||
class LocalVideoFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
|
||||
|
||||
companion object {
|
||||
private lateinit var view: LocalVideoPlatformView
|
||||
|
||||
fun getViewInstance(context: Context): LocalVideoPlatformView {
|
||||
if(!this::view.isInitialized) {
|
||||
view = LocalVideoPlatformView(context)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
}
|
||||
|
||||
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
|
||||
return getViewInstance(context)
|
||||
}
|
||||
}
|
||||
|
||||
class LocalVideoPlatformView(context: Context) : PlatformView {
|
||||
private val videoContainer: LocalVideoContainer = LocalVideoContainer(context)
|
||||
|
||||
val container get() = videoContainer.publisherContainer
|
||||
|
||||
override fun getView(): View {
|
||||
return videoContainer
|
||||
}
|
||||
|
||||
override fun dispose() {}
|
||||
}
|
||||
|
||||
class LocalVideoContainer @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyle: Int = 0,
|
||||
defStyleRes: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyle, defStyleRes) {
|
||||
|
||||
var publisherContainer: FrameLayout private set
|
||||
|
||||
init {
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.local_video, this, true)
|
||||
publisherContainer = view.findViewById(R.id.publisher_container)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,181 @@
|
||||
package com.ejada.hmg.opentok
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import com.facebook.stetho.urlconnection.StethoURLConnectionManager
|
||||
import com.opentok.android.*
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
|
||||
enum class OpenTokSDKState {
|
||||
LOGGED_OUT,
|
||||
LOGGED_IN,
|
||||
WAIT,
|
||||
ERROR
|
||||
}
|
||||
|
||||
class OpenTok(private var context: Context, private var flutterEngine: FlutterEngine){
|
||||
private lateinit var remoteVideoPlatformView: RemoteVideoPlatformView
|
||||
private lateinit var localVideoPlatformView: LocalVideoPlatformView
|
||||
|
||||
init {
|
||||
remoteVideoPlatformView = RemoteVideoFactory.getViewInstance(context)
|
||||
flutterEngine
|
||||
.platformViewsController
|
||||
.registry
|
||||
.registerViewFactory("remote-video-container", RemoteVideoFactory())
|
||||
|
||||
localVideoPlatformView = LocalVideoFactory.getViewInstance(context)
|
||||
flutterEngine
|
||||
.platformViewsController
|
||||
.registry
|
||||
.registerViewFactory("local-video-container", LocalVideoFactory())
|
||||
}
|
||||
|
||||
private var session: Session? = null
|
||||
private var publisher: Publisher? = null
|
||||
private var subscriber: Subscriber? = null
|
||||
|
||||
|
||||
|
||||
private val sessionListener: Session.SessionListener = object: Session.SessionListener {
|
||||
override fun onConnected(session: Session) {
|
||||
// Connected to session
|
||||
Log.d("MainActivity", "Connected to session ${session.sessionId}")
|
||||
|
||||
publisher = Publisher.Builder(context).build().apply {
|
||||
setPublisherListener(publisherListener)
|
||||
renderer?.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL)
|
||||
|
||||
view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
localVideoPlatformView.container.addView(view)
|
||||
}
|
||||
|
||||
notifyFlutter(OpenTokSDKState.LOGGED_IN)
|
||||
session.publish(publisher)
|
||||
}
|
||||
|
||||
override fun onDisconnected(session: Session) {
|
||||
notifyFlutter(OpenTokSDKState.LOGGED_OUT)
|
||||
}
|
||||
|
||||
override fun onStreamReceived(session: Session, stream: Stream) {
|
||||
Log.d(
|
||||
"MainActivity",
|
||||
"onStreamReceived: New Stream Received " + stream.streamId + " in session: " + session.sessionId
|
||||
)
|
||||
if (subscriber == null) {
|
||||
subscriber = Subscriber.Builder(context, stream).build().apply {
|
||||
renderer?.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL)
|
||||
setSubscriberListener(subscriberListener)
|
||||
session.subscribe(this)
|
||||
|
||||
remoteVideoPlatformView.container.addView(view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStreamDropped(session: Session, stream: Stream) {
|
||||
Log.d(
|
||||
"MainActivity",
|
||||
"onStreamDropped: Stream Dropped: " + stream.streamId + " in session: " + session.sessionId
|
||||
)
|
||||
|
||||
if (subscriber != null) {
|
||||
subscriber = null
|
||||
|
||||
remoteVideoPlatformView.container.removeAllViews()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(session: Session, opentokError: OpentokError) {
|
||||
Log.d("MainActivity", "Session error: " + opentokError.message)
|
||||
notifyFlutter(OpenTokSDKState.ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
private val publisherListener: PublisherKit.PublisherListener = object : PublisherKit.PublisherListener {
|
||||
override fun onStreamCreated(publisherKit: PublisherKit, stream: Stream) {
|
||||
Log.d("MainActivity", "onStreamCreated: Publisher Stream Created. Own stream " + stream.streamId)
|
||||
}
|
||||
|
||||
override fun onStreamDestroyed(publisherKit: PublisherKit, stream: Stream) {
|
||||
Log.d("MainActivity", "onStreamDestroyed: Publisher Stream Destroyed. Own stream " + stream.streamId)
|
||||
}
|
||||
|
||||
override fun onError(publisherKit: PublisherKit, opentokError: OpentokError) {
|
||||
Log.d("MainActivity", "PublisherKit onError: " + opentokError.message)
|
||||
notifyFlutter(OpenTokSDKState.ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
var subscriberListener: SubscriberKit.SubscriberListener = object : SubscriberKit.SubscriberListener {
|
||||
override fun onConnected(subscriberKit: SubscriberKit) {
|
||||
Log.d("MainActivity", "onConnected: Subscriber connected. Stream: " + subscriberKit.stream.streamId)
|
||||
}
|
||||
|
||||
override fun onDisconnected(subscriberKit: SubscriberKit) {
|
||||
Log.d("MainActivity", "onDisconnected: Subscriber disconnected. Stream: " + subscriberKit.stream.streamId)
|
||||
notifyFlutter(OpenTokSDKState.LOGGED_OUT)
|
||||
}
|
||||
|
||||
override fun onError(subscriberKit: SubscriberKit, opentokError: OpentokError) {
|
||||
Log.d("MainActivity", "SubscriberKit onError: " + opentokError.message)
|
||||
notifyFlutter(OpenTokSDKState.ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
fun initSession(call: MethodCall, result: MethodChannel.Result) {
|
||||
|
||||
val apiKey = requireNotNull(call.argument<String>("apiKey"))
|
||||
val sessionId = requireNotNull(call.argument<String>("sessionId"))
|
||||
val token = requireNotNull(call.argument<String>("token"))
|
||||
|
||||
notifyFlutter(OpenTokSDKState.WAIT)
|
||||
session = Session.Builder(context, apiKey, sessionId).build()
|
||||
session?.setSessionListener(sessionListener)
|
||||
session?.connect(token)
|
||||
result.success("")
|
||||
}
|
||||
|
||||
fun swapCamera(call: MethodCall, result: MethodChannel.Result) {
|
||||
publisher?.cycleCamera()
|
||||
result.success(true)
|
||||
}
|
||||
|
||||
fun toggleAudio(call: MethodCall, result: MethodChannel.Result) {
|
||||
if (publisher != null) {
|
||||
publisher?.publishAudio = !(publisher!!.publishAudio)
|
||||
result.success(true)
|
||||
}else{
|
||||
result.success(false)
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleVideo(call: MethodCall, result: MethodChannel.Result) {
|
||||
if (publisher != null) {
|
||||
publisher?.publishVideo = !(publisher!!.publishVideo)
|
||||
result.success(true)
|
||||
}else{
|
||||
result.success(false)
|
||||
}
|
||||
}
|
||||
|
||||
fun hangupCall(call: MethodCall, result: MethodChannel.Result) {
|
||||
session?.disconnect()
|
||||
result.success(true)
|
||||
}
|
||||
|
||||
private fun notifyFlutter(state: OpenTokSDKState) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "OpenTok-Platform-Bridge")
|
||||
.invokeMethod("updateState", state.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.ejada.hmg.opentok
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import com.ejada.hmg.R
|
||||
import io.flutter.plugin.common.StandardMessageCodec
|
||||
import io.flutter.plugin.platform.PlatformView
|
||||
import io.flutter.plugin.platform.PlatformViewFactory
|
||||
|
||||
class RemoteVideoFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
|
||||
|
||||
companion object {
|
||||
private lateinit var view: RemoteVideoPlatformView
|
||||
|
||||
fun getViewInstance(context: Context): RemoteVideoPlatformView {
|
||||
if(!this::view.isInitialized) {
|
||||
view = RemoteVideoPlatformView(context)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
}
|
||||
|
||||
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
|
||||
return getViewInstance(context)
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteVideoPlatformView(context: Context) : PlatformView {
|
||||
private val videoContainer: RemoteVideoContainer = RemoteVideoContainer(context)
|
||||
|
||||
val container get() = videoContainer.subscriberContainer
|
||||
|
||||
override fun getView(): View {
|
||||
return videoContainer
|
||||
}
|
||||
|
||||
override fun dispose() {}
|
||||
}
|
||||
|
||||
class RemoteVideoContainer @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyle: Int = 0,
|
||||
defStyleRes: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyle, defStyleRes) {
|
||||
|
||||
var subscriberContainer: FrameLayout private set
|
||||
|
||||
init {
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.remote_video, this, true)
|
||||
subscriberContainer = view.findViewById(R.id.subscriber_container)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.cloud.hmg_patient_app.penguin
|
||||
|
||||
enum class PenguinMethod {
|
||||
// initializePenguin("initializePenguin"),
|
||||
// configurePenguin("configurePenguin"),
|
||||
// showPenguinUI("showPenguinUI"),
|
||||
// onPenNavUIDismiss("onPenNavUIDismiss"),
|
||||
// onReportIssue("onReportIssue"),
|
||||
// onPenNavSuccess("onPenNavSuccess"),
|
||||
onPenNavInitializationError // onLocationOffCampus("onLocationOffCampus"),
|
||||
// navigateToPOI("navigateToPOI"),
|
||||
// openSharedLocation("openSharedLocation");
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
package com.cloud.hmg_patient_app.penguin
|
||||
|
||||
import android.content.Context
|
||||
import com.google.gson.Gson
|
||||
import com.peng.pennavmap.PlugAndPlaySDK
|
||||
import com.peng.pennavmap.connections.ApiController
|
||||
import com.peng.pennavmap.interfaces.RefIdDelegate
|
||||
import com.peng.pennavmap.models.TokenModel
|
||||
import com.peng.pennavmap.models.postmodels.PostToken
|
||||
import com.peng.pennavmap.utils.AppSharedData
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import android.util.Log
|
||||
|
||||
|
||||
class PenguinNavigator() {
|
||||
|
||||
fun navigateTo(mContext: Context, refID: String, delegate: RefIdDelegate,clientID : String,clientKey : String ) {
|
||||
val postToken = PostToken(clientID, clientKey)
|
||||
getToken(mContext, postToken, object : RefIdDelegate {
|
||||
override fun onRefByIDSuccess(PoiId: String?) {
|
||||
Log.e("navigateTo", "PoiId is+++++++ $PoiId")
|
||||
|
||||
PlugAndPlaySDK.navigateTo(mContext, refID, object : RefIdDelegate {
|
||||
override fun onRefByIDSuccess(PoiId: String?) {
|
||||
Log.e("navigateTo", "PoiId 2is+++++++ $PoiId")
|
||||
|
||||
delegate.onRefByIDSuccess(refID)
|
||||
|
||||
}
|
||||
|
||||
override fun onGetByRefIDError(error: String?) {
|
||||
delegate.onRefByIDSuccess(error)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun onGetByRefIDError(error: String?) {
|
||||
delegate.onRefByIDSuccess(error)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
fun getToken(mContext: Context, postToken: PostToken?, apiTokenCallBack: RefIdDelegate) {
|
||||
try {
|
||||
// Create the API call
|
||||
val purposesCall: Call<ResponseBody> = ApiController.getInstance(mContext)
|
||||
.apiMethods
|
||||
.getToken(postToken)
|
||||
|
||||
// Enqueue the call for asynchronous execution
|
||||
purposesCall.enqueue(object : Callback<ResponseBody?> {
|
||||
override fun onResponse(
|
||||
call: Call<ResponseBody?>,
|
||||
response: Response<ResponseBody?>
|
||||
) {
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
try {
|
||||
response.body()?.use { responseBody ->
|
||||
val responseBodyString: String = responseBody.string() // Use `string()` to get the actual response content
|
||||
if (responseBodyString.isNotEmpty()) {
|
||||
val tokenModel = Gson().fromJson(responseBodyString, TokenModel::class.java)
|
||||
if (tokenModel != null && tokenModel.token != null) {
|
||||
AppSharedData.apiToken = tokenModel.token
|
||||
apiTokenCallBack.onRefByIDSuccess(tokenModel.token)
|
||||
} else {
|
||||
apiTokenCallBack.onGetByRefIDError("Failed to parse token model")
|
||||
}
|
||||
} else {
|
||||
apiTokenCallBack.onGetByRefIDError("Response body is empty")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
apiTokenCallBack.onGetByRefIDError("An error occurred: ${e.message}")
|
||||
}
|
||||
} else {
|
||||
apiTokenCallBack.onGetByRefIDError("Unsuccessful response: " + response.code())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<ResponseBody?>, t: Throwable) {
|
||||
apiTokenCallBack.onGetByRefIDError(t.message)
|
||||
}
|
||||
})
|
||||
} catch (error: Exception) {
|
||||
apiTokenCallBack.onGetByRefIDError("Exception during API call: $error")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,320 @@
|
||||
package com.cloud.hmg_patient_app.penguin
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Context.RECEIVER_EXPORTED
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.cloud.hmg_patient_app.PermissionManager.PermissionHelper
|
||||
import com.cloud.hmg_patient_app.PermissionManager.PermissionManager
|
||||
import com.cloud.hmg_patient_app.PermissionManager.PermissionResultReceiver
|
||||
import com.ejada.hmg.MainActivity
|
||||
import com.peng.pennavmap.PlugAndPlayConfiguration
|
||||
import com.peng.pennavmap.PlugAndPlaySDK
|
||||
import com.peng.pennavmap.enums.InitializationErrorType
|
||||
import com.peng.pennavmap.interfaces.PenNavUIDelegate
|
||||
import com.peng.pennavmap.utils.Languages
|
||||
import io.flutter.plugin.common.BinaryMessenger
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.platform.PlatformView
|
||||
import com.cloud.hmg_patient_app.penguin.PenguinNavigator
|
||||
import com.peng.pennavmap.interfaces.PIEventsDelegate
|
||||
import com.peng.pennavmap.interfaces.PILocationDelegate
|
||||
import com.peng.pennavmap.interfaces.RefIdDelegate
|
||||
import com.peng.pennavmap.models.PIReportIssue
|
||||
/**
|
||||
* Custom PlatformView for displaying Penguin UI components within a Flutter app.
|
||||
* Implements `PlatformView` for rendering the view, `MethodChannel.MethodCallHandler` for handling method calls,
|
||||
* and `PenNavUIDelegate` for handling SDK events.
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
internal class PenguinView(
|
||||
context: Context,
|
||||
id: Int,
|
||||
val creationParams: Map<String, Any>,
|
||||
messenger: BinaryMessenger,
|
||||
activity: MainActivity,
|
||||
val channel: MethodChannel
|
||||
) : PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate {
|
||||
// The layout for displaying the Penguin UI
|
||||
private val mapLayout: RelativeLayout = RelativeLayout(context)
|
||||
private val _context: Context = context
|
||||
|
||||
private val permissionResultReceiver: PermissionResultReceiver
|
||||
private val permissionIntentFilter = IntentFilter("PERMISSION_RESULT_ACTION")
|
||||
|
||||
private companion object {
|
||||
const val PERMISSIONS_REQUEST_CODE = 1
|
||||
}
|
||||
|
||||
private lateinit var permissionManager: PermissionManager
|
||||
|
||||
// Reference to the main activity
|
||||
private var _activity: Activity = activity
|
||||
|
||||
private lateinit var mContext: Context
|
||||
|
||||
lateinit var navigator: PenguinNavigator
|
||||
|
||||
init {
|
||||
// Set layout parameters for the mapLayout
|
||||
mapLayout.layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
|
||||
mContext = context
|
||||
|
||||
|
||||
permissionResultReceiver = PermissionResultReceiver { granted ->
|
||||
if (granted) {
|
||||
onPermissionsGranted()
|
||||
} else {
|
||||
onPermissionsDenied()
|
||||
}
|
||||
}
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
mContext.registerReceiver(
|
||||
permissionResultReceiver,
|
||||
permissionIntentFilter,
|
||||
RECEIVER_EXPORTED
|
||||
)
|
||||
} else {
|
||||
mContext.registerReceiver(
|
||||
permissionResultReceiver,
|
||||
permissionIntentFilter,
|
||||
)
|
||||
}
|
||||
|
||||
// Set the background color of the layout
|
||||
mapLayout.setBackgroundColor(Color.RED)
|
||||
|
||||
permissionManager = PermissionManager(
|
||||
context = mContext,
|
||||
listener = object : PermissionManager.PermissionListener {
|
||||
override fun onPermissionGranted() {
|
||||
// Handle permissions granted
|
||||
onPermissionsGranted()
|
||||
}
|
||||
|
||||
override fun onPermissionDenied() {
|
||||
// Handle permissions denied
|
||||
onPermissionsDenied()
|
||||
}
|
||||
},
|
||||
requestCode = PERMISSIONS_REQUEST_CODE,
|
||||
PermissionHelper.getRequiredPermissions().get(0)
|
||||
)
|
||||
|
||||
if (!permissionManager.arePermissionsGranted()) {
|
||||
permissionManager.requestPermissions(_activity)
|
||||
} else {
|
||||
// Permissions already granted
|
||||
permissionManager.listener.onPermissionGranted()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun onPermissionsGranted() {
|
||||
// Handle the actions when permissions are granted
|
||||
Log.d("PermissionsResult", "onPermissionsGranted")
|
||||
// Register the platform view factory for creating custom views
|
||||
|
||||
// Initialize the Penguin SDK
|
||||
initPenguin()
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun onPermissionsDenied() {
|
||||
// Handle the actions when permissions are denied
|
||||
Log.d("PermissionsResult", "onPermissionsDenied")
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the view associated with this PlatformView.
|
||||
*
|
||||
* @return The main view for this PlatformView.
|
||||
*/
|
||||
override fun getView(): View {
|
||||
return mapLayout
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up resources associated with this PlatformView.
|
||||
*/
|
||||
override fun dispose() {
|
||||
// Cleanup code if needed
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles method calls from Dart code.
|
||||
*
|
||||
* @param call The method call from Dart.
|
||||
* @param result The result callback to send responses back to Dart.
|
||||
*/
|
||||
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
|
||||
// Handle method calls from Dart code here
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Penguin SDK with custom configuration and delegates.
|
||||
*/
|
||||
private fun initPenguin() {
|
||||
navigator = PenguinNavigator()
|
||||
// Configure the PlugAndPlaySDK
|
||||
val language = when (creationParams["languageCode"] as String) {
|
||||
"ar" -> Languages.ar
|
||||
"en" -> Languages.en
|
||||
else -> {
|
||||
Languages.en
|
||||
}
|
||||
}
|
||||
Log.d(
|
||||
"TAG",
|
||||
"initPenguin: ${Languages.getLanguageEnum(creationParams["languageCode"] as String)}"
|
||||
)
|
||||
PlugAndPlaySDK.configuration = PlugAndPlayConfiguration.Builder()
|
||||
.setBaseUrl(
|
||||
creationParams["dataURL"] as String,
|
||||
creationParams["positionURL"] as String
|
||||
)
|
||||
.setServiceName(
|
||||
creationParams["dataServiceName"] as String,
|
||||
creationParams["positionServiceName"] as String
|
||||
)
|
||||
.setClientData(
|
||||
creationParams["clientID"] as String,
|
||||
creationParams["clientKey"] as String
|
||||
)
|
||||
.setUserName(creationParams["username"] as String)
|
||||
// .setLanguageID(Languages.en)
|
||||
.setLanguageID(language)
|
||||
.setSimulationModeEnabled(creationParams["isSimulationModeEnabled"] as Boolean)
|
||||
.setEnableBackButton(true)
|
||||
// .setDeepLinkData("deeplink")
|
||||
.setCustomizeColor("#2CA0AF")
|
||||
.setDeepLinkSchema("")
|
||||
.setIsEnableReportIssue(true)
|
||||
.build()
|
||||
|
||||
// Set location delegate to handle location updates
|
||||
// PlugAndPlaySDK.setPiLocationDelegate {
|
||||
// Example code to handle location updates
|
||||
// Uncomment and modify as needed
|
||||
// if (location.size() > 0)
|
||||
// Toast.makeText(_context, "Location Info Latitude: ${location[0]}, Longitude: ${location[1]}", Toast.LENGTH_SHORT).show()
|
||||
// }
|
||||
|
||||
// Set events delegate for reporting issues
|
||||
// PlugAndPlaySDK.setPiEventsDelegate(new PIEventsDelegate() {
|
||||
// @Override
|
||||
// public void onReportIssue(PIReportIssue issue) {
|
||||
// Log.e("Issue Reported: ", issue.getReportType());
|
||||
// }
|
||||
// // Implement issue reporting logic here }
|
||||
// @Override
|
||||
// public void onSharedLocation(String link) {
|
||||
// // Implement Shared location logic here
|
||||
// }
|
||||
// })
|
||||
|
||||
// Start the Penguin SDK
|
||||
PlugAndPlaySDK.start(mContext, this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Navigates to the specified reference ID.
|
||||
*
|
||||
* @param refID The reference ID to navigate to.
|
||||
*/
|
||||
fun navigateTo(refID: String) {
|
||||
try {
|
||||
if (refID.isBlank()) {
|
||||
Log.e("navigateTo", "Invalid refID: The reference ID is blank.")
|
||||
}
|
||||
// referenceId = refID
|
||||
navigator.navigateTo(mContext, refID,object : RefIdDelegate {
|
||||
override fun onRefByIDSuccess(PoiId: String?) {
|
||||
Log.e("navigateTo", "PoiId is penguin view+++++++ $PoiId")
|
||||
|
||||
// channelFlutter.invokeMethod(
|
||||
// PenguinMethod.navigateToPOI.name,
|
||||
// "navigateTo Success"
|
||||
// )
|
||||
}
|
||||
|
||||
override fun onGetByRefIDError(error: String?) {
|
||||
Log.e("navigateTo", "error is penguin view+++++++ $error")
|
||||
|
||||
// channelFlutter.invokeMethod(
|
||||
// PenguinMethod.navigateToPOI.name,
|
||||
// "navigateTo Failed: Invalid refID"
|
||||
// )
|
||||
}
|
||||
} , creationParams["clientID"] as String, creationParams["clientKey"] as String )
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e("navigateTo", "Exception occurred during navigation: ${e.message}", e)
|
||||
// channelFlutter.invokeMethod(
|
||||
// PenguinMethod.navigateToPOI.name,
|
||||
// "Failed: Exception - ${e.message}"
|
||||
// )
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when Penguin UI setup is successful.
|
||||
*
|
||||
* @param warningCode Optional warning code received from the SDK.
|
||||
*/
|
||||
override fun onPenNavSuccess(warningCode: String?) {
|
||||
val clinicId = creationParams["clinicID"] as String
|
||||
|
||||
if(clinicId.isEmpty()) return
|
||||
|
||||
navigateTo(clinicId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there is an initialization error with Penguin UI.
|
||||
*
|
||||
* @param description Description of the error.
|
||||
* @param errorType Type of initialization error.
|
||||
*/
|
||||
override fun onPenNavInitializationError(
|
||||
description: String?,
|
||||
errorType: InitializationErrorType?
|
||||
) {
|
||||
val arguments: Map<String, Any?> = mapOf(
|
||||
"description" to description,
|
||||
"type" to errorType?.name
|
||||
)
|
||||
|
||||
channel.invokeMethod(PenguinMethod.onPenNavInitializationError.name, arguments)
|
||||
Toast.makeText(mContext, "Navigation Error: $description", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when Penguin UI is dismissed.
|
||||
*/
|
||||
override fun onPenNavUIDismiss() {
|
||||
// Handle UI dismissal if needed
|
||||
try {
|
||||
mContext.unregisterReceiver(permissionResultReceiver)
|
||||
dispose();
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Log.e("PenguinView", "Receiver not registered: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.ejada.hmg.utils
|
||||
|
||||
class API {
|
||||
companion object{
|
||||
private val BASE = "https://hmgwebservices.com"
|
||||
private val SERVICE = "Services/Patients.svc/REST"
|
||||
|
||||
val WIFI_CREDENTIALS = "$BASE/$SERVICE/Hmg_SMS_Get_By_ProjectID_And_PatientID"
|
||||
val LOG_GEOFENCE = "$BASE/$SERVICE/GeoF_InsertPatientFileInfo"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.ejada.hmg.utils
|
||||
|
||||
|
||||
const val PREFS_STORAGE = "FlutterSharedPreferences"
|
||||
const val PREF_KEY_SUCCESS = "HMG_GEOFENCE_SUCCESS"
|
||||
const val PREF_KEY_FAILED = "HMG_GEOFENCE_FAILED"
|
||||
const val PREF_KEY_HMG_ZONES = "flutter.hmg-geo-fences"
|
||||
const val PREF_KEY_LANGUAGE = "flutter.language"
|
||||
@ -0,0 +1,36 @@
|
||||
package com.ejada.hmg.utils
|
||||
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.Result
|
||||
|
||||
class FlutterText{
|
||||
|
||||
companion object{
|
||||
fun with(key:String, completion:(String)->Unit){
|
||||
HMGUtils.getPlatformChannel().invokeMethod("localizedValue",key, object:MethodChannel.Result{
|
||||
override fun success(result: Any?) {
|
||||
val localized = result as String?
|
||||
if (localized != null){
|
||||
completion(localized)
|
||||
}else{
|
||||
completion(key)
|
||||
}
|
||||
}
|
||||
|
||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
||||
completion(key)
|
||||
require(false){
|
||||
"'localizedValue' $errorMessage"
|
||||
}
|
||||
}
|
||||
|
||||
override fun notImplemented() {
|
||||
require(false){
|
||||
"'localizedValue' method not implemented at flutter"
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,224 @@
|
||||
package com.ejada.hmg.utils
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.job.JobInfo
|
||||
import android.app.job.JobScheduler
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.Nullable
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.TaskStackBuilder
|
||||
import com.ejada.hmg.BuildConfig
|
||||
import com.ejada.hmg.MainActivity
|
||||
import com.ejada.hmg.R
|
||||
import com.ejada.hmg.geofence.GeoZoneModel
|
||||
import com.github.kittinunf.fuel.core.extensions.jsonBody
|
||||
import com.github.kittinunf.fuel.httpPost
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
//import org.jetbrains.anko.doAsyncResult
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.concurrent.timerTask
|
||||
|
||||
|
||||
class HMGUtils {
|
||||
|
||||
companion object{
|
||||
private lateinit var platformChannel: MethodChannel
|
||||
fun getPlatformChannel():MethodChannel{
|
||||
return platformChannel
|
||||
}
|
||||
fun setPlatformChannel(channel: MethodChannel){
|
||||
platformChannel = channel
|
||||
}
|
||||
|
||||
fun timer(delay: Long, repeat: Boolean, tick: (Timer) -> Unit) : Timer{
|
||||
val timer = Timer()
|
||||
if(repeat)
|
||||
timer.schedule(timerTask {
|
||||
tick(timer)
|
||||
}, delay, delay)
|
||||
else
|
||||
timer.schedule(timerTask {
|
||||
tick(timer)
|
||||
}, delay)
|
||||
|
||||
return timer
|
||||
}
|
||||
|
||||
fun popMessage(context: MainActivity, message: String){
|
||||
context.runOnUiThread {
|
||||
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun popFlutterText(context: MainActivity, key: String){
|
||||
context.runOnUiThread {
|
||||
FlutterText.with(key){
|
||||
Toast.makeText(context, it, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getLanguageCode(context: Context) : Int {
|
||||
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||
val lang = pref.getString(PREF_KEY_LANGUAGE, "ar")
|
||||
return if (lang == "ar") 2 else 1
|
||||
}
|
||||
|
||||
fun defaultHTTPParams(context: Context) : Map<String, Any?>{
|
||||
return mapOf(
|
||||
"ZipCode" to "966",
|
||||
"VersionID" to 5.8,
|
||||
"Channel" to 3,
|
||||
"LanguageID" to getLanguageCode(context),
|
||||
"IPAdress" to "10.20.10.20",
|
||||
"generalid" to "Cs2020@2016$2958",
|
||||
"PatientOutSA" to 0,
|
||||
"SessionID" to null,
|
||||
"isDentalAllowedBackend" to false,
|
||||
"DeviceTypeID" to 2)
|
||||
}
|
||||
|
||||
|
||||
fun <T>scheduleJob(context: Context, pendingIntentClassType:Class<T>, jobId:Int, intervalDuration:String, deadlineMillis:Long = (30 * 1000)) { // default deadline: 30 Seconds
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||
val jobScheduler: JobScheduler = context.getSystemService(JobScheduler::class.java)
|
||||
|
||||
val serviceComponent = ComponentName(context, pendingIntentClassType)
|
||||
val builder = JobInfo.Builder(jobId, serviceComponent)
|
||||
builder.setPersisted(true)
|
||||
builder.setBackoffCriteria(30000, JobInfo.BACKOFF_POLICY_LINEAR)
|
||||
|
||||
val intervalMillis = timeToMillis(intervalDuration,"HH:mm:ss")
|
||||
builder.setMinimumLatency(intervalMillis) // wait at least
|
||||
builder.setOverrideDeadline((intervalMillis + deadlineMillis)) // maximum delay
|
||||
if (jobScheduler.schedule(builder.build()) == JobScheduler.RESULT_SUCCESS){
|
||||
Logs.save(context,"ScheduleJob", "${pendingIntentClassType.simpleName}: Job scheduled to trigger after duration $intervalDuration >> HH:mm:ss --('MinimumLatency:$intervalMillis Deadline:${(intervalMillis + deadlineMillis)}')--",Logs.STATUS.SUCCESS)
|
||||
}else{
|
||||
Logs.save(context,"ScheduleJob", "${pendingIntentClassType.simpleName}: Failed to scheduled Job",Logs.STATUS.ERROR)
|
||||
}
|
||||
|
||||
} else {
|
||||
Logs.save(context,"ScheduleJob", "${pendingIntentClassType.simpleName}: Failed to scheduled Job on VERSION.SDK_INT < ${android.os.Build.VERSION_CODES.M}",Logs.STATUS.ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private const val NOTIFICATION_CHANNEL_ID = BuildConfig.APPLICATION_ID + ".channel"
|
||||
|
||||
|
||||
fun timeToMillis(time:String, format:String):Long{
|
||||
val sdf = SimpleDateFormat(format, Locale.US)
|
||||
val millis = sdf.parse(time).time + TimeZone.getDefault().rawOffset
|
||||
return millis
|
||||
}
|
||||
|
||||
fun sendNotification(context: Context, title: String, @Nullable subtitle: String?, message: String?) {
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID) == null) {
|
||||
val name = context.getString(R.string.app_name)
|
||||
val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID,
|
||||
name,
|
||||
NotificationManager.IMPORTANCE_DEFAULT)
|
||||
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
|
||||
val stackBuilder = TaskStackBuilder.create(context)
|
||||
.addParentStack(MainActivity::class.java)
|
||||
.addNextIntent(intent)
|
||||
val notificationPendingIntent = stackBuilder.getPendingIntent(getUniqueId(), PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
|
||||
.setSmallIcon(R.mipmap.ic_launcher_local)
|
||||
.setContentIntent(notificationPendingIntent)
|
||||
.setAutoCancel(true)
|
||||
.setContentTitle(title)
|
||||
|
||||
subtitle.let { notification.setContentText(it) }
|
||||
message.let { notification.setSubText(it) }
|
||||
|
||||
notificationManager.notify(getUniqueId(), notification.build())
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
// Open Helper Methods
|
||||
//-------------------------
|
||||
fun getUniqueId() = ((System.currentTimeMillis() % 10000).toInt())
|
||||
|
||||
object DateUtils {
|
||||
@JvmStatic
|
||||
fun dateTimeNow() : String {
|
||||
val format = SimpleDateFormat("dd-MMM-yyy hh:mm:ss")
|
||||
return format.format(Date())
|
||||
}
|
||||
}
|
||||
|
||||
fun isJSONValid(jsonString: String?): Boolean {
|
||||
try { JSONObject(jsonString) } catch (ex: JSONException) {
|
||||
try { JSONArray(jsonString) } catch (ex1: JSONException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun saveLog(context: Context, tag: String, message: String){
|
||||
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||
var logs = pref.getString("LOGS", "")
|
||||
logs += "$tag -> $message \n"
|
||||
pref.edit().putString("LOGS", logs).apply();
|
||||
}
|
||||
|
||||
fun getLogs(context: Context) : String?{
|
||||
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||
return pref.getString("LOGS", "")
|
||||
}
|
||||
|
||||
class HTTPResponse<T>(data: T){
|
||||
final var data:T = data
|
||||
}
|
||||
|
||||
fun <T>httpPost(url: String, body: Map<String, Any?>, onSuccess: (response: HTTPResponse<T>) -> Unit, onError: (error: Exception) -> Unit){
|
||||
val gson = Gson()
|
||||
val type = object : TypeToken<T>() {}.type
|
||||
val jsonBody = gson.toJson(body)
|
||||
url.httpPost()
|
||||
.jsonBody(jsonBody, Charsets.UTF_8)
|
||||
.timeout(10000)
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Allow", "*/*")
|
||||
.response { request, response, result ->
|
||||
result.fold({ data ->
|
||||
val dataString = String(data)
|
||||
if (isJSONValid(dataString)) {
|
||||
val responseData = gson.fromJson<T>(dataString, type)
|
||||
onSuccess(HTTPResponse(responseData))
|
||||
} else {
|
||||
onError(Exception("Invalid response from server (Not a valid JSON)"))
|
||||
}
|
||||
}, {
|
||||
onError(it)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,351 @@
|
||||
//package com.ejada.hmg.utils
|
||||
//
|
||||
//import android.annotation.SuppressLint
|
||||
//import android.content.Context
|
||||
//import android.net.ConnectivityManager
|
||||
//import android.net.Network
|
||||
//import android.net.NetworkCapabilities
|
||||
//import android.net.NetworkRequest
|
||||
//import android.net.wifi.ScanResult
|
||||
//import android.net.wifi.WifiConfiguration
|
||||
//import android.net.wifi.WifiManager
|
||||
//import android.util.Log
|
||||
//import com.ejada.hmg.utils.API
|
||||
//import com.ejada.hmg.FlutterMainActivity
|
||||
//import com.github.kittinunf.fuel.core.extensions.jsonBody
|
||||
//import com.github.kittinunf.fuel.httpGet
|
||||
//import com.github.kittinunf.fuel.httpPost
|
||||
//import org.json.JSONObject
|
||||
//import java.util.*
|
||||
//
|
||||
//
|
||||
//@SuppressLint("MissingPermission")
|
||||
//class HMG_Wifi_(flutterMainActivity: FlutterMainActivity) {
|
||||
// val TAG = "WIFI"
|
||||
// val TEST = true
|
||||
//
|
||||
// var context = flutterMainActivity;
|
||||
// var completionListener: ((status: Boolean, message: String) -> Unit)? = null
|
||||
//
|
||||
//
|
||||
// private var SSID = "HMG-GUEST"
|
||||
// private var USER_NAME = ""
|
||||
// private var PASSWORD = ""
|
||||
// var NETWORK_ID = -1 // HMG-GUEST Assigned Network ID by Android
|
||||
// private lateinit var PATIENT_ID:String
|
||||
// /*
|
||||
// * Helpful:
|
||||
// * http://stackoverflow.com/questions/5452940/how-can-i-get-android-wifi-scan-results-into-a-list
|
||||
// */
|
||||
// fun triggerWifiScan(context: Context) {
|
||||
// val wifi = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
// wifi.startScan()
|
||||
// }
|
||||
//
|
||||
// /*
|
||||
// * Helpful:
|
||||
// * http://stackoverflow.com/questions/8818290/how-to-connect-to-a-specific-wifi-network-in-android-programmatically
|
||||
// */
|
||||
// fun connectToWifiNetworkWith(patientId: String): HMG_Wifi_ {
|
||||
//
|
||||
// val connectivityManager = context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
//
|
||||
// PATIENT_ID = patientId
|
||||
//
|
||||
// val security = "OPEN"
|
||||
// val networkPass = ""
|
||||
// Log.d(TAG, "Connecting to SSID \"$SSID\" with password \"$networkPass\" and with security \"$security\" ...")
|
||||
//
|
||||
// // You need to create WifiConfiguration instance like this:
|
||||
// val conf = WifiConfiguration()
|
||||
// conf.SSID = "\"" + SSID + "\""
|
||||
//
|
||||
// if (security == "OPEN") {
|
||||
// conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
|
||||
// } else if (security == "WEP") {
|
||||
// conf.wepKeys[0] = "\"" + networkPass + "\""
|
||||
// conf.wepTxKeyIndex = 0
|
||||
// conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
|
||||
// conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40)
|
||||
// } else {
|
||||
// conf.preSharedKey = "\"" + networkPass + "\""
|
||||
// }
|
||||
//
|
||||
// // Then, you need to add it to Android wifi manager settings:
|
||||
// val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
//
|
||||
// NETWORK_ID = wifiManager.addNetwork(conf)
|
||||
// Log.d(TAG, "Network ID: $NETWORK_ID")
|
||||
//
|
||||
// //wifiManager.disconnect();
|
||||
// val result = wifiManager.enableNetwork(NETWORK_ID, true)
|
||||
// //wifiManager.reconnect();
|
||||
// wifiManager.saveConfiguration()
|
||||
//
|
||||
// if(result == true){
|
||||
// authNetworkConnection(NETWORK_ID);
|
||||
// }else{
|
||||
// completionListener?.let { it(false, "Error connecting to HMG network") }
|
||||
// }
|
||||
// return this
|
||||
// }
|
||||
//
|
||||
// private var authTimer:Timer? = null
|
||||
// fun authNetworkConnection(networkId: Int){
|
||||
// authTimer = Timer()
|
||||
// authTimer?.scheduleAtFixedRate(object : TimerTask() {
|
||||
// override fun run() {
|
||||
// if (connectedNetworkId() == networkId && connectedNetworkIPAddress() > 0) {
|
||||
// authServerCall()
|
||||
// authTimer?.cancel()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }, 2000, 1000)
|
||||
//
|
||||
// // If wifi not connected in 5 sec terminate with fail status
|
||||
// Timer().schedule(object : TimerTask() {
|
||||
// override fun run() {
|
||||
// if (null != authTimer) {
|
||||
// authTimer?.cancel()
|
||||
// completionListener?.let { it(false, "Error connecting to HMG network") }
|
||||
// }
|
||||
// }
|
||||
// }, 5000)
|
||||
//
|
||||
// }
|
||||
//
|
||||
// fun authServerCall(){
|
||||
//
|
||||
// fun call(){
|
||||
//
|
||||
// forceNetworkCallOverWifi()
|
||||
//
|
||||
// val params = listOf("cmd" to "authenticate", "password" to PASSWORD, "user" to USER_NAME)
|
||||
// val serverUrl = "https://captiveportal-login.hmg.com/cgi-bin/login"
|
||||
//// val serverUrl = "http://192.168.102.223/cgi-bin/login"
|
||||
// serverUrl
|
||||
// .httpPost(params)
|
||||
// .timeout(10000)
|
||||
// .response { request, response, result ->
|
||||
// Log.v(TAG, response.statusCode.toString())
|
||||
//
|
||||
// haveInternet { have ->
|
||||
// if(have){
|
||||
// Log.v(TAG, "Connected to internet via $SSID network at HMG")
|
||||
// completionListener?.let { it(true, "Successfully connected to the internet") }
|
||||
// }else{
|
||||
// Log.e(TAG, "failed to connect to internet via $SSID network at HMG")
|
||||
// completionListener?.let { it(false, "Authentication failed or you are already using your credentials on another device") }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// haveInternet { has ->
|
||||
// if (has){
|
||||
// getAuthCredentials {
|
||||
// call()
|
||||
// }
|
||||
// }else{
|
||||
// completionListener?.let { it(false, "You must have active internet connection to connect with HMG Network") }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun haveInternet(completion: ((status: Boolean) -> Unit)){
|
||||
// if (TEST)
|
||||
// completion(true)
|
||||
//
|
||||
// "https://captive.apple.com".httpGet().response { request, response, result ->
|
||||
// val have = response.statusCode == 200 && String(response.data).contains("<TITLE>Success</TITLE>", true)
|
||||
// completion(have)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun getAuthCredentials(completion: (() -> Unit)){
|
||||
// if (TEST){
|
||||
// USER_NAME = "2300"
|
||||
// PASSWORD = "1820"
|
||||
// completion()
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// val jsonBody = """{"PatientID":$PATIENT_ID}"""
|
||||
// API.WIFI_CREDENTIALS
|
||||
// .httpPost()
|
||||
// .jsonBody(jsonBody, Charsets.UTF_8)
|
||||
// .response { request, response, result ->
|
||||
// val jsonString = String(response.data)
|
||||
// Log.d(TAG, "JSON $jsonString")
|
||||
//
|
||||
// if (response.statusCode == 200){
|
||||
//
|
||||
// val jsonObject = JSONObject(jsonString)
|
||||
// if(!jsonObject.getString("ErrorMessage").equals("null")){
|
||||
// val errorMsg = jsonObject.getString("ErrorMessage")
|
||||
// completionListener?.let { it(false, errorMsg) }
|
||||
//
|
||||
// }else{
|
||||
// jsonObject.getJSONArray("Hmg_SMS_Get_By_ProjectID_And_PatientIDList").let { array ->
|
||||
// array.getJSONObject(0).let { object_ ->
|
||||
// if (object_.has("UserName") && object_.has("UserName")){
|
||||
// USER_NAME = object_.getString("UserName")
|
||||
// PASSWORD = object_.getString("Password")
|
||||
// completion()
|
||||
// }else{
|
||||
// completionListener?.let { it(false, "Failed to get your internet credentials") }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }else{
|
||||
// completionListener?.let { it(false, "Failed to get your internet credentials") }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun forceNetworkCallOverWifi(){
|
||||
// val connectivityManager = context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
//// val network = Network
|
||||
//// connectivityManager.activeNetwork
|
||||
// // Exit app if Network disappears.
|
||||
// // Exit app if Network disappears.
|
||||
//// val networkCapabilities: NetworkCapabilities = ConnectivityManager.from(context).getNetworkCapabilities(network)
|
||||
//// val networkCapabilities: NetworkCapabilities = connectivityManager.getNetworkCapabilities(network)
|
||||
//
|
||||
//// if (networkCapabilities == null) {
|
||||
//// return
|
||||
//// }
|
||||
//
|
||||
// val mNetworkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
// override fun onLost(lostNetwork: Network?) {
|
||||
//// if (network.equals(lostNetwork)){
|
||||
//// //GlyphLayout.done(false)
|
||||
//// }
|
||||
// }
|
||||
// }
|
||||
// val builder: NetworkRequest.Builder = NetworkRequest.Builder()
|
||||
//// for (transportType in networkCapabilities.getTransportTypes()) {
|
||||
//// builder.addTransportType(transportType)
|
||||
//// }
|
||||
// connectivityManager.registerNetworkCallback(builder.build(), mNetworkCallback)
|
||||
// }
|
||||
//
|
||||
// /*
|
||||
// * Helpful:
|
||||
// * http://stackoverflow.com/questions/6517314/android-wifi-connection-programmatically
|
||||
// */
|
||||
// fun getScanResultSecurity(result: ScanResult): String? {
|
||||
// val capabilities: String = result.capabilities
|
||||
// val securityModes = arrayOf("WEP", "PSK", "EAP")
|
||||
// for (securityMode in securityModes) {
|
||||
// if (capabilities.contains(securityMode)) {
|
||||
// return securityMode
|
||||
// }
|
||||
// }
|
||||
// return "OPEN"
|
||||
// }
|
||||
//
|
||||
// //connects to the given ssid
|
||||
// fun connectToWPAWiFi(ssid: String, password: String){
|
||||
//
|
||||
// WifiUtils.withContext(context)
|
||||
// .connectWith(ssid, "")
|
||||
// .setTimeout(40000)
|
||||
// .onConnectionResult(object : ConnectionSuccessListener {
|
||||
// override fun success() {
|
||||
// Log.v(TAG,"Success")
|
||||
// }
|
||||
//
|
||||
// override fun failed(@NonNull errorCode: ConnectionErrorCode) {
|
||||
// Log.v(TAG,"Failed")
|
||||
// }
|
||||
// })
|
||||
// .start()
|
||||
// if(isConnectedTo(ssid)){ //see if we are already connected to the given ssid
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
// Log.e(TAG, "connection wifi Q")
|
||||
//
|
||||
// val wifiNetworkSpecifier: WifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
|
||||
// .setSsid(ssid)
|
||||
// .setWpa2Passphrase(password)
|
||||
// .build()
|
||||
//
|
||||
// val networkRequest: NetworkRequest = NetworkRequest.Builder()
|
||||
// .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
// .setNetworkSpecifier(wifiNetworkSpecifier)
|
||||
// .build()
|
||||
//
|
||||
// var connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
// var networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
// override fun onAvailable(network: Network) {
|
||||
// super.onAvailable(network)
|
||||
// connectivityManager.bindProcessToNetwork(network)
|
||||
// Log.e(TAG, "onAvailable")
|
||||
// }
|
||||
//
|
||||
// override fun onLosing(network: Network, maxMsToLive: Int) {
|
||||
// super.onLosing(network, maxMsToLive)
|
||||
// Log.e(TAG, "onLosing")
|
||||
// }
|
||||
//
|
||||
// override fun onLost(network: Network) {
|
||||
// super.onLost(network)
|
||||
// Log.e(TAG, "onLosing")
|
||||
// Log.e(TAG, "losing active connection")
|
||||
// }
|
||||
//
|
||||
// override fun onUnavailable() {
|
||||
// super.onUnavailable()
|
||||
// Log.e(TAG, "onUnavailable")
|
||||
// }
|
||||
// }
|
||||
// connectivityManager.requestNetwork(networkRequest, networkCallback)
|
||||
//
|
||||
// }else{
|
||||
//
|
||||
// try {
|
||||
// val wm:WifiManager= context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
//
|
||||
// Log.e(TAG, "connection wifi pre Q")
|
||||
//
|
||||
// var netId: Int = wm.addNetwork(getWifiConfig(ssid))
|
||||
// if (netId == -1) netId = getExistingNetworkId(ssid);
|
||||
// wm.saveConfiguration()
|
||||
// if(wm.enableNetwork(netId, true)){
|
||||
// Log.v(TAG,"HMG-GUEST Connected")
|
||||
// }else{
|
||||
// Log.v(TAG,"HMG-GUEST failed to connect")
|
||||
// }
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// Log.v(TAG,"HMG-GUEST failed to connect")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// fun connectedNetworkId():Int{
|
||||
// val wm:WifiManager= context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
// return wm.connectionInfo.networkId
|
||||
// }
|
||||
//
|
||||
// fun connectedNetworkIPAddress():Int{
|
||||
// val wm:WifiManager= context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
// return wm.connectionInfo.ipAddress
|
||||
// }
|
||||
//
|
||||
// fun isConnectedTo(bssid: String):Boolean{
|
||||
// val wm:WifiManager= context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
// if(wm.connectionInfo.bssid == bssid){
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@ -0,0 +1,145 @@
|
||||
package com.ejada.hmg.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import com.ejada.hmg.BuildConfig
|
||||
import com.google.gson.Gson
|
||||
|
||||
class Logs {
|
||||
|
||||
enum class STATUS{
|
||||
SUCCESS,
|
||||
ERROR;
|
||||
}
|
||||
class GeofenceEvent{
|
||||
companion object{
|
||||
fun save(context: Context, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
|
||||
Logs.Common.save(context,"GeofenceEvent", tag, message, status)
|
||||
}
|
||||
|
||||
fun list(context: Context, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
|
||||
return Logs.Common.list(context,"GeofenceEvent", tag, status)
|
||||
}
|
||||
|
||||
fun raw(context: Context):String{
|
||||
return Logs.Common.raw(context,"GeofenceEvent")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RegisterGeofence{
|
||||
companion object{
|
||||
fun save(context: Context, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
|
||||
Logs.Common.save(context,"RegisterGeofence", tag, message, status)
|
||||
}
|
||||
|
||||
fun list(context: Context, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
|
||||
return Logs.Common.list(context,"RegisterGeofence", tag, status)
|
||||
}
|
||||
|
||||
fun raw(context: Context):String{
|
||||
return Logs.Common.raw(context,"RegisterGeofence");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object{
|
||||
private var pref:SharedPreferences? = null
|
||||
fun save(context: Context, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
|
||||
Logs.Common.save(context,"Logs", tag, message, status)
|
||||
}
|
||||
|
||||
fun list(context: Context, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
|
||||
return Logs.Common.list(context,"Logs", tag, status)
|
||||
}
|
||||
|
||||
fun raw(context: Context):String{
|
||||
return Logs.Common.raw(context,"Logs");
|
||||
}
|
||||
|
||||
private fun storage(context: Context):SharedPreferences{
|
||||
if(pref == null) {
|
||||
pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||
}
|
||||
return pref!!
|
||||
}
|
||||
}
|
||||
|
||||
private class Common{
|
||||
companion object{
|
||||
private val gson = Gson()
|
||||
|
||||
fun save(context: Context, key:String, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
|
||||
if(!BuildConfig.DEBUG)
|
||||
return
|
||||
|
||||
val pref = Logs.storage(context)
|
||||
|
||||
val string = pref.getString(key,"{}")
|
||||
val json = gson.fromJson<LogsContainerModel>(string,LogsContainerModel::class.java)
|
||||
json.add(
|
||||
LogModel().apply {
|
||||
this.TAG = tag
|
||||
this.MESSAGE = message
|
||||
this.STATUS = status.name
|
||||
this.DATE = DateUtils.dateTimeNow()
|
||||
}
|
||||
)
|
||||
|
||||
pref.edit().putString(key,gson.toJson(json)).apply()
|
||||
}
|
||||
|
||||
fun list(context: Context, key:String, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
|
||||
val pref = Logs.storage(context)
|
||||
val string = pref.getString(key,"{}")
|
||||
val json = gson.fromJson<LogsContainerModel>(string,LogsContainerModel::class.java)
|
||||
if(tag == null && status == null) {
|
||||
return json.LOGS
|
||||
}else if(tag != null && status != null){
|
||||
return json.LOGS.filter { (it.TAG == tag && it.STATUS == status.name) }
|
||||
}else if(tag != null){
|
||||
return json.LOGS.filter { (it.TAG == tag) }
|
||||
}else if(status != null){
|
||||
return json.LOGS.filter { (it.STATUS == status.name) }
|
||||
}
|
||||
return listOf()
|
||||
}
|
||||
|
||||
fun raw(context: Context, key:String):String{
|
||||
val pref = Logs.storage(context)
|
||||
val string = pref.getString(key,"{}")
|
||||
return string!!
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class LogModel{
|
||||
lateinit var TAG:String
|
||||
lateinit var MESSAGE:String
|
||||
lateinit var STATUS:String
|
||||
lateinit var DATE:String
|
||||
|
||||
companion object{
|
||||
fun with(tag:String, message:String, status:String):LogModel{
|
||||
return LogModel().apply {
|
||||
this.TAG = tag
|
||||
this.MESSAGE = message
|
||||
this.STATUS = status
|
||||
this.DATE = DateUtils.dateTimeNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LogsContainerModel{
|
||||
var LOGS = mutableListOf<LogModel>()
|
||||
fun add(log:LogModel){
|
||||
LOGS.add(log)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.ejada.hmg.utils
|
||||
|
||||
import com.ejada.hmg.MainActivity
|
||||
import com.ejada.hmg.opentok.OpenTok
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
class OpenTokPlatformBridge(private var flutterEngine: FlutterEngine, private var mainActivity: MainActivity) {
|
||||
|
||||
private lateinit var channel: MethodChannel
|
||||
private lateinit var openTok: OpenTok
|
||||
|
||||
companion object {
|
||||
private const val CHANNEL = "OpenTok-Platform-Bridge"
|
||||
}
|
||||
|
||||
fun create(){
|
||||
openTok = OpenTok(mainActivity, flutterEngine)
|
||||
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
|
||||
channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
|
||||
when (call.method) {
|
||||
"initSession" -> {
|
||||
openTok.initSession(call, result)
|
||||
}
|
||||
"swapCamera" -> {
|
||||
openTok.swapCamera(call, result)
|
||||
}
|
||||
"toggleAudio" -> {
|
||||
openTok.toggleAudio(call, result)
|
||||
}
|
||||
"toggleVideo" -> {
|
||||
openTok.toggleVideo(call, result)
|
||||
}
|
||||
"hangupCall" -> {
|
||||
openTok.hangupCall(call, result)
|
||||
}
|
||||
else -> {
|
||||
result.notImplemented()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,199 @@
|
||||
package com.ejada.hmg.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.getIntent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ActivityCompat.startActivityForResult
|
||||
import android.net.wifi.WifiManager
|
||||
import android.util.Log
|
||||
import com.ejada.hmg.MainActivity
|
||||
import com.ejada.hmg.hmgwifi.HMG_Guest
|
||||
import com.ejada.hmg.geofence.GeoZoneModel
|
||||
import com.ejada.hmg.geofence.HMG_Geofence
|
||||
import com.ejada.hmg.hmgwifi.WpaEnterprise
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
class PlatformBridge(private var flutterEngine: FlutterEngine, private var mainActivity: MainActivity) {
|
||||
|
||||
private lateinit var channel: MethodChannel
|
||||
|
||||
companion object {
|
||||
private const val CHANNEL = "HMG-Platform-Bridge"
|
||||
private const val HMG_INTERNET_WIFI_CONNECT_METHOD = "connectHMGInternetWifi"
|
||||
private const val HMG_GUEST_WIFI_CONNECT_METHOD = "connectHMGGuestWifi"
|
||||
private const val ENABLE_WIFI_IF_NOT = "enableWifiIfNot"
|
||||
private const val REGISTER_HMG_GEOFENCES = "registerHmgGeofences"
|
||||
private const val UN_REGISTER_HMG_GEOFENCES = "unRegisterHmgGeofences"
|
||||
private const val IS_DRAW_OVER_APPS_PERMISSION_ALLOWED = "isDrawOverAppsPermissionAllowed"
|
||||
private const val ASK_DRAW_OVER_APPS_PERMISSION = "askDrawOverAppsPermission"
|
||||
private const val GET_INTENT = "getIntent"
|
||||
}
|
||||
|
||||
fun create() {
|
||||
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
|
||||
HMGUtils.setPlatformChannel(channel)
|
||||
channel.setMethodCallHandler { methodCall: MethodCall, result: MethodChannel.Result ->
|
||||
|
||||
if (methodCall.method == HMG_INTERNET_WIFI_CONNECT_METHOD) {
|
||||
connectHMGInternetWifi(methodCall, result)
|
||||
|
||||
} else if (methodCall.method == HMG_GUEST_WIFI_CONNECT_METHOD) {
|
||||
connectHMGGuestWifi(methodCall, result)
|
||||
|
||||
} else if (methodCall.method == ENABLE_WIFI_IF_NOT) {
|
||||
enableWifiIfNot(methodCall, result)
|
||||
} else if (methodCall.method == REGISTER_HMG_GEOFENCES) {
|
||||
registerHmgGeofences(methodCall, result)
|
||||
} else if (methodCall.method == UN_REGISTER_HMG_GEOFENCES) {
|
||||
unRegisterHmgGeofences(methodCall, result)
|
||||
} else if (methodCall.method == IS_DRAW_OVER_APPS_PERMISSION_ALLOWED) {
|
||||
isDrawOverAppsPermissionAllowed(methodCall, result)
|
||||
} else if (methodCall.method == ASK_DRAW_OVER_APPS_PERMISSION) {
|
||||
askDrawOverAppsPermission(methodCall, result)
|
||||
} else if (methodCall.method == GET_INTENT) {
|
||||
getIntentData(methodCall, result)
|
||||
} else {
|
||||
result.notImplemented()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val res = channel.invokeMethod("localizedValue", "errorConnectingHmgNetwork")
|
||||
|
||||
}
|
||||
|
||||
private fun connectHMGInternetWifi(methodCall: MethodCall, result: MethodChannel.Result) {
|
||||
(methodCall.arguments as ArrayList<*>).let {
|
||||
require(it.size == 3 && (it[0] is String) && (it[1] is String), lazyMessage = {
|
||||
"Missing or invalid arguments (Must have three argument of 'String'"
|
||||
})
|
||||
|
||||
val ssid = it[0].toString()
|
||||
val username = it[1].toString()
|
||||
val password = it[2].toString()
|
||||
|
||||
WpaEnterprise(mainActivity,ssid).connect(username,password) { status, message ->
|
||||
HMGUtils.timer(2000,false){
|
||||
mainActivity.runOnUiThread {
|
||||
if(status)
|
||||
result.success(if (status) 1 else 0)
|
||||
else
|
||||
result.error(message, null, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HMG_Internet(mainActivity)
|
||||
// .connectToHMGGuestNetwork(username, password) { status, message ->
|
||||
// mainActivity.runOnUiThread {
|
||||
// result.success(if (status) 1 else 0)
|
||||
//
|
||||
// HMGUtils.popFlutterText(mainActivity, message)
|
||||
// Log.v(this.javaClass.simpleName, "$status | $message")
|
||||
// }
|
||||
//
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun connectHMGGuestWifi(methodCall: MethodCall, result: MethodChannel.Result) {
|
||||
(methodCall.arguments as ArrayList<*>).let {
|
||||
require(it.size == 1 && (it[0] is String), lazyMessage = {
|
||||
"Missing or invalid arguments (Must have one argument 'String at 0'"
|
||||
})
|
||||
|
||||
val ssid = it[0].toString()
|
||||
HMG_Guest(mainActivity, ssid).connectToHMGGuestNetwork { status, message ->
|
||||
mainActivity.runOnUiThread {
|
||||
result.success(if (status) 1 else 0)
|
||||
|
||||
HMGUtils.popFlutterText(mainActivity, message)
|
||||
Log.v(this.javaClass.simpleName, "$status | $message")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun enableWifiIfNot(methodCall: MethodCall, result: MethodChannel.Result) {
|
||||
val wm = mainActivity.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager?
|
||||
if (wm != null) {
|
||||
if (!wm.isWifiEnabled)
|
||||
wm.isWifiEnabled = true
|
||||
result.success(true)
|
||||
} else
|
||||
result.error("101", "Error while opening wifi, Please try to open wifi yourself and try again", "'WifiManager' service failed");
|
||||
}
|
||||
|
||||
|
||||
private fun registerHmgGeofences(methodCall: MethodCall, result: MethodChannel.Result) {
|
||||
|
||||
channel.invokeMethod("getGeoZones", null, object : MethodChannel.Result {
|
||||
override fun success(result: Any?) {
|
||||
if (result is String) {
|
||||
val geoZones = GeoZoneModel().listFrom(result)
|
||||
HMG_Geofence.shared(mainActivity).register() { s, e -> }
|
||||
}
|
||||
}
|
||||
|
||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {}
|
||||
override fun notImplemented() {}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private fun unRegisterHmgGeofences(methodCall: MethodCall, result: MethodChannel.Result) {
|
||||
HMG_Geofence.shared(mainActivity).unRegisterAll { status, exception ->
|
||||
if (status)
|
||||
result.success(true)
|
||||
else
|
||||
result.error("101", exception?.localizedMessage, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDrawOverAppsPermissionAllowed(methodCall: MethodCall, result: MethodChannel.Result) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (
|
||||
Settings.canDrawOverlays(mainActivity)
|
||||
) {
|
||||
result.success(true)
|
||||
} else {
|
||||
result.success(false)
|
||||
}
|
||||
} else {
|
||||
result.success(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun askDrawOverAppsPermission(methodCall: MethodCall, result: MethodChannel.Result) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
|
||||
val uri = Uri.parse("package:" + mainActivity.getPackageName())
|
||||
intent.setData(uri)
|
||||
startActivityForResult(mainActivity, intent, 102, null)
|
||||
result.success(true)
|
||||
} else {
|
||||
result.success(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getIntentData(methodCall: MethodCall, result: MethodChannel.Result) {
|
||||
|
||||
val bundle: Bundle? = getIntent("").extras
|
||||
if (bundle != null) {
|
||||
val message = bundle.getString("notification") // 1
|
||||
System.out.println("BundleExtra:" + message)
|
||||
Toast.makeText(this.mainActivity, message + "", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(this.mainActivity, "Bundle Null", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
result.success(true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.cloud.hmg_patient_app.whatsapp;
|
||||
|
||||
import static java.sql.DriverManager.println;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.util.Base64;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AppSignatureRetriever {
|
||||
|
||||
private static final String HASH_TYPE = "SHA-256";
|
||||
public static final int NUM_HASHED_BYTES = 9;
|
||||
public static final int NUM_BASE64_CHAR = 11;
|
||||
|
||||
|
||||
public void logSignatures(Context context) {
|
||||
Collection<String> appSignatures = getAppSignatures(context);
|
||||
appSignatures.forEach(signature -> println("Signature: " + signature));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the app signatures for the current package.
|
||||
*
|
||||
* @return signatures for current app
|
||||
*/
|
||||
public Collection<String> getAppSignatures(Context context) {
|
||||
try {
|
||||
// Get all package signatures for the current package
|
||||
String packageName = context.getPackageName();
|
||||
println("Package name: " + packageName);
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
Signature[] signatures = packageManager.getPackageInfo(packageName,
|
||||
PackageManager.GET_SIGNATURES).signatures;
|
||||
|
||||
// For each signature create a compatible hash
|
||||
Collection<String> appCodes = Arrays.stream(signatures)
|
||||
.map(signature -> hash(packageName, signature.toCharsString()))
|
||||
.collect(Collectors.toList());
|
||||
return appCodes;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
println("Unable to find package to obtain hash.");
|
||||
throw new RuntimeException("Unable to find package to obtain hash.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String hash(String packageName, String signature) {
|
||||
String appInfo = packageName + " " + signature;
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest.getInstance(HASH_TYPE);
|
||||
messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8));
|
||||
byte[] hashSignature = messageDigest.digest();
|
||||
|
||||
// truncated into NUM_HASHED_BYTES
|
||||
hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES);
|
||||
// encode into Base64
|
||||
String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP);
|
||||
base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR);
|
||||
|
||||
println(String.format("pkg: %s -- hash: %s", packageName, base64Hash));
|
||||
return base64Hash;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Unable to generate hash for application", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
|
||||
package com.cloud.hmg_patient_app.whatsapp
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.whatsapp.otp.android.sdk.WhatsAppOtpHandler
|
||||
import com.whatsapp.otp.android.sdk.WhatsAppOtpIncomingIntentHandler
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
object WhatsApp {
|
||||
val whatsAppOtpHandler = WhatsAppOtpHandler()
|
||||
inline fun handleOTP ( intent: Intent, crossinline validateOTP:(code: String )-> Unit) =
|
||||
WhatsAppOtpIncomingIntentHandler().processOtpCode(
|
||||
intent,
|
||||
// call your function to validate
|
||||
{code -> validateOTP(code) },
|
||||
{error,exception->
|
||||
println("the error is ${error.name}")
|
||||
println("the exception stacktrace is ${exception.message}")
|
||||
println("the exception is cause ${exception.cause}")
|
||||
})
|
||||
|
||||
|
||||
fun performHandShake(context : WeakReference<Context>) = whatsAppOtpHandler.sendOtpIntentToWhatsApp(context.get()!!)
|
||||
|
||||
|
||||
|
||||
fun isWhatsAppInstalled(context : WeakReference<Context>) : Boolean = whatsAppOtpHandler.isWhatsAppInstalled(context.get()!!)
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.cloud.hmg_patient_app.whatsapp
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.cloud.hmg_patient_app.whatsapp.WhatsApp
|
||||
import com.cloud.hmg_patient_app.whatsapp.WhatsAppOtpPlatformBridge
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||
|
||||
class WhatsAppCodeActivity : FlutterFragmentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
WhatsApp.handleOTP(intent){code ->
|
||||
WhatsAppOtpPlatformBridge.result?.success(code);
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.cloud.hmg_patient_app.whatsapp
|
||||
|
||||
import com.ejada.hmg.MainActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class WhatsAppOtpPlatformBridge(
|
||||
private var flutterEngine: FlutterEngine,
|
||||
private var mainActivity: MainActivity
|
||||
) {
|
||||
|
||||
|
||||
private lateinit var channel: MethodChannel
|
||||
|
||||
companion object {
|
||||
private const val CHANNEL = "whats_app_otp"
|
||||
var result: MethodChannel.Result? = null
|
||||
}
|
||||
|
||||
fun invoke() {
|
||||
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
|
||||
channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
|
||||
when (call.method) {
|
||||
"isWhatsAppInstalled" -> {
|
||||
val isAppInstalled =
|
||||
WhatsApp.isWhatsAppInstalled(WeakReference(mainActivity))
|
||||
result.success(isAppInstalled)
|
||||
}
|
||||
|
||||
"performHandShake" -> {
|
||||
WhatsApp.performHandShake(WeakReference(mainActivity))
|
||||
}
|
||||
|
||||
|
||||
"startListening" -> {
|
||||
WhatsAppOtpPlatformBridge.result = result
|
||||
}
|
||||
|
||||
else -> {
|
||||
result.notImplemented()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
|
After Width: | Height: | Size: 1021 B |
|
After Width: | Height: | Size: 180 B |
|
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.cloud.diplomaticquarterapp.whatsapp.WhatsAppCodeActivity">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_gravity="center_horizontal">
|
||||
<FrameLayout
|
||||
android:id="@+id/publisher_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FF9800" />
|
||||
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_gravity="center_horizontal">
|
||||
<FrameLayout
|
||||
android:id="@+id/subscriber_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#3F51B5" />
|
||||
|
||||
<TextView
|
||||
android:text="Remote"
|
||||
android:textColor="#FFFFFF"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:keep="@drawable/*,@raw/slow_spring_board" />
|
||||
@ -0,0 +1,23 @@
|
||||
<resources>
|
||||
<string name="app_name">HMG Patient App</string>
|
||||
|
||||
<string name="geofence_unknown_error">
|
||||
Unknown error: the Geofence service is not available now.
|
||||
</string>
|
||||
<string name="geofence_not_available">
|
||||
Geofence service is not available now. Go to Settings>Location>Mode and choose High accuracy.
|
||||
</string>
|
||||
<string name="geofence_too_many_geofences">
|
||||
Your app has registered too many geofences.
|
||||
</string>
|
||||
<string name="geofence_too_many_pending_intents">
|
||||
You have provided too many PendingIntents to the addGeofences() call.
|
||||
</string>
|
||||
<string name="GEOFENCE_INSUFFICIENT_LOCATION_PERMISSION">
|
||||
App do not have permission to access location service.
|
||||
</string>
|
||||
<string name="GEOFENCE_REQUEST_TOO_FREQUENT">
|
||||
Geofence requests happened too frequently.
|
||||
</string>
|
||||
<string name="mapbox_access_token" translatable="false">sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg</string>
|
||||
</resources>
|
||||
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting -->
|
||||
<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>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">@android:color/white</item>
|
||||
</style>
|
||||
</resources>
|
||||
@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.ejada.hmg">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
@ -0,0 +1,113 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url "https://developer.huawei.com/repo/" }
|
||||
maven {
|
||||
url = uri("https://api.mapbox.com/downloads/v2/releases/maven")
|
||||
credentials {
|
||||
username = "mapbox"
|
||||
password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
|
||||
if (password == null || password == "") {
|
||||
throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the environment variables.")
|
||||
}
|
||||
}
|
||||
authentication {
|
||||
basic(BasicAuthentication)
|
||||
}
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.1.0'
|
||||
classpath 'com.huawei.agconnect:agcp:1.9.1.304'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url 'https://developer.huawei.com/repo/'
|
||||
}
|
||||
maven {
|
||||
url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local"
|
||||
}
|
||||
maven {
|
||||
url 'https://api.mapbox.com/downloads/v2/releases/maven'
|
||||
|
||||
credentials {
|
||||
username = 'mapbox'
|
||||
password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
|
||||
if (password == null || password == "") {
|
||||
throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the environment variables.")
|
||||
}
|
||||
}
|
||||
authentication {
|
||||
basic(BasicAuthentication)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exclude old BouncyCastle globally to avoid duplicate classes
|
||||
configurations.all {
|
||||
exclude group: 'org.bouncycastle', module: 'bcprov-jdk16'
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||
kotlinOptions {
|
||||
jvmTarget = "21"
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
afterEvaluate { project ->
|
||||
if (project.hasProperty('android')) {
|
||||
project.android {
|
||||
if (namespace == null) {
|
||||
namespace project.group
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
if (buildConfig == null) {
|
||||
buildConfig true
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
targetCompatibility JavaVersion.VERSION_21
|
||||
}
|
||||
}
|
||||
}
|
||||
// Force Java 17 for all JavaCompile tasks in all subprojects (including plugins)
|
||||
project.tasks.withType(JavaCompile).configureEach {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
// Force Kotlin JVM target for all subprojects
|
||||
project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||
kotlinOptions {
|
||||
jvmTarget = "21"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rootProject.buildDir = '../build'
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
tasks.register("clean", Delete) {
|
||||
delete rootProject.layout.buildDirectory
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "815750722565",
|
||||
"firebase_url": "https://api-project-815750722565.firebaseio.com",
|
||||
"project_id": "api-project-815750722565",
|
||||
"storage_bucket": "api-project-815750722565.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:815750722565:android:62281cd3e5df4063",
|
||||
"android_client_info": {
|
||||
"package_name": "com.ejada.hmg"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "815750722565-3a0gc7neins0eoahdrimrfksk0sqice8.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDZDeWcBlRE3YfJWYt_DCiToVnANfaj8qg"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "815750722565-3a0gc7neins0eoahdrimrfksk0sqice8.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "815750722565-0cq9366orvsk5ipivq6lijcj56u03fr7.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.void.demo"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
org.gradle.jvmargs=-Xmx4096m
|
||||
kotlin.daemon.jvmargs=-Xmx4096m
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.suppressUnsupportedCompileSdk=33
|
||||
MAPBOX_USER_NAME = "mapbox"
|
||||
MAPBOX_DOWNLOADS_TOKEN="sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
|
||||
@ -0,0 +1,6 @@
|
||||
#Wed Jul 02 15:26:33 AST 2025
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@ -0,0 +1,203 @@
|
||||
//pluginManagement {
|
||||
// def flutterSdkPath = {
|
||||
// def properties = new Properties()
|
||||
// file("local.properties").withInputStream { properties.load(it) }
|
||||
// def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
// assert flutterSdkPath != null : "flutter.sdk not set in local.properties"
|
||||
// return flutterSdkPath
|
||||
// }()
|
||||
//
|
||||
// includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
//
|
||||
// repositories {
|
||||
// google()
|
||||
// mavenCentral()
|
||||
// gradlePluginPortal()
|
||||
// }
|
||||
//
|
||||
// plugins {
|
||||
// id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
// id "com.android.application" version "8.1.0" apply false
|
||||
// id "org.jetbrains.kotlin.android" version "2.1.10" apply false
|
||||
// id "com.google.gms.google-services" version "4.4.2" apply false
|
||||
// id "com.google.firebase.crashlytics" version "3.0.3" apply false
|
||||
//
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//dependencyResolutionManagement {
|
||||
// repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
//
|
||||
// repositories {
|
||||
// google()
|
||||
// mavenCentral()
|
||||
// flatDir {
|
||||
// dirs 'libs'
|
||||
// }
|
||||
// maven {
|
||||
// url 'https://developer.huawei.com/repo/'
|
||||
// }
|
||||
// maven {
|
||||
// url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local"
|
||||
// }
|
||||
// maven {
|
||||
// url 'https://api.mapbox.com/downloads/v2/releases/maven'
|
||||
//
|
||||
// credentials {
|
||||
// username = 'mapbox'
|
||||
// password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
|
||||
// if (password == null || password == "") {
|
||||
// throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the environment variables.")
|
||||
// }
|
||||
// }
|
||||
// authentication {
|
||||
// basic(BasicAuthentication)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//// Load local properties
|
||||
//def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||
//def properties = new Properties()
|
||||
//assert localPropertiesFile.exists()
|
||||
//localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||
//
|
||||
//// Get Flutter SDK path
|
||||
//def flutterSdkPath = properties.getProperty('flutter.sdk')
|
||||
//assert flutterSdkPath != null : "flutter.sdk not set in local.properties"
|
||||
//
|
||||
//// Get vital-sign-engine path
|
||||
//def vitalSignEnginePath = properties.getProperty('vital.sign.engine.path')
|
||||
//assert vitalSignEnginePath != null : "vital.sign.engine.path not set in local.properties"
|
||||
//
|
||||
//// Include modules
|
||||
//include ':app'
|
||||
////project(':vital-sign-engine').projectDir = file(vitalSignEnginePath)
|
||||
//// ':vital-sign-engine'
|
||||
|
||||
|
||||
//include ':app'
|
||||
//
|
||||
//def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
|
||||
//
|
||||
//def plugins = new Properties()
|
||||
//def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
|
||||
//if (pluginsFile.exists()) {
|
||||
// pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
|
||||
//}
|
||||
//
|
||||
//plugins.each { name, path ->
|
||||
// def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
|
||||
// include ":$name"
|
||||
// project(":$name").projectDir = pluginDirectory
|
||||
//}
|
||||
|
||||
//// Load local properties
|
||||
//def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||
//def properties = new Properties()
|
||||
//assert localPropertiesFile.exists()
|
||||
//localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||
//
|
||||
//// Get Flutter SDK path
|
||||
//def flutterSdkPath = properties.getProperty('flutter.sdk')
|
||||
//assert flutterSdkPath != null : "flutter.sdk not set in local.properties"
|
||||
//
|
||||
//// Get vital-sign-engine path
|
||||
//def vitalSignEnginePath = properties.getProperty('vital.sign.engine.path')
|
||||
//assert vitalSignEnginePath != null : "vital.sign.engine.path not set in local.properties"
|
||||
//
|
||||
|
||||
pluginManagement {
|
||||
def flutterSdkPath = {
|
||||
def properties = new Properties()
|
||||
file("local.properties").withInputStream { properties.load(it) }
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
return flutterSdkPath
|
||||
}()
|
||||
|
||||
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
// Get vital-sign-engine path
|
||||
// def vitalSignEngine = {
|
||||
// def properties = new Properties()
|
||||
// file("local.properties").withInputStream { properties.load(it) }
|
||||
// def vitalSignEnginePath = properties.getProperty("vital.sign.engine.path")
|
||||
// assert vitalSignEnginePath != null, "vital.sign.engine.path not set in local.properties"
|
||||
// return vitalSignEnginePath
|
||||
// }()
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://developer.huawei.com/repo/' }
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
resolutionStrategy {
|
||||
eachPlugin {
|
||||
if (requested.id.id == "com.huawei.agconnect") {
|
||||
useModule("com.huawei.agconnect:agcp:1.9.1.304")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
maven {
|
||||
url 'https://developer.huawei.com/repo/'
|
||||
}
|
||||
maven {
|
||||
url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local"
|
||||
}
|
||||
maven {
|
||||
url 'https://api.mapbox.com/downloads/v2/releases/maven'
|
||||
credentials {
|
||||
username = 'mapbox'
|
||||
password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
|
||||
if (password == null || password == "") {
|
||||
throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the environment variables.")
|
||||
}
|
||||
}
|
||||
authentication {
|
||||
basic(BasicAuthentication)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version '8.11.0' apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.2.0" apply false
|
||||
id("com.google.gms.google-services") version "4.4.3" apply false
|
||||
id("com.google.firebase.crashlytics") version "3.0.4" apply false
|
||||
id('org.gradle.toolchains.foojay-resolver-convention') version '0.9.0' apply false
|
||||
id "com.huawei.agconnect" version "1.9.1.304" apply false
|
||||
|
||||
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
||||
//// Add the following to include vitalSignEngine as a module
|
||||
//def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||
//def properties = new Properties()
|
||||
//assert localPropertiesFile.exists()
|
||||
//localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||
//def vitalSignEnginePath = properties.getProperty('vital.sign.engine.path')
|
||||
//assert vitalSignEnginePath != null : "vital.sign.engine.path not set in local.properties"
|
||||
//
|
||||
//include ':vitalSignEngine'
|
||||
//project(':vitalSignEngine').projectDir = file(vitalSignEnginePath)
|
||||
@ -0,0 +1 @@
|
||||
include ':app'
|
||||
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20.516" height="23.447" viewBox="0 0 20.516 23.447">
|
||||
<path id="doctor_information_icon" d="M10.258,11.724A5.862,5.862,0,1,0,4.4,5.862,5.861,5.861,0,0,0,10.258,11.724Zm-5.5,7.694a1.1,1.1,0,1,0,1.1-1.1A1.1,1.1,0,0,0,4.763,19.417Zm9.892-6.2V15.46a3.669,3.669,0,0,1,2.931,3.59v1.91a.735.735,0,0,1-.591.719l-1.475.293a.365.365,0,0,1-.43-.289l-.142-.719a.362.362,0,0,1,.289-.43l.884-.179V19.051a2.2,2.2,0,1,0-4.4.087V20.36l.884.179a.372.372,0,0,1,.289.43l-.142.719a.372.372,0,0,1-.43.289l-1.429-.192a.732.732,0,0,1-.632-.728V19.051a3.673,3.673,0,0,1,2.931-3.59V13.39c-.1.032-.2.05-.3.087a7.923,7.923,0,0,1-5.257,0A5.061,5.061,0,0,0,6.6,13.239v3.737a2.565,2.565,0,1,1-1.465,0V13.294A6.139,6.139,0,0,0,0,19.344V21.4a2.054,2.054,0,0,0,2.052,2.052H18.465A2.054,2.054,0,0,0,20.516,21.4V19.344A6.146,6.146,0,0,0,14.654,13.216Z" fill="#40acc9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 889 B |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="21.503" height="21.503" viewBox="0 0 21.503 21.503">
|
||||
<path id="doctor_qualification_icon" d="M9.4,5.491,6.494.653A1.344,1.344,0,0,0,5.341,0H.673A.672.672,0,0,0,.123,1.058L4.8,7.733A8.692,8.692,0,0,1,9.4,5.491ZM20.83,0H16.162a1.344,1.344,0,0,0-1.152.653l-2.9,4.839a8.694,8.694,0,0,1,4.6,2.242L21.38,1.058A.672.672,0,0,0,20.83,0ZM10.751,6.72a7.392,7.392,0,1,0,7.392,7.392A7.392,7.392,0,0,0,10.751,6.72Zm3.886,6.6-1.593,1.552.377,2.193a.482.482,0,0,1-.7.508l-1.97-1.035-1.97,1.035a.482.482,0,0,1-.7-.508l.377-2.193L6.866,13.324a.482.482,0,0,1,.267-.823l2.2-.321.984-2a.483.483,0,0,1,.866,0l.984,2,2.2.321a.482.482,0,0,1,.267.823Z" transform="translate(0)" fill="#40acc9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 726 B |
|
After Width: | Height: | Size: 76 KiB |
@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="36.081" height="36.091" viewBox="0 0 36.081 36.091">
|
||||
<g id="call_down" transform="matrix(-0.719, 0.695, -0.695, -0.719, 111.538, -60.904)">
|
||||
<g id="Group_916" data-name="Group 916" transform="translate(109.442 -4.706)">
|
||||
<path id="Path_1199" data-name="Path 1199" d="M25.19,18.88l-3.54-3.59a2.341,2.341,0,0,0-3.92.9,2.4,2.4,0,0,1-2.782,1.539c-2.529-.641-5.943-3.975-6.575-6.667A2.33,2.33,0,0,1,9.892,8.238a2.4,2.4,0,0,0,.885-3.975L7.236.673a2.5,2.5,0,0,0-3.414,0L1.42,3.109c-2.4,2.564.253,9.36,6.2,15.386s12.644,8.847,15.172,6.283l2.4-2.436A2.587,2.587,0,0,0,25.19,18.88Z" transform="translate(-0.539 0)" fill="#fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 699 B |
@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="25.315" height="25.726" viewBox="0 0 25.315 25.726">
|
||||
<g id="call_down" transform="translate(-109.442 4.706)">
|
||||
<g id="Group_916" data-name="Group 916" transform="translate(109.442 -4.706)">
|
||||
<path id="Path_1199" data-name="Path 1199" d="M25.19,18.88l-3.54-3.59a2.341,2.341,0,0,0-3.92.9,2.4,2.4,0,0,1-2.782,1.539c-2.529-.641-5.943-3.975-6.575-6.667A2.33,2.33,0,0,1,9.892,8.238a2.4,2.4,0,0,0,.885-3.975L7.236.673a2.5,2.5,0,0,0-3.414,0L1.42,3.109c-2.4,2.564.253,9.36,6.2,15.386s12.644,8.847,15.172,6.283l2.4-2.436A2.587,2.587,0,0,0,25.19,18.88Z" transform="translate(-0.539 0)" fill="#fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 669 B |
@ -0,0 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="204.4" height="41.203" viewBox="0 0 204.4 41.203">
|
||||
<g id="Group_417" data-name="Group 417" transform="translate(-2052 119)">
|
||||
<g id="Group_22" data-name="Group 22" transform="translate(2052 -119)">
|
||||
<path id="Path_19" data-name="Path 19" d="M500.8,34.444s1.442-.01,2.454-.01l7.69.036c.917,0,1.682-.976,1.725-2.385l.007-6.426c0-1.369.614-2.441,1.564-2.5l2.359-.02c.95.059,1.6,1.141,1.6,2.5L518.2,32.1c.043,1.409.683,2.329,1.607,2.329l10.352.026.02-7.944c0-1.366-.656-2.428-1.61-2.487l-4.16-.02c-.92,0-1.643-.973-1.686-2.382l-.016-2.148c.046-1.409.772-2.379,1.7-2.379l4.183.013c.95-.063,1.57-1.184,1.57-2.547l.01-9.913a4.218,4.218,0,0,1-3.2,2l-7.03,0c-.917,0-1.682,1-1.725,2.408v6.367c-.043,1.409-.762,2.4-1.682,2.4l-2.128-.016c-.924,0-1.659-.963-1.7-2.365l.007-6.436c-.043-1.409-.772-2.359-1.692-2.359l-10.21,0,0,7.917c0,1.369.64,2.461,1.593,2.527l4.183-.016c.947.063,1.616,1.191,1.616,2.55l-.013,1.834c0,1.366-.647,2.461-1.6,2.524l-4.19-.01c-.953.066-1.593,1.148-1.593,2.51Zm35.16-30.35V37.208a4.212,4.212,0,0,1-4.256,4H499.026a4.192,4.192,0,0,1-4.236-4.008l0-33.174A4.213,4.213,0,0,1,499.032.01l32.652.013A4.284,4.284,0,0,1,535.964,4.094Z" transform="translate(-331.564 -0.01)" fill="#ed1c2b"/>
|
||||
<path id="Path_20" data-name="Path 20" d="M111.074,102.986h-.426v-.792a1.911,1.911,0,0,1-1.739.93c-1.923,0-1.927-1.3-1.927-1.834V98.569h.429v2.705c0,.871.3,1.455,1.511,1.455a1.559,1.559,0,0,0,1.725-1.583V98.572h.426Zm-7.221-4.552a2.347,2.347,0,1,1-2.365,2.349A2.273,2.273,0,0,1,103.852,98.433Zm0,4.292a1.948,1.948,0,1,0-1.94-1.946A1.859,1.859,0,0,0,103.852,102.725Zm-5.13-4.157h.429v.924a1.762,1.762,0,0,1,1.7-1.059.9.9,0,0,1,.313.056l.02.459a1.066,1.066,0,0,0-.455-.063,1.581,1.581,0,0,0-1.58,1.715v2.388h-.429Zm-1.415.871c-.023-.122-.023-.868-.023-.868h.429v4.176c0,1.009-.346,2.115-2.3,2.115-1.287,0-2.029-.406-2.167-1.491l.426-.033c.092.7.544,1.128,1.745,1.128,1.59,0,1.867-.9,1.867-1.7v-.8a2.287,2.287,0,1,1-1.917-3.533A2.011,2.011,0,0,1,97.307,99.44Zm-3.8,1.2a1.712,1.712,0,0,0,1.9,1.9,1.737,1.737,0,0,0,1.877-1.907,1.889,1.889,0,0,0-3.774.01ZM89.9,96.85h.422v6.139H89.9Zm-5.044,3.124c.142-1.151.7-1.541,1.956-1.541,1.207,0,1.923.3,1.923,1.306v2.444c0,.333.007.488.251.488a1.06,1.06,0,0,0,.356-.066l.033.389a1.3,1.3,0,0,1-.482.076.431.431,0,0,1-.468-.277,1.126,1.126,0,0,1-.059-.31c0-.089-.007-.185-.007-.294a2.191,2.191,0,0,1-1.96.934,3.059,3.059,0,0,1-.416-.023,1.824,1.824,0,0,1-.574-.148,1.186,1.186,0,0,1-.736-1.188c0-.92.746-1.23,1.587-1.283l1.445-.1c.422-.033.607-.079.607-.59,0-.564-.294-.96-1.511-.96-1.079,0-1.405.35-1.514,1.118Zm3.454.61a1.248,1.248,0,0,1-.65.195l-1.4.1c-.693.053-1.161.254-1.161.884,0,.854.815.957,1.32.957.828,0,1.89-.393,1.89-1.4v-.736ZM83.663,100a1.623,1.623,0,0,0-1.732-1.165,1.946,1.946,0,0,0,0,3.893,1.692,1.692,0,0,0,1.785-1.3l.432-.023a2.077,2.077,0,0,1-2.217,1.719,2.346,2.346,0,1,1,0-4.691,1.964,1.964,0,0,1,2.154,1.537Zm-5.321-1.428h.426v4.417h-.426Zm-1.422,2.253a1.794,1.794,0,0,0-1.861-1.989,1.949,1.949,0,1,0,1.861,1.989Zm-.053,1.313a1.918,1.918,0,0,1-1.821.993,2.348,2.348,0,0,1,0-4.691,2.033,2.033,0,0,1,1.811.986l.013-2.567H77.3V103h-.429v-.861Zm-4.988-1.64a1.77,1.77,0,0,0-1.87-1.663,1.808,1.808,0,0,0-1.864,1.663Zm-3.738.4a1.8,1.8,0,0,0,1.946,1.834,1.663,1.663,0,0,0,1.735-1.224l.432-.02a2.1,2.1,0,0,1-2.21,1.643,2.192,2.192,0,0,1-2.332-2.379,2.324,2.324,0,1,1,4.645.119ZM60,98.569h.426v.676a1.89,1.89,0,0,1,1.583-.812,1.466,1.466,0,0,1,1.59.97,1.659,1.659,0,0,1,1.593-.97c1.2,0,1.748.574,1.748,1.57v2.986h-.426v-2.857a1.191,1.191,0,0,0-1.313-1.3,1.342,1.342,0,0,0-1.517,1.445v2.712h-.426v-2.933c0-.749-.376-1.224-1.316-1.224a1.414,1.414,0,0,0-1.517,1.527v2.626H60Zm52.086,0h.429v.858a1.914,1.914,0,0,1,1.821-.993,2.35,2.35,0,0,1,0,4.694,2.019,2.019,0,0,1-1.808-.986l-.016,2.57h-.429V98.569Zm.379,2.167a1.791,1.791,0,0,0,1.861,1.989,1.949,1.949,0,1,0-1.861-1.989ZM78.25,97.266a.307.307,0,1,1,.307.323A.317.317,0,0,1,78.25,97.266Z" transform="translate(-40.207 -64.904)" fill="#5f6765"/>
|
||||
<path id="Path_21" data-name="Path 21" d="M248.783,104.229a.309.309,0,1,1,.307.323A.316.316,0,0,1,248.783,104.229Zm-.841,0a.319.319,0,0,1,.31-.323.324.324,0,0,1,0,.647A.319.319,0,0,1,247.941,104.229Zm45.921-.01a.314.314,0,0,1,.3-.323.323.323,0,0,1,0,.647A.308.308,0,0,1,293.862,104.219Zm-24.356-7.007a.3.3,0,1,1,.307.323A.31.31,0,0,1,269.506,97.212Zm-.841,0a.307.307,0,1,1,.31.323A.313.313,0,0,1,268.665,97.212Zm-25.451.013a.307.307,0,1,1,.307.323A.317.317,0,0,1,243.214,97.225Zm-.838,0a.309.309,0,1,1,.307.323A.317.317,0,0,1,242.376,97.225Zm66.173-.383h.429v6.136h-.429Zm-44.631.056h.426v6.139h-.426Zm-1.725,4.289v-4.3h.429V101.2c0,.531-.016,1.834-1.94,1.834h-6.9a1.8,1.8,0,0,1-1.706-.739c-.224.442-.716.821-1.755.821s-1.524-.376-1.748-.821a1.793,1.793,0,0,1-1.706.739h-1.28c-.492,0-.558-.373-.551-.887a2.3,2.3,0,0,1-1.989.967,2.346,2.346,0,1,1,2.375-2.3l.007,1.31c0,.333.007.515.251.515l1.2,0c1.214,0,1.5-.584,1.5-1.455V98.565h.426v2.705c0,.871.327,1.452,1.531,1.452s1.5-.581,1.5-1.452V98.565h.426v2.689c.013.835.32,1.389,1.508,1.389h1.353V96.889h.426v2.527a1.911,1.911,0,0,1,1.739-.93c1.923,0,1.923,1.3,1.923,1.837v2.322h1.471C261.9,102.642,262.193,102.058,262.193,101.187Zm-21.021-.369a1.915,1.915,0,1,0,1.867-1.989A1.878,1.878,0,0,0,241.172,100.818Zm17.616-.482c0-.874-.3-1.455-1.5-1.455a1.561,1.561,0,0,0-1.732,1.583v2.177h3.236Zm12.948.442,0,1.346c0,.336.007.515.251.515h2.454v-2.448c0-.534.016-1.834,1.943-1.834a3.592,3.592,0,0,1,.706.066l-.221.366a3.064,3.064,0,0,0-.468-.036c-1.2,0-1.531.584-1.531,1.455v2.431h3.207v.4H271.9a.436.436,0,0,1-.462-.264,1.8,1.8,0,0,1-.086-.591,2.393,2.393,0,0,1-1.986.937,2.344,2.344,0,1,1,2.372-2.339Zm-4.252.036a1.916,1.916,0,1,0,1.87-1.989A1.889,1.889,0,0,0,267.484,100.815Zm36.482.541c.046.779.376,1.287,1.5,1.287,1.178-.01,1.494-.59,1.494-1.455v-4.4h.426V101.2c0,.528-.017,1.824-1.923,1.834a1.851,1.851,0,0,1-1.656-.666,2.4,2.4,0,0,1-4.414-.007,1.864,1.864,0,0,1-1.666.67h-5.094a1.849,1.849,0,0,1-1.663-.673,2.4,2.4,0,0,1-4.417.01,1.849,1.849,0,0,1-1.659.663h-1.465c-.073.92-.528,1.821-2.283,1.821-1.29,0-2.026-.4-2.167-1.488l.422-.036c.092.693.541,1.125,1.745,1.125,1.4,0,1.758-.716,1.851-1.422h-1.758a2.217,2.217,0,0,1-2.392-2.329,2.3,2.3,0,0,1,4.592.033v1.9H284.9c1.066,0,1.415-.439,1.484-1.128.013-.132.02-.247.03-.34a2.237,2.237,0,0,1,2.345-2.032,2.265,2.265,0,0,1,2.359,2.273c.043.739.393,1.227,1.5,1.227h3.269v-2.454c0-.871-.284-1.452-1.5-1.452a1.4,1.4,0,0,0-1.257.475l-.373-.264a1.928,1.928,0,0,1,1.613-.607c1.923,0,1.943,1.3,1.943,1.834v2.468h1.419c1.125,0,1.438-.5,1.5-1.257a2.367,2.367,0,0,1,4.721-.092Zm-20.948-.673a1.7,1.7,0,0,0-1.884-1.828,1.736,1.736,0,0,0-1.857,1.834,1.825,1.825,0,0,0,2.019,1.946h1.722Zm3.81.884a1.937,1.937,0,0,0,3.873-.082c0-.059,0-.112,0-.162a1.938,1.938,0,0,0-3.853-.1A1.689,1.689,0,0,0,286.829,101.567Zm16.712-.059c0-.063,0-.106-.007-.148a1.935,1.935,0,0,0-3.866.076,1.937,1.937,0,1,0,3.873.073Zm-51.733,2.722a.307.307,0,1,1,.307.323A.316.316,0,0,1,251.808,104.229Z" transform="translate(-161.322 -64.863)" fill="#5f6765"/>
|
||||
<path id="Path_22" data-name="Path 22" d="M29.1,16.1a.705.705,0,0,1-.709.7.717.717,0,0,1-.722-.7.7.7,0,0,1,.722-.666A.683.683,0,0,1,29.1,16.1ZM70.27,12.105V7.817a.576.576,0,0,1,.64-.528.568.568,0,0,1,.64.548v4.077c0,1.7.059,2.887-.871,3.761a3.722,3.722,0,0,1-2.652.9,3.919,3.919,0,0,1-2.689-.93,3.387,3.387,0,0,1-.845-2.758V7.843a.577.577,0,0,1,.653-.558.583.583,0,0,1,.66.587l0,.878,0,4.269a2.346,2.346,0,0,0,.551,1.927,2.482,2.482,0,0,0,1.712.574,2.319,2.319,0,0,0,1.6-.558C70.326,14.345,70.27,13.649,70.27,12.105ZM5.892,16.1a.708.708,0,0,1-.713.7.72.72,0,0,1-.726-.7.7.7,0,0,1,.726-.666A.686.686,0,0,1,5.892,16.1Zm12.711,0a.708.708,0,0,1-.713.7.72.72,0,0,1-.726-.7.7.7,0,0,1,.726-.666A.686.686,0,0,1,18.6,16.1Zm1.953,0a.708.708,0,0,1-.709.7.715.715,0,0,1-.722-.7.7.7,0,0,1,.722-.666A.685.685,0,0,1,20.555,16.1ZM35.8,7.78l.267-.132a4.573,4.573,0,0,1,1.194-.333,6.041,6.041,0,0,1,.815-.056c2.468,0,4.463,1.772,4.463,4.816a6.088,6.088,0,0,1-.115,1.2h7.67a2.488,2.488,0,0,0,1.719-.574,2.349,2.349,0,0,0,.554-1.927V4.508a.661.661,0,0,1,1.31-.026V10.64a3.385,3.385,0,0,1-.848,2.764,3.884,3.884,0,0,1-2.689.927H42.905l-11.843-.007a3.613,3.613,0,0,1-2.4-.894,3.078,3.078,0,0,1-.228-.244,3.177,3.177,0,0,1-.231.244,3.722,3.722,0,0,1-2.649.9H21.647a3.891,3.891,0,0,1-2.6-.927c-.271-.129-.343-.049-.429.026a3.707,3.707,0,0,1-2.642.9h-3.8a3.845,3.845,0,0,1-2.56-.93c-.267-.129-.343-.049-.426.026a3.583,3.583,0,0,1-2.4.9l-3.256.007A3.9,3.9,0,0,1,.844,13.4,3.4,3.4,0,0,1,0,10.644V7.833a.586.586,0,0,1,.656-.561.578.578,0,0,1,.653.587v2.92a2.341,2.341,0,0,0,.554,1.927,2.488,2.488,0,0,0,1.719.574l3.21-.007a2.2,2.2,0,0,0,1.4-.554,2.056,2.056,0,0,0,.587-1.6l0-.485V7.827a.583.583,0,0,1,.653-.561.578.578,0,0,1,.653.587l0,.878,0,2.042a2.35,2.35,0,0,0,.551,1.927,2.372,2.372,0,0,0,1.547.567l3.843.007a2.268,2.268,0,0,0,1.6-.561,2.1,2.1,0,0,0,.594-1.673V7.83a.659.659,0,0,1,1.306.026v2.923a2.341,2.341,0,0,0,.554,1.927,2.436,2.436,0,0,0,1.61.571l3.919,0a2.282,2.282,0,0,0,1.6-.558,2.252,2.252,0,0,0,.59-1.87c-.01-.363,0-.755,0-1.181V7.823A.648.648,0,0,1,29.066,7.8V9.865c0,1.544-.059,2.24.6,2.857a2.222,2.222,0,0,0,1.392.554l10.075,0a5.085,5.085,0,0,0,.162-1.31A3.313,3.313,0,0,0,38,8.341l-.211,0a5.337,5.337,0,0,0-.815.086c-.475.086-.4.073-.851.181C35.661,8.76,35.483,8.057,35.8,7.78ZM68.739,4.33a.7.7,0,0,1-.713.689A.719.719,0,0,1,67.3,4.33a.7.7,0,0,1,.726-.67A.687.687,0,0,1,68.739,4.33ZM101.725,16.1a.7.7,0,0,1-.706.7.721.721,0,0,1-.729-.7.7.7,0,0,1,.729-.666A.682.682,0,0,1,101.725,16.1Zm1.95,0a.708.708,0,0,1-.709.7.718.718,0,0,1-.726-.7.7.7,0,0,1,.726-.666A.685.685,0,0,1,103.674,16.1Zm35.447-1.775.023-1.069,5.209,0c2.029-.059,2.563-.9,2.6-2.359-.076-1.468-.571-2.448-2.6-2.51a5.939,5.939,0,0,0-.874.1,7.663,7.663,0,0,0-.848.181c-.468.145-.65-.554-.336-.831l.264-.129a4.575,4.575,0,0,1,1.2-.336,6.162,6.162,0,0,1,.818-.053c2.5.069,3.513,1.372,3.593,3.533-.056,2.131-1.092,3.4-3.593,3.467Zm-.911-.6a.708.708,0,0,1-.713.693.717.717,0,0,1-.722-.693.7.7,0,0,1,.722-.67A.685.685,0,0,1,138.21,13.725Zm-4.5-4.054c0,1.7.056,2.887-.878,3.764a3.71,3.71,0,0,1-2.642.9,3.894,3.894,0,0,1-2.689-.927l-.4.026a3.725,3.725,0,0,1-2.646.9,4.228,4.228,0,0,1-2.217-.571v.564l-7.126.01a3.891,3.891,0,0,1-2.685-.927c-.267-.129-.34-.049-.419.026a3.734,3.734,0,0,1-2.649.9l-4.628-.01a3.8,3.8,0,0,1-2.461-.924h-.383a3.9,3.9,0,0,1-2.689.927l-6.3-.007a3.679,3.679,0,0,1-.848,1.343,3.707,3.707,0,0,1-2.642.9,3.91,3.91,0,0,1-2.692-.93,2.479,2.479,0,0,1-.742-1.329l-7.686.02a3.9,3.9,0,0,1-2.689-.927,3.393,3.393,0,0,1-.845-2.764V4.478a.661.661,0,0,1,1.31.026v6.275a2.35,2.35,0,0,0,.551,1.927,2.494,2.494,0,0,0,1.719.574l7.479-.007.066-.389v-1.8a3.514,3.514,0,0,1,.841-2.863,3.91,3.91,0,0,1,2.692-.93,3.71,3.71,0,0,1,2.642.9c.825.775.874,1.791.874,3.19v1c0,.313,0,.614-.013.894l6.245,0a2.485,2.485,0,0,0,1.715-.574,2.015,2.015,0,0,0,.551-1.6v-.323l0-2.049,0-.881a.583.583,0,0,1,.653-.591.591.591,0,0,1,.66.561l-.007.91.007,1.91c0,.851-.02,1.527.554,2.065a2.344,2.344,0,0,0,1.445.564l4.668.007a2.3,2.3,0,0,0,1.6-.558c.653-.617.6-1.313.6-2.857L111.568,7.7V4.478a.661.661,0,0,1,1.31.026V9.667c0,.422,0,.812-.007,1.174a2.286,2.286,0,0,0,.571,1.864,2.482,2.482,0,0,0,1.712.574l5.776,0V7.817A.561.561,0,0,1,121.5,7.3c.508.026.709.231.732.525V8.6l0,2.685a1.891,1.891,0,0,0,.548,1.425,2.494,2.494,0,0,0,1.719.574,2.3,2.3,0,0,0,1.6-.558c.653-.617.594-1.313.594-2.857V7.817a.648.648,0,0,1,1.277.023v2.943a2.341,2.341,0,0,0,.551,1.923,2.485,2.485,0,0,0,1.715.574,2.294,2.294,0,0,0,1.6-.558c.653-.617.594-1.313.594-2.857V7.817a.581.581,0,0,1,.643-.528.573.573,0,0,1,.64.551V9.671ZM91.043,14.962c.6-.564.6-1.191.594-2.474V11.459c0-1.405-.016-2.019-.594-2.563a2.3,2.3,0,0,0-1.6-.561,2.47,2.47,0,0,0-1.712.574,2.332,2.332,0,0,0-.551,1.927v2.181a2.335,2.335,0,0,0,.551,1.927,2.47,2.47,0,0,0,1.712.574A2.278,2.278,0,0,0,91.043,14.962Zm-34.177-.637,0-8.943,0-.878a.661.661,0,0,1,1.31-.026v9.847Z" transform="translate(0 -2.456)" fill="#3d4543"/>
|
||||
<path id="Path_23" data-name="Path 23" d="M34.919,58.788V54.5a.649.649,0,0,1,1.28.023V58.6c0,1.7.053,2.883-.871,3.757a3.728,3.728,0,0,1-2.652.9,3.921,3.921,0,0,1-2.689-.934,3.392,3.392,0,0,1-.841-2.761V54.529a.661.661,0,0,1,1.31.033l0,.878,0,4.265a2.343,2.343,0,0,0,.551,1.927,2.491,2.491,0,0,0,1.715.574,2.3,2.3,0,0,0,1.6-.561C34.978,61.028,34.919,60.332,34.919,58.788Zm3.5,4.292V54.529a.581.581,0,0,1,.653-.558.574.574,0,0,1,.65.525V62.04h4.028v1.042H38.422Zm15.881,0V54.486a.574.574,0,0,1,.574-.525c.508.026.709.231.732.525v.779l.007,7.818H54.3Zm3.5,0,.96-8.458a.813.813,0,0,1,.9-.647.9.9,0,0,1,.838.574l2.642,6.862,2.56-6.875a.885.885,0,0,1,.779-.561.832.832,0,0,1,.947.643l1,8.462h-1.28l-.8-7.37-2.745,7.37H62.527L59.72,55.71l-.736,7.37Zm27.513-1.831L85.3,54.9v-.383a.595.595,0,0,1,1.184-.03v.775l0,7.815h-1.3l-4.572-7.261.026,7.261H79.447V54.608c0-.548.495-.633.808-.633.419.016.558.195.858.627Zm15.8,1.831V54.5a.672.672,0,0,1,1.31-.026v7.564h4.028V63.08Zm10.517,0V54.463a.674.674,0,0,1,1.31.026v3.3h4.447v-3.3a.673.673,0,0,1,1.31-.016V63.08h-1.31V58.827h-4.447V63.08Zm26.54,0v-8.6a.586.586,0,0,1,.653-.521.58.58,0,0,1,.653.515v8.6ZM.643,53.994h1.5c1.88,0,3.292.066,4.46,1.158a4.75,4.75,0,0,1,0,6.7C5.38,63,3.935,63.08,2.131,63.08H0V54.661A.591.591,0,0,1,.643,53.994ZM6.66,58.448a3.379,3.379,0,0,0-1.033-2.616c-.845-.792-1.808-.858-3.484-.858H1.3v7.112H2.507a4.271,4.271,0,0,0,3.177-.927A3.686,3.686,0,0,0,6.66,58.448Zm3.263-3.814c-.016-.445.261-.64.663-.64H12.08c1.3,0,2.3-.013,3.088.726a2.369,2.369,0,0,1,.755,1.811,2.137,2.137,0,0,1-.6,1.567,2.608,2.608,0,0,1-1.557.719,1.405,1.405,0,0,1,.828.369,4.073,4.073,0,0,1,.755,1.267l1.254,2.629H15.234l-1.118-2.369c-.673-1.405-.993-1.527-2.306-1.527H11.2v3.9H9.916V54.634Zm4.708,1.894a1.506,1.506,0,0,0-.426-1.089,2.693,2.693,0,0,0-2-.478H11.2V58.22h.452a3.566,3.566,0,0,0,2.494-.548A1.587,1.587,0,0,0,14.63,56.528ZM44.5,63.08l3-7.762.307-.729a.871.871,0,0,1,.874-.614.9.9,0,0,1,.937.614l.363.868,2.972,7.624H51.571L50.691,60.7h-4L45.8,63.08ZM50.324,59.7l-1.643-4.44-1.63,4.44ZM69.583,63.08l3-7.762.3-.729a.877.877,0,0,1,.878-.614.9.9,0,0,1,.937.614l.366.868,2.966,7.624H76.666L75.775,60.7h-4l-.884,2.379ZM75.409,59.7l-1.636-4.44L72.14,59.7Zm15.96,3.378,3-7.762.3-.729a.873.873,0,0,1,.874-.614.889.889,0,0,1,.934.614l.366.868,2.966,7.624H98.442L97.561,60.7h-4l-.891,2.379ZM97.2,59.7l-1.643-4.44L93.929,59.7ZM119.99,63.08l2.992-7.762.307-.729a.871.871,0,0,1,.874-.614.9.9,0,0,1,.94.614l.36.868,2.969,7.624H127.07l-.891-2.379h-3.995L121.3,63.08Zm5.832-3.378-1.649-4.44L122.55,59.7Zm4.054,3.378V54.865c0-.65.165-.9.643-.9h2.032a3.527,3.527,0,0,1,2.6.7,2.268,2.268,0,0,1,.759,1.752,1.943,1.943,0,0,1-1.554,2,1.975,1.975,0,0,1,1.861,2.035,2.4,2.4,0,0,1-.726,1.791c-.934.874-2.154.848-3.9.848h-1.719Zm4.724-6.644a1.369,1.369,0,0,0-.376-1.009,3.125,3.125,0,0,0-2.24-.492h-.845V58h.746a3.518,3.518,0,0,0,2.263-.508A1.3,1.3,0,0,0,134.6,56.436Zm.29,4.031a1.362,1.362,0,0,0-.439-1.023,3.64,3.64,0,0,0-2.514-.508h-.8V62.08h1.079a2.952,2.952,0,0,0,2.256-.574A1.5,1.5,0,0,0,134.892,60.467Zm6.938-6.505h2.679a3.531,3.531,0,0,1,2.6.7,2.282,2.282,0,0,1,.762,1.752,1.942,1.942,0,0,1-1.557,2,1.972,1.972,0,0,1,1.857,2.035,2.414,2.414,0,0,1-.722,1.791c-.937.874-2.151.848-3.9.848h-1.715V53.961Zm4.724,2.474a1.394,1.394,0,0,0-.373-1.009,3.108,3.108,0,0,0-2.237-.492H143.1V58h.742a3.547,3.547,0,0,0,2.273-.508A1.3,1.3,0,0,0,146.553,56.436Zm.3,4.031a1.35,1.35,0,0,0-.439-1.023,3.64,3.64,0,0,0-2.514-.508h-.8V62.08h1.079c1.138,0,1.732-.082,2.253-.574A1.49,1.49,0,0,0,146.85,60.467ZM21.386,56.244c0-1.435,1.224-2.441,2.982-2.464a5.629,5.629,0,0,1,2.085.442c.472.181.277,1.046-.244.878-.445-.106-.4-.106-.878-.2a3.156,3.156,0,0,0-.7-.079c-1.181,0-1.94.492-1.94,1.31,0,.864.858,1.138,1.818,1.6.858.412,2.761,1.079,2.761,2.873,0,1.5-1.174,2.666-3.183,2.666a4.922,4.922,0,0,1-2.982-.983l.63-.845a4.376,4.376,0,0,0,2.3.779c1.194,0,1.89-.67,1.89-1.5,0-1-1.234-1.488-2.283-1.969C22.406,58.187,21.386,57.584,21.386,56.244Z" transform="translate(0 -36.042)" fill="#3d4543"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="42.237" height="42.237" viewBox="0 0 42.237 42.237">
|
||||
<path id="alert_icon" d="M24.494,3.375A21.119,21.119,0,1,0,45.612,24.494,21.115,21.115,0,0,0,24.494,3.375ZM26.24,14.5l-.315,11.686a1.453,1.453,0,0,1-1.432,1.5h0a1.453,1.453,0,0,1-1.432-1.5L22.747,14.5a1.749,1.749,0,0,1,1.746-1.787h0A1.749,1.749,0,0,1,26.24,14.5ZM24.494,34.444a1.869,1.869,0,1,1,1.939-1.868A1.886,1.886,0,0,1,24.494,34.444Z" transform="translate(-3.375 -3.375)" fill="#fff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 501 B |
@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 17 17">
|
||||
<g id="Group_8364" data-name="Group 8364" transform="translate(-238 -335)">
|
||||
<circle id="Ellipse_4" data-name="Ellipse 4" cx="8.5" cy="8.5" r="8.5" transform="translate(238 335)" fill="#349745"/>
|
||||
<text id="Check" transform="translate(242 347)" fill="#fff" font-size="9" font-family="FontAwesome5Free-Solid, 'Font Awesome \35 Free'" letter-spacing="-0.06em"><tspan x="0" y="0">✓</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 503 B |
@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Artwork" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="165.52107px" height="105.9651px" viewBox="0 0 165.52107 105.9651"
|
||||
enable-background="new 0 0 165.52107 105.9651" xml:space="preserve">
|
||||
<g>
|
||||
<path id="XMLID_4_" d="M150.69807,0H14.82318c-0.5659,0-1.1328,0-1.69769,0.0033c-0.47751,0.0034-0.95391,0.0087-1.43031,0.0217
|
||||
c-1.039,0.0281-2.0869,0.0894-3.1129,0.2738c-1.0424,0.1876-2.0124,0.4936-2.9587,0.9754
|
||||
c-0.9303,0.4731-1.782,1.0919-2.52009,1.8303c-0.73841,0.7384-1.35721,1.5887-1.83021,2.52
|
||||
c-0.4819,0.9463-0.7881,1.9166-0.9744,2.9598c-0.18539,1.0263-0.2471,2.074-0.2751,3.1119
|
||||
c-0.0128,0.4764-0.01829,0.9528-0.0214,1.4291c-0.0033,0.5661-0.0022,1.1318-0.0022,1.6989V91.142
|
||||
c0,0.5671-0.0011,1.13181,0.0022,1.69901c0.00311,0.4763,0.0086,0.9527,0.0214,1.4291
|
||||
c0.028,1.03699,0.08971,2.08469,0.2751,3.11069c0.1863,1.0436,0.4925,2.0135,0.9744,2.9599
|
||||
c0.473,0.9313,1.0918,1.7827,1.83021,2.52c0.73809,0.7396,1.58979,1.3583,2.52009,1.8302
|
||||
c0.9463,0.4831,1.9163,0.7892,2.9587,0.9767c1.026,0.1832,2.0739,0.2456,3.1129,0.2737c0.4764,0.0108,0.9528,0.0172,1.43031,0.0194
|
||||
c0.56489,0.0044,1.13179,0.0044,1.69769,0.0044h135.87489c0.5649,0,1.13181,0,1.69659-0.0044
|
||||
c0.47641-0.0022,0.95282-0.0086,1.4314-0.0194c1.0368-0.0281,2.0845-0.0905,3.11301-0.2737
|
||||
c1.041-0.1875,2.0112-0.4936,2.9576-0.9767c0.9313-0.4719,1.7805-1.0906,2.52011-1.8302c0.7372-0.7373,1.35599-1.5887,1.8302-2.52
|
||||
c0.48299-0.9464,0.78889-1.9163,0.97429-2.9599c0.1855-1.026,0.2457-2.0737,0.2738-3.11069
|
||||
c0.013-0.4764,0.01941-0.9528,0.02161-1.4291c0.00439-0.5672,0.00439-1.1319,0.00439-1.69901V14.8242
|
||||
c0-0.5671,0-1.1328-0.00439-1.6989c-0.0022-0.4763-0.00861-0.9527-0.02161-1.4291c-0.02811-1.0379-0.0883-2.0856-0.2738-3.1119
|
||||
c-0.18539-1.0432-0.4913-2.0135-0.97429-2.9598c-0.47421-0.9313-1.093-1.7816-1.8302-2.52
|
||||
c-0.73961-0.7384-1.58881-1.3572-2.52011-1.8303c-0.9464-0.4818-1.9166-0.7878-2.9576-0.9754
|
||||
c-1.0285-0.1844-2.0762-0.2457-3.11301-0.2738c-0.47858-0.013-0.95499-0.0183-1.4314-0.0217C151.82988,0,151.26297,0,150.69807,0
|
||||
L150.69807,0z"/>
|
||||
<path id="XMLID_3_" fill="#FFFFFF" d="M150.69807,3.532l1.67149,0.0032c0.4528,0.0032,0.90561,0.0081,1.36092,0.0205
|
||||
c0.79201,0.0214,1.71849,0.0643,2.58209,0.2191c0.7507,0.1352,1.38029,0.3408,1.9845,0.6484
|
||||
c0.5965,0.3031,1.14301,0.7003,1.62019,1.1768c0.479,0.4797,0.87671,1.0271,1.18381,1.6302
|
||||
c0.30589,0.5995,0.51019,1.2261,0.64459,1.9823c0.1544,0.8542,0.1971,1.7832,0.21881,2.5801
|
||||
c0.01219,0.4498,0.01819,0.8996,0.0204,1.3601c0.00429,0.5569,0.0042,1.1135,0.0042,1.6715V91.142
|
||||
c0,0.558,0.00009,1.1136-0.0043,1.6824c-0.00211,0.4497-0.0081,0.8995-0.0204,1.3501c-0.02161,0.7957-0.0643,1.7242-0.2206,2.5885
|
||||
c-0.13251,0.7458-0.3367,1.3725-0.64429,1.975c-0.30621,0.6016-0.70331,1.1484-1.18022,1.6251
|
||||
c-0.47989,0.48-1.0246,0.876-1.62819,1.1819c-0.5997,0.3061-1.22821,0.51151-1.97151,0.6453
|
||||
c-0.88109,0.157-1.84639,0.2002-2.57339,0.2199c-0.4574,0.0103-0.9126,0.01649-1.37889,0.0187
|
||||
c-0.55571,0.0043-1.1134,0.0042-1.6692,0.0042H14.82318c-0.0074,0-0.0146,0-0.0221,0c-0.5494,0-1.0999,0-1.6593-0.0043
|
||||
c-0.4561-0.00211-0.9112-0.0082-1.3512-0.0182c-0.7436-0.0201-1.7095-0.0632-2.5834-0.2193
|
||||
c-0.74969-0.1348-1.3782-0.3402-1.9858-0.6503c-0.59789-0.3032-1.1422-0.6988-1.6223-1.1797
|
||||
c-0.4764-0.4756-0.8723-1.0207-1.1784-1.6232c-0.3064-0.6019-0.5114-1.2305-0.64619-1.9852
|
||||
c-0.15581-0.8626-0.19861-1.7874-0.22-2.5777c-0.01221-0.4525-0.01731-0.9049-0.02021-1.3547l-0.0022-1.3279l0.0001-0.3506V14.8242
|
||||
l-0.0001-0.3506l0.0021-1.3251c0.003-0.4525,0.0081-0.9049,0.02031-1.357c0.02139-0.7911,0.06419-1.7163,0.22129-2.5861
|
||||
c0.1336-0.7479,0.3385-1.3765,0.6465-1.9814c0.3037-0.5979,0.7003-1.1437,1.17921-1.6225
|
||||
c0.477-0.4772,1.02309-0.8739,1.62479-1.1799c0.6011-0.3061,1.2308-0.5116,1.9805-0.6465c0.8638-0.1552,1.7909-0.198,2.5849-0.2195
|
||||
c0.4526-0.0123,0.9052-0.0172,1.3544-0.0203l1.6771-0.0033H150.69807"/>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M45.1862,35.64053c1.41724-1.77266,2.37897-4.15282,2.12532-6.58506c-2.07464,0.10316-4.60634,1.36871-6.07207,3.14276
|
||||
c-1.31607,1.5192-2.4809,3.99902-2.17723,6.3293C41.39111,38.72954,43.71785,37.36345,45.1862,35.64053"/>
|
||||
<path d="M47.28506,38.98252c-3.38211-0.20146-6.25773,1.91951-7.87286,1.91951c-1.61602,0-4.08931-1.81799-6.76438-1.76899
|
||||
c-3.48177,0.05114-6.71245,2.01976-8.4793,5.15079c-3.63411,6.2636-0.95904,15.55471,2.57494,20.65606
|
||||
c1.71618,2.5238,3.78447,5.30269,6.50976,5.20287c2.57494-0.10104,3.58421-1.66732,6.71416-1.66732
|
||||
c3.12765,0,4.03679,1.66732,6.76252,1.61681c2.82665-0.05054,4.59381-2.52506,6.30997-5.05132
|
||||
c1.96878-2.877,2.77473-5.65498,2.82542-5.80748c-0.0507-0.05051-5.45058-2.12204-5.50065-8.33358
|
||||
c-0.05098-5.20101,4.23951-7.6749,4.44144-7.82832C52.3832,39.4881,48.5975,39.08404,47.28506,38.98252"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M76.73385,31.94381c7.35096,0,12.4697,5.06708,12.4697,12.44437c0,7.40363-5.22407,12.49704-12.65403,12.49704h-8.13892
|
||||
v12.94318h-5.88037v-37.8846H76.73385z M68.41059,51.9493h6.74732c5.11975,0,8.0336-2.75636,8.0336-7.53479
|
||||
c0-4.77792-2.91385-7.50845-8.00727-7.50845h-6.77365V51.9493z"/>
|
||||
<path d="M90.73997,61.97864c0-4.8311,3.70182-7.79761,10.26583-8.16526l7.56061-0.44614v-2.12639
|
||||
c0-3.07185-2.07423-4.90959-5.53905-4.90959c-3.28251,0-5.33041,1.57492-5.82871,4.04313h-5.35574
|
||||
c0.31499-4.98859,4.56777-8.66407,11.3941-8.66407c6.69466,0,10.97377,3.54432,10.97377,9.08388v19.03421h-5.43472v-4.54194
|
||||
h-0.13065c-1.60125,3.07185-5.09341,5.01441-8.71623,5.01441C94.52078,70.30088,90.73997,66.94038,90.73997,61.97864z
|
||||
M108.56641,59.4846v-2.17905l-6.8,0.41981c-3.38683,0.23649-5.30306,1.73291-5.30306,4.09579
|
||||
c0,2.41504,1.99523,3.99046,5.04075,3.99046C105.46823,65.81161,108.56641,63.08108,108.56641,59.4846z"/>
|
||||
<path d="M119.34167,79.9889v-4.5946c0.4193,0.10483,1.36425,0.10483,1.83723,0.10483c2.6252,0,4.04313-1.10245,4.90908-3.9378
|
||||
c0-0.05267,0.49931-1.68025,0.49931-1.70658l-9.97616-27.64562h6.14268l6.98432,22.47371h0.10432l6.98433-22.47371h5.9857
|
||||
l-10.34483,29.06304c-2.36186,6.69517-5.0924,8.84789-10.81577,8.84789C121.17891,80.12006,119.76098,80.06739,119.34167,79.9889
|
||||
z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="88.566" height="86.817" viewBox="0 0 88.566 86.817">
|
||||
<g id="calendar_reminder_red_icon" transform="translate(0 -0.215)">
|
||||
<path id="Path_892" data-name="Path 892" d="M83.672,185.309h14a1.75,1.75,0,1,0,0-3.5h-14a1.75,1.75,0,0,0,0,3.5Zm0,0" transform="translate(-60.918 -135.035)" fill="#ce1d2b"/>
|
||||
<path id="Path_893" data-name="Path 893" d="M83.672,219.443h24.5a1.751,1.751,0,1,0,0-3.5h-24.5a1.751,1.751,0,0,0,0,3.5Zm0,0" transform="translate(-60.918 -160.416)" fill="#ce1d2b"/>
|
||||
<path id="Path_894" data-name="Path 894" d="M108.176,250.074h-24.5a1.751,1.751,0,0,0,0,3.5h24.5a1.751,1.751,0,1,0,0-3.5Zm0,0" transform="translate(-60.918 -185.797)" fill="#ce1d2b"/>
|
||||
<path id="Path_895" data-name="Path 895" d="M88.566,17.019a16.8,16.8,0,0,0-33.236-3.5H28V8.267a5.251,5.251,0,1,0-10.5,0v5.251H9.216A9.227,9.227,0,0,0,0,22.734v55.08a9.227,9.227,0,0,0,9.216,9.217H71.3a9.227,9.227,0,0,0,9.216-9.217V31.337A16.793,16.793,0,0,0,88.566,17.019ZM21,8.267a1.75,1.75,0,0,1,3.5,0V20.52a1.75,1.75,0,0,1-3.5,0Zm56.01,69.547A5.722,5.722,0,0,1,71.3,83.53H9.216A5.722,5.722,0,0,1,3.5,77.814V39.773h8.751V74.779A1.751,1.751,0,0,0,14,76.53H56.01a1.763,1.763,0,0,0,1.238-.513l10.5-10.5A1.731,1.731,0,0,0,68.091,65a1.56,1.56,0,0,0,.059-.166,1.683,1.683,0,0,0,.089-.449c0-.039.022-.073.022-.111v-24.5h8.751V77.814ZM64.761,39.773V62.527H56.01a1.75,1.75,0,0,0-1.751,1.75v8.752H15.753V39.773ZM62.286,66.027,57.76,70.553V66.027ZM77.014,36.272H3.5V22.734a5.722,5.722,0,0,1,5.716-5.716H17.5v3.5a5.251,5.251,0,1,0,10.5,0v-3.5H54.959A16.776,16.776,0,0,0,77.014,32.971Zm-5.251-5.949a13.3,13.3,0,1,1,13.3-13.3A13.317,13.317,0,0,1,71.763,30.323Zm0,0" fill="#ce1d2b"/>
|
||||
<path id="Path_896" data-name="Path 896" d="M262.382,37.634l-1.174-1.3a5.623,5.623,0,0,1-1.469-3.763v-.905a6.913,6.913,0,0,0-6.243-6.831,7.143,7.143,0,0,0-5.419,1.8,6.563,6.563,0,0,0-2.153,4.825v1.49a5.549,5.549,0,0,1-1.135,3.357L243.7,37.754a1.751,1.751,0,0,0,1.4,2.8h5.962v1.751a1.75,1.75,0,0,0,3.5,0V40.557h6.523a1.751,1.751,0,0,0,1.3-2.922Zm-13.948-.578a8.972,8.972,0,0,0,.992-4.111v-1.49a3.012,3.012,0,0,1,1.014-2.24,3.594,3.594,0,0,1,2.74-.894,3.385,3.385,0,0,1,3.059,3.345v.906a9.044,9.044,0,0,0,1.2,4.485Zm0,0" transform="translate(-180.954 -18.287)" fill="#ce1d2b"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 26 26">
|
||||
<g id="check_icon" transform="translate(-17 -71)">
|
||||
<circle id="Ellipse_331" data-name="Ellipse 331" cx="13" cy="13" r="13" transform="translate(17 71)" fill="#fff"/>
|
||||
<g id="Group_743" data-name="Group 743" transform="translate(-141 -256.936)">
|
||||
<path id="Icon_awesome-check-circle" data-name="Icon awesome-check-circle" d="M26.4,13.481A12.918,12.918,0,1,1,13.481.563,12.918,12.918,0,0,1,26.4,13.481Zm-14.413,6.84,9.585-9.585a.833.833,0,0,0,0-1.179L20.393,8.379a.833.833,0,0,0-1.179,0L11.4,16.2,7.748,12.546a.834.834,0,0,0-1.179,0L5.391,13.725a.833.833,0,0,0,0,1.179l5.417,5.417a.833.833,0,0,0,1.179,0Z" transform="translate(157.438 327.373)" fill="#6ea231"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 781 B |
@ -0,0 +1,26 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="103.843" height="79.732" viewBox="0 0 103.843 79.732">
|
||||
<g id="Group_776" data-name="Group 776" transform="translate(-67.806 -333.834)">
|
||||
<g id="Group_772" data-name="Group 772" transform="translate(72.721 385.261)">
|
||||
<path id="Rectangle_494" data-name="Rectangle 494" d="M3.513,0h5.5a3.512,3.512,0,0,1,3.512,3.512V24.794a3.512,3.512,0,0,1-3.512,3.512h-5.5A3.512,3.512,0,0,1,0,24.793V3.513A3.513,3.513,0,0,1,3.513,0Z" transform="translate(81.49)" fill="#404040"/>
|
||||
<path id="Rectangle_495" data-name="Rectangle 495" d="M3.513,0h5.5a3.512,3.512,0,0,1,3.512,3.512V24.794a3.512,3.512,0,0,1-3.512,3.512h-5.5A3.512,3.512,0,0,1,0,24.793V3.513A3.513,3.513,0,0,1,3.513,0Z" transform="translate(0)" fill="#404040"/>
|
||||
</g>
|
||||
<g id="Group_774" data-name="Group 774" transform="translate(67.806 333.834)">
|
||||
<g id="Group_773" data-name="Group 773" transform="translate(0 20.106)">
|
||||
<path id="Path_964" data-name="Path 964" d="M202.791,368.713a2.117,2.117,0,0,1-1.4,1.881l.87,1.595a2.144,2.144,0,0,1,2.578-.721h.784v-2.755Z" transform="translate(-108.451 -364.552)" fill="#b2361d"/>
|
||||
<path id="Path_965" data-name="Path 965" d="M212.887,366.617c.07,1.4-1.91,2.76-3.882,3.26-2.9.735-5.653-.648-5.653-3.515,0-2.783,1.939-4.222,4.769-3.4C210.072,363.532,212.818,365.233,212.887,366.617Z" transform="translate(-109.046 -362.733)" fill="#d84c2f"/>
|
||||
<path id="Path_966" data-name="Path 966" d="M80.223,368.713a2.116,2.116,0,0,0,1.4,1.881l-.87,1.595a2.144,2.144,0,0,0-2.578-.721h-.785v-2.755Z" transform="translate(-70.722 -364.552)" fill="#b2361d"/>
|
||||
<path id="Path_967" data-name="Path 967" d="M67.808,366.617c-.07,1.4,1.909,2.76,3.882,3.26,2.9.735,5.654-.648,5.654-3.515,0-2.783-1.939-4.222-4.769-3.4C70.623,363.532,67.877,365.233,67.808,366.617Z" transform="translate(-67.806 -362.733)" fill="#d84c2f"/>
|
||||
</g>
|
||||
<path id="Path_968" data-name="Path 968" d="M168.258,369.52c-.522-3.479-3.218-7.392-4.7-10.349s-6.929-16.872-8.262-19.307a10.983,10.983,0,0,0-7.653-5.435c-3.479-.522-18.843-.594-25.511-.594s-22.032.072-25.51.594a10.981,10.981,0,0,0-7.653,5.435c-1.334,2.435-6.784,16.35-8.262,19.307s-4.174,6.871-4.7,10.349-.348,24.09.522,27.482a7.356,7.356,0,0,0,6.61,5.479h77.982a7.356,7.356,0,0,0,6.61-5.479C168.606,393.61,168.78,373,168.258,369.52Z" transform="translate(-70.214 -333.834)" fill="#d84c2f"/>
|
||||
<path id="Path_969" data-name="Path 969" d="M75.773,405.294c.09,5.924.349,11.778.779,13.45a7.356,7.356,0,0,0,6.61,5.479h77.982a7.356,7.356,0,0,0,6.61-5.479c.429-1.671.687-7.525.779-13.45Z" transform="translate(-70.23 -355.576)" fill="#d63828"/>
|
||||
<path id="Path_970" data-name="Path 970" d="M160.494,364.834s4.871,7.37,5.508,9.221.725,3.533-1.1,4.374-15.567,4.261-18.7,4.261H101.385c-3.131,0-16.872-3.42-18.7-4.261s-1.739-2.522-1.1-4.374,5.508-9.221,5.508-9.221" transform="translate(-71.873 -343.266)" fill="none" stroke="#b2361d" stroke-miterlimit="10" stroke-width="0.5"/>
|
||||
</g>
|
||||
<path id="Path_971" data-name="Path 971" d="M165.792,420.908a1.465,1.465,0,0,1-1.364,2.224H83.859a1.465,1.465,0,0,1-1.364-2.224l1.75-4.285a3.366,3.366,0,0,1,2.887-1.956h74.025a3.364,3.364,0,0,1,2.887,1.956Z" transform="translate(-4.416 -24.593)" fill="#404040"/>
|
||||
<path id="Path_972" data-name="Path 972" d="M152.824,394.283c-.522-1.565-2.783-2.783-5.044-2.783h-26.96c-2.261,0-4.522,1.218-5.044,2.783s1.826,8.009,2.7,9.179,1.826,1.46,4.609,1.46h22.438c2.783,0,3.74-.29,4.609-1.46S153.346,395.848,152.824,394.283Z" transform="translate(-14.572 -17.545)" fill="#404040"/>
|
||||
<path id="Path_973" data-name="Path 973" d="M163.631,358.436c-.435-1.508-4.609-12.147-5.827-14.669s-2.87-3.392-4.088-3.392H98c-1.218,0-2.87.87-4.088,3.392s-5.392,13.161-5.827,14.669.261,2.2,1.391,2.2h72.764C163.37,360.639,164.066,359.943,163.631,358.436Z" transform="translate(-6.13 -1.99)" fill="#404040"/>
|
||||
<g id="Group_775" data-name="Group 775" transform="translate(76.803 368.998)">
|
||||
<path id="Path_974" data-name="Path 974" d="M175.9,389.332s3.827,4.783,5.74,4.783h11.045a2.421,2.421,0,0,0,2.522-2,23,23,0,0,0,0-7.74A90.156,90.156,0,0,1,175.9,389.332Z" transform="translate(-109.692 -384.375)" fill="#fff"/>
|
||||
<path id="Path_975" data-name="Path 975" d="M100.374,389.332s-3.827,4.783-5.74,4.783H83.589a2.421,2.421,0,0,1-2.522-2,23,23,0,0,1,0-7.74A90.156,90.156,0,0,0,100.374,389.332Z" transform="translate(-80.738 -384.375)" fill="#fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14.068" height="14.94" viewBox="0 0 14.068 14.94">
|
||||
<g id="Group_8471" data-name="Group 8471" transform="translate(-325.503 -184.253)">
|
||||
<path id="Path_5005" data-name="Path 5005" d="M9.7,3.407h2.814a.7.7,0,0,0,0-1.407H9.7a.7.7,0,0,0,0,1.407Z" transform="translate(321.427 182.253)" fill="#5a282e"/>
|
||||
<path id="Path_5004" data-name="Path 5004" d="M15.365,5H2.7a.7.7,0,1,0,0,1.407H4.11v8.441a2.111,2.111,0,0,0,2.11,2.11h5.627a2.111,2.111,0,0,0,2.11-2.11V6.407h1.407a.7.7,0,1,0,0-1.407ZM8.331,12.738a.7.7,0,1,1-1.407,0V9.221a.7.7,0,1,1,1.407,0Zm2.814,0a.7.7,0,1,1-1.407,0V9.221a.7.7,0,1,1,1.407,0Z" transform="translate(323.503 182.235)" fill="#5a282e"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 721 B |
@ -0,0 +1,12 @@
|
||||
<svg id="calendar" xmlns="http://www.w3.org/2000/svg" width="16.407" height="16.407" viewBox="0 0 16.407 16.407">
|
||||
<g id="Group_8220" data-name="Group 8220">
|
||||
<g id="Group_8219" data-name="Group 8219">
|
||||
<path id="Path_4987" data-name="Path 4987" d="M14.767,1.641h-.82V.82a.82.82,0,1,0-1.641,0v.82H4.1V.82A.775.775,0,0,0,3.281,0a.775.775,0,0,0-.82.82v.82H.82a.822.822,0,0,0-.82.82V13.946a.822.822,0,0,0,.82.82h5A6.53,6.53,0,0,1,15.587,6.4V2.461A.882.882,0,0,0,14.767,1.641Z" fill="#2e303a"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group_8222" data-name="Group 8222" transform="translate(6.563 6.563)">
|
||||
<g id="Group_8221" data-name="Group 8221">
|
||||
<path id="Path_4988" data-name="Path 4988" d="M209.722,204.8a4.922,4.922,0,1,0,4.922,4.922A4.937,4.937,0,0,0,209.722,204.8Zm1.641,5.743h-1.641a.775.775,0,0,1-.82-.82v-2.461a.82.82,0,0,1,1.641,0V208.9h.82a.82.82,0,1,1,0,1.641Z" transform="translate(-204.8 -204.8)" fill="#2e303a"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 953 B |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
|
||||
<path id="Icon_ionic-ios-checkmark-circle" data-name="Icon ionic-ios-checkmark-circle" d="M12.375,3.375a9,9,0,1,0,9,9A9,9,0,0,0,12.375,3.375Zm4.608,6.512L11.2,15.7h0a.781.781,0,0,1-.5.238.757.757,0,0,1-.506-.247L7.763,13.266a.172.172,0,0,1,0-.247l.77-.77a.167.167,0,0,1,.242,0L10.7,14.171l5.279-5.318A.171.171,0,0,1,16.1,8.8h0a.157.157,0,0,1,.121.052l.757.783A.171.171,0,0,1,16.983,9.887Z" transform="translate(-3.375 -3.375)" fill="#15c940"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 537 B |