compress mib cards and add prep support for bml cards
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 294 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
After Width: | Height: | Size: 227 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 390 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 197 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 302 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 295 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 242 KiB |
|
After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 378 KiB |
|
After Width: | Height: | Size: 208 KiB |
|
Before Width: | Height: | Size: 633 KiB |
|
After Width: | Height: | Size: 41 KiB |
@@ -166,16 +166,21 @@ class BmlAccountClient {
|
|||||||
internalId = internalId
|
internalId = internalId
|
||||||
))
|
))
|
||||||
} else if (accountType == "Card") {
|
} else if (accountType == "Card") {
|
||||||
val isVisible = item.optBoolean("account_visible", false)
|
|
||||||
if (!isVisible) continue
|
|
||||||
val isPrepaid = item.optBoolean("prepaid_card", false)
|
val isPrepaid = item.optBoolean("prepaid_card", false)
|
||||||
|
val productCode = item.optString("product_code", "")
|
||||||
val cardBalance = item.optJSONObject("cardBalance")
|
val cardBalance = item.optJSONObject("cardBalance")
|
||||||
val available = cardBalance?.optDouble("AvailableLimit", 0.0) ?: 0.0
|
val available = cardBalance?.optDouble("AvailableLimit", 0.0) ?: 0.0
|
||||||
val current = cardBalance?.optDouble("CurrentBalance", 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(
|
prepaidCards.add(BankAccount(
|
||||||
bank = "BML",
|
bank = "BML",
|
||||||
profileName = profileName,
|
profileName = profileName,
|
||||||
profileType = if (isPrepaid) "BML_PREPAID" else "BML_CREDIT",
|
profileType = cardProfileType,
|
||||||
|
cifType = productCode,
|
||||||
accountNumber = accountNumber,
|
accountNumber = accountNumber,
|
||||||
accountBriefName = item.optString("alias").ifBlank { product },
|
accountBriefName = item.optString("alias").ifBlank { product },
|
||||||
currencyName = currency,
|
currencyName = currency,
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import androidx.fragment.app.activityViewModels
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import sh.sar.basedbank.R
|
import sh.sar.basedbank.R
|
||||||
import sh.sar.basedbank.api.mib.MibCard
|
|
||||||
import sh.sar.basedbank.databinding.FragmentCardSettingsBinding
|
import sh.sar.basedbank.databinding.FragmentCardSettingsBinding
|
||||||
|
import sh.sar.basedbank.util.bmlapi.BmlCardParser
|
||||||
|
|
||||||
class CardSettingsFragment : Fragment() {
|
class CardSettingsFragment : Fragment() {
|
||||||
|
|
||||||
@@ -44,17 +44,23 @@ class CardSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.swipeRefresh.setOnRefreshListener {
|
binding.swipeRefresh.setOnRefreshListener {
|
||||||
(activity as? HomeActivity)?.triggerRefreshCards()
|
(activity as? HomeActivity)?.triggerRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.mibCards.observe(viewLifecycleOwner) { cards ->
|
val updateCardList = {
|
||||||
if (cards == null) return@observe
|
val mibItems = (viewModel.mibCards.value ?: emptyList()).map { CardItem.Mib(it) }
|
||||||
adapter.update(cards)
|
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.loadingView.visibility = View.GONE
|
||||||
binding.swipeRefresh.isRefreshing = false
|
binding.swipeRefresh.isRefreshing = false
|
||||||
binding.emptyView.visibility = if (cards.isEmpty()) View.VISIBLE else View.GONE
|
binding.emptyView.visibility = if (all.isEmpty()) View.VISIBLE else View.GONE
|
||||||
binding.recyclerView.visibility = if (cards.isEmpty()) View.GONE else View.VISIBLE
|
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) {
|
if (viewModel.mibCards.value == null) {
|
||||||
binding.loadingView.visibility = View.VISIBLE
|
binding.loadingView.visibility = View.VISIBLE
|
||||||
@@ -73,11 +79,11 @@ class CardSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class CardSettingsAdapter(
|
private inner class CardSettingsAdapter(
|
||||||
private var cards: List<MibCard>,
|
private var cards: List<CardItem>,
|
||||||
private val context: Context
|
private val context: Context
|
||||||
) : RecyclerView.Adapter<CardSettingsAdapter.VH>() {
|
) : RecyclerView.Adapter<CardSettingsAdapter.VH>() {
|
||||||
|
|
||||||
fun update(newCards: List<MibCard>) {
|
fun update(newCards: List<CardItem>) {
|
||||||
cards = newCards
|
cards = newCards
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
@@ -93,17 +99,34 @@ class CardSettingsFragment : Fragment() {
|
|||||||
private val tvCardOwner: TextView = view.findViewById(R.id.tvCardOwner)
|
private val tvCardOwner: TextView = view.findViewById(R.id.tvCardOwner)
|
||||||
private val tvCardNumber: TextView = view.findViewById(R.id.tvCardNumber)
|
private val tvCardNumber: TextView = view.findViewById(R.id.tvCardNumber)
|
||||||
private val tvCardType: TextView = view.findViewById(R.id.tvCardType)
|
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 btnChangePin: View = view.findViewById(R.id.btnChangePin)
|
||||||
private val btnFreeze: View = view.findViewById(R.id.btnFreeze)
|
private val btnFreeze: View = view.findViewById(R.id.btnFreeze)
|
||||||
private val btnBlock: View = view.findViewById(R.id.btnBlock)
|
private val btnBlock: View = view.findViewById(R.id.btnBlock)
|
||||||
|
|
||||||
fun bind(card: MibCard) {
|
fun bind(item: CardItem) {
|
||||||
tvCardOwner.text = card.cardHolderName
|
when (item) {
|
||||||
tvCardNumber.text = PayWithCardFragment.formatMasked(card.maskedCardNumber)
|
is CardItem.Mib -> {
|
||||||
tvCardType.text = card.cardTypeDesc
|
tvCardOwner.text = item.card.cardHolderName
|
||||||
val assetPath = PayWithCardFragment.cardImageAsset(card)
|
tvCardNumber.text = PayWithCardFragment.formatMasked(item.card.maskedCardNumber)
|
||||||
if (assetPath != null) PayWithCardFragment.loadCardImage(ivCardImage, assetPath)
|
tvCardType.text = item.card.cardTypeDesc
|
||||||
else ivCardImage.setImageDrawable(null)
|
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 {
|
val wip = View.OnClickListener {
|
||||||
Toast.makeText(context, R.string.work_in_progress, Toast.LENGTH_SHORT).show()
|
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 fromAccount = accounts.find { it.accountNumber == fromAccountNumber }
|
||||||
val fromCurrency = fromAccount?.currencyName ?: ""
|
val fromCurrency = fromAccount?.currencyName ?: ""
|
||||||
val fromLoginTag = fromAccount?.loginTag ?: ""
|
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) {
|
if (tabTag == MY_ACCOUNTS_TAG) {
|
||||||
val regularAccounts = 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" }
|
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 {
|
val filteredRegular = if (search.isBlank()) regularAccounts else regularAccounts.filter {
|
||||||
it.accountBriefName.contains(search, ignoreCase = true) || it.accountNumber.contains(search)
|
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.models.BankAccount
|
||||||
import sh.sar.basedbank.api.mib.MibCard
|
import sh.sar.basedbank.api.mib.MibCard
|
||||||
import sh.sar.basedbank.api.mib.MibFinanceDeal
|
import sh.sar.basedbank.api.mib.MibFinanceDeal
|
||||||
|
import sh.sar.basedbank.util.bmlapi.BmlCardParser
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import sh.sar.basedbank.databinding.FragmentDashboardBinding
|
import sh.sar.basedbank.databinding.FragmentDashboardBinding
|
||||||
import sh.sar.basedbank.databinding.ItemForeignLimitBinding
|
import sh.sar.basedbank.databinding.ItemForeignLimitBinding
|
||||||
@@ -57,11 +58,17 @@ class DashboardFragment : Fragment() {
|
|||||||
binding.rvCards.adapter = cardAdapter
|
binding.rvCards.adapter = cardAdapter
|
||||||
LinearSnapHelper().attachToRecyclerView(binding.rvCards)
|
LinearSnapHelper().attachToRecyclerView(binding.rvCards)
|
||||||
|
|
||||||
viewModel.mibCards.observe(viewLifecycleOwner) { cards ->
|
val updateCardList = {
|
||||||
if (cards.isNullOrEmpty()) return@observe
|
val mibItems = (viewModel.mibCards.value ?: emptyList()).map { CardItem.Mib(it) }
|
||||||
cardAdapter.update(cards)
|
val bmlItems = (viewModel.accounts.value ?: emptyList())
|
||||||
binding.sectionCards.visibility = View.VISIBLE
|
.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()
|
val bottomPaddingBase = (16 * resources.displayMetrics.density).toInt()
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(binding.buttonBar) { v, insets ->
|
ViewCompat.setOnApplyWindowInsetsListener(binding.buttonBar) { v, insets ->
|
||||||
@@ -229,9 +236,9 @@ class DashboardFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class DashboardCardAdapter : RecyclerView.Adapter<DashboardCardAdapter.VH>() {
|
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
|
cards = newCards
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
@@ -249,15 +256,27 @@ class DashboardFragment : Fragment() {
|
|||||||
private val ivCardImage: ImageView = view.findViewById(R.id.ivCardImage)
|
private val ivCardImage: ImageView = view.findViewById(R.id.ivCardImage)
|
||||||
private val tvCardOwner: TextView = view.findViewById(R.id.tvCardOwner)
|
private val tvCardOwner: TextView = view.findViewById(R.id.tvCardOwner)
|
||||||
private val tvCardNumber: TextView = view.findViewById(R.id.tvCardNumber)
|
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 btnPayQr: View = view.findViewById(R.id.btnPayQr)
|
||||||
private val btnPayNfc: View = view.findViewById(R.id.btnPayNfc)
|
private val btnPayNfc: View = view.findViewById(R.id.btnPayNfc)
|
||||||
|
|
||||||
fun bind(card: MibCard) {
|
fun bind(item: CardItem) {
|
||||||
tvCardOwner.text = card.cardHolderName
|
when (item) {
|
||||||
tvCardNumber.text = PayWithCardFragment.formatMasked(card.maskedCardNumber)
|
is CardItem.Mib -> {
|
||||||
val assetPath = PayWithCardFragment.cardImageAsset(card)
|
tvCardOwner.text = item.card.cardHolderName
|
||||||
if (assetPath != null) PayWithCardFragment.loadCardImage(ivCardImage, assetPath)
|
tvCardNumber.text = PayWithCardFragment.formatMasked(item.card.maskedCardNumber)
|
||||||
else ivCardImage.setImageDrawable(null)
|
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 {
|
btnPayQr.setOnClickListener {
|
||||||
Toast.makeText(requireContext(), R.string.work_in_progress, Toast.LENGTH_SHORT).show()
|
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.MibCard
|
||||||
import sh.sar.basedbank.api.mib.MibFinanceDeal
|
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() {
|
class HomeViewModel : ViewModel() {
|
||||||
val accounts = MutableLiveData<List<BankAccount>>(emptyList())
|
val accounts = MutableLiveData<List<BankAccount>>(emptyList())
|
||||||
val financing = MutableLiveData<List<MibFinanceDeal>>(emptyList())
|
val financing = MutableLiveData<List<MibFinanceDeal>>(emptyList())
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class PayMvQrFragment : Fragment() {
|
|||||||
private fun setupDropdown() {
|
private fun setupDropdown() {
|
||||||
viewModel.accounts.observe(viewLifecycleOwner) { accounts ->
|
viewModel.accounts.observe(viewLifecycleOwner) { accounts ->
|
||||||
val eligible = accounts.filter {
|
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)
|
val adapter = QrAccountAdapter(requireContext(), eligible)
|
||||||
binding.actvAccount.setAdapter(adapter)
|
binding.actvAccount.setAdapter(adapter)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package sh.sar.basedbank.ui.home
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.drawable.GradientDrawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -16,9 +17,11 @@ import androidx.fragment.app.activityViewModels
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import sh.sar.basedbank.R
|
import sh.sar.basedbank.R
|
||||||
|
import sh.sar.basedbank.api.models.BankAccount
|
||||||
import sh.sar.basedbank.api.mib.MibCard
|
import sh.sar.basedbank.api.mib.MibCard
|
||||||
import sh.sar.basedbank.databinding.FragmentPayWithCardBinding
|
import sh.sar.basedbank.databinding.FragmentPayWithCardBinding
|
||||||
import sh.sar.basedbank.util.CardsCache
|
import sh.sar.basedbank.util.CardsCache
|
||||||
|
import sh.sar.basedbank.util.bmlapi.BmlCardParser
|
||||||
|
|
||||||
class PayWithCardFragment : Fragment() {
|
class PayWithCardFragment : Fragment() {
|
||||||
|
|
||||||
@@ -46,17 +49,23 @@ class PayWithCardFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.swipeRefresh.setOnRefreshListener {
|
binding.swipeRefresh.setOnRefreshListener {
|
||||||
(activity as? HomeActivity)?.triggerRefreshCards()
|
(activity as? HomeActivity)?.triggerRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.mibCards.observe(viewLifecycleOwner) { cards ->
|
val updateCardList = {
|
||||||
if (cards == null) return@observe
|
val mibItems = (viewModel.mibCards.value ?: emptyList()).map { CardItem.Mib(it) }
|
||||||
adapter.update(cards)
|
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.loadingView.visibility = View.GONE
|
||||||
binding.swipeRefresh.isRefreshing = false
|
binding.swipeRefresh.isRefreshing = false
|
||||||
binding.emptyView.visibility = if (cards.isEmpty()) View.VISIBLE else View.GONE
|
binding.emptyView.visibility = if (all.isEmpty()) View.VISIBLE else View.GONE
|
||||||
binding.recyclerView.visibility = if (cards.isEmpty()) View.GONE else View.VISIBLE
|
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())
|
val cached = CardsCache.load(requireContext())
|
||||||
if (cached.isNotEmpty()) {
|
if (cached.isNotEmpty()) {
|
||||||
@@ -78,11 +87,11 @@ class PayWithCardFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class CardWalletAdapter(
|
private inner class CardWalletAdapter(
|
||||||
private var cards: List<MibCard>,
|
private var cards: List<CardItem>,
|
||||||
private val context: Context
|
private val context: Context
|
||||||
) : RecyclerView.Adapter<CardWalletAdapter.VH>() {
|
) : RecyclerView.Adapter<CardWalletAdapter.VH>() {
|
||||||
|
|
||||||
fun update(newCards: List<MibCard>) {
|
fun update(newCards: List<CardItem>) {
|
||||||
cards = newCards
|
cards = newCards
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
@@ -98,16 +107,30 @@ class PayWithCardFragment : Fragment() {
|
|||||||
private val tvCardOwner: TextView = view.findViewById(R.id.tvCardOwner)
|
private val tvCardOwner: TextView = view.findViewById(R.id.tvCardOwner)
|
||||||
private val tvCardNumber: TextView = view.findViewById(R.id.tvCardNumber)
|
private val tvCardNumber: TextView = view.findViewById(R.id.tvCardNumber)
|
||||||
private val tvCardType: TextView = view.findViewById(R.id.tvCardType)
|
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 btnPayQr: View = view.findViewById(R.id.btnPayQr)
|
||||||
private val btnPayNfc: View = view.findViewById(R.id.btnPayNfc)
|
private val btnPayNfc: View = view.findViewById(R.id.btnPayNfc)
|
||||||
|
|
||||||
fun bind(card: MibCard) {
|
fun bind(item: CardItem) {
|
||||||
tvCardOwner.text = card.cardHolderName
|
when (item) {
|
||||||
tvCardNumber.text = formatMasked(card.maskedCardNumber)
|
is CardItem.Mib -> {
|
||||||
tvCardType.text = card.cardTypeDesc
|
tvCardOwner.text = item.card.cardHolderName
|
||||||
val assetPath = cardImageAsset(card)
|
tvCardNumber.text = formatMasked(item.card.maskedCardNumber)
|
||||||
if (assetPath != null) loadCardImage(ivCardImage, assetPath)
|
tvCardType.text = item.card.cardTypeDesc
|
||||||
else ivCardImage.setImageDrawable(null)
|
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 {
|
btnPayQr.setOnClickListener {
|
||||||
Toast.makeText(context, R.string.work_in_progress, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, R.string.work_in_progress, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
@@ -127,9 +150,9 @@ class PayWithCardFragment : Fragment() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun cardImageAsset(card: MibCard): String? = when (card.cardType) {
|
fun cardImageAsset(card: MibCard): String? = when (card.cardType) {
|
||||||
"53" -> "cards/mib/visa_black_platinum.jpg"
|
"53" -> "cards/mib/visa_black_platinum.png"
|
||||||
"57" -> "cards/mib/visa_blue_everyday.jpg"
|
"57" -> "cards/mib/visa_blue_everyday.png"
|
||||||
"70" -> "cards/mib/visa_business.jpg"
|
"70" -> "cards/mib/visa_business.png"
|
||||||
else -> null
|
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 {
|
fun formatMasked(masked: String): String {
|
||||||
if (masked.length < 4) return masked
|
if (masked.length < 4) return masked
|
||||||
return "\u2022\u2022\u2022\u2022 ${masked.takeLast(4)}"
|
return "\u2022\u2022\u2022\u2022 ${masked.takeLast(4)}"
|
||||||
|
|||||||
@@ -283,6 +283,7 @@ class TransferFragment : Fragment() {
|
|||||||
val typeLabel = when {
|
val typeLabel = when {
|
||||||
account.profileType == "BML_PREPAID" -> "Prepaid Card"
|
account.profileType == "BML_PREPAID" -> "Prepaid Card"
|
||||||
account.profileType == "BML_CREDIT" -> "Credit Card"
|
account.profileType == "BML_CREDIT" -> "Credit Card"
|
||||||
|
account.profileType == "BML_DEBIT" -> "Debit Card"
|
||||||
account.accountTypeName.isNotBlank() -> account.accountTypeName
|
account.accountTypeName.isNotBlank() -> account.accountTypeName
|
||||||
else -> account.profileType
|
else -> account.profileType
|
||||||
}
|
}
|
||||||
@@ -632,7 +633,7 @@ class TransferFragment : Fragment() {
|
|||||||
|
|
||||||
val isSrcBml = src.bank == "BML"
|
val isSrcBml = src.bank == "BML"
|
||||||
val isBmlBusiness = isSrcBml && isBusinessProfile(src) // to test on personal accounts: use `isSrcBml`
|
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 isDestMib = AccountInputParser.detect(resolvedAccountNumber) == AccountInputParser.InputType.MIB_ACCOUNT
|
||||||
val currency = src.currencyName.ifBlank { "MVR" }
|
val currency = src.currencyName.ifBlank { "MVR" }
|
||||||
val allAccounts = viewModel.accounts.value ?: emptyList()
|
val allAccounts = viewModel.accounts.value ?: emptyList()
|
||||||
@@ -860,7 +861,7 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine type + credit account
|
// 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 {
|
val (transferType, creditAccount, bank) = when {
|
||||||
isSrcCard -> {
|
isSrcCard -> {
|
||||||
// CAD: card → own BML account
|
// CAD: card → own BML account
|
||||||
@@ -869,7 +870,7 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
isDestMyCard -> {
|
isDestMyCard -> {
|
||||||
// CPA: BML CASA → own card top-up
|
// 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?)
|
Triple("CPA", card.internalId.ifBlank { destAccount }, null as String?)
|
||||||
}
|
}
|
||||||
isDestMib && currency == "MVR" -> Triple("DOT", destAccount, "MIB")
|
isDestMib && currency == "MVR" -> Triple("DOT", destAccount, "MIB")
|
||||||
@@ -950,7 +951,7 @@ class TransferFragment : Fragment() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
val isDestMyCard = allAccounts.any {
|
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 {
|
val (transferType, creditAccount, bank) = when {
|
||||||
isSrcCard -> {
|
isSrcCard -> {
|
||||||
@@ -959,7 +960,7 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
isDestMyCard -> {
|
isDestMyCard -> {
|
||||||
val card = allAccounts.first {
|
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?)
|
Triple("CPA", card.internalId.ifBlank { destAccount }, null as String?)
|
||||||
}
|
}
|
||||||
@@ -1337,8 +1338,8 @@ class TransferFragment : Fragment() {
|
|||||||
) : BaseAdapter(), Filterable {
|
) : BaseAdapter(), Filterable {
|
||||||
|
|
||||||
private val items: List<Any> = buildList {
|
private val items: List<Any> = buildList {
|
||||||
val regular = accounts.filter { it.profileType != "BML_PREPAID" && it.profileType != "BML_CREDIT" && it.profileType != "BML_LOAN" }
|
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" }
|
val cards = accounts.filter { it.profileType == "BML_PREPAID" || it.profileType == "BML_CREDIT" || it.profileType == "BML_DEBIT" }
|
||||||
addAll(regular)
|
addAll(regular)
|
||||||
if (cards.isNotEmpty()) {
|
if (cards.isNotEmpty()) {
|
||||||
add(getString(R.string.cards))
|
add(getString(R.string.cards))
|
||||||
@@ -1347,7 +1348,7 @@ class TransferFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getAccount(position: Int): BankAccount? = (items.getOrNull(position) as? BankAccount)
|
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 getCount() = items.size
|
||||||
override fun getItem(position: Int) = items[position]
|
override fun getItem(position: Int) = items[position]
|
||||||
@@ -1378,7 +1379,7 @@ class TransferFragment : Fragment() {
|
|||||||
ItemAccountDropdownBinding.inflate(LayoutInflater.from(context), parent, false)
|
ItemAccountDropdownBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||||
.also { it.root.tag = it }
|
.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 isBmlAccount = acc.bank == "BML"
|
||||||
val ownerPrefix = if (isBmlAccount && acc.profileName.isNotBlank()) "${acc.profileName} · " else ""
|
val ownerPrefix = if (isBmlAccount && acc.profileName.isNotBlank()) "${acc.profileName} · " else ""
|
||||||
b.tvDropdownAccountName.text = "$ownerPrefix${acc.accountBriefName}"
|
b.tvDropdownAccountName.text = "$ownerPrefix${acc.accountBriefName}"
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class TransferHistoryFragment : Fragment() {
|
|||||||
) {
|
) {
|
||||||
fun hasMore(): Boolean = when {
|
fun hasMore(): Boolean = when {
|
||||||
account.bank == "FAHIPAY" -> fahipayTotal < 0 || fahipayNextStart < fahipayTotal
|
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
|
account.bank == "BML" -> bmlTotalPages < 0 || bmlNextPage <= bmlTotalPages
|
||||||
else -> mibTotalCount < 0 || mibNextStart <= mibTotalCount
|
else -> mibTotalCount < 0 || mibNextStart <= mibTotalCount
|
||||||
}
|
}
|
||||||
@@ -187,7 +187,7 @@ class TransferHistoryFragment : Fragment() {
|
|||||||
async {
|
async {
|
||||||
try {
|
try {
|
||||||
when {
|
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 session = app.bmlSessionFor(state.account) ?: return@async emptyList()
|
||||||
val cal = Calendar.getInstance()
|
val cal = Calendar.getInstance()
|
||||||
cal.add(Calendar.MONTH, -state.cardMonthOffset)
|
cal.add(Calendar.MONTH, -state.cardMonthOffset)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import java.util.Locale
|
|||||||
class HistoryFetcher(private val account: BankAccount) {
|
class HistoryFetcher(private val account: BankAccount) {
|
||||||
|
|
||||||
private val isMib get() = account.bank == "MIB"
|
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 isBmlLoan get() = account.profileType == "BML_LOAN"
|
||||||
private val isFahipay get() = account.bank == "FAHIPAY"
|
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? {
|
fun displayData(account: BankAccount): AccountListDisplay? {
|
||||||
if (account.profileType == "BML_LOAN") return null // Loans shown on financing page only
|
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) {
|
return if (isCard) {
|
||||||
val isActive = account.statusDesc.equals("Active", ignoreCase = true)
|
val isActive = account.statusDesc.equals("Active", ignoreCase = true)
|
||||||
AccountListDisplay(
|
AccountListDisplay(
|
||||||
|
|||||||
@@ -31,6 +31,21 @@
|
|||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_card_overlay_gradient"/>
|
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
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
@@ -32,6 +32,21 @@
|
|||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_card_overlay_gradient"/>
|
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 -->
|
<!-- Bottom-left: card owner name + masked number -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -32,6 +32,21 @@
|
|||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_card_overlay_gradient"/>
|
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 -->
|
<!-- Bottom-left: card owner name + masked number -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||