forked from shihaam/thijooree
remove bml linked cards from account ui, trasfer drop down and added a cards section to show master cards
This commit is contained in:
@@ -185,25 +185,66 @@ class BmlLoginFlow {
|
|||||||
val root = JSONObject(json)
|
val root = JSONObject(json)
|
||||||
if (!root.optBoolean("success")) return emptyList()
|
if (!root.optBoolean("success")) return emptyList()
|
||||||
val dashboard = root.optJSONObject("payload")?.optJSONArray("dashboard") ?: return emptyList()
|
val dashboard = root.optJSONObject("payload")?.optJSONArray("dashboard") ?: return emptyList()
|
||||||
return (0 until dashboard.length()).map { i ->
|
|
||||||
|
val casaAccounts = mutableListOf<MibAccount>()
|
||||||
|
val seenPrepaid = mutableSetOf<String>()
|
||||||
|
val prepaidCards = mutableListOf<MibAccount>()
|
||||||
|
|
||||||
|
for (i in 0 until dashboard.length()) {
|
||||||
val item = dashboard.getJSONObject(i)
|
val item = dashboard.getJSONObject(i)
|
||||||
val currency = item.optString("currency", "MVR")
|
val currency = item.optString("currency", "MVR")
|
||||||
val available = item.optDouble("availableBalance", 0.0)
|
val accountType = item.optString("account_type", "CASA")
|
||||||
MibAccount(
|
val product = item.optString("product")
|
||||||
profileName = "Bank of Maldives",
|
val accountNumber = item.optString("account")
|
||||||
profileType = "BML",
|
val status = item.optString("account_status", "Active")
|
||||||
accountNumber = item.optString("account"),
|
|
||||||
accountBriefName = item.optString("alias"),
|
if (accountType == "CASA") {
|
||||||
currencyName = currency,
|
val available = item.optDouble("availableBalance", 0.0)
|
||||||
accountTypeName = item.optString("product"),
|
casaAccounts.add(MibAccount(
|
||||||
availableBalance = "%.2f".format(available),
|
profileName = "Bank of Maldives",
|
||||||
currentBalance = "%.2f".format(item.optDouble("ledgerBalance", 0.0)),
|
profileType = "BML",
|
||||||
blockedAmount = "%.2f".format(item.optDouble("lockedAmount", 0.0)),
|
accountNumber = accountNumber,
|
||||||
mvrBalance = if (currency == "MVR") "%.2f".format(available) else "0.00",
|
accountBriefName = item.optString("alias"),
|
||||||
statusDesc = item.optString("account_status", "Active"),
|
currencyName = currency,
|
||||||
profileImageHash = null
|
accountTypeName = product,
|
||||||
)
|
availableBalance = "%.2f".format(available),
|
||||||
|
currentBalance = "%.2f".format(item.optDouble("ledgerBalance", 0.0)),
|
||||||
|
blockedAmount = "%.2f".format(item.optDouble("lockedAmount", 0.0)),
|
||||||
|
mvrBalance = if (currency == "MVR") "%.2f".format(available) else "0.00",
|
||||||
|
statusDesc = status,
|
||||||
|
profileImageHash = null
|
||||||
|
))
|
||||||
|
} else if (accountType == "Card") {
|
||||||
|
val isPrepaid = item.optBoolean("prepaid_card", false)
|
||||||
|
if (isPrepaid) {
|
||||||
|
// Deduplicate by account number, prefer Active
|
||||||
|
if (!seenPrepaid.contains(accountNumber) || status == "Active") {
|
||||||
|
seenPrepaid.add(accountNumber)
|
||||||
|
prepaidCards.removeAll { it.accountNumber == accountNumber }
|
||||||
|
val cardBalance = item.optJSONObject("cardBalance")
|
||||||
|
val available = cardBalance?.optDouble("AvailableLimit", 0.0) ?: 0.0
|
||||||
|
prepaidCards.add(MibAccount(
|
||||||
|
profileName = "Cards",
|
||||||
|
profileType = "BML_PREPAID",
|
||||||
|
accountNumber = accountNumber,
|
||||||
|
accountBriefName = product,
|
||||||
|
currencyName = currency,
|
||||||
|
accountTypeName = product,
|
||||||
|
availableBalance = "%.2f".format(available),
|
||||||
|
currentBalance = "%.2f".format(cardBalance?.optDouble("CurrentBalance", 0.0) ?: 0.0),
|
||||||
|
blockedAmount = "0.00",
|
||||||
|
mvrBalance = if (currency == "MVR") "%.2f".format(available) else "0.00",
|
||||||
|
statusDesc = status,
|
||||||
|
profileImageHash = null
|
||||||
|
))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Linked debit cards have no independent balance or account link — skip
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return casaAccounts + prepaidCards
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseContacts(json: String): List<MibBeneficiary> {
|
private fun parseContacts(json: String): List<MibBeneficiary> {
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
package sh.sar.basedbank.ui.home
|
package sh.sar.basedbank.ui.home
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.GradientDrawable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import sh.sar.basedbank.api.mib.MibAccount
|
import sh.sar.basedbank.api.mib.MibAccount
|
||||||
import sh.sar.basedbank.databinding.ItemAccountBinding
|
import sh.sar.basedbank.databinding.ItemAccountBinding
|
||||||
|
import sh.sar.basedbank.databinding.ItemCardBinding
|
||||||
import sh.sar.basedbank.databinding.ItemProfileHeaderBinding
|
import sh.sar.basedbank.databinding.ItemProfileHeaderBinding
|
||||||
|
|
||||||
class AccountsAdapter(accounts: List<MibAccount>) :
|
class AccountsAdapter(accounts: List<MibAccount>) :
|
||||||
@@ -13,6 +17,7 @@ class AccountsAdapter(accounts: List<MibAccount>) :
|
|||||||
private sealed class Item {
|
private sealed class Item {
|
||||||
data class Header(val profileName: String, val profileType: String) : Item()
|
data class Header(val profileName: String, val profileType: String) : Item()
|
||||||
data class Account(val account: MibAccount) : Item()
|
data class Account(val account: MibAccount) : Item()
|
||||||
|
data class Card(val account: MibAccount) : Item()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val items: MutableList<Item> = buildItems(accounts).toMutableList()
|
private val items: MutableList<Item> = buildItems(accounts).toMutableList()
|
||||||
@@ -30,28 +35,34 @@ class AccountsAdapter(accounts: List<MibAccount>) :
|
|||||||
add(Item.Header(account.profileName, account.profileType))
|
add(Item.Header(account.profileName, account.profileType))
|
||||||
lastProfile = account.profileName
|
lastProfile = account.profileName
|
||||||
}
|
}
|
||||||
add(Item.Account(account))
|
if (account.profileType == "BML_PREPAID") {
|
||||||
|
add(Item.Card(account))
|
||||||
|
} else {
|
||||||
|
add(Item.Account(account))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int) = when (items[position]) {
|
override fun getItemViewType(position: Int) = when (items[position]) {
|
||||||
is Item.Header -> TYPE_HEADER
|
is Item.Header -> TYPE_HEADER
|
||||||
is Item.Account -> TYPE_ACCOUNT
|
is Item.Account -> TYPE_ACCOUNT
|
||||||
|
is Item.Card -> TYPE_CARD
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
return if (viewType == TYPE_HEADER) {
|
return when (viewType) {
|
||||||
HeaderViewHolder(ItemProfileHeaderBinding.inflate(inflater, parent, false))
|
TYPE_HEADER -> HeaderViewHolder(ItemProfileHeaderBinding.inflate(inflater, parent, false))
|
||||||
} else {
|
TYPE_CARD -> CardViewHolder(ItemCardBinding.inflate(inflater, parent, false))
|
||||||
AccountViewHolder(ItemAccountBinding.inflate(inflater, parent, false))
|
else -> AccountViewHolder(ItemAccountBinding.inflate(inflater, parent, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
when (val item = items[position]) {
|
when (val item = items[position]) {
|
||||||
is Item.Header -> (holder as HeaderViewHolder).bind(item)
|
is Item.Header -> (holder as HeaderViewHolder).bind(item)
|
||||||
is Item.Account -> (holder as AccountViewHolder).bind(item.account)
|
is Item.Account -> (holder as AccountViewHolder).bind(item.account)
|
||||||
|
is Item.Card -> (holder as CardViewHolder).bind(item.account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,9 +73,10 @@ class AccountsAdapter(accounts: List<MibAccount>) :
|
|||||||
fun bind(item: Item.Header) {
|
fun bind(item: Item.Header) {
|
||||||
binding.tvProfileName.text = item.profileName
|
binding.tvProfileName.text = item.profileName
|
||||||
binding.tvProfileType.text = when (item.profileType) {
|
binding.tvProfileType.text = when (item.profileType) {
|
||||||
"BML" -> "Bank of Maldives"
|
"BML" -> "Bank of Maldives"
|
||||||
"0" -> "Personal"
|
"BML_PREPAID" -> "BML"
|
||||||
else -> "Business"
|
"0" -> "Personal"
|
||||||
|
else -> "Business"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,8 +92,45 @@ class AccountsAdapter(accounts: List<MibAccount>) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inner class CardViewHolder(private val binding: ItemCardBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(account: MibAccount) {
|
||||||
|
val brand = cardBrand(account.accountTypeName)
|
||||||
|
binding.tvCardBrand.text = brand.label
|
||||||
|
setBrandBackground(brand.color)
|
||||||
|
binding.tvCardName.text = account.accountBriefName
|
||||||
|
binding.tvCardNumber.text = account.accountNumber
|
||||||
|
|
||||||
|
val isPrepaid = account.profileType == "BML_PREPAID"
|
||||||
|
binding.layoutCardBalance.visibility = if (isPrepaid) View.VISIBLE else View.GONE
|
||||||
|
if (isPrepaid) {
|
||||||
|
binding.tvCardBalance.text = "${account.currencyName} ${account.availableBalance}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setBrandBackground(colorHex: String) {
|
||||||
|
val drawable = GradientDrawable().apply {
|
||||||
|
shape = GradientDrawable.RECTANGLE
|
||||||
|
cornerRadius = 100f
|
||||||
|
setColor(Color.parseColor(colorHex))
|
||||||
|
}
|
||||||
|
binding.tvCardBrand.background = drawable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TYPE_HEADER = 0
|
private const val TYPE_HEADER = 0
|
||||||
private const val TYPE_ACCOUNT = 1
|
private const val TYPE_ACCOUNT = 1
|
||||||
|
private const val TYPE_CARD = 2
|
||||||
|
|
||||||
|
private data class Brand(val label: String, val color: String)
|
||||||
|
|
||||||
|
private fun cardBrand(productName: String): Brand = when {
|
||||||
|
productName.contains("AMEX", ignoreCase = true) ||
|
||||||
|
productName.contains("AMERICAN EXPRESS", ignoreCase = true) -> Brand("AMEX", "#016FD0")
|
||||||
|
productName.contains("VISA", ignoreCase = true) -> Brand("VISA", "#1A1F71")
|
||||||
|
productName.contains("MASTERCARD", ignoreCase = true) -> Brand("MC", "#FF5F00")
|
||||||
|
else -> Brand("CARD", "#555555")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardCornerRadius="16dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
|
app:strokeColor="?attr/colorOutlineVariant">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="20dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<!-- Brand chip -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvCardBrand"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="10dp"
|
||||||
|
android:paddingVertical="6dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:background="@drawable/chip_background" />
|
||||||
|
|
||||||
|
<!-- Card name + number -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvCardName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?attr/textAppearanceTitleSmall"
|
||||||
|
android:textColor="?attr/colorOnSurface" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvCardNumber"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||||
|
android:textColor="?attr/colorOnSurfaceVariant"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Balance (prepaid only) -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layoutCardBalance"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="end"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/available_balance"
|
||||||
|
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||||
|
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvCardBalance"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?attr/textAppearanceTitleSmall"
|
||||||
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:layout_marginTop="2dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
Reference in New Issue
Block a user