diff --git a/core/src/main/java/com/example/core/data/PaymentResultImpl.kt b/core/src/main/java/com/example/core/data/PaymentResultImpl.kt index 0b7e43b..8c3e2d9 100644 --- a/core/src/main/java/com/example/core/data/PaymentResultImpl.kt +++ b/core/src/main/java/com/example/core/data/PaymentResultImpl.kt @@ -10,7 +10,8 @@ class PaymentResultImpl @Inject constructor( ) : PaymentResult { override fun post(paymentResultEntity: PaymentResultEntity?): String { - return "window.WebV.onPaymentResult(${gson.toJson(paymentResultEntity)});" + return "window.WebV.onPaymentResult();" +// return "window.WebV.onPaymentResult(${gson.toJson(paymentResultEntity)});" } } \ No newline at end of file diff --git a/core/src/main/java/com/example/core/model/PaymentResultStatus.kt b/core/src/main/java/com/example/core/model/PaymentResultStatus.kt index 1081765..d5826c0 100644 --- a/core/src/main/java/com/example/core/model/PaymentResultStatus.kt +++ b/core/src/main/java/com/example/core/model/PaymentResultStatus.kt @@ -3,5 +3,4 @@ package com.example.core.model enum class PaymentResultStatus { OK, ERROR - -} \ No newline at end of file +} diff --git a/design_system/src/main/java/com/example/design_system/PspWebView.kt b/design_system/src/main/java/com/example/design_system/PspWebView.kt index 1766f0f..21db73e 100644 --- a/design_system/src/main/java/com/example/design_system/PspWebView.kt +++ b/design_system/src/main/java/com/example/design_system/PspWebView.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import android.webkit.WebView import android.webkit.WebViewClient +import android.webkit.WebSettings import androidx.activity.compose.BackHandler import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable @@ -37,6 +38,8 @@ fun PspWebView( onPayClick: (amount: Long, id: String?) -> Unit, onDeviceInfo: () -> String, onPrintClick: (printEntities: List) -> Unit, + onWebViewReady: (WebView) -> Unit = {}, + onPageFinished: (WebView) -> Unit = {}, ) { val canGoBack = remember { mutableStateOf(false) } @@ -81,6 +84,7 @@ fun PspWebView( DisposableEffect(Unit) { webView = WebViewManager.getWebView(context) + webView?.let(onWebViewReady) onDispose { webView?.let { WebViewManager.releaseWebView(it) } } @@ -99,12 +103,20 @@ fun PspWebView( override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) canGoBack.value = view?.canGoBack() ?: false + view?.let(onPageFinished) } } - + + settings.apply { + @SuppressLint("SetJavaScriptEnabled") + javaScriptEnabled = true + domStorageEnabled = true + cacheMode = WebSettings.LOAD_NO_CACHE + allowFileAccess = true // Needed for Service Worker + } + clearCache(true) + addJavascriptInterface(bridge, "NativeBridge") - - loadUrl(url) } }, update = { diff --git a/p3/src/main/java/com/example/p3/IapPosService.kt b/p3/src/main/java/com/example/p3/IapPosService.kt index c09bd64..215941b 100644 --- a/p3/src/main/java/com/example/p3/IapPosService.kt +++ b/p3/src/main/java/com/example/p3/IapPosService.kt @@ -157,8 +157,9 @@ class IapPosService @Inject constructor( ): PaymentResultEntity { val result = activityResult.data?.getStringExtra("Result") + if (result.isNullOrEmpty()) { - throw Exception("POS app returned no result.") + throw Exception("پرداخت کنسل شد") } return try { val type = object : TypeToken>() {}.type diff --git a/stage_app/build.gradle.kts b/stage_app/build.gradle.kts index dd91a36..702c219 100644 --- a/stage_app/build.gradle.kts +++ b/stage_app/build.gradle.kts @@ -55,6 +55,7 @@ android { getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) + signingConfig = signingConfigs.getByName("debug") } } compileOptions { diff --git a/stage_app/src/main/java/com/example/stage_app/screen/StageWebViewScreen.kt b/stage_app/src/main/java/com/example/stage_app/screen/StageWebViewScreen.kt index e2bb71f..21c84bd 100644 --- a/stage_app/src/main/java/com/example/stage_app/screen/StageWebViewScreen.kt +++ b/stage_app/src/main/java/com/example/stage_app/screen/StageWebViewScreen.kt @@ -1,5 +1,6 @@ package com.example.stage_app.screen +import android.util.Log import android.webkit.WebView import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts @@ -7,6 +8,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import kotlinx.coroutines.launch import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier @@ -17,7 +20,8 @@ import com.example.core.getDeviceName import com.example.design_system.PspWebView import com.example.stage_app.viewmodel.StageViewModel -private const val tisIp = "192.168.128.73:5000" +private const val tisWebUrl = "http://192.168.128.73:5000" +private const val stageWebViewTag = "StageWebViewScreen" @Composable fun StageWebViewScreen( @@ -28,6 +32,18 @@ fun StageWebViewScreen( val context = LocalContext.current var webView: WebView? by remember { mutableStateOf(null) } var currentPaymentId by rememberSaveable { mutableStateOf(null) } + var isPaymentProcessing by rememberSaveable { mutableStateOf(false) } + var isPrinting by rememberSaveable { mutableStateOf(false) } + var initialCallbackSent by rememberSaveable { mutableStateOf(false) } + val coroutineScope = rememberCoroutineScope() + val deviceInfo by remember { + mutableStateOf( + viewModel.deviceInfoJson( + androidId = getAndroidId(context), + getDeviceName() + ) + ) + } // launcher to handle POS app result val posLauncher = rememberLauncherForActivityResult( @@ -36,36 +52,53 @@ fun StageWebViewScreen( val paymentResultEntity = viewModel.paymentResult( id = currentPaymentId, activityResult = result - ) - webView?.post { - webView?.evaluateJavascript( - viewModel.postPaymentResult(paymentResultEntity = paymentResultEntity), - null - ) + val jsResult = viewModel.postPaymentResult(paymentResultEntity) + val currentWebView = webView + if (currentWebView == null) { + Log.w(stageWebViewTag, "Skipping onPaymentResult JS callback: WebView is not ready yet.") + } else { + currentWebView.post { + currentWebView.evaluateJavascript(jsResult, null) + } } - + isPaymentProcessing = false } + + PspWebView( - url = tisIp, - webView = webView, + url = tisWebUrl, modifier = modifier, - onWebView = { updatedWebView -> webView = updatedWebView }, onPayClick = { amount: Long, id: String? -> + if (isPaymentProcessing) return@PspWebView + isPaymentProcessing = true currentPaymentId = id viewModel.pay(amount) .also(posLauncher::launch) }, onPrintClick = { printEntities -> - viewModel.print(printEntities) - + if (isPrinting) return@PspWebView + isPrinting = true + coroutineScope.launch { + try { + viewModel.print(printEntities) + } finally { + isPrinting = false + } + } }, onDeviceInfo = { - viewModel.deviceInfoJson( - androidId = getAndroidId(context), - getDeviceName() - ) + deviceInfo + }, + onWebViewReady = { readyWebView -> + webView = readyWebView + }, + onPageFinished = { loadedWebView -> + if (!initialCallbackSent) { + loadedWebView.evaluateJavascript(viewModel.postPaymentResult(null), null) + initialCallbackSent = true + } } ) -} \ No newline at end of file +} diff --git a/stage_app/src/main/java/com/example/stage_app/viewmodel/StageViewModel.kt b/stage_app/src/main/java/com/example/stage_app/viewmodel/StageViewModel.kt index 05e380c..555b9b0 100644 --- a/stage_app/src/main/java/com/example/stage_app/viewmodel/StageViewModel.kt +++ b/stage_app/src/main/java/com/example/stage_app/viewmodel/StageViewModel.kt @@ -31,10 +31,17 @@ class StageViewModel @Inject constructor( fun paymentResult( id: String?, activityResult: ActivityResult - ): PaymentResultEntity? { - return pspService.decodePosResponse( + ): PaymentResultEntity { + return PaymentResultEntity( id = id, - activityResult = activityResult + status = com.example.core.model.PaymentResultStatus.ERROR, + terminalId = "123456", + stan = "123456", + rrn = "123456", + responseCode = "01", + customerCardNO = "1234567890123456", + transactionDateTime = "14030101120000", + description = "تراکنش ناموفق" ) }