redeisgn accounts page
All checks were successful
Auto Tag on Version Change / check-version (push) Successful in 3s
All checks were successful
Auto Tag on Version Change / check-version (push) Successful in 3s
This commit is contained in:
@@ -34,6 +34,7 @@ class AccountHistoryAdapter(
|
||||
private val iconUrlCache = mutableMapOf<String, Bitmap>()
|
||||
var onImageNeeded: ((counterpartyName: String) -> Unit)? = null
|
||||
var onIconUrlNeeded: ((url: String) -> Unit)? = null
|
||||
var onTransferClick: ((MibAccount) -> Unit)? = null
|
||||
|
||||
fun updateImage(counterpartyName: String, bitmap: Bitmap) {
|
||||
imageCache[counterpartyName] = bitmap
|
||||
@@ -164,6 +165,7 @@ class AccountHistoryAdapter(
|
||||
} else {
|
||||
b.llHeaderBlocked.visibility = View.GONE
|
||||
}
|
||||
b.btnHeaderTransfer.setOnClickListener { onTransferClick?.invoke(acc) }
|
||||
}
|
||||
|
||||
private fun friendlyType(raw: String): String {
|
||||
|
||||
@@ -20,6 +20,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import sh.sar.basedbank.BasedBankApp
|
||||
import sh.sar.basedbank.R
|
||||
import sh.sar.basedbank.api.bml.BmlLoginFlow
|
||||
import sh.sar.basedbank.api.fahipay.FahipayLoginFlow
|
||||
import sh.sar.basedbank.api.mib.MibAccount
|
||||
@@ -82,6 +83,9 @@ class AccountHistoryFragment : Fragment() {
|
||||
adapter = AccountHistoryAdapter(account)
|
||||
adapter.onImageNeeded = { name -> loadContactImage(name) }
|
||||
adapter.onIconUrlNeeded = { url -> loadMerchantIcon(url) }
|
||||
adapter.onTransferClick = { acc ->
|
||||
(activity as? HomeActivity)?.navigateTo(R.id.nav_transfer, TransferFragment.newInstanceFrom(acc))
|
||||
}
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
|
||||
@@ -13,7 +13,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import sh.sar.basedbank.api.mib.MibAccount
|
||||
import sh.sar.basedbank.databinding.ItemAccountBinding
|
||||
import sh.sar.basedbank.databinding.ItemCardBinding
|
||||
import sh.sar.basedbank.databinding.ItemProfileHeaderBinding
|
||||
import sh.sar.basedbank.databinding.ItemDateHeaderBinding
|
||||
|
||||
class AccountsAdapter(
|
||||
accounts: List<MibAccount>,
|
||||
@@ -21,7 +21,7 @@ class AccountsAdapter(
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
private sealed class Item {
|
||||
data class SectionTitle(val label: String, val chip: String) : Item()
|
||||
data class SectionTitle(val label: String) : Item()
|
||||
data class Account(val account: MibAccount) : Item()
|
||||
data class Card(val account: MibAccount) : Item()
|
||||
}
|
||||
@@ -35,19 +35,40 @@ class AccountsAdapter(
|
||||
}
|
||||
|
||||
private fun buildItems(accounts: List<MibAccount>): List<Item> = buildList {
|
||||
val regular = accounts.filter { it.profileType != "BML_PREPAID" }
|
||||
val prepaid = accounts.filter { it.profileType == "BML_PREPAID" }
|
||||
val nonPrepaid = 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)) }
|
||||
// Group non-prepaid accounts by their derived section title, preserving order
|
||||
val groups = LinkedHashMap<String, MutableList<MibAccount>>()
|
||||
for (acc in nonPrepaid) {
|
||||
val title = sectionTitle(acc)
|
||||
groups.getOrPut(title) { mutableListOf() }.add(acc)
|
||||
}
|
||||
for ((title, group) in groups) {
|
||||
add(Item.SectionTitle(title))
|
||||
group.forEach { add(Item.Account(it)) }
|
||||
}
|
||||
|
||||
if (prepaid.isNotEmpty()) {
|
||||
add(Item.SectionTitle("Cards", "BML"))
|
||||
add(Item.SectionTitle("Cards · Bank of Maldives"))
|
||||
prepaid.forEach { add(Item.Card(it)) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun sectionTitle(account: MibAccount): String {
|
||||
val profileLabel = when (account.profileType) {
|
||||
"0" -> "Personal"
|
||||
"1" -> "Business"
|
||||
else -> account.profileName
|
||||
}
|
||||
val bank = when {
|
||||
account.profileType.startsWith("BML") -> "Bank of Maldives"
|
||||
account.profileType == "FAHIPAY" -> "Fahipay"
|
||||
else -> "Maldives Islamic Bank"
|
||||
}
|
||||
return if (profileLabel.isNotBlank()) "$profileLabel · $bank" else bank
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int) = when (items[position]) {
|
||||
is Item.SectionTitle -> TYPE_HEADER
|
||||
is Item.Account -> TYPE_ACCOUNT
|
||||
@@ -57,7 +78,7 @@ class AccountsAdapter(
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
return when (viewType) {
|
||||
TYPE_HEADER -> SectionViewHolder(ItemProfileHeaderBinding.inflate(inflater, parent, false))
|
||||
TYPE_HEADER -> SectionViewHolder(ItemDateHeaderBinding.inflate(inflater, parent, false))
|
||||
TYPE_CARD -> CardViewHolder(ItemCardBinding.inflate(inflater, parent, false))
|
||||
else -> AccountViewHolder(ItemAccountBinding.inflate(inflater, parent, false))
|
||||
}
|
||||
@@ -73,16 +94,10 @@ class AccountsAdapter(
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
private inner class SectionViewHolder(private val binding: ItemProfileHeaderBinding) :
|
||||
private inner class SectionViewHolder(private val binding: ItemDateHeaderBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
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
|
||||
}
|
||||
binding.tvDateHeader.text = item.label
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,18 +106,8 @@ class AccountsAdapter(
|
||||
fun bind(account: MibAccount) {
|
||||
binding.tvAccountName.text = account.accountBriefName
|
||||
binding.tvAccountNumber.text = account.accountNumber
|
||||
binding.tvPillBank.text = when {
|
||||
account.profileType.startsWith("BML") -> "BML"
|
||||
account.profileType == "FAHIPAY" -> "FP"
|
||||
else -> null
|
||||
}
|
||||
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.tvPillType.text = friendlyAccountType(account.accountTypeName)
|
||||
binding.tvBalance.text = "${account.currencyName} ${account.availableBalance}"
|
||||
binding.root.setOnClickListener { onAccountClick(account) }
|
||||
binding.root.setOnLongClickListener {
|
||||
copyToClipboard(it.context, account.accountNumber)
|
||||
|
||||
@@ -158,7 +158,7 @@ class ContactsFragment : Fragment() {
|
||||
colorHex = contact.bankColor,
|
||||
imageHash = contact.customerImgHash
|
||||
)
|
||||
(requireActivity() as HomeActivity).showWithBackStack(fragment)
|
||||
(requireActivity() as HomeActivity).navigateTo(R.id.nav_transfer, fragment)
|
||||
}
|
||||
|
||||
private fun confirmDelete(contact: MibBeneficiary) {
|
||||
|
||||
@@ -199,18 +199,19 @@ class HomeActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
fun navigateTo(itemId: Int) {
|
||||
when (itemId) {
|
||||
R.id.nav_dashboard -> show(DashboardFragment())
|
||||
R.id.nav_accounts -> show(AccountsFragment())
|
||||
R.id.nav_contacts -> show(ContactsFragment())
|
||||
R.id.nav_transfer -> show(TransferFragment())
|
||||
R.id.nav_transfer_history -> show(TransferHistoryFragment())
|
||||
R.id.nav_finances -> show(FinancingFragment())
|
||||
R.id.nav_otp -> show(OtpFragment())
|
||||
R.id.nav_settings -> show(SettingsFragment())
|
||||
else -> Toast.makeText(this, R.string.work_in_progress, Toast.LENGTH_SHORT).show()
|
||||
fun navigateTo(itemId: Int, fragment: Fragment? = null) {
|
||||
val dest = fragment ?: when (itemId) {
|
||||
R.id.nav_dashboard -> DashboardFragment()
|
||||
R.id.nav_accounts -> AccountsFragment()
|
||||
R.id.nav_contacts -> ContactsFragment()
|
||||
R.id.nav_transfer -> TransferFragment()
|
||||
R.id.nav_transfer_history -> TransferHistoryFragment()
|
||||
R.id.nav_finances -> FinancingFragment()
|
||||
R.id.nav_otp -> OtpFragment()
|
||||
R.id.nav_settings -> SettingsFragment()
|
||||
else -> { Toast.makeText(this, R.string.work_in_progress, Toast.LENGTH_SHORT).show(); return }
|
||||
}
|
||||
show(dest)
|
||||
binding.navigationView.setCheckedItem(itemId)
|
||||
val bottomNavIds = setOf(R.id.nav_dashboard, R.id.nav_accounts, R.id.nav_contacts, R.id.nav_transfer, R.id.nav_more)
|
||||
if (binding.bottomNavigation.visibility == View.VISIBLE && itemId in bottomNavIds) {
|
||||
|
||||
@@ -93,6 +93,11 @@ class TransferFragment : Fragment() {
|
||||
private const val ARG_SUBTITLE = "contact_subtitle"
|
||||
private const val ARG_COLOR = "contact_color"
|
||||
private const val ARG_IMAGE_HASH = "contact_image_hash"
|
||||
private const val ARG_FROM_ACCOUNT = "from_account"
|
||||
|
||||
fun newInstanceFrom(account: MibAccount) = TransferFragment().apply {
|
||||
arguments = Bundle().apply { putString(ARG_FROM_ACCOUNT, account.accountNumber) }
|
||||
}
|
||||
|
||||
fun newInstance(
|
||||
accountNumber: String,
|
||||
@@ -171,6 +176,16 @@ class TransferFragment : Fragment() {
|
||||
updateAmountPrefix(picked)
|
||||
showFromCard(picked)
|
||||
}
|
||||
|
||||
val fromNumber = arguments?.getString(ARG_FROM_ACCOUNT)
|
||||
if (fromNumber != null && selectedAccount == null) {
|
||||
val match = accounts.firstOrNull { it.accountNumber == fromNumber }
|
||||
if (match != null) {
|
||||
selectedAccount = match
|
||||
updateAmountPrefix(match)
|
||||
showFromCard(match)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
<LinearLayout
|
||||
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">
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="20dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="14dp"
|
||||
android:gravity="center_vertical"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
|
||||
@@ -43,7 +39,7 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Right: segmented pill (bank | type | profile) + balance -->
|
||||
<!-- Right: segmented pill (bank | type) + balance -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -58,41 +54,11 @@
|
||||
android:gravity="center_vertical"
|
||||
android:background="@drawable/pill_segment_bg">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPillBank"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingVertical="6dp"
|
||||
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="16dp"
|
||||
android:background="?attr/colorOutline" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPillType"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:paddingVertical="6dp"
|
||||
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="16dp"
|
||||
android:background="?attr/colorOutline" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPillProfile"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="6dp"
|
||||
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
@@ -111,4 +77,10 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:background="?attr/colorOutlineVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<LinearLayout
|
||||
@@ -165,6 +166,20 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnHeaderTransfer"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:minHeight="0dp"
|
||||
app:icon="@drawable/ic_send"
|
||||
app:iconSize="20dp"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="0dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
<LinearLayout
|
||||
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">
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="20dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="14dp"
|
||||
android:gravity="center_vertical"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
|
||||
@@ -89,4 +85,10 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:background="?attr/colorOutlineVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
Reference in New Issue
Block a user