Files
fksar/docs/thijooree/22-cards.md
T
2026-06-13 21:30:12 +05:00

101 lines
4.3 KiB
Markdown

# Cards
Unified card management screen for both MIB and BML cards. Supports a horizontally-paged stack, freeze / unfreeze, default-card and hide-from-dashboard toggles, and launches the [Tap to Pay](23-tap-to-pay.md) NFC flow.
---
## Fragment — `CardsFragment`
File: `ui/home/PayWithCardFragment.kt`. Bound to nav id `R.id.nav_pay_with_card`.
Opened via:
- Navigation slot ("Cards")
- `OPEN_PAY_WITH_CARD` intent
- `TAP_TO_PAY` intent — auto-enters tap mode for the user's default BML card
- Dashboard NFC button — auto-enters tap mode for the selected card
`newInstanceWithAutoTapMode(accountNumber? = null)` (`PayWithCardFragment.kt:1203-1208`) is the factory for the auto-tap entry points.
---
## Card Stack
A horizontal `RecyclerView` driven by `CardStackAdapter` with a `PagerSnapHelper`. Off-centre cards are scaled to 82% and faded to 60% via `applyCardScales()`. Page dots beneath the stack are rebuilt on each scroll-idle.
### Sources
`rebuildCards()` (`PayWithCardFragment.kt:894-958`) merges two lists:
- BML: `viewModel.accounts` filtered to `profileType in (BML_PREPAID, BML_CREDIT, BML_DEBIT)`
- MIB: `viewModel.mibCards`
The combined order is `bmlActive + mibActive + bmlInactive + mibInactive`. The user's default card (`CredentialStore.getDefaultCardAccountNumber()`) is moved to position 0. Initial data is seeded from `CardsCache` so the stack appears immediately; a background `HomeActivity.triggerRefreshCards()` refreshes it.
### Card Art
| Source | Asset path |
|---|---|
| MIB `cardType` → asset | `CardsFragment.cardImageAsset(card)``51``cards/mib/faisa_card.png`, `53``visa_black_platinum.png`, `57``visa_blue_everyday.png`, `70``visa_business.png`, `701/702``visa_bingaa_mvr.png` / `visa_bingaa_usd.png` |
| BML | `BmlCardParser.cardImageAsset(account)` |
Status chips use `bindCardStatus(...)`. MIB statuses: `CHST0` = active (no chip), `CHST20` = "Temporary blocked by client", other values shown verbatim.
---
## Pay Buttons
| Button | Behaviour |
|---|---|
| Scan to Pay (`btnScanToPay`) | Launches [QrScannerActivity](25-qr-scanner.md). BML cards route the result to `TransferFragment` (BML QR mode or PayMV pre-fill). MIB cards show "not supported" |
| Tap to Pay (`btnTapToPay`) | `NfcPaymentUtil.checkAndProceed(...)`. If `biometrics_transfer_confirm` is on, shows a `BIOMETRIC_STRONG` prompt first, then enters tap mode. MIB cards show "not supported" |
---
## Manage Mode
Toggle: `btnManageCard`. Animates the focused card up into a single full-width "manage card" panel, hides the carousel, and exposes:
| Control | Effect |
|---|---|
| Default card switch | `CredentialStore.setDefaultCardAccountNumber()` — BML only |
| Hide from dashboard switch | `CredentialStore.setCardHiddenFromDashboard(accountNumber, hidden)` |
| Freeze / Unfreeze | BML: `BmlCardClient.setCardFreezeState(session, internalId, "freeze"/"unfreeze")`. MIB: prompts for a comments string, then `MibCardsClient().setCardFreezeState(session, cardId, action, comments)` serialised through `app.mibMutex` with a profile switch first |
| Change PIN / Block | Wired but currently shows a "work in progress" toast |
Manage mode can be dismissed by tapping the button again or swipe-down on the manage card.
---
## Tap Mode
Entered via `setTapMode(true, item)`. Hides the carousel, animates the selected card to the top, draws an `NfcTapAnimationView` and a Cancel button.
`fetchAndArmToken()`:
1. Generates a TOTP from the BML OTP seed
2. `BmlTapToPayClient().fetchTokens(session, internalId, otp)` returns a single-use `BmlWalletToken`
3. `BmlHostCardEmulatorService.setToken(token)`
4. Sets `BmlHostCardEmulatorService.onTransactionComplete` — on success shows a "Payment complete" toast and refreshes balances
Exiting tap mode clears the token and the callback. See [Tap to Pay](23-tap-to-pay.md) for the HCE protocol details.
---
## Inactive Cards
Inactive cards remain in the stack at 45% alpha. Tap-to-pay and "default card" are disabled for them. Hide-from-dashboard is force-enabled and locked on for inactive cards (`PayWithCardFragment.kt:522-530`).
---
## Back Handling
`onBackPressed()` returns `true` while in manage mode or tap mode so `HomeActivity` does not pop the back stack — instead the fragment exits the current mode.
---
 
---
[← Dashboard](21-dashboard.md)     **Next →** [Tap to Pay](23-tap-to-pay.md)