compress mib cards and add prep support for bml cards
All checks were successful
Auto Tag on Version Change / check-version (push) Successful in 4s

This commit is contained in:
2026-05-23 21:03:25 +05:00
parent 268f3dada0
commit e9f0cec698
50 changed files with 249 additions and 66 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -166,16 +166,21 @@ class BmlAccountClient {
internalId = internalId
))
} else if (accountType == "Card") {
val isVisible = item.optBoolean("account_visible", false)
if (!isVisible) continue
val isPrepaid = item.optBoolean("prepaid_card", false)
val productCode = item.optString("product_code", "")
val cardBalance = item.optJSONObject("cardBalance")
val available = cardBalance?.optDouble("AvailableLimit", 0.0) ?: 0.0
val current = cardBalance?.optDouble("CurrentBalance", 0.0) ?: 0.0
val cardProfileType = when {
isPrepaid -> "BML_PREPAID"
product.contains("CREDIT", ignoreCase = true) -> "BML_CREDIT"
else -> "BML_DEBIT"
}
prepaidCards.add(BankAccount(
bank = "BML",
profileName = profileName,
profileType = if (isPrepaid) "BML_PREPAID" else "BML_CREDIT",
profileType = cardProfileType,
cifType = productCode,
accountNumber = accountNumber,
accountBriefName = item.optString("alias").ifBlank { product },
currencyName = currency,

View File

@@ -15,8 +15,8 @@ import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import sh.sar.basedbank.R
import sh.sar.basedbank.api.mib.MibCard
import sh.sar.basedbank.databinding.FragmentCardSettingsBinding
import sh.sar.basedbank.util.bmlapi.BmlCardParser
class CardSettingsFragment : Fragment() {
@@ -44,17 +44,23 @@ class CardSettingsFragment : Fragment() {
}
binding.swipeRefresh.setOnRefreshListener {
(activity as? HomeActivity)?.triggerRefreshCards()
(activity as? HomeActivity)?.triggerRefresh()
}
viewModel.mibCards.observe(viewLifecycleOwner) { cards ->
if (cards == null) return@observe
adapter.update(cards)
val updateCardList = {
val mibItems = (viewModel.mibCards.value ?: emptyList()).map { CardItem.Mib(it) }
val bmlItems = (viewModel.accounts.value ?: emptyList())
.filter { it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT" }
.map { CardItem.Bml(it) }
val all = mibItems + bmlItems
adapter.update(all)
binding.loadingView.visibility = View.GONE
binding.swipeRefresh.isRefreshing = false
binding.emptyView.visibility = if (cards.isEmpty()) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (cards.isEmpty()) View.GONE else View.VISIBLE
binding.emptyView.visibility = if (all.isEmpty()) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (all.isEmpty()) View.GONE else View.VISIBLE
}
viewModel.mibCards.observe(viewLifecycleOwner) { updateCardList() }
viewModel.accounts.observe(viewLifecycleOwner) { updateCardList() }
if (viewModel.mibCards.value == null) {
binding.loadingView.visibility = View.VISIBLE
@@ -73,11 +79,11 @@ class CardSettingsFragment : Fragment() {
}
private inner class CardSettingsAdapter(
private var cards: List<MibCard>,
private var cards: List<CardItem>,
private val context: Context
) : RecyclerView.Adapter<CardSettingsAdapter.VH>() {
fun update(newCards: List<MibCard>) {
fun update(newCards: List<CardItem>) {
cards = newCards
notifyDataSetChanged()
}
@@ -93,17 +99,34 @@ class CardSettingsFragment : Fragment() {
private val tvCardOwner: TextView = view.findViewById(R.id.tvCardOwner)
private val tvCardNumber: TextView = view.findViewById(R.id.tvCardNumber)
private val tvCardType: TextView = view.findViewById(R.id.tvCardType)
private val tvCardStatus: TextView = view.findViewById(R.id.tvCardStatus)
private val btnChangePin: View = view.findViewById(R.id.btnChangePin)
private val btnFreeze: View = view.findViewById(R.id.btnFreeze)
private val btnBlock: View = view.findViewById(R.id.btnBlock)
fun bind(card: MibCard) {
tvCardOwner.text = card.cardHolderName
tvCardNumber.text = PayWithCardFragment.formatMasked(card.maskedCardNumber)
tvCardType.text = card.cardTypeDesc
val assetPath = PayWithCardFragment.cardImageAsset(card)
if (assetPath != null) PayWithCardFragment.loadCardImage(ivCardImage, assetPath)
else ivCardImage.setImageDrawable(null)
fun bind(item: CardItem) {
when (item) {
is CardItem.Mib -> {
tvCardOwner.text = item.card.cardHolderName
tvCardNumber.text = PayWithCardFragment.formatMasked(item.card.maskedCardNumber)
tvCardType.text = item.card.cardTypeDesc
val assetPath = PayWithCardFragment.cardImageAsset(item.card)
if (assetPath != null) PayWithCardFragment.loadCardImage(ivCardImage, assetPath)
else ivCardImage.setImageDrawable(null)
PayWithCardFragment.bindCardStatus(tvCardStatus, PayWithCardFragment.mibCardStatusLabel(item.card.cardStatus))
itemView.alpha = 1f
}
is CardItem.Bml -> {
tvCardOwner.text = item.account.accountBriefName
tvCardNumber.text = PayWithCardFragment.formatMasked(item.account.accountNumber)
tvCardType.text = item.account.accountTypeName
PayWithCardFragment.loadCardImage(ivCardImage, BmlCardParser.cardImageAsset(item.account))
val isActive = item.account.statusDesc.equals("Active", ignoreCase = true)
val bmlStatus = item.account.statusDesc.takeUnless { isActive }
PayWithCardFragment.bindCardStatus(tvCardStatus, bmlStatus)
itemView.alpha = if (isActive) 1f else 0.45f
}
}
val wip = View.OnClickListener {
Toast.makeText(context, R.string.work_in_progress, Toast.LENGTH_SHORT).show()
}

View File

@@ -209,11 +209,11 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
val fromAccount = accounts.find { it.accountNumber == fromAccountNumber }
val fromCurrency = fromAccount?.currencyName ?: ""
val fromLoginTag = fromAccount?.loginTag ?: ""
val fromIsCard = fromAccount?.profileType == "BML_PREPAID" || fromAccount?.profileType == "BML_CREDIT"
val fromIsCard = fromAccount?.profileType == "BML_PREPAID" || fromAccount?.profileType == "BML_CREDIT" || fromAccount?.profileType == "BML_DEBIT"
if (tabTag == MY_ACCOUNTS_TAG) {
val regularAccounts = accounts.filter { it.profileType != "BML_PREPAID" && it.profileType != "BML_CREDIT" }
val cards = accounts.filter { it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" }
val regularAccounts = accounts.filter { it.profileType != "BML_PREPAID" && it.profileType != "BML_CREDIT" && it.profileType != "BML_DEBIT" }
val cards = accounts.filter { it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT" }
val filteredRegular = if (search.isBlank()) regularAccounts else regularAccounts.filter {
it.accountBriefName.contains(search, ignoreCase = true) || it.accountNumber.contains(search)

View File

@@ -21,6 +21,7 @@ import sh.sar.basedbank.api.bml.BmlForeignLimit
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 kotlin.math.abs
import sh.sar.basedbank.databinding.FragmentDashboardBinding
import sh.sar.basedbank.databinding.ItemForeignLimitBinding
@@ -57,11 +58,17 @@ class DashboardFragment : Fragment() {
binding.rvCards.adapter = cardAdapter
LinearSnapHelper().attachToRecyclerView(binding.rvCards)
viewModel.mibCards.observe(viewLifecycleOwner) { cards ->
if (cards.isNullOrEmpty()) return@observe
cardAdapter.update(cards)
binding.sectionCards.visibility = View.VISIBLE
val updateCardList = {
val mibItems = (viewModel.mibCards.value ?: emptyList()).map { CardItem.Mib(it) }
val bmlItems = (viewModel.accounts.value ?: emptyList())
.filter { (it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT") && it.statusDesc.equals("Active", ignoreCase = true) }
.map { CardItem.Bml(it) }
val all = mibItems + bmlItems
cardAdapter.update(all)
binding.sectionCards.visibility = if (all.isNotEmpty()) View.VISIBLE else View.GONE
}
viewModel.mibCards.observe(viewLifecycleOwner) { updateCardList() }
viewModel.accounts.observe(viewLifecycleOwner) { updateCardList() }
val bottomPaddingBase = (16 * resources.displayMetrics.density).toInt()
ViewCompat.setOnApplyWindowInsetsListener(binding.buttonBar) { v, insets ->
@@ -229,9 +236,9 @@ class DashboardFragment : Fragment() {
}
private inner class DashboardCardAdapter : RecyclerView.Adapter<DashboardCardAdapter.VH>() {
private var cards: List<MibCard> = emptyList()
private var cards: List<CardItem> = emptyList()
fun update(newCards: List<MibCard>) {
fun update(newCards: List<CardItem>) {
cards = newCards
notifyDataSetChanged()
}
@@ -249,15 +256,27 @@ class DashboardFragment : Fragment() {
private val ivCardImage: ImageView = view.findViewById(R.id.ivCardImage)
private val tvCardOwner: TextView = view.findViewById(R.id.tvCardOwner)
private val tvCardNumber: TextView = view.findViewById(R.id.tvCardNumber)
private val tvCardStatus: TextView = view.findViewById(R.id.tvCardStatus)
private val btnPayQr: View = view.findViewById(R.id.btnPayQr)
private val btnPayNfc: View = view.findViewById(R.id.btnPayNfc)
fun bind(card: MibCard) {
tvCardOwner.text = card.cardHolderName
tvCardNumber.text = PayWithCardFragment.formatMasked(card.maskedCardNumber)
val assetPath = PayWithCardFragment.cardImageAsset(card)
if (assetPath != null) PayWithCardFragment.loadCardImage(ivCardImage, assetPath)
else ivCardImage.setImageDrawable(null)
fun bind(item: CardItem) {
when (item) {
is CardItem.Mib -> {
tvCardOwner.text = item.card.cardHolderName
tvCardNumber.text = PayWithCardFragment.formatMasked(item.card.maskedCardNumber)
val assetPath = PayWithCardFragment.cardImageAsset(item.card)
if (assetPath != null) PayWithCardFragment.loadCardImage(ivCardImage, assetPath)
else ivCardImage.setImageDrawable(null)
PayWithCardFragment.bindCardStatus(tvCardStatus, PayWithCardFragment.mibCardStatusLabel(item.card.cardStatus))
}
is CardItem.Bml -> {
tvCardOwner.text = item.account.accountBriefName
tvCardNumber.text = PayWithCardFragment.formatMasked(item.account.accountNumber)
PayWithCardFragment.loadCardImage(ivCardImage, BmlCardParser.cardImageAsset(item.account))
PayWithCardFragment.bindCardStatus(tvCardStatus, null) // only Active BML cards reach dashboard
}
}
btnPayQr.setOnClickListener {
Toast.makeText(requireContext(), R.string.work_in_progress, Toast.LENGTH_SHORT).show()
}

View File

@@ -10,6 +10,11 @@ import sh.sar.basedbank.api.models.BankContactCategory
import sh.sar.basedbank.api.mib.MibCard
import sh.sar.basedbank.api.mib.MibFinanceDeal
sealed class CardItem {
data class Mib(val card: MibCard) : CardItem()
data class Bml(val account: BankAccount) : CardItem()
}
class HomeViewModel : ViewModel() {
val accounts = MutableLiveData<List<BankAccount>>(emptyList())
val financing = MutableLiveData<List<MibFinanceDeal>>(emptyList())

View File

@@ -97,7 +97,7 @@ class PayMvQrFragment : Fragment() {
private fun setupDropdown() {
viewModel.accounts.observe(viewLifecycleOwner) { accounts ->
val eligible = accounts.filter {
it.profileType != "BML_PREPAID" && it.profileType != "BML_CREDIT" && it.profileType != "BML_LOAN"
it.profileType != "BML_PREPAID" && it.profileType != "BML_CREDIT" && it.profileType != "BML_DEBIT" && it.profileType != "BML_LOAN"
}
val adapter = QrAccountAdapter(requireContext(), eligible)
binding.actvAccount.setAdapter(adapter)

View File

@@ -2,6 +2,7 @@ package sh.sar.basedbank.ui.home
import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -16,9 +17,11 @@ import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import sh.sar.basedbank.R
import sh.sar.basedbank.api.models.BankAccount
import sh.sar.basedbank.api.mib.MibCard
import sh.sar.basedbank.databinding.FragmentPayWithCardBinding
import sh.sar.basedbank.util.CardsCache
import sh.sar.basedbank.util.bmlapi.BmlCardParser
class PayWithCardFragment : Fragment() {
@@ -46,17 +49,23 @@ class PayWithCardFragment : Fragment() {
}
binding.swipeRefresh.setOnRefreshListener {
(activity as? HomeActivity)?.triggerRefreshCards()
(activity as? HomeActivity)?.triggerRefresh()
}
viewModel.mibCards.observe(viewLifecycleOwner) { cards ->
if (cards == null) return@observe
adapter.update(cards)
val updateCardList = {
val mibItems = (viewModel.mibCards.value ?: emptyList()).map { CardItem.Mib(it) }
val bmlItems = (viewModel.accounts.value ?: emptyList())
.filter { (it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT") && it.statusDesc.equals("Active", ignoreCase = true) }
.map { CardItem.Bml(it) }
val all = mibItems + bmlItems
adapter.update(all)
binding.loadingView.visibility = View.GONE
binding.swipeRefresh.isRefreshing = false
binding.emptyView.visibility = if (cards.isEmpty()) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (cards.isEmpty()) View.GONE else View.VISIBLE
binding.emptyView.visibility = if (all.isEmpty()) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (all.isEmpty()) View.GONE else View.VISIBLE
}
viewModel.mibCards.observe(viewLifecycleOwner) { updateCardList() }
viewModel.accounts.observe(viewLifecycleOwner) { updateCardList() }
val cached = CardsCache.load(requireContext())
if (cached.isNotEmpty()) {
@@ -78,11 +87,11 @@ class PayWithCardFragment : Fragment() {
}
private inner class CardWalletAdapter(
private var cards: List<MibCard>,
private var cards: List<CardItem>,
private val context: Context
) : RecyclerView.Adapter<CardWalletAdapter.VH>() {
fun update(newCards: List<MibCard>) {
fun update(newCards: List<CardItem>) {
cards = newCards
notifyDataSetChanged()
}
@@ -98,16 +107,30 @@ class PayWithCardFragment : Fragment() {
private val tvCardOwner: TextView = view.findViewById(R.id.tvCardOwner)
private val tvCardNumber: TextView = view.findViewById(R.id.tvCardNumber)
private val tvCardType: TextView = view.findViewById(R.id.tvCardType)
private val tvCardStatus: TextView = view.findViewById(R.id.tvCardStatus)
private val btnPayQr: View = view.findViewById(R.id.btnPayQr)
private val btnPayNfc: View = view.findViewById(R.id.btnPayNfc)
fun bind(card: MibCard) {
tvCardOwner.text = card.cardHolderName
tvCardNumber.text = formatMasked(card.maskedCardNumber)
tvCardType.text = card.cardTypeDesc
val assetPath = cardImageAsset(card)
if (assetPath != null) loadCardImage(ivCardImage, assetPath)
else ivCardImage.setImageDrawable(null)
fun bind(item: CardItem) {
when (item) {
is CardItem.Mib -> {
tvCardOwner.text = item.card.cardHolderName
tvCardNumber.text = formatMasked(item.card.maskedCardNumber)
tvCardType.text = item.card.cardTypeDesc
val assetPath = cardImageAsset(item.card)
if (assetPath != null) loadCardImage(ivCardImage, assetPath)
else ivCardImage.setImageDrawable(null)
bindCardStatus(tvCardStatus, mibCardStatusLabel(item.card.cardStatus))
}
is CardItem.Bml -> {
tvCardOwner.text = item.account.accountBriefName
tvCardNumber.text = formatMasked(item.account.accountNumber)
tvCardType.text = item.account.accountTypeName
loadCardImage(ivCardImage, BmlCardParser.cardImageAsset(item.account))
val bmlStatus = item.account.statusDesc.takeUnless { it.equals("Active", ignoreCase = true) }
bindCardStatus(tvCardStatus, bmlStatus)
}
}
btnPayQr.setOnClickListener {
Toast.makeText(context, R.string.work_in_progress, Toast.LENGTH_SHORT).show()
}
@@ -127,9 +150,9 @@ class PayWithCardFragment : Fragment() {
companion object {
fun cardImageAsset(card: MibCard): String? = when (card.cardType) {
"53" -> "cards/mib/visa_black_platinum.jpg"
"57" -> "cards/mib/visa_blue_everyday.jpg"
"70" -> "cards/mib/visa_business.jpg"
"53" -> "cards/mib/visa_black_platinum.png"
"57" -> "cards/mib/visa_blue_everyday.png"
"70" -> "cards/mib/visa_business.png"
else -> null
}
@@ -144,6 +167,23 @@ class PayWithCardFragment : Fragment() {
}
}
fun mibCardStatusLabel(cardStatus: String): String? = when (cardStatus) {
"CHST0" -> null // Active — no badge
else -> cardStatus
}
fun bindCardStatus(tv: TextView, statusLabel: String?) {
if (statusLabel == null) { tv.visibility = View.GONE; return }
tv.visibility = View.VISIBLE
tv.text = statusLabel
val dp = tv.context.resources.displayMetrics.density
tv.background = GradientDrawable().apply {
shape = GradientDrawable.RECTANGLE
cornerRadius = 12 * dp
setColor(0xCC212121.toInt())
}
}
fun formatMasked(masked: String): String {
if (masked.length < 4) return masked
return "\u2022\u2022\u2022\u2022 ${masked.takeLast(4)}"

View File

@@ -283,6 +283,7 @@ class TransferFragment : Fragment() {
val typeLabel = when {
account.profileType == "BML_PREPAID" -> "Prepaid Card"
account.profileType == "BML_CREDIT" -> "Credit Card"
account.profileType == "BML_DEBIT" -> "Debit Card"
account.accountTypeName.isNotBlank() -> account.accountTypeName
else -> account.profileType
}
@@ -632,7 +633,7 @@ class TransferFragment : Fragment() {
val isSrcBml = src.bank == "BML"
val isBmlBusiness = isSrcBml && isBusinessProfile(src) // to test on personal accounts: use `isSrcBml`
val isSrcCard = src.profileType == "BML_PREPAID" || src.profileType == "BML_CREDIT"
val isSrcCard = src.profileType == "BML_PREPAID" || src.profileType == "BML_CREDIT" || src.profileType == "BML_DEBIT"
val isDestMib = AccountInputParser.detect(resolvedAccountNumber) == AccountInputParser.InputType.MIB_ACCOUNT
val currency = src.currencyName.ifBlank { "MVR" }
val allAccounts = viewModel.accounts.value ?: emptyList()
@@ -860,7 +861,7 @@ class TransferFragment : Fragment() {
}
// Determine type + credit account
val isDestMyCard = allAccounts.any { (it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT") && it.accountNumber == destAccount }
val isDestMyCard = allAccounts.any { (it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT") && it.accountNumber == destAccount }
val (transferType, creditAccount, bank) = when {
isSrcCard -> {
// CAD: card → own BML account
@@ -869,7 +870,7 @@ class TransferFragment : Fragment() {
}
isDestMyCard -> {
// CPA: BML CASA → own card top-up
val card = allAccounts.first { (it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT") && it.accountNumber == destAccount }
val card = allAccounts.first { (it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT") && it.accountNumber == destAccount }
Triple("CPA", card.internalId.ifBlank { destAccount }, null as String?)
}
isDestMib && currency == "MVR" -> Triple("DOT", destAccount, "MIB")
@@ -950,7 +951,7 @@ class TransferFragment : Fragment() {
return
}
val isDestMyCard = allAccounts.any {
(it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT") && it.accountNumber == destAccount
(it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT") && it.accountNumber == destAccount
}
val (transferType, creditAccount, bank) = when {
isSrcCard -> {
@@ -959,7 +960,7 @@ class TransferFragment : Fragment() {
}
isDestMyCard -> {
val card = allAccounts.first {
(it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT") && it.accountNumber == destAccount
(it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT") && it.accountNumber == destAccount
}
Triple("CPA", card.internalId.ifBlank { destAccount }, null as String?)
}
@@ -1337,8 +1338,8 @@ class TransferFragment : Fragment() {
) : BaseAdapter(), Filterable {
private val items: List<Any> = buildList {
val regular = accounts.filter { it.profileType != "BML_PREPAID" && it.profileType != "BML_CREDIT" && it.profileType != "BML_LOAN" }
val cards = accounts.filter { it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" }
val regular = accounts.filter { it.profileType != "BML_PREPAID" && it.profileType != "BML_CREDIT" && it.profileType != "BML_DEBIT" && it.profileType != "BML_LOAN" }
val cards = accounts.filter { it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT" }
addAll(regular)
if (cards.isNotEmpty()) {
add(getString(R.string.cards))
@@ -1347,7 +1348,7 @@ class TransferFragment : Fragment() {
}
fun getAccount(position: Int): BankAccount? = (items.getOrNull(position) as? BankAccount)
?.takeUnless { (it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT") && !it.statusDesc.equals("Active", ignoreCase = true) }
?.takeUnless { (it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT") && !it.statusDesc.equals("Active", ignoreCase = true) }
override fun getCount() = items.size
override fun getItem(position: Int) = items[position]
@@ -1378,7 +1379,7 @@ class TransferFragment : Fragment() {
ItemAccountDropdownBinding.inflate(LayoutInflater.from(context), parent, false)
.also { it.root.tag = it }
}
val inactive = (acc.profileType == "BML_PREPAID" || acc.profileType == "BML_CREDIT") && !acc.statusDesc.equals("Active", ignoreCase = true)
val inactive = (acc.profileType == "BML_PREPAID" || acc.profileType == "BML_CREDIT" || acc.profileType == "BML_DEBIT") && !acc.statusDesc.equals("Active", ignoreCase = true)
val isBmlAccount = acc.bank == "BML"
val ownerPrefix = if (isBmlAccount && acc.profileName.isNotBlank()) "${acc.profileName} · " else ""
b.tvDropdownAccountName.text = "$ownerPrefix${acc.accountBriefName}"

View File

@@ -64,7 +64,7 @@ class TransferHistoryFragment : Fragment() {
) {
fun hasMore(): Boolean = when {
account.bank == "FAHIPAY" -> fahipayTotal < 0 || fahipayNextStart < fahipayTotal
account.profileType == "BML_PREPAID" || account.profileType == "BML_CREDIT" -> cardMonthOffset < 2
account.profileType == "BML_PREPAID" || account.profileType == "BML_CREDIT" || account.profileType == "BML_DEBIT" -> cardMonthOffset < 2
account.bank == "BML" -> bmlTotalPages < 0 || bmlNextPage <= bmlTotalPages
else -> mibTotalCount < 0 || mibNextStart <= mibTotalCount
}
@@ -187,7 +187,7 @@ class TransferHistoryFragment : Fragment() {
async {
try {
when {
state.account.profileType == "BML_PREPAID" || state.account.profileType == "BML_CREDIT" -> {
state.account.profileType == "BML_PREPAID" || state.account.profileType == "BML_CREDIT" || state.account.profileType == "BML_DEBIT" -> {
val session = app.bmlSessionFor(state.account) ?: return@async emptyList()
val cal = Calendar.getInstance()
cal.add(Calendar.MONTH, -state.cardMonthOffset)

View File

@@ -21,7 +21,7 @@ import java.util.Locale
class HistoryFetcher(private val account: BankAccount) {
private val isMib get() = account.bank == "MIB"
private val isBmlCard get() = account.profileType == "BML_PREPAID" || account.profileType == "BML_CREDIT"
private val isBmlCard get() = account.profileType == "BML_PREPAID" || account.profileType == "BML_CREDIT" || account.profileType == "BML_DEBIT"
private val isBmlLoan get() = account.profileType == "BML_LOAN"
private val isFahipay get() = account.bank == "FAHIPAY"

View File

@@ -0,0 +1,45 @@
package sh.sar.basedbank.util.bmlapi
import sh.sar.basedbank.api.models.BankAccount
object BmlCardParser {
/**
* Returns the asset path for the card image.
* The product code is stored in [BankAccount.cifType] for BML Card accounts.
*/
fun cardImageAsset(account: BankAccount): String =
productCodeToAsset(account.cifType)
fun productCodeToAsset(productCode: String): String = when (productCode) {
"C8201" -> "cards/bml/master_prepaid.png"
"C8205" -> "cards/bml/master_prepaid_travel.png"
"C3007" -> "cards/bml/amex_debit_green.png"
"C1007" -> "cards/bml/visa_debit.png"
"C1003" -> "cards/bml/visa_gold.png"
"C8022" -> "cards/bml/master_gold.png"
"C1020" -> "cards/bml/visa_debit_platinum.png"
"C8902" -> "cards/bml/master_islamic.png"
"C8101" -> "cards/bml/master_masveriyaa.png"
// "?????" -> "cards/bml/amex_credit_gold.png"
// "?????" -> "cards/bml/amex_credit_green.png"
// "?????" -> "cards/bml/amex_debit_gold.png"
// "?????" -> "cards/bml/amex_platinum.png"
// "?????" -> "cards/bml/master.png"
// "?????" -> "cards/bml/master_business_debit.png"
// "?????" -> "cards/bml/master_odiveriyaa.png"
// "?????" -> "cards/bml/master_passport.png"
// "?????" -> "cards/bml/master_platinum.png"
// "?????" -> "cards/bml/master_prepaid_business.png"
// "?????" -> "cards/bml/master_world.png"
// "?????" -> "cards/bml/visa_corporate.png"
// "?????" -> "cards/bml/visa_credit.png"
// "?????" -> "cards/bml/visa_debit_generic.png"
// "?????" -> "cards/bml/visa_debit_islamic.png"
// "?????" -> "cards/bml/visa_infinite.png"
// "?????" -> "cards/bml/visa_platinum.png"
// "?????" -> "cards/bml/visa_student_black.png"
// "?????" -> "cards/bml/visa_student_blue.png"
else -> "cards/bml/defaultcard.png"
}
}

View File

@@ -12,7 +12,7 @@ object BmlDashboardParser {
*/
fun displayData(account: BankAccount): AccountListDisplay? {
if (account.profileType == "BML_LOAN") return null // Loans shown on financing page only
val isCard = account.profileType == "BML_PREPAID" || account.profileType == "BML_CREDIT"
val isCard = account.profileType == "BML_PREPAID" || account.profileType == "BML_CREDIT" || account.profileType == "BML_DEBIT"
return if (isCard) {
val isActive = account.statusDesc.equals("Active", ignoreCase = true)
AccountListDisplay(

View File

@@ -31,6 +31,21 @@
android:layout_gravity="bottom"
android:background="@drawable/bg_card_overlay_gradient"/>
<TextView
android:id="@+id/tvCardStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_margin="8dp"
android:paddingStart="6dp"
android:paddingEnd="6dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:textSize="9sp"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:visibility="gone"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@@ -32,6 +32,21 @@
android:layout_gravity="bottom"
android:background="@drawable/bg_card_overlay_gradient"/>
<TextView
android:id="@+id/tvCardStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_margin="10dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:textSize="10sp"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:visibility="gone"/>
<!-- Bottom-left: card owner name + masked number -->
<LinearLayout
android:layout_width="wrap_content"

View File

@@ -32,6 +32,21 @@
android:layout_gravity="bottom"
android:background="@drawable/bg_card_overlay_gradient"/>
<TextView
android:id="@+id/tvCardStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_margin="10dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:textSize="10sp"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:visibility="gone"/>
<!-- Bottom-left: card owner name + masked number -->
<LinearLayout
android:layout_width="wrap_content"