diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/DashboardFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/DashboardFragment.kt index 3664459..254eab3 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/DashboardFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/DashboardFragment.kt @@ -25,6 +25,7 @@ import sh.sar.basedbank.api.models.BankAccount import sh.sar.basedbank.api.mib.MibCard import sh.sar.basedbank.api.mib.MibFinanceDeal import sh.sar.basedbank.util.bmlapi.BmlCardParser +import sh.sar.basedbank.util.PaymvQrParser import sh.sar.basedbank.util.CredentialStore import kotlin.math.abs import sh.sar.basedbank.databinding.FragmentDashboardBinding @@ -41,10 +42,10 @@ class DashboardFragment : Fragment() { private val qrLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult val raw = result.data?.getStringExtra(QrScannerActivity.EXTRA_QR_CONTENT) ?: return@registerForActivityResult - if (raw.startsWith("https://ebanking.bankofmaldives.com.mv/qrpay/") || - raw.startsWith("https://pay.bml.com.mv/app/")) { + val bmlUrl = PaymvQrParser.extractBmlGatewayUrl(raw) + if (raw.startsWith("https://ebanking.bankofmaldives.com.mv/qrpay/") || bmlUrl != null) { (requireActivity() as HomeActivity).navigateTo( - R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(raw, pendingQrAccountNumber) + R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(bmlUrl ?: raw, pendingQrAccountNumber) ) } else { Toast.makeText(requireContext(), R.string.transfer_qr_invalid, Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/PayMvQrFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/PayMvQrFragment.kt index c45406b..c05e72b 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/PayMvQrFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/PayMvQrFragment.kt @@ -61,9 +61,9 @@ class PayMvQrFragment : Fragment() { val raw = result.data?.getStringExtra(QrScannerActivity.EXTRA_QR_CONTENT) ?: return@registerForActivityResult // BML card/gateway QR — hand off to dedicated payment screen - if (raw.startsWith("https://ebanking.bankofmaldives.com.mv/qrpay/") || - raw.startsWith("https://pay.bml.com.mv/app/")) { - (requireActivity() as HomeActivity).navigateTo(R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(raw)) + val bmlUrl = PaymvQrParser.extractBmlGatewayUrl(raw) + if (raw.startsWith("https://ebanking.bankofmaldives.com.mv/qrpay/") || bmlUrl != null) { + (requireActivity() as HomeActivity).navigateTo(R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(bmlUrl ?: raw)) return@registerForActivityResult } diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/PayWithCardFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/PayWithCardFragment.kt index c452720..c0fdd29 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/PayWithCardFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/PayWithCardFragment.kt @@ -31,6 +31,7 @@ import sh.sar.basedbank.databinding.FragmentCardsBinding import sh.sar.basedbank.util.CardsCache import sh.sar.basedbank.util.CredentialStore import sh.sar.basedbank.util.bmlapi.BmlCardParser +import sh.sar.basedbank.util.PaymvQrParser import kotlin.math.abs class CardsFragment : Fragment() { @@ -60,10 +61,10 @@ class CardsFragment : Fragment() { private val qrLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult val raw = result.data?.getStringExtra(QrScannerActivity.EXTRA_QR_CONTENT) ?: return@registerForActivityResult - if (raw.startsWith("https://ebanking.bankofmaldives.com.mv/qrpay/") || - raw.startsWith("https://pay.bml.com.mv/app/")) { + val bmlUrl = PaymvQrParser.extractBmlGatewayUrl(raw) + if (raw.startsWith("https://ebanking.bankofmaldives.com.mv/qrpay/") || bmlUrl != null) { (requireActivity() as HomeActivity).navigateTo( - R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(raw, pendingQrAccountNumber) + R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(bmlUrl ?: raw, pendingQrAccountNumber) ) } else { Toast.makeText(requireContext(), R.string.transfer_qr_invalid, Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/TransferFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/TransferFragment.kt index 3a2309c..d5c4941 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/TransferFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/TransferFragment.kt @@ -125,12 +125,12 @@ class TransferFragment : Fragment() { val raw = result.data?.getStringExtra(QrScannerActivity.EXTRA_QR_CONTENT) ?: return@registerForActivityResult // BML card/gateway QR — hand off to dedicated payment screen - if (raw.startsWith("https://ebanking.bankofmaldives.com.mv/qrpay/") || - raw.startsWith("https://pay.bml.com.mv/app/")) { + val bmlUrl = PaymvQrParser.extractBmlGatewayUrl(raw) + if (raw.startsWith("https://ebanking.bankofmaldives.com.mv/qrpay/") || bmlUrl != null) { val fromCard = selectedAccount?.takeIf { it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT" } - (requireActivity() as HomeActivity).navigateTo(R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(raw, fromCard?.accountNumber)) + (requireActivity() as HomeActivity).navigateTo(R.id.nav_transfer, TransferFragment.newInstanceFromBmlQr(bmlUrl ?: raw, fromCard?.accountNumber)) return@registerForActivityResult } diff --git a/app/src/main/java/sh/sar/basedbank/util/PaymvQrParser.kt b/app/src/main/java/sh/sar/basedbank/util/PaymvQrParser.kt index 4232a8e..bbc468b 100644 --- a/app/src/main/java/sh/sar/basedbank/util/PaymvQrParser.kt +++ b/app/src/main/java/sh/sar/basedbank/util/PaymvQrParser.kt @@ -9,6 +9,24 @@ data class PaymvQrData( object PaymvQrParser { + /** + * Returns the BML gateway URL if [raw] is or contains one, otherwise null. + * Handles both plain URL QRs and combined EMV QRs (e.g. Fahipay+BML card QR). + * For combined EMV QRs the URL is parsed from TLV (root tag 35 → sub-tag 20 → sub-sub-tag 01) + * rather than via regex, to avoid greedily consuming subsequent EMV tag bytes. + */ + fun extractBmlGatewayUrl(raw: String): String? { + if (raw.startsWith("https://pay.bml.com.mv/app/")) return raw + return try { + val root = parseTlv(raw) + val bmlMerchantInfo = root["35"]?.let { parseTlv(it) } ?: return null + val inner = bmlMerchantInfo["20"]?.let { parseTlv(it) } ?: return null + inner["01"]?.takeIf { it.startsWith("https://pay.bml.com.mv/app/") } + } catch (_: Exception) { + null + } + } + fun parse(raw: String): PaymvQrData? { return try { val root = parseTlv(raw)