Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
395e2308a0
|
|||
|
ad7c5a4e5b
|
|||
|
0ba2396c2c
|
@@ -11,8 +11,8 @@ android {
|
|||||||
applicationId = "sh.sar.basedbank"
|
applicationId = "sh.sar.basedbank"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 12
|
versionCode = 13
|
||||||
versionName = "1.0.13"
|
versionName = "1.0.14"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ class HomeActivity : AppCompatActivity() {
|
|||||||
private val viewModel: HomeViewModel by viewModels()
|
private val viewModel: HomeViewModel by viewModels()
|
||||||
private lateinit var toggle: ActionBarDrawerToggle
|
private lateinit var toggle: ActionBarDrawerToggle
|
||||||
private var suppressBottomNavCallback = false
|
private var suppressBottomNavCallback = false
|
||||||
|
private var cachedTransferFragment: TransferFragment? = null
|
||||||
|
|
||||||
private var backPressedOnce = false
|
private var backPressedOnce = false
|
||||||
private val backPressHandler = Handler(Looper.getMainLooper())
|
private val backPressHandler = Handler(Looper.getMainLooper())
|
||||||
@@ -156,7 +157,7 @@ class HomeActivity : AppCompatActivity() {
|
|||||||
R.id.nav_dashboard -> DashboardFragment()
|
R.id.nav_dashboard -> DashboardFragment()
|
||||||
R.id.nav_accounts -> AccountsFragment()
|
R.id.nav_accounts -> AccountsFragment()
|
||||||
R.id.nav_contacts -> ContactsFragment()
|
R.id.nav_contacts -> ContactsFragment()
|
||||||
R.id.nav_transfer -> TransferFragment()
|
R.id.nav_transfer -> cachedTransferFragment ?: TransferFragment().also { cachedTransferFragment = it }
|
||||||
R.id.nav_pay_mv_qr -> PayMvQrFragment()
|
R.id.nav_pay_mv_qr -> PayMvQrFragment()
|
||||||
R.id.nav_more -> MoreFragment()
|
R.id.nav_more -> MoreFragment()
|
||||||
R.id.nav_activities -> ActivitiesFragment()
|
R.id.nav_activities -> ActivitiesFragment()
|
||||||
@@ -390,7 +391,7 @@ fun applyNavLabelVisibility() {
|
|||||||
R.id.nav_dashboard -> DashboardFragment()
|
R.id.nav_dashboard -> DashboardFragment()
|
||||||
R.id.nav_accounts -> AccountsFragment()
|
R.id.nav_accounts -> AccountsFragment()
|
||||||
R.id.nav_contacts -> ContactsFragment()
|
R.id.nav_contacts -> ContactsFragment()
|
||||||
R.id.nav_transfer -> TransferFragment()
|
R.id.nav_transfer -> cachedTransferFragment ?: TransferFragment().also { cachedTransferFragment = it }
|
||||||
R.id.nav_pay_mv_qr -> PayMvQrFragment()
|
R.id.nav_pay_mv_qr -> PayMvQrFragment()
|
||||||
R.id.nav_activities -> ActivitiesFragment()
|
R.id.nav_activities -> ActivitiesFragment()
|
||||||
R.id.nav_transfer_history -> TransferHistoryFragment()
|
R.id.nav_transfer_history -> TransferHistoryFragment()
|
||||||
|
|||||||
@@ -92,6 +92,14 @@ class TransferFragment : Fragment() {
|
|||||||
// Values: "FAHIPAY_TRANSFER", "RAASTAS", "OOREDOO_BILL"
|
// Values: "FAHIPAY_TRANSFER", "RAASTAS", "OOREDOO_BILL"
|
||||||
private var selectedFahipayService: String? = null
|
private var selectedFahipayService: String? = null
|
||||||
|
|
||||||
|
// Form state preserved across view destroy/create when the fragment instance is cached
|
||||||
|
private var savedAmount = ""
|
||||||
|
private var savedRemarks = ""
|
||||||
|
private var savedToText = ""
|
||||||
|
private var savedToSubtitle = ""
|
||||||
|
private var savedToColorHex = "#607D8B"
|
||||||
|
private var savedToImageHash: String? = null
|
||||||
|
|
||||||
// BML QR merchant payment mode (set when navigated from a card QR scan)
|
// BML QR merchant payment mode (set when navigated from a card QR scan)
|
||||||
private var bmlQrInfo: BmlQrPayInfo? = null
|
private var bmlQrInfo: BmlQrPayInfo? = null
|
||||||
private var bmlGatewayQr = false // true for pay.bml.com.mv QRs (requires pre-initiate step)
|
private var bmlGatewayQr = false // true for pay.bml.com.mv QRs (requires pre-initiate step)
|
||||||
@@ -255,6 +263,18 @@ class TransferFragment : Fragment() {
|
|||||||
val colorHex = bundle.getString(ContactPickerSheetFragment.KEY_COLOR) ?: "#607D8B"
|
val colorHex = bundle.getString(ContactPickerSheetFragment.KEY_COLOR) ?: "#607D8B"
|
||||||
val imageHash = bundle.getString(ContactPickerSheetFragment.KEY_IMAGE_HASH)
|
val imageHash = bundle.getString(ContactPickerSheetFragment.KEY_IMAGE_HASH)
|
||||||
prefillToDirectly(accountNumber, label, subtitle, colorHex, imageHash)
|
prefillToDirectly(accountNumber, label, subtitle, colorHex, imageHash)
|
||||||
|
if (selectedAccount == null) {
|
||||||
|
val defaultNum = CredentialStore(requireContext()).getDefaultAccountNumber()
|
||||||
|
if (defaultNum != null) {
|
||||||
|
val defaultAcc = viewModel.accounts.value?.firstOrNull { it.accountNumber == defaultNum }
|
||||||
|
if (defaultAcc != null) {
|
||||||
|
selectedAccount = defaultAcc
|
||||||
|
updateAmountPrefix(defaultAcc)
|
||||||
|
showFromCard(defaultAcc)
|
||||||
|
updateTransferButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.btnPickContact.setOnClickListener {
|
binding.btnPickContact.setOnClickListener {
|
||||||
@@ -294,6 +314,33 @@ class TransferFragment : Fragment() {
|
|||||||
if (arguments?.getBoolean(ARG_AUTO_SCAN, false) == true) {
|
if (arguments?.getBoolean(ARG_AUTO_SCAN, false) == true) {
|
||||||
qrLauncher.launch(Intent(requireContext(), QrScannerActivity::class.java))
|
qrLauncher.launch(Intent(requireContext(), QrScannerActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore form state when view is recreated on the cached no-args instance
|
||||||
|
if (arguments == null) {
|
||||||
|
if (resolvedAccountNumber.isNotEmpty()) {
|
||||||
|
val ownAccount = viewModel.accounts.value?.firstOrNull { it.accountNumber == resolvedAccountNumber }
|
||||||
|
if (ownAccount != null) {
|
||||||
|
showToCard(ownAccount)
|
||||||
|
} else {
|
||||||
|
binding.tvToAccountName.text = resolvedRecipientName
|
||||||
|
binding.tvToBankBic.text = savedToSubtitle
|
||||||
|
binding.tvToAccountDetails.visibility = View.GONE
|
||||||
|
binding.tvToBalance.visibility = View.GONE
|
||||||
|
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
|
||||||
|
binding.ivToPhoto.setImageBitmap(makeInitialsBitmap(resolvedRecipientName, savedToColorHex))
|
||||||
|
}
|
||||||
|
binding.tilTo.visibility = View.GONE
|
||||||
|
binding.btnPickContact.visibility = View.GONE
|
||||||
|
binding.btnScanQr.visibility = View.GONE
|
||||||
|
binding.cardToInfo.visibility = View.VISIBLE
|
||||||
|
if (savedToImageHash != null) loadToPhoto(savedToImageHash!!, isProfile = resolvedToOwnAccount != null)
|
||||||
|
} else if (savedToText.isNotEmpty()) {
|
||||||
|
binding.etTo.setText(savedToText)
|
||||||
|
}
|
||||||
|
if (savedAmount.isNotEmpty()) binding.etAmount.setText(savedAmount)
|
||||||
|
if (savedRemarks.isNotEmpty()) binding.etRemarks.setText(savedRemarks)
|
||||||
|
updateTransferButton()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun lookupBmlQrMerchant(qrUrl: String) {
|
private fun lookupBmlQrMerchant(qrUrl: String) {
|
||||||
@@ -439,6 +486,20 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-select default account when arriving from contacts page (TO account already pre-filled)
|
||||||
|
if (selectedAccount == null && arguments?.getString(ARG_ACCOUNT) != null) {
|
||||||
|
val defaultNum = CredentialStore(requireContext()).getDefaultAccountNumber()
|
||||||
|
if (defaultNum != null) {
|
||||||
|
val defaultAcc = accounts.firstOrNull { it.accountNumber == defaultNum }
|
||||||
|
if (defaultAcc != null) {
|
||||||
|
selectedAccount = defaultAcc
|
||||||
|
updateAmountPrefix(defaultAcc)
|
||||||
|
showFromCard(defaultAcc)
|
||||||
|
updateTransferButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// On a cold start (e.g. share intent), anyBmlSession() may be null when
|
// On a cold start (e.g. share intent), anyBmlSession() may be null when
|
||||||
// onViewCreated runs. Retry the lookup once sessions are available.
|
// onViewCreated runs. Retry the lookup once sessions are available.
|
||||||
val pendingBmlQrUrl = arguments?.getString(ARG_BML_QR_URL)
|
val pendingBmlQrUrl = arguments?.getString(ARG_BML_QR_URL)
|
||||||
@@ -446,6 +507,13 @@ class TransferFragment : Fragment() {
|
|||||||
val app = requireActivity().application as BasedBankApp
|
val app = requireActivity().application as BasedBankApp
|
||||||
if (app.anyBmlSession() != null) lookupBmlQrMerchant(pendingBmlQrUrl)
|
if (app.anyBmlSession() != null) lookupBmlQrMerchant(pendingBmlQrUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-render the from card when the view is recreated on a cached instance
|
||||||
|
if (selectedAccount != null && binding.cardFromInfo.visibility != View.VISIBLE) {
|
||||||
|
updateAmountPrefix(selectedAccount!!)
|
||||||
|
showFromCard(selectedAccount!!)
|
||||||
|
updateTransferButton()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,6 +799,13 @@ class TransferFragment : Fragment() {
|
|||||||
resolvedAccountNumber = info.accountNumber
|
resolvedAccountNumber = info.accountNumber
|
||||||
resolvedRecipientName = info.accountName
|
resolvedRecipientName = info.accountName
|
||||||
resolvedBankName = info.bankId
|
resolvedBankName = info.bankId
|
||||||
|
savedToSubtitle = "${info.accountNumber} · ${info.bankId}"
|
||||||
|
savedToColorHex = colorHex
|
||||||
|
savedToImageHash = when {
|
||||||
|
matchedAcc?.profileImageHash != null -> matchedAcc.profileImageHash
|
||||||
|
matchedCont?.customerImgHash != null -> matchedCont.customerImgHash
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
if (matchedAcc != null) {
|
if (matchedAcc != null) {
|
||||||
showToCard(matchedAcc)
|
showToCard(matchedAcc)
|
||||||
@@ -863,6 +938,9 @@ class TransferFragment : Fragment() {
|
|||||||
) {
|
) {
|
||||||
resolvedAccountNumber = accountNumber
|
resolvedAccountNumber = accountNumber
|
||||||
resolvedRecipientName = displayName
|
resolvedRecipientName = displayName
|
||||||
|
savedToSubtitle = subtitle
|
||||||
|
savedToColorHex = colorHex
|
||||||
|
savedToImageHash = imageHash
|
||||||
val contacts = viewModel.contacts.value ?: emptyList()
|
val contacts = viewModel.contacts.value ?: emptyList()
|
||||||
resolvedBankName = contacts.firstOrNull { it.benefAccount == accountNumber }?.benefBankName ?: ""
|
resolvedBankName = contacts.firstOrNull { it.benefAccount == accountNumber }?.benefBankName ?: ""
|
||||||
|
|
||||||
@@ -2053,6 +2131,14 @@ class TransferFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
// Persist form state so it can be restored when the view is recreated
|
||||||
|
savedAmount = binding.etAmount.text?.toString() ?: ""
|
||||||
|
savedRemarks = binding.etRemarks.text?.toString() ?: ""
|
||||||
|
savedToText = if (resolvedAccountNumber.isEmpty()) binding.etTo.text?.toString() ?: "" else ""
|
||||||
|
// Reset in-progress OTP flow — it cannot sensibly resume after the view is gone
|
||||||
|
bmlOtpState = BmlOtpState.NONE
|
||||||
|
pendingBmlTransfer = null
|
||||||
|
bmlOtpChannel = null
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user