Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
045eb1b1a2
|
||
|
|
22806da1b3
|
||
|
|
29ac4352ff
|
||
|
|
df892ec8d5
|
||
|
|
5cba468781
|
||
|
|
ed2054fb81
|
||
|
|
e9583f0580
|
||
|
|
a32841a319
|
||
|
|
7a66dd836c
|
||
|
|
68dd49b90c
|
||
|
|
8d09e760a8
|
||
|
|
62ccae602d
|
||
|
|
9011ef2f5a
|
@@ -27,6 +27,10 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
debug {
|
||||||
|
applicationIdSuffix = ".debug"
|
||||||
|
versionNameSuffix = "-debug"
|
||||||
|
}
|
||||||
release {
|
release {
|
||||||
signingConfig = signingConfigs.getByName("release")
|
signingConfig = signingConfigs.getByName("release")
|
||||||
isMinifyEnabled = false
|
isMinifyEnabled = false
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#CC0000"
|
||||||
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Thijooree Debug</string>
|
||||||
|
</resources>
|
||||||
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 294 KiB After Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 227 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 332 KiB After Width: | Height: | Size: 296 KiB |
|
Before Width: | Height: | Size: 390 KiB After Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 302 KiB After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 295 KiB After Width: | Height: | Size: 213 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 267 KiB |
|
Before Width: | Height: | Size: 468 KiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 36 KiB |
@@ -264,6 +264,13 @@ class LockActivity : AppCompatActivity() {
|
|||||||
if (intent.getBooleanExtra(EXTRA_RESUME, false)) {
|
if (intent.getBooleanExtra(EXTRA_RESUME, false)) {
|
||||||
finish()
|
finish()
|
||||||
} else {
|
} else {
|
||||||
|
val store = CredentialStore(this)
|
||||||
|
val hasCredentials = store.hasMibCredentials() || store.hasBmlCredentials() || store.hasFahipayCredentials()
|
||||||
|
if (!hasCredentials) {
|
||||||
|
startActivity(Intent(this, sh.sar.basedbank.ui.login.LoginActivity::class.java))
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
val navDest = intent.getIntExtra("nav_destination", -1)
|
val navDest = intent.getIntExtra("nav_destination", -1)
|
||||||
val autoScan = intent.getBooleanExtra("auto_scan", false)
|
val autoScan = intent.getBooleanExtra("auto_scan", false)
|
||||||
startActivity(Intent(this, HomeActivity::class.java).apply {
|
startActivity(Intent(this, HomeActivity::class.java).apply {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.json.JSONObject
|
|||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import kotlin.math.abs
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
class SessionExpiredException : Exception("MIB session expired")
|
class SessionExpiredException : Exception("MIB session expired")
|
||||||
@@ -168,7 +169,7 @@ class MibLoginFlow(private val credentialStore: CredentialStore) {
|
|||||||
accountTypeName = a.optString("accountTypeName"),
|
accountTypeName = a.optString("accountTypeName"),
|
||||||
availableBalance = a.optString("availableBalance"),
|
availableBalance = a.optString("availableBalance"),
|
||||||
currentBalance = a.optString("currentBalance"),
|
currentBalance = a.optString("currentBalance"),
|
||||||
blockedAmount = a.optString("blockedAmount"),
|
blockedAmount = absBlockedAmount(a.optString("blockedAmount")),
|
||||||
mvrBalance = a.optString("mvrBalance"),
|
mvrBalance = a.optString("mvrBalance"),
|
||||||
statusDesc = a.optString("statusDesc"),
|
statusDesc = a.optString("statusDesc"),
|
||||||
profileImageHash = profile.customerImage,
|
profileImageHash = profile.customerImage,
|
||||||
@@ -188,6 +189,13 @@ class MibLoginFlow(private val credentialStore: CredentialStore) {
|
|||||||
|
|
||||||
// ─── Helpers ─────────────────────────────────────────────────────────────
|
// ─── Helpers ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** MIB returns blockedAmount as a signed decimal where negative = funds held.
|
||||||
|
* Normalize to a positive magnitude so downstream code can treat it uniformly. */
|
||||||
|
private fun absBlockedAmount(raw: String): String {
|
||||||
|
val v = raw.toDoubleOrNull() ?: return raw
|
||||||
|
return "%.2f".format(abs(v))
|
||||||
|
}
|
||||||
|
|
||||||
private fun initialKeyExchange(
|
private fun initialKeyExchange(
|
||||||
appId: String, encKey: String, sfunc: String, key2: String? = null
|
appId: String, encKey: String, sfunc: String, key2: String? = null
|
||||||
): Pair<MibSession, String> {
|
): Pair<MibSession, String> {
|
||||||
@@ -325,7 +333,7 @@ class MibLoginFlow(private val credentialStore: CredentialStore) {
|
|||||||
accountTypeName = a.optString("accountTypeName"),
|
accountTypeName = a.optString("accountTypeName"),
|
||||||
availableBalance = a.optString("availableBalance"),
|
availableBalance = a.optString("availableBalance"),
|
||||||
currentBalance = a.optString("currentBalance"),
|
currentBalance = a.optString("currentBalance"),
|
||||||
blockedAmount = a.optString("blockedAmount"),
|
blockedAmount = absBlockedAmount(a.optString("blockedAmount")),
|
||||||
mvrBalance = a.optString("mvrBalance"),
|
mvrBalance = a.optString("mvrBalance"),
|
||||||
statusDesc = a.optString("statusDesc"),
|
statusDesc = a.optString("statusDesc"),
|
||||||
profileImageHash = profile.customerImage,
|
profileImageHash = profile.customerImage,
|
||||||
|
|||||||
@@ -142,6 +142,8 @@ class AccountHistoryFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
adapter.setTransactions(filtered)
|
adapter.setTransactions(filtered)
|
||||||
binding.emptyView.visibility = if (filtered.isEmpty() && !isLoading) View.VISIBLE else View.GONE
|
binding.emptyView.visibility = if (filtered.isEmpty() && !isLoading) View.VISIBLE else View.GONE
|
||||||
|
binding.skeletonContainer.visibility =
|
||||||
|
if (allTransactions.isEmpty() && isLoading) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resetAndReload() {
|
private fun resetAndReload() {
|
||||||
@@ -168,6 +170,9 @@ class AccountHistoryFragment : Fragment() {
|
|||||||
|
|
||||||
if (firstPageDone && allTransactions.isNotEmpty()) {
|
if (firstPageDone && allTransactions.isNotEmpty()) {
|
||||||
adapter.showLoadingFooter = true
|
adapter.showLoadingFooter = true
|
||||||
|
} else if (allTransactions.isEmpty()) {
|
||||||
|
binding.skeletonContainer.visibility = View.VISIBLE
|
||||||
|
binding.emptyView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
val app = requireActivity().application as BasedBankApp
|
val app = requireActivity().application as BasedBankApp
|
||||||
@@ -187,6 +192,7 @@ class AccountHistoryFragment : Fragment() {
|
|||||||
|
|
||||||
isLoading = false
|
isLoading = false
|
||||||
if (_binding == null) return@launch
|
if (_binding == null) return@launch
|
||||||
|
binding.skeletonContainer.visibility = View.GONE
|
||||||
|
|
||||||
if (!firstPageDone) {
|
if (!firstPageDone) {
|
||||||
firstPageDone = true
|
firstPageDone = true
|
||||||
|
|||||||
@@ -125,6 +125,14 @@ class AccountsAdapter(
|
|||||||
binding.tvAccountNumber.text = display.number
|
binding.tvAccountNumber.text = display.number
|
||||||
binding.tvAccountType.text = display.typeLabel
|
binding.tvAccountType.text = display.typeLabel
|
||||||
binding.tvBalance.text = if (hideAmounts) maskAmount(display.balance) else display.balance
|
binding.tvBalance.text = if (hideAmounts) maskAmount(display.balance) else display.balance
|
||||||
|
val blocked = display.blockedBalance
|
||||||
|
if (blocked != null) {
|
||||||
|
val shown = if (hideAmounts) maskAmount(blocked) else blocked
|
||||||
|
binding.tvBlocked.text = binding.root.context.getString(R.string.account_blocked_label, shown)
|
||||||
|
binding.tvBlocked.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.tvBlocked.visibility = View.GONE
|
||||||
|
}
|
||||||
binding.btnTransfer.setOnClickListener { onTransferClick?.invoke(account) }
|
binding.btnTransfer.setOnClickListener { onTransferClick?.invoke(account) }
|
||||||
binding.root.setOnClickListener { onAccountClick(account) }
|
binding.root.setOnClickListener { onAccountClick(account) }
|
||||||
binding.root.setOnLongClickListener {
|
binding.root.setOnLongClickListener {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
@@ -194,10 +195,10 @@ class ContactsFragment : Fragment() {
|
|||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
val success = withContext(Dispatchers.IO) { ContactManager.delete(contact, app) }
|
val success = withContext(Dispatchers.IO) { ContactManager.delete(contact, app) }
|
||||||
if (success) {
|
if (success) {
|
||||||
Toast.makeText(requireContext(), R.string.contact_deleted, Toast.LENGTH_SHORT).show()
|
|
||||||
removeFromViewModel(contact)
|
removeFromViewModel(contact)
|
||||||
|
Snackbar.make(binding.root, R.string.contact_deleted, Snackbar.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(requireContext(), R.string.contact_delete_failed, Toast.LENGTH_SHORT).show()
|
Snackbar.make(binding.root, R.string.contact_delete_failed, Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,14 +57,24 @@ class DashboardFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
viewModel.accounts.observe(viewLifecycleOwner) { updateBalances(it) }
|
viewModel.accounts.observe(viewLifecycleOwner) {
|
||||||
viewModel.financing.observe(viewLifecycleOwner) { updatePendingFinances() }
|
updateBalances(it)
|
||||||
viewModel.bmlLoanDetails.observe(viewLifecycleOwner) { updatePendingFinances() }
|
updateAttentionRow()
|
||||||
|
}
|
||||||
|
viewModel.financing.observe(viewLifecycleOwner) {
|
||||||
|
updatePendingFinances()
|
||||||
|
updateAttentionRow()
|
||||||
|
}
|
||||||
|
viewModel.bmlLoanDetails.observe(viewLifecycleOwner) {
|
||||||
|
updatePendingFinances()
|
||||||
|
updateAttentionRow()
|
||||||
|
}
|
||||||
viewModel.bmlLimits.observe(viewLifecycleOwner) { updateForeignLimits(it) }
|
viewModel.bmlLimits.observe(viewLifecycleOwner) { updateForeignLimits(it) }
|
||||||
viewModel.hideAmounts.observe(viewLifecycleOwner) {
|
viewModel.hideAmounts.observe(viewLifecycleOwner) {
|
||||||
updateBalances(viewModel.accounts.value ?: emptyList())
|
updateBalances(viewModel.accounts.value ?: emptyList())
|
||||||
updatePendingFinances()
|
updatePendingFinances()
|
||||||
updateForeignLimits(viewModel.bmlLimits.value ?: emptyList())
|
updateForeignLimits(viewModel.bmlLimits.value ?: emptyList())
|
||||||
|
updateAttentionRow()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.swipeRefresh.setOnRefreshListener {
|
binding.swipeRefresh.setOnRefreshListener {
|
||||||
@@ -76,6 +86,10 @@ class DashboardFragment : Fragment() {
|
|||||||
(activity as? HomeActivity)?.navigateTo(R.id.nav_finances)
|
(activity as? HomeActivity)?.navigateTo(R.id.nav_finances)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.cardOverdue.setOnClickListener {
|
||||||
|
(activity as? HomeActivity)?.navigateTo(R.id.nav_finances)
|
||||||
|
}
|
||||||
|
|
||||||
val cardAdapter = DashboardCardAdapter()
|
val cardAdapter = DashboardCardAdapter()
|
||||||
binding.rvCards.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
|
binding.rvCards.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
|
||||||
binding.rvCards.adapter = cardAdapter
|
binding.rvCards.adapter = cardAdapter
|
||||||
@@ -112,6 +126,12 @@ class DashboardFragment : Fragment() {
|
|||||||
|
|
||||||
private fun refreshQuickActions() {
|
private fun refreshQuickActions() {
|
||||||
val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
||||||
|
val isBottom = prefs.getBoolean("bottom_nav", false)
|
||||||
|
if (isBottom) {
|
||||||
|
binding.buttonBar.visibility = View.GONE
|
||||||
|
return
|
||||||
|
}
|
||||||
|
binding.buttonBar.visibility = View.VISIBLE
|
||||||
val ids = NavCustomization.getQuickActions(prefs)
|
val ids = NavCustomization.getQuickActions(prefs)
|
||||||
listOf(binding.btnQuickAction1, binding.btnQuickAction2).forEachIndexed { i, btn ->
|
listOf(binding.btnQuickAction1, binding.btnQuickAction2).forEachIndexed { i, btn ->
|
||||||
val def = NavCustomization.ALL_SWAPPABLE.find { it.id == ids[i] }
|
val def = NavCustomization.ALL_SWAPPABLE.find { it.id == ids[i] }
|
||||||
@@ -244,6 +264,56 @@ class DashboardFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateAttentionRow() {
|
||||||
|
val hide = viewModel.hideAmounts.value ?: false
|
||||||
|
val accounts = viewModel.accounts.value ?: emptyList()
|
||||||
|
|
||||||
|
// Blocked: sum across CASA-style accounts (exclude cards and loans) per currency.
|
||||||
|
val blockedByCurrency = accounts
|
||||||
|
.filter { it.profileType != "BML_CREDIT" && it.profileType != "BML_PREPAID" && it.profileType != "BML_DEBIT" && it.profileType != "BML_LOAN" }
|
||||||
|
.mapNotNull { acc ->
|
||||||
|
val v = acc.blockedAmount.replace(",", "").toDoubleOrNull() ?: 0.0
|
||||||
|
if (v > 0.0) acc.currencyName.uppercase() to v else null
|
||||||
|
}
|
||||||
|
.groupBy({ it.first }, { it.second })
|
||||||
|
.mapValues { (_, vs) -> vs.sum() }
|
||||||
|
|
||||||
|
val blockedTotal = blockedByCurrency.values.sum()
|
||||||
|
if (blockedTotal > 0.0) {
|
||||||
|
// Primary line: prefer MVR if present, otherwise the first currency.
|
||||||
|
val primaryCcy = if ("MVR" in blockedByCurrency) "MVR" else blockedByCurrency.keys.first()
|
||||||
|
val primaryAmt = blockedByCurrency.getValue(primaryCcy)
|
||||||
|
binding.tvBlockedTotal.text = if (hide) "$primaryCcy ••••••" else "$primaryCcy %,.2f".format(primaryAmt)
|
||||||
|
|
||||||
|
val secondary = blockedByCurrency.filterKeys { it != primaryCcy }
|
||||||
|
if (secondary.isNotEmpty()) {
|
||||||
|
binding.tvBlockedSecondary.text = secondary.entries.joinToString(" · ") { (ccy, amt) ->
|
||||||
|
if (hide) "$ccy ••••••" else "$ccy %,.2f".format(amt)
|
||||||
|
}
|
||||||
|
binding.tvBlockedSecondary.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.tvBlockedSecondary.visibility = View.GONE
|
||||||
|
}
|
||||||
|
binding.cardBlocked.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.cardBlocked.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overdue: MIB finance deals + BML loan details (assumed MVR — matches existing Pending Finances).
|
||||||
|
val mibOverdue = (viewModel.financing.value ?: emptyList()).sumOf { it.overdueAmount }
|
||||||
|
val bmlOverdue = (viewModel.bmlLoanDetails.value ?: emptyMap()).values.sumOf { it.overdueAmount }
|
||||||
|
val overdueTotal = mibOverdue + bmlOverdue
|
||||||
|
if (overdueTotal > 0.0) {
|
||||||
|
binding.tvOverdueTotal.text = if (hide) "MVR ••••••" else "MVR %,.2f".format(overdueTotal)
|
||||||
|
binding.cardOverdue.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.cardOverdue.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.rowAttention.visibility =
|
||||||
|
if (blockedTotal > 0.0 || overdueTotal > 0.0) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
private fun updatePendingFinances() {
|
private fun updatePendingFinances() {
|
||||||
val hide = viewModel.hideAmounts.value ?: false
|
val hide = viewModel.hideAmounts.value ?: false
|
||||||
val mibTotal = (viewModel.financing.value ?: emptyList()).sumOf { it.outstandingAmount }
|
val mibTotal = (viewModel.financing.value ?: emptyList()).sumOf { it.outstandingAmount }
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ ViewCompat.setOnApplyWindowInsetsListener(binding.contentLayout) { v, insets ->
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun cardImageAsset(card: MibCard): String? = when (card.cardType) {
|
fun cardImageAsset(card: MibCard): String? = when (card.cardType) {
|
||||||
"51" -> "cards/mib/faisa.png"
|
"51" -> "cards/mib/faisa_card.png"
|
||||||
"53" -> "cards/mib/visa_black_platinum.png"
|
"53" -> "cards/mib/visa_black_platinum.png"
|
||||||
"57" -> "cards/mib/visa_blue_everyday.png"
|
"57" -> "cards/mib/visa_blue_everyday.png"
|
||||||
"70" -> "cards/mib/visa_business.png"
|
"70" -> "cards/mib/visa_business.png"
|
||||||
@@ -305,12 +305,7 @@ ViewCompat.setOnApplyWindowInsetsListener(binding.contentLayout) { v, insets ->
|
|||||||
if (statusLabel == null) { tv.visibility = View.GONE; return }
|
if (statusLabel == null) { tv.visibility = View.GONE; return }
|
||||||
tv.visibility = View.VISIBLE
|
tv.visibility = View.VISIBLE
|
||||||
tv.text = statusLabel
|
tv.text = statusLabel
|
||||||
val dp = tv.context.resources.displayMetrics.density
|
tv.setBackgroundResource(R.drawable.card_overlay_pill_bg)
|
||||||
tv.background = GradientDrawable().apply {
|
|
||||||
shape = GradientDrawable.RECTANGLE
|
|
||||||
cornerRadius = 12 * dp
|
|
||||||
setColor(0xCC212121.toInt())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun formatMasked(masked: String): String {
|
fun formatMasked(masked: String): String {
|
||||||
|
|||||||
@@ -54,19 +54,29 @@ class SettingsAppearanceFragment : Fragment() {
|
|||||||
// Quick actions
|
// Quick actions
|
||||||
quickActions.clear()
|
quickActions.clear()
|
||||||
quickActions.addAll(NavCustomization.getQuickActions(prefs))
|
quickActions.addAll(NavCustomization.getQuickActions(prefs))
|
||||||
quickActionAdapter = NavItemAdapter(quickActions) {
|
quickActionAdapter = NavItemAdapter(
|
||||||
NavCustomization.saveQuickActions(prefs, quickActions)
|
items = quickActions,
|
||||||
|
onSave = { NavCustomization.saveQuickActions(prefs, quickActions) },
|
||||||
|
isEnabled = { !prefs.getBoolean("bottom_nav", false) }
|
||||||
|
)
|
||||||
|
setupNavItemRecyclerView(binding.rvQuickActions, quickActionAdapter, quickActions) {
|
||||||
|
!prefs.getBoolean("bottom_nav", false)
|
||||||
}
|
}
|
||||||
setupNavItemRecyclerView(binding.rvQuickActions, quickActionAdapter, quickActions)
|
|
||||||
|
|
||||||
// Bottom bar shortcuts
|
// Bottom bar shortcuts
|
||||||
slots.clear()
|
slots.clear()
|
||||||
slots.addAll(NavCustomization.getSlots(prefs))
|
slots.addAll(NavCustomization.getSlots(prefs))
|
||||||
slotAdapter = NavItemAdapter(slots) {
|
slotAdapter = NavItemAdapter(
|
||||||
NavCustomization.saveSlots(prefs, slots)
|
items = slots,
|
||||||
(activity as? HomeActivity)?.rebuildBottomNav(prefs)
|
onSave = {
|
||||||
|
NavCustomization.saveSlots(prefs, slots)
|
||||||
|
(activity as? HomeActivity)?.rebuildBottomNav(prefs)
|
||||||
|
},
|
||||||
|
isEnabled = { prefs.getBoolean("bottom_nav", false) }
|
||||||
|
)
|
||||||
|
setupNavItemRecyclerView(binding.rvNavSlots, slotAdapter, slots) {
|
||||||
|
prefs.getBoolean("bottom_nav", false)
|
||||||
}
|
}
|
||||||
setupNavItemRecyclerView(binding.rvNavSlots, slotAdapter, slots)
|
|
||||||
// Show labels toggle
|
// Show labels toggle
|
||||||
val showLabels = prefs.getBoolean("bottom_nav_show_labels", true)
|
val showLabels = prefs.getBoolean("bottom_nav_show_labels", true)
|
||||||
binding.switchShowLabels.isChecked = showLabels
|
binding.switchShowLabels.isChecked = showLabels
|
||||||
@@ -109,13 +119,18 @@ class SettingsAppearanceFragment : Fragment() {
|
|||||||
private fun setupNavItemRecyclerView(
|
private fun setupNavItemRecyclerView(
|
||||||
rv: RecyclerView,
|
rv: RecyclerView,
|
||||||
adapter: NavItemAdapter,
|
adapter: NavItemAdapter,
|
||||||
items: MutableList<Int>
|
items: MutableList<Int>,
|
||||||
|
isEnabled: () -> Boolean
|
||||||
) {
|
) {
|
||||||
rv.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
|
rv.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
|
||||||
rv.adapter = adapter
|
rv.adapter = adapter
|
||||||
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(
|
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(
|
||||||
ItemTouchHelper.START or ItemTouchHelper.END, 0
|
ItemTouchHelper.START or ItemTouchHelper.END, 0
|
||||||
) {
|
) {
|
||||||
|
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
|
||||||
|
if (!isEnabled()) return 0
|
||||||
|
return super.getMovementFlags(recyclerView, viewHolder)
|
||||||
|
}
|
||||||
override fun onMove(
|
override fun onMove(
|
||||||
rv: RecyclerView,
|
rv: RecyclerView,
|
||||||
from: RecyclerView.ViewHolder,
|
from: RecyclerView.ViewHolder,
|
||||||
@@ -134,11 +149,17 @@ class SettingsAppearanceFragment : Fragment() {
|
|||||||
|
|
||||||
private fun updateShortcutsVisibility() {
|
private fun updateShortcutsVisibility() {
|
||||||
val isBottom = prefs.getBoolean("bottom_nav", false)
|
val isBottom = prefs.getBoolean("bottom_nav", false)
|
||||||
|
binding.sectionQuickActions.alpha = if (isBottom) 0.38f else 1f
|
||||||
binding.sectionBottomBarShortcuts.alpha = if (isBottom) 1f else 0.38f
|
binding.sectionBottomBarShortcuts.alpha = if (isBottom) 1f else 0.38f
|
||||||
|
binding.switchShowLabels.isClickable = isBottom
|
||||||
|
quickActionAdapter.notifyDataSetChanged()
|
||||||
|
slotAdapter.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showItemPicker(items: MutableList<Int>, slotIndex: Int, adapter: NavItemAdapter) {
|
private fun showItemPicker(items: MutableList<Int>, slotIndex: Int, adapter: NavItemAdapter) {
|
||||||
if (items === slots && !prefs.getBoolean("bottom_nav", false)) return
|
val isBottom = prefs.getBoolean("bottom_nav", false)
|
||||||
|
if (items === slots && !isBottom) return
|
||||||
|
if (items === quickActions && isBottom) return
|
||||||
val ctx = requireContext()
|
val ctx = requireContext()
|
||||||
val otherIds = items.filterIndexed { i, _ -> i != slotIndex }.toSet()
|
val otherIds = items.filterIndexed { i, _ -> i != slotIndex }.toSet()
|
||||||
val available = NavCustomization.ALL_SWAPPABLE.filter { it.id !in otherIds }
|
val available = NavCustomization.ALL_SWAPPABLE.filter { it.id !in otherIds }
|
||||||
@@ -169,7 +190,8 @@ class SettingsAppearanceFragment : Fragment() {
|
|||||||
|
|
||||||
private inner class NavItemAdapter(
|
private inner class NavItemAdapter(
|
||||||
val items: MutableList<Int>,
|
val items: MutableList<Int>,
|
||||||
val onSave: () -> Unit
|
val onSave: () -> Unit,
|
||||||
|
val isEnabled: () -> Boolean = { true }
|
||||||
) : RecyclerView.Adapter<NavItemAdapter.VH>() {
|
) : RecyclerView.Adapter<NavItemAdapter.VH>() {
|
||||||
|
|
||||||
inner class VH(view: View) : RecyclerView.ViewHolder(view) {
|
inner class VH(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
@@ -191,7 +213,12 @@ class SettingsAppearanceFragment : Fragment() {
|
|||||||
val def = NavCustomization.ALL_SWAPPABLE.find { it.id == items[position] } ?: return
|
val def = NavCustomization.ALL_SWAPPABLE.find { it.id == items[position] } ?: return
|
||||||
holder.ivNavIcon.setImageResource(def.iconRes)
|
holder.ivNavIcon.setImageResource(def.iconRes)
|
||||||
holder.tvNavLabel.setText(def.titleRes)
|
holder.tvNavLabel.setText(def.titleRes)
|
||||||
holder.itemView.setOnClickListener { showItemPicker(items, holder.adapterPosition, this) }
|
val enabled = isEnabled()
|
||||||
|
holder.itemView.setOnClickListener(
|
||||||
|
if (enabled) View.OnClickListener { showItemPicker(items, holder.adapterPosition, this) }
|
||||||
|
else null
|
||||||
|
)
|
||||||
|
holder.itemView.isClickable = enabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -181,6 +181,9 @@ class TransferHistoryFragment : Fragment() {
|
|||||||
|
|
||||||
if (firstBatchDone && allTransactions.isNotEmpty()) {
|
if (firstBatchDone && allTransactions.isNotEmpty()) {
|
||||||
adapter.showLoadingFooter = true
|
adapter.showLoadingFooter = true
|
||||||
|
} else if (allTransactions.isEmpty()) {
|
||||||
|
binding.skeletonContainer.visibility = View.VISIBLE
|
||||||
|
binding.emptyView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
val app = requireActivity().application as BasedBankApp
|
val app = requireActivity().application as BasedBankApp
|
||||||
@@ -286,6 +289,7 @@ class TransferHistoryFragment : Fragment() {
|
|||||||
|
|
||||||
isLoading = false
|
isLoading = false
|
||||||
if (_binding == null) return@launch
|
if (_binding == null) return@launch
|
||||||
|
binding.skeletonContainer.visibility = View.GONE
|
||||||
|
|
||||||
val raw = bannerMsg.get()
|
val raw = bannerMsg.get()
|
||||||
when {
|
when {
|
||||||
@@ -329,6 +333,8 @@ class TransferHistoryFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
adapter.setTransactions(filtered)
|
adapter.setTransactions(filtered)
|
||||||
binding.emptyView.visibility = if (filtered.isEmpty() && !isLoading) View.VISIBLE else View.GONE
|
binding.emptyView.visibility = if (filtered.isEmpty() && !isLoading) View.VISIBLE else View.GONE
|
||||||
|
binding.skeletonContainer.visibility =
|
||||||
|
if (allTransactions.isEmpty() && isLoading) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadContactImage(name: String) {
|
private fun loadContactImage(name: String) {
|
||||||
|
|||||||
@@ -109,6 +109,9 @@ class OnboardingActivity : AppCompatActivity(), SecuritySetupFragment.Callback {
|
|||||||
|
|
||||||
binding.btnGetStarted.setOnClickListener {
|
binding.btnGetStarted.setOnClickListener {
|
||||||
prefs.edit().putBoolean("onboarding_done", true).apply()
|
prefs.edit().putBoolean("onboarding_done", true).apply()
|
||||||
|
// Mark as unlocked so LoginActivity doesn't redirect to LockActivity.
|
||||||
|
// The user just completed setup — they shouldn't have to re-authenticate immediately.
|
||||||
|
(application as BasedBankApp).isUnlocked = true
|
||||||
startActivity(Intent(this, LoginActivity::class.java))
|
startActivity(Intent(this, LoginActivity::class.java))
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ data class AccountListDisplay(
|
|||||||
val number: String,
|
val number: String,
|
||||||
val typeLabel: String,
|
val typeLabel: String,
|
||||||
val balance: String,
|
val balance: String,
|
||||||
|
val blockedBalance: String? = null, // null when zero or not applicable
|
||||||
val isCard: Boolean = false,
|
val isCard: Boolean = false,
|
||||||
val cardBrandIcon: Int = 0, // drawable res, only meaningful if isCard
|
val cardBrandIcon: Int = 0, // drawable res, only meaningful if isCard
|
||||||
val statusLabel: String? = null // null = active; shown as status pill if set
|
val statusLabel: String? = null // null = active; shown as status pill if set
|
||||||
|
|||||||
@@ -26,11 +26,13 @@ object BmlDashboardParser {
|
|||||||
statusLabel = if (isActive) null else account.statusDesc
|
statusLabel = if (isActive) null else account.statusDesc
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
val blocked = account.blockedAmount.toDoubleOrNull() ?: 0.0
|
||||||
AccountListDisplay(
|
AccountListDisplay(
|
||||||
name = account.accountBriefName,
|
name = account.accountBriefName,
|
||||||
number = account.accountNumber,
|
number = account.accountNumber,
|
||||||
typeLabel = productLabel(account.accountTypeName),
|
typeLabel = productLabel(account.accountTypeName),
|
||||||
balance = listBalance(account)
|
balance = listBalance(account),
|
||||||
|
blockedBalance = if (blocked > 0.0) "${account.currencyName} ${account.blockedAmount}" else null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,9 +54,9 @@ object BmlDashboardParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Balance shown in the accounts list — ledger (working) balance for BML CASA. */
|
/** Balance shown in the accounts list — available balance, consistent with transfer/contact picker. */
|
||||||
fun listBalance(account: BankAccount): String =
|
fun listBalance(account: BankAccount): String =
|
||||||
"${account.currencyName} ${account.currentBalance}"
|
"${account.currencyName} ${account.availableBalance}"
|
||||||
|
|
||||||
fun cardBrandIcon(productName: String): Int = when {
|
fun cardBrandIcon(productName: String): Int = when {
|
||||||
productName.contains("AMEX", ignoreCase = true) ||
|
productName.contains("AMEX", ignoreCase = true) ||
|
||||||
|
|||||||
@@ -5,12 +5,16 @@ import sh.sar.basedbank.util.AccountListDisplay
|
|||||||
|
|
||||||
object MibAccountParser {
|
object MibAccountParser {
|
||||||
|
|
||||||
fun displayData(account: BankAccount) = AccountListDisplay(
|
fun displayData(account: BankAccount): AccountListDisplay {
|
||||||
name = account.accountBriefName,
|
val blocked = account.blockedAmount.toDoubleOrNull() ?: 0.0
|
||||||
number = account.accountNumber,
|
return AccountListDisplay(
|
||||||
typeLabel = productLabel(account.accountTypeName),
|
name = account.accountBriefName,
|
||||||
balance = "${account.currencyName} ${account.availableBalance}"
|
number = account.accountNumber,
|
||||||
)
|
typeLabel = productLabel(account.accountTypeName),
|
||||||
|
balance = "${account.currencyName} ${account.availableBalance}",
|
||||||
|
blockedBalance = if (blocked > 0.0) "${account.currencyName} ${account.blockedAmount}" else null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a display-ready product label for a MIB (Faisanet) account type name.
|
* Returns a display-ready product label for a MIB (Faisanet) account type name.
|
||||||
|
|||||||
@@ -5,13 +5,16 @@ import sh.sar.basedbank.util.AccountHistoryDisplay
|
|||||||
|
|
||||||
object MibHistoryParser {
|
object MibHistoryParser {
|
||||||
|
|
||||||
fun displayData(account: BankAccount) = AccountHistoryDisplay(
|
fun displayData(account: BankAccount): AccountHistoryDisplay {
|
||||||
name = account.accountBriefName,
|
val blocked = account.blockedAmount.toDoubleOrNull() ?: 0.0
|
||||||
number = account.accountNumber,
|
return AccountHistoryDisplay(
|
||||||
bankPill = null, // MIB has no bank pill
|
name = account.accountBriefName,
|
||||||
typeLabel = MibAccountParser.productLabel(account.accountTypeName),
|
number = account.accountNumber,
|
||||||
availableBalance = "${account.currencyName} ${account.availableBalance}",
|
bankPill = null, // MIB has no bank pill
|
||||||
workingBalance = "${account.currencyName} ${account.currentBalance}",
|
typeLabel = MibAccountParser.productLabel(account.accountTypeName),
|
||||||
blockedBalance = null
|
availableBalance = "${account.currencyName} ${account.availableBalance}",
|
||||||
)
|
workingBalance = "${account.currencyName} ${account.currentBalance}",
|
||||||
|
blockedBalance = if (blocked > 0.0) "${account.currencyName} ${account.blockedAmount}" else null
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Translucent dark pill used as a status overlay on card-visual surfaces
|
||||||
|
(item_card_dashboard / _stack / _wallet / _settings_entry). Theme-independent
|
||||||
|
by design: it sits on top of card artwork, not the surface color. -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="12dp" />
|
||||||
|
<solid android:color="#CC212121" />
|
||||||
|
</shape>
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
android:id="@+id/connectivityBanner"
|
android:id="@+id/connectivityBanner"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="#C62828"
|
android:background="?attr/colorErrorContainer"
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="?attr/colorOnErrorContainer"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingTop="6dp"
|
android:paddingTop="6dp"
|
||||||
android:paddingBottom="6dp"
|
android:paddingBottom="6dp"
|
||||||
|
|||||||
@@ -48,12 +48,28 @@
|
|||||||
android:paddingBottom="16dp"
|
android:paddingBottom="16dp"
|
||||||
android:clipToPadding="false" />
|
android:clipToPadding="false" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/skeletonContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/emptyView"
|
android:id="@+id/emptyView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="No transactions found"
|
android:text="@string/transactions_empty"
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||||
android:textColor="?attr/colorOnSurfaceVariant"
|
android:textColor="?attr/colorOnSurfaceVariant"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="No recent transfers"
|
android:text="@string/activities_empty"
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||||
android:textColor="?attr/colorOnSurfaceVariant"
|
android:textColor="?attr/colorOnSurfaceVariant"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:cardCornerRadius="16dp"
|
app:cardCornerRadius="@dimen/card_radius_lg"
|
||||||
app:strokeWidth="1dp"
|
app:strokeWidth="1dp"
|
||||||
app:strokeColor="?attr/colorOutline">
|
app:strokeColor="?attr/colorOutline">
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:cardCornerRadius="16dp"
|
app:cardCornerRadius="@dimen/card_radius_lg"
|
||||||
app:strokeWidth="1dp"
|
app:strokeWidth="1dp"
|
||||||
app:strokeColor="?attr/colorOutline">
|
app:strokeColor="?attr/colorOutline">
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:cardCornerRadius="16dp"
|
app:cardCornerRadius="@dimen/card_radius_lg"
|
||||||
app:strokeWidth="1dp"
|
app:strokeWidth="1dp"
|
||||||
app:strokeColor="?attr/colorOutline">
|
app:strokeColor="?attr/colorOutline">
|
||||||
|
|
||||||
|
|||||||
@@ -117,8 +117,8 @@
|
|||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
app:cardBackgroundColor="?attr/colorSecondaryContainer"
|
app:cardBackgroundColor="?attr/colorSecondaryContainer"
|
||||||
app:cardCornerRadius="12dp"
|
app:cardCornerRadius="@dimen/card_radius_md"
|
||||||
app:cardElevation="0dp">
|
app:cardElevation="@dimen/card_elevation_flat">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="16dp">
|
android:padding="@dimen/screen_margin">
|
||||||
|
|
||||||
<!-- Balance cards row -->
|
<!-- Balance cards row -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
app:cardElevation="1dp"
|
app:cardElevation="@dimen/card_elevation_raised"
|
||||||
app:cardCornerRadius="12dp">
|
app:cardCornerRadius="@dimen/card_radius_md">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -56,7 +56,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="MVR —"
|
android:text="MVR —"
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium" />
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -67,8 +68,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
app:cardElevation="1dp"
|
app:cardElevation="@dimen/card_elevation_raised"
|
||||||
app:cardCornerRadius="12dp">
|
app:cardCornerRadius="@dimen/card_radius_md">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -89,7 +90,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="USD —"
|
android:text="USD —"
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium" />
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -112,8 +114,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
app:cardElevation="1dp"
|
app:cardElevation="@dimen/card_elevation_raised"
|
||||||
app:cardCornerRadius="12dp">
|
app:cardCornerRadius="@dimen/card_radius_md">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -134,7 +136,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="MVR —"
|
android:text="MVR —"
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium" />
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -146,8 +149,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
app:cardElevation="1dp"
|
app:cardElevation="@dimen/card_elevation_raised"
|
||||||
app:cardCornerRadius="12dp">
|
app:cardCornerRadius="@dimen/card_radius_md">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -168,7 +171,108 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="USD —"
|
android:text="USD —"
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium" />
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Attention row: Blocked + Overdue (hidden when nothing applies) -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/rowAttention"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/cardBlocked"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
app:cardElevation="@dimen/card_elevation_raised"
|
||||||
|
app:cardCornerRadius="@dimen/card_radius_md"
|
||||||
|
app:cardBackgroundColor="?attr/colorErrorContainer"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/dashboard_blocked"
|
||||||
|
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||||
|
android:textColor="?attr/colorOnErrorContainer" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvBlockedTotal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:text="MVR —"
|
||||||
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
|
android:textColor="?attr/colorOnErrorContainer"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvBlockedSecondary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||||
|
android:textColor="?attr/colorOnErrorContainer"
|
||||||
|
android:fontFeatureSettings="tnum"
|
||||||
|
android:alpha="0.75"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/cardOverdue"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
app:cardElevation="@dimen/card_elevation_raised"
|
||||||
|
app:cardCornerRadius="@dimen/card_radius_md"
|
||||||
|
app:cardBackgroundColor="?attr/colorErrorContainer"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/dashboard_overdue"
|
||||||
|
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||||
|
android:textColor="?attr/colorOnErrorContainer" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvOverdueTotal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:text="MVR —"
|
||||||
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
|
android:textColor="?attr/colorOnErrorContainer"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -182,8 +286,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
app:cardElevation="1dp"
|
app:cardElevation="@dimen/card_elevation_raised"
|
||||||
app:cardCornerRadius="12dp"
|
app:cardCornerRadius="@dimen/card_radius_md"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true">
|
android:focusable="true">
|
||||||
|
|
||||||
@@ -206,7 +310,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="MVR —"
|
android:text="MVR —"
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium" />
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:cardCornerRadius="16dp"
|
app:cardCornerRadius="@dimen/card_radius_lg"
|
||||||
app:strokeWidth="1dp"
|
app:strokeWidth="1dp"
|
||||||
app:strokeColor="?attr/colorOutline">
|
app:strokeColor="?attr/colorOutline">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:cardCornerRadius="16dp"
|
app:cardCornerRadius="@dimen/card_radius_lg"
|
||||||
app:strokeWidth="1dp"
|
app:strokeWidth="1dp"
|
||||||
app:strokeColor="?attr/colorOutline">
|
app:strokeColor="?attr/colorOutline">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -45,22 +45,30 @@
|
|||||||
|
|
||||||
</com.google.android.material.button.MaterialButtonToggleGroup>
|
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||||
|
|
||||||
<!-- Quick actions (always active) -->
|
<!-- Quick actions — shown only when drawer nav is active -->
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/sectionQuickActions"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/dashboard_quick_actions"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginBottom="12dp" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/rvQuickActions"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nestedScrollingEnabled="false"
|
android:orientation="vertical"
|
||||||
android:overScrollMode="never"
|
android:layout_marginBottom="16dp">
|
||||||
android:layout_marginBottom="16dp" />
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/dashboard_quick_actions"
|
||||||
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rvQuickActions"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:nestedScrollingEnabled="false"
|
||||||
|
android:overScrollMode="never" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Bottom bar shortcuts — shown only when bottom nav is active -->
|
<!-- Bottom bar shortcuts — shown only when bottom nav is active -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -49,12 +49,28 @@
|
|||||||
android:paddingBottom="16dp"
|
android:paddingBottom="16dp"
|
||||||
android:clipToPadding="false" />
|
android:clipToPadding="false" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/skeletonContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
<include layout="@layout/item_skeleton_transaction" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/emptyView"
|
android:id="@+id/emptyView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="No transactions found"
|
android:text="@string/transactions_empty"
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||||
android:textColor="?attr/colorOnSurfaceVariant"
|
android:textColor="?attr/colorOnSurfaceVariant"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="@dimen/list_item_padding_h"
|
||||||
android:paddingVertical="14dp"
|
android:paddingVertical="@dimen/list_item_padding_v"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:foreground="?attr/selectableItemBackground">
|
android:foreground="?attr/selectableItemBackground">
|
||||||
|
|
||||||
@@ -70,7 +70,18 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
android:textAppearance="?attr/textAppearanceTitleSmall"
|
||||||
android:textColor="?attr/colorOnSurface" />
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvBlocked"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||||
|
android:textColor="?attr/colorError"
|
||||||
|
android:fontFeatureSettings="tnum"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/btnTransfer"
|
android:id="@+id/btnTransfer"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
app:shapeAppearanceOverlay="@style/ShapeAppearance.Circle"
|
app:shapeAppearanceOverlay="@style/ShapeAppearance.Circle"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto" />
|
xmlns:app="http://schemas.android.com/apk/res-auto" />
|
||||||
|
|
||||||
@@ -49,7 +50,8 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||||
android:textColor="?attr/colorOnSurface" />
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="12dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
app:cardCornerRadius="16dp"
|
app:cardCornerRadius="@dimen/card_radius_lg"
|
||||||
app:cardElevation="0dp"
|
app:cardElevation="@dimen/card_elevation_flat"
|
||||||
app:strokeWidth="1dp"
|
app:strokeWidth="1dp"
|
||||||
app:strokeColor="?attr/colorOutlineVariant">
|
app:strokeColor="?attr/colorOutlineVariant">
|
||||||
|
|
||||||
@@ -114,7 +114,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
android:textColor="?attr/colorOnSurface"
|
android:textColor="?attr/colorOnSurface"
|
||||||
android:layout_marginTop="2dp" />
|
android:layout_marginTop="2dp"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -137,7 +138,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
android:textColor="?attr/colorOnSurface"
|
android:textColor="?attr/colorOnSurface"
|
||||||
android:layout_marginTop="2dp" />
|
android:layout_marginTop="2dp"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -162,7 +164,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
android:textColor="?attr/colorError"
|
android:textColor="?attr/colorError"
|
||||||
android:layout_marginTop="2dp" />
|
android:layout_marginTop="2dp"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
app:cardCornerRadius="16dp"
|
android:clickable="true"
|
||||||
app:cardElevation="0dp"
|
android:focusable="true"
|
||||||
|
app:cardCornerRadius="@dimen/card_radius_lg"
|
||||||
|
app:cardElevation="@dimen/card_elevation_flat"
|
||||||
app:strokeWidth="1dp"
|
app:strokeWidth="1dp"
|
||||||
app:strokeColor="?attr/colorOutlineVariant">
|
app:strokeColor="?attr/colorOutlineVariant">
|
||||||
|
|
||||||
@@ -51,11 +53,7 @@
|
|||||||
android:id="@+id/tvLoanStatus"
|
android:id="@+id/tvLoanStatus"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="10dp"
|
style="@style/Widget.App.StatusChip" />
|
||||||
android:paddingVertical="4dp"
|
|
||||||
android:background="@drawable/chip_background"
|
|
||||||
android:textAppearance="?attr/textAppearanceLabelSmall"
|
|
||||||
android:textColor="?attr/colorOnSecondaryContainer" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="@dimen/list_item_padding_h"
|
||||||
android:paddingVertical="14dp"
|
android:paddingVertical="@dimen/list_item_padding_v"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:foreground="?attr/selectableItemBackground">
|
android:foreground="?attr/selectableItemBackground">
|
||||||
|
|
||||||
@@ -83,7 +83,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
android:textAppearance="?attr/textAppearanceTitleSmall"
|
||||||
android:textColor="?attr/colorOnSurface"
|
android:textColor="?attr/colorOnSurface"
|
||||||
android:layout_marginTop="6dp" />
|
android:layout_marginTop="6dp"
|
||||||
|
android:fontFeatureSettings="tnum" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/btnTransfer"
|
android:id="@+id/btnTransfer"
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
app:cardCornerRadius="16dp"
|
android:clickable="true"
|
||||||
app:cardElevation="0dp"
|
android:focusable="true"
|
||||||
|
app:cardCornerRadius="@dimen/card_radius_lg"
|
||||||
|
app:cardElevation="@dimen/card_elevation_flat"
|
||||||
app:strokeWidth="1dp"
|
app:strokeWidth="1dp"
|
||||||
app:strokeColor="?attr/colorOutlineVariant">
|
app:strokeColor="?attr/colorOutlineVariant">
|
||||||
|
|
||||||
@@ -51,11 +53,7 @@
|
|||||||
android:id="@+id/tvStatus"
|
android:id="@+id/tvStatus"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="10dp"
|
style="@style/Widget.App.StatusChip" />
|
||||||
android:paddingVertical="4dp"
|
|
||||||
android:background="@drawable/chip_background"
|
|
||||||
android:textAppearance="?attr/textAppearanceLabelSmall"
|
|
||||||
android:textColor="?attr/colorOnSecondaryContainer" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
app:cardElevation="1dp"
|
android:clickable="true"
|
||||||
app:cardCornerRadius="12dp">
|
android:focusable="true"
|
||||||
|
app:cardElevation="@dimen/card_elevation_raised"
|
||||||
|
app:cardCornerRadius="@dimen/card_radius_md">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -5,15 +5,16 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="@dimen/list_item_padding_h"
|
||||||
android:paddingVertical="14dp"
|
android:paddingVertical="@dimen/list_item_padding_v"
|
||||||
android:background="?attr/selectableItemBackground">
|
android:background="?attr/selectableItemBackground">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/ivIcon"
|
android:id="@+id/ivIcon"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:layout_marginEnd="16dp" />
|
android:layout_marginEnd="16dp"
|
||||||
|
android:importantForAccessibility="no" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
android:id="@+id/ivNavIcon"
|
android:id="@+id/ivNavIcon"
|
||||||
android:layout_width="28dp"
|
android:layout_width="28dp"
|
||||||
android:layout_height="28dp"
|
android:layout_height="28dp"
|
||||||
android:layout_marginBottom="6dp" />
|
android:layout_marginBottom="6dp"
|
||||||
|
android:importantForAccessibility="no" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvNavLabel"
|
android:id="@+id/tvNavLabel"
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
app:cardCornerRadius="16dp"
|
app:cardCornerRadius="@dimen/card_radius_lg"
|
||||||
app:cardElevation="2dp">
|
app:cardElevation="@dimen/card_elevation_raised">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
android:layout_width="44dp"
|
android:layout_width="44dp"
|
||||||
android:layout_height="44dp"
|
android:layout_height="44dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
app:shapeAppearanceOverlay="@style/ShapeAppearance.Circle" />
|
app:shapeAppearanceOverlay="@style/ShapeAppearance.Circle" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -53,6 +54,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||||
android:textColor="?attr/colorOnSurface"
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:fontFeatureSettings="tnum"
|
||||||
android:paddingHorizontal="8dp"
|
android:paddingHorizontal="8dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,6 @@
|
|||||||
android:id="@+id/tvProfileType"
|
android:id="@+id/tvProfileType"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="10dp"
|
style="@style/Widget.App.StatusChip" />
|
||||||
android:paddingVertical="4dp"
|
|
||||||
android:background="@drawable/chip_background"
|
|
||||||
android:textAppearance="?attr/textAppearanceLabelSmall"
|
|
||||||
android:textColor="?attr/colorOnSecondaryContainer" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
android:textAppearance="?attr/textAppearanceTitleSmall"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:fontFeatureSettings="tnum"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@id/fvAvatar"
|
app:layout_constraintTop_toTopOf="@id/fvAvatar"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/fvAvatar" />
|
app:layout_constraintBottom_toBottomOf="@id/fvAvatar" />
|
||||||
|
|||||||
@@ -65,8 +65,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:cardCornerRadius="12dp"
|
app:cardCornerRadius="@dimen/card_radius_md"
|
||||||
app:cardElevation="2dp">
|
app:cardElevation="@dimen/card_elevation_raised">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -5,4 +5,36 @@
|
|||||||
<dimen name="nav_header_vertical_spacing">8dp</dimen>
|
<dimen name="nav_header_vertical_spacing">8dp</dimen>
|
||||||
<dimen name="nav_header_height">176dp</dimen>
|
<dimen name="nav_header_height">176dp</dimen>
|
||||||
<dimen name="fab_margin">16dp</dimen>
|
<dimen name="fab_margin">16dp</dimen>
|
||||||
</resources>
|
|
||||||
|
<!-- ====== Design tokens ======================================== -->
|
||||||
|
|
||||||
|
<!-- Card surfaces.
|
||||||
|
Two-tier radius:
|
||||||
|
lg → hero/standalone cards (bank tiles, history header, finance deals, OTP cards)
|
||||||
|
md → repeating row/summary cards (dashboard cards, foreign limit, bottom sheets)
|
||||||
|
Card-visual representations (item_card_*) keep their own larger radius/elevation
|
||||||
|
to read as real credit cards — they are not tokenized. -->
|
||||||
|
<dimen name="card_radius_lg">16dp</dimen>
|
||||||
|
<dimen name="card_radius_md">12dp</dimen>
|
||||||
|
|
||||||
|
<!-- Card elevation. Two tiers:
|
||||||
|
flat → outlined cards (paired with a colorOutlineVariant stroke)
|
||||||
|
raised → subtle Material 3 default raise
|
||||||
|
Larger elevations belong to specific card-visual surfaces only. -->
|
||||||
|
<dimen name="card_elevation_flat">0dp</dimen>
|
||||||
|
<dimen name="card_elevation_raised">1dp</dimen>
|
||||||
|
|
||||||
|
<!-- Screen-level spacing -->
|
||||||
|
<dimen name="screen_margin">16dp</dimen>
|
||||||
|
<dimen name="section_gap">16dp</dimen>
|
||||||
|
|
||||||
|
<!-- Standard list/row padding -->
|
||||||
|
<dimen name="list_item_padding_h">16dp</dimen>
|
||||||
|
<dimen name="list_item_padding_v">14dp</dimen>
|
||||||
|
|
||||||
|
<!-- Gutters: small inline spacing units -->
|
||||||
|
<dimen name="gutter_xs">2dp</dimen>
|
||||||
|
<dimen name="gutter_sm">4dp</dimen>
|
||||||
|
<dimen name="gutter_md">8dp</dimen>
|
||||||
|
<dimen name="gutter_lg">12dp</dimen>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -208,6 +208,9 @@
|
|||||||
<string name="accounts">Accounts</string>
|
<string name="accounts">Accounts</string>
|
||||||
<string name="cards">Cards</string>
|
<string name="cards">Cards</string>
|
||||||
<string name="available_balance">Available Balance</string>
|
<string name="available_balance">Available Balance</string>
|
||||||
|
<string name="account_blocked_label">%1$s blocked</string>
|
||||||
|
<string name="dashboard_blocked">Blocked Funds</string>
|
||||||
|
<string name="dashboard_overdue">Overdue Financing</string>
|
||||||
|
|
||||||
<!-- Transfer -->
|
<!-- Transfer -->
|
||||||
<string name="transfer_tab_quick">Quick Transfer</string>
|
<string name="transfer_tab_quick">Quick Transfer</string>
|
||||||
@@ -252,6 +255,8 @@
|
|||||||
|
|
||||||
<!-- Accounts -->
|
<!-- Accounts -->
|
||||||
<string name="accounts_empty">No accounts found</string>
|
<string name="accounts_empty">No accounts found</string>
|
||||||
|
<string name="activities_empty">No recent transfers</string>
|
||||||
|
<string name="transactions_empty">No transactions found</string>
|
||||||
|
|
||||||
<!-- Contacts -->
|
<!-- Contacts -->
|
||||||
<string name="contacts_empty">No contacts found</string>
|
<string name="contacts_empty">No contacts found</string>
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<style name="ShapeAppearance.Circle" parent="ShapeAppearance.Material3.Corner.Full" />
|
<style name="ShapeAppearance.Circle" parent="ShapeAppearance.Material3.Corner.Full" />
|
||||||
|
|
||||||
|
<!-- Reusable status chip (filled, secondary container). Apply to a TextView via style. -->
|
||||||
|
<style name="Widget.App.StatusChip" parent="">
|
||||||
|
<item name="android:paddingHorizontal">10dp</item>
|
||||||
|
<item name="android:paddingVertical">4dp</item>
|
||||||
|
<item name="android:background">@drawable/chip_background</item>
|
||||||
|
<item name="android:textAppearance">?attr/textAppearanceLabelSmall</item>
|
||||||
|
<item name="android:textColor">?attr/colorOnSecondaryContainer</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="Theme.BasedBank" parent="Theme.Material3.DayNight.NoActionBar">
|
<style name="Theme.BasedBank" parent="Theme.Material3.DayNight.NoActionBar">
|
||||||
<item name="colorPrimary">@color/seed_primary</item>
|
<item name="colorPrimary">@color/seed_primary</item>
|
||||||
<item name="colorSecondary">@color/seed_secondary</item>
|
<item name="colorSecondary">@color/seed_secondary</item>
|
||||||
|
|||||||