Merge branch 'dev_v3.13.6' into dev_v_3.13.6_CR_6804
# Conflicts: # lib/config/localized_values.dart # lib/pages/BookAppointment/BookConfirm.dart # lib/pages/BookAppointment/QRCode.dartmerge-update-with-lab-changes
@ -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<String, Any>?
|
||||
Log.d("TAG", "configureFlutterEngine: $args")
|
||||
println("args")
|
||||
args?.let {
|
||||
PenguinView(
|
||||
mainActivity,
|
||||
100,
|
||||
args,
|
||||
flutterEngine.dartExecutor.binaryMessenger,
|
||||
activity = mainActivity,
|
||||
channel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
result.notImplemented()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.cloud.diplomaticquarterapp.PermissionManager
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
|
||||
object PermissionHelper {
|
||||
|
||||
fun getRequiredPermissions(): Array<String> {
|
||||
val permissions = mutableListOf(
|
||||
Manifest.permission.INTERNET,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
Manifest.permission.ACCESS_NETWORK_STATE,
|
||||
Manifest.permission.BLUETOOTH,
|
||||
Manifest.permission.BLUETOOTH_ADMIN,
|
||||
// Manifest.permission.ACTIVITY_RECOGNITION
|
||||
)
|
||||
|
||||
// For Android 12 (API level 31) and above, add specific permissions
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12 (API 31) and above
|
||||
permissions.add(Manifest.permission.BLUETOOTH_SCAN)
|
||||
permissions.add(Manifest.permission.BLUETOOTH_CONNECT)
|
||||
permissions.add(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS)
|
||||
}
|
||||
|
||||
return permissions.toTypedArray()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package com.cloud.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<out String>, grantResults: IntArray) {
|
||||
if (this.requestCode == requestCode) {
|
||||
val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
|
||||
if (allGranted) {
|
||||
listener.onPermissionGranted()
|
||||
} else {
|
||||
listener.onPermissionDenied()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.cloud.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)
|
||||
}
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
@ -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<ResponseBody> = ApiController.getInstance(mContext)
|
||||
.apiMethods
|
||||
.getToken(postToken)
|
||||
|
||||
// Enqueue the call for asynchronous execution
|
||||
purposesCall.enqueue(object : Callback<ResponseBody?> {
|
||||
override fun onResponse(
|
||||
call: Call<ResponseBody?>,
|
||||
response: Response<ResponseBody?>
|
||||
) {
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
try {
|
||||
response.body()?.use { responseBody ->
|
||||
val responseBodyString: String = responseBody.string() // Use `string()` to get the actual response content
|
||||
if (responseBodyString.isNotEmpty()) {
|
||||
val tokenModel = Gson().fromJson(responseBodyString, TokenModel::class.java)
|
||||
if (tokenModel != null && tokenModel.token != null) {
|
||||
AppSharedData.apiToken = tokenModel.token
|
||||
apiTokenCallBack.onRefByIDSuccess(tokenModel.token)
|
||||
} else {
|
||||
apiTokenCallBack.onGetByRefIDError("Failed to parse token model")
|
||||
}
|
||||
} else {
|
||||
apiTokenCallBack.onGetByRefIDError("Response body is empty")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
apiTokenCallBack.onGetByRefIDError("An error occurred: ${e.message}")
|
||||
}
|
||||
} else {
|
||||
apiTokenCallBack.onGetByRefIDError("Unsuccessful response: " + response.code())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<ResponseBody?>, t: Throwable) {
|
||||
apiTokenCallBack.onGetByRefIDError(t.message)
|
||||
}
|
||||
})
|
||||
} catch (error: Exception) {
|
||||
apiTokenCallBack.onGetByRefIDError("Exception during API call: $error")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,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<String, Any>,
|
||||
messenger: BinaryMessenger,
|
||||
activity: MainActivity,
|
||||
val channel: MethodChannel
|
||||
) : PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate {
|
||||
// The layout for displaying the Penguin UI
|
||||
private val mapLayout: RelativeLayout = RelativeLayout(context)
|
||||
private val _context: Context = context
|
||||
|
||||
private val permissionResultReceiver: PermissionResultReceiver
|
||||
private val permissionIntentFilter = IntentFilter("PERMISSION_RESULT_ACTION")
|
||||
|
||||
private companion object {
|
||||
const val PERMISSIONS_REQUEST_CODE = 1
|
||||
}
|
||||
|
||||
private lateinit var permissionManager: PermissionManager
|
||||
|
||||
// Reference to the main activity
|
||||
private var _activity: Activity = activity
|
||||
|
||||
private lateinit var mContext: Context
|
||||
|
||||
lateinit var navigator: PenguinNavigator
|
||||
|
||||
init {
|
||||
// Set layout parameters for the mapLayout
|
||||
mapLayout.layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
|
||||
mContext = context
|
||||
|
||||
|
||||
permissionResultReceiver = PermissionResultReceiver { granted ->
|
||||
if (granted) {
|
||||
onPermissionsGranted()
|
||||
} else {
|
||||
onPermissionsDenied()
|
||||
}
|
||||
}
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
mContext.registerReceiver(
|
||||
permissionResultReceiver,
|
||||
permissionIntentFilter,
|
||||
RECEIVER_EXPORTED
|
||||
)
|
||||
} else {
|
||||
mContext.registerReceiver(
|
||||
permissionResultReceiver,
|
||||
permissionIntentFilter,
|
||||
)
|
||||
}
|
||||
|
||||
// Set the background color of the layout
|
||||
mapLayout.setBackgroundColor(Color.RED)
|
||||
|
||||
permissionManager = PermissionManager(
|
||||
context = mContext,
|
||||
listener = object : PermissionManager.PermissionListener {
|
||||
override fun onPermissionGranted() {
|
||||
// Handle permissions granted
|
||||
onPermissionsGranted()
|
||||
}
|
||||
|
||||
override fun onPermissionDenied() {
|
||||
// Handle permissions denied
|
||||
onPermissionsDenied()
|
||||
}
|
||||
},
|
||||
requestCode = PERMISSIONS_REQUEST_CODE,
|
||||
*PermissionHelper.getRequiredPermissions()
|
||||
)
|
||||
|
||||
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<String, Any?> = mapOf(
|
||||
"description" to description,
|
||||
"type" to errorType?.name
|
||||
)
|
||||
|
||||
channel.invokeMethod(PenguinMethod.onPenNavInitializationError.name, arguments)
|
||||
Toast.makeText(mContext, "Navigation Error: $description", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when Penguin UI is dismissed.
|
||||
*/
|
||||
override fun onPenNavUIDismiss() {
|
||||
// Handle UI dismissal if needed
|
||||
try {
|
||||
mContext.unregisterReceiver(permissionResultReceiver)
|
||||
dispose();
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Log.e("PenguinView", "Receiver not registered: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 432 KiB |
@ -0,0 +1,61 @@
|
||||
//
|
||||
// HMGPenguinInPlatformBridge.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by Haroon Amjad on 13/08/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
var flutterMethodChannelPenguinIn:FlutterMethodChannel? = nil
|
||||
fileprivate var mainViewController:MainFlutterVC!
|
||||
|
||||
class HMGPenguinInPlatformBridge{
|
||||
|
||||
private let channelName = "launch_penguin_ui"
|
||||
private static var shared_:HMGPenguinInPlatformBridge?
|
||||
|
||||
class func initialize(flutterViewController:MainFlutterVC){
|
||||
shared_ = HMGPenguinInPlatformBridge()
|
||||
mainViewController = flutterViewController
|
||||
shared_?.openChannel()
|
||||
}
|
||||
|
||||
func shared() -> 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
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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")
|
||||
// }
|
||||
//}
|
||||
@ -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)")
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
import 'package:diplomaticquarterapp/pages/BookAppointment/waiting_appointment/waiting_appointment_verification.dart';
|
||||
import 'package:diplomaticquarterapp/theme/colors.dart';
|
||||
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
|
||||
import 'package:diplomaticquarterapp/uitl/utils_new.dart';
|
||||
import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart';
|
||||
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
|
||||
import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class WaitingAppointmentInfo extends StatelessWidget {
|
||||
const WaitingAppointmentInfo({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppScaffold(
|
||||
appBarTitle: TranslationBase.of(context).waitingAppointment,
|
||||
isShowAppBar: true,
|
||||
isShowDecPage: false,
|
||||
showNewAppBar: true,
|
||||
showNewAppBarTitle: true,
|
||||
backgroundColor: CustomColors.appBackgroudGreyColor,
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: containerRadius(Colors.white, 10),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
"assets/images/new/waitingAppo.svg",
|
||||
width: 52.0,
|
||||
height: 52.0,
|
||||
),
|
||||
mHeight(11),
|
||||
Text(
|
||||
TranslationBase.of(context).whatWaitingAppointment,
|
||||
maxLines: 1,
|
||||
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w700, color: Color(0xff2B353E), letterSpacing: -1.44, height: 35 / 24),
|
||||
),
|
||||
mHeight(11),
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.8,
|
||||
child: Text(
|
||||
TranslationBase.of(context).waitingAppointmentText1,
|
||||
style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip),
|
||||
),
|
||||
),
|
||||
mHeight(18),
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.8,
|
||||
child: Text(
|
||||
TranslationBase.of(context).waitingAppointmentText2,
|
||||
style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip),
|
||||
),
|
||||
),
|
||||
mHeight(24),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.warning,
|
||||
size: 20,
|
||||
color: Color(0xffA78618),
|
||||
),
|
||||
mWidth(10),
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.7,
|
||||
child: Text(
|
||||
TranslationBase.of(context).waitingAppointmentText3,
|
||||
style: TextStyle(
|
||||
fontSize: 14, fontStyle: FontStyle.italic, fontWeight: FontWeight.w600, color: Color(0xffA78618), letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomSheet: Container(
|
||||
height: 80,
|
||||
color: CustomColors.white,
|
||||
padding: EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 25.0),
|
||||
child: Container(
|
||||
child: DefaultButton(
|
||||
TranslationBase.of(context).continues,
|
||||
() {
|
||||
Navigator.push(
|
||||
context,
|
||||
FadePage(
|
||||
page: WaitingAppointmentVerification(),
|
||||
),
|
||||
);
|
||||
},
|
||||
color: CustomColors.accentColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,292 @@
|
||||
import 'package:barcode_scan2/barcode_scan2.dart';
|
||||
import 'package:diplomaticquarterapp/core/model/privilege/ProjectDetailListModel.dart';
|
||||
import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
|
||||
import 'package:diplomaticquarterapp/pages/BookAppointment/BookConfirm.dart';
|
||||
import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart';
|
||||
import 'package:diplomaticquarterapp/theme/colors.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/location_util.dart';
|
||||
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
|
||||
import 'package:diplomaticquarterapp/uitl/utils_new.dart';
|
||||
import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart';
|
||||
import 'package:diplomaticquarterapp/widgets/nfc/nfc_reader_sheet.dart';
|
||||
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
|
||||
import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../../uitl/utils.dart';
|
||||
|
||||
class WaitingAppointmentVerification extends StatefulWidget {
|
||||
const WaitingAppointmentVerification({super.key});
|
||||
|
||||
@override
|
||||
State<WaitingAppointmentVerification> createState() => _WaitingAppointmentVerificationState();
|
||||
}
|
||||
|
||||
class _WaitingAppointmentVerificationState extends State<WaitingAppointmentVerification> {
|
||||
String selectedVerificationMethod = "QR";
|
||||
|
||||
late ProjectViewModel projectViewModel;
|
||||
late LocationUtils locationUtils;
|
||||
ProjectDetailListModel projectDetailListModel = ProjectDetailListModel();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
projectViewModel = Provider.of(context);
|
||||
return AppScaffold(
|
||||
appBarTitle: TranslationBase.of(context).waitingAppointment,
|
||||
isShowAppBar: true,
|
||||
isShowDecPage: false,
|
||||
showNewAppBar: true,
|
||||
showNewAppBarTitle: true,
|
||||
backgroundColor: CustomColors.appBackgroudGreyColor,
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
mHeight(11),
|
||||
Text(
|
||||
TranslationBase.of(context).waitingAppointmentVerificationMethod,
|
||||
maxLines: 1,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700, color: Color(0xff2B353E), letterSpacing: -1.04, height: 35 / 24),
|
||||
),
|
||||
mHeight(12),
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: containerRadius(Colors.white, 10),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 0.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedVerificationMethod = "QR";
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: containerColorRadiusBorderWidth(selectedVerificationMethod == "QR" ? CustomColors.accentColor : Colors.transparent, 100, Colors.grey, 0.5),
|
||||
),
|
||||
mWidth(6),
|
||||
Container(
|
||||
height: 40.0,
|
||||
width: 40.0,
|
||||
padding: EdgeInsets.all(7.0),
|
||||
child: SvgPicture.asset(
|
||||
"assets/images/new/services/qr_code.svg",
|
||||
),
|
||||
),
|
||||
Text(
|
||||
TranslationBase.of(context).pharmaLiveCareScanQR,
|
||||
style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, fontWeight: FontWeight.w600, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedVerificationMethod = "NFC";
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: containerColorRadiusBorderWidth(selectedVerificationMethod == "NFC" ? CustomColors.accentColor : Colors.transparent, 100, Colors.grey, 0.5),
|
||||
),
|
||||
mWidth(6),
|
||||
Container(
|
||||
height: 40.0,
|
||||
width: 40.0,
|
||||
padding: EdgeInsets.all(7.0),
|
||||
child: SvgPicture.asset(
|
||||
"assets/images/new/services/contactless.svg",
|
||||
),
|
||||
),
|
||||
Text(
|
||||
TranslationBase.of(context).scanNFC,
|
||||
style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, fontWeight: FontWeight.w600, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedVerificationMethod = "Location";
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: containerColorRadiusBorderWidth(selectedVerificationMethod == "Location" ? CustomColors.accentColor : Colors.transparent, 100, Colors.grey, 0.5),
|
||||
),
|
||||
mWidth(6),
|
||||
Container(
|
||||
height: 40.0,
|
||||
width: 40.0,
|
||||
padding: EdgeInsets.all(7.0),
|
||||
child: SvgPicture.asset(
|
||||
"assets/images/new/services/location.svg",
|
||||
),
|
||||
),
|
||||
Text(
|
||||
TranslationBase.of(context).checkInViaLocation,
|
||||
style: TextStyle(fontSize: 14, color: CustomColors.textDarkColor, fontWeight: FontWeight.w600, letterSpacing: -1.04, height: 35 / 24, overflow: TextOverflow.clip),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
mHeight(6),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
mHeight(12),
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: containerRadius(Colors.white, 10),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 0.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
mHeight(12),
|
||||
Text(
|
||||
TranslationBase.of(context).howToUseVerificationMethod,
|
||||
maxLines: 1,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -1.04, height: 35 / 24),
|
||||
),
|
||||
mHeight(12),
|
||||
Image.asset(
|
||||
'assets/images/new/NFCCheckIn_QR_gps_HMG.png',
|
||||
fit: BoxFit.fitWidth,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
),
|
||||
mHeight(12),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomSheet: Container(
|
||||
height: 80,
|
||||
color: CustomColors.white,
|
||||
padding: EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 25.0),
|
||||
child: Container(
|
||||
child: DefaultButton(
|
||||
TranslationBase.of(context).continues,
|
||||
() {
|
||||
startVerification();
|
||||
},
|
||||
color: CustomColors.accentColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
startVerification() {
|
||||
switch (selectedVerificationMethod) {
|
||||
case "QR":
|
||||
startQRCodeScan();
|
||||
break;
|
||||
case "NFC":
|
||||
startNFCScan();
|
||||
break;
|
||||
case "Location":
|
||||
startLocationCheckIn();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
checkScannedNFCAndQRCode(String nfcId) {
|
||||
GifLoaderDialogUtils.showMyDialog(context);
|
||||
DoctorsListService service = new DoctorsListService();
|
||||
service.checkScannedNFCAndQRCode(nfcId, projectViewModel.waitingAppointmentDoctor!.projectID!).then((res) {
|
||||
GifLoaderDialogUtils.hideDialog(context);
|
||||
projectViewModel.setWaitingAppointmentNFCCode(nfcId);
|
||||
if (res["returnValue"] == 1) {
|
||||
navigateToBookConfirm(context);
|
||||
} else {
|
||||
AppToast.showErrorToast(message: "Invalid verification point scanned.");
|
||||
}
|
||||
}).catchError((err) {
|
||||
GifLoaderDialogUtils.hideDialog(context);
|
||||
print(err);
|
||||
});
|
||||
}
|
||||
|
||||
Future navigateToBookConfirm(context) async {
|
||||
final DateFormat formatter = DateFormat('yyyy-MM-dd');
|
||||
Navigator.push(
|
||||
context,
|
||||
FadePage(
|
||||
page: BookConfirm(
|
||||
doctor: projectViewModel.waitingAppointmentDoctor!,
|
||||
isLiveCareAppointment: false,
|
||||
selectedDate: formatter.format(DateTime.now()),
|
||||
selectedTime: TranslationBase.of(context).waitingAppointment,
|
||||
initialSlotDuration: 15,
|
||||
isWalkinAppointment: true,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
startLocationCheckIn() async {
|
||||
locationUtils = new LocationUtils(isShowConfirmDialog: true, context: context);
|
||||
locationUtils.getCurrentLocation(callBack: (value) {
|
||||
projectDetailListModel = Utils.getProjectDetailObj(projectViewModel, projectViewModel.waitingAppointmentProjectID);
|
||||
double dist = Utils.distance(value.latitude, value.longitude, double.parse(projectDetailListModel.latitude!), double.parse(projectDetailListModel.longitude!)).ceilToDouble() * 1000;
|
||||
projectViewModel.setWaitingAppointmentNFCCode(projectDetailListModel.checkInQrCode!);
|
||||
print(dist);
|
||||
if (dist <= projectDetailListModel.geofenceRadius!) {
|
||||
navigateToBookConfirm(context);
|
||||
} else {
|
||||
AppToast.showErrorToast(message: TranslationBase.of(context).locationCheckInError);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
startNFCScan() {
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
showNfcReader(context, onNcfScan: (String nfcId) {
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
checkScannedNFCAndQRCode(nfcId);
|
||||
});
|
||||
}, onCancel: () {
|
||||
// Navigator.of(context).pop();
|
||||
// locator<GAnalytics>().todoList.to_do_list_nfc_cancel(widget.appointment!);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
startQRCodeScan() async {
|
||||
String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent));
|
||||
if (onlineCheckInQRCode != "") {
|
||||
checkScannedNFCAndQRCode(onlineCheckInQRCode);
|
||||
} else {}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class PenguinMethodChannel {
|
||||
static const MethodChannel _channel = MethodChannel('launch_penguin_ui');
|
||||
|
||||
static Future<void> 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<dynamic, dynamic> 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;
|
||||
}
|
||||
@ -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<HospitalsModel> 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<HospitalsModel> data;
|
||||
final Function(int)? onValueSelected;
|
||||
final int? selectedIndex;
|
||||
|
||||
const LocationDialogBody(
|
||||
{super.key,
|
||||
required this.data,
|
||||
this.onValueSelected,
|
||||
this.selectedIndex});
|
||||
|
||||
@override
|
||||
State<LocationDialogBody> createState() => _LocationDialogBodyState();
|
||||
}
|
||||
|
||||
class _LocationDialogBodyState extends State<LocationDialogBody> {
|
||||
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<HospitalsModel> data;
|
||||
final Function(String) onItemClick;
|
||||
|
||||
const LocationListExpandedBody(
|
||||
{super.key, required this.data, required this.onItemClick});
|
||||
|
||||
@override
|
||||
State<LocationListExpandedBody> createState() =>
|
||||
_LocationListExpandedBodyState();
|
||||
}
|
||||
|
||||
class _LocationListExpandedBodyState extends State<LocationListExpandedBody> {
|
||||
List<HospitalsModel> 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),
|
||||
))
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||