# 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)