Merge branch 'dev_v3.13.6' of http://34.17.52.180/Haroon6138/diplomatic-quarter into dev_v3.13.6_search_hospital_by_region

# Conflicts:
#	android/app/build.gradle
#	android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt
#	android/app/src/main/res/values/strings.xml
merge-update-with-lab-changes
taha.alam 11 months ago
commit c2f38f1b7f

@ -78,7 +78,7 @@ android {
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled false
multiDexEnabled true
}
sourceSets.main {
@ -99,8 +99,8 @@ android {
debug {
debuggable true
signingConfig signingConfigs.debug
shrinkResources false
minifyEnabled false
shrinkResources false
// ndk {
// abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
// }
@ -137,6 +137,9 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
flutter {
@ -186,6 +189,10 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'androidx.test.ext:junit:1.1.5'
implementation 'com.android.volley:volley:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.8.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.8.5'
implementation 'androidx.activity:activity:1.9.3'
def room_version = "2.4.0-alpha04"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
@ -196,11 +203,11 @@ dependencies {
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
// implementation "com.mapbox.maps:android:10.16.6"
// implementation 'com.mapbox.maps:android:11.3.1'
implementation 'com.mapbox.maps:android:11.3.1'
// implementation files('libs/PenNavUI.aar')
// implementation files('libs/Penguin.aar')
// implementation files('libs/PenguinRenderer.aar')
implementation files('libs/PenNavUI.aar')
implementation files('libs/Penguin.aar')
implementation files('libs/PenguinRenderer.aar')
// implementation "org.jetbrains.anko:anko-commons:0.10.4"
implementation 'com.github.kittinunf.fuel:fuel:2.3.0' //for JVM
@ -215,7 +222,10 @@ dependencies {
implementation 'com.google.android.material:material:1.9.0'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.22'
androidTestImplementation "androidx.test:core:1.4.0"
implementation 'com.airbnb.android:lottie:5.2.0'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.22'
// implementation 'com.airbnb.android:lottie:5.2.0'
// implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.22'
implementation 'com.whatsapp.otp:whatsapp-otp-android-sdk:0.1.0'
implementation 'com.whatsapp.otp:whatsapp-otp-android-sdk:0.1.0'
}

@ -1,51 +1,82 @@
<?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
<!--
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"/>
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" />
<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_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_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-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.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.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-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" />
@ -53,106 +84,146 @@
<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" />-->
<uses-feature
android:name="android.hardware.location.network"
android:required="false" />
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
<!-- 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"/>-->
<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:icon="@mipmap/ic_launcher_local"
android:usesCleartextTraffic="true"
android:showOnLockScreen="true"
android:screenOrientation="sensorPortrait"
android:allowBackup="false"
android:extractNativeLibs="true"
tools:replace="android:extractNativeLibs,android:label"
android:label="Dr. Alhabib">
android:icon="@mipmap/ic_launcher_local"
android:label="Dr. Alhabib"
android:screenOrientation="sensorPortrait"
android:showOnLockScreen="true"
android:usesCleartextTraffic="true"
tools:replace="android:extractNativeLibs,android:label">
<activity
android:name=".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" />
<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:exported="true"
tools:node="merge"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
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. -->
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
<!--
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. -->
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>
</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="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">
<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"/>
<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">
<receiver
android:name=".geofence.intent_receivers.LocationProviderChangeReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.location.PROVIDERS_CHANGED"/>
<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 -->
<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" />-->
<!-- <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">
<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>
@ -168,26 +239,17 @@
<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 -->
</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>
<!-- <uses-permission android:name="android.permission.INTERNET" />-->
<!-- <uses-permission android:name="android.permission.USE_FINGERPRINT" />-->
<!-- <uses-permission android:name="android.permission.READ_CALENDAR" />-->
<!-- <uses-permission android:name="android.permission.WRITE_CALENDAR" />-->
</manifest>
</manifest>

@ -1,4 +1,5 @@
package com.ejada.hmg
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
@ -6,11 +7,15 @@ import android.util.Log
import android.view.WindowManager
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi
//import com.cloud.diplomaticquarterapp.PenguinInPlatformBridge
import com.cloud.diplomaticquarterapp.PenguinInPlatformBridge
import com.cloud.diplomaticquarterapp.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.diplomaticquarterapp.whatsapp.WhatsApp
import com.cloud.diplomaticquarterapp.whatsapp.WhatsAppOtpPlatformBridge
class MainActivity: FlutterFragmentActivity() {
@RequiresApi(Build.VERSION_CODES.O)
@ -21,9 +26,10 @@ class MainActivity: FlutterFragmentActivity() {
PlatformBridge(flutterEngine, this).create()
OpenTokPlatformBridge(flutterEngine, this).create()
// PenguinInPlatformBridge(flutterEngine, this).create()
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
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)

@ -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.diplomaticquarterapp.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.diplomaticquarterapp.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.ejada.hmg
import android.app.PendingIntent
import android.content.Intent
import android.os.Bundle
import com.cloud.diplomaticquarterapp.whatsapp.WhatsApp
import com.cloud.diplomaticquarterapp.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,52 @@
package com.cloud.diplomaticquarterapp.whatsapp
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.cloud.diplomaticquarterapp.penguin.PenguinView
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()
}
}
}
}
}

@ -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=".WhatsAppCodeActivity">
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,23 +1,23 @@
<resources>
<string name="app_name">HMG Patient App</string>
<string name="app_name">HMG Patient App</string>
<string name="geofence_unknown_error">
<string name="geofence_unknown_error">
Unknown error: the Geofence service is not available now.
</string>
<string name="geofence_not_available">
<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">
<string name="geofence_too_many_geofences">
Your app has registered too many geofences.
</string>
<string name="geofence_too_many_pending_intents">
<string name="geofence_too_many_pending_intents">
You have provided too many PendingIntents to the addGeofences() call.
</string>
<string name="GEOFENCE_INSUFFICIENT_LOCATION_PERMISSION">
<string name="GEOFENCE_INSUFFICIENT_LOCATION_PERMISSION">
App do not have permission to access location service.
</string>
<string name="GEOFENCE_REQUEST_TOO_FREQUENT">
<string name="GEOFENCE_REQUEST_TOO_FREQUENT">
Geofence requests happened too frequently.
</string>
<string name="mapbox_access_token" translatable="false">pk.eyJ1IjoicndhaWQiLCJhIjoiY2x5cGo4aHNjMGNsbTJyc2djempobGQxaSJ9.RCaC6WrUt4A4YnZNfxnONQ</string>
<string name="mapbox_access_token" translatable="false">sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg</string>
</resources>

@ -19,8 +19,8 @@ buildscript {
credentials {
username = 'mapbox'
// password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
password = "pk.eyJ1IjoicndhaWQiLCJhIjoiY2x5cGo4aHNjMGNsbTJyc2djempobGQxaSJ9.RCaC6WrUt4A4YnZNfxnONQ"
password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
// password = "pk.eyJ1IjoicndhaWQiLCJhIjoiY2x5cGo4aHNjMGNsbTJyc2djempobGQxaSJ9.RCaC6WrUt4A4YnZNfxnONQ"
if (password == null || password == "") {
throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the enviroment variables.")
}

@ -4,5 +4,5 @@ android.useAndroidX=true
android.enableJetifier=true
android.suppressUnsupportedCompileSdk=33
MAPBOX_USER_NAME = "mapbox"
#MAPBOX_DOWNLOADS_TOKEN="sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
MAPBOX_DOWNLOADS_TOKEN="pk.eyJ1IjoicndhaWQiLCJhIjoiY2x5cGo4aHNjMGNsbTJyc2djempobGQxaSJ9.RCaC6WrUt4A4YnZNfxnONQ"
MAPBOX_DOWNLOADS_TOKEN="sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
#MAPBOX_DOWNLOADS_TOKEN="pk.eyJ1IjoicndhaWQiLCJhIjoiY2x5cGo4aHNjMGNsbTJyc2djempobGQxaSJ9.RCaC6WrUt4A4YnZNfxnONQ"

@ -1,4 +1,6 @@
include ':app'
include ':vital-sign-engine'
project(':vital-sign-engine').projectDir = new File('/Users/mohamedmekawy/Documents/Work/DiplomaticQuarter_3.16/packages/vital_sign_camera/android/libs')
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()

@ -33,7 +33,8 @@ target 'Runner' do
pod 'OpenTok', '~> 2.22.0'
pod 'VTO2Lib'
pod 'MapboxMaps', '10.18.2'
pod 'MapboxMaps', '10.19.0'
pod 'MapboxNavigation', '2.19.0'
pod 'FLAnimatedImage'
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))

@ -14,15 +14,16 @@
306FE6C8271D790C002D6EFC /* OpenTokPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */; };
306FE6CB271D8B73002D6EFC /* OpenTok.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306FE6CA271D8B73002D6EFC /* OpenTok.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
47C935002C91766800981BA7 /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FC2C91766400981BA7 /* Penguin.xcframework */; };
47C935012C91766800981BA7 /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FC2C91766400981BA7 /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
47C935022C91766900981BA7 /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */; };
47C935032C91766900981BA7 /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
47C935042C91766A00981BA7 /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FB2C91766400981BA7 /* PenNavUI.xcframework */; };
47C935052C91766A00981BA7 /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 47C934FB2C91766400981BA7 /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
55DE18989C1F69DC483B9FB6 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C56AF9B31AA04A5292EEA39F /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
762D738E274E42650063CE73 /* ring_30Sec.caf in Resources */ = {isa = PBXBuildFile; fileRef = 762D738C274E42650063CE73 /* ring_30Sec.caf */; };
762D738F274E42650063CE73 /* ring_30Sec.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 762D738D274E42650063CE73 /* ring_30Sec.mp3 */; };
7651B82F2D3E9CA40066B33A /* PenguinINRenderer.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7651B82C2D3E9CA40066B33A /* PenguinINRenderer.xcframework */; };
7651B8302D3E9CA40066B33A /* PenguinINRenderer.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7651B82C2D3E9CA40066B33A /* PenguinINRenderer.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
7651B8312D3E9CA40066B33A /* Penguin.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7651B82D2D3E9CA40066B33A /* Penguin.xcframework */; };
7651B8322D3E9CA40066B33A /* Penguin.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7651B82D2D3E9CA40066B33A /* Penguin.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
7651B8332D3E9CA40066B33A /* PenNavUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7651B82E2D3E9CA40066B33A /* PenNavUI.xcframework */; };
7651B8342D3E9CA40066B33A /* PenNavUI.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7651B82E2D3E9CA40066B33A /* PenNavUI.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
76815B27275F381C00E66E94 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76815B26275F381C00E66E94 /* HealthKit.framework */; };
76962ECE28AE5C10004EAE09 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 76962ECD28AE5C10004EAE09 /* GoogleService-Info.plist */; };
76D71B672C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B662C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift */; };
@ -51,19 +52,18 @@
E9C8C136256BACDA00EFFB62 /* HMG_Guest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9C8C135256BACDA00EFFB62 /* HMG_Guest.swift */; };
E9E27168256E3A4000F49B69 /* LocalizedFromFlutter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E27167256E3A4000F49B69 /* LocalizedFromFlutter.swift */; };
E9F7623B25922BCE00FB5CCF /* FlutterConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F7623A25922BCE00FB5CCF /* FlutterConstants.swift */; };
FD7241B0D73FB24C87572FAC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E413842321D0D624872E9BE /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
768D81742C6DF6E4005C655F /* Embed Frameworks */ = {
7651B8352D3E9CA50066B33A /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
buildActionMask = 12;
dstPath = "";
dstSubfolderSpec = 10;
files = (
47C935032C91766900981BA7 /* PenguinINRenderer.xcframework in Embed Frameworks */,
47C935012C91766800981BA7 /* Penguin.xcframework in Embed Frameworks */,
47C935052C91766A00981BA7 /* PenNavUI.xcframework in Embed Frameworks */,
7651B8322D3E9CA40066B33A /* Penguin.xcframework in Embed Frameworks */,
7651B8302D3E9CA40066B33A /* PenguinINRenderer.xcframework in Embed Frameworks */,
7651B8342D3E9CA40066B33A /* PenNavUI.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@ -71,6 +71,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
02C0468611167F0E858967A9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
29631B9D2C96C7F600DF5916 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = "<group>"; };
@ -79,10 +80,6 @@
306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokPlatformBridge.swift; sourceTree = "<group>"; };
306FE6CA271D8B73002D6EFC /* OpenTok.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTok.swift; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenguinINRenderer.xcframework; path = Frameworks/PenguinINRenderer.xcframework; sourceTree = "<group>"; };
47C934FB2C91766400981BA7 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = "<group>"; };
47C934FC2C91766400981BA7 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = "<group>"; };
6EE8819867EC2775AB578377 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
762D738C274E42650063CE73 /* ring_30Sec.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = ring_30Sec.caf; path = ../../assets/sounds/ring_30Sec.caf; sourceTree = "<group>"; };
@ -90,6 +87,9 @@
7643E4042BE0D0B400BD2F25 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Main_Custom.strings; sourceTree = "<group>"; };
7643E4052BE0D0B400BD2F25 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Main.strings; sourceTree = "<group>"; };
7643E4062BE0D0B400BD2F25 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
7651B82C2D3E9CA40066B33A /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenguinINRenderer.xcframework; path = Frameworks/PenguinINRenderer.xcframework; sourceTree = "<group>"; };
7651B82D2D3E9CA40066B33A /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = "<group>"; };
7651B82E2D3E9CA40066B33A /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = "<group>"; };
76815B26275F381C00E66E94 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; };
76962ECD28AE5C10004EAE09 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
76D71B662C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = "<group>"; };
@ -99,8 +99,6 @@
76D71B6F2C6B81EA00DAFB84 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = "<group>"; };
76F2556027F1FFED0062C1CD /* PassKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PassKit.framework; path = System/Library/Frameworks/PassKit.framework; sourceTree = SDKROOT; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
838788A2BEDC4910F4B029A6 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
8E413842321D0D624872E9BE /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -108,6 +106,9 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9E4A8F0312C6AED5D3DC152C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
C56AF9B31AA04A5292EEA39F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D72A14381E2E5999FC41D0A8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
E91B538D256AAA6500E96549 /* GlobalHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalHelper.swift; sourceTree = "<group>"; };
E91B538E256AAA6500E96549 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
E91B538F256AAA6500E96549 /* API.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = "<group>"; };
@ -126,7 +127,6 @@
E9C8C135256BACDA00EFFB62 /* HMG_Guest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMG_Guest.swift; sourceTree = "<group>"; };
E9E27167256E3A4000F49B69 /* LocalizedFromFlutter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedFromFlutter.swift; sourceTree = "<group>"; };
E9F7623A25922BCE00FB5CCF /* FlutterConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterConstants.swift; sourceTree = "<group>"; };
F2C7D3C4718A1DED85DA3AD4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -134,13 +134,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7651B8312D3E9CA40066B33A /* Penguin.xcframework in Frameworks */,
76F2556127F1FFED0062C1CD /* PassKit.framework in Frameworks */,
76815B27275F381C00E66E94 /* HealthKit.framework in Frameworks */,
E9620805255C2ED100D3A35D /* NetworkExtension.framework in Frameworks */,
47C935042C91766A00981BA7 /* PenNavUI.xcframework in Frameworks */,
47C935002C91766800981BA7 /* Penguin.xcframework in Frameworks */,
47C935022C91766900981BA7 /* PenguinINRenderer.xcframework in Frameworks */,
FD7241B0D73FB24C87572FAC /* Pods_Runner.framework in Frameworks */,
7651B8332D3E9CA40066B33A /* PenNavUI.xcframework in Frameworks */,
7651B82F2D3E9CA40066B33A /* PenguinINRenderer.xcframework in Frameworks */,
55DE18989C1F69DC483B9FB6 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -160,13 +160,13 @@
555EAAA626EFB641859EF0BE /* Frameworks */ = {
isa = PBXGroup;
children = (
47C934FC2C91766400981BA7 /* Penguin.xcframework */,
47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */,
47C934FB2C91766400981BA7 /* PenNavUI.xcframework */,
7651B82D2D3E9CA40066B33A /* Penguin.xcframework */,
7651B82C2D3E9CA40066B33A /* PenguinINRenderer.xcframework */,
7651B82E2D3E9CA40066B33A /* PenNavUI.xcframework */,
76F2556027F1FFED0062C1CD /* PassKit.framework */,
76815B26275F381C00E66E94 /* HealthKit.framework */,
E9620804255C2ED100D3A35D /* NetworkExtension.framework */,
8E413842321D0D624872E9BE /* Pods_Runner.framework */,
C56AF9B31AA04A5292EEA39F /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -174,9 +174,9 @@
605039E5DDF72C245F9765FE /* Pods */ = {
isa = PBXGroup;
children = (
F2C7D3C4718A1DED85DA3AD4 /* Pods-Runner.debug.xcconfig */,
838788A2BEDC4910F4B029A6 /* Pods-Runner.release.xcconfig */,
6EE8819867EC2775AB578377 /* Pods-Runner.profile.xcconfig */,
D72A14381E2E5999FC41D0A8 /* Pods-Runner.debug.xcconfig */,
02C0468611167F0E858967A9 /* Pods-Runner.release.xcconfig */,
9E4A8F0312C6AED5D3DC152C /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -293,15 +293,15 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
6D0B2FE51DC05E2D0395E861 /* [CP] Check Pods Manifest.lock */,
BEE88E0BBD555ACCD7E82B57 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
768D81742C6DF6E4005C655F /* Embed Frameworks */,
7651B8352D3E9CA50066B33A /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
487FDD6493EB9AE7D8E39485 /* [CP] Embed Pods Frameworks */,
4671D3CD126F6635F4B75A6E /* [CP] Copy Pods Resources */,
191312D8478950EB12CBDD28 /* [CP] Embed Pods Frameworks */,
4CC68CB45B720A365C7CF7DC /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -368,6 +368,23 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
191312D8478950EB12CBDD28 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@ -384,7 +401,7 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
};
4671D3CD126F6635F4B75A6E /* [CP] Copy Pods Resources */ = {
4CC68CB45B720A365C7CF7DC /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -401,24 +418,22 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
487FDD6493EB9AE7D8E39485 /* [CP] Embed Pods Frameworks */ = {
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
6D0B2FE51DC05E2D0395E861 /* [CP] Check Pods Manifest.lock */ = {
BEE88E0BBD555ACCD7E82B57 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -440,21 +455,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -583,12 +583,13 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
"$(SRCROOT)/Frameworks",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@ -600,7 +601,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 4.5.991;
MARKETING_VERSION = 4.5.999;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -734,12 +735,13 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
"$(SRCROOT)/Frameworks",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@ -751,7 +753,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 4.5.991;
MARKETING_VERSION = 4.5.999;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -777,12 +779,13 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 3A359E86ZF;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
"$(SRCROOT)/Frameworks",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@ -794,7 +797,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 4.5.991;
MARKETING_VERSION = 4.5.999;
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

@ -352,7 +352,7 @@ var CAN_PAY_FOR_FOR_WALKIN_APPOINTMENT = 'Services/Doctors.svc/REST/CanPayForWal
var CHANNEL = 3;
var GENERAL_ID = 'Cs2020@2016\$2958';
var IP_ADDRESS = '10.20.10.20';
var VERSION_ID = 17.1;
var VERSION_ID = 17.4;
var SETUP_ID = '91877';
var LANGUAGE = 2;
// var PATIENT_OUT_SA = 0;
@ -694,6 +694,8 @@ var GET_PROJECT_FROM_NFC = 'Services/OUTPs.svc/Rest/GetProjectByNFC';
var GET_PATIENT_OCCUPATION_LIST = 'Services/Authentication.svc/REST/GetPatientOccupation';
var IS_DOCTOR_AVAILABLE_BY_CALENDAR_SCHEDULE = 'Services/OUTPs.svc/REST/HIS_IsDoctorAvailableByCalendarSchedule';
//PAYFORT
var getPayFortProjectDetails = "Services/PayFort_Serv.svc/REST/GetPayFortProjectDetails";
var addPayFortApplePayResponse = "Services/PayFort_Serv.svc/REST/AddResponse";

@ -187,7 +187,7 @@ class BaseAppClient {
// body['IdentificationNo'] = 1023854217;
// body['MobileNo'] = "531940021"; //0560717232
// body['PatientID'] = 1058229; //4609100
// body['PatientID'] = 5185584; //4609100
// body['TokenID'] = "@dm!n";
// Patient ID: 3027574

@ -29,6 +29,25 @@ class AskDoctorService extends BaseService {
return Future.value(localRes);
}
Future isDoctorAvailable({int? projectId, int? doctorId, int? clinicId}) async {
hasError = false;
Map<String, dynamic> body = Map();
body['isDentalAllowedBackend'] = false;
body['DoctorID'] = doctorId;
body['ProjectID'] = projectId;
body['ClinicID'] = clinicId;
dynamic localRes;
await baseAppClient.post(IS_DOCTOR_AVAILABLE_BY_CALENDAR_SCHEDULE, onSuccess: (dynamic response, int statusCode) {
localRes = response;
}, onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
}, body: body);
return Future.value(localRes);
}
Future getCallRequestTypeLOV() async {
hasError = false;
Map<String, dynamic> body = Map();

@ -42,7 +42,7 @@ class LabsService extends BaseService {
_requestPatientLabSpecialResult.invoiceNo = isVidaPlus! ? "0" : invoiceNo;
_requestPatientLabSpecialResult.invoiceNoVP = isVidaPlus ? invoiceNo : "0";
_requestPatientLabSpecialResult.invoiceType = invoiceType!;
_requestPatientLabSpecialResult.invoiceType = invoiceType ?? "";
_requestPatientLabSpecialResult.orderNo = orderNo;
_requestPatientLabSpecialResult.setupID = setupID;

@ -670,8 +670,8 @@ class _AnicllaryOrdersState extends State<AnicllaryOrdersDetails> with SingleTic
currency: projectViewModel.user.outSA == 1 ? "AED" : "SAR",
onFailed: (failureResult) async {
GifLoaderDialogUtils.hideDialog(context);
log("failureResult: ${failureResult.toString()}");
AppToast.showErrorToast(message: failureResult.toString());
log("failureResult: ${failureResult.message.toString()}");
AppToast.showErrorToast(message: failureResult.message.toString());
},
onSuccess: (successResult) async {
log("Payfort: ${successResult.responseMessage}");

@ -459,8 +459,9 @@ class _BookConfirmState extends State<BookConfirm> {
payfortProjectDetailsRespModel: payfortProjectDetailsRespModel,
currency: projectViewModel.user.outSA == 1 ? "AED" : "SAR",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.toString()}");
AppToast.showErrorToast(message: failureResult.toString());
GifLoaderDialogUtils.hideDialog(context);
log("failureResult: ${failureResult.message.toString()}");
AppToast.showErrorToast(message: failureResult.message.toString());
},
onSuccess: (successResult) async {
log("Payfort: ${successResult.responseMessage}");

@ -712,8 +712,8 @@ class _BookSuccessState extends State<BookSuccess> {
currency: projectViewModel.user.outSA == 1 ? "AED" : "SAR",
onFailed: (failureResult) async {
GifLoaderDialogUtils.hideDialog(context);
log("failureResult: ${failureResult.toString()}");
AppToast.showErrorToast(message: failureResult.toString());
log("failureResult: ${failureResult.message.toString()}");
AppToast.showErrorToast(message: failureResult.message.toString());
},
onSuccess: (successResult) async {
log("Payfort: ${successResult.responseMessage}");

@ -389,7 +389,6 @@ class _QRCodeState extends State<QRCode> {
service.sendCheckinNfcRequest(widget!.patientShareResponse!.appointmentNo!, nfcId, widget.patientShareResponse!.projectID!, checkInBy, widget.patientShareResponse!.clinicID!, context).then((res) {
print(res);
GifLoaderDialogUtils.hideDialog(context);
_showMyDialog(res["SuccessMsg"], this.context);
}).catchError((err) {

@ -423,8 +423,9 @@ class _EROnlineCheckInPaymentDetailsState extends State<EROnlineCheckInPaymentDe
payfortProjectDetailsRespModel: payfortProjectDetailsRespModel,
currency: projectViewModel.user.outSA == 1 ? "AED" : "SAR",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.toString()}");
AppToast.showErrorToast(message: failureResult.toString());
GifLoaderDialogUtils.hideDialog(context);
log("failureResult: ${failureResult.message.toString()}");
AppToast.showErrorToast(message: failureResult.message.toString());
},
onSuccess: (successResult) async {
log("Payfort: ${successResult.responseMessage}");

@ -255,6 +255,7 @@ class _InPatientPendingAdvancePaymentState extends State<InPatientPendingAdvance
int clinicID = projectViewModel.isPatientAdmitted ? projectViewModel.getAdmissionInfoResponseModel.clinicID! : 17;
service
.getInPatientPaymentLink(
widget.inPatientAdvanceResponseModel.responseInpatientAdvanceInfo![0].paymentRequestID!,
projectViewModel.inPatientProjectID,
// projectViewModel.getAdmissionInfoResponseModel.admissionNo!,
projectViewModel.isPatientAdmitted ? projectViewModel.getAdmissionInfoResponseModel.admissionRequestNo! : projectViewModel.getAdmissionRequestInfoResponseModel.admissionRequestNo!,

@ -514,7 +514,8 @@ class InPatientGeneralConsent extends StatelessWidget {
.then((res) {
GifLoaderDialogUtils.hideDialog(context);
if (res["MessageStatus"] == 1) {
AppToast.showErrorToast(message: res["SuccessMsg"]);
AppToast.showSuccessToast(message: res["SuccessMsg"] ?? TranslationBase.of(context).success);
Navigator.of(context);
} else {
AppToast.showErrorToast(message: res["endUserMessage"]);
}

@ -105,7 +105,7 @@ class _AppointmentDetailsState extends State<AppointmentDetails> with SingleTick
widget.appo.doctorImageURL!,
widget.appo.doctorSpeciality!,
"",
widget.appo.projectName!,
widget.appo.projectName ?? "",
DateUtil.convertStringToDate(widget.appo.appointmentDate!),
widget.appo.isLiveCareAppointment! ? DateUtil.convertStringToDate(widget.appo.appointmentDate!).toString().split(" ")[1].substring(0, 5) : widget.appo.startTime!.substring(0, 5),
"",

@ -409,6 +409,7 @@ class _AppointmentActionsState extends State<AppointmentActions> {
if (res['ListLabResultsByAppNo'] != null) {
patientLabOrders.orderNo = res['ListLabResultsByAppNo'][0]['OrderNo'].toString();
patientLabOrders.invoiceNo = res['ListLabResultsByAppNo'][0]['InvoiceNo'].toString();
patientLabOrders.invoiceType = res['ListLabResultsByAppNo'][0]['InvoiceType'].toString();
patientLabOrders.clinicID = widget.appo.clinicID;
patientLabOrders.clinicDescription = widget.appo.clinicName;
patientLabOrders.projectID = widget.appo.projectID.toString();

@ -1531,8 +1531,8 @@ class _ToDoState extends State<ToDo> with SingleTickerProviderStateMixin {
currency: projectViewModel.user.outSA == 1 ? "AED" : "SAR",
onFailed: (failureResult) async {
GifLoaderDialogUtils.hideDialog(context);
log("failureResult: ${failureResult.toString()}");
AppToast.showErrorToast(message: failureResult.toString());
log("failureResult: ${failureResult.message.toString()}");
AppToast.showErrorToast(message: failureResult.message.toString());
},
onSuccess: (successResult) async {
log("Payfort: ${successResult.responseMessage}");

@ -171,17 +171,17 @@ class _InsuranceCardState extends State<InsuranceCard> {
SizedBox(
height: 8.5,
),
if (model.insurance[index].isActive == true)
Container(
color: Colors.transparent,
child: DefaultButton(
TranslationBase.of(context).seeDetails,
() => {
getDetails(model.insurance[index]),
},
),
width: double.infinity,
),
// if (model.insurance[index].isActive == true)
// Container(
// color: Colors.transparent,
// child: DefaultButton(
// TranslationBase.of(context).seeDetails,
// () => {
// getDetails(model.insurance[index]),
// },
// ),
// width: double.infinity,
// ),
],
),
),

@ -41,6 +41,7 @@ import 'package:diplomaticquarterapp/uitl/penguin_method_channel.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:diplomaticquarterapp/uitl/utils_new.dart';
import 'package:diplomaticquarterapp/vital_signs/vital_sign.dart';
import 'package:diplomaticquarterapp/widgets/dialogs/covid_consent_dialog.dart';
import 'package:diplomaticquarterapp/widgets/dialogs/location_selection_dialog.dart';
import 'package:diplomaticquarterapp/widgets/dialogs/radio_selection_dialog.dart';
@ -229,6 +230,9 @@ class ServicesView extends StatelessWidget {
} else if (hmgServices.action == 1) {
openLiveCare(context);
} else if (hmgServices.action == 2) {
//todo for temporary basis
// Navigator.push(context, FadePage(page: VitalSigns()));
// initPenguinSDK();
if (projectViewModel.isIndoorNavigationEnabled) {
if (!isLocked) openNavigationProjectSelection(context);

@ -230,36 +230,6 @@ class _LiveCarePatmentPageState extends State<LiveCarePatmentPage> {
),
),
mHeight(32.0),
AutoSizeText(
TranslationBase.of(context).selectedCallType,
maxLines: 1,
minFontSize: 12,
style: TextStyle(
fontSize: SizeConfig.textMultiplier! * 2.0,
fontWeight: FontWeight.w600,
letterSpacing: -0.39,
height: 0.8,
),
),
mHeight(12.0),
Row(
children: <Widget>[
SvgPicture.asset(
getCallTypeImagePath(),
width: 18,
height: 18,
),
mWidth(10),
Text(
getCallTypeText(),
style: TextStyle(
fontSize: 14.0,
letterSpacing: -0.4,
fontWeight: FontWeight.w600,
),
),
],
),
Container(
margin: EdgeInsets.only(top: 16.0),
child: Row(
@ -300,6 +270,36 @@ class _LiveCarePatmentPageState extends State<LiveCarePatmentPage> {
],
),
),
AutoSizeText(
TranslationBase.of(context).selectedCallType,
maxLines: 1,
minFontSize: 12,
style: TextStyle(
fontSize: SizeConfig.textMultiplier! * 2.0,
fontWeight: FontWeight.w600,
letterSpacing: -0.39,
height: 0.8,
),
),
mHeight(12.0),
Row(
children: <Widget>[
SvgPicture.asset(
getCallTypeImagePath(),
width: 18,
height: 18,
),
mWidth(10),
Text(
getCallTypeText(),
style: TextStyle(
fontSize: 14.0,
letterSpacing: -0.4,
fontWeight: FontWeight.w600,
),
),
],
),
mFlex(1),
Text(
TranslationBase.of(context).upComingPayOption,

@ -486,9 +486,9 @@ class _clinic_listState extends State<ClinicList> {
payfortProjectDetailsRespModel: payfortProjectDetailsRespModel,
currency: projectViewModel.user.outSA == 1 ? "AED" : "SAR",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.toString()}");
GifLoaderDialogUtils.hideDialog(localContext!);
AppToast.showErrorToast(message: failureResult.toString());
GifLoaderDialogUtils.hideDialog(context);
log("failureResult: ${failureResult.message.toString()}");
AppToast.showErrorToast(message: failureResult.message.toString());
},
onSuccess: (successResult) async {
GifLoaderDialogUtils.hideDialog(localContext!);

@ -30,6 +30,7 @@ import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:diplomaticquarterapp/uitl/whatsapp_method_channel.dart';
import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart';
import 'package:diplomaticquarterapp/widgets/card/rounded_container.dart';
import 'package:diplomaticquarterapp/widgets/data_display/text.dart';
@ -344,7 +345,18 @@ class _ConfirmLogin extends State<ConfirmLogin> {
sharedPref.setInt(LAST_LOGIN, this.selectedOption); //this.cs.sharedService.setStorage(this.selectedOption, AuthenticationService.LAST_LOGIN);
}
loginWithSMS(type) {
loginWithSMS(type) async {
if (type == 4) {
var channel = WhatsappMethodChannel();
// var whatsappStatus = await channel.isWhatsAppInstalled();
// if(whatsappStatus) {
// print("whatapp is installed");
channel.handleHandShake();
// }else{
// print("whatapp is not installed");
// }
}
//if (!el.disabled) {
if (this.user != null && this.registerd_data == null) {
this.checkUserAuthentication(type);
@ -697,37 +709,37 @@ class _ConfirmLogin extends State<ConfirmLogin> {
}
checkIfUserAgreedBefore(CheckActivationCode result) {
// this.authService.checkIfUserAgreed().then((result) {
// if (result['IsPatientAlreadyAgreed']) {
// goToHome();
// } else {
// this.authService.getUserAgreementContent().then((result) {
// GifLoaderDialogUtils.hideDialog(AppGlobal.context);
// Navigator.pushAndRemoveUntil(
// context,
// FadePage(
// page: UserLoginAgreementPage(
// userAgreementText: result['UserAgreementContent'],
// authenticatedUserObject: authenticatedUserObject,
// appointmentRateViewModel: appointmentRateViewModel,
// selectedOption: selectedOption,
// ),
// ),
// (r) => false);
// }).catchError((err) {
// GifLoaderDialogUtils.hideDialog(context);
// print(err);
// });
// }
// }).catchError((err) {
// GifLoaderDialogUtils.hideDialog(context);
// print(err);
// });
this.authService.checkIfUserAgreed().then((result) {
if (result['IsPatientAlreadyAgreed']) {
goToHome();
} else {
this.authService.getUserAgreementContent().then((result) {
GifLoaderDialogUtils.hideDialog(AppGlobal.context);
Navigator.pushAndRemoveUntil(
context,
FadePage(
page: UserLoginAgreementPage(
userAgreementText: result['UserAgreementContent'],
authenticatedUserObject: authenticatedUserObject,
appointmentRateViewModel: appointmentRateViewModel,
selectedOption: selectedOption,
),
),
(r) => false);
}).catchError((err) {
GifLoaderDialogUtils.hideDialog(context);
print(err);
});
}
}).catchError((err) {
GifLoaderDialogUtils.hideDialog(context);
print(err);
});
// if (result.isNeedUserAgreement == true) {
//move to agreement page.
// // move to agreement page.
// } else {
goToHome();
// goToHome();
// }
}

@ -362,12 +362,12 @@ class _Login extends State<Login> {
projectViewModel.setPrivilege(privilegeList: result);
result = CheckActivationCode.fromJson(result);
result.list.isFamily = false;
this.sharedPref.setString(BLOOD_TYPE,
await this.sharedPref.setString(BLOOD_TYPE,
result.patientBloodType != null ? result.patientBloodType : "");
this.sharedPref.setObject(USER_PROFILE, result.list);
this.sharedPref.setObject(MAIN_USER, result.list);
this.sharedPref.setObject(LOGIN_TOKEN_ID, result.logInTokenID);
this.sharedPref.setString(TOKEN, result.authenticationTokenID);
await this.sharedPref.setObject(USER_PROFILE, result.list);
await this.sharedPref.setObject(MAIN_USER, result.list);
await this.sharedPref.setObject(LOGIN_TOKEN_ID, result.logInTokenID);
await this.sharedPref.setString(TOKEN, result.authenticationTokenID);
await authenticatedUserObject.getUser(getUser: true);
authenticatedUserObject.isLogin = true;
appointmentRateViewModel.isLogin = true;

@ -80,21 +80,23 @@ class AskDoctorPage extends StatelessWidget {
doctor: doctorList,
isLiveCareAppointment: false,
isShowFlag: false,
onTap: () {
GifLoaderDialogUtils.showMyDialog(context);
service.getCallInfoHoursResult(doctorId: _doctor.doctorID, projectId: _doctor.projectID).then((res) {
GifLoaderDialogUtils.hideDialog(context);
Navigator.push(
context,
FadePage(
page: RequestTypePage(doctorList: _doctor),
),
);
}).catchError((err) {
GifLoaderDialogUtils.hideDialog(context);
if (err != null) AppToast.showErrorToast(message: err.toString());
print(err);
});
onTap: () async {
if (await checkIfDoctorAvailable(_doctor, context)) {
GifLoaderDialogUtils.showMyDialog(context);
service.getCallInfoHoursResult(doctorId: _doctor.doctorID, projectId: _doctor.projectID).then((res) {
GifLoaderDialogUtils.hideDialog(context);
Navigator.push(
context,
FadePage(
page: RequestTypePage(doctorList: _doctor),
),
);
}).catchError((err) {
GifLoaderDialogUtils.hideDialog(context);
if (err != null) AppToast.showErrorToast(message: err.toString());
print(err);
});
}
},
);
},
@ -106,6 +108,27 @@ class AskDoctorPage extends StatelessWidget {
);
}
Future<bool> checkIfDoctorAvailable(DoctorList _doctor, BuildContext context) {
bool isAvailable = false;
GifLoaderDialogUtils.showMyDialog(context);
service.isDoctorAvailable(doctorId: _doctor.doctorID, projectId: _doctor.projectID, clinicId: _doctor.clinicID).then((res) {
GifLoaderDialogUtils.hideDialog(context);
print(res['IsDoctorAvailable']);
if (res['IsDoctorAvailable']) {
isAvailable = true;
} else {
isAvailable = false;
AppToast.showErrorToast(message: res['endUserMessage']);
}
}).catchError((err) {
GifLoaderDialogUtils.hideDialog(context);
if (err != null) AppToast.showErrorToast(message: err.toString());
print(err);
});
return Future.value(isAvailable);
}
String getDate(String date) {
DateTime dateObj = DateUtil.convertStringToDate(date);
return DateUtil.getWeekDay(dateObj.weekday) +

@ -330,8 +330,8 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
currency: projectViewModel.authenticatedUserObject.user.outSA == 1 ? "AED" : "SAR",
onFailed: (failureResult) async {
GifLoaderDialogUtils.hideDialog(context);
log("failureResult: ${failureResult.toString()}");
AppToast.showErrorToast(message: failureResult.toString());
log("failureResult: ${failureResult.message.toString()}");
AppToast.showErrorToast(message: failureResult.message.toString());
},
onSuccess: (successResult) async {
log("Payfort: ${successResult.responseMessage}");

@ -1777,7 +1777,7 @@ class AuthProvider with ChangeNotifier {
Future<dynamic> checkIfUserAgreed() async {
Map<String, dynamic> request;
request = {"Region": 1};
request = {"Region": 1, "SessionID": SESSION_ID};
dynamic localRes;
try {
await new BaseAppClient().post(CHECK_USAGE_AGREEMENT, onSuccess: (dynamic response, int statusCode) {

@ -184,12 +184,13 @@ class ClinicListService extends BaseService {
return Future.value(localRes);
}
Future<Map> getInPatientPaymentLink(int projectID, int admissionNo, int orderID, String name, String email, num amount, String nationalID, int clinicID, context) async {
Future<Map> getInPatientPaymentLink(int paymentRequestID, int projectID, int admissionNo, int orderID, String name, String email, num amount, String nationalID, int clinicID, context) async {
Map<String, dynamic> request;
// request = {"ProjectID": projectID, "AdmissionReqNo": admissionReqNo, "AdmissionNo": admissionNo};
request = {
"ProjectID": projectID,
"PaymentRequestId": paymentRequestID,
"ClientOrderID": orderID,
"OrderDescription": "InPatient Advance Payment",
"CustomerName": name,

@ -0,0 +1,34 @@
import 'dart:async';
import 'package:flutter/services.dart';
class WhatsappMethodChannel {
static const MethodChannel _channel = MethodChannel('whats_app_otp');
FutureOr<void> handleHandShake() async {
try {
await _channel.invokeMethod("performHandShake");
} on PlatformException catch (e) {
print("Failed to launch PenguinIn: '${e.message}'.");
}
}
Future<bool> isWhatsAppInstalled() async {
try {
return await _channel.invokeMethod("isWhatsAppInstalled");
} catch (e) {
return false;
}
}
Future<String> startListening() async {
try{
String code = await _channel.invokeMethod("startListening");
print("the code in flutter is ${code}");
return code;
}catch(e){
return "";
}
}
}

@ -0,0 +1,70 @@
// import 'package:flutter/material.dart';
// import 'package:vital_sign_camera/vital_sign_camera.dart';
//
// class VitalSigns extends StatefulWidget {
// const VitalSigns({super.key});
//
// @override
// State<VitalSigns> createState() => _VitalSignState();
// }
//
// class _VitalSignState extends State<VitalSigns> {
// late final VitalSignCameraController _vitalSignCameraController;
// late Future<CameraDevice?> cameraDevice;
//
// @override
// void initState() {
// super.initState();
// cameraDevice = getFrontCamera();
// }
//
// double? _heartRate;
//
// Future<CameraDevice?> getFrontCamera() async {
// if (CameraPermissionStatus.authorized != await requestCameraPermission()) {
// return null;
// }
// return queryCameraDevice(CameraPosition.front);
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// body: Stack(children: [
// VitalSignCamera(
// onCreated: _onVitalSignCameraCreated,
// isActive: true,
// userInfo: UserInfo(
// age: 30, gender: Gender.male, userId: '__YOUR_USER_ID__'),
// config: VitalSignCameraConfig(apiKey: '__YOUR_API_KEY__'),
// device: cameraDevice,
// onVideoFrameProcessed: _onVideoFrameProcessed),
// Center(
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// ElevatedButton(
// onPressed: () {
// setState(() {
// _vitalSignCameraController.startScanning();
// });
// },
// child: const Text('start')),
// Text('Heart rate: $_heartRate'),
// ],
// ),
// ),
// ]),
// );
// }
//
// void _onVideoFrameProcessed(VideoFrameProcessedEvent event) {
// // setState(() {
// // _heartRate = event.healthResult?.health?.vitalSigns.heartRate;
// // });
// }
//
// void _onVitalSignCameraCreated(VitalSignCameraController controller) {
// _vitalSignCameraController = controller;
// }
// }

@ -40,7 +40,7 @@ class MyInAppBrowser extends InAppBrowser {
// static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT
static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWebL/ive/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL LIVE
static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL LIVE
// static String SERVICE_URL = 'https://uat.hmgwebservices.com/payfortforvidaplus/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL UAT VIDA PLUS

@ -5,6 +5,7 @@ import 'package:diplomaticquarterapp/config/size_config.dart';
import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
import 'package:diplomaticquarterapp/theme/colors.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/uitl/whatsapp_method_channel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
@ -102,9 +103,10 @@ class SMSOTP {
child: StatefulBuilder(builder: (context, setState) {
if (displayTime == '') {
startTimer(setState);
// startLister();
if (Platform.isAndroid && type == 1) checkSignature();
if (Platform.isAndroid ) {
if (type == 1) checkSignature();
else if(type == 4) _listenWhatsAppCode();
}
}
return Container(
@ -298,6 +300,15 @@ class SMSOTP {
});
}
void _listenWhatsAppCode(){
WhatsappMethodChannel().startListening().then((message) {
final intRegex = RegExp(r'\d+', multiLine: true);
var otp = SmsVerification.getCode(message, intRegex);
_pinPutController.text = otp;
onSuccess(otp);
});
}
// startLister() {
// var signature = checkSignature();
//

@ -0,0 +1 @@
TODO: Add your license here.

@ -0,0 +1,4 @@
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx

@ -0,0 +1,69 @@
group 'ai.panoptic.vital_sign_camera'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.5.20'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 34
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
minSdkVersion 24
}
}
dependencies {
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.camera:camera-core:1.0.2'
implementation 'com.google.mlkit:face-detection:16.1.2'
implementation 'com.android.volley:volley:1.2.1'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(":vital-sign-engine")
implementation "androidx.camera:camera-core:1.1.0-beta02"
implementation "androidx.camera:camera-camera2:1.1.0-beta02"
implementation "androidx.camera:camera-lifecycle:1.1.0-beta02"
implementation "androidx.camera:camera-video:1.1.0-beta02"
implementation "androidx.camera:camera-view:1.1.0-beta02"
implementation "androidx.camera:camera-extensions:1.1.0-beta02"
implementation "androidx.exifinterface:exifinterface:1.3.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.5.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
}

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

@ -0,0 +1,234 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# 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 ;; #(
MSYS* | 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" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@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 Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@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="-Xmx64m" "-Xms64m"
@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 execute
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 execute
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
: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 %*
: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,2 @@
configurations.maybeCreate("default")
artifacts.add("default", file('vital-sign-engine-debug.aar'))

@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ai.panoptic.vital_sign_camera">
</manifest>

@ -0,0 +1,108 @@
package ai.panoptic.vital_sign_camera
import ai.panoptic.wvs.camera.*
import ai.panoptic.wvs.engine.Converter
import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.view.View
import androidx.annotation.RequiresApi
import androidx.lifecycle.Lifecycle
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.platform.PlatformView
@RequiresApi(Build.VERSION_CODES.O)
class FlutterVitalSignCamera internal constructor(
context: Context,
messenger: BinaryMessenger,
id: Int,
props: Map<String, Any>,
lifecycle: Lifecycle
) : PlatformView, MethodChannel.MethodCallHandler, EventChannel.StreamHandler, VitalSignCameraEventHandler {
private val camera: VitalSignCamera
private val methodChannel: MethodChannel
private var eventSink: EventChannel.EventSink? = null
private val mainThread = Handler(Looper.getMainLooper())
override fun getView(): View {
return camera
}
init {
camera = VitalSignCamera(context, MLKitFaceDetector(), lifecycle, this)
methodChannel = MethodChannel(messenger, "ai.panoptic/channel/flutter_vital_sign_camera_$id")
methodChannel.setMethodCallHandler(this)
val eventChannel = EventChannel(messenger, "ai.panoptic/channel/flutter_vital_sign_camera_processed_frame_event_$id")
eventChannel.setStreamHandler(this)
camera.setProps(props)
}
override fun onMethodCall(methodCall: MethodCall, result: MethodChannel.Result) {
when (methodCall.method) {
"startScanning" -> {
camera.startStartScanning()
.thenAccept { result.success(null) }
.exceptionally {
result.error("-1", it.message, it.cause)
return@exceptionally null
}
}
"stopScanning" -> {
camera.stopScanning()
.thenAccept { result.success(null) }
.exceptionally {
result.error("-2", it.message, it.cause)
return@exceptionally null
}
}
"configure" -> {
val arguments = methodCall.arguments as? Map<String, Any>
arguments?.let {
camera.setProps(it)
}
}
else -> {
result.notImplemented()
}
}
}
override fun dispose() {
// camera.destroy()
}
override fun onVideoFrameProcessed(result: ai.panoptic.wvs.engine.ProcessFrameResult): kotlin.Unit {
// Already handled in onEvent.
// No need to handle here.
}
override fun onEvent(cameraView: VitalSignCamera, eventName: String, event: Map<String,Any>?) {
when(eventName) {
"videoFrameProcessed" -> {
eventSink?.let {
mainThread.post {
it.success(event)
}
}
}
}
}
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
eventSink = events
}
override fun onCancel(arguments: Any?) {
eventSink = null
}
}

@ -0,0 +1,165 @@
package ai.panoptic.vital_sign_camera;
import static com.google.mlkit.vision.face.FaceContour.FACE;
import android.graphics.PointF;
import android.media.Image;
import android.util.ArraySet;
import com.google.android.gms.tasks.Task;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.face.Face;
import com.google.mlkit.vision.face.FaceContour;
import com.google.mlkit.vision.face.FaceDetection;
import com.google.mlkit.vision.face.FaceDetector;
import com.google.mlkit.vision.face.FaceDetectorOptions;
import java.util.List;
import java.util.Set;
import ai.panoptic.wvs.engine.EyesOpenProbability;
import ai.panoptic.wvs.engine.FaceDetectorFeature;
import ai.panoptic.wvs.engine.HeadEulerAngle;
import ai.panoptic.wvs.engine.NormalizedFacebox;
import ai.panoptic.wvs.engine.VitalSignFaceDetector;
public class MLKitFaceDetector implements VitalSignFaceDetector {
ai.panoptic.wvs.engine.Face face = null;
FaceDetectorOptions options =
new FaceDetectorOptions.Builder()
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST)
.setContourMode(FaceDetectorOptions.CONTOUR_MODE_NONE)
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
.setMinFaceSize(0.15f)
.build();
FaceDetector faceDetector = FaceDetection.getClient(options);
public ai.panoptic.wvs.engine.Face detectFace(Image mediaImage, int rotationDegrees) {
if (mediaImage == null) {
return null;
}
float width = mediaImage.getWidth();
float height = mediaImage.getHeight();
if (rotationDegrees == 270 || rotationDegrees == 90) {
width = mediaImage.getHeight();
height = mediaImage.getWidth();
}
final float _width = width;
final float _height = height;
InputImage image = InputImage.fromMediaImage(mediaImage, rotationDegrees);
Task<List<Face>> task = faceDetector.process(image);
task.addOnCompleteListener( result -> {
if (result.isCanceled()) {
return;
}
if (!result.isSuccessful()) {
return;
}
if (!result.isComplete()) {
return;
}
try {
List<Face> faces = result.getResult();
if (faces.isEmpty()) {
this.face = null;
return;
}
Face face = faces.get(0);
this.face = createFace(face, _width, _height);
} catch (Exception e) {
e.printStackTrace();
this.face = null;
}
});
return face;
}
static private ai.panoptic.wvs.engine.Face createFace(Face face, float _width, float _height) {
FaceContour contour = face.getContour(FACE);
NormalizedFacebox facebox = new NormalizedFacebox();
float minX = _width;
float minY = _height;
float maxX = 0;
float maxY = 0;
if (contour != null) {
for (PointF p : contour.getPoints()) {
if (p.x < minX) {
minX = p.x;
}
if (p.y < minY) {
minY = p.y;
}
if (p.x > maxX) {
maxX = p.x;
}
if (p.y > maxY) {
maxY = p.y;
}
}
} else {
minX = face.getBoundingBox().left;
minY = face.getBoundingBox().top;
maxX = face.getBoundingBox().right;
maxY = face.getBoundingBox().bottom;
}
facebox.xCenter = (minX + (maxX - minX) / 2.0f) / _width;
facebox.yCenter = (minY + (maxY - minY) / 2.0f) / _height;
facebox.width = (maxX - minX) / _width;
facebox.height = (maxY - minY) / _height;
ai.panoptic.wvs.engine.Face result = new ai.panoptic.wvs.engine.Face(facebox);
result.setEulerAngle(
new HeadEulerAngle(
face.getHeadEulerAngleX(),
face.getHeadEulerAngleY(),
face.getHeadEulerAngleY()
)
);
if (face.getLeftEyeOpenProbability() != null && face.getRightEyeOpenProbability() != null) {
result.setEyesOpenProbability(
new EyesOpenProbability(
face.getLeftEyeOpenProbability(),
face.getRightEyeOpenProbability()
)
);
}
return result;
}
@Override
public Set<FaceDetectorFeature> supportedFeatures() {
ArraySet<FaceDetectorFeature> features = new ArraySet<FaceDetectorFeature>();
features.add(FaceDetectorFeature.eyeOpenProbability);
features.add(FaceDetectorFeature.eulerAngle);
return features;
}
@Override
public NormalizedFacebox detect(Image mediaImage, int rotationDegrees) {
detectFace(mediaImage, rotationDegrees);
if (face == null) {
return null;
}
return face.getFacebox();
}
}

@ -0,0 +1,145 @@
package ai.panoptic.vital_sign_camera
import ai.panoptic.wvs.camera.availableCameraDevices
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.annotation.NonNull
import androidx.core.content.ContextCompat
import androidx.lifecycle.*
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
/** VitalSignCameraPlugin */
class VitalSignCameraPlugin: FlutterPlugin, MethodCallHandler, ActivityAware,
RequestPermissionsResultListener {
companion object {
const val TAG = "VitalSignCameraPlugin"
fun parsePermissionStatus(status: Int): String {
return when (status) {
PackageManager.PERMISSION_DENIED -> "denied"
PackageManager.PERMISSION_GRANTED -> "authorized"
else -> "not-determined"
}
}
}
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel
private lateinit var pluginBinding: FlutterPlugin.FlutterPluginBinding
private lateinit var context: Context
private lateinit var activity: Activity
private lateinit var activityBinding:ActivityPluginBinding
private val coroutineScope = CoroutineScope(Dispatchers.Main)
private var requestCode = 1
private var permissionRequests = HashMap<Int, Result>()
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
Log.d("VitalSignCameraPlugin", "onAttachedToEngine")
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "vital_sign_camera_plugin")
channel.setMethodCallHandler(this)
pluginBinding = flutterPluginBinding
context = flutterPluginBinding.applicationContext
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
Log.d(TAG, "onAttachedToActivity")
val lifecycle: Lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(binding)
pluginBinding.platformViewRegistry.registerViewFactory(
"ai.panoptic/flutter_vital_sign_camera",
VitalSignCameraFactory(pluginBinding.binaryMessenger, lifecycle)
)
activity = binding.activity
activityBinding = binding
activityBinding.addRequestPermissionsResultListener(this)
}
override fun onDetachedFromActivityForConfigChanges() {}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {}
override fun onDetachedFromActivity() {
activityBinding.removeRequestPermissionsResultListener(this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"availableCameraDevices" -> {
coroutineScope.launch {
val devices = availableCameraDevices(context)
val returnValue = devices.map { it.map }
Log.d(TAG, "$returnValue")
result.success(returnValue)
}
}
"getCameraPermissionStatus" -> {
Log.d(TAG, "getCameraPermissionStatus")
val status =
parsePermissionStatus(
ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA))
result.success(status)
}
"requestCameraPermission" -> {
Log.d(TAG, "requestCameraPermission")
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// API 21 and below always grants permission on app install
result.success("authorized")
}
activity.requestPermissions(arrayOf(Manifest.permission.CAMERA), requestCode)
permissionRequests[requestCode] = result
requestCode += 1
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
): Boolean {
permissionRequests[requestCode]?.let {
val permissionStatus = if (grantResults.isNotEmpty()) grantResults[0] else PackageManager.PERMISSION_DENIED
it.success(parsePermissionStatus(permissionStatus))
permissionRequests.remove(requestCode)
return true
}
return false
}
}

@ -0,0 +1,218 @@
//
// MLKitFaceDetector.swift
// VitalSignEngineCore
//
// Created by Eddie Lau on 24/8/2022.
//
import Foundation
import MLKitFaceDetection
import MLKitVision
import VitalSignEngineCore
public class MLKitFaceDetector : VitalSignFaceDetector {
public typealias Face = MLKitFace
public let supportedFeatures: Set<VitalSignEngineCore.FaceDetectorFeature>
= [.eyesOpenProbability, .eularAngle]
public init() {
}
public let maxDetectionHeight:CGFloat = 240
let fps = Fps(name: "MLKitFaceDetector")
lazy var faceDetector:FaceDetector = {
let option = FaceDetectorOptions()
option.contourMode = .all
option.classificationMode = .all
option.landmarkMode = .none
option.performanceMode = .fast
return FaceDetector.faceDetector(options: option)
}()
var face:Face? {
didSet {
fps.tick()
}
}
public var frameRate: Double? { fps.lastReportedAverage }
public var maxConcurrency = 2
var jobCount = 0
public func detect(from frame: UIImage) -> Face? {
guard jobCount < maxConcurrency else {
return face
}
jobCount += 1
DispatchQueue.global().async {
let scaledFrame = self.scaled(videoFrame: frame)
let frameSize = scaledFrame.size
let image = VisionImage(image: scaledFrame)
image.orientation = image.orientation
DispatchQueue.main.async {
self.faceDetector.process(image) { faces, error in
guard let face = faces?.first else {
self.face = nil
self.jobCount -= 1
return
}
self.face = MLKitFace(face: face, frameSize: frameSize)
self.jobCount -= 1
}
}
}
return face
}
func scaled(videoFrame frame:UIImage) -> UIImage {
var scale = CGFloat(1.0)
if frame.size.height > maxDetectionHeight {
scale = maxDetectionHeight / frame.size.height
}
let scaledScale = CGSize(width:frame.size.width * scale, height:frame.size.height * scale)
return frame.resizedImage(size: scaledScale)!
}
}
public struct MLKitFaceLandmarks: FaceLandmarks {
public typealias ContourType = FaceContour
let mlkitFace:MLKitFaceDetection.Face
public let videoFrameSize: CGSize
init(mlkitFace: MLKitFaceDetection.Face, videoFrameSize: CGSize) {
self.mlkitFace = mlkitFace
self.videoFrameSize = videoFrameSize
}
public var faceOval: FaceContour? { mlkitFace.contour(ofType: .face) }
public func contour(of type: VitalSignEngineCore.FaceLandmarkType) -> FaceContour? {
guard let contourType = type.asContourType else { return nil }
return mlkitFace.contour(ofType: contourType)
}
}
public class MLKitFace : FaceProtocol {
public typealias ContourType = FaceContour
let mlkitFace:MLKitFaceDetection.Face
public let faceBox: NormalizedFaceBox
public let faceLandmarks: MLKitFaceLandmarks
public let eulerAngle: (x: CGFloat, y: CGFloat, z: CGFloat)?
public let eyesOpenProbability: (leftEye:CGFloat, rightEye:CGFloat)?
init?(face:MLKitFaceDetection.Face, frameSize:CGSize) {
self.mlkitFace = face
self.faceLandmarks = MLKitFaceLandmarks(mlkitFace: face, videoFrameSize: frameSize)
guard let faceContour = face.contour(ofType: FaceContourType.face) else {
return nil
}
let eyesOpenPropbability: (leftEye:CGFloat, rightEye:CGFloat)?
if face.hasLeftEyeOpenProbability && face.hasRightEyeOpenProbability {
eyesOpenPropbability = (face.leftEyeOpenProbability, face.rightEyeOpenProbability)
} else {
eyesOpenPropbability = nil
}
self.eyesOpenProbability = eyesOpenPropbability
let eulerAngle: (x:CGFloat, y:CGFloat, z:CGFloat)?
if face.hasHeadEulerAngleX && face.hasHeadEulerAngleY && face.hasHeadEulerAngleZ {
eulerAngle = (face.headEulerAngleX, face.headEulerAngleY, face.headEulerAngleZ)
} else {
eulerAngle = nil
}
self.eulerAngle = eulerAngle
self.faceBox = faceContour.toFacebox(frameSize: frameSize)
}
}
fileprivate extension MLKitFaceDetection.FaceContour {
func toFacebox(frameSize:CGSize) -> NormalizedFaceBox {
var minX = CGFloat.greatestFiniteMagnitude
var minY = CGFloat.greatestFiniteMagnitude
var maxX = -CGFloat.greatestFiniteMagnitude
var maxY = -CGFloat.greatestFiniteMagnitude
points.forEach { point in
minX = min(minX, point.x)
minY = min(minY, point.y)
maxX = max(maxX, point.x)
maxY = max(maxY, point.y)
}
return NormalizedFaceBox(
xCenter: ((maxX - minX)/2 + minX) / frameSize.width,
yCenter: ((maxY - minY)/2 + minY) / frameSize.height,
width: (maxX - minX) / frameSize.width,
height: (maxY - minY) / frameSize.height
)
}
}
fileprivate extension UIImage {
func resizedImage(size: CGSize) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(origin: .zero, size: size))
let image = UIGraphicsGetImageFromCurrentImageContext()
return image?.data.flatMap(UIImage.init) // This line is copied from MLKit, Not sure why is needed
}
private var data: Data? {
#if swift(>=4.2)
return pngData() ?? jpegData(compressionQuality: Constant.jpegCompressionQuality)
#else
return pngData() ?? jpegData(compressionQuality: Constant.jpegCompressionQuality)
#endif // swift(>=4.2)
}
private enum Constant {
static let jpegCompressionQuality: CGFloat = 0.8
}
}
extension VisionPoint : FaceContourPoint {
}
extension FaceContour : Contour {
}
extension VitalSignEngineCore.FaceLandmarkType {
var asContourType:MLKitFaceDetection.FaceContourType? {
switch self {
case .faceOval: return .face
case .leftEyebrowTop: return .leftEyebrowTop
case .leftEyebrowBottom: return .leftEyebrowBottom
case .rightEyebrowTop: return .rightEyebrowTop
case .rightEyebrowBottom: return .rightEyebrowBottom
case .leftEye: return .leftEye
case .rightEye: return .rightEye
case .upperLipTop: return .upperLipTop
case .upperLipBottom: return .upperLipBottom
case .lowerLipTop: return .lowerLipTop
case .lowerLipBottom: return .lowerLipBottom
case .noseBridge: return .noseBridge
case .noseBottom: return .noseBottom
case .leftCheek: return .leftCheek
case .rightCheek: return .rightCheek
@unknown default: return nil
}
}
}

@ -0,0 +1,91 @@
import Flutter
import UIKit
import VitalSignEngineCore
public class SwiftVitalSignCameraPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "vital_sign_camera_plugin", binaryMessenger: registrar.messenger())
let instance = SwiftVitalSignCameraPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
registrar.register(VitalSignCameraFactory(messenger: registrar.messenger()), withId: "ai.panoptic/flutter_vital_sign_camera")
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "availableCameraDevices" {
let devices = VitalSignCamera.availableCameraDevices()
result(devices.map({ $0.flutterCompatibleDict }))
}
if call.method == "requestCameraPermission" {
VitalSignCamera.requestCameraPermission().done { status in
result(status.rawValue)
}.catch { error in
result(FlutterError(code: "\(error.code)", message: error.message, details: nil))
}
}
if call.method == "getCameraPermissionStatus" {
let status = VitalSignCamera.getCameraPermissionStatus()
result(status.rawValue)
}
}
}
fileprivate extension CameraDevice {
var flutterCompatibleDict:[String:Any] {
[
"id": id,
"devices": devices.map { $0.rawValue },
"position": position.rawValue,
"name": name,
"hasFlash": NSNumber(value: hasFlash),
"hasTorch": NSNumber(value: hasTorch),
"minZoom": NSNumber(value: Double(minZoom)),
"neutralZoom": NSNumber(value: Double(neutralZoom)),
"maxZoom": NSNumber(value: Double(maxZoom)),
"isMultiCam": NSNumber(value: isMultiCam),
"supportsParallelVideoProcessing": NSNumber(value: supportsParallelVideoProcessing),
"supportsDepthCapture": NSNumber(value: supportsDepthCapture),
"supportsRawCapture": NSNumber(value: supportsRawCapture),
"supportsLowLightBoost": NSNumber(value: supportsLowLightBoost),
"supportsFocus": NSNumber(value: supportsFocus),
"formats": formats.map { format -> [String: Any] in
format.flutterCompatibleDict
},
]
}
}
fileprivate extension CameraCaptureFormat {
var flutterCompatibleDict:[String:Any] {
var dict:[String:Any] = [
"videoStabilizationModes": videoStabilizationModes.map { $0.rawValue },
"autoFocusSystem": autoFocusSystem.rawValue,
"photoHeight": NSNumber(value: Double(photoHeight)),
"photoWidth": NSNumber(value: Double(photoWidth)),
"videoHeight": NSNumber(value: Double(videoHeight)),
"videoWidth": NSNumber(value: Double(videoWidth)),
"maxISO": NSNumber(value: Int(maxISO)),
"minISO": NSNumber(value: Int(minISO)),
"fieldOfView": NSNumber(value: Double(fieldOfView)),
"maxZoom": NSNumber(value: Double(maxZoom)),
"colorSpaces": colorSpaces.map { $0.rawValue },
"supportsVideoHDR": NSNumber(value: supportsVideoHDR),
"supportsPhotoHDR": NSNumber(value: supportsPhotoHDR),
"frameRateRanges": frameRateRanges.map {
[
"minFrameRate": NSNumber(value: Int($0.minFrameRate)),
"maxFrameRate": NSNumber(value: Int($0.maxFrameRate)),
]
},
"pixelFormat": pixelFormat.rawValue,
]
if let isHighestPhotoQualitySupported = isHighestPhotoQualitySupported {
dict["isHighestPhotoQualitySupported"] = isHighestPhotoQualitySupported
}
return dict
}
}

@ -0,0 +1,37 @@
//
// VitalSignCameraFactory.swift
// vital_sign_camera
//
// Created by Eddie Lau on 24/1/2023.
//
import Foundation
import Foundation
import Flutter
import UIKit
class VitalSignCameraFactory: NSObject, FlutterPlatformViewFactory {
private var messenger: FlutterBinaryMessenger
init(messenger: FlutterBinaryMessenger) {
self.messenger = messenger
super.init()
}
func create(
withFrame frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?
) -> FlutterPlatformView {
return FlutterVitalSignCamera(
frame: frame,
viewIdentifier: viewId,
arguments: args,
binaryMessenger: messenger)
}
func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
FlutterStandardMessageCodec.sharedInstance()
}
}

@ -0,0 +1,4 @@
#import <Flutter/Flutter.h>
@interface VitalSignCameraPlugin : NSObject<FlutterPlugin>
@end

@ -0,0 +1,15 @@
#import "VitalSignCameraPlugin.h"
#if __has_include(<vital_sign_camera/vital_sign_camera-Swift.h>)
#import <vital_sign_camera/vital_sign_camera-Swift.h>
#else
// Support project import fallback if the generated compatibility header
// is not copied when this plugin is created as a library.
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
#import "vital_sign_camera-Swift.h"
#endif
@implementation VitalSignCameraPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftVitalSignCameraPlugin registerWithRegistrar:registrar];
}
@end

@ -0,0 +1,411 @@
#if 0
#elif defined(__arm64__) && __arm64__
// Generated by Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
#ifndef VITALSIGNENGINECORE_SWIFT_H
#define VITALSIGNENGINECORE_SWIFT_H
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
#if !defined(__has_include)
# define __has_include(x) 0
#endif
#if !defined(__has_attribute)
# define __has_attribute(x) 0
#endif
#if !defined(__has_feature)
# define __has_feature(x) 0
#endif
#if !defined(__has_warning)
# define __has_warning(x) 0
#endif
#if __has_include(<swift/objc-prologue.h>)
# include <swift/objc-prologue.h>
#endif
#pragma clang diagnostic ignored "-Wauto-import"
#if defined(__OBJC__)
#include <Foundation/Foundation.h>
#endif
#if defined(__cplusplus)
#include <cstdint>
#include <cstddef>
#include <cstdbool>
#include <cstring>
#include <stdlib.h>
#include <new>
#include <type_traits>
#else
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#endif
#if defined(__cplusplus)
#if defined(__arm64e__) && __has_include(<ptrauth.h>)
# include <ptrauth.h>
#else
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
# ifndef __ptrauth_swift_value_witness_function_pointer
# define __ptrauth_swift_value_witness_function_pointer(x)
# endif
# ifndef __ptrauth_swift_class_method_pointer
# define __ptrauth_swift_class_method_pointer(x)
# endif
#pragma clang diagnostic pop
#endif
#endif
#if !defined(SWIFT_TYPEDEFS)
# define SWIFT_TYPEDEFS 1
# if __has_include(<uchar.h>)
# include <uchar.h>
# elif !defined(__cplusplus)
typedef uint_least16_t char16_t;
typedef uint_least32_t char32_t;
# endif
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
#endif
#if !defined(SWIFT_PASTE)
# define SWIFT_PASTE_HELPER(x, y) x##y
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
#endif
#if !defined(SWIFT_METATYPE)
# define SWIFT_METATYPE(X) Class
#endif
#if !defined(SWIFT_CLASS_PROPERTY)
# if __has_feature(objc_class_property)
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
# else
# define SWIFT_CLASS_PROPERTY(...)
# endif
#endif
#if !defined(SWIFT_RUNTIME_NAME)
# if __has_attribute(objc_runtime_name)
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
# else
# define SWIFT_RUNTIME_NAME(X)
# endif
#endif
#if !defined(SWIFT_COMPILE_NAME)
# if __has_attribute(swift_name)
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
# else
# define SWIFT_COMPILE_NAME(X)
# endif
#endif
#if !defined(SWIFT_METHOD_FAMILY)
# if __has_attribute(objc_method_family)
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
# else
# define SWIFT_METHOD_FAMILY(X)
# endif
#endif
#if !defined(SWIFT_NOESCAPE)
# if __has_attribute(noescape)
# define SWIFT_NOESCAPE __attribute__((noescape))
# else
# define SWIFT_NOESCAPE
# endif
#endif
#if !defined(SWIFT_RELEASES_ARGUMENT)
# if __has_attribute(ns_consumed)
# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed))
# else
# define SWIFT_RELEASES_ARGUMENT
# endif
#endif
#if !defined(SWIFT_WARN_UNUSED_RESULT)
# if __has_attribute(warn_unused_result)
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
# else
# define SWIFT_WARN_UNUSED_RESULT
# endif
#endif
#if !defined(SWIFT_NORETURN)
# if __has_attribute(noreturn)
# define SWIFT_NORETURN __attribute__((noreturn))
# else
# define SWIFT_NORETURN
# endif
#endif
#if !defined(SWIFT_CLASS_EXTRA)
# define SWIFT_CLASS_EXTRA
#endif
#if !defined(SWIFT_PROTOCOL_EXTRA)
# define SWIFT_PROTOCOL_EXTRA
#endif
#if !defined(SWIFT_ENUM_EXTRA)
# define SWIFT_ENUM_EXTRA
#endif
#if !defined(SWIFT_CLASS)
# if __has_attribute(objc_subclassing_restricted)
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# else
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# endif
#endif
#if !defined(SWIFT_RESILIENT_CLASS)
# if __has_attribute(objc_class_stub)
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub))
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME)
# else
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME)
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME)
# endif
#endif
#if !defined(SWIFT_PROTOCOL)
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
#endif
#if !defined(SWIFT_EXTENSION)
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
#endif
#if !defined(OBJC_DESIGNATED_INITIALIZER)
# if __has_attribute(objc_designated_initializer)
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
# else
# define OBJC_DESIGNATED_INITIALIZER
# endif
#endif
#if !defined(SWIFT_ENUM_ATTR)
# if __has_attribute(enum_extensibility)
# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility)))
# else
# define SWIFT_ENUM_ATTR(_extensibility)
# endif
#endif
#if !defined(SWIFT_ENUM)
# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# if __has_feature(generalized_swift_name)
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# else
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility)
# endif
#endif
#if !defined(SWIFT_UNAVAILABLE)
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
#endif
#if !defined(SWIFT_UNAVAILABLE_MSG)
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
#endif
#if !defined(SWIFT_AVAILABILITY)
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
#endif
#if !defined(SWIFT_WEAK_IMPORT)
# define SWIFT_WEAK_IMPORT __attribute__((weak_import))
#endif
#if !defined(SWIFT_DEPRECATED)
# define SWIFT_DEPRECATED __attribute__((deprecated))
#endif
#if !defined(SWIFT_DEPRECATED_MSG)
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
#endif
#if !defined(SWIFT_DEPRECATED_OBJC)
# if __has_feature(attribute_diagnose_if_objc)
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
# else
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
# endif
#endif
#if defined(__OBJC__)
#if !defined(IBSegueAction)
# define IBSegueAction
#endif
#endif
#if !defined(SWIFT_EXTERN)
# if defined(__cplusplus)
# define SWIFT_EXTERN extern "C"
# else
# define SWIFT_EXTERN extern
# endif
#endif
#if !defined(SWIFT_CALL)
# define SWIFT_CALL __attribute__((swiftcall))
#endif
#if !defined(SWIFT_INDIRECT_RESULT)
# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result))
#endif
#if !defined(SWIFT_CONTEXT)
# define SWIFT_CONTEXT __attribute__((swift_context))
#endif
#if !defined(SWIFT_ERROR_RESULT)
# define SWIFT_ERROR_RESULT __attribute__((swift_error_result))
#endif
#if defined(__cplusplus)
# define SWIFT_NOEXCEPT noexcept
#else
# define SWIFT_NOEXCEPT
#endif
#if !defined(SWIFT_C_INLINE_THUNK)
# if __has_attribute(always_inline)
# if __has_attribute(nodebug)
# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug))
# else
# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline))
# endif
# else
# define SWIFT_C_INLINE_THUNK inline
# endif
#endif
#if defined(_WIN32)
#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL)
# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport)
#endif
#else
#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL)
# define SWIFT_IMPORT_STDLIB_SYMBOL
#endif
#endif
#if defined(__OBJC__)
#if __has_feature(objc_modules)
#if __has_warning("-Watimport-in-framework-header")
#pragma clang diagnostic ignored "-Watimport-in-framework-header"
#endif
@import AVFoundation;
@import CoreFoundation;
@import CoreMedia;
@import Dispatch;
@import ObjectiveC;
@import UIKit;
#endif
#endif
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
#if __has_warning("-Wpragma-clang-attribute")
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
#endif
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wnullability"
#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
#if __has_attribute(external_source_symbol)
# pragma push_macro("any")
# undef any
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="VitalSignEngineCore",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
# pragma pop_macro("any")
#endif
#if defined(__OBJC__)
SWIFT_CLASS("_TtC19VitalSignEngineCore12CameraQueues")
@interface CameraQueues : NSObject
/// The serial execution queue for the camera preview layer (input stream) as well as output processing of photos.
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull cameraQueue;)
+ (dispatch_queue_t _Nonnull)cameraQueue SWIFT_WARN_UNUSED_RESULT;
/// The serial execution queue for output processing of videos for recording.
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull videoQueue;)
+ (dispatch_queue_t _Nonnull)videoQueue SWIFT_WARN_UNUSED_RESULT;
/// The serial execution queue for output processing of videos for frame processing.
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull frameProcessorQueue;)
+ (dispatch_queue_t _Nonnull)frameProcessorQueue SWIFT_WARN_UNUSED_RESULT;
/// The serial execution queue for output processing of audio buffers.
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull audioQueue;)
+ (dispatch_queue_t _Nonnull)audioQueue SWIFT_WARN_UNUSED_RESULT;
/// The serial execution queue for output processing of audio buffers.
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull recordingQueue;)
+ (dispatch_queue_t _Nonnull)recordingQueue SWIFT_WARN_UNUSED_RESULT;
/// The serial execution queue for output processing of audio buffers.
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull simulatorQueue;)
+ (dispatch_queue_t _Nonnull)simulatorQueue SWIFT_WARN_UNUSED_RESULT;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end
@class NSCoder;
SWIFT_CLASS("_TtC19VitalSignEngineCore10CameraView")
@interface CameraView : UIView
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly) Class _Nonnull layerClass;)
+ (Class _Nonnull)layerClass SWIFT_WARN_UNUSED_RESULT;
- (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)_ OBJC_DESIGNATED_INITIALIZER SWIFT_UNAVAILABLE;
- (void)willMoveToSuperview:(UIView * _Nullable)newSuperview;
@end
@class UIPinchGestureRecognizer;
@interface CameraView (SWIFT_EXTENSION(VitalSignEngineCore))
- (void)onPinch:(UIPinchGestureRecognizer * _Nonnull)gesture;
- (void)zoomWithFactor:(CGFloat)factor animated:(BOOL)animated;
@end
@class AVCaptureOutput;
@class AVCaptureConnection;
@interface CameraView (SWIFT_EXTENSION(VitalSignEngineCore)) <AVCaptureAudioDataOutputSampleBufferDelegate, AVCaptureVideoDataOutputSampleBufferDelegate>
- (void)captureOutput:(AVCaptureOutput * _Nonnull)captureOutput didOutputSampleBuffer:(CMSampleBufferRef _Nonnull)sampleBuffer fromConnection:(AVCaptureConnection * _Nonnull)_;
@end
SWIFT_CLASS("_TtC19VitalSignEngineCore15VitalSignCamera")
@interface VitalSignCamera : UIView
- (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder SWIFT_UNAVAILABLE;
- (void)layoutSubviews;
@end
#endif
#if __has_attribute(external_source_symbol)
# pragma clang attribute pop
#endif
#if defined(__cplusplus)
#endif
#pragma clang diagnostic pop
#endif
#else
#error unsupported Swift architecture
#endif

@ -0,0 +1,4 @@
framework module VitalSignEngineCore {
header "VitalSignEngineCore-Swift.h"
requires objc
}

@ -0,0 +1,183 @@
/* Class = "UILabel"; text = "Continuously monitors exposure levels and automatically adjusts exposure when necessary."; ObjectID = "2ad-p5-WH5"; */
"2ad-p5-WH5.text" = "Continuously monitors exposure levels and automatically adjusts exposure when necessary.";
/* Class = "UILabel"; text = "White Balance"; ObjectID = "4ie-UM-xw1"; */
"4ie-UM-xw1.text" = "White Balance";
/* Class = "UILabel"; text = "Front"; ObjectID = "55X-XR-Xoe"; */
"55X-XR-Xoe.text" = "Front";
/* Class = "UITableViewController"; title = "Preview Layer Gravity"; ObjectID = "5qf-l9-Bpt"; */
"5qf-l9-Bpt.title" = "Preview Layer Gravity";
/* Class = "UILabel"; text = "Show the camera preview by preserving its aspect ratio and fits it within the layer's bounds."; ObjectID = "6I3-ak-vEx"; */
"6I3-ak-vEx.text" = "Show the camera preview by preserving its aspect ratio and fits it within the layer's bounds.";
/* Class = "UILabel"; text = "Continuous Auto"; ObjectID = "6yD-61-CEf"; */
"6yD-61-CEf.text" = "Continuous Auto";
/* Class = "UILabel"; text = "White Balance"; ObjectID = "77e-kN-xI5"; */
"77e-kN-xI5.text" = "White Balance";
/* Class = "UILabel"; text = "Preview Gravity"; ObjectID = "7AW-UQ-WfA"; */
"7AW-UQ-WfA.text" = "Preview Gravity";
/* Class = "UILabel"; text = "Lens Aperture"; ObjectID = "7ZB-LO-AYF"; */
"7ZB-LO-AYF.text" = "Lens Aperture";
/* Class = "UINavigationItem"; title = "Preview Gravity"; ObjectID = "7aV-Vw-b2w"; */
"7aV-Vw-b2w.title" = "Preview Gravity";
/* Class = "UINavigationItem"; title = "Camera"; ObjectID = "8D6-fu-CJu"; */
"8D6-fu-CJu.title" = "Camera";
/* Class = "UILabel"; text = "Medium"; ObjectID = "9xa-bl-6eJ"; */
"9xa-bl-6eJ.text" = "Medium";
/* Class = "UITableViewSection"; headerTitle = "Camera"; ObjectID = "AKs-Pq-lcR"; */
"AKs-Pq-lcR.headerTitle" = "Camera";
/* Class = "UILabel"; text = "640x480"; ObjectID = "B6a-KT-T4m"; */
"B6a-KT-T4m.text" = "640x480";
/* Class = "UILabel"; text = "Face Detector"; ObjectID = "Byq-a3-CTH"; */
"Byq-a3-CTH.text" = "Face Detector";
/* Class = "UILabel"; text = "1920x1080"; ObjectID = "Dp9-9b-EEt"; */
"Dp9-9b-EEt.text" = "1920x1080";
/* Class = "UILabel"; text = "A mode that locks the white balance state."; ObjectID = "FOH-2X-R88"; */
"FOH-2X-R88.text" = "A mode that locks the white balance state.";
/* Class = "UILabel"; text = "Duration"; ObjectID = "FPh-cx-ffz"; */
"FPh-cx-ffz.text" = "Duration";
/* Class = "UILabel"; text = "Exposure"; ObjectID = "Hmc-Mc-AME"; */
"Hmc-Mc-AME.text" = "Exposure";
/* Class = "UILabel"; text = "Resolution"; ObjectID = "J12-De-6Ah"; */
"J12-De-6Ah.text" = "Resolution";
/* Class = "UITextField"; text = "100"; ObjectID = "J2A-ot-v0j"; */
"J2A-ot-v0j.text" = "100";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "J5t-dB-TfS"; */
"J5t-dB-TfS.text" = "30 fps";
/* Class = "UILabel"; text = "Frame Rate"; ObjectID = "JgS-aW-Prv"; */
"JgS-aW-Prv.text" = "Frame Rate";
/* Class = "UILabel"; text = "Video Size"; ObjectID = "KJ4-Uw-4AI"; */
"KJ4-Uw-4AI.text" = "Video Size";
/* Class = "UILabel"; text = "Locked"; ObjectID = "Nuf-3J-OLu"; */
"Nuf-3J-OLu.text" = "Locked";
/* Class = "UILabel"; text = "Frame Rate"; ObjectID = "RKd-LF-IM5"; */
"RKd-LF-IM5.text" = "Frame Rate";
/* Class = "UILabel"; text = "Resize Aspect"; ObjectID = "Rz5-6b-y0h"; */
"Rz5-6b-y0h.text" = "Resize Aspect";
/* Class = "UILabel"; text = "f1.0"; ObjectID = "SxX-36-5NN"; */
"SxX-36-5NN.text" = "f1.0";
/* Class = "UILabel"; text = "Exposure"; ObjectID = "Szo-Pj-jno"; */
"Szo-Pj-jno.text" = "Exposure";
/* Class = "UILabel"; text = "ISO"; ObjectID = "TTb-bW-pMN"; */
"TTb-bW-pMN.text" = "ISO";
/* Class = "UILabel"; text = "Camera"; ObjectID = "WaU-wB-ecv"; */
"WaU-wB-ecv.text" = "Camera";
/* Class = "UITableViewController"; title = "White Balance"; ObjectID = "X40-UA-27w"; */
"X40-UA-27w.title" = "White Balance";
/* Class = "UINavigationItem"; title = "Settings"; ObjectID = "Xje-kQ-L0P"; */
"Xje-kQ-L0P.title" = "Settings";
/* Class = "UIBarButtonItem"; title = "Close"; ObjectID = "XvT-YW-xBL"; */
"XvT-YW-xBL.title" = "Close";
/* Class = "UILabel"; text = "Locked"; ObjectID = "YGU-l8-ZMR"; */
"YGU-l8-ZMR.text" = "Locked";
/* Class = "UILabel"; text = "Format"; ObjectID = "YPv-nc-7nK"; */
"YPv-nc-7nK.text" = "Format";
/* Class = "UILabel"; text = "Locked"; ObjectID = "YrA-Y0-l1z"; */
"YrA-Y0-l1z.text" = "Locked";
/* Class = "UINavigationItem"; title = "Format"; ObjectID = "Z09-mH-385"; */
"Z09-mH-385.title" = "Format";
/* Class = "UILabel"; text = "Camera On/Off"; ObjectID = "ZiN-q3-8Cs"; */
"ZiN-q3-8Cs.text" = "Camera On/Off";
/* Class = "UINavigationItem"; title = "White Balance"; ObjectID = "b1A-7E-zBH"; */
"b1A-7E-zBH.title" = "White Balance";
/* Class = "UILabel"; text = "100"; ObjectID = "b1L-VE-boz"; */
"b1L-VE-boz.text" = "100";
/* Class = "UINavigationItem"; title = "Exposure"; ObjectID = "bwF-Fn-XeY"; */
"bwF-Fn-XeY.title" = "Exposure";
/* Class = "UIButton"; configuration.title = "Test"; ObjectID = "cC0-N9-hxt"; */
"cC0-N9-hxt.configuration.title" = "Test";
/* Class = "UIButton"; normalTitle = "Button"; ObjectID = "cC0-N9-hxt"; */
"cC0-N9-hxt.normalTitle" = "Test";
/* Class = "UISegmentedControl"; fSu-H9-Cz9.segmentTitles[0] = "sec"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[0]" = "sec";
/* Class = "UISegmentedControl"; fSu-H9-Cz9.segmentTitles[1] = "ms"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[1]" = "ms";
/* Class = "UISegmentedControl"; fSu-H9-Cz9.segmentTitles[2] = "μs"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[2]" = "μs";
/* Class = "UILabel"; text = "Locked"; ObjectID = "fty-cZ-huK"; */
"fty-cZ-huK.text" = "Locked";
/* Class = "UILabel"; text = "Auto (10ms)"; ObjectID = "hVI-M7-yVe"; */
"hVI-M7-yVe.text" = "Auto (10ms)";
/* Class = "UILabel"; text = "Camera Name"; ObjectID = "if3-5B-xPF"; */
"if3-5B-xPF.text" = "Camera Name";
/* Class = "UILabel"; text = "Unit"; ObjectID = "l6D-7r-DH5"; */
"l6D-7r-DH5.text" = "Unit";
/* Class = "UINavigationItem"; title = "Camera Test"; ObjectID = "lZ7-W3-MRS"; */
"lZ7-W3-MRS.title" = "Camera Test";
/* Class = "UILabel"; text = "8ms"; ObjectID = "lct-8a-Lqk"; */
"lct-8a-Lqk.text" = "8ms";
/* Class = "UITableViewController"; title = "Camera"; ObjectID = "lvC-jH-Oee"; */
"lvC-jH-Oee.title" = "Camera";
/* Class = "UILabel"; text = "Resize Aspect Fill"; ObjectID = "mod-K3-RQU"; */
"mod-K3-RQU.text" = "Resize Aspect Fill";
/* Class = "UILabel"; text = "HD 1920x1080"; ObjectID = "nbm-4k-ihb"; */
"nbm-4k-ihb.text" = "HD 1920x1080";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "pKS-rd-Dx6"; */
"pKS-rd-Dx6.text" = "30 fps";
/* Class = "UILabel"; text = "Exposure Duration"; ObjectID = "soE-ah-Y4f"; */
"soE-ah-Y4f.text" = "Exposure Duration";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "u82-lR-lTP"; */
"u82-lR-lTP.text" = "30 fps";
/* Class = "UILabel"; text = "100"; ObjectID = "y9H-1I-dYX"; */
"y9H-1I-dYX.text" = "100";
/* Class = "UILabel"; text = "ISO"; ObjectID = "yOn-QG-KiO"; */
"yOn-QG-KiO.text" = "ISO";

@ -0,0 +1,183 @@
/* Class = "UILabel"; text = "Continuously monitors exposure levels and automatically adjusts exposure when necessary."; ObjectID = "2ad-p5-WH5"; */
"2ad-p5-WH5.text" = "持續監測曝光水平並在必要時自動調整曝光。";
/* Class = "UILabel"; text = "White Balance"; ObjectID = "4ie-UM-xw1"; */
"4ie-UM-xw1.text" = "白平衡";
/* Class = "UILabel"; text = "Front"; ObjectID = "55X-XR-Xoe"; */
"55X-XR-Xoe.text" = "前置";
/* Class = "UITableViewController"; text = "Preview Layer Gravity"; ObjectID = "5qf-l9-Bpt"; */
"5qf-l9-Bpt.title" = "相機預覽展示形式";
/* Class = "UILabel"; text = "Show the camera preview by preserving its aspect ratio and fits it within the layer's bounds."; ObjectID = "6I3-ak-vEx"; */
"6I3-ak-vEx.text" = "按比例顯示相機預覽,並使其限制在圖層的範圍內。";
/* Class = "UILabel"; text = "Continuous Auto"; ObjectID = "6yD-61-CEf"; */
"6yD-61-CEf.text" = "連續自動";
/* Class = "UILabel"; text = "White Balance"; ObjectID = "77e-kN-xI5"; */
"77e-kN-xI5.text" = "白平衡";
/* Class = "UILabel"; text = "Preview Gravity"; ObjectID = "7AW-UQ-WfA"; */
"7AW-UQ-WfA.text" = "相機預覽展示形式";
/* Class = "UILabel"; text = "Lens Aperture"; ObjectID = "7ZB-LO-AYF"; */
"7ZB-LO-AYF.text" = "鏡頭光圈";
/* Class = "UINavigationItem"; text = "Preview Gravity"; ObjectID = "7aV-Vw-b2w"; */
"7aV-Vw-b2w.title" = "相機預覽展示形式";
/* Class = "UINavigationItem"; text = "Camera"; ObjectID = "8D6-fu-CJu"; */
"8D6-fu-CJu.title" = "相機";
/* Class = "UILabel"; text = "Medium"; ObjectID = "9xa-bl-6eJ"; */
"9xa-bl-6eJ.text" = "中等品質";
/* Class = "UITableViewSection"; text = "Camera"; ObjectID = "AKs-Pq-lcR"; */
"AKs-Pq-lcR.headerTitle" = "相機";
/* Class = "UILabel"; text = "640x480"; ObjectID = "B6a-KT-T4m"; */
"B6a-KT-T4m.text" = "640x480";
/* Class = "UILabel"; text = "Face Detector"; ObjectID = "Byq-a3-CTH"; */
"Byq-a3-CTH.text" = "人臉辨識";
/* Class = "UILabel"; text = "1920x1080"; ObjectID = "Dp9-9b-EEt"; */
"Dp9-9b-EEt.text" = "1920x1080";
/* Class = "UILabel"; text = "A mode that locks the white balance state."; ObjectID = "FOH-2X-R88"; */
"FOH-2X-R88.text" = "一種鎖定白平衡狀態的模式。";
/* Class = "UILabel"; text = "Duration"; ObjectID = "FPh-cx-ffz"; */
"FPh-cx-ffz.text" = "持續時間";
/* Class = "UILabel"; text = "Exposure"; ObjectID = "Hmc-Mc-AME"; */
"Hmc-Mc-AME.text" = "曝光";
/* Class = "UILabel"; text = "Resolution"; ObjectID = "J12-De-6Ah"; */
"J12-De-6Ah.text" = "解析度";
/* Class = "UITextField"; text = "100"; ObjectID = "J2A-ot-v0j"; */
"J2A-ot-v0j.text" = "100";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "J5t-dB-TfS"; */
"J5t-dB-TfS.text" = "30 fps";
/* Class = "UILabel"; text = "Frame Rate"; ObjectID = "JgS-aW-Prv"; */
"JgS-aW-Prv.text" = "幀率";
/* Class = "UILabel"; text = "Video Size"; ObjectID = "KJ4-Uw-4AI"; */
"KJ4-Uw-4AI.text" = "視頻尺寸";
/* Class = "UILabel"; text = "Locked"; ObjectID = "Nuf-3J-OLu"; */
"Nuf-3J-OLu.text" = "鎖定";
/* Class = "UILabel"; text = "Frame Rate"; ObjectID = "RKd-LF-IM5"; */
"RKd-LF-IM5.text" = "幀率";
/* Class = "UILabel"; text = "Resize Aspect"; ObjectID = "Rz5-6b-y0h"; */
"Rz5-6b-y0h.text" = "按比例調整";
/* Class = "UILabel"; text = "f1.0"; ObjectID = "SxX-36-5NN"; */
"SxX-36-5NN.text" = "f1.0";
/* Class = "UILabel"; text = "Exposure"; ObjectID = "Szo-Pj-jno"; */
"Szo-Pj-jno.text" = "曝光";
/* Class = "UILabel"; text = "ISO"; ObjectID = "TTb-bW-pMN"; */
"TTb-bW-pMN.text" = "ISO";
/* Class = "UILabel"; text = "Camera"; ObjectID = "WaU-wB-ecv"; */
"WaU-wB-ecv.text" = "相機";
/* Class = "UITableViewController"; text = "White Balance"; ObjectID = "X40-UA-27w"; */
"X40-UA-27w.title" = "白平衡";
/* Class = "UINavigationItem"; text = "Settings"; ObjectID = "Xje-kQ-L0P"; */
"Xje-kQ-L0P.title" = "設定";
/* Class = "UIBarButtonItem"; text = "Close"; ObjectID = "XvT-YW-xBL"; */
"XvT-YW-xBL.title" = "關閉";
/* Class = "UILabel"; text = "Locked"; ObjectID = "YGU-l8-ZMR"; */
"YGU-l8-ZMR.text" = "鎖定";
/* Class = "UILabel"; text = "Format"; ObjectID = "YPv-nc-7nK"; */
"YPv-nc-7nK.text" = "格式";
/* Class = "UILabel"; text = "Locked"; ObjectID = "YrA-Y0-l1z"; */
"YrA-Y0-l1z.text" = "鎖定";
/* Class = "UINavigationItem"; text = "Format"; ObjectID = "Z09-mH-385"; */
"Z09-mH-385.title" = "格式";
/* Class = "UILabel"; text = "Camera On/Off"; ObjectID = "ZiN-q3-8Cs"; */
"ZiN-q3-8Cs.text" = "相機 開/關";
/* Class = "UINavigationItem"; text = "White Balance"; ObjectID = "b1A-7E-zBH"; */
"b1A-7E-zBH.title" = "白平衡";
/* Class = "UILabel"; text = "100"; ObjectID = "b1L-VE-boz"; */
"b1L-VE-boz.text" = "100";
/* Class = "UINavigationItem"; text = "Exposure"; ObjectID = "bwF-Fn-XeY"; */
"bwF-Fn-XeY.title" = "曝光";
/* Class = "UIButton"; text = "Test"; ObjectID = "cC0-N9-hxt"; */
"cC0-N9-hxt.configuration.title" = "測試";
/* Class = "UIButton"; text = "Button"; ObjectID = "cC0-N9-hxt"; */
"cC0-N9-hxt.normalTitle" = "測試";
/* Class = "UISegmentedControl"; text = "sec"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[0]" = "秒";
/* Class = "UISegmentedControl"; text = "ms"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[1]" = "毫秒";
/* Class = "UISegmentedControl"; text = "μs"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[2]" = "微秒";
/* Class = "UILabel"; text = "Locked"; ObjectID = "fty-cZ-huK"; */
"fty-cZ-huK.text" = "鎖定";
/* Class = "UILabel"; text = "Auto (10ms)"; ObjectID = "hVI-M7-yVe"; */
"hVI-M7-yVe.text" = "自動10毫秒";
/* Class = "UILabel"; text = "Camera Name"; ObjectID = "if3-5B-xPF"; */
"if3-5B-xPF.text" = "相機名稱";
/* Class = "UILabel"; text = "Unit"; ObjectID = "l6D-7r-DH5"; */
"l6D-7r-DH5.text" = "單位";
/* Class = "UINavigationItem"; text = "Camera Test"; ObjectID = "lZ7-W3-MRS"; */
"lZ7-W3-MRS.title" = "相機測試";
/* Class = "UILabel"; text = "8ms"; ObjectID = "lct-8a-Lqk"; */
"lct-8a-Lqk.text" = "8毫秒";
/* Class = "UITableViewController"; text = "Camera"; ObjectID = "lvC-jH-Oee"; */
"lvC-jH-Oee.title" = "相機";
/* Class = "UILabel"; text = "Resize Aspect Fill"; ObjectID = "mod-K3-RQU"; */
"mod-K3-RQU.text" = "按比例填充";
/* Class = "UILabel"; text = "HD 1920x1080"; ObjectID = "nbm-4k-ihb"; */
"nbm-4k-ihb.text" = "HD 1920x1080";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "pKS-rd-Dx6"; */
"pKS-rd-Dx6.text" = "30 fps";
/* Class = "UILabel"; text = "Exposure Duration"; ObjectID = "soE-ah-Y4f"; */
"soE-ah-Y4f.text" = "曝光時間";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "u82-lR-lTP"; */
"u82-lR-lTP.text" = "30 fps";
/* Class = "UILabel"; text = "100"; ObjectID = "y9H-1I-dYX"; */
"y9H-1I-dYX.text" = "100";
/* Class = "UILabel"; text = "ISO"; ObjectID = "yOn-QG-KiO"; */
"yOn-QG-KiO.text" = "ISO";

@ -0,0 +1,183 @@
/* Class = "UILabel"; text = "Continuously monitors exposure levels and automatically adjusts exposure when necessary."; ObjectID = "2ad-p5-WH5"; */
"2ad-p5-WH5.text" = "持续监测曝光水平并在必要时自动调整曝光。";
/* Class = "UILabel"; text = "White Balance"; ObjectID = "4ie-UM-xw1"; */
"4ie-UM-xw1.text" = "白平衡";
/* Class = "UILabel"; text = "Front"; ObjectID = "55X-XR-Xoe"; */
"55X-XR-Xoe.text" = "前置";
/* Class = "UITableViewController"; text = "Preview Layer Gravity"; ObjectID = "5qf-l9-Bpt"; */
"5qf-l9-Bpt.title" = "相机预览展示形式";
/* Class = "UILabel"; text = "Show the camera preview by preserving its aspect ratio and fits it within the layer's bounds."; ObjectID = "6I3-ak-vEx"; */
"6I3-ak-vEx.text" = "按比例显示相机预览,并使其限制在图层的范围内。";
/* Class = "UILabel"; text = "Continuous Auto"; ObjectID = "6yD-61-CEf"; */
"6yD-61-CEf.text" = "连续自动";
/* Class = "UILabel"; text = "White Balance"; ObjectID = "77e-kN-xI5"; */
"77e-kN-xI5.text" = "白平衡";
/* Class = "UILabel"; text = "Preview Gravity"; ObjectID = "7AW-UQ-WfA"; */
"7AW-UQ-WfA.text" = "相机预览展示形式";
/* Class = "UILabel"; text = "Lens Aperture"; ObjectID = "7ZB-LO-AYF"; */
"7ZB-LO-AYF.text" = "镜头光圈";
/* Class = "UINavigationItem"; text = "Preview Gravity"; ObjectID = "7aV-Vw-b2w"; */
"7aV-Vw-b2w.title" = "相机预览展示形式";
/* Class = "UINavigationItem"; text = "Camera"; ObjectID = "8D6-fu-CJu"; */
"8D6-fu-CJu.title" = "相机";
/* Class = "UILabel"; text = "Medium"; ObjectID = "9xa-bl-6eJ"; */
"9xa-bl-6eJ.text" = "中等品质";
/* Class = "UITableViewSection"; text = "Camera"; ObjectID = "AKs-Pq-lcR"; */
"AKs-Pq-lcR.headerTitle" = "相机";
/* Class = "UILabel"; text = "640x480"; ObjectID = "B6a-KT-T4m"; */
"B6a-KT-T4m.text" = "640x480";
/* Class = "UILabel"; text = "Face Detector"; ObjectID = "Byq-a3-CTH"; */
"Byq-a3-CTH.text" = "人脸识别";
/* Class = "UILabel"; text = "1920x1080"; ObjectID = "Dp9-9b-EEt"; */
"Dp9-9b-EEt.text" = "1920x1080";
/* Class = "UILabel"; text = "A mode that locks the white balance state."; ObjectID = "FOH-2X-R88"; */
"FOH-2X-R88.text" = "一种锁定白平衡状态的模式。";
/* Class = "UILabel"; text = "Duration"; ObjectID = "FPh-cx-ffz"; */
"FPh-cx-ffz.text" = "持续时间";
/* Class = "UILabel"; text = "Exposure"; ObjectID = "Hmc-Mc-AME"; */
"Hmc-Mc-AME.text" = "曝光";
/* Class = "UILabel"; text = "Resolution"; ObjectID = "J12-De-6Ah"; */
"J12-De-6Ah.text" = "分辨率";
/* Class = "UITextField"; text = "100"; ObjectID = "J2A-ot-v0j"; */
"J2A-ot-v0j.text" = "100";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "J5t-dB-TfS"; */
"J5t-dB-TfS.text" = "30 fps";
/* Class = "UILabel"; text = "Frame Rate"; ObjectID = "JgS-aW-Prv"; */
"JgS-aW-Prv.text" = "帧率";
/* Class = "UILabel"; text = "Video Size"; ObjectID = "KJ4-Uw-4AI"; */
"KJ4-Uw-4AI.text" = "视频尺寸";
/* Class = "UILabel"; text = "Locked"; ObjectID = "Nuf-3J-OLu"; */
"Nuf-3J-OLu.text" = "锁定";
/* Class = "UILabel"; text = "Frame Rate"; ObjectID = "RKd-LF-IM5"; */
"RKd-LF-IM5.text" = "帧率";
/* Class = "UILabel"; text = "Resize Aspect"; ObjectID = "Rz5-6b-y0h"; */
"Rz5-6b-y0h.text" = "按比例调整";
/* Class = "UILabel"; text = "f1.0"; ObjectID = "SxX-36-5NN"; */
"SxX-36-5NN.text" = "f1.0";
/* Class = "UILabel"; text = "Exposure"; ObjectID = "Szo-Pj-jno"; */
"Szo-Pj-jno.text" = "曝光";
/* Class = "UILabel"; text = "ISO"; ObjectID = "TTb-bW-pMN"; */
"TTb-bW-pMN.text" = "ISO";
/* Class = "UILabel"; text = "Camera"; ObjectID = "WaU-wB-ecv"; */
"WaU-wB-ecv.text" = "相机";
/* Class = "UITableViewController"; text = "White Balance"; ObjectID = "X40-UA-27w"; */
"X40-UA-27w.title" = "白平衡";
/* Class = "UINavigationItem"; text = "Settings"; ObjectID = "Xje-kQ-L0P"; */
"Xje-kQ-L0P.title" = "设定";
/* Class = "UIBarButtonItem"; text = "Close"; ObjectID = "XvT-YW-xBL"; */
"XvT-YW-xBL.title" = "关闭";
/* Class = "UILabel"; text = "Locked"; ObjectID = "YGU-l8-ZMR"; */
"YGU-l8-ZMR.text" = "鎖定";
/* Class = "UILabel"; text = "Format"; ObjectID = "YPv-nc-7nK"; */
"YPv-nc-7nK.text" = "格式";
/* Class = "UILabel"; text = "Locked"; ObjectID = "YrA-Y0-l1z"; */
"YrA-Y0-l1z.text" = "鎖定";
/* Class = "UINavigationItem"; text = "Format"; ObjectID = "Z09-mH-385"; */
"Z09-mH-385.title" = "格式";
/* Class = "UILabel"; text = "Camera On/Off"; ObjectID = "ZiN-q3-8Cs"; */
"ZiN-q3-8Cs.text" = "相机 开/关";
/* Class = "UINavigationItem"; text = "White Balance"; ObjectID = "b1A-7E-zBH"; */
"b1A-7E-zBH.title" = "白平衡";
/* Class = "UILabel"; text = "100"; ObjectID = "b1L-VE-boz"; */
"b1L-VE-boz.text" = "100";
/* Class = "UINavigationItem"; text = "Exposure"; ObjectID = "bwF-Fn-XeY"; */
"bwF-Fn-XeY.title" = "曝光";
/* Class = "UIButton"; text = "Test"; ObjectID = "cC0-N9-hxt"; */
"cC0-N9-hxt.configuration.title" = "测试";
/* Class = "UIButton"; text = "Button"; ObjectID = "cC0-N9-hxt"; */
"cC0-N9-hxt.normalTitle" = "测试";
/* Class = "UISegmentedControl"; text = "sec"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[0]" = "秒";
/* Class = "UISegmentedControl"; text = "ms"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[1]" = "毫秒";
/* Class = "UISegmentedControl"; text = "μs"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[2]" = "微秒";
/* Class = "UILabel"; text = "Locked"; ObjectID = "fty-cZ-huK"; */
"fty-cZ-huK.text" = "鎖定";
/* Class = "UILabel"; text = "Auto (10ms)"; ObjectID = "hVI-M7-yVe"; */
"hVI-M7-yVe.text" = "自动10毫秒";
/* Class = "UILabel"; text = "Camera Name"; ObjectID = "if3-5B-xPF"; */
"if3-5B-xPF.text" = "相机名称";
/* Class = "UILabel"; text = "Unit"; ObjectID = "l6D-7r-DH5"; */
"l6D-7r-DH5.text" = "单位";
/* Class = "UINavigationItem"; text = "Camera Test"; ObjectID = "lZ7-W3-MRS"; */
"lZ7-W3-MRS.title" = "相机测试";
/* Class = "UILabel"; text = "8ms"; ObjectID = "lct-8a-Lqk"; */
"lct-8a-Lqk.text" = "8毫秒";
/* Class = "UITableViewController"; text = "Camera"; ObjectID = "lvC-jH-Oee"; */
"lvC-jH-Oee.title" = "相机";
/* Class = "UILabel"; text = "Resize Aspect Fill"; ObjectID = "mod-K3-RQU"; */
"mod-K3-RQU.text" = "按比例填充";
/* Class = "UILabel"; text = "HD 1920x1080"; ObjectID = "nbm-4k-ihb"; */
"nbm-4k-ihb.text" = "HD 1920x1080";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "pKS-rd-Dx6"; */
"pKS-rd-Dx6.text" = "30 fps";
/* Class = "UILabel"; text = "Exposure Duration"; ObjectID = "soE-ah-Y4f"; */
"soE-ah-Y4f.text" = "曝光时间";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "u82-lR-lTP"; */
"u82-lR-lTP.text" = "30 fps";
/* Class = "UILabel"; text = "100"; ObjectID = "y9H-1I-dYX"; */
"y9H-1I-dYX.text" = "100";
/* Class = "UILabel"; text = "ISO"; ObjectID = "yOn-QG-KiO"; */
"yOn-QG-KiO.text" = "ISO";

@ -0,0 +1,183 @@
/* Class = "UILabel"; text = "Continuously monitors exposure levels and automatically adjusts exposure when necessary."; ObjectID = "2ad-p5-WH5"; */
"2ad-p5-WH5.text" = "持續監測曝光水平並在必要時自動調整曝光。";
/* Class = "UILabel"; text = "White Balance"; ObjectID = "4ie-UM-xw1"; */
"4ie-UM-xw1.text" = "白平衡";
/* Class = "UILabel"; text = "Front"; ObjectID = "55X-XR-Xoe"; */
"55X-XR-Xoe.text" = "前置";
/* Class = "UITableViewController"; text = "Preview Layer Gravity"; ObjectID = "5qf-l9-Bpt"; */
"5qf-l9-Bpt.title" = "相機預覽展示形式";
/* Class = "UILabel"; text = "Show the camera preview by preserving its aspect ratio and fits it within the layer's bounds."; ObjectID = "6I3-ak-vEx"; */
"6I3-ak-vEx.text" = "按比例顯示相機預覽,並使其限制在圖層的範圍內。";
/* Class = "UILabel"; text = "Continuous Auto"; ObjectID = "6yD-61-CEf"; */
"6yD-61-CEf.text" = "連續自動";
/* Class = "UILabel"; text = "White Balance"; ObjectID = "77e-kN-xI5"; */
"77e-kN-xI5.text" = "白平衡";
/* Class = "UILabel"; text = "Preview Gravity"; ObjectID = "7AW-UQ-WfA"; */
"7AW-UQ-WfA.text" = "相機預覽展示形式";
/* Class = "UILabel"; text = "Lens Aperture"; ObjectID = "7ZB-LO-AYF"; */
"7ZB-LO-AYF.text" = "鏡頭光圈";
/* Class = "UINavigationItem"; text = "Preview Gravity"; ObjectID = "7aV-Vw-b2w"; */
"7aV-Vw-b2w.title" = "相機預覽展示形式";
/* Class = "UINavigationItem"; text = "Camera"; ObjectID = "8D6-fu-CJu"; */
"8D6-fu-CJu.title" = "相機";
/* Class = "UILabel"; text = "Medium"; ObjectID = "9xa-bl-6eJ"; */
"9xa-bl-6eJ.text" = "中等品質";
/* Class = "UITableViewSection"; text = "Camera"; ObjectID = "AKs-Pq-lcR"; */
"AKs-Pq-lcR.headerTitle" = "相機";
/* Class = "UILabel"; text = "640x480"; ObjectID = "B6a-KT-T4m"; */
"B6a-KT-T4m.text" = "640x480";
/* Class = "UILabel"; text = "Face Detector"; ObjectID = "Byq-a3-CTH"; */
"Byq-a3-CTH.text" = "人臉辨識";
/* Class = "UILabel"; text = "1920x1080"; ObjectID = "Dp9-9b-EEt"; */
"Dp9-9b-EEt.text" = "1920x1080";
/* Class = "UILabel"; text = "A mode that locks the white balance state."; ObjectID = "FOH-2X-R88"; */
"FOH-2X-R88.text" = "一種鎖定白平衡狀態的模式。";
/* Class = "UILabel"; text = "Duration"; ObjectID = "FPh-cx-ffz"; */
"FPh-cx-ffz.text" = "持續時間";
/* Class = "UILabel"; text = "Exposure"; ObjectID = "Hmc-Mc-AME"; */
"Hmc-Mc-AME.text" = "曝光";
/* Class = "UILabel"; text = "Resolution"; ObjectID = "J12-De-6Ah"; */
"J12-De-6Ah.text" = "解析度";
/* Class = "UITextField"; text = "100"; ObjectID = "J2A-ot-v0j"; */
"J2A-ot-v0j.text" = "100";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "J5t-dB-TfS"; */
"J5t-dB-TfS.text" = "30 fps";
/* Class = "UILabel"; text = "Frame Rate"; ObjectID = "JgS-aW-Prv"; */
"JgS-aW-Prv.text" = "幀率";
/* Class = "UILabel"; text = "Video Size"; ObjectID = "KJ4-Uw-4AI"; */
"KJ4-Uw-4AI.text" = "視頻尺寸";
/* Class = "UILabel"; text = "Locked"; ObjectID = "Nuf-3J-OLu"; */
"Nuf-3J-OLu.text" = "鎖定";
/* Class = "UILabel"; text = "Frame Rate"; ObjectID = "RKd-LF-IM5"; */
"RKd-LF-IM5.text" = "幀率";
/* Class = "UILabel"; text = "Resize Aspect"; ObjectID = "Rz5-6b-y0h"; */
"Rz5-6b-y0h.text" = "按比例調整";
/* Class = "UILabel"; text = "f1.0"; ObjectID = "SxX-36-5NN"; */
"SxX-36-5NN.text" = "f1.0";
/* Class = "UILabel"; text = "Exposure"; ObjectID = "Szo-Pj-jno"; */
"Szo-Pj-jno.text" = "曝光";
/* Class = "UILabel"; text = "ISO"; ObjectID = "TTb-bW-pMN"; */
"TTb-bW-pMN.text" = "ISO";
/* Class = "UILabel"; text = "Camera"; ObjectID = "WaU-wB-ecv"; */
"WaU-wB-ecv.text" = "相機";
/* Class = "UITableViewController"; text = "White Balance"; ObjectID = "X40-UA-27w"; */
"X40-UA-27w.title" = "白平衡";
/* Class = "UINavigationItem"; text = "Settings"; ObjectID = "Xje-kQ-L0P"; */
"Xje-kQ-L0P.title" = "設定";
/* Class = "UIBarButtonItem"; text = "Close"; ObjectID = "XvT-YW-xBL"; */
"XvT-YW-xBL.title" = "關閉";
/* Class = "UILabel"; text = "Locked"; ObjectID = "YGU-l8-ZMR"; */
"YGU-l8-ZMR.text" = "鎖定";
/* Class = "UILabel"; text = "Format"; ObjectID = "YPv-nc-7nK"; */
"YPv-nc-7nK.text" = "格式";
/* Class = "UILabel"; text = "Locked"; ObjectID = "YrA-Y0-l1z"; */
"YrA-Y0-l1z.text" = "鎖定";
/* Class = "UINavigationItem"; text = "Format"; ObjectID = "Z09-mH-385"; */
"Z09-mH-385.title" = "格式";
/* Class = "UILabel"; text = "Camera On/Off"; ObjectID = "ZiN-q3-8Cs"; */
"ZiN-q3-8Cs.text" = "相機 開/關";
/* Class = "UINavigationItem"; text = "White Balance"; ObjectID = "b1A-7E-zBH"; */
"b1A-7E-zBH.title" = "白平衡";
/* Class = "UILabel"; text = "100"; ObjectID = "b1L-VE-boz"; */
"b1L-VE-boz.text" = "100";
/* Class = "UINavigationItem"; text = "Exposure"; ObjectID = "bwF-Fn-XeY"; */
"bwF-Fn-XeY.title" = "曝光";
/* Class = "UIButton"; text = "Test"; ObjectID = "cC0-N9-hxt"; */
"cC0-N9-hxt.configuration.title" = "測試";
/* Class = "UIButton"; text = "Button"; ObjectID = "cC0-N9-hxt"; */
"cC0-N9-hxt.normalTitle" = "測試";
/* Class = "UISegmentedControl"; text = "sec"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[0]" = "秒";
/* Class = "UISegmentedControl"; text = "ms"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[1]" = "毫秒";
/* Class = "UISegmentedControl"; text = "μs"; ObjectID = "fSu-H9-Cz9"; */
"fSu-H9-Cz9.segmentTitles[2]" = "微秒";
/* Class = "UILabel"; text = "Locked"; ObjectID = "fty-cZ-huK"; */
"fty-cZ-huK.text" = "鎖定";
/* Class = "UILabel"; text = "Auto (10ms)"; ObjectID = "hVI-M7-yVe"; */
"hVI-M7-yVe.text" = "自動10毫秒";
/* Class = "UILabel"; text = "Camera Name"; ObjectID = "if3-5B-xPF"; */
"if3-5B-xPF.text" = "相機名稱";
/* Class = "UILabel"; text = "Unit"; ObjectID = "l6D-7r-DH5"; */
"l6D-7r-DH5.text" = "單位";
/* Class = "UINavigationItem"; text = "Camera Test"; ObjectID = "lZ7-W3-MRS"; */
"lZ7-W3-MRS.title" = "相機測試";
/* Class = "UILabel"; text = "8ms"; ObjectID = "lct-8a-Lqk"; */
"lct-8a-Lqk.text" = "8毫秒";
/* Class = "UITableViewController"; text = "Camera"; ObjectID = "lvC-jH-Oee"; */
"lvC-jH-Oee.title" = "相機";
/* Class = "UILabel"; text = "Resize Aspect Fill"; ObjectID = "mod-K3-RQU"; */
"mod-K3-RQU.text" = "按比例填充";
/* Class = "UILabel"; text = "HD 1920x1080"; ObjectID = "nbm-4k-ihb"; */
"nbm-4k-ihb.text" = "HD 1920x1080";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "pKS-rd-Dx6"; */
"pKS-rd-Dx6.text" = "30 fps";
/* Class = "UILabel"; text = "Exposure Duration"; ObjectID = "soE-ah-Y4f"; */
"soE-ah-Y4f.text" = "曝光時間";
/* Class = "UILabel"; text = "30 fps"; ObjectID = "u82-lR-lTP"; */
"u82-lR-lTP.text" = "30 fps";
/* Class = "UILabel"; text = "100"; ObjectID = "y9H-1I-dYX"; */
"y9H-1I-dYX.text" = "100";
/* Class = "UILabel"; text = "ISO"; ObjectID = "yOn-QG-KiO"; */
"yOn-QG-KiO.text" = "ISO";

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleIdentifier</key>
<string>com.apple.xcode.dsym.com.demo.panoptic</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>dSYM</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>4.8.1</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

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

Loading…
Cancel
Save