quality of life features: logo and account type shown in trasfer page and contact picker and my accounts in contact picker, also money amount is dispayed bigger

This commit is contained in:
2026-05-28 01:14:20 +05:00
parent 6daeb5f72e
commit 3d632606a0
8 changed files with 294 additions and 39 deletions
@@ -31,7 +31,9 @@ class ContactPickerAdapter(
val isSameAsFrom: Boolean = false, val isSameAsFrom: Boolean = false,
val isManualEntry: Boolean = false, val isManualEntry: Boolean = false,
val imageHash: String? = null, val imageHash: String? = null,
val inactiveReason: String? = null val inactiveReason: String? = null,
val balance: String? = null,
val bankLogoRes: Int? = null
) : PickerItem() ) : PickerItem()
} }
@@ -89,14 +91,31 @@ class ContactPickerAdapter(
binding.tvPrimary.text = item.displayName binding.tvPrimary.text = item.displayName
binding.tvSecondary.text = item.subtitle binding.tvSecondary.text = item.subtitle
val cached = item.imageHash?.let { imageCache[it] } if (item.balance != null) {
if (cached != null) { binding.tvBalance.text = item.balance
binding.ivIcon.setImageBitmap(cached) binding.tvBalance.visibility = android.view.View.VISIBLE
} else { } else {
val iconChar = if (item.isManualEntry) "" else item.displayName.firstOrNull()?.uppercaseChar()?.toString() ?: "?" binding.tvBalance.visibility = android.view.View.GONE
val iconColor = if (item.isManualEntry) "#546E7A" else item.colorHex }
binding.ivIcon.setImageBitmap(makeInitialsBitmap(iconChar, iconColor, binding.ivIcon.context))
if (item.imageHash != null) onImageNeeded?.invoke(item.imageHash) val cached = item.imageHash?.let { imageCache[it] }
when {
cached != null -> {
binding.ivIcon.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
binding.ivIcon.setImageBitmap(cached)
}
item.bankLogoRes != null -> {
binding.ivIcon.scaleType = android.widget.ImageView.ScaleType.FIT_CENTER
binding.ivIcon.setImageResource(item.bankLogoRes)
if (item.imageHash != null) onImageNeeded?.invoke(item.imageHash)
}
else -> {
binding.ivIcon.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
val iconChar = if (item.isManualEntry) "" else item.displayName.firstOrNull()?.uppercaseChar()?.toString() ?: "?"
val iconColor = if (item.isManualEntry) "#546E7A" else item.colorHex
binding.ivIcon.setImageBitmap(makeInitialsBitmap(iconChar, iconColor, binding.ivIcon.context))
if (item.imageHash != null) onImageNeeded?.invoke(item.imageHash)
}
} }
binding.root.alpha = if (item.isSameAsFrom || item.inactiveReason != null) 0.4f else 1.0f binding.root.alpha = if (item.isSameAsFrom || item.inactiveReason != null) 0.4f else 1.0f
@@ -24,7 +24,10 @@ import sh.sar.basedbank.BasedBankApp
import sh.sar.basedbank.R import sh.sar.basedbank.R
import sh.sar.basedbank.api.mib.MibContactsClient import sh.sar.basedbank.api.mib.MibContactsClient
import sh.sar.basedbank.databinding.SheetContactPickerBinding import sh.sar.basedbank.databinding.SheetContactPickerBinding
import sh.sar.basedbank.util.AccountListParser
import sh.sar.basedbank.util.RecentsCache import sh.sar.basedbank.util.RecentsCache
import sh.sar.basedbank.util.bmlapi.BmlCardParser
import sh.sar.basedbank.util.bmlapi.BmlDashboardParser
class ContactPickerSheetFragment : BottomSheetDialogFragment() { class ContactPickerSheetFragment : BottomSheetDialogFragment() {
@@ -225,17 +228,27 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
for (acc in filteredRegular) { for (acc in filteredRegular) {
if (acc.profileImageHash != null) profileImageHashes.add(acc.profileImageHash) if (acc.profileImageHash != null) profileImageHashes.add(acc.profileImageHash)
val isSame = acc.accountNumber == fromAccountNumber val isSame = acc.accountNumber == fromAccountNumber
val accBal = if (hide) "••••••" else acc.availableBalance val parsedBalance = AccountListParser.from(acc)?.balance
?: "${acc.currencyName} ${acc.availableBalance}"
val balance = if (hide) maskAmount(parsedBalance) else parsedBalance
val logoRes = when (acc.bank) {
"BML" -> R.drawable.bml_logo_vector
"FAHIPAY" -> R.drawable.fahipay_logo
"MIB" -> R.drawable.mib_logo
else -> null
}
items.add(ContactPickerAdapter.PickerItem.Row( items.add(ContactPickerAdapter.PickerItem.Row(
accountNumber = acc.accountNumber, accountNumber = acc.accountNumber,
displayName = acc.accountBriefName, displayName = acc.accountBriefName,
subtitle = "${acc.accountNumber} · ${acc.currencyName} $accBal", subtitle = acc.accountNumber,
colorHex = "#FE860E", colorHex = "#FE860E",
isSameAsFrom = isSame, isSameAsFrom = isSame,
imageHash = acc.profileImageHash, imageHash = acc.profileImageHash,
inactiveReason = if (isSame) null inactiveReason = if (isSame) null
else if (fromIsCard && acc.loginTag != fromLoginTag) "Cards can only be used within the same BML account" else if (fromIsCard && acc.loginTag != fromLoginTag) "Cards can only be used within the same BML account"
else currencyMismatchReason(fromCurrency, acc.currencyName) else currencyMismatchReason(fromCurrency, acc.currencyName),
balance = balance,
bankLogoRes = logoRes
)) ))
} }
} }
@@ -249,18 +262,24 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
if (acc.profileImageHash != null) profileImageHashes.add(acc.profileImageHash) if (acc.profileImageHash != null) profileImageHashes.add(acc.profileImageHash)
val isSame = acc.accountNumber == fromAccountNumber val isSame = acc.accountNumber == fromAccountNumber
val isActive = acc.statusDesc.equals("Active", ignoreCase = true) val isActive = acc.statusDesc.equals("Active", ignoreCase = true)
val cardBal = if (hide) "••••••" else acc.availableBalance val isDebit = acc.profileType == "BML_DEBIT"
val parsedBalance = if (isDebit) null
else AccountListParser.from(acc)?.balance ?: "${acc.currencyName} ${acc.availableBalance}"
val balance = parsedBalance?.let { if (hide) maskAmount(it) else it }
val logoRes = BmlCardParser.cardNetworkIcon(acc) ?: R.drawable.bml_logo_vector
items.add(ContactPickerAdapter.PickerItem.Row( items.add(ContactPickerAdapter.PickerItem.Row(
accountNumber = acc.accountNumber, accountNumber = acc.accountNumber,
displayName = acc.accountBriefName, displayName = acc.accountBriefName,
subtitle = "${acc.accountNumber} · ${acc.currencyName} $cardBal", subtitle = acc.accountNumber,
colorHex = "#FE860E", colorHex = "#FE860E",
isSameAsFrom = isSame, isSameAsFrom = isSame,
imageHash = acc.profileImageHash, imageHash = acc.profileImageHash,
inactiveReason = if (isSame) null inactiveReason = if (isSame) null
else if (!isActive) acc.statusDesc else if (!isActive) acc.statusDesc
else if (acc.loginTag != fromLoginTag) "Cards can only be used within the same BML account" else if (acc.loginTag != fromLoginTag) "Cards can only be used within the same BML account"
else currencyMismatchReason(fromCurrency, acc.currencyName) else currencyMismatchReason(fromCurrency, acc.currencyName),
balance = balance,
bankLogoRes = logoRes
)) ))
} }
} }
@@ -32,11 +32,15 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import sh.sar.basedbank.BasedBankApp
import sh.sar.basedbank.R import sh.sar.basedbank.R
import sh.sar.basedbank.api.models.BankAccount import sh.sar.basedbank.api.models.BankAccount
import sh.sar.basedbank.databinding.FragmentPayMvQrBinding import sh.sar.basedbank.databinding.FragmentPayMvQrBinding
import sh.sar.basedbank.databinding.ItemAccountDropdownBinding import sh.sar.basedbank.databinding.ItemAccountDropdownBinding
import sh.sar.basedbank.util.AccountListParser
import sh.sar.basedbank.util.PaymvQrParser import sh.sar.basedbank.util.PaymvQrParser
import sh.sar.basedbank.util.bmlapi.BmlCardParser
import sh.sar.basedbank.util.bmlapi.BmlDashboardParser
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
@@ -49,6 +53,7 @@ class PayMvQrFragment : Fragment() {
private var selectedAccount: BankAccount? = null private var selectedAccount: BankAccount? = null
private var generatedBitmap: Bitmap? = null private var generatedBitmap: Bitmap? = null
private var generateJob: Job? = null private var generateJob: Job? = null
private val dropdownProfileImageCache = mutableMapOf<String, Bitmap>()
private val qrLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> private val qrLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult
@@ -410,9 +415,66 @@ class PayMvQrFragment : Fragment() {
} }
val ownerPrefix = if (acc.bank == "BML" && acc.profileName.isNotBlank()) "${acc.profileName} · " else "" val ownerPrefix = if (acc.bank == "BML" && acc.profileName.isNotBlank()) "${acc.profileName} · " else ""
b.tvDropdownAccountName.text = "$ownerPrefix${acc.accountBriefName}" b.tvDropdownAccountName.text = "$ownerPrefix${acc.accountBriefName}"
val displayData = AccountListParser.from(acc)
val typeLabel = displayData?.typeLabel
?: if (acc.bank == "BML") BmlDashboardParser.productLabel(acc.accountTypeName)
else acc.accountTypeName.trim()
b.tvDropdownAccountNumber.text = acc.accountNumber b.tvDropdownAccountNumber.text = acc.accountNumber
b.tvDropdownBalance.text = "" if (typeLabel.isNotBlank()) {
b.tvDropdownAccountType.text = typeLabel
b.tvDropdownAccountType.visibility = View.VISIBLE
} else {
b.tvDropdownAccountType.visibility = View.GONE
}
b.tvDropdownBalance.text = displayData?.balance ?: ""
b.root.alpha = 1f b.root.alpha = 1f
val networkIcon = BmlCardParser.cardNetworkIcon(acc)
when {
networkIcon != null -> {
b.ivDropdownCardLogo.setImageResource(networkIcon)
b.ivDropdownCardLogo.visibility = View.VISIBLE
}
acc.bank == "BML" -> {
b.ivDropdownCardLogo.setImageResource(R.drawable.bml_logo_vector)
b.ivDropdownCardLogo.visibility = View.VISIBLE
}
acc.bank == "FAHIPAY" -> {
b.ivDropdownCardLogo.setImageResource(R.drawable.fahipay_logo)
b.ivDropdownCardLogo.visibility = View.VISIBLE
}
acc.bank == "MIB" -> {
val hash = acc.profileImageHash
val cached = hash?.let { dropdownProfileImageCache[it] }
val imageView = b.ivDropdownCardLogo
imageView.tag = hash
if (cached != null) {
imageView.setImageBitmap(cached)
} else {
imageView.setImageResource(R.drawable.mib_logo)
if (hash != null) {
val app = requireActivity().application as BasedBankApp
viewLifecycleOwner.lifecycleScope.launch {
val bitmap = withContext(Dispatchers.IO) {
try {
val sess = app.anyMibSession() ?: return@withContext null
val b64 = app.anyMibFlow()?.fetchProfileImage(sess, hash) ?: return@withContext null
val bytes = android.util.Base64.decode(b64, android.util.Base64.DEFAULT)
BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
} catch (_: Exception) { null }
}
if (bitmap != null) {
dropdownProfileImageCache[hash] = bitmap
if (imageView.tag == hash) imageView.setImageBitmap(bitmap)
}
}
}
}
imageView.visibility = View.VISIBLE
}
else -> b.ivDropdownCardLogo.visibility = View.GONE
}
return b.root return b.root
} }
@@ -62,6 +62,7 @@ import sh.sar.basedbank.util.CredentialStore
import sh.sar.basedbank.util.AccountInputParser import sh.sar.basedbank.util.AccountInputParser
import sh.sar.basedbank.util.PaymvQrParser import sh.sar.basedbank.util.PaymvQrParser
import sh.sar.basedbank.util.bmlapi.BmlCardParser import sh.sar.basedbank.util.bmlapi.BmlCardParser
import sh.sar.basedbank.util.bmlapi.BmlDashboardParser
import sh.sar.basedbank.util.RecentPick import sh.sar.basedbank.util.RecentPick
import sh.sar.basedbank.util.RecentsCache import sh.sar.basedbank.util.RecentsCache
import sh.sar.basedbank.util.ReceiptStore import sh.sar.basedbank.util.ReceiptStore
@@ -85,6 +86,7 @@ class TransferFragment : Fragment() {
private var resolvedAccountNumber = "" private var resolvedAccountNumber = ""
private var resolvedRecipientName = "" private var resolvedRecipientName = ""
private var resolvedBankName = "" private var resolvedBankName = ""
private var resolvedToOwnAccount: BankAccount? = null
// Selected Fahipay service when source is Fahipay and destination is a phone number // Selected Fahipay service when source is Fahipay and destination is a phone number
// Values: "FAHIPAY_TRANSFER", "RAASTAS", "OOREDOO_BILL" // Values: "FAHIPAY_TRANSFER", "RAASTAS", "OOREDOO_BILL"
@@ -206,6 +208,7 @@ class TransferFragment : Fragment() {
viewModel.hideAmounts.observe(viewLifecycleOwner) { viewModel.hideAmounts.observe(viewLifecycleOwner) {
accountDropdownAdapter?.notifyDataSetChanged() accountDropdownAdapter?.notifyDataSetChanged()
selectedAccount?.let { showFromCard(it) } selectedAccount?.let { showFromCard(it) }
resolvedToOwnAccount?.let { showToCard(it) }
} }
childFragmentManager.setFragmentResultListener(ContactPickerSheetFragment.REQUEST_KEY, viewLifecycleOwner) { _, bundle -> childFragmentManager.setFragmentResultListener(ContactPickerSheetFragment.REQUEST_KEY, viewLifecycleOwner) { _, bundle ->
@@ -281,6 +284,9 @@ class TransferFragment : Fragment() {
// Show merchant in the "To" card — clear button hidden (can't change recipient for QR) // Show merchant in the "To" card — clear button hidden (can't change recipient for QR)
binding.tvToAccountName.text = info.merchantName binding.tvToAccountName.text = info.merchantName
binding.tvToBankBic.text = info.merchantAddress.ifBlank { "BML Merchant" } binding.tvToBankBic.text = info.merchantAddress.ifBlank { "BML Merchant" }
binding.tvToAccountDetails.visibility = View.GONE
binding.tvToBalance.visibility = View.GONE
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
binding.ivToPhoto.setImageBitmap(makeInitialsBitmap(info.merchantName, "#0066A1")) binding.ivToPhoto.setImageBitmap(makeInitialsBitmap(info.merchantName, "#0066A1"))
binding.btnClearToInfo.visibility = View.GONE binding.btnClearToInfo.visibility = View.GONE
binding.cardToInfo.visibility = View.VISIBLE binding.cardToInfo.visibility = View.VISIBLE
@@ -366,34 +372,102 @@ class TransferFragment : Fragment() {
val bankLabel = when (account.bank) { val bankLabel = when (account.bank) {
"BML" -> "BML" "BML" -> "BML"
"FAHIPAY" -> "FP" "FAHIPAY" -> "FP"
"MIB" -> "MIB"
else -> null else -> null
} }
val typeLabel = when { val typeLabel = AccountListParser.from(account)?.typeLabel
account.profileType == "BML_PREPAID" -> "Prepaid Card" ?: if (account.bank == "BML") BmlDashboardParser.productLabel(account.accountTypeName)
account.profileType == "BML_CREDIT" -> "Credit Card" else account.accountTypeName.ifBlank { account.profileType }
account.profileType == "BML_DEBIT" -> "Debit Card"
account.accountTypeName.isNotBlank() -> account.accountTypeName
else -> account.profileType
}
val hide = viewModel.hideAmounts.value ?: false val hide = viewModel.hideAmounts.value ?: false
val isDebitCard = account.profileType == "BML_DEBIT" val isDebitCard = account.profileType == "BML_DEBIT"
val balancePart = if (isDebitCard) null else "${account.currencyName} ${account.availableBalance}" val balancePart = if (isDebitCard) null else "${account.currencyName} ${account.availableBalance}"
binding.tvFromAccountName.text = account.accountBriefName binding.tvFromAccountName.text = account.accountBriefName
binding.tvFromAccountNumber.text = account.accountNumber binding.tvFromAccountNumber.text = account.accountNumber
binding.tvFromAccountDetails.text = listOfNotNull(bankLabel, typeLabel).joinToString(" · ")
val balanceDisplay = balancePart?.let { if (hide) maskAmount(it) else it } val balanceDisplay = balancePart?.let { if (hide) maskAmount(it) else it }
binding.tvFromAccountDetails.text = listOfNotNull(bankLabel, typeLabel, balanceDisplay).joinToString(" · ") if (balanceDisplay != null) {
val networkIcon = BmlCardParser.cardNetworkIcon(account) binding.tvFromBalance.text = balanceDisplay
if (networkIcon != null) { binding.tvFromBalance.visibility = View.VISIBLE
binding.ivFromPhoto.setImageResource(networkIcon)
} else { } else {
binding.ivFromPhoto.setImageBitmap(makeInitialsBitmap(account.accountBriefName, colorHex)) binding.tvFromBalance.visibility = View.GONE
}
val networkIcon = BmlCardParser.cardNetworkIcon(account)
when {
networkIcon != null -> {
binding.ivFromPhoto.scaleType = android.widget.ImageView.ScaleType.FIT_CENTER
binding.ivFromPhoto.setImageResource(networkIcon)
}
account.bank == "BML" -> {
binding.ivFromPhoto.scaleType = android.widget.ImageView.ScaleType.FIT_CENTER
binding.ivFromPhoto.setImageResource(R.drawable.bml_logo_vector)
}
account.bank == "FAHIPAY" -> {
binding.ivFromPhoto.scaleType = android.widget.ImageView.ScaleType.FIT_CENTER
binding.ivFromPhoto.setImageResource(R.drawable.fahipay_logo)
}
else -> {
binding.ivFromPhoto.scaleType = android.widget.ImageView.ScaleType.FIT_CENTER
binding.ivFromPhoto.setImageResource(R.drawable.mib_logo)
if (account.profileImageHash != null) loadFromPhoto(account.profileImageHash)
}
} }
binding.tilFrom.visibility = View.GONE binding.tilFrom.visibility = View.GONE
binding.cardFromInfo.visibility = View.VISIBLE binding.cardFromInfo.visibility = View.VISIBLE
}
if (account.bank != "BML" && account.profileImageHash != null) { private fun showToCard(account: BankAccount) {
loadFromPhoto(account.profileImageHash) resolvedToOwnAccount = account
val colorHex = when (account.bank) {
"BML" -> "#0066A1"
"FAHIPAY" -> "#15BEA7"
else -> "#FE860E"
}
val bankLabel = when (account.bank) {
"BML" -> "BML"
"FAHIPAY" -> "FP"
"MIB" -> "MIB"
else -> null
}
val typeLabel = AccountListParser.from(account)?.typeLabel
?: if (account.bank == "BML") BmlDashboardParser.productLabel(account.accountTypeName)
else account.accountTypeName.ifBlank { account.profileType }
val hide = viewModel.hideAmounts.value ?: false
val isDebitCard = account.profileType == "BML_DEBIT"
val balancePart = if (isDebitCard) null else AccountListParser.from(account)?.balance
?: "${account.currencyName} ${account.availableBalance}"
binding.tvToAccountName.text = account.accountBriefName
binding.tvToBankBic.text = account.accountNumber
binding.tvToAccountDetails.text = listOfNotNull(bankLabel, typeLabel).joinToString(" · ")
binding.tvToAccountDetails.visibility = View.VISIBLE
val balanceDisplay = balancePart?.let { if (hide) maskAmount(it) else it }
if (balanceDisplay != null) {
binding.tvToBalance.text = balanceDisplay
binding.tvToBalance.visibility = View.VISIBLE
} else {
binding.tvToBalance.visibility = View.GONE
}
val networkIcon = BmlCardParser.cardNetworkIcon(account)
when {
networkIcon != null -> {
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.FIT_CENTER
binding.ivToPhoto.setImageResource(networkIcon)
}
account.bank == "BML" -> {
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.FIT_CENTER
binding.ivToPhoto.setImageResource(R.drawable.bml_logo_vector)
}
account.bank == "FAHIPAY" -> {
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.FIT_CENTER
binding.ivToPhoto.setImageResource(R.drawable.fahipay_logo)
}
else -> {
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.FIT_CENTER
binding.ivToPhoto.setImageResource(R.drawable.mib_logo)
if (account.profileImageHash != null) loadToPhoto(account.profileImageHash, isProfile = true)
}
} }
} }
@@ -406,7 +480,10 @@ class TransferFragment : Fragment() {
val bytes = Base64.decode(base64, Base64.DEFAULT) val bytes = Base64.decode(base64, Base64.DEFAULT)
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size) ?: return@launch val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size) ?: return@launch
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (_binding != null) binding.ivFromPhoto.setImageBitmap(bitmap) if (_binding != null) {
binding.ivFromPhoto.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
binding.ivFromPhoto.setImageBitmap(bitmap)
}
} }
} catch (_: Exception) { } } catch (_: Exception) { }
} }
@@ -422,6 +499,7 @@ class TransferFragment : Fragment() {
binding.btnClearToInfo.setOnClickListener { binding.btnClearToInfo.setOnClickListener {
resolvedAccountNumber = "" resolvedAccountNumber = ""
resolvedRecipientName = "" resolvedRecipientName = ""
resolvedToOwnAccount = null
selectedFahipayService = null selectedFahipayService = null
binding.cardToInfo.visibility = View.GONE binding.cardToInfo.visibility = View.GONE
binding.layoutServiceSelector.visibility = View.INVISIBLE binding.layoutServiceSelector.visibility = View.INVISIBLE
@@ -437,6 +515,7 @@ class TransferFragment : Fragment() {
if (binding.cardToInfo.visibility == View.VISIBLE) { if (binding.cardToInfo.visibility == View.VISIBLE) {
resolvedAccountNumber = "" resolvedAccountNumber = ""
resolvedRecipientName = "" resolvedRecipientName = ""
resolvedToOwnAccount = null
binding.cardToInfo.visibility = View.GONE binding.cardToInfo.visibility = View.GONE
binding.tilTo.visibility = View.VISIBLE binding.tilTo.visibility = View.VISIBLE
binding.btnPickContact.visibility = View.VISIBLE binding.btnPickContact.visibility = View.VISIBLE
@@ -546,9 +625,16 @@ class TransferFragment : Fragment() {
resolvedRecipientName = info.accountName resolvedRecipientName = info.accountName
resolvedBankName = info.bankId resolvedBankName = info.bankId
binding.tvToAccountName.text = displayName if (matchedAcc != null) {
binding.tvToBankBic.text = "${info.accountNumber} · ${info.bankId}" showToCard(matchedAcc)
binding.ivToPhoto.setImageBitmap(makeInitialsBitmap(displayName, colorHex)) } else {
binding.tvToAccountName.text = displayName
binding.tvToBankBic.text = "${info.accountNumber} · ${info.bankId}"
binding.tvToAccountDetails.visibility = View.GONE
binding.tvToBalance.visibility = View.GONE
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
binding.ivToPhoto.setImageBitmap(makeInitialsBitmap(displayName, colorHex))
}
binding.tilTo.visibility = View.GONE binding.tilTo.visibility = View.GONE
binding.btnPickContact.visibility = View.GONE binding.btnPickContact.visibility = View.GONE
binding.btnScanQr.visibility = View.GONE binding.btnScanQr.visibility = View.GONE
@@ -673,9 +759,18 @@ class TransferFragment : Fragment() {
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 ?: ""
binding.tvToAccountName.text = displayName val ownAccount = viewModel.accounts.value?.firstOrNull { it.accountNumber == accountNumber }
binding.tvToBankBic.text = subtitle if (ownAccount != null) {
binding.ivToPhoto.setImageBitmap(makeInitialsBitmap(displayName, colorHex)) showToCard(ownAccount)
} else {
resolvedToOwnAccount = null
binding.tvToAccountName.text = displayName
binding.tvToBankBic.text = subtitle
binding.tvToAccountDetails.visibility = View.GONE
binding.tvToBalance.visibility = View.GONE
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
binding.ivToPhoto.setImageBitmap(makeInitialsBitmap(displayName, colorHex))
}
binding.tilTo.visibility = View.GONE binding.tilTo.visibility = View.GONE
binding.btnPickContact.visibility = View.GONE binding.btnPickContact.visibility = View.GONE
binding.btnScanQr.visibility = View.GONE binding.btnScanQr.visibility = View.GONE
@@ -1479,6 +1574,7 @@ class TransferFragment : Fragment() {
resolvedAccountNumber = "" resolvedAccountNumber = ""
resolvedRecipientName = "" resolvedRecipientName = ""
resolvedBankName = "" resolvedBankName = ""
resolvedToOwnAccount = null
selectedFahipayService = null selectedFahipayService = null
binding.cardToInfo.visibility = View.GONE binding.cardToInfo.visibility = View.GONE
binding.chipGroupService.visibility = View.GONE binding.chipGroupService.visibility = View.GONE
@@ -1505,7 +1601,10 @@ class TransferFragment : Fragment() {
val bytes = Base64.decode(base64, Base64.DEFAULT) val bytes = Base64.decode(base64, Base64.DEFAULT)
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size) ?: return@launch val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size) ?: return@launch
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (_binding != null) binding.ivToPhoto.setImageBitmap(bitmap) if (_binding != null) {
binding.ivToPhoto.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP
binding.ivToPhoto.setImageBitmap(bitmap)
}
} }
} catch (_: Exception) { } } catch (_: Exception) { }
} }
@@ -1633,8 +1732,18 @@ class TransferFragment : Fragment() {
val ownerPrefix = if (isBmlAccount && acc.profileName.isNotBlank()) "${acc.profileName} · " else "" val ownerPrefix = if (isBmlAccount && acc.profileName.isNotBlank()) "${acc.profileName} · " else ""
val hide = viewModel.hideAmounts.value ?: false val hide = viewModel.hideAmounts.value ?: false
b.tvDropdownAccountName.text = "$ownerPrefix${acc.accountBriefName}" b.tvDropdownAccountName.text = "$ownerPrefix${acc.accountBriefName}"
val displayData = AccountListParser.from(acc)
val typeLabel = displayData?.typeLabel
?: if (acc.bank == "BML") BmlDashboardParser.productLabel(acc.accountTypeName)
else acc.accountTypeName.trim()
b.tvDropdownAccountNumber.text = if (inactive) "${acc.accountNumber} · ${acc.statusDesc}" else acc.accountNumber b.tvDropdownAccountNumber.text = if (inactive) "${acc.accountNumber} · ${acc.statusDesc}" else acc.accountNumber
val balance = AccountListParser.from(acc)?.balance ?: "" if (typeLabel.isNotBlank()) {
b.tvDropdownAccountType.text = typeLabel
b.tvDropdownAccountType.visibility = View.VISIBLE
} else {
b.tvDropdownAccountType.visibility = View.GONE
}
val balance = displayData?.balance ?: ""
b.tvDropdownBalance.text = if (hide && balance.isNotBlank()) maskAmount(balance) else balance b.tvDropdownBalance.text = if (hide && balance.isNotBlank()) maskAmount(balance) else balance
b.root.alpha = if (inactive) 0.4f else 1f b.root.alpha = if (inactive) 0.4f else 1f
val networkIcon = BmlCardParser.cardNetworkIcon(acc) val networkIcon = BmlCardParser.cardNetworkIcon(acc)
@@ -55,6 +55,7 @@
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<!-- Amount (optional) --> <!-- Amount (optional) -->
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilAmount" android:id="@+id/tilAmount"
+29 -1
View File
@@ -101,6 +101,15 @@
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/tvFromBalance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceTitleMedium"
android:textColor="?attr/colorOnSurface"
android:paddingHorizontal="8dp"
android:visibility="gone" />
<ImageButton <ImageButton
android:id="@+id/btnClearFromInfo" android:id="@+id/btnClearFromInfo"
android:layout_width="40dp" android:layout_width="40dp"
@@ -218,10 +227,29 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:textAppearance="?attr/textAppearanceBodySmall" android:textAppearance="?attr/textAppearanceBodySmall"
android:textColor="?attr/colorOnSurfaceVariant" /> android:textColor="?attr/colorOnSurfaceVariant"
android:fontFamily="monospace" />
<TextView
android:id="@+id/tvToAccountDetails"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textAppearance="?attr/textAppearanceBodySmall"
android:textColor="?attr/colorOnSurfaceVariant"
android:visibility="gone" />
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/tvToBalance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceTitleMedium"
android:textColor="?attr/colorOnSurface"
android:paddingHorizontal="8dp"
android:visibility="gone" />
<ImageButton <ImageButton
android:id="@+id/btnClearToInfo" android:id="@+id/btnClearToInfo"
android:layout_width="40dp" android:layout_width="40dp"
@@ -53,6 +53,14 @@
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/tvDropdownAccountType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceBodySmall"
android:textColor="?attr/colorOnSurfaceVariant"
android:visibility="gone" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
@@ -47,4 +47,13 @@
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/tvBalance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceTitleMedium"
android:textColor="?attr/colorOnSurface"
android:paddingHorizontal="8dp"
android:visibility="gone" />
</LinearLayout> </LinearLayout>