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
BIN
app/src/main/assets/cards/bml/amex_credit_gold.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
app/src/main/assets/cards/bml/amex_credit_green.png
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
app/src/main/assets/cards/bml/amex_debit_gold.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
app/src/main/assets/cards/bml/amex_debit_green.png
Normal file
|
After Width: | Height: | Size: 151 KiB |
BIN
app/src/main/assets/cards/bml/amex_platinum.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
app/src/main/assets/cards/bml/defaultcard.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
app/src/main/assets/cards/bml/master.png
Normal file
|
After Width: | Height: | Size: 294 KiB |
BIN
app/src/main/assets/cards/bml/master_business_debit.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
app/src/main/assets/cards/bml/master_gold.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
app/src/main/assets/cards/bml/master_islamic.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
app/src/main/assets/cards/bml/master_masveriyaa.png
Normal file
|
After Width: | Height: | Size: 332 KiB |
BIN
app/src/main/assets/cards/bml/master_odiveriyaa.png
Normal file
|
After Width: | Height: | Size: 390 KiB |
BIN
app/src/main/assets/cards/bml/master_passport.png
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
app/src/main/assets/cards/bml/master_platinum.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
app/src/main/assets/cards/bml/master_prepaid.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
app/src/main/assets/cards/bml/master_prepaid_business.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
app/src/main/assets/cards/bml/master_prepaid_travel.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
app/src/main/assets/cards/bml/master_world.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
app/src/main/assets/cards/bml/visa_corporate.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
app/src/main/assets/cards/bml/visa_credit.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
app/src/main/assets/cards/bml/visa_debit.png
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
app/src/main/assets/cards/bml/visa_debit_generic.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
app/src/main/assets/cards/bml/visa_debit_islamic.png
Normal file
|
After Width: | Height: | Size: 302 KiB |
BIN
app/src/main/assets/cards/bml/visa_debit_platinum.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
app/src/main/assets/cards/bml/visa_gold.png
Normal file
|
After Width: | Height: | Size: 295 KiB |
BIN
app/src/main/assets/cards/bml/visa_infinite.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/src/main/assets/cards/bml/visa_platinum.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
app/src/main/assets/cards/bml/visa_student_black.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
app/src/main/assets/cards/bml/visa_student_blue.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 242 KiB |
BIN
app/src/main/assets/cards/mib/visa_black_platinum.png
Normal file
|
After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 378 KiB |
BIN
app/src/main/assets/cards/mib/visa_blue_everyday.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
|
Before Width: | Height: | Size: 633 KiB |
BIN
app/src/main/assets/cards/mib/visa_business.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)}"
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||