This commit is contained in:
@@ -32,7 +32,10 @@ import androidx.fragment.app.activityViewModels
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import androidx.activity.result.ActivityResult
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import java.util.UUID
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -162,9 +165,21 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
).also { mfaisaHandler = it }
|
).also { mfaisaHandler = it }
|
||||||
|
|
||||||
private val qrLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
// Registered manually against the activity registry in onViewCreated rather than with a
|
||||||
if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult
|
// registerForActivityResult() field initializer: HomeActivity caches one TransferFragment
|
||||||
val raw = result.data?.getStringExtra(QrScannerActivity.EXTRA_QR_CONTENT) ?: return@registerForActivityResult
|
// instance (cachedTransferFragment) and re-shows it after a replace(). A field initializer
|
||||||
|
// runs only once, so once that instance was destroyed the launcher stayed unregistered and
|
||||||
|
// launching it threw. Keying off viewLifecycleOwner re-registers on every view creation.
|
||||||
|
private val qrLauncherKey = "transfer_qr_" + UUID.randomUUID()
|
||||||
|
private var qrLauncher: ActivityResultLauncher<Intent>? = null
|
||||||
|
|
||||||
|
private fun launchQrScanner() {
|
||||||
|
qrLauncher?.launch(Intent(requireContext(), QrScannerActivity::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onQrScanned(result: ActivityResult) {
|
||||||
|
if (result.resultCode != Activity.RESULT_OK) return
|
||||||
|
val raw = result.data?.getStringExtra(QrScannerActivity.EXTRA_QR_CONTENT) ?: return
|
||||||
|
|
||||||
// BML card/gateway QR — hand off to dedicated payment screen
|
// BML card/gateway QR — hand off to dedicated payment screen
|
||||||
val bmlUrl = PaymvQrParser.extractBmlGatewayUrl(raw)
|
val bmlUrl = PaymvQrParser.extractBmlGatewayUrl(raw)
|
||||||
@@ -173,7 +188,7 @@ class TransferFragment : Fragment() {
|
|||||||
it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT"
|
it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT"
|
||||||
}
|
}
|
||||||
(requireActivity() as HomeActivity).navigateTo(R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(bmlUrl ?: raw, fromCard?.accountNumber))
|
(requireActivity() as HomeActivity).navigateTo(R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(bmlUrl ?: raw, fromCard?.accountNumber))
|
||||||
return@registerForActivityResult
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// M-Faisa merchant QR — content is just the numeric qrCodeId. Only attempt the lookup
|
// M-Faisa merchant QR — content is just the numeric qrCodeId. Only attempt the lookup
|
||||||
@@ -184,13 +199,13 @@ class TransferFragment : Fragment() {
|
|||||||
if (trimmedRaw.length in 8..16 && trimmedRaw.all { it.isDigit() } &&
|
if (trimmedRaw.length in 8..16 && trimmedRaw.all { it.isDigit() } &&
|
||||||
app.mfaisaSessions.isNotEmpty()) {
|
app.mfaisaSessions.isNotEmpty()) {
|
||||||
lookupMfaisaQrMerchant(trimmedRaw)
|
lookupMfaisaQrMerchant(trimmedRaw)
|
||||||
return@registerForActivityResult
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val qr = PaymvQrParser.parse(raw)
|
val qr = PaymvQrParser.parse(raw)
|
||||||
if (qr == null || qr.accountNumber == null) {
|
if (qr == null || qr.accountNumber == null) {
|
||||||
Toast.makeText(requireContext(), R.string.transfer_qr_invalid, Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), R.string.transfer_qr_invalid, Toast.LENGTH_SHORT).show()
|
||||||
return@registerForActivityResult
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cards can't pay PayMV QR — fall back to default account or clear selection
|
// Cards can't pay PayMV QR — fall back to default account or clear selection
|
||||||
@@ -287,6 +302,10 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
qrLauncher = requireActivity().activityResultRegistry.register(
|
||||||
|
qrLauncherKey, viewLifecycleOwner, ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { onQrScanned(it) }
|
||||||
|
|
||||||
setupFromDropdown()
|
setupFromDropdown()
|
||||||
setupAccountLookup()
|
setupAccountLookup()
|
||||||
|
|
||||||
@@ -340,7 +359,7 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.btnScanQr.setOnClickListener {
|
binding.btnScanQr.setOnClickListener {
|
||||||
qrLauncher.launch(Intent(requireContext(), QrScannerActivity::class.java))
|
launchQrScanner()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.connectivityErrors.observe(viewLifecycleOwner) { updateTransferButton() }
|
viewModel.connectivityErrors.observe(viewLifecycleOwner) { updateTransferButton() }
|
||||||
@@ -369,7 +388,7 @@ class TransferFragment : Fragment() {
|
|||||||
arguments?.getString(ARG_BML_QR_URL)?.let { bmlHandler().lookupQrMerchant(it) }
|
arguments?.getString(ARG_BML_QR_URL)?.let { bmlHandler().lookupQrMerchant(it) }
|
||||||
|
|
||||||
if (arguments?.getBoolean(ARG_AUTO_SCAN, false) == true) {
|
if (arguments?.getBoolean(ARG_AUTO_SCAN, false) == true) {
|
||||||
qrLauncher.launch(Intent(requireContext(), QrScannerActivity::class.java))
|
launchQrScanner()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore form state when view is recreated on the cached no-args instance
|
// Restore form state when view is recreated on the cached no-args instance
|
||||||
@@ -2002,6 +2021,8 @@ class TransferFragment : Fragment() {
|
|||||||
bmlHandler = null
|
bmlHandler = null
|
||||||
mfaisaHandler?.clearState()
|
mfaisaHandler?.clearState()
|
||||||
mfaisaHandler = null
|
mfaisaHandler = null
|
||||||
|
// Unregistered automatically with viewLifecycleOwner; drop the stale handle.
|
||||||
|
qrLauncher = null
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user