optimize contact picker ui to disable forbidden transfers
This commit is contained in:
@@ -7,7 +7,9 @@ import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import sh.sar.basedbank.R
|
||||
import sh.sar.basedbank.databinding.ItemPickerRowBinding
|
||||
import sh.sar.basedbank.databinding.ItemPickerSectionHeaderBinding
|
||||
|
||||
@@ -27,7 +29,8 @@ class ContactPickerAdapter(
|
||||
val colorHex: String,
|
||||
val isSameAsFrom: Boolean = false,
|
||||
val isManualEntry: Boolean = false,
|
||||
val imageHash: String? = null
|
||||
val imageHash: String? = null,
|
||||
val inactiveReason: String? = null
|
||||
) : PickerItem()
|
||||
}
|
||||
|
||||
@@ -96,10 +99,15 @@ class ContactPickerAdapter(
|
||||
if (item.imageHash != null) onImageNeeded?.invoke(item.imageHash)
|
||||
}
|
||||
|
||||
binding.root.alpha = if (item.isSameAsFrom) 0.4f else 1.0f
|
||||
binding.root.alpha = if (item.isSameAsFrom || item.inactiveReason != null) 0.4f else 1.0f
|
||||
binding.root.setOnClickListener {
|
||||
if (item.isSameAsFrom) onSameAsFrom()
|
||||
else onItemClick(item.accountNumber, item.displayName)
|
||||
when {
|
||||
item.inactiveReason != null ->
|
||||
Toast.makeText(binding.root.context, item.inactiveReason, Toast.LENGTH_SHORT).show()
|
||||
item.isSameAsFrom ->
|
||||
Toast.makeText(binding.root.context, R.string.transfer_same_account, Toast.LENGTH_SHORT).show()
|
||||
else -> onItemClick(item.accountNumber, item.displayName)
|
||||
}
|
||||
}
|
||||
binding.root.setOnLongClickListener { view ->
|
||||
onItemLongClick?.invoke(item.accountNumber, view) ?: false
|
||||
|
||||
@@ -76,10 +76,13 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
|
||||
|
||||
binding.etSheetSearch.addTextChangedListener { rebuildList(selectedAccountNumber) }
|
||||
|
||||
// Tabs: Recents | All | <categories...>
|
||||
// Tabs: Recents | My Accounts | All | <categories...>
|
||||
binding.sheetCategoryTabs.addTab(
|
||||
binding.sheetCategoryTabs.newTab().setText(R.string.contacts_tab_recents).apply { tag = RECENTS_TAG }
|
||||
)
|
||||
binding.sheetCategoryTabs.addTab(
|
||||
binding.sheetCategoryTabs.newTab().setText(R.string.transfer_my_accounts).apply { tag = MY_ACCOUNTS_TAG }
|
||||
)
|
||||
binding.sheetCategoryTabs.addTab(
|
||||
binding.sheetCategoryTabs.newTab().setText(R.string.contacts_tab_all).apply { tag = null }
|
||||
)
|
||||
@@ -93,8 +96,8 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
|
||||
})
|
||||
|
||||
viewModel.contactCategories.observe(viewLifecycleOwner) { cats ->
|
||||
// Remove all tabs after "All" (index 1) and re-add categories
|
||||
while (binding.sheetCategoryTabs.tabCount > 2) binding.sheetCategoryTabs.removeTabAt(2)
|
||||
// Remove all tabs after "All" (index 2) and re-add categories
|
||||
while (binding.sheetCategoryTabs.tabCount > 3) binding.sheetCategoryTabs.removeTabAt(3)
|
||||
for (cat in cats) {
|
||||
binding.sheetCategoryTabs.addTab(
|
||||
binding.sheetCategoryTabs.newTab().setText(cat.categoryName).apply { tag = cat.id }
|
||||
@@ -133,25 +136,63 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
|
||||
|
||||
val accounts = viewModel.accounts.value ?: emptyList()
|
||||
val contacts = viewModel.contacts.value ?: emptyList()
|
||||
val fromAccount = accounts.find { it.accountNumber == fromNumber }
|
||||
val fromCurrency = fromAccount?.currencyName ?: ""
|
||||
val fromLoginTag = fromAccount?.loginTag ?: ""
|
||||
val fromIsCard = fromAccount?.profileType == "BML_PREPAID"
|
||||
|
||||
if (activeCategoryId == null) {
|
||||
val filtered = if (search.isBlank()) accounts else accounts.filter {
|
||||
if (activeCategoryId == MY_ACCOUNTS_TAG) {
|
||||
val regularAccounts = accounts.filter { it.profileType != "BML_PREPAID" }
|
||||
val cards = accounts.filter { it.profileType == "BML_PREPAID" }
|
||||
|
||||
val filteredRegular = if (search.isBlank()) regularAccounts else regularAccounts.filter {
|
||||
it.accountBriefName.contains(search, ignoreCase = true) || it.accountNumber.contains(search)
|
||||
}
|
||||
if (filtered.isNotEmpty()) {
|
||||
items.add(ContactPickerAdapter.PickerItem.Header(getString(R.string.transfer_my_accounts)))
|
||||
for (acc in filtered) {
|
||||
if (filteredRegular.isNotEmpty()) {
|
||||
items.add(ContactPickerAdapter.PickerItem.Header(getString(R.string.accounts)))
|
||||
for (acc in filteredRegular) {
|
||||
if (acc.profileImageHash != null) profileImageHashes.add(acc.profileImageHash)
|
||||
val isSame = acc.accountNumber == fromNumber
|
||||
items.add(ContactPickerAdapter.PickerItem.Row(
|
||||
accountNumber = acc.accountNumber,
|
||||
displayName = acc.accountBriefName,
|
||||
subtitle = "${acc.accountNumber} · ${acc.currencyName} ${acc.availableBalance}",
|
||||
colorHex = "#FE860E",
|
||||
isSameAsFrom = acc.accountNumber == fromNumber,
|
||||
imageHash = acc.profileImageHash
|
||||
isSameAsFrom = isSame,
|
||||
imageHash = acc.profileImageHash,
|
||||
inactiveReason = if (isSame) null
|
||||
else if (fromIsCard && acc.loginTag != fromLoginTag) "Cards can only be used within the same BML account"
|
||||
else currencyMismatchReason(fromCurrency, acc.currencyName)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
val filteredCards = if (search.isBlank()) cards else cards.filter {
|
||||
it.accountBriefName.contains(search, ignoreCase = true) || it.accountNumber.contains(search)
|
||||
}
|
||||
if (filteredCards.isNotEmpty()) {
|
||||
items.add(ContactPickerAdapter.PickerItem.Header(getString(R.string.cards)))
|
||||
for (acc in filteredCards) {
|
||||
if (acc.profileImageHash != null) profileImageHashes.add(acc.profileImageHash)
|
||||
val isSame = acc.accountNumber == fromNumber
|
||||
val isActive = acc.statusDesc.equals("Active", ignoreCase = true)
|
||||
items.add(ContactPickerAdapter.PickerItem.Row(
|
||||
accountNumber = acc.accountNumber,
|
||||
displayName = acc.accountBriefName,
|
||||
subtitle = "${acc.accountNumber} · ${acc.currencyName} ${acc.availableBalance}",
|
||||
colorHex = "#FE860E",
|
||||
isSameAsFrom = isSame,
|
||||
imageHash = acc.profileImageHash,
|
||||
inactiveReason = if (isSame) null
|
||||
else if (!isActive) acc.statusDesc
|
||||
else if (acc.loginTag != fromLoginTag) "Cards can only be used within the same BML account"
|
||||
else currencyMismatchReason(fromCurrency, acc.currencyName)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
adapter.submitList(items)
|
||||
return
|
||||
}
|
||||
|
||||
val filteredContacts = contacts.filter { contact ->
|
||||
@@ -164,9 +205,6 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
|
||||
}
|
||||
|
||||
if (filteredContacts.isNotEmpty()) {
|
||||
if (activeCategoryId == null) {
|
||||
items.add(ContactPickerAdapter.PickerItem.Header(getString(R.string.nav_contacts)))
|
||||
}
|
||||
for (contact in filteredContacts) {
|
||||
items.add(ContactPickerAdapter.PickerItem.Row(
|
||||
accountNumber = contact.benefAccount,
|
||||
@@ -174,7 +212,8 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
|
||||
subtitle = "${contact.benefBankName} · ${contact.benefAccount}",
|
||||
colorHex = contact.bankColor,
|
||||
isSameAsFrom = contact.benefAccount == fromNumber,
|
||||
imageHash = contact.customerImgHash
|
||||
imageHash = contact.customerImgHash,
|
||||
inactiveReason = currencyMismatchReason(fromCurrency, contact.transferCyDesc)
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -203,6 +242,9 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun currencyMismatchReason(fromCurrency: String, toCurrency: String): String? =
|
||||
if (fromCurrency == "MVR" && toCurrency == "USD") "Cannot transfer from MVR to USD account" else null
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
@@ -214,6 +256,7 @@ class ContactPickerSheetFragment : BottomSheetDialogFragment() {
|
||||
const val KEY_LABEL = "label"
|
||||
private const val ARG_FROM_ACCOUNT = "fromAccount"
|
||||
private const val RECENTS_TAG = "__recents__"
|
||||
private const val MY_ACCOUNTS_TAG = "__my_accounts__"
|
||||
|
||||
fun newInstance(fromAccountNumber: String) = ContactPickerSheetFragment().apply {
|
||||
arguments = bundleOf(ARG_FROM_ACCOUNT to fromAccountNumber)
|
||||
|
||||
Reference in New Issue
Block a user