Compare commits

...
13 Commits
Author SHA1 Message Date
ahusanandClaude Opus 4.7 045eb1b1a2 ui: pass 3 — skeleton loading, a11y, snackbars, dark mode
Skeleton loading state:
  * Wire item_skeleton_transaction (previously dormant in res) into
    AccountHistoryFragment and TransferHistoryFragment. When a load
    starts with no cached transactions, 8 skeleton rows appear under
    the search bar instead of a blank screen. Skeleton hides as soon
    as transactions arrive or the load completes.
  * Decision: ActivitiesFragment loads from local storage synchronously,
    so no skeleton there — would only flash for a frame.

Accessibility:
  * Decorative icons in item_more_nav, item_nav_slot, item_picker_row,
    and item_account_dropdown now declare importantForAccessibility="no"
    so TalkBack skips them (the adjacent text label conveys meaning).
  * Also added tnum to item_picker_row.tvBalance and
    item_account_dropdown.tvDropdownBalance — missed amounts from Pass 2.

Snackbar:
  * ContactsFragment.deleteContact's success/failure feedback is now
    a Snackbar instead of Toast — the fragment stays visible, so a
    bottom-anchored Snackbar fits better than a floating Toast.
  * Other Toasts are either followed by navigation away (Snackbar
    couldn't display), or purely informational ("copied", "press back
    to exit") where Toast is the right primitive. Left as-is.

Dark mode:
  * Connectivity banner in activity_home no longer hardcodes
    #C62828 / #FFFFFF — uses colorErrorContainer / colorOnErrorContainer
    so it adapts to the user's theme.
  * Other hex literals (card-artwork text, receipt screens that
    intentionally emulate paper) are intentional and stay.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 18:02:50 +05:00
ahusanandClaude Opus 4.7 22806da1b3 ui: pass 2 — pill style, tabular figures, ripple feedback, empty strings
Status pills:
  * New Widget.App.StatusChip style bundling the 10dp/4dp padding +
    chip_background + label-small text used in 3 places (item_bml_loan,
    item_finance_deal, item_profile_header). The 3 layouts now apply
    the style instead of repeating 4 attributes each.
  * Extract the bindCardStatus card-overlay pill background from inline
    GradientDrawable code into a real drawable resource
    (card_overlay_pill_bg.xml). PayWithCardFragment.bindCardStatus just
    sets a background resource now.

Tabular figures (android:fontFeatureSettings="tnum"):
  * Applied to amount TextViews on the highest-traffic surfaces —
    transactions list, accounts list, card list, dashboard balance /
    credit / blocked / overdue / pending finances totals, and the
    account history header (available / balance / blocked).
  * Digits become same-width, so right-aligned amounts in a column
    line up.

Ripple feedback:
  * item_finance_deal, item_bml_loan, item_foreign_limit get
    android:clickable="true" android:focusable="true" so their
    MaterialCardView roots show the M3 ripple when the adapter
    attaches a click listener. All three are clickable from code
    but were missing the ripple cue.

Empty-state strings:
  * Hardcoded "No recent transfers" / "No transactions found" in
    fragment_activities, fragment_transfer_history, and
    fragment_account_history moved to strings.xml as
    activities_empty / transactions_empty, matching the existing
    accounts_empty / contacts_empty / financing_empty pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 17:48:23 +05:00
ahusanandClaude Opus 4.7 29ac4352ff ui: swap list-item and screen-margin paddings onto tokens
Replaces hardcoded paddings in the three layouts that share the
standard 16dp/14dp list-row pattern (item_account, item_card,
item_more_nav) with @dimen/list_item_padding_h / list_item_padding_v.

Dashboard root content padding becomes @dimen/screen_margin. Card
content paddings inside the dashboard are left as raw 16dp — they're
a separate semantic (card-interior padding, not screen edge) and
will be addressed once we either need a distinct token or have a
reason to change them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 17:32:18 +05:00
ahusanandClaude Opus 4.7 df892ec8d5 ui: tokenize card surfaces in dimens.xml and sweep layouts
Introduces a small set of design tokens for card surfaces so the same
look is enforced everywhere instead of being hand-tuned per layout:

  card_radius_lg / card_radius_md       — 16dp / 12dp two-tier radius
  card_elevation_flat / *_raised        — 0dp outlined / 1dp subtle raise

Sweeps the existing layouts onto these tokens. Two-tier policy:

  lg → hero/standalone cards (account history header, bml loan,
       finance deal, otp card, bank selection tiles, security setup
       options)
  md → repeating row/summary cards (dashboard summary cards,
       credentials inset, foreign limit, add-contact sheet)

Card-visual representations (item_card_dashboard / _stack / _wallet
/ _settings_entry) deliberately keep their bespoke radius/elevation
so they continue to read as credit cards — the tokens are for
content cards only. Tight inset frames inside fragment_bml_qr_pay
and fragment_transfer also remain on 4dp/0dp as form details.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 17:20:16 +05:00
shihaam 5cba468781 debug builds has debug suffix and different launcher icon color 2026-05-28 17:11:55 +05:00
shihaam ed2054fb81 fixbug that took user to empty dashboard without any accounts 2026-05-28 16:32:06 +05:00
shihaamandshihaam e9583f0580 Merge pull request 'fix/accounts-list-balance-consistency' (#5) from ahusan/fksar:fix/accounts-list-balance-consistency into main
Reviewed-on: shihaam/thijooree#5
2026-05-28 16:23:33 +05:00
shihaam a32841a319 compress images 2026-05-28 15:58:26 +05:00
shihaam 7a66dd836c add faisawear images (intergration later) 2026-05-28 15:57:23 +05:00
shihaam 68dd49b90c rename fisa to fisa card 2026-05-28 15:55:49 +05:00
ahusan 8d09e760a8 Enhance dashboard: add attention row for blocked and overdue funds
Introduces a new attention row in the dashboard to display blocked funds and overdue financing. The row is conditionally visible based on the presence of blocked amounts or overdue totals. Updates the account display logic to show blocked amounts where applicable, ensuring users have a clear view of their financial status. Additionally, new string resources for "Blocked Funds" and "Overdue Financing" are added for localization.
2026-05-28 15:24:49 +05:00
ahusanandClaude Opus 4.7 62ccae602d accounts list: use available balance, show blocked amount as secondary line
BML CASA rows on the accounts list were showing currentBalance (the
working/ledger balance, which includes blocked funds). Every other
balance display in the app — transfer screen, contact picker, QR pay,
dashboard totals — uses availableBalance, so the same account was
showing a different figure depending on where you looked at it.

This switches the accounts list to availableBalance for consistency,
and adds a small muted "MVR X.XX blocked" line beneath the balance
when blocked > 0 so the blocked funds are still visible at a glance.
Only BML reports a non-zero blocked amount; MIB and Fahipay rows are
unaffected.

The per-account history page header is untouched — its three-column
Available / Balance / Blocked breakdown still works as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 14:54:33 +05:00
ahusanandClaude Opus 4.7 9011ef2f5a debug builds: separate applicationId so they coexist with release
Adds applicationIdSuffix=.debug and versionNameSuffix=-debug so a
side-loaded debug build can be installed alongside the Play/release
build without conflicting on package id.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 14:53:45 +05:00
81 changed files with 505 additions and 130 deletions
+4
View File
@@ -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>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Thijooree Debug</string>
</resources>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 KiB

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 KiB

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 KiB

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 KiB

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

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>
+2 -2
View File
@@ -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"
+121 -16
View File
@@ -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" />
+14 -3
View File
@@ -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 -7
View File
@@ -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>
+4 -3
View File
@@ -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"
+4 -3
View File
@@ -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"
+2 -1
View File
@@ -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"
+2 -2
View File
@@ -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"
+33 -1
View File
@@ -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>
+5
View File
@@ -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>
+9
View File
@@ -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>