Skip to content

feat: home screen hardware wallet ui#999

Draft
ovitrif wants to merge 45 commits into
masterfrom
feat/home-hw-wallet-ui
Draft

feat: home screen hardware wallet ui#999
ovitrif wants to merge 45 commits into
masterfrom
feat/home-hw-wallet-ui

Conversation

@ovitrif

@ovitrif ovitrif commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Part of #998

This PR brings the first slice of the Trezor hardware wallet epic to the wallet home screen. A paired Trezor now shows up as a watch-only balance: a device row under the Savings/Spending tiles, its sats folded into the headline total, and its on-chain transactions merged into the recent activity list. A new Hardware suggestion card prompts users with no paired device to start connecting.

Description

  • Adds a full-width hardware-wallet row beneath the Savings/Spending tiles showing the device name, a real-time Bluetooth/USB connection indicator (green when linked, grey otherwise), a blue bitcoin icon, and the watch-only balance. The hardware balance is included in the headline total.
  • Merges the device's on-chain activity into the home recent-activity list and the All Activity screen, with blue hardware-wallet icon variants distinguishing those rows from regular on-chain activity. The All Activity filters apply to hardware items too: Sent/Received tabs and date range match them, while tag filters and the Other tab exclude them (no tags, no transfers yet).
  • Adds the Hardware / Connect device suggestion card, shown only while no device is paired. Tapping it opens the connect-flow sheet with the final intro screen per Figma (Trezor + Ledger visuals, localized copy, Cancel) — Continue stays disabled until the connect flow lands in its dedicated subtask. Tapping the hardware row shows a not-yet-implemented notice for the hardware overview screen (also a later subtask).
  • Opens the standard activity detail for hardware-wallet items tapped on the home list, resolving them from the watch-only data when they are not in the activity database (blue icon included).
  • Introduces a watch-only data layer: balances and activity stream from the on-chain xpub watcher from feat: add trezor onchain event watcher #976, with one watcher per monitored address type per device (honouring Settings ▸ Advanced ▸ Address Type, same as the on-chain wallet), aggregated per device. Account xpubs for all address types are captured on connect and persisted, so balances show while the device is disconnected and toggling a type on later starts watching it without reconnecting.
  • Fixes stale Trezor connection status by detecting the phone's Bluetooth being switched off and USB unplug, so the indicator reflects reality in real time. Disconnect events are now observed for the whole app lifetime — previously they were only collected while the dev Trezor screen was open.
  • Auto-reconnects to a known device when its transport comes back: Bluetooth re-enabled (adapter broadcast) or the Trezor plugged back in (USB attach is an activity intent delivered via the OS app picker, handled in the main activity — tapping "Always" makes future replugs fully automatic). Stored pairing credentials make the connect prompt-free, so the indicator recovers to green on its own.
  • Fixes the Trezor restarting PIN/pairing entry mid-typing: a transport event (USB attach, Bluetooth on) could trigger auto-reconnect during a live handshake, whose half-open session looks identical to a stale one, so the reset dropped the session being authenticated. Auto-reconnect now backs off while any connect is in progress or the device awaits PIN/pairing input — including connects started from the dev Trezor screen. Reconnect triggers are also serialized into a single in-flight retry loop: a Trezor re-enumerates USB during its unlock flow, so one replug delivers several attach intents, and uncoordinated loops kept restarting the device's PIN entry for the first seconds after plugging in. Reconnects also prefer the transport that came back, so a USB replug does not reconnect over BLE when the same device is paired on both.
  • Fixes a native crash (SIGSEGV in libusbhost) when a USB-connected device responded after a read timeout: timed-out async UsbRequests were closed while their URB was still queued in the kernel, which then wrote into freed memory once data arrived. USB reads/writes now use synchronous bulkTransfer, eliminating the request-lifetime race.
  • Adds a Pair Device sheet shown app-wide whenever the device requests its one-time security code mid-connect (pairing credentials are per transport, so e.g. the first USB connect after BLE pairing asks again): instruction text, visible 6-digit code entry in fixed-width cells (digits replace placeholder dots without layout shifts) on the app numpad — hardware keyboards work too — auto-submit when complete, swipe-down cancels the request. The dev Trezor screen now uses this sheet too — its old pairing dialog is removed.
  • Shows the receive confetti for new hw wallet txs.
    The initial history sync after a watcher starts is treated as a baseline, so only transactions arriving while watching trigger the sheet.
  • Syncs suggestion cards with the v61 design
    • Invite uses green instead of blue
    • Profile uses the brand tint
    • Hardware sits before Shop in the default set
  • Shows the same physical device paired over both bluetooth and usb as one wallet
    Identifies by xpubs, ensures balance and activity isn't duped. The default tile name is the vendor-prefixed model (e.g. "Trezor Safe 7") unless a custom on-device label is set.
  • General UI: Large sheets now reserve the full home toolbar block plus clearance instead of overlapping its bottom edge, so the toolbar stays visible above large sheets app-wide (Receive, hardware connect, etc.).

Preview

BLE USB
trezorBle2x.mp4
trezorUsb2x.mp4
Receive Suggestions
receive2x.mp4

Edge Cases & State Variants

Same Trezor 2x BLE+USB Activity, Icons, Sheet
trezorViaBle.Usb2x.mp4
trezorActivity2x.mp4

QA Notes

Manual Tests

  • 1. No paired device → Home: no hardware row, Hardware device suggestion card shown.
  • 2. Tap the Hardware suggestion card: connect intro sheet opens (device visuals, Cancel works, Continue disabled).
  • 3. Connect a Trezor device (dev Trezor screen or Bridge emulator) → Home: hardware row appears with device name, blue BTC icon and balance; headline total includes the hardware balance; recent device transactions appear in the activity list with blue icons.
  • 4a. BLE-connected device → disable phone Bluetooth: indicator turns grey, balance stays visible.
    • 4b. re-enable Bluetooth: indicator turns green again on its own (auto-reconnect, no pairing prompt).
  • 5a. USB-connected device → unplug it: indicator turns grey, balance stays visible.
    • 5b. plug it back in: indicator turns green again on its own (auto-reconnect, no pairing prompt).
    • 5c. if the device asks for its one-time security code: Pair Device sheet opens with the app numpad; entering the code on-screen completes the connect; swipe-down dismiss cancels it.
    • 5d. same device also paired over BLE → replug USB: home tile shows the usb indicator green, not bluetooth.
  • 6. Tap the hardware row: not-yet-implemented toast shows.
  • 7. Tap a hardware activity item in the home list: Activity Detail opens with a blue icon.
  • 8. Watcher running → send sats to a trezor address from an external wallet: received sheet pops up once picked up; details button opens the activity.
  • 9. Pair the same Trezor over BLE and USB: home shows one tile named "Trezor ", balance and activity counted once; indicator reflects the connected transport (USB or BLE).
  • 10. Show All → All Activity: hardware activities listed with blue icons; Sent/Received tabs filter them; tag filter hides them.
  • 11. regression: open Receive and other large sheets: sheet top sits below the home toolbar, toolbar fully visible.

Automated Checks

  • Unit tests added: cover watch-only balance/activity aggregation per device, HistoryTransaction to Activity mapping, address-type monitor filtering, and the Env network pin in HwWalletRepoTest.kt.
  • Unit tests added: cover the per-device hardware balances and total getters in BalanceStateTest.kt.
  • Unit tests updated: wire the new HwWalletRepo dependency into WalletRepoTest.kt and DeriveBalanceStateUseCaseTest.kt.
  • Unit tests added: cover the hardware-wallet fallback and not-found path of activity detail loading in ActivityDetailViewModelTest.kt.
  • Unit tests added: cover received-tx detection (baseline sync, new inbound, outbound ignored, no re-emission) in HwWalletRepoTest.kt.
  • Unit tests added: cover cross-transport dedup (single wallet, single watcher, connected entry wins) and vendor-prefixed default names in HwWalletRepoTest.kt.
  • Unit tests added: cover external-disconnect clearing the connected device without any screen observing in TrezorRepoTest.kt.
  • Unit tests added: cover transport-restored auto-reconnect and its already-connected guard in TrezorRepoTest.kt. Also cover scan retries until the device advertises again and stale-session reset before scanning. The usb-attach intent chain is covered across TrezorRepoTest.kt, HwWalletRepoTest.kt, and AppViewModelSendFlowTest.kt.
  • Unit tests added: cover the auto-reconnect back-off during pending PIN/pairing entry, the single-loop serialization of repeated reconnect triggers, and the restored-transport preference in TrezorRepoTest.kt.
  • Unit tests added: cover the Pair Device sheet trigger (show/hide, high-priority sheet guard) and the pairing-code passthroughs in AppViewModelSendFlowTest.kt and HwWalletRepoTest.kt.
  • Unit tests added: cover the All Activity merge (newest-first ordering, tab filtering, tag-filter exclusion, hardware id exposure) in ActivityListViewModelTest.kt.
  • AI journeys added in .agents/journeys/ for the deterministic bitkit-docker Trezor Bridge emulator: connect + home tile, blue activity icons and filters, injected usb-attach auto-reconnect, and the suggestion card + intro sheet (see the folder README for scope and limits).
  • Ran locally: just compile, just test (full suite), just lint.

@ovitrif ovitrif added this to the 2.4.0 milestone Jun 9, 2026
@ovitrif ovitrif self-assigned this Jun 9, 2026
@ovitrif ovitrif force-pushed the feat/home-hw-wallet-ui branch 2 times, most recently from 490121b to a4dbd43 Compare June 9, 2026 15:18
@ovitrif

ovitrif commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

@greptile review

@greptile-apps

This comment has been minimized.

Comment thread app/src/main/java/to/bitkit/ui/sheets/HardwareSheet.kt Outdated
Comment thread app/src/main/java/to/bitkit/repositories/HwWalletRepo.kt Outdated
@ovitrif ovitrif mentioned this pull request Jun 9, 2026
28 tasks
@ovitrif ovitrif force-pushed the feat/home-hw-wallet-ui branch from 1d82489 to b301a77 Compare June 10, 2026 08:26
@ovitrif ovitrif force-pushed the feat/home-hw-wallet-ui branch from 0717842 to 0e6d5d7 Compare June 15, 2026 17:35
@ovitrif

ovitrif commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator Author

emptyWalletSuggestions is the only suggestion builder that does not receive hasHardwareWallet and does not include Suggestion.HARDWARE.takeIf { !hasHardwareWallet }.

Added Suggestion.HARDWARE to the empty-wallet suggestion path and passed through hasHardwareWallet, so empty wallets now show the Hardware card unless a hardware wallet is already paired. I also added HomeViewModelTest.kt coverage for both states.

Resolved in 4b0482e

@ovitrif ovitrif left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a couple self-review remarks.

Comment on lines +3069 to +3085
/**
* The device asks for its one-time pairing code mid-connect, which can happen on
* any screen via silent reconnects, so the sheet is shown app-wide. High-priority
* sheets are not interrupted: reconnect retries re-raise the request shortly after.
*/
private fun showPairingCodeSheet() {
val current = _currentSheet.value
val isHighPrioritySheetShowing = current is Sheet.Gift ||
current is Sheet.Send ||
current is Sheet.BTCPayConnection ||
current is Sheet.LnurlAuth ||
current is Sheet.Pin ||
current is Sheet.PubkyAuth
if (!isHighPrioritySheetShowing) {
showSheet(Sheet.Hardware(route = HardwareRoute.PairingCode))
}
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need to queue the pairing sheet so the user doesn't lose the UI response for that action.

@@ -0,0 +1 @@
Show paired Trezor hardware wallet balances and activity on the wallet home screen, with safer USB reconnection, pairing-code entry, and a received sheet for new incoming transactions.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compact into:

Show paired Trezor hardware wallet balances and activity on the home screen, with sheets to enter pairing code and notify incoming hardware wallet transactions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant