diff --git a/.gitignore b/.gitignore
index cff0e374..55ad4693 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,7 @@ pubspec.lock
.pub-cache/
.pub/
/build/
+/ios/Frameworks/
# Web related
lib/generated_plugin_registrant.dart
diff --git a/android/app/build.gradle b/android/app/build.gradle
index f1799225..b5f2d00f 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -56,6 +56,10 @@ android {
compileSdkVersion 34
// ndkVersion "24.0.8215888"
+ buildFeatures {
+ viewBinding true
+ }
+
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
@@ -69,7 +73,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.ejada.hmg"
- minSdkVersion 24
+ minSdkVersion 26
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
@@ -117,15 +121,16 @@ android {
packagingOptions {
exclude 'META-INF/proguard/androidx-annotations.pro'
-// pickFirst 'lib/x86/libc++_shared.so'
-// pickFirst 'lib/x86_64/libc++_shared.so'
-// pickFirst 'lib/armeabi-v7a/libc++_shared.so'
-// pickFirst 'lib/arm64-v8a/libc++_shared.so'
-// pickFirst '**/*.so'
+ pickFirst 'lib/x86/libc++_shared.so'
+ pickFirst 'lib/x86_64/libc++_shared.so'
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
+ pickFirst '**/*.so'
}
compileOptions {
+// coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@@ -136,13 +141,15 @@ flutter {
}
dependencies {
+// coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.google.firebase:firebase-messaging:21.0.0"
// implementation ('com.google.firebase:firebase-inappmessaging-display:19.1.2',{
// exclude group: 'com.google.protobuf',module: 'protobuf-javalite'
// exclude group: 'com.google.protobuf',module: 'protobuf-lite'
// })
- implementation 'pub.devrel:easypermissions:0.4.0'
+ implementation 'pub.devrel:easypermissions:3.0.0'
// implementation 'com.google.firebase:firebase-inappmessaging-display:17.2.0'
// implementation 'com.google.firebase:firebase-inappmessaging-display:17.2.0'
implementation 'com.google.guava:guava:27.0.1-android'
@@ -163,9 +170,34 @@ dependencies {
// implementation "us.zoom.videosdk:ZoomVideoSDK:1.10.11"
// implementation group: 'us.zoom.videosdk', name: 'zoomvideosdk-core', version: '1.10.11'
- implementation "us.zoom.videosdk:zoomvideosdk-core:1.10.1"
- implementation "us.zoom.videosdk:zoomvideosdk-annotation:1.10.1"
- implementation "us.zoom.videosdk:zoomvideosdk-videoeffects:1.10.1"
+// implementation "us.zoom.videosdk:zoomvideosdk-core:1.10.1"
+// implementation "us.zoom.videosdk:zoomvideosdk-annotation:1.10.1"
+// implementation "us.zoom.videosdk:zoomvideosdk-videoeffects:1.10.1"
+
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
+ implementation 'com.squareup.retrofit2:retrofit:2.9.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
+ implementation 'com.squareup.retrofit2:adapter-java8:2.4.0'
+ implementation 'com.google.code.gson:gson:2.8.9'
+ implementation 'com.google.android.gms:play-services-location:21.3.0'
+ implementation 'com.squareup.okhttp3:okhttp:4.10.0'
+ implementation 'androidx.test.ext:junit:1.1.5'
+ implementation 'com.android.volley:volley:1.2.1'
+ def room_version = "2.4.0-alpha04"
+ implementation "androidx.room:room-runtime:$room_version"
+ annotationProcessor "androidx.room:room-compiler:$room_version"
+ implementation 'net.zetetic:android-database-sqlcipher:4.5.2'
+ implementation 'com.intuit.ssp:ssp-android:1.1.0'
+ implementation 'com.intuit.sdp:sdp-android:1.1.0'
+ implementation 'com.github.bumptech.glide:glide:4.12.0'
+ 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 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
@@ -177,6 +209,7 @@ dependencies {
implementation 'com.facebook.stetho:stetho-urlconnection:1.5.1'
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
+ implementation 'com.google.android.material:material:1.9.0'
androidTestImplementation "androidx.test:core:1.4.0"
}
diff --git a/android/app/libs/PenNavUI.aar b/android/app/libs/PenNavUI.aar
new file mode 100644
index 00000000..6291c4ec
Binary files /dev/null and b/android/app/libs/PenNavUI.aar differ
diff --git a/android/app/libs/Penguin.aar b/android/app/libs/Penguin.aar
new file mode 100644
index 00000000..7cdc0b71
Binary files /dev/null and b/android/app/libs/Penguin.aar differ
diff --git a/android/app/libs/PenguinRenderer.aar b/android/app/libs/PenguinRenderer.aar
new file mode 100644
index 00000000..c60248c9
Binary files /dev/null and b/android/app/libs/PenguinRenderer.aar differ
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
index 69cd8026..ab7b2ca4 100644
--- a/android/app/proguard-rules.pro
+++ b/android/app/proguard-rules.pro
@@ -53,4 +53,20 @@
}
-dontwarn com.opentok.android.**
--dontwarn com.opentok.otc.**
\ No newline at end of file
+-dontwarn com.opentok.otc.**
+
+-dontwarn penguin.com.pennav.Model.Navigation.NearLandmark
+
+-keep,includedescriptorclasses class net.sqlcipher.** { *; }
+-keep,includedescriptorclasses interface net.sqlcipher.** { *; }
+
+-keep class retrofit2.** { *; }
+-keep class okhttp3.** { *; }
+-dontwarn retrofit2.**
+
+-keep class com.google.gson.** { *; }
+-dontwarn com.google.gson.**
+
+# Penguin classes
+-keep class com.peng.pennavmap.models.** { *; }
+-keep class com.peng.pennavmap.db.** { *; }
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index b1540644..58ac88b7 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -8,21 +8,36 @@
FlutterApplication and put your custom class here. -->
-
-
-
-
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -42,6 +57,7 @@
+
@@ -59,13 +75,13 @@
diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt
index 8aa1ef85..df41e342 100644
--- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt
@@ -1,21 +1,19 @@
package com.ejada.hmg
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.content.ContentResolver
-import android.media.AudioAttributes
-import android.net.Uri
-import android.os.Bundle
-import android.util.Log
+import android.content.Intent
+import android.content.pm.PackageManager
import android.os.Build
+import android.util.Log
import android.view.WindowManager
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi
+import com.cloud.diplomaticquarterapp.PenguinInPlatformBridge
import com.ejada.hmg.utils.*
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
-import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterFragmentActivity() {
+ @RequiresApi(Build.VERSION_CODES.O)
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
// Create Flutter Platform Bridge
@@ -23,6 +21,7 @@ class MainActivity: FlutterFragmentActivity() {
PlatformBridge(flutterEngine, this).create()
OpenTokPlatformBridge(flutterEngine, this).create()
+ PenguinInPlatformBridge(flutterEngine, this).create()
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// val mChannel = NotificationChannel("video_call_noti", "video call", NotificationManager.IMPORTANCE_HIGH)
@@ -43,6 +42,25 @@ class MainActivity: FlutterFragmentActivity() {
// val time = timeToMillis("04:00:00", "HH:mm:ss")
+ }
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+
+ val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
+ val intent = Intent("PERMISSION_RESULT_ACTION").apply {
+ putExtra("PERMISSION_GRANTED", granted)
+ }
+ sendBroadcast(intent)
+
+ // Log the request code and permission results
+ Log.d("PermissionsResult", "Request Code: $requestCode")
+ Log.d("PermissionsResult", "Permissions: ${permissions.joinToString()}")
+ Log.d("PermissionsResult", "Grant Results: ${grantResults.joinToString()}")
+
}
override fun onResume() {
diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PenguinInPlatformBridge.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PenguinInPlatformBridge.kt
new file mode 100644
index 00000000..93affaef
--- /dev/null
+++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PenguinInPlatformBridge.kt
@@ -0,0 +1,52 @@
+package com.cloud.diplomaticquarterapp
+import com.ejada.hmg.MainActivity
+import android.os.Build
+import android.util.Log
+import androidx.annotation.RequiresApi
+import com.cloud.diplomaticquarterapp.penguin.PenguinView
+import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+
+class PenguinInPlatformBridge(
+ private var flutterEngine: FlutterEngine,
+ private var mainActivity: MainActivity
+) {
+
+ private lateinit var channel: MethodChannel
+
+ companion object {
+ private const val CHANNEL = "launch_penguin_ui"
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ fun create() {
+// openTok = OpenTok(mainActivity, flutterEngine)
+ channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
+ channel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
+ when (call.method) {
+ "launchPenguin" -> {
+ print("the platform channel is being called")
+ val args = call.arguments as Map?
+ Log.d("TAG", "configureFlutterEngine: $args")
+ println("args")
+ args?.let {
+ PenguinView(
+ mainActivity,
+ 100,
+ args,
+ flutterEngine.dartExecutor.binaryMessenger,
+ activity = mainActivity,
+ channel
+ )
+ }
+ }
+
+ else -> {
+ result.notImplemented()
+ }
+ }
+ }
+ }
+
+}
diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionHelper.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionHelper.kt
new file mode 100644
index 00000000..b308af05
--- /dev/null
+++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionHelper.kt
@@ -0,0 +1,28 @@
+package com.cloud.diplomaticquarterapp.PermissionManager
+
+import android.Manifest
+import android.os.Build
+
+object PermissionHelper {
+
+ fun getRequiredPermissions(): Array {
+ val permissions = mutableListOf(
+ Manifest.permission.INTERNET,
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION,
+ Manifest.permission.ACCESS_NETWORK_STATE,
+ Manifest.permission.BLUETOOTH,
+ Manifest.permission.BLUETOOTH_ADMIN,
+// Manifest.permission.ACTIVITY_RECOGNITION
+ )
+
+ // For Android 12 (API level 31) and above, add specific permissions
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12 (API 31) and above
+ permissions.add(Manifest.permission.BLUETOOTH_SCAN)
+ permissions.add(Manifest.permission.BLUETOOTH_CONNECT)
+ permissions.add(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS)
+ }
+
+ return permissions.toTypedArray()
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionManager.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionManager.kt
new file mode 100644
index 00000000..81f2a6f0
--- /dev/null
+++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionManager.kt
@@ -0,0 +1,50 @@
+package com.cloud.diplomaticquarterapp.PermissionManager
+
+import android.app.Activity
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Build
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+
+class PermissionManager(
+ private val context: Context,
+ val listener: PermissionListener,
+ private val requestCode: Int,
+ vararg permissions: String
+) {
+
+ private val permissionsArray = permissions
+
+ interface PermissionListener {
+ fun onPermissionGranted()
+ fun onPermissionDenied()
+ }
+
+ fun arePermissionsGranted(): Boolean {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ permissionsArray.all {
+ ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
+ }
+ } else {
+ true
+ }
+ }
+
+ fun requestPermissions(activity: Activity) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ ActivityCompat.requestPermissions(activity, permissionsArray, requestCode)
+ }
+ }
+
+ fun handlePermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
+ if (this.requestCode == requestCode) {
+ val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
+ if (allGranted) {
+ listener.onPermissionGranted()
+ } else {
+ listener.onPermissionDenied()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionResultReceiver.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionResultReceiver.kt
new file mode 100644
index 00000000..33765192
--- /dev/null
+++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/PermissionManager/PermissionResultReceiver.kt
@@ -0,0 +1,15 @@
+package com.cloud.diplomaticquarterapp.PermissionManager
+
+// PermissionResultReceiver.kt
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+
+class PermissionResultReceiver(
+ private val callback: (Boolean) -> Unit
+) : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ val granted = intent?.getBooleanExtra("PERMISSION_GRANTED", false) ?: false
+ callback(granted)
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinMethod.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinMethod.kt
new file mode 100644
index 00000000..c76f9784
--- /dev/null
+++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinMethod.kt
@@ -0,0 +1,13 @@
+package com.cloud.diplomaticquarterapp.penguin
+
+enum class PenguinMethod {
+ // initializePenguin("initializePenguin"),
+ // configurePenguin("configurePenguin"),
+ // showPenguinUI("showPenguinUI"),
+ // onPenNavUIDismiss("onPenNavUIDismiss"),
+ // onReportIssue("onReportIssue"),
+ // onPenNavSuccess("onPenNavSuccess"),
+ onPenNavInitializationError // onLocationOffCampus("onLocationOffCampus"),
+ // navigateToPOI("navigateToPOI"),
+ // openSharedLocation("openSharedLocation");
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinNavigator.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinNavigator.kt
new file mode 100644
index 00000000..98245cc9
--- /dev/null
+++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinNavigator.kt
@@ -0,0 +1,97 @@
+package com.cloud.diplomaticquarterapp.penguin
+
+import android.content.Context
+import com.google.gson.Gson
+import com.peng.pennavmap.PlugAndPlaySDK
+import com.peng.pennavmap.connections.ApiController
+import com.peng.pennavmap.interfaces.RefIdDelegate
+import com.peng.pennavmap.models.TokenModel
+import com.peng.pennavmap.models.postmodels.PostToken
+import com.peng.pennavmap.utils.AppSharedData
+import okhttp3.ResponseBody
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import android.util.Log
+
+
+class PenguinNavigator() {
+
+ fun navigateTo(mContext: Context, refID: String, delegate: RefIdDelegate,clientID : String,clientKey : String ) {
+ val postToken = PostToken(clientID, clientKey)
+ getToken(mContext, postToken, object : RefIdDelegate {
+ override fun onRefByIDSuccess(PoiId: String?) {
+ Log.e("navigateTo", "PoiId is+++++++ $PoiId")
+
+ PlugAndPlaySDK.navigateTo(mContext, refID, object : RefIdDelegate {
+ override fun onRefByIDSuccess(PoiId: String?) {
+ Log.e("navigateTo", "PoiId 2is+++++++ $PoiId")
+
+ delegate.onRefByIDSuccess(refID)
+
+ }
+
+ override fun onGetByRefIDError(error: String?) {
+ delegate.onRefByIDSuccess(error)
+ }
+
+ })
+
+
+ }
+
+ override fun onGetByRefIDError(error: String?) {
+ delegate.onRefByIDSuccess(error)
+ }
+
+ })
+
+ }
+
+ fun getToken(mContext: Context, postToken: PostToken?, apiTokenCallBack: RefIdDelegate) {
+ try {
+ // Create the API call
+ val purposesCall: Call = ApiController.getInstance(mContext)
+ .apiMethods
+ .getToken(postToken)
+
+ // Enqueue the call for asynchronous execution
+ purposesCall.enqueue(object : Callback {
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ if (response.isSuccessful() && response.body() != null) {
+ try {
+ response.body()?.use { responseBody ->
+ val responseBodyString: String = responseBody.string() // Use `string()` to get the actual response content
+ if (responseBodyString.isNotEmpty()) {
+ val tokenModel = Gson().fromJson(responseBodyString, TokenModel::class.java)
+ if (tokenModel != null && tokenModel.token != null) {
+ AppSharedData.apiToken = tokenModel.token
+ apiTokenCallBack.onRefByIDSuccess(tokenModel.token)
+ } else {
+ apiTokenCallBack.onGetByRefIDError("Failed to parse token model")
+ }
+ } else {
+ apiTokenCallBack.onGetByRefIDError("Response body is empty")
+ }
+ }
+ } catch (e: Exception) {
+ apiTokenCallBack.onGetByRefIDError("An error occurred: ${e.message}")
+ }
+ } else {
+ apiTokenCallBack.onGetByRefIDError("Unsuccessful response: " + response.code())
+ }
+ }
+
+ override fun onFailure(call: Call, t: Throwable) {
+ apiTokenCallBack.onGetByRefIDError(t.message)
+ }
+ })
+ } catch (error: Exception) {
+ apiTokenCallBack.onGetByRefIDError("Exception during API call: $error")
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinView.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinView.kt
new file mode 100644
index 00000000..743ce93b
--- /dev/null
+++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/penguin/PenguinView.kt
@@ -0,0 +1,316 @@
+package com.cloud.diplomaticquarterapp.penguin
+
+import android.app.Activity
+import android.content.Context
+import android.content.Context.RECEIVER_EXPORTED
+import android.content.IntentFilter
+import android.graphics.Color
+import android.os.Build
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import android.widget.RelativeLayout
+import android.widget.Toast
+import androidx.annotation.RequiresApi
+import com.cloud.diplomaticquarterapp.PermissionManager.PermissionHelper
+import com.cloud.diplomaticquarterapp.PermissionManager.PermissionManager
+import com.cloud.diplomaticquarterapp.PermissionManager.PermissionResultReceiver
+import com.ejada.hmg.MainActivity
+import com.peng.pennavmap.PlugAndPlayConfiguration
+import com.peng.pennavmap.PlugAndPlaySDK
+import com.peng.pennavmap.enums.InitializationErrorType
+import com.peng.pennavmap.interfaces.PenNavUIDelegate
+import com.peng.pennavmap.utils.Languages
+import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.platform.PlatformView
+import com.cloud.diplomaticquarterapp.penguin.PenguinNavigator
+import com.peng.pennavmap.interfaces.PIEventsDelegate
+import com.peng.pennavmap.interfaces.PILocationDelegate
+import com.peng.pennavmap.interfaces.RefIdDelegate
+import com.peng.pennavmap.models.PIReportIssue
+/**
+ * Custom PlatformView for displaying Penguin UI components within a Flutter app.
+ * Implements `PlatformView` for rendering the view, `MethodChannel.MethodCallHandler` for handling method calls,
+ * and `PenNavUIDelegate` for handling SDK events.
+ */
+@RequiresApi(Build.VERSION_CODES.O)
+internal class PenguinView(
+ context: Context,
+ id: Int,
+ val creationParams: Map,
+ messenger: BinaryMessenger,
+ activity: MainActivity,
+ val channel: MethodChannel
+) : PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate {
+ // The layout for displaying the Penguin UI
+ private val mapLayout: RelativeLayout = RelativeLayout(context)
+ private val _context: Context = context
+
+ private val permissionResultReceiver: PermissionResultReceiver
+ private val permissionIntentFilter = IntentFilter("PERMISSION_RESULT_ACTION")
+
+ private companion object {
+ const val PERMISSIONS_REQUEST_CODE = 1
+ }
+
+ private lateinit var permissionManager: PermissionManager
+
+ // Reference to the main activity
+ private var _activity: Activity = activity
+
+ private lateinit var mContext: Context
+
+ lateinit var navigator: PenguinNavigator
+
+ init {
+ // Set layout parameters for the mapLayout
+ mapLayout.layoutParams = ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
+ )
+
+ mContext = context
+
+
+ permissionResultReceiver = PermissionResultReceiver { granted ->
+ if (granted) {
+ onPermissionsGranted()
+ } else {
+ onPermissionsDenied()
+ }
+ }
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ mContext.registerReceiver(
+ permissionResultReceiver,
+ permissionIntentFilter,
+ RECEIVER_EXPORTED
+ )
+ } else {
+ mContext.registerReceiver(
+ permissionResultReceiver,
+ permissionIntentFilter,
+ )
+ }
+
+ // Set the background color of the layout
+ mapLayout.setBackgroundColor(Color.RED)
+
+ permissionManager = PermissionManager(
+ context = mContext,
+ listener = object : PermissionManager.PermissionListener {
+ override fun onPermissionGranted() {
+ // Handle permissions granted
+ onPermissionsGranted()
+ }
+
+ override fun onPermissionDenied() {
+ // Handle permissions denied
+ onPermissionsDenied()
+ }
+ },
+ requestCode = PERMISSIONS_REQUEST_CODE,
+ *PermissionHelper.getRequiredPermissions()
+ )
+
+ if (!permissionManager.arePermissionsGranted()) {
+ permissionManager.requestPermissions(_activity)
+ } else {
+ // Permissions already granted
+ permissionManager.listener.onPermissionGranted()
+ }
+
+
+ }
+
+ private fun onPermissionsGranted() {
+ // Handle the actions when permissions are granted
+ Log.d("PermissionsResult", "onPermissionsGranted")
+ // Register the platform view factory for creating custom views
+
+ // Initialize the Penguin SDK
+ initPenguin()
+
+
+ }
+
+ private fun onPermissionsDenied() {
+ // Handle the actions when permissions are denied
+ Log.d("PermissionsResult", "onPermissionsDenied")
+
+ }
+
+ /**
+ * Returns the view associated with this PlatformView.
+ *
+ * @return The main view for this PlatformView.
+ */
+ override fun getView(): View {
+ return mapLayout
+ }
+
+ /**
+ * Cleans up resources associated with this PlatformView.
+ */
+ override fun dispose() {
+ // Cleanup code if needed
+ }
+
+ /**
+ * Handles method calls from Dart code.
+ *
+ * @param call The method call from Dart.
+ * @param result The result callback to send responses back to Dart.
+ */
+ override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
+ // Handle method calls from Dart code here
+ }
+
+ /**
+ * Initializes the Penguin SDK with custom configuration and delegates.
+ */
+ private fun initPenguin() {
+ navigator = PenguinNavigator()
+ // Configure the PlugAndPlaySDK
+ val language = when (creationParams["languageCode"] as String) {
+ "ar" -> Languages.ar
+ "en" -> Languages.en
+ else -> {
+ Languages.en
+ }
+ }
+ Log.d(
+ "TAG",
+ "initPenguin: ${Languages.getLanguageEnum(creationParams["languageCode"] as String)}"
+ )
+ PlugAndPlaySDK.configuration = PlugAndPlayConfiguration.Builder()
+ .setBaseUrl(
+ creationParams["dataURL"] as String,
+ creationParams["positionURL"] as String
+ )
+ .setServiceName(
+ creationParams["dataServiceName"] as String,
+ creationParams["positionServiceName"] as String
+ )
+ .setClientData(
+ creationParams["clientID"] as String,
+ creationParams["clientKey"] as String
+ )
+ .setUserName(creationParams["username"] as String)
+// .setLanguageID(Languages.en)
+ .setLanguageID(language)
+ .setSimulationModeEnabled(creationParams["isSimulationModeEnabled"] as Boolean)
+ .setEnableBackButton(true)
+// .setDeepLinkData("deeplink")
+ .setCustomizeColor("#2CA0AF")
+ .setDeepLinkSchema("")
+ .build()
+
+ // Set location delegate to handle location updates
+ PlugAndPlaySDK.setPiLocationDelegate {
+ // Example code to handle location updates
+ // Uncomment and modify as needed
+ // if (location.size() > 0)
+ // Toast.makeText(_context, "Location Info Latitude: ${location[0]}, Longitude: ${location[1]}", Toast.LENGTH_SHORT).show()
+ }
+
+ // Set events delegate for reporting issues
+ PlugAndPlaySDK.setPiEventsDelegate { }
+
+ // Start the Penguin SDK
+ PlugAndPlaySDK.start(mContext, this)
+ }
+
+
+ /**
+ * Navigates to the specified reference ID.
+ *
+ * @param refID The reference ID to navigate to.
+ */
+ fun navigateTo(refID: String) {
+ try {
+ if (refID.isBlank()) {
+ Log.e("navigateTo", "Invalid refID: The reference ID is blank.")
+
+ }
+
+
+
+// referenceId = refID
+
+
+ navigator.navigateTo(mContext, refID,object : RefIdDelegate {
+ override fun onRefByIDSuccess(PoiId: String?) {
+ Log.e("navigateTo", "PoiId is penguin view+++++++ $PoiId")
+
+// channelFlutter.invokeMethod(
+// PenguinMethod.navigateToPOI.name,
+// "navigateTo Success"
+// )
+ }
+
+ override fun onGetByRefIDError(error: String?) {
+ Log.e("navigateTo", "error is penguin view+++++++ $error")
+
+// channelFlutter.invokeMethod(
+// PenguinMethod.navigateToPOI.name,
+// "navigateTo Failed: Invalid refID"
+// )
+ }
+ } , creationParams["clientID"] as String, creationParams["clientKey"] as String )
+
+ } catch (e: Exception) {
+ Log.e("navigateTo", "Exception occurred during navigation: ${e.message}", e)
+// channelFlutter.invokeMethod(
+// PenguinMethod.navigateToPOI.name,
+// "Failed: Exception - ${e.message}"
+// )
+ }
+ }
+
+ /**
+ * Called when Penguin UI setup is successful.
+ *
+ * @param warningCode Optional warning code received from the SDK.
+ */
+ override fun onPenNavSuccess(warningCode: String?) {
+ val clinicId = creationParams["clinicID"] as String
+
+ if(clinicId.isEmpty()) return
+
+ navigateTo(clinicId)
+ }
+
+ /**
+ * Called when there is an initialization error with Penguin UI.
+ *
+ * @param description Description of the error.
+ * @param errorType Type of initialization error.
+ */
+ override fun onPenNavInitializationError(
+ description: String?,
+ errorType: InitializationErrorType?
+ ) {
+ val arguments: Map = mapOf(
+ "description" to description,
+ "type" to errorType?.name
+ )
+
+ channel.invokeMethod(PenguinMethod.onPenNavInitializationError.name, arguments)
+ Toast.makeText(mContext, "Navigation Error: $description", Toast.LENGTH_SHORT).show()
+ }
+
+ /**
+ * Called when Penguin UI is dismissed.
+ */
+ override fun onPenNavUIDismiss() {
+ // Handle UI dismissal if needed
+ try {
+ mContext.unregisterReceiver(permissionResultReceiver)
+ dispose();
+ } catch (e: IllegalArgumentException) {
+ Log.e("PenguinView", "Receiver not registered: $e")
+ }
+ }
+}
+
diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt
index 7fbf859a..57da2eb8 100644
--- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt
+++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt
@@ -22,7 +22,7 @@ import com.github.kittinunf.fuel.httpPost
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import io.flutter.plugin.common.MethodChannel
-import org.jetbrains.anko.doAsyncResult
+//import org.jetbrains.anko.doAsyncResult
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
@@ -149,7 +149,7 @@ fun sendNotification(context: Context, title: String, @Nullable subtitle: String
val notificationPendingIntent = stackBuilder.getPendingIntent(getUniqueId(), PendingIntent.FLAG_UPDATE_CURRENT)
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
- .setSmallIcon(R.mipmap.ic_launcher)
+ .setSmallIcon(R.mipmap.ic_launcher_local)
.setContentIntent(notificationPendingIntent)
.setAutoCancel(true)
.setContentTitle(title)
@@ -208,7 +208,6 @@ fun httpPost(url: String, body: Map, onSuccess: (response: HTTP
.header("Content-Type", "application/json")
.header("Allow", "*/*")
.response { request, response, result ->
- result.doAsyncResult { }
result.fold({ data ->
val dataString = String(data)
if (isJSONValid(dataString)) {
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png
similarity index 100%
rename from android/app/src/main/res/mipmap-hdpi/ic_launcher.png
rename to android/app/src/main/res/mipmap-hdpi/ic_launcher_local.png
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png
similarity index 100%
rename from android/app/src/main/res/mipmap-mdpi/ic_launcher.png
rename to android/app/src/main/res/mipmap-mdpi/ic_launcher_local.png
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_local.png
similarity index 100%
rename from android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
rename to android/app/src/main/res/mipmap-xhdpi/ic_launcher_local.png
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png
similarity index 100%
rename from android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
rename to android/app/src/main/res/mipmap-xxhdpi/ic_launcher_local.png
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png
similarity index 100%
rename from android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
rename to android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_local.png
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 4e107030..1093435a 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -19,4 +19,5 @@
Geofence requests happened too frequently.
+ sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg
diff --git a/android/build.gradle b/android/build.gradle
index b5185cca..c5f1baa2 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -13,6 +13,20 @@ buildscript {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
+ maven {
+ url 'https://api.mapbox.com/downloads/v2/releases/maven'
+
+ credentials {
+ username = 'mapbox'
+ password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
+ if (password == null || password == "") {
+ throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the enviroment variables.")
+ }
+ }
+ authentication {
+ basic(BasicAuthentication)
+ }
+ }
// maven {
// url "https://dl.bintray.com/kotlin/kotlin-eap/"
@@ -26,6 +40,7 @@ buildscript {
// classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12'
+ classpath "com.mapbox.gradle.plugins:access-token:0.4.0"
}
}
@@ -34,12 +49,29 @@ allprojects {
google()
// jcenter()
mavenCentral()
+ flatDir {
+ dirs 'libs'
+ }
maven {
url 'https://developer.huawei.com/repo/'
}
maven {
url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local"
}
+ maven {
+ url 'https://api.mapbox.com/downloads/v2/releases/maven'
+
+ credentials {
+ username = 'mapbox'
+ password = "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
+ if (password == null || password == "") {
+ throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the enviroment variables.")
+ }
+ }
+ authentication {
+ basic(BasicAuthentication)
+ }
+ }
}
}
diff --git a/android/gradle.properties b/android/gradle.properties
index 06a44c05..cf554544 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -3,3 +3,5 @@ org.gradle.jvmargs=-Xmx4096m
android.useAndroidX=true
android.enableJetifier=true
android.suppressUnsupportedCompileSdk=33
+MAPBOX_USER_NAME = "mapbox"
+MAPBOX_DOWNLOADS_TOKEN="sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg"
\ No newline at end of file
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index cb6be309..c5ff5d37 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 11.0
+ 13.0
diff --git a/ios/Podfile b/ios/Podfile
index 5495f0ca..5564c00b 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -33,6 +33,7 @@ target 'Runner' do
pod 'OpenTok', '~> 2.22.0'
pod 'VTO2Lib'
+ pod 'MapboxMaps', '10.18.2'
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
@@ -54,6 +55,7 @@ post_install do |installer|
]
build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64 i386'
build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
+ build_configuration.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
xcconfig_path = build_configuration.base_configuration_reference.real_path
xcconfig = File.read(xcconfig_path)
xcconfig_mod = xcconfig.gsub(/DT_TOOLCHAIN_DIR/, "TOOLCHAIN_DIR")
@@ -62,6 +64,17 @@ post_install do |installer|
if build_configuration.build_settings['WRAPPER_EXTENSION'] == 'bundle'
build_configuration.build_settings['DEVELOPMENT_TEAM'] = '3A359E86ZF'
end
+ if target.name == 'MapboxMobileEvents'
+ `xcrun -sdk iphoneos bitcode_strip -r Pods/MapboxMobileEvents/MapboxMobileEvents.xcframework/ios-arm64_armv7/MapboxMobileEvents.framework/MapboxMobileEvents -o Pods/MapboxMobileEvents/MapboxMobileEvents.xcframework/ios-arm64_armv7/MapboxMobileEvents.framework/MapboxMobileEvents`
+ end
+
+ if target.name == 'MapboxCommon'
+ `xcrun -sdk iphoneos bitcode_strip -r Pods/MapboxCommon/MapboxCommon.xcframework/ios-arm64/MapboxCommon.framework/MapboxCommon -o Pods/MapboxCommon/MapboxCommon.xcframework/ios-arm64/MapboxCommon.framework/MapboxCommon`
+ end
+
+ if target.name == 'MapboxCoreMaps'
+ `xcrun -sdk iphoneos bitcode_strip -r Pods/MapboxCoreMaps/MapboxCoreMaps.xcframework/ios-arm64/MapboxCoreMaps.framework/MapboxCoreMaps -o Pods/MapboxCoreMaps/MapboxCoreMaps.xcframework/ios-arm64/MapboxCoreMaps.framework/MapboxCoreMaps`
+ end
end
end
end
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index e7357518..5dad833f 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -8,18 +8,30 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 29631B9E2C96C7F600DF5916 /* PenguinNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29631B9D2C96C7F600DF5916 /* PenguinNavigator.swift */; };
301C79AE27200D9F0016307B /* OpenTokRemoteVideoFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301C79AD27200D9F0016307B /* OpenTokRemoteVideoFactory.swift */; };
301C79B027200DED0016307B /* OpenTokLocalVideoFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301C79AF27200DED0016307B /* OpenTokLocalVideoFactory.swift */; };
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 */; };
- 4EE411B2E3CB5D4F81AE5078 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D1513E0724DAFB89C198BDD /* Pods_Runner.framework */; };
+ 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, ); }; };
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 */; };
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 */; };
+ 76D71B6A2C6B819000DAFB84 /* PenguinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B692C6B819000DAFB84 /* PenguinModel.swift */; };
+ 76D71B6C2C6B81B300DAFB84 /* PenguinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B6B2C6B81B300DAFB84 /* PenguinView.swift */; };
+ 76D71B6E2C6B81CC00DAFB84 /* PenguinPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B6D2C6B81CC00DAFB84 /* PenguinPlugin.swift */; };
+ 76D71B702C6B81EA00DAFB84 /* PenguinViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76D71B6F2C6B81EA00DAFB84 /* PenguinViewFactory.swift */; };
76F2556127F1FFED0062C1CD /* PassKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76F2556027F1FFED0062C1CD /* PassKit.framework */; };
+ 76F9B0E22C6DED310064C51B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13E5B711BC29EB6ECCE1964C /* Pods_Runner.framework */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@@ -43,12 +55,15 @@
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
- 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ 768D81742C6DF6E4005C655F /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
+ 47C935032C91766900981BA7 /* PenguinINRenderer.xcframework in Embed Frameworks */,
+ 47C935012C91766800981BA7 /* Penguin.xcframework in Embed Frameworks */,
+ 47C935052C91766A00981BA7 /* PenNavUI.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -56,14 +71,18 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 13E5B711BC29EB6ECCE1964C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 29631B9D2C96C7F600DF5916 /* PenguinNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinNavigator.swift; sourceTree = ""; };
301C79AD27200D9F0016307B /* OpenTokRemoteVideoFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokRemoteVideoFactory.swift; sourceTree = ""; };
301C79AF27200DED0016307B /* OpenTokLocalVideoFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokLocalVideoFactory.swift; sourceTree = ""; };
306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokPlatformBridge.swift; sourceTree = ""; };
306FE6CA271D8B73002D6EFC /* OpenTok.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTok.swift; sourceTree = ""; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
- 3D1513E0724DAFB89C198BDD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenguinINRenderer.xcframework; path = Frameworks/PenguinINRenderer.xcframework; sourceTree = ""; };
+ 47C934FB2C91766400981BA7 /* PenNavUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = PenNavUI.xcframework; path = Frameworks/PenNavUI.xcframework; sourceTree = ""; };
+ 47C934FC2C91766400981BA7 /* Penguin.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Penguin.xcframework; path = Frameworks/Penguin.xcframework; sourceTree = ""; };
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 = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
@@ -74,6 +93,11 @@
7643E4062BE0D0B400BD2F25 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LaunchScreen.strings; sourceTree = ""; };
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 = ""; };
+ 76D71B662C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMGPenguinInPlatformBridge.swift; sourceTree = ""; };
+ 76D71B692C6B819000DAFB84 /* PenguinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinModel.swift; sourceTree = ""; };
+ 76D71B6B2C6B81B300DAFB84 /* PenguinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinView.swift; sourceTree = ""; };
+ 76D71B6D2C6B81CC00DAFB84 /* PenguinPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinPlugin.swift; sourceTree = ""; };
+ 76D71B6F2C6B81EA00DAFB84 /* PenguinViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinViewFactory.swift; sourceTree = ""; };
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 = ""; };
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 = ""; };
@@ -110,10 +134,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 76F9B0E22C6DED310064C51B /* Pods_Runner.framework in Frameworks */,
76F2556127F1FFED0062C1CD /* PassKit.framework in Frameworks */,
76815B27275F381C00E66E94 /* HealthKit.framework in Frameworks */,
E9620805255C2ED100D3A35D /* NetworkExtension.framework in Frameworks */,
- 4EE411B2E3CB5D4F81AE5078 /* Pods_Runner.framework in Frameworks */,
+ 47C935042C91766A00981BA7 /* PenNavUI.xcframework in Frameworks */,
+ 47C935002C91766800981BA7 /* Penguin.xcframework in Frameworks */,
+ 47C935022C91766900981BA7 /* PenguinINRenderer.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -133,10 +160,13 @@
555EAAA626EFB641859EF0BE /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 47C934FC2C91766400981BA7 /* Penguin.xcframework */,
+ 47C934FA2C91766400981BA7 /* PenguinINRenderer.xcframework */,
+ 47C934FB2C91766400981BA7 /* PenNavUI.xcframework */,
76F2556027F1FFED0062C1CD /* PassKit.framework */,
76815B26275F381C00E66E94 /* HealthKit.framework */,
E9620804255C2ED100D3A35D /* NetworkExtension.framework */,
- 3D1513E0724DAFB89C198BDD /* Pods_Runner.framework */,
+ 13E5B711BC29EB6ECCE1964C /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "";
@@ -151,6 +181,18 @@
path = Pods;
sourceTree = "";
};
+ 76D71B682C6B817500DAFB84 /* Penguin */ = {
+ isa = PBXGroup;
+ children = (
+ 76D71B692C6B819000DAFB84 /* PenguinModel.swift */,
+ 76D71B6B2C6B81B300DAFB84 /* PenguinView.swift */,
+ 76D71B6D2C6B81CC00DAFB84 /* PenguinPlugin.swift */,
+ 76D71B6F2C6B81EA00DAFB84 /* PenguinViewFactory.swift */,
+ 29631B9D2C96C7F600DF5916 /* PenguinNavigator.swift */,
+ );
+ path = Penguin;
+ sourceTree = "";
+ };
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -186,6 +228,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
+ 76D71B682C6B817500DAFB84 /* Penguin */,
762D738C274E42650063CE73 /* ring_30Sec.caf */,
762D738D274E42650063CE73 /* ring_30Sec.mp3 */,
306FE6C9271D8B54002D6EFC /* OpenTok */,
@@ -220,6 +263,7 @@
E923EFD52587443800E3E751 /* HMGPlatformBridge.swift */,
306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */,
E9F7623A25922BCE00FB5CCF /* FlutterConstants.swift */,
+ 76D71B662C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift */,
);
path = Helper;
sourceTree = "";
@@ -254,7 +298,7 @@
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
- 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 768D81742C6DF6E4005C655F /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
487FDD6493EB9AE7D8E39485 /* [CP] Embed Pods Frameworks */,
4671D3CD126F6635F4B75A6E /* [CP] Copy Pods Resources */,
@@ -274,7 +318,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1430;
+ LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -419,12 +463,18 @@
buildActionMask = 2147483647;
files = (
306FE6C8271D790C002D6EFC /* OpenTokPlatformBridge.swift in Sources */,
+ 76D71B6E2C6B81CC00DAFB84 /* PenguinPlugin.swift in Sources */,
E923EFD225863FDF00E3E751 /* GeoZoneModel.swift in Sources */,
E91B539A256AAA6500E96549 /* MainFlutterVC.swift in Sources */,
+ 76D71B672C6B7F9C00DAFB84 /* HMGPenguinInPlatformBridge.swift in Sources */,
E91B539C256AAA6500E96549 /* HMG_GUEST_bkp.swift in Sources */,
E91B5396256AAA6500E96549 /* GlobalHelper.swift in Sources */,
E923EFD4258645C100E3E751 /* HMG_Geofence.swift in Sources */,
E923EFD62587443800E3E751 /* HMGPlatformBridge.swift in Sources */,
+ 76D71B6C2C6B81B300DAFB84 /* PenguinView.swift in Sources */,
+ 29631B9E2C96C7F600DF5916 /* PenguinNavigator.swift in Sources */,
+ 76D71B6A2C6B819000DAFB84 /* PenguinModel.swift in Sources */,
+ 76D71B702C6B81EA00DAFB84 /* PenguinViewFactory.swift in Sources */,
301C79AE27200D9F0016307B /* OpenTokRemoteVideoFactory.swift in Sources */,
E9F7623B25922BCE00FB5CCF /* FlutterConstants.swift in Sources */,
306FE6CB271D8B73002D6EFC /* OpenTok.swift in Sources */,
@@ -528,6 +578,7 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
@@ -553,10 +604,13 @@
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
- SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_COMPILATION_MODE = singlefile;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
@@ -675,6 +729,7 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
@@ -700,10 +755,14 @@
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_COMPILATION_MODE = singlefile;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@@ -713,6 +772,7 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
@@ -738,11 +798,14 @@
PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
- SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_COMPILATION_MODE = singlefile;
"SWIFT_COMPILATION_MODE[arch=*]" = singlefile;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index fab8f735..b2d2f7e5 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
HMGPenguinInPlatformBridge{
+ assert((HMGPenguinInPlatformBridge.shared_ != nil), "HMGPenguinInPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
+ return HMGPenguinInPlatformBridge.shared_!
+ }
+
+ private func openChannel(){
+ flutterMethodChannelPenguinIn = FlutterMethodChannel(name: channelName, binaryMessenger: mainViewController.binaryMessenger)
+
+ flutterMethodChannelPenguinIn?.setMethodCallHandler { (methodCall, result) in
+ print("Called function \(methodCall.method)")
+
+ if let arguments = methodCall.arguments as Any? {
+ if methodCall.method == "launchPenguin"{
+ self.launchPenguinView(arguments: arguments, result: result)
+ }
+ } else {
+ result(FlutterError(code: "INVALID_ARGUMENT", message: "Storyboard name is required", details: nil))
+ }
+ }
+ }
+
+ private func launchPenguinView(arguments: Any, result: @escaping FlutterResult) {
+ let penguinView = PenguinView(
+ frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height),
+ viewIdentifier: 0,
+ arguments: arguments,
+ binaryMessenger: mainViewController.binaryMessenger
+ )
+
+ let penguinUIView = penguinView.view()
+ penguinUIView.frame = mainViewController.view.bounds
+ penguinUIView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ mainViewController.view.addSubview(penguinUIView)
+
+ result(nil) // Call result to indicate the method was successfully handled
+ }
+
+}
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 43474d39..13782c80 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -39,7 +39,7 @@
LSRequiresIPhoneOS
MinimumOSVersion
- 11.0
+ 13.0
NFCReaderUsageDescription
This app requires NFC Usage access to allow for Online CheckIn for appointments.
NSAppTransportSecurity
@@ -60,7 +60,7 @@
NSCalendarsUsageDescription
This app requires calendar access to set reminders for Virtual & Normal Appointments.
NSCalendarsWriteOnlyAccessUsageDescription
- This app requires calendar access to set reminders for Virtual & Normal Appointments.
+ This app requires calendar access to set reminders for Virtual & Normal Appointments.
NSCalendarsFullAccessUsageDescription
This app requires calendar access to set reminders for Virtual & Normal Appointments.
NSCameraUsageDescription
diff --git a/ios/Runner/Penguin/PenguinModel.swift b/ios/Runner/Penguin/PenguinModel.swift
new file mode 100644
index 00000000..e41979d6
--- /dev/null
+++ b/ios/Runner/Penguin/PenguinModel.swift
@@ -0,0 +1,76 @@
+//
+// PenguinModel.swift
+// Runner
+//
+// Created by Amir on 06/08/2024.
+//
+
+import Foundation
+
+// Define the model class
+struct PenguinModel {
+ let baseURL: String
+ let dataURL: String
+ let dataServiceName: String
+ let positionURL: String
+ let clientKey: String
+ let storyboardName: String
+ let mapBoxKey: String
+ let clientID: String
+ let positionServiceName: String
+ let username: String
+ let isSimulationModeEnabled: Bool
+ let isShowUserName: Bool
+ let isUpdateUserLocationSmoothly: Bool
+ let isEnableReportIssue: Bool
+ let languageCode: String
+ let clinicID: String
+ let patientID: String
+ let projectID: String
+
+ // Initialize the model from a dictionary
+ init?(from dictionary: [String: Any]) {
+ guard
+ let baseURL = dictionary["baseURL"] as? String,
+ let dataURL = dictionary["dataURL"] as? String,
+ let dataServiceName = dictionary["dataServiceName"] as? String,
+ let positionURL = dictionary["positionURL"] as? String,
+ let clientKey = dictionary["clientKey"] as? String,
+ let storyboardName = dictionary["storyboardName"] as? String,
+ let mapBoxKey = dictionary["mapBoxKey"] as? String,
+ let clientID = dictionary["clientID"] as? String,
+ let positionServiceName = dictionary["positionServiceName"] as? String,
+ let username = dictionary["username"] as? String,
+ let isSimulationModeEnabled = dictionary["isSimulationModeEnabled"] as? Bool,
+ let isShowUserName = dictionary["isShowUserName"] as? Bool,
+ let isUpdateUserLocationSmoothly = dictionary["isUpdateUserLocationSmoothly"] as? Bool,
+ let isEnableReportIssue = dictionary["isEnableReportIssue"] as? Bool,
+ let languageCode = dictionary["languageCode"] as? String,
+ let clinicID = dictionary["clinicID"] as? String,
+ let patientID = dictionary["patientID"] as? String,
+ let projectID = dictionary["projectID"] as? String
+ else {
+ print("Initialization failed due to missing or invalid keys.")
+ return nil
+ }
+
+ self.baseURL = baseURL
+ self.dataURL = dataURL
+ self.dataServiceName = dataServiceName
+ self.positionURL = positionURL
+ self.clientKey = clientKey
+ self.storyboardName = storyboardName
+ self.mapBoxKey = mapBoxKey
+ self.clientID = clientID
+ self.positionServiceName = positionServiceName
+ self.username = username
+ self.isSimulationModeEnabled = isSimulationModeEnabled
+ self.isShowUserName = isShowUserName
+ self.isUpdateUserLocationSmoothly = isUpdateUserLocationSmoothly
+ self.isEnableReportIssue = isEnableReportIssue
+ self.languageCode = languageCode
+ self.clinicID = clinicID
+ self.patientID = patientID
+ self.projectID = projectID
+ }
+}
diff --git a/ios/Runner/Penguin/PenguinNavigator.swift b/ios/Runner/Penguin/PenguinNavigator.swift
new file mode 100644
index 00000000..e7ce55b4
--- /dev/null
+++ b/ios/Runner/Penguin/PenguinNavigator.swift
@@ -0,0 +1,57 @@
+import PenNavUI
+import UIKit
+
+class PenguinNavigator {
+ private var config: PenguinModel
+
+ init(config: PenguinModel) {
+ self.config = config
+ }
+
+ private func logError(_ message: String) {
+ // Centralized logging function
+ print("PenguinSDKNavigator Error: \(message)")
+ }
+
+ func navigateToPOI( referenceId:String,completion: @escaping (Bool, String?) -> Void) {
+ PenNavUIManager.shared.getToken(clientID: config.clientID, clientKey: config.clientKey) { [weak self] token, error in
+
+ if let error = error {
+ let errorMessage = "Token error while getting the for Navigate to method"
+ completion(false, "Failed to get token: \(errorMessage)")
+
+ print("Failed to get token: \(errorMessage)")
+ return
+ }
+
+ guard let token = token else {
+ completion(false, "Token is nil")
+ print("Token is nil")
+ return
+ }
+ print("Token Generated")
+ print(token);
+
+
+ }
+ }
+
+ private func handleNavigation(referenceId: String, token: String, completion: @escaping (Bool, String?) -> Void) {
+ DispatchQueue.main.async {
+ PenNavUIManager.shared.setToken(token: token)
+
+ PenNavUIManager.shared.navigate(to: referenceId) { [weak self] _, navError in
+ guard let self = self else { return }
+
+ if let navError = navError {
+ self.logError("Navigation error: Reference ID invalid")
+ completion(false, "Navigation error: \(navError.localizedDescription)")
+ return
+ }
+
+ // Navigation successful
+ completion(true, nil)
+ }
+ }
+ }
+}
diff --git a/ios/Runner/Penguin/PenguinPlugin.swift b/ios/Runner/Penguin/PenguinPlugin.swift
new file mode 100644
index 00000000..029bec35
--- /dev/null
+++ b/ios/Runner/Penguin/PenguinPlugin.swift
@@ -0,0 +1,31 @@
+//
+// BlueGpsPlugin.swift
+// Runner
+//
+// Created by Penguin .
+//
+
+//import Foundation
+//import Flutter
+//
+///**
+// * A Flutter plugin for integrating Penguin SDK functionality.
+// * This class registers a view factory with the Flutter engine to create native views.
+// */
+//class PenguinPlugin: NSObject, FlutterPlugin {
+//
+// /**
+// * Registers the plugin with the Flutter engine.
+// *
+// * @param registrar The [FlutterPluginRegistrar] used to register the plugin.
+// * This method is called when the plugin is initialized, and it sets up the communication
+// * between Flutter and native code.
+// */
+// public static func register(with registrar: FlutterPluginRegistrar) {
+// // Create an instance of PenguinViewFactory with the binary messenger from the registrar
+// let factory = PenguinViewFactory(messenger: registrar.messenger())
+//
+// // Register the view factory with a unique ID for use in Flutter code
+// registrar.register(factory, withId: "penguin_native")
+// }
+//}
diff --git a/ios/Runner/Penguin/PenguinView.swift b/ios/Runner/Penguin/PenguinView.swift
new file mode 100644
index 00000000..81377f7b
--- /dev/null
+++ b/ios/Runner/Penguin/PenguinView.swift
@@ -0,0 +1,224 @@
+//
+// BlueGpsView.swift
+// Runner
+//
+// Created by Penguin.
+//
+
+import Foundation
+import UIKit
+import Flutter
+import PenNavUI
+
+import Foundation
+import Flutter
+import UIKit
+
+/**
+ * A custom Flutter platform view for displaying Penguin UI components.
+ * This class integrates with the Penguin navigation SDK and handles UI events.
+ */
+class PenguinView: NSObject, FlutterPlatformView
+
+, PIEventsDelegate, PenNavInitializationDelegate
+{
+
+ // The main view displayed within the platform view
+ private var _view: UIView
+ private var model: PenguinModel?
+
+
+ /**
+ * Initializes the PenguinView with the provided parameters.
+ *
+ * @param frame The frame of the view, specifying its size and position.
+ * @param viewId A unique identifier for this view instance.
+ * @param args Optional arguments provided for creating the view.
+ * @param messenger The [FlutterBinaryMessenger] used for communication with Dart.
+ */
+ init(
+ frame: CGRect,
+ viewIdentifier viewId: Int64,
+ arguments args: Any?,
+ binaryMessenger messenger: FlutterBinaryMessenger?
+ ) {
+ _view = UIView()
+ super.init()
+
+ // Get the screen's width and height to set the view's frame
+ let screenWidth = UIScreen.main.bounds.width
+ let screenHeight = UIScreen.main.bounds.height
+
+ // Uncomment to set the background color of the view
+ // _view.backgroundColor = UIColor.red
+
+ // Set the frame of the view to cover the entire screen
+ _view.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
+ print("========Inside Penguin View ========")
+ print(args)
+ guard let arguments = args as? [String: Any] else {
+ print("Error: Arguments are not in the expected format.")
+ return
+ }
+ print("===== i got tha Args=======")
+
+ // Initialize the model from the arguments
+ if let penguinModel = PenguinModel(from: arguments) {
+ self.model = penguinModel
+ initPenguin(args: penguinModel)
+ } else {
+ print("Error: Failed to initialize PenguinModel from arguments ")
+ }
+ // Initialize the Penguin SDK with required configurations
+ // initPenguin( arguments: args)
+ }
+
+ /**
+ * Initializes the Penguin SDK with custom configuration settings.
+ */
+ func initPenguin(args: PenguinModel) {
+// Set the initialization delegate to handle SDK initialization events
+ PenNavUIManager.shared.initializationDelegate = self
+ // Configure the Penguin SDK with necessary parameters
+ PenNavUIManager.shared
+ .setClientKey(args.clientKey)
+ .setClientID(args.clientID)
+ .setUsername(args.username)
+ .setSimulationModeEnabled(isEnable: args.isSimulationModeEnabled)
+ .setBaseURL(dataURL: args.dataURL, positionURL: args.positionURL)
+ .setServiceName(dataServiceName: args.dataServiceName, positionServiceName: args.positionServiceName)
+ .setIsShowUserName(args.isShowUserName)
+ .setIsUpdateUserLocationSmoothly(args.isUpdateUserLocationSmoothly)
+ .setEnableReportIssue(enable: args.isEnableReportIssue)
+ .setLanguage(args.languageCode)
+ .setBackButtonVisibility(true)
+ .build()
+ }
+
+ /**
+ * Returns the main view associated with this platform view.
+ *
+ * @return The UIView instance that represents this platform view.
+ */
+ func view() -> UIView {
+ return _view
+ }
+
+ // MARK: - PIEventsDelegate Methods
+
+ /**
+ * Called when the Penguin UI is dismissed.
+ */
+ func onPenNavUIDismiss() {
+ // Handle UI dismissal if needed
+ print("====== onPenNavUIDismiss =========")
+
+
+ self.view().removeFromSuperview()
+ }
+
+ /**
+ * Called when a report issue is generated.
+ *
+ * @param issue The type of issue reported.
+ */
+ func onReportIssue(_ issue: PenNavUI.IssueType) {
+ // Handle report issue events if needed
+ print("====== onReportIssueError =========")
+ }
+
+ /**
+ * Called when the Penguin UI setup is successful.
+ */
+ func onPenNavSuccess() {
+ print("====== onPenNavSuccess =========")
+ // Obtain the FlutterViewController instance
+ let controller: FlutterViewController = UIApplication.shared.windows.first?.rootViewController as! FlutterViewController
+
+ print("====== after contoller onPenNavSuccess =========")
+
+ // Set the events delegate to handle SDK events
+ PenNavUIManager.shared.eventsDelegate = self
+
+ print("====== after eventsDelegate onPenNavSuccess =========")
+
+ // Present the Penguin UI on top of the Flutter view controller
+ PenNavUIManager.shared.present(root: controller, view: _view)
+
+
+ print("====== after present onPenNavSuccess =========")
+ print(model?.clinicID)
+ print("====== after present onPenNavSuccess =========")
+
+ guard let config = self.model else {
+ print("Error: Config Model is nil")
+ return
+ }
+
+ guard let clinicID = self.model?.clinicID,
+ let clientID = self.model?.clientID, !clientID.isEmpty else {
+ print("Error: Config Client ID is nil or empty")
+ return
+ }
+
+ let navigator = PenguinNavigator(config: config)
+
+ PenNavUIManager.shared.getToken(clientID: config.clientID, clientKey: config.clientKey) { [weak self] token, error in
+ if let error = error {
+ let errorMessage = "Token error while getting the for Navigate to method"
+ print("Failed to get token: \(errorMessage)")
+ return
+ }
+
+ guard let token = token else {
+ print("Token is nil")
+ return
+ }
+ print("Token Generated")
+ print(token);
+
+ self?.handleNavigation(clinicID: clinicID, token: token) { success, errorMessage in
+ if success {
+ print("Navigation successful")
+ } else {
+ print("Navigation failed: \(errorMessage ?? "Unknown error")")
+ }
+
+ }
+
+ print("====== after Token onPenNavSuccess =========")
+ }
+
+ }
+
+
+
+ private func handleNavigation(clinicID: String, token: String, completion: @escaping (Bool, String?) -> Void) {
+ DispatchQueue.main.async {
+ PenNavUIManager.shared.setToken(token: token)
+ PenNavUIManager.shared.navigate(to: clinicID)
+ completion(true,nil)
+ }
+ }
+
+
+
+
+ /**
+ * Called when there is an initialization error with the Penguin UI.
+ *
+ * @param errorType The type of initialization error.
+ * @param errorDescription A description of the error.
+ */
+ func onPenNavInitializationError(errorType: PenNavUI.PenNavUIError, errorDescription: String) {
+ // Handle initialization errors if needed
+
+ print("onPenNavInitializationErrorType: \(errorType.rawValue)")
+ print("onPenNavInitializationError: \(errorDescription)")
+
+ }
+
+
+
+
+}
diff --git a/ios/Runner/Penguin/PenguinViewFactory.swift b/ios/Runner/Penguin/PenguinViewFactory.swift
new file mode 100644
index 00000000..a88bb5d0
--- /dev/null
+++ b/ios/Runner/Penguin/PenguinViewFactory.swift
@@ -0,0 +1,59 @@
+//
+// BlueGpsViewFactory.swift
+// Runner
+//
+// Created by Penguin .
+//
+
+import Foundation
+import Flutter
+
+/**
+ * A factory class for creating instances of [PenguinView].
+ * This class implements `FlutterPlatformViewFactory` to create and manage native views.
+ */
+class PenguinViewFactory: NSObject, FlutterPlatformViewFactory {
+
+ // The binary messenger used for communication with the Flutter engine
+ private var messenger: FlutterBinaryMessenger
+
+ /**
+ * Initializes the PenguinViewFactory with the given messenger.
+ *
+ * @param messenger The [FlutterBinaryMessenger] used to communicate with Dart code.
+ */
+ init(messenger: FlutterBinaryMessenger) {
+ self.messenger = messenger
+ super.init()
+ }
+
+ /**
+ * Creates a new instance of [PenguinView].
+ *
+ * @param frame The frame of the view, specifying its size and position.
+ * @param viewId A unique identifier for this view instance.
+ * @param args Optional arguments provided for creating the view.
+ * @return An instance of [PenguinView] configured with the provided parameters.
+ */
+ func create(
+ withFrame frame: CGRect,
+ viewIdentifier viewId: Int64,
+ arguments args: Any?
+ ) -> FlutterPlatformView {
+ return PenguinView(
+ frame: frame,
+ viewIdentifier: viewId,
+ arguments: args,
+ binaryMessenger: messenger)
+ }
+
+ /**
+ * Returns the codec used for encoding and decoding method channel arguments.
+ * This method is required when `arguments` in `create` is not `nil`.
+ *
+ * @return A [FlutterMessageCodec] instance used for serialization.
+ */
+ public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
+ return FlutterStandardMessageCodec.sharedInstance()
+ }
+}
diff --git a/lib/config/config.dart b/lib/config/config.dart
index 75eac393..16a900ec 100644
--- a/lib/config/config.dart
+++ b/lib/config/config.dart
@@ -22,8 +22,8 @@ var PACKAGES_ORDER_HISTORY = '/api/orders/items';
var PACKAGES_TAMARA_OPT = '/api/orders/paymentoptions/tamara';
// var BASE_URL = 'http://10.50.100.198:2018/';
// var BASE_URL = 'http://10.50.100.198:4422/';
-// var BASE_URL = 'https://uat.hmgwebservices.com/';
-var BASE_URL = 'https://hmgwebservices.com/';
+var BASE_URL = 'https://uat.hmgwebservices.com/';
+// var BASE_URL = 'https://hmgwebservices.com/';
// var BASE_URL = 'http://10.20.200.111:1010/';
// var BASE_URL = 'https://orash.cloudsolutions.com.sa/';
// var BASE_URL = 'https://vidauat.cloudsolutions.com.sa/';
diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart
index a2165f33..7107d357 100644
--- a/lib/config/localized_values.dart
+++ b/lib/config/localized_values.dart
@@ -1976,5 +1976,8 @@ const Map localizedValues = {
"selectHospitalBloodDonation": {"en": "Please select the hospital you want to book an appointment with: ", "ar": "يرجى اختيار المستشفى الذي تريد حجز موعد معه:"},
"wecare": {"en": "We Care", "ar": "نحن نهتم"},
"myinstructions": {"en": "My Instructions", "ar": "تعليماتي"},
+ "clinicLocation": {"en": "Clinic Location", "ar": "موقع العيادة"},
"searchClinic": {"en": "Search Clinic", "ar": "بحث العيادة"},
+ "selectBranch":{"en":"Select Branch", "ar":"اختر الفرع"},
+ "searchByBranch":{"en":"Search By Branch Name", "ar":"البحث عن طريق اسم الفرع"}
};
diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart
index 98a884f4..3bd1cf62 100644
--- a/lib/core/service/client/base_app_client.dart
+++ b/lib/core/service/client/base_app_client.dart
@@ -199,9 +199,9 @@ class BaseAppClient {
// }
// if (AppGlobal.isNetworkDebugEnabled) {
- // print("URL : $url");
- // final jsonBody = json.encode(body);
- // print(jsonBody);
+ print("URL : $url");
+ final jsonBody = json.encode(body);
+ print(jsonBody);
// }
if (await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck)) {
diff --git a/lib/core/viewModels/project_view_model.dart b/lib/core/viewModels/project_view_model.dart
index 7216da7b..61b453a4 100644
--- a/lib/core/viewModels/project_view_model.dart
+++ b/lib/core/viewModels/project_view_model.dart
@@ -19,6 +19,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter_datetime_picker_plus/flutter_datetime_picker_plus.dart';
bool isAppArabic = false;
+
class ProjectViewModel extends BaseViewModel {
GAnalytics get analytics => locator();
@@ -38,6 +39,7 @@ class ProjectViewModel extends BaseViewModel {
dynamic searchvalue;
bool isLogin = false;
bool _isAllAppointmentsLoaded = false;
+
bool get isAllAppointmentsLoaded => _isAllAppointmentsLoaded;
bool isPatientAdmitted = false;
bool patientHasAdmissionRequest = false;
@@ -45,15 +47,17 @@ class ProjectViewModel extends BaseViewModel {
GetAdmissionInfoResponseModel getAdmissionInfoResponseModel = GetAdmissionInfoResponseModel();
GetAdmissionRequestInfoResponseModel getAdmissionRequestInfoResponseModel = GetAdmissionRequestInfoResponseModel();
+ bool isIndoorNavigationEnabled = false;
+
void setIsAllAppointmentsLoaded(bool value) {
_isAllAppointmentsLoaded = value;
notifyListeners();
}
-
RegisterInfoResponse _registerInfo = RegisterInfoResponse();
RegisterInfoResponse get registerInfo => _registerInfo;
+
dynamic get searchValue => searchvalue;
Locale get appLocal => _appLocale;
@@ -70,7 +74,9 @@ class ProjectViewModel extends BaseViewModel {
List _projectDetailListModel = [];
List get privileges => isLoginChild ? privilegeChildUser : privilegeChildUser;
+
List get vidaPlusProjectList => _vidaPlusProjectListModel;
+
List get hMCProjectListModel => _hMCProjectListModel;
List get projectDetailListModel => _projectDetailListModel;
@@ -137,6 +143,11 @@ class ProjectViewModel extends BaseViewModel {
notifyListeners();
}
+ setIsIndoorNavigationEnabled(bool isEnabled) {
+ this.isIndoorNavigationEnabled = isEnabled;
+ notifyListeners();
+ }
+
setPatientHasAdmissionRequest(bool hasAdmissionRequest) {
this.patientHasAdmissionRequest = hasAdmissionRequest;
notifyListeners();
@@ -200,8 +211,6 @@ class ProjectViewModel extends BaseViewModel {
notifyListeners();
}
-
-
bool havePrivilege(int id) {
bool isHavePrivilege = false;
try {
@@ -222,7 +231,7 @@ class ProjectViewModel extends BaseViewModel {
@override
void dispose() {
- if (subscription != null) subscription.cancel();
+ if (subscription != null) subscription.cancel();
super.dispose();
}
diff --git a/lib/pages/AlHabibMedicalService/all_habib_medical_service_page2.dart b/lib/pages/AlHabibMedicalService/all_habib_medical_service_page2.dart
index f23d175d..420f08f1 100644
--- a/lib/pages/AlHabibMedicalService/all_habib_medical_service_page2.dart
+++ b/lib/pages/AlHabibMedicalService/all_habib_medical_service_page2.dart
@@ -37,6 +37,7 @@ class _AllHabibMedicalSevicePage2State extends State
AuthProvider authProvider = new AuthProvider();
WeatherService _weatherService = WeatherService();
double weatherNum = 30;
+ late ProjectViewModel projectViewModel;
@override
void initState() {
@@ -235,7 +236,7 @@ class _AllHabibMedicalSevicePage2State extends State
itemCount: hmgServices.length,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext context, int index) {
- return ServicesView(hmgServices[index], index, false);
+ return ServicesView(hmgServices[index], index, false, projectViewModel);
},
),
),
diff --git a/lib/pages/InPatientServices/components/inpatient_pending_advance_payment.dart b/lib/pages/InPatientServices/components/inpatient_pending_advance_payment.dart
index 82e6ab96..8281450b 100644
--- a/lib/pages/InPatientServices/components/inpatient_pending_advance_payment.dart
+++ b/lib/pages/InPatientServices/components/inpatient_pending_advance_payment.dart
@@ -272,7 +272,7 @@ class _InPatientPendingAdvancePaymentState extends State {
navigateToInsertComplaint();
locator().appointment.appointment_detail_action(appointment: widget.appo, action: 'raise complaint');
break;
+
+ case "goToNavigation":
+ initPenguinSDK();
+ locator().appointment.appointment_detail_action(appointment: widget.appo, action: 'navigate to clinic');
+ break;
+ }
+ }
+
+ initPenguinSDK() async {
+ NavigationClinicDetails data = NavigationClinicDetails();
+ // data.clinicId = widget.appo.clinicID.toString();
+ data.clinicId = "49";
+ data.patientId = widget.appo.patientID.toString();
+ data.projectId = widget.appo.projectID.toString();
+ final bool permited = await AppPermission.askPenguinPermissions();
+ if (!permited) {
+ Map statuses = await [
+ Permission.location,
+ Permission.bluetooth,
+ Permission.bluetoothConnect,
+ Permission.bluetoothScan,
+ Permission.activityRecognition,
+ ].request().whenComplete(() {
+ PenguinMethodChannel.launch("penguin", widget.projectViewModel!.isArabic ? "ar" : "en", widget.projectViewModel!.authenticatedUserObject.user.patientID.toString(), details: data);
+ });
}
}
diff --git a/lib/pages/ToDoList/ToDo.dart b/lib/pages/ToDoList/ToDo.dart
index bb1c3f93..b9ede8f8 100644
--- a/lib/pages/ToDoList/ToDo.dart
+++ b/lib/pages/ToDoList/ToDo.dart
@@ -29,10 +29,12 @@ import 'package:diplomaticquarterapp/services/livecare_services/livecare_provide
import 'package:diplomaticquarterapp/services/payfort_services/payfort_project_details_resp_model.dart';
import 'package:diplomaticquarterapp/services/payfort_services/payfort_view_model.dart';
import 'package:diplomaticquarterapp/theme/colors.dart';
+import 'package:diplomaticquarterapp/uitl/app-permissions.dart';
import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
import 'package:diplomaticquarterapp/uitl/app_toast.dart';
import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
+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';
@@ -50,6 +52,7 @@ import 'package:flutter_countdown_timer/current_remaining_time.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
class ToDo extends StatefulWidget {
@@ -354,23 +357,56 @@ class _ToDoState extends State with SingleTickerProviderStateMixin {
style: TextStyle(fontSize: 10, fontWeight: FontWeight.w600, color: Color(0xff2E303A), letterSpacing: -0.48, height: 25 / 16),
),
),
- InkWell(
- onTap: () {
- navigateToAppointmentDetails(context, appoList[index]);
- },
- child: Padding(
- padding: const EdgeInsets.only(top: 0.0),
- child: Text(
- TranslationBase.of(context).moreDetails,
- style: TextStyle(
- fontSize: 10,
- fontWeight: FontWeight.w600,
- color: CustomColors.accentColor,
- letterSpacing: -0.48,
- height: 25 / 16,
- decoration: TextDecoration.underline),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ InkWell(
+ onTap: () {
+ navigateToAppointmentDetails(context, appoList[index]);
+ },
+ child: Padding(
+ padding: const EdgeInsets.only(top: 0.0),
+ child: Text(
+ TranslationBase.of(context).moreDetails,
+ style: TextStyle(
+ fontSize: 10,
+ fontWeight: FontWeight.w600,
+ color: CustomColors.accentColor,
+ letterSpacing: -0.48,
+ height: 25 / 16,
+ decoration: TextDecoration.underline),
+ ),
+ ),
),
- ),
+ if (projectViewModel.isIndoorNavigationEnabled)
+ InkWell(
+ onTap: () {
+ NavigationClinicDetails data = NavigationClinicDetails();
+ // data.clinicId = appoList[index].clinicID.toString();
+ data.clinicId = "46";
+ data.patientId = appoList[index].patientID.toString();
+ data.projectId = appoList[index].projectID.toString();
+ initPenguinSDK(data);
+ },
+ child: Column(
+ children: [
+ SvgPicture.asset(
+ "assets/images/new/Indoor_nav_appo.svg",
+ ),
+ Text(
+ TranslationBase.of(context).clinicLocation,
+ style: TextStyle(
+ fontSize: 10,
+ fontWeight: FontWeight.w600,
+ color: CustomColors.accentColor,
+ letterSpacing: -0.48,
+ height: 25 / 16,
+ decoration: TextDecoration.underline),
+ ),
+ ],
+ ),
+ ),
+ ],
),
],
),
@@ -530,6 +566,21 @@ class _ToDoState extends State with SingleTickerProviderStateMixin {
);
}
+ initPenguinSDK(NavigationClinicDetails data) async {
+ final bool permited = await AppPermission.askPenguinPermissions();
+ if (!permited) {
+ Map statuses = await [
+ Permission.location,
+ Permission.bluetooth,
+ Permission.bluetoothConnect,
+ Permission.bluetoothScan,
+ Permission.activityRecognition,
+ ].request().whenComplete(() {
+ PenguinMethodChannel.launch("penguin", projectViewModel.isArabic ? "ar" : "en", projectViewModel.authenticatedUserObject.user.patientID.toString(), details: data);
+ });
+ }
+ }
+
String getNextActionImage(nextAction) {
switch (nextAction) {
case 0:
diff --git a/lib/pages/landing/fragments/home_page_fragment2.dart b/lib/pages/landing/fragments/home_page_fragment2.dart
index c1c922ac..7711b4ff 100644
--- a/lib/pages/landing/fragments/home_page_fragment2.dart
+++ b/lib/pages/landing/fragments/home_page_fragment2.dart
@@ -52,7 +52,11 @@ class _HomePageFragment2State extends State {
hmgServices.add(HmgServices(0, TranslationBase.of(context).book, TranslationBase.of(context).appointmentLabel, "assets/images/new/book appointment.svg", isLogin));
hmgServices.add(HmgServices(1, TranslationBase.of(context).liveCare, TranslationBase.of(context).onlineConsulting, "assets/images/new/Live_Care.svg", isLogin));
- hmgServices.add(HmgServices(2, TranslationBase.of(context).emergencyTitle, TranslationBase.of(context).emergencySubtitle, "assets/images/new/emergency.svg", isLogin));
+
+ projectViewModel.isIndoorNavigationEnabled
+ ? hmgServices.add(HmgServices(2, "Hospital", "Navigation", "assets/images/new/indoor_nav_home.svg", isLogin))
+ : hmgServices.add(HmgServices(2, TranslationBase.of(context).emergencyTitle, TranslationBase.of(context).emergencySubtitle, "assets/images/new/emergency.svg", isLogin));
+
hmgServices.add(HmgServices(3, TranslationBase.of(context).hhcHome, TranslationBase.of(context).healthCare, "assets/images/new/HHC.svg", isLogin));
hmgServices.add(HmgServices(4, TranslationBase.of(context).checkup, TranslationBase.of(context).comprehensive, "assets/images/new/comprehensive_checkup.svg", isLogin));
hmgServices.add(HmgServices(5, TranslationBase.of(context).online, TranslationBase.of(context).payment, "assets/images/new/paymentMethods.png", isLogin));
@@ -296,15 +300,16 @@ class _HomePageFragment2State extends State {
child: ServicesView(
new HmgServices(23, TranslationBase.of(context).InPatient, TranslationBase.of(context).inPatientServices, "assets/images/new/InPatient.svg", false),
23,
- true)),
+ true,
+ projectViewModel)),
),
),
Expanded(
flex: 4,
child: AspectRatio(
aspectRatio: 1.0,
- child: ServicesView(
- new HmgServices(5, TranslationBase.of(context).online, TranslationBase.of(context).payment, "assets/images/new/paymentMethods.png", false), 2, true)),
+ child: ServicesView(new HmgServices(5, TranslationBase.of(context).online, TranslationBase.of(context).payment, "assets/images/new/paymentMethods.png", false), 2,
+ true, projectViewModel)),
),
],
),
@@ -322,7 +327,7 @@ class _HomePageFragment2State extends State {
itemCount: hmgServices.length,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext context, int index) {
- return ServicesView(hmgServices[index], index, true);
+ return ServicesView(hmgServices[index], index, true, projectViewModel);
},
),
),
@@ -341,7 +346,7 @@ class _HomePageFragment2State extends State {
itemCount: hmgServices.length,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext context, int index) {
- return ServicesView(hmgServices[index], index, true);
+ return ServicesView(hmgServices[index], index, true, projectViewModel, isLocked: hmgServices[index].action == 2 ? !projectViewModel.havePrivilege(107) : false);
},
),
),
@@ -489,8 +494,7 @@ class _HomePageFragment2State extends State {
flex: 1,
child: InkWell(
onTap: () {
- if (projectViewModel.havePrivilege(100))
- widget.onPharmacyClick!();
+ if (projectViewModel.havePrivilege(100)) widget.onPharmacyClick!();
},
child: Stack(children: [
Container(
diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart
index 6fe004fc..0cf6fd2c 100644
--- a/lib/pages/landing/landing_page.dart
+++ b/lib/pages/landing/landing_page.dart
@@ -43,7 +43,7 @@ import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_app_icon_badge/flutter_app_icon_badge.dart';
+// import 'package:flutter_app_icon_badge/flutter_app_icon_badge.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart';
@@ -664,7 +664,7 @@ class _LandingPageState extends State with WidgetsBindingObserver {
notificationCount = value['List_PatientDashboard'][0]['UnreadPatientNotificationCount'] > 99 ? '99+' : value['List_PatientDashboard'][0]['UnreadPatientNotificationCount'].toString();
model.setState(model.count, 0, true, notificationCount);
sharedPref.setString(NOTIFICATION_COUNT, notificationCount);
- FlutterAppIconBadge.updateBadge(int.parse(notificationCount));
+ // FlutterAppIconBadge.updateBadge(int.parse(notificationCount));
}
});
// if (await AppSharedPreferences().getBool(IS_LAST_APPOINTMENT_RATE_SHOWN) == null || !await AppSharedPreferences().getBool(IS_LAST_APPOINTMENT_RATE_SHOWN)) {
diff --git a/lib/pages/landing/widgets/services_view.dart b/lib/pages/landing/widgets/services_view.dart
index 5635a4a6..c69f772c 100644
--- a/lib/pages/landing/widgets/services_view.dart
+++ b/lib/pages/landing/widgets/services_view.dart
@@ -4,7 +4,9 @@ import 'package:auto_size_text/auto_size_text.dart';
import 'package:diplomaticquarterapp/analytics/google-analytics.dart';
import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/config/size_config.dart';
+import 'package:diplomaticquarterapp/core/model/hospitals/hospitals_model.dart';
import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart';
+import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart';
import 'package:diplomaticquarterapp/models/hmg_services.dart';
import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/%E2%80%8B%20health_calculators.dart';
@@ -31,14 +33,20 @@ import 'package:diplomaticquarterapp/pages/medical/smart_watch_health_data/smart
import 'package:diplomaticquarterapp/pages/paymentService/payment_service.dart';
import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart';
import 'package:diplomaticquarterapp/theme/colors.dart';
+import 'package:diplomaticquarterapp/uitl/app-permissions.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
import 'package:diplomaticquarterapp/uitl/location_util.dart';
+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/widgets/dialogs/covid_consent_dialog.dart';
+import 'package:diplomaticquarterapp/widgets/dialogs/location_selection_dialog.dart';
+import 'package:diplomaticquarterapp/widgets/dialogs/radio_selection_dialog.dart';
import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:permission_handler/permission_handler.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../locator.dart';
@@ -52,8 +60,10 @@ class ServicesView extends StatelessWidget {
PharmacyModuleViewModel pharmacyModuleViewModel = locator();
late LocationUtils locationUtils;
bool isHomePage;
+ late ProjectViewModel projectViewModel;
+ bool isLocked;
- ServicesView(this.hmgServices, this.index, this.isHomePage);
+ ServicesView(this.hmgServices, this.index, this.isHomePage, this.projectViewModel, {this.isLocked = false});
@override
Widget build(BuildContext context) {
@@ -159,12 +169,57 @@ class ServicesView extends StatelessWidget {
],
),
),
+ isLocked
+ ? Container(
+ width: double.infinity,
+ height: double.infinity,
+ decoration: containerRadiusWithGradientServices(20, lightColor: Colors.grey.withOpacity(0.6), darkColor: Colors.grey.withOpacity(0.6)),
+ child: Icon(
+ Icons.lock_outline,
+ size: 40,
+ ),
+ )
+ : Container()
],
),
),
);
}
+ openNavigationProjectSelection(BuildContext context) {
+ int _selectedHospitalIndex = 0;
+ List projectsListLocal = [];
+ Utils.navigationProjectsList.forEach((v) {
+ projectsListLocal.add(new HospitalsModel.fromJson(v));
+ });
+ showDialog(
+ context: context,
+ builder: (cxt) => LocationSelectionDialog(
+ data: projectsListLocal,
+ selectedIndex: _selectedHospitalIndex,
+ onValueSelected: (index) {
+ _selectedHospitalIndex = index;
+ initPenguinSDK(projectsListLocal[index].iD);
+ },
+ ),
+ );
+ }
+
+ initPenguinSDK(int projectID) async {
+ final bool permited = await AppPermission.askPenguinPermissions();
+ if (!permited) {
+ Map statuses = await [
+ Permission.location,
+ Permission.bluetooth,
+ Permission.bluetoothConnect,
+ Permission.bluetoothScan,
+ Permission.activityRecognition,
+ ].request().whenComplete(() {
+ PenguinMethodChannel.launch("penguin", projectViewModel.isArabic ? "ar" : "en", "1231755");
+ });
+ } //
+ }
+
handleHomePageServices(HmgServices hmgServices, BuildContext context) {
if (hmgServices.action == 0) {
Navigator.push(context, FadePage(page: Search()));
@@ -172,8 +227,13 @@ class ServicesView extends StatelessWidget {
} else if (hmgServices.action == 1) {
openLiveCare(context);
} else if (hmgServices.action == 2) {
- Navigator.push(context, FadePage(page: ErOptions(isAppbar: true)));
- locator().hmgServices.logServiceName('emergency service');
+ // initPenguinSDK();
+ if (projectViewModel.isIndoorNavigationEnabled) {
+ if (!isLocked) openNavigationProjectSelection(context);
+ } else {
+ Navigator.push(context, FadePage(page: ErOptions(isAppbar: true)));
+ locator().hmgServices.logServiceName('emergency service');
+ }
} else if (hmgServices.action == 3) {
Navigator.push(context, FadePage(page: HomeHealthCarePage()));
locator().hmgServices.logServiceName('home health care');
@@ -266,10 +326,8 @@ class ServicesView extends StatelessWidget {
} else if (hmgServices.action == 21) {
Navigator.of(context).push(
MaterialPageRoute(
- builder: (BuildContext context) => MyWebView(
- title: "HMG News",
- selectedUrl:"https://twitter.com/hmg" //"https://twitter.com/hashtag/مجموعة_د_سليمان_الحبيب_الطبية?src=hashtag_click&f=live",
- ),
+ builder: (BuildContext context) => MyWebView(title: "HMG News", selectedUrl: "https://twitter.com/hmg" //"https://twitter.com/hashtag/مجموعة_د_سليمان_الحبيب_الطبية?src=hashtag_click&f=live",
+ ),
),
);
locator().hmgServices.logServiceName('latest news');
diff --git a/lib/pages/livecare/video-call-web-page.dart b/lib/pages/livecare/video-call-web-page.dart
index 46a29924..f755d1b0 100644
--- a/lib/pages/livecare/video-call-web-page.dart
+++ b/lib/pages/livecare/video-call-web-page.dart
@@ -14,7 +14,7 @@ class VideoCallWebPage extends StatelessWidget{
final String receiverId;
final String callerId;
VideoCallWebPage({required this.receiverId, required this.callerId}){
- request = URLRequest(url: Uri.parse("https://vcallapi.hmg.com/Mobileindex.html?username=$receiverId&doctorid=$callerId"));
+ request = URLRequest(url: WebUri.uri(Uri.parse("https://vcallapi.hmg.com/Mobileindex.html?username=$receiverId&doctorid=$callerId")));
}
InAppWebViewGroupOptions options = InAppWebViewGroupOptions(
diff --git a/lib/pages/medical/smart_watch_health_data/syncHealthData.dart b/lib/pages/medical/smart_watch_health_data/syncHealthData.dart
index e6ec5c9a..6d6fdf4f 100644
--- a/lib/pages/medical/smart_watch_health_data/syncHealthData.dart
+++ b/lib/pages/medical/smart_watch_health_data/syncHealthData.dart
@@ -34,7 +34,7 @@ class _syncHealthDataButtonState extends State {
int MedCategoryID = 0;
- HealthFactory health = HealthFactory();
+ // HealthFactory health = HealthFactory();
List types = [HealthDataType.STEPS, HealthDataType.HEART_RATE, Platform.isAndroid ? HealthDataType.DISTANCE_DELTA : HealthDataType.DISTANCE_WALKING_RUNNING];
@override
@@ -48,29 +48,29 @@ class _syncHealthDataButtonState extends State {
}
checkPermissions() async {
- if (Platform.isAndroid) {
- if (await PermissionService.isHealthDataPermissionEnabled()) {
- await health.requestAuthorization(types).then((value) {
- if (value) {
- readAll();
- }
- });
- } else {
- Utils.showPermissionConsentDialog(context, TranslationBase.of(context).physicalActivityPermission, () async {
- await health.requestAuthorization(types).then((value) {
- if (value) {
- readAll();
- }
- });
- });
- }
- } else {
- await health.requestAuthorization(types).then((value) {
- if (value) {
- readAll();
- }
- });
- }
+ // if (Platform.isAndroid) {
+ // if (await PermissionService.isHealthDataPermissionEnabled()) {
+ // await health.requestAuthorization(types).then((value) {
+ // if (value) {
+ // readAll();
+ // }
+ // });
+ // } else {
+ // Utils.showPermissionConsentDialog(context, TranslationBase.of(context).physicalActivityPermission, () async {
+ // await health.requestAuthorization(types).then((value) {
+ // if (value) {
+ // readAll();
+ // }
+ // });
+ // });
+ // }
+ // } else {
+ // await health.requestAuthorization(types).then((value) {
+ // if (value) {
+ // readAll();
+ // }
+ // });
+ // }
}
void readAll() async {
@@ -83,13 +83,13 @@ class _syncHealthDataButtonState extends State {
DateTime startDate = DateTime.now().subtract(new Duration(days: 30));
try {
- List healthData = await health.getHealthDataFromTypes(startDate, DateTime.now(), types);
- _healthDataList.addAll(healthData);
+ // List healthData = await health.getHealthDataFromTypes(startDate, DateTime.now(), types);
+ // _healthDataList.addAll(healthData);
} catch (e) {
print("Caught exception in getHealthDataFromTypes: $e");
}
- _healthDataList = HealthFactory.removeDuplicates(_healthDataList);
+ // _healthDataList = HealthFactory.removeDuplicates(_healthDataList);
_healthDataList.forEach((x) {
if (x.type == HealthDataType.STEPS) {
diff --git a/lib/services/payfort_services/payfort_service.dart b/lib/services/payfort_services/payfort_service.dart
index 755ec7b7..64a015cd 100644
--- a/lib/services/payfort_services/payfort_service.dart
+++ b/lib/services/payfort_services/payfort_service.dart
@@ -54,7 +54,7 @@ class PayfortService extends BaseService {
"Pat_Token": result.tokenName,
"IsRefund": false,
"RemmeberMe": false,
- "Reconciliation_Reference": result.reconciliationReference,
+ // "Reconciliation_Reference": result.reconciliationReference,
"LanguageID": 1,
"PatientID": patientID
};
diff --git a/lib/services/permission/permission_service.dart b/lib/services/permission/permission_service.dart
index 641d6444..cc73c303 100644
--- a/lib/services/permission/permission_service.dart
+++ b/lib/services/permission/permission_service.dart
@@ -3,7 +3,7 @@ import 'package:diplomaticquarterapp/core/service/base_service.dart';
import 'package:flutter/material.dart';
import 'package:localstorage/localstorage.dart';
import 'package:permission_handler/permission_handler.dart';
-import 'package:vibration/vibration.dart';
+// import 'package:vibration/vibration.dart';
import 'package:geolocator/geolocator.dart' as geo;
class PermissionService extends BaseService {
@@ -25,10 +25,10 @@ class PermissionService extends BaseService {
vibrate(callback, context) async {
if (callback == null) return null;
if (isVibrationEnabled() == true) {
- if (await Vibration.hasVibrator() !=null) {
- Vibration.vibrate(duration: 100);
- callback();
- }
+ // if (await Vibration.hasVibrator() !=null) {
+ // Vibration.vibrate(duration: 100);
+ // callback();
+ // }
} else {
callback();
}
diff --git a/lib/uitl/app-permissions.dart b/lib/uitl/app-permissions.dart
index 62fd484a..94697e4f 100644
--- a/lib/uitl/app-permissions.dart
+++ b/lib/uitl/app-permissions.dart
@@ -7,9 +7,7 @@ import 'package:permission_handler/permission_handler.dart';
import 'PlatformBridge.dart';
-class AppPermission{
-
-
+class AppPermission {
static Future askVideoCallPermission(BuildContext context) async {
if (!(await Permission.camera.request().isGranted) || !(await Permission.microphone.request().isGranted)) {
return false;
@@ -21,6 +19,30 @@ class AppPermission{
return true;
}
+//
+
+ // Manifest.permission.INTERNET,
+ // Manifest.permission.ACCESS_FINE_LOCATION,
+ // Manifest.permission.ACCESS_COARSE_LOCATION,
+ // Manifest.permission.ACCESS_NETWORK_STATE,
+ // Manifest.permission.BLUETOOTH,
+ // Manifest.permission.BLUETOOTH_ADMIN,
+ // Manifest.permission.BLUETOOTH_SCAN,
+ // Manifest.permission.BLUETOOTH_CONNECT,
+ // Manifest.permission.HIGH_SAMPLING_RATE_SENSORS,
+ // Manifest.permission.ACTIVITY_RECOGNITION
+
+ static Future askPenguinPermissions() async {
+ if (!(await Permission.location.request().isGranted) ||
+ !(await Permission.bluetooth.request().isGranted) ||
+ !(await Permission.bluetoothScan.request().isGranted) ||
+ !(await Permission.bluetoothConnect.request().isGranted) ||
+ !(await Permission.activityRecognition.request().isGranted)) {
+ return false;
+ }
+ return true;
+ }
+
static Future _drawOverAppsMessageDialog(BuildContext context) async {
ConfirmDialog dialog = new ConfirmDialog(
context: context,
@@ -34,4 +56,4 @@ class AppPermission{
cancelFunction: () => {});
dialog.showAlertDialog(context);
}
-}
\ No newline at end of file
+}
diff --git a/lib/uitl/penguin_method_channel.dart b/lib/uitl/penguin_method_channel.dart
new file mode 100644
index 00000000..12421f5e
--- /dev/null
+++ b/lib/uitl/penguin_method_channel.dart
@@ -0,0 +1,98 @@
+import 'package:flutter/services.dart';
+
+class PenguinMethodChannel {
+ static const MethodChannel _channel = MethodChannel('launch_penguin_ui');
+
+ static Future launch(String storyboardName, String languageCode, String username, {NavigationClinicDetails? details}) async {
+ try {
+ await _channel.invokeMethod('launchPenguin', {
+ "storyboardName": storyboardName,
+ "baseURL": "https://prod.hmg.nav.penguinin.com",
+ // "dataURL": "https://hmg.nav.penguinin.com",
+ // "positionURL": "https://hmg.nav.penguinin.com",
+ // "dataURL": "https://hmg-v33.local.penguinin.com",
+ // "positionURL": "https://hmg-v33.local.penguinin.com",
+ "dataURL": "https://prod.hmg.nav.penguinin.com",
+ "positionURL": "https://prod.hmg.nav.penguinin.com",
+ "dataServiceName": "api",
+ "positionServiceName": "pe",
+ "clientID": "HMG",
+ "username": "test",
+ "isSimulationModeEnabled": false,
+ "isShowUserName": false,
+ "isUpdateUserLocationSmoothly": true,
+ "isEnableReportIssue": true,
+ "languageCode": languageCode,
+ "clientKey": "UGVuZ3VpbklOX1Blbk5hdl9QSUY=",
+ "mapBoxKey": "sk.eyJ1IjoicndhaWQiLCJhIjoiY2x6NWo0bTMzMWZodzJrcGZpemYzc3Z4dSJ9.uSSZuwNSGCcCdPAiORECmg",
+ // "clinicID": details?.clinicId ?? "",
+ "clinicID": details?.clinicId ?? "", // 46 ,49, 133
+ "patientID": details?.patientId ?? "",
+ "projectID": details?.projectId ?? "",
+ });
+ } on PlatformException catch (e) {
+ print("Failed to launch PenguinIn: '${e.message}'.");
+ }
+ }
+
+ void setMethodCallHandler(){
+ _channel.setMethodCallHandler((MethodCall call) async {
+ try {
+
+ print(call.method);
+
+ switch (call.method) {
+
+ case PenguinMethodNames.onPenNavInitializationError:
+ _handleInitializationError(call.arguments); // Handle onPenNavInitializationError errors.
+ break;
+ case PenguinMethodNames.onPenNavUIDismiss:
+ //todo handle pen dismissable
+ // _handlePenNavUIDismiss(); // Handle UI dismissal event.
+ break;
+ case PenguinMethodNames.onReportIssue:
+ // Handle the report issue event.
+ _handleInitializationError(call.arguments);
+ break;
+ default:
+ _handleUnknownMethod(call.method); // Handle unknown method calls.
+ }
+ } catch (e) {
+ print("Error handling method call '${call.method}': $e");
+ // Optionally, log this error to an external service
+ }
+ });
+ }
+ static void _handleUnknownMethod(String method) {
+ print("Unknown method: $method");
+ // Optionally, handle this unknown method case, such as reporting or ignoring it
+ }
+
+
+ static void _handleInitializationError(Map error) {
+ final type = error['type'] as String?;
+ final description = error['description'] as String?;
+ print("Initialization Error: ${type ?? 'Unknown Type'}, ${description ?? 'No Description'}");
+
+ }
+
+}
+// Define constants for method names
+class PenguinMethodNames {
+ static const String showPenguinUI = 'showPenguinUI';
+ static const String openSharedLocation = 'openSharedLocation';
+
+ // ---- Handler Method
+ static const String onPenNavSuccess = 'onPenNavSuccess'; // Tested Android,iOS
+ static const String onPenNavInitializationError = 'onPenNavInitializationError'; // Tested Android,iOS
+ static const String onPenNavUIDismiss = 'onPenNavUIDismiss'; //Tested Android,iOS
+ static const String onReportIssue = 'onReportIssue'; // Tested Android,iOS
+ static const String onLocationOffCampus = 'onLocationOffCampus'; // Tested iOS,Android
+ static const String navigateToPOI = 'navigateToPOI'; // Tested Android,iOS
+}
+
+class NavigationClinicDetails {
+ String? clinicId;
+ String? patientId;
+ String? projectId;
+}
diff --git a/lib/uitl/push-notification-handler.dart b/lib/uitl/push-notification-handler.dart
index f1c53bbe..5bf073b3 100644
--- a/lib/uitl/push-notification-handler.dart
+++ b/lib/uitl/push-notification-handler.dart
@@ -15,6 +15,7 @@ import 'package:diplomaticquarterapp/pages/webRTC/OpenTok/OpenTok.dart';
import 'package:diplomaticquarterapp/uitl/LocalNotification.dart';
import 'package:diplomaticquarterapp/uitl/app-permissions.dart';
import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
+import 'package:diplomaticquarterapp/uitl/penguin_method_channel.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:firebase_messaging/firebase_messaging.dart' as fir;
@@ -388,9 +389,16 @@ class PushNotificationHandler {
if (remoteMessage.data.isEmpty) {
return;
}
+ debugPrint('the value of the remote message is ${remoteMessage.data}');
if (remoteMessage.data['is_call'] == 'true' || remoteMessage.data['is_call'] == true) {
_incomingCall(remoteMessage.data);
// showCallkitIncoming(remoteMessage.data);
+ }if(remoteMessage.data['is_navigation'] == 'true' || remoteMessage.data['is_navigation'] == true ){
+ NavigationClinicDetails data = NavigationClinicDetails();
+ data.clinicId = remoteMessage.data['clinic_Id'];
+ data.patientId = remoteMessage.data['patient_Id'];
+ data.projectId = remoteMessage.data['project_Id'];
+ initPenguinSDK(data);
} else {
GetNotificationsResponseModel notification = new GetNotificationsResponseModel();
@@ -408,6 +416,21 @@ class PushNotificationHandler {
}
}
+ initPenguinSDK(NavigationClinicDetails data) async {
+ final bool permited = await AppPermission.askPenguinPermissions();
+ if (!permited) {
+ Map statuses = await [
+ Permission.location,
+ Permission.bluetooth,
+ Permission.bluetoothConnect,
+ Permission.bluetoothScan,
+ Permission.activityRecognition,
+ ].request().whenComplete(() {
+ PenguinMethodChannel.launch("penguin", "en", "1231755", details: data);
+ });
+ }
+ }
+
onToken(String token) async {
// print("Push Notification Token: " + token);
await AppSharedPreferences().setString(PUSH_TOKEN, token);
diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart
index 9aa15082..01e737a8 100644
--- a/lib/uitl/translations_delegate_base.dart
+++ b/lib/uitl/translations_delegate_base.dart
@@ -2963,7 +2963,10 @@ class TranslationBase {
String get selectHospitalBloodDonation => localizedValues["selectHospitalBloodDonation"][locale.languageCode];
String get wecare => localizedValues["wecare"][locale.languageCode];
String get myinstructions => localizedValues["myinstructions"][locale.languageCode];
+ String get clinicLocation => localizedValues["clinicLocation"][locale.languageCode];
String get searchClinic => localizedValues["searchClinic"][locale.languageCode];
+ String get selectBranch => localizedValues["selectBranch"][locale.languageCode];
+ String get searchByBranch => localizedValues["searchByBranch"][locale.languageCode];
}
diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart
index d923dfed..01779851 100644
--- a/lib/uitl/utils.dart
+++ b/lib/uitl/utils.dart
@@ -65,6 +65,30 @@ AppSharedPreferences sharedPref = new AppSharedPreferences();
class Utils {
// static ProgressDialog pr;
+ static var navigationProjectsList = [
+ {
+ "Desciption": "Sahafa Hospital",
+ "DesciptionN": null,
+ "ID": 130,
+ "LegalName": "Sahafa Hospital",
+ "LegalNameN": "مستشفى الصحافة",
+ "Name": "Sahafa Hospital",
+ "NameN": null,
+ "PhoneNumber": "+966115222222",
+ "SetupID": "013311",
+ "DistanceInKilometers": 0,
+ "HasVida3": false,
+ "IsActive": true,
+ "IsHmg": true,
+ "IsVidaPlus": false,
+ "Latitude": "24.8113774",
+ "Longitude": "46.6239813",
+ "MainProjectID": 130,
+ "ProjectOutSA": false,
+ "UsingInDoctorApp": false
+ }
+ ];
+
///show custom Error Toast
/// [message] to show for user
static showErrorToast([String? message]) {
@@ -909,7 +933,7 @@ class Utils {
return projectDetailListModel;
}
- //static String generateSignature() {}
+//static String generateSignature() {}
}
Widget applyShadow({Color color = Colors.grey, double shadowOpacity = 0.5, double spreadRadius = 2, double blurRadius = 7, Offset offset = const Offset(2, 2), required Widget child}) {
diff --git a/lib/widgets/dialogs/location_selection_dialog.dart b/lib/widgets/dialogs/location_selection_dialog.dart
new file mode 100644
index 00000000..9181615f
--- /dev/null
+++ b/lib/widgets/dialogs/location_selection_dialog.dart
@@ -0,0 +1,290 @@
+import 'package:diplomaticquarterapp/core/model/hospitals/hospitals_model.dart';
+import 'package:diplomaticquarterapp/core/viewModels/medical/radiology_view_model.dart';
+import 'package:diplomaticquarterapp/theme/colors.dart';
+import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart';
+import 'package:flutter/material.dart';
+
+import '../../uitl/translations_delegate_base.dart';
+
+class LocationSelectionDialog extends StatelessWidget {
+ final List data;
+ final Function(int)? onValueSelected;
+ final int? selectedIndex;
+
+ const LocationSelectionDialog(
+ {super.key,
+ required this.data,
+ this.onValueSelected,
+ this.selectedIndex});
+
+ @override
+ Widget build(BuildContext context) {
+ return Dialog(
+ backgroundColor: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(8),
+ ),
+ child: LocationDialogBody(
+ data: data,
+ onValueSelected: onValueSelected,
+ selectedIndex: selectedIndex,
+ ));
+ }
+}
+
+class LocationDialogBody extends StatefulWidget {
+ final List data;
+ final Function(int)? onValueSelected;
+ final int? selectedIndex;
+
+ const LocationDialogBody(
+ {super.key,
+ required this.data,
+ this.onValueSelected,
+ this.selectedIndex});
+
+ @override
+ State createState() => _LocationDialogBodyState();
+}
+
+class _LocationDialogBodyState extends State {
+ bool isListVisible = false;
+ int currentlySelected = -1;
+
+ @override
+ Widget build(BuildContext context) {
+ return isListVisible
+ ? LocationListExpandedBody(
+ data: widget.data,
+ onItemClick: (data) {
+ if (data.isEmpty) return;
+ var selected = widget.data.indexWhere(
+ (item) => item.name == data,
+ );
+
+ if (selected == -1) return;
+ setState(() {
+ currentlySelected = selected;
+ isListVisible = false;
+ });
+ },
+ )
+ : LocationListWrapBody(
+ onConfirmClicked: () {
+ widget.onValueSelected?.call(currentlySelected);
+ },
+ onTextBoxClicked: () {
+ setState(() {
+ isListVisible = true;
+ });
+ },
+ selectedText: currentlySelected == -1
+ ? ""
+ : widget.data[currentlySelected].name ?? "");
+ }
+}
+
+class LocationListExpandedBody extends StatefulWidget {
+ final List data;
+ final Function(String) onItemClick;
+
+ const LocationListExpandedBody(
+ {super.key, required this.data, required this.onItemClick});
+
+ @override
+ State createState() =>
+ _LocationListExpandedBodyState();
+}
+
+class _LocationListExpandedBodyState extends State {
+ List tempListData = [];
+ TextEditingController controller = new TextEditingController();
+
+ @override
+ void initState() {
+ super.initState();
+ setState(() {
+ tempListData.addAll(widget.data);
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ child: Padding(
+ padding: const EdgeInsets.all(24),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ SelectBranchHeader(),
+ SizedBox(height: 8,),
+ TextField(
+ controller: controller,
+ onChanged: (v) {
+ tempListData.clear();
+ if (v.length > 0) {
+ for (int i = 0; i < widget.data.length; i++) {
+ if (widget.data[i].name
+ ?.toLowerCase()
+ .contains(v.toLowerCase()) ==
+ true) {
+ tempListData.add(widget.data[i]);
+ }
+ }
+ } else {
+ tempListData.addAll(widget.data);
+ }
+ setState(() {});
+ },
+ decoration: InputDecoration(
+ hintStyle: TextStyle(fontSize: 12),
+ hintText: TranslationBase.of(context).searchByBranch,
+ suffixIcon: Icon(Icons.search),
+ contentPadding: EdgeInsets.symmetric(vertical: 9,horizontal: 14),
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8.0),
+ borderSide: BorderSide(
+ color: Colors.grey, // Normal border color
+ width: 1.0,
+ ),
+ ),
+ ),
+ ),
+ SizedBox(
+ height: 16,
+ ),
+ ListView.builder(
+ itemCount: tempListData.length,
+ shrinkWrap: true,
+ itemBuilder: (context, index) {
+ return Padding(
+ padding: EdgeInsets.only(bottom: 8),
+ child: SizedBox(
+ height: 24,
+ child: InkWell(
+ onTap: () {
+ widget
+ .onItemClick(tempListData[index].name ?? "");
+ },
+ child: Text(
+ "${tempListData[index].name ?? ""} ( ${tempListData[index].distanceInKilometers} km )",
+ style: TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.w600,
+ color: Colors.black,
+ letterSpacing: -0.96),
+ ),
+ ),
+ ),
+ );
+ })
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+class LocationListWrapBody extends StatelessWidget {
+ final VoidCallback? onConfirmClicked;
+ final VoidCallback? onTextBoxClicked;
+ final String selectedText;
+
+ const LocationListWrapBody(
+ {super.key,
+ this.onConfirmClicked,
+ this.onTextBoxClicked,
+ required this.selectedText});
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.all(24.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ SelectBranchHeader(),
+ SizedBox(
+ height: 24,
+ ),
+ ListTile(
+ onTap: () {
+ onTextBoxClicked?.call();
+ },
+ title: Text(
+ TranslationBase.of(context).selectBranch,
+ style: TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.w600,
+ color: Colors.black,
+ letterSpacing: -0.96),
+ ),
+ subtitle: selectedText.isEmpty
+ ? null
+ : Text(
+ selectedText,
+ style: TextStyle(
+ fontSize: 16,
+ fontWeight: FontWeight.w400,
+ color: Colors.black,
+ letterSpacing: -0.96),
+ ),
+ trailing: Icon(
+ Icons.arrow_drop_down_outlined,
+ color: Colors.black,
+ ),
+ shape: RoundedRectangleBorder(
+ side: BorderSide(color: Colors.grey, width: 1),
+ borderRadius: BorderRadius.circular(8),
+ ),
+ ),
+ SizedBox(
+ height: 24,
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Expanded(
+ child: DefaultButton(
+ TranslationBase.of(context).confirm,
+ () {
+ Navigator.pop(context);
+ onConfirmClicked?.call();
+ },
+ color: CustomColors.accentColor,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class SelectBranchHeader extends StatelessWidget{
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ TranslationBase.of(context).selectBranch,
+ style: TextStyle(
+ fontSize: 24,
+ fontWeight: FontWeight.w600,
+ color: Colors.black,
+ letterSpacing: -0.96),
+ ),
+ InkWell(
+ onTap: () {
+ Navigator.of(context).pop();
+ },
+ child: Padding(
+ padding: const EdgeInsets.all(4.0),
+ child: Icon(Icons.close),
+ ))
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/in_app_browser/InAppBrowser.dart b/lib/widgets/in_app_browser/InAppBrowser.dart
index f353eec2..93a4a0e0 100644
--- a/lib/widgets/in_app_browser/InAppBrowser.dart
+++ b/lib/widgets/in_app_browser/InAppBrowser.dart
@@ -38,9 +38,9 @@ class MyInAppBrowser extends InAppBrowser {
static String APPLE_PAY_PAYFORT_URL = 'https://hmgwebservices.com/PayFortWebLive/PayFortApi/MakeApplePayRequest'; // Payfort Payment Gateway URL LIVE
// static String APPLE_PAY_PAYFORT_URL = 'https://hmgwebservices.com/PayFortWebLive/PayFortApi/MakeApplePayRequest'; // Payfort Payment Gateway URL UAT
- // static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT
+ static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT
- static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWebLive/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
@@ -138,7 +138,7 @@ class MyInAppBrowser extends InAppBrowser {
openPackagesPaymentBrowser({required int customer_id, required int order_id}) {
paymentType = _PAYMENT_TYPE.PACKAGES;
var full_url = '$PACKAGES_REQUEST_PAYMENT_URL?customer_id=$customer_id&order_id=$order_id';
- this.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(full_url)), options: _InAppBrowserOptions);
+ this.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(full_url))), options: _InAppBrowserOptions);
}
openPaymentBrowser(num amount, String orderDesc, String transactionID, String projId, String emailId, String paymentMethod, dynamic patientType, String patientName, dynamic patientID,
@@ -190,7 +190,7 @@ class MyInAppBrowser extends InAppBrowser {
String url = "https://hmgwebservices.com/HMGApplePayLive/applepay/pay?apq=" + res['result']; // Prod
// String url = "https://uat.hmgwebservices.com/HMGApplePayLive/applepay/pay?apq=" + res['result']; // UAT
// safariBrowser.open(url: Uri.parse(url));
- this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(url)), options: _InAppBrowserOptions);
+ this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(url))), options: _InAppBrowserOptions);
}).catchError((err) {
print(err);
if (context != null) GifLoaderDialogUtils.hideDialog(context);
@@ -233,7 +233,7 @@ class MyInAppBrowser extends InAppBrowser {
appoNo, clinicID, doctorID, "", installments)
.then((value) {
paymentType = _PAYMENT_TYPE.PATIENT;
- this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(value)), options: _InAppBrowserOptions);
+ this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(value))), options: _InAppBrowserOptions);
});
}).catchError((err) {
print(err);
@@ -245,7 +245,7 @@ class MyInAppBrowser extends InAppBrowser {
clinicID, doctorID)
.then((value) {
paymentType = _PAYMENT_TYPE.PATIENT;
- this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(value)), options: _InAppBrowserOptions);
+ this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(value))), options: _InAppBrowserOptions);
});
}
}
@@ -258,16 +258,16 @@ class MyInAppBrowser extends InAppBrowser {
// getPatientData();
generatePharmacyURL(order, amount, orderDesc, transactionID, emailId, paymentMethod, patientName, patientID, authenticatedUser).then((value) {
if (order.customValuesXml!.contains("ApplePay")) {
- safariBrowser.open(url: Uri.parse(value));
+ safariBrowser.open(url: WebUri.uri(Uri.parse(value)));
} else {
- this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(value)), options: _InAppBrowserOptions);
+ this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(value))), options: _InAppBrowserOptions);
}
});
}
openBrowser(String url) {
this.browser = browser;
- this.browser.openUrlRequest(urlRequest: URLRequest(url: Uri.parse(url)), options: _InAppBrowserOptions);
+ this.browser.openUrlRequest(urlRequest: URLRequest(url: WebUri.uri(Uri.parse(url))), options: _InAppBrowserOptions);
}
Future generateURL(num amount, String orderDesc, String transactionID, String projId, String emailId, String paymentMethod, dynamic patientType, String patientName, dynamic patientID,
@@ -489,7 +489,7 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
}
@override
- void onCompletedInitialLoad() {
+ void onCompletedInitialLoad(bool? didLoadSuccessfully) {
print("ChromeSafari browser initial load completed");
onLoadStartCallback!("ApplePay");
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 8085ed80..02c894e1 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,7 +1,7 @@
name: diplomaticquarterapp
description: A new Flutter application.
-version: 4.5.063+4050063
+version: 4.5.065+4050065
environment:
sdk: ">=3.0.0 <3.13.0"
@@ -34,7 +34,8 @@ dependencies:
get_it: ^7.2.0
#Google Fit & Apple HealthKit
- health: ^3.0.3
+# health: ^3.0.3
+ health: ^11.1.0
#chart
fl_chart: ^0.64.0
@@ -99,7 +100,7 @@ dependencies:
flutter_rating_bar: ^4.0.1
# Calendar
-# syncfusion_flutter_calendar: ^23.1.42
+ # syncfusion_flutter_calendar: ^23.1.42
syncfusion_flutter_calendar: ^24.1.47
# SVG Images
@@ -109,7 +110,7 @@ dependencies:
manage_calendar_events: ^2.0.3
#InAppBrowser
- flutter_inappwebview: ^5.8.0
+ flutter_inappwebview: ^6.1.5
#Circular progress bar for reverse timer
circular_countdown_timer: ^0.2.0
@@ -124,7 +125,7 @@ dependencies:
flutter_datetime_picker_plus: ^2.1.0
carousel_pro_nullsafety: ^2.0.0
flutter_local_notifications: any
- device_calendar: ^4.3.2
+ device_calendar: ^4.3.3
geolocator: ^9.0.2
geocoding: ^2.0.1
jiffy: ^6.2.1
@@ -135,13 +136,15 @@ dependencies:
google_maps_place_picker_mb: ^3.0.0
map_launcher: ^3.0.1
flutter_countdown_timer: ^4.1.0
+ carousel_slider: ^5.0.0
#Dependencies for video call implementation
native_device_orientation: ^1.0.0
- wakelock: ^0.6.2
+# wakelock: ^0.6.2
+ wakelock_plus: ^1.1.4
after_layout: ^1.1.0
cached_network_image: ^3.3.0
flutter_tts: ^3.6.1
- vibration: ^1.7.3
+# vibration: ^1.7.3
flutter_nfc_kit: ^3.3.1
#geofencing: any
speech_to_text: ^6.1.1
@@ -151,16 +154,16 @@ dependencies:
in_app_review: ^2.0.3
badges: ^3.1.2
- flutter_app_icon_badge: ^2.0.0
+# flutter_app_icon_badge: ^2.0.0
# dropdown_search: 5.0.6
- youtube_player_flutter: ^8.1.2
+ youtube_player_flutter: ^9.1.0
# shimmer: ^3.0.0
- carousel_slider: ^5.0.0
+# carousel_slider: ^4.0.0
# flutter_staggered_grid_view: ^0.7.0
huawei_hmsavailability: ^6.11.0+301
huawei_location: ^6.11.0+301
- share_plus: ^6.3.4
+ share_plus: ^10.0.2
# Marker Animation
auto_size_text: ^3.0.0
equatable: ^2.0.3
@@ -170,17 +173,17 @@ dependencies:
google_api_availability: ^5.0.0
open_filex: ^4.3.2
path_provider: ^2.0.8
- amazon_payfort: ^1.1.0
+ amazon_payfort: ^1.1.3
logger: ^2.0.2+1
network_info_plus: any
- flutter_zoom_videosdk: ^1.10.11
+ flutter_zoom_videosdk: ^1.11.2
dart_jsonwebtoken: ^2.14.0
+ win32: ^5.5.4
cloudflare_turnstile: ^2.0.1
dependency_overrides:
- win32: ^5.5.4
dev_dependencies:
flutter_test: