Skip to content

Commit 9cac660

Browse files
authored
Merge pull request #2304 from SatoshiPortal/760-add-utxos-view
feat: Coins (UTXO) view with freeze/unfreeze only, on a new bull_ui design system (#760)
2 parents 9984a6e + 24432e5 commit 9cac660

124 files changed

Lines changed: 21702 additions & 234 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.git_hooks/pre-commit

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,13 @@ if ! grep -q "Nothing to fix!" "$fixOut"; then
5252
exit 1
5353
fi
5454

55+
# bull_ui import boundary: feature UI built on the design system must import
56+
# only `package:bull_ui/bull_ui.dart` for widgets — never Flutter UI directly.
57+
# (Until a first-party analyzer rule lands, this grep is the enforcement.)
58+
if grep -rEl "package:flutter/(material|cupertino|widgets)\.dart" "$REPO_ROOT/lib/features/coins/ui" >/dev/null 2>&1; then
59+
echo "lib/features/coins/ui must import only package:bull_ui/bull_ui.dart, not package:flutter/{material,cupertino,widgets}.dart:"
60+
grep -rEl "package:flutter/(material|cupertino|widgets)\.dart" "$REPO_ROOT/lib/features/coins/ui"
61+
exit 1
62+
fi
63+
5564
echo "End pre-commit hook"

.github/workflows/analyze_and_test.yml

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,16 @@ jobs:
6666
- run: make build-runner
6767
- run: make translations
6868

69-
- name: Create .env file
70-
run: |
71-
echo "TEST_ALICE_MNEMONIC=${{ secrets.ENV_TEST_ALICE_MNEMONIC }}" >> .env
72-
echo "TEST_BOB_MNEMONIC=${{ secrets.ENV_TEST_BOB_MNEMONIC }}" >> .env
73-
7469
- name: Linter shouldn't raise errors, warnings or infos
7570
run: make analyze
7671

72+
- name: bull_ui import boundary (coins/ui imports only package:bull_ui)
73+
run: |
74+
if grep -rEl "package:flutter/(material|cupertino|widgets)\.dart" lib/features/coins/ui; then
75+
echo "lib/features/coins/ui must import only package:bull_ui/bull_ui.dart, not Flutter UI directly"
76+
exit 1
77+
fi
78+
7779
- name: dart fix should have nothing to suggest
7880
run: |
7981
output=$(fvm dart fix --dry-run)
@@ -100,7 +102,14 @@ jobs:
100102
# stopped unexpectedly / Unable to start the app on the device").
101103
# xvfb-run gives it a virtual X server. dbus-run-session + an
102104
# unlocked gnome-keyring provide the Secret Service flutter_secure_storage needs.
105+
# Tests read the mnemonics via Platform.environment, so the secrets are
106+
# exported as real env vars (not a .env file, which nothing loads). When a
107+
# secret is unset (e.g. on forks) the var is empty and the funded-testnet
108+
# groups skip themselves — "use the mnemonic if available".
103109
- name: Integration tests (Linux desktop)
110+
env:
111+
TEST_ALICE_MNEMONIC: ${{ secrets.ENV_TEST_ALICE_MNEMONIC }}
112+
TEST_BOB_MNEMONIC: ${{ secrets.ENV_TEST_BOB_MNEMONIC }}
104113
run: |
105114
xvfb-run -a dbus-run-session -- bash -c '
106115
echo "" | gnome-keyring-daemon --unlock --daemonize --components=secrets

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ When the same role exists with two names in the codebase, use the dominant one a
137137

138138
The codebase is migrating toward a real UI Kit. The skeleton already lives in [`lib/core/widgets/`](lib/core/widgets/) (`buttons/`, `cards/`, `inputs/`, `lists/`, `dropdown/`, `bottom_sheet/`, `text/`, `selectors/`, …) and theme tokens in [`lib/core/themes/`](lib/core/themes/). Today the same widgets get re-implemented per feature (`_SaveButton`, `_ConfirmButton`, `_BottomButtons` …) — stop adding to that pile.
139139

140+
The go-forward home for the kit is the **`bull_ui` design-system package** (`packages/bull_ui`; see ARCHITECTURE.md "Design-system package"). Provenance: **`BB*` = legacy `lib/core/widgets`, `Bull*` = `bull_ui`**. A feature whose UI is built on the kit imports only `package:bull_ui/bull_ui.dart` for widgets — never `package:flutter/material.dart`/`cupertino.dart`/`widgets.dart` (the `coins` feature is the first to enforce this). Migration of `core/widgets` into `bull_ui` is incremental (one scoped PR at a time), so both still exist; prefer a `Bull*` widget when one exists, otherwise follow the workflow below against `lib/core/widgets/`.
141+
140142
Workflow when you need a widget:
141143

142144
1. **Search `lib/core/widgets/` first.** If something close exists, use it.

ARCHITECTURE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ The codebase is migrating, incrementally, from a single Flutter package to a [me
343343

344344
- **root = the app shell** — thin: routing, DI/get_it wiring, and composition of feature packages. It ships no domain or UI of its own beyond that wiring.
345345
- **`features/`** — Flutter packages, one per user-facing flow (`send`, `receive`, `buy`, `sell`, `recoverbull`, …). Each owns its domain behind its `public/` facade and is mounted into the shell (routes + DI). A feature may carry an `example/` mini-app to run it in isolation during development; the shipped artifact is the shell embedding the feature, not a standalone app.
346-
- **`packages/`** — pure-Dart packages with no Flutter UI: the shared foundation consumed by features. This is both shared domain (`wallet`, `secrets`) and infrastructure (`storage`, `electrum`, `blockchain`, …). The lone exception is a package that must own a sealed UI component (see "Sealed UI" below), which may depend on Flutter.
346+
- **`packages/`**mostly pure-Dart packages with no Flutter UI: the shared foundation consumed by features. This is both shared domain (`wallet`, `secrets`) and infrastructure (`storage`, `electrum`, `blockchain`, …). Two narrow categories may depend on Flutter: a package that must own a sealed UI component (see "Sealed UI" below), and the shared **design-system package** (`bull_ui`, see "Design-system package" below).
347347

348348
Each extracted package gets `resolution: workspace` and is listed under a `workspace:` key in the root `pubspec.yaml`; the root app keeps `useRootAsPackage: true` and consumes the members. Dependencies point one way and stay acyclic: **shell → features → packages**. `packages/` never import `features/`; a feature touches a package only through its published API.
349349

@@ -357,6 +357,8 @@ Each extracted package gets `resolution: workspace` and is listed under a `works
357357

358358
**Sealed UI as a security tool.** A package can expose a *widget* that uses a secret internally without ever exposing the secret value. The mnemonic-display case is the canonical example: `secrets` exports a `MnemonicView` widget but no function that returns the words. The mnemonic lives only in `lib/src/`, is read inside the widget's `build`, and never crosses the package boundary — so a feature developer can show the user their words but cannot obtain them programmatically. Because Dart has no cross-package "friend" visibility, the widget must live in the same package that holds the seed, which is why `secrets` is the one package allowed to depend on Flutter. This seal stops programmatic/API leakage only — not OS-level capture; pair it with screenshot blocking (`no_screenshot`), exclusion from the accessibility/semantics tree, and treating the revealed value as ephemeral.
359359

360+
**Design-system package (`bull_ui`).** Shared *UI* is migrating out of `lib/core/widgets/` into a Flutter-dependent design-system package, `packages/bull_ui` — the project's go-forward component kit (theme tokens injected by the app via a `ThemeExtension`, plus `Bull*` widgets). It is a deliberate, sanctioned exception to "packages are pure-Dart": a design system is inherently Flutter UI, and like every package it stays acyclic (`bull_ui` depends only on Flutter + leaf UI deps, never on `features/` or app services). Provenance convention at the call site: **`BB*` = legacy `lib/core/widgets`, `Bull*` = `bull_ui`** (the source of truth). Widgets move from `core/widgets` into `bull_ui` **incrementally, never big-bang** — each extraction is its own scoped PR, and a widget entangled with feature/app services waits until those deps are refactored out. A dev-only `bull_ui_catalogue` (Widgetbook) renders the kit in isolation and ships in nothing.
361+
360362
This is a slow, deliberate migration. Until a module is extracted, it stays in `lib/` and follows the same rules it does today. Do not move code into `packages/`/`features/` opportunistically — extraction is its own scoped, reviewed change with the security/bitcoin/build implications considered per module.
361363

362364
## 🤖 Rules for AI

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to Bull Bitcoin Mobile will be documented in this file.
44

55
---
66

7+
## [Unreleased]
8+
9+
### New Features
10+
11+
- **Coins (UTXO) view**: See every unspent output in a Bitcoin wallet — amount, label, keychain, and confirmation status — from a new "Coins" entry on the wallet screen. Sort and filter your coins, then freeze any you don't want to spend; frozen coins are excluded from every transaction until you unfreeze them, and the freeze survives app restarts. ([#760](https://github.com/SatoshiPortal/bullbitcoin-mobile/issues/760))
12+
13+
---
14+
715
## [6.11.0] - 2026-06-08
816

917
### New Features

FEATURES.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ graph TB
4444
SELL[Sell]
4545
PAY[Pay]
4646
BUY[Buy]
47+
COINS[Coins / UTXOs]
4748
4849
%% Dependencies to Core (all features depend on Core, but showing it explicitly would clutter the diagram)
4950
%% Instead, we note this in the documentation below
@@ -60,6 +61,9 @@ graph TB
6061
BTC_PRICE --> SETTINGS
6162
BUY --> EXCHANGE
6263
BUY --> RECEIVE
64+
COINS --> UTXO_MGMT
65+
COINS --> LABELS
66+
COINS --> WALLETS
6367
DCA --> RECEIVE
6468
EXCHANGE --> SETTINGS
6569
FEES --> NETWORK
@@ -101,7 +105,7 @@ graph TB
101105
classDef featureStyle fill:#1a202c,stroke:#2d3748,stroke-width:2px,color:#e2e8f0
102106
103107
class CORE coreStyle
104-
class SETTINGS,TOR,PIN_CODE,LABELS,SECRETS,HW_WALLETS,BTC_PRICE,NETWORK,BIP85,FEES,WALLETS,EXCHANGE,APP_STARTUP,UTXO_MGMT,ADDRESS_MGMT,RECIPIENTS,FUNDING,BACKUPS,SWAPS,PAYJOIN,WITHDRAWAL,STATUS,SEND,RECEIVE,TRANSFER,TX_HISTORY,BG_TASKS,AUTOSWAPS,DCA,SELL,PAY,BUY featureStyle
108+
class SETTINGS,TOR,PIN_CODE,LABELS,SECRETS,HW_WALLETS,BTC_PRICE,NETWORK,BIP85,FEES,WALLETS,EXCHANGE,APP_STARTUP,UTXO_MGMT,ADDRESS_MGMT,RECIPIENTS,FUNDING,BACKUPS,SWAPS,PAYJOIN,WITHDRAWAL,STATUS,SEND,RECEIVE,TRANSFER,TX_HISTORY,BG_TASKS,AUTOSWAPS,DCA,SELL,PAY,BUY,COINS featureStyle
105109
```
106110

107111
## About Package Dependency Diagrams

0 commit comments

Comments
 (0)