Compare commits

...

2 Commits

Author SHA1 Message Date
ahasani 2b03af6e52 Merge branch 'master' of http://194.59.214.243:3000/ahasani/psp_pwa 2026-05-17 11:09:14 +03:30
ahasani 6aaa648128 update 2026-05-17 11:08:53 +03:30
7 changed files with 82 additions and 28 deletions
@@ -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)});"
}
}
@@ -3,5 +3,4 @@ package com.example.core.model
enum class PaymentResultStatus {
OK,
ERROR
}
}
@@ -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<PrintEntity>) -> 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 = {
@@ -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<Map<String, Any>>() {}.type
+1
View File
@@ -55,6 +55,7 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("debug")
}
}
compileOptions {
@@ -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<String?>(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
}
}
)
}
}
@@ -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 = "تراکنش ناموفق"
)
}