Ref(DeviceInfo-PaymentResult-WebView):

- Refactor `PaymentResultEntity` to include a nested `PaymentResultDataEntity` and companion factory methods for success and failure.
- Update `PaymentResultStatus` enum members from `OK`/`ERROR` to `SUCCESS`/`FAILURE`.
- Modify `PspService` and its implementations (`P3`, `PS4`, `Stage`) to return a non-nullable `PaymentResultEntity`.
- Enhance `PspWebView` with improved instance lifecycle management, `rememberUpdatedState` for callbacks, and new `onWebViewReady` and `onPageFinished` hooks.
- Optimize `PspWebView` to prevent redundant `loadUrl` calls during recomposition.
- Add `README.md` and `AGENT.md` to provide project architecture overviews and hardware-specific development guidelines.
- Update `TisWebViewScreen` and `StageWebViewScreen` to handle the refactored result models and utilize new WebView callbacks.
This commit is contained in:
Amir Mousavi
2026-05-17 13:40:32 +03:30
parent 2b03af6e52
commit 08060001e1
14 changed files with 254 additions and 72 deletions
@@ -1,5 +1,6 @@
package com.example.tis_app.screen
import android.util.Log
import android.webkit.WebView
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
@@ -17,10 +18,10 @@ import androidx.hilt.navigation.compose.hiltViewModel
import com.example.core.getAndroidId
import com.example.core.getDeviceName
import com.example.design_system.PspWebView
import com.example.design_system.util.WebViewManager
import com.example.tis_app.viewmodel.WebViewModel
private const val tisWebUrl = "https://tis.shift-am.ir"
private const val tisWebViewTag = "TisWebViewScreen"
@Composable
fun TisWebViewScreen(
@@ -29,10 +30,11 @@ fun TisWebViewScreen(
) {
val context = LocalContext.current
var webView: WebView by remember { mutableStateOf(WebViewManager.getWebView(context)) }
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(
@@ -50,17 +52,16 @@ fun TisWebViewScreen(
val paymentResultEntity = viewModel.paymentResult(
id = currentPaymentId,
activityResult = result
)
webView.post {
webView.evaluateJavascript(
viewModel.postPaymentResult(paymentResultEntity = paymentResultEntity),
null
)
val jsResult = viewModel.postPaymentResult(paymentResultEntity)
webView?.let {
it.post {
it.evaluateJavascript(jsResult, null)
}
} ?: run {
Log.w(tisWebViewTag, "Skipping onPaymentResult JS callback: WebView is not ready yet.")
}
isPaymentProcessing = false
}
PspWebView(
@@ -86,6 +87,15 @@ fun TisWebViewScreen(
},
onDeviceInfo = {
deviceInfo
},
onWebViewReady = { readyWebView ->
webView = readyWebView
},
onPageFinished = { loadedWebView ->
if (!initialCallbackSent) {
loadedWebView.evaluateJavascript(viewModel.postPaymentResult(null), null)
initialCallbackSent = true
}
}
)
}
}
@@ -32,7 +32,7 @@ class WebViewModel @Inject constructor(
fun paymentResult(
id: String?,
activityResult: ActivityResult
): PaymentResultEntity? {
): PaymentResultEntity {
return pspService.decodePosResponse(
id = id,
activityResult = activityResult