diff --git a/app/src/main/java/sh/sar/basedbank/api/bml/BmlLoginFlow.kt b/app/src/main/java/sh/sar/basedbank/api/bml/BmlLoginFlow.kt index 6c5fe00..4bfc7dc 100644 --- a/app/src/main/java/sh/sar/basedbank/api/bml/BmlLoginFlow.kt +++ b/app/src/main/java/sh/sar/basedbank/api/bml/BmlLoginFlow.kt @@ -187,7 +187,6 @@ class BmlLoginFlow { val dashboard = root.optJSONObject("payload")?.optJSONArray("dashboard") ?: return emptyList() val casaAccounts = mutableListOf() - val seenPrepaid = mutableSetOf() val prepaidCards = mutableListOf() for (i in 0 until dashboard.length()) { @@ -201,7 +200,7 @@ class BmlLoginFlow { if (accountType == "CASA") { val available = item.optDouble("availableBalance", 0.0) casaAccounts.add(MibAccount( - profileName = "Bank of Maldives", + profileName = "Personal", profileType = "BML", accountNumber = accountNumber, accountBriefName = item.optString("alias"), @@ -217,27 +216,22 @@ class BmlLoginFlow { } 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 - )) - } + val cardBalance = item.optJSONObject("cardBalance") + val available = cardBalance?.optDouble("AvailableLimit", 0.0) ?: 0.0 + prepaidCards.add(MibAccount( + profileName = "Personal", + 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 } diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/AccountsAdapter.kt b/app/src/main/java/sh/sar/basedbank/ui/home/AccountsAdapter.kt index 7562eac..07b0393 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/AccountsAdapter.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/AccountsAdapter.kt @@ -1,10 +1,14 @@ package sh.sar.basedbank.ui.home +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context import android.graphics.Color import android.graphics.drawable.GradientDrawable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.recyclerview.widget.RecyclerView import sh.sar.basedbank.api.mib.MibAccount import sh.sar.basedbank.databinding.ItemAccountBinding @@ -15,7 +19,7 @@ class AccountsAdapter(accounts: List) : RecyclerView.Adapter() { private sealed class Item { - data class Header(val profileName: String, val profileType: String) : Item() + data class SectionTitle(val label: String, val chip: String) : Item() data class Account(val account: MibAccount) : Item() data class Card(val account: MibAccount) : Item() } @@ -29,30 +33,29 @@ class AccountsAdapter(accounts: List) : } private fun buildItems(accounts: List): List = buildList { - var lastProfile = "" - for (account in accounts) { - if (account.profileName != lastProfile) { - add(Item.Header(account.profileName, account.profileType)) - lastProfile = account.profileName - } - if (account.profileType == "BML_PREPAID") { - add(Item.Card(account)) - } else { - add(Item.Account(account)) - } + val regular = accounts.filter { it.profileType != "BML_PREPAID" } + val prepaid = accounts.filter { it.profileType == "BML_PREPAID" } + + if (regular.isNotEmpty()) { + add(Item.SectionTitle("Accounts", "")) + regular.forEach { add(Item.Account(it)) } + } + if (prepaid.isNotEmpty()) { + add(Item.SectionTitle("Cards", "BML")) + prepaid.forEach { add(Item.Card(it)) } } } override fun getItemViewType(position: Int) = when (items[position]) { - is Item.Header -> TYPE_HEADER - is Item.Account -> TYPE_ACCOUNT - is Item.Card -> TYPE_CARD + is Item.SectionTitle -> TYPE_HEADER + is Item.Account -> TYPE_ACCOUNT + is Item.Card -> TYPE_CARD } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { val inflater = LayoutInflater.from(parent.context) return when (viewType) { - TYPE_HEADER -> HeaderViewHolder(ItemProfileHeaderBinding.inflate(inflater, parent, false)) + TYPE_HEADER -> SectionViewHolder(ItemProfileHeaderBinding.inflate(inflater, parent, false)) TYPE_CARD -> CardViewHolder(ItemCardBinding.inflate(inflater, parent, false)) else -> AccountViewHolder(ItemAccountBinding.inflate(inflater, parent, false)) } @@ -60,23 +63,23 @@ class AccountsAdapter(accounts: List) : override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (val item = items[position]) { - is Item.Header -> (holder as HeaderViewHolder).bind(item) - is Item.Account -> (holder as AccountViewHolder).bind(item.account) - is Item.Card -> (holder as CardViewHolder).bind(item.account) + is Item.SectionTitle -> (holder as SectionViewHolder).bind(item) + is Item.Account -> (holder as AccountViewHolder).bind(item.account) + is Item.Card -> (holder as CardViewHolder).bind(item.account) } } override fun getItemCount() = items.size - private inner class HeaderViewHolder(private val binding: ItemProfileHeaderBinding) : + private inner class SectionViewHolder(private val binding: ItemProfileHeaderBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(item: Item.Header) { - binding.tvProfileName.text = item.profileName - binding.tvProfileType.text = when (item.profileType) { - "BML" -> "Bank of Maldives" - "BML_PREPAID" -> "BML" - "0" -> "Personal" - else -> "Business" + fun bind(item: Item.SectionTitle) { + binding.tvProfileName.text = item.label + if (item.chip.isNotEmpty()) { + binding.tvProfileType.text = item.chip + binding.tvProfileType.visibility = View.VISIBLE + } else { + binding.tvProfileType.visibility = View.GONE } } } @@ -84,11 +87,20 @@ class AccountsAdapter(accounts: List) : private inner class AccountViewHolder(private val binding: ItemAccountBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(account: MibAccount) { - binding.tvAccountName.text = account.accountBriefName + binding.tvAccountName.text = account.accountBriefName binding.tvAccountNumber.text = account.accountNumber + binding.tvPillBank.text = if (account.profileType.startsWith("BML")) "BML" else "MIB" + binding.tvPillType.text = friendlyAccountType(account.accountTypeName) + binding.tvPillProfile.text = when (account.profileType) { + "0" -> "Personal" + "1" -> "Business" + else -> account.profileName + } binding.tvBalance.text = "${account.currencyName} ${account.availableBalance}" - binding.tvAccountType.text = account.accountTypeName - binding.tvStatus.text = account.statusDesc + binding.root.setOnLongClickListener { + copyToClipboard(it.context, account.accountNumber) + true + } } } @@ -97,24 +109,25 @@ class AccountsAdapter(accounts: List) : 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 { + binding.tvCardBrand.background = GradientDrawable().apply { shape = GradientDrawable.RECTANGLE cornerRadius = 100f - setColor(Color.parseColor(colorHex)) + setColor(Color.parseColor(brand.color)) + } + binding.tvCardName.text = account.accountBriefName + binding.tvCardNumber.text = account.accountNumber + binding.layoutCardBalance.visibility = View.VISIBLE + binding.tvCardBalance.text = "${account.currencyName} ${account.availableBalance}" + + val isActive = account.statusDesc.equals("Active", ignoreCase = true) + if (isActive) { + binding.tvCardStatus.visibility = View.GONE + binding.root.alpha = 1f + } else { + binding.tvCardStatus.text = account.statusDesc + binding.tvCardStatus.visibility = View.VISIBLE + binding.root.alpha = 0.45f } - binding.tvCardBrand.background = drawable } } @@ -123,6 +136,27 @@ class AccountsAdapter(accounts: List) : private const val TYPE_ACCOUNT = 1 private const val TYPE_CARD = 2 + private fun copyToClipboard(context: Context, accountNumber: String) { + val cm = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + cm.setPrimaryClip(ClipData.newPlainText("Account Number", accountNumber)) + Toast.makeText(context, "Account number copied", Toast.LENGTH_SHORT).show() + } + + private fun friendlyAccountType(raw: String): String { + val u = raw.trim().uppercase() + return when { + u == "SAVINGS ACCOUNT" || + u == "SAVING ACCOUNT" -> "Savings" + u == "CURRENT ACCOUNT" || + u == "CURRENT ACCOUNT(PERSONAL)" || + u == "CURRENT ACCOUNT(BUSINESS)" -> "Current" + u == "WADIAH RETAIL CURRENT ACCOUNT" || + u == "WADIAH BUSINESS CURRENT ACCOUNT" -> "Islamic Current" + u == "BML ISLAMIC SAVINGS ACCOUNT" -> "Islamic Savings" + else -> raw.trim() + } + } + private data class Brand(val label: String, val color: String) private fun cardBrand(productName: String): Brand = when { diff --git a/app/src/main/res/drawable/pill_segment_bg.xml b/app/src/main/res/drawable/pill_segment_bg.xml new file mode 100644 index 0000000..879d45d --- /dev/null +++ b/app/src/main/res/drawable/pill_segment_bg.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/layout/item_account.xml b/app/src/main/res/layout/item_account.xml index 0d29a2e..cf4cd0e 100644 --- a/app/src/main/res/layout/item_account.xml +++ b/app/src/main/res/layout/item_account.xml @@ -13,92 +13,98 @@ + android:orientation="horizontal" + android:padding="20dp" + android:gravity="center_vertical"> + - - - - - - - - + android:layout_weight="1" + android:orientation="vertical"> + android:textAppearance="?attr/textAppearanceTitleMedium" + android:textColor="?attr/colorOnSurface" /> + + - - + + android:orientation="vertical" + android:gravity="end" + android:layout_marginStart="16dp"> + android:orientation="horizontal" + android:gravity="center_vertical" + android:background="@drawable/pill_segment_bg"> + android:textColor="?attr/colorOnSurface" /> + + + android:paddingHorizontal="10dp" + android:paddingVertical="6dp" + android:textAppearance="?attr/textAppearanceLabelSmall" + android:textColor="?attr/colorOnSurface" /> + + + + + android:textAppearance="?attr/textAppearanceTitleSmall" + android:textColor="?attr/colorOnSurface" + android:layout_marginTop="6dp" /> diff --git a/app/src/main/res/layout/item_card.xml b/app/src/main/res/layout/item_card.xml index 6e5cd09..754c7af 100644 --- a/app/src/main/res/layout/item_card.xml +++ b/app/src/main/res/layout/item_card.xml @@ -41,35 +41,40 @@ android:id="@+id/tvCardName" android:layout_width="match_parent" android:layout_height="wrap_content" - android:textAppearance="?attr/textAppearanceTitleSmall" + android:textAppearance="?attr/textAppearanceTitleMedium" android:textColor="?attr/colorOnSurface" /> - + + android:textColor="?attr/colorOnSurfaceVariant" + android:background="@drawable/pill_segment_bg" + android:visibility="gone" /> + android:layout_marginTop="6dp" />