Skip to content

Commit de09b60

Browse files
authored
Merge pull request #2302 from SatoshiPortal/bull_ui_and_catalogue
feat(bull_ui): design-system package + component catalogue
2 parents dc19458 + fc9a75d commit de09b60

84 files changed

Lines changed: 7278 additions & 1 deletion

File tree

Some content is hidden

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

lib/core/themes/app_theme.dart

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,59 @@
11
import 'package:bb_mobile/core/themes/colors.dart';
22
import 'package:bb_mobile/core/themes/fonts.dart';
3+
import 'package:bull_ui/bull_ui.dart';
34
import 'package:flutter/material.dart';
45
import 'package:flutter/services.dart';
56

67
enum AppThemeType { light, dark }
78

9+
/// Builds the `bull_ui` [BullTheme] colour extension from an [AppColors]
10+
/// palette. `bull_ui` is brightness-agnostic — the app hands it the right
11+
/// palette per brightness, so `AppColors` stays the single source of truth.
12+
BullTheme _bullThemeFrom(AppColors colors) {
13+
return BullTheme(
14+
primary: colors.primary,
15+
onPrimary: colors.onPrimary,
16+
primaryFixed: colors.primaryFixed,
17+
onPrimaryFixed: colors.onPrimaryFixed,
18+
secondary: colors.secondary,
19+
onSecondary: colors.onSecondary,
20+
secondaryFixed: colors.secondaryFixed,
21+
secondaryFixedDim: colors.secondaryFixedDim,
22+
onSecondaryFixed: colors.onSecondaryFixed,
23+
tertiary: colors.tertiary,
24+
onTertiary: colors.onTertiary,
25+
tertiaryContainer: colors.tertiaryContainer,
26+
background: colors.background,
27+
surface: colors.surface,
28+
surfaceContainer: colors.surfaceContainer,
29+
surfaceContainerHighest: colors.surfaceContainerHighest,
30+
surfaceBright: colors.surfaceBright,
31+
onSurface: colors.onSurface,
32+
onSurfaceVariant: colors.onSurfaceVariant,
33+
inverseSurface: colors.inverseSurface,
34+
cardBackground: colors.cardBackground,
35+
text: colors.text,
36+
textMuted: colors.textMuted,
37+
border: colors.border,
38+
outline: colors.outline,
39+
outlineVariant: colors.outlineVariant,
40+
error: colors.error,
41+
onError: colors.onError,
42+
errorContainer: colors.errorContainer,
43+
success: colors.success,
44+
warning: colors.warning,
45+
warningContainer: colors.warningContainer,
46+
info: colors.info,
47+
scrim: colors.scrim,
48+
overlay: colors.overlay,
49+
transparent: colors.transparent,
50+
surfaceFixed: colors.surfaceFixed,
51+
onSurfaceFixed: colors.onSurfaceFixed,
52+
shimmerBase: colors.shimmerBase,
53+
shimmerHighlight: colors.shimmerHighlight,
54+
);
55+
}
56+
857
class AppTheme {
958
static ThemeData themeData(AppThemeType themeType) {
1059
final colors = themeType == AppThemeType.dark
@@ -18,6 +67,7 @@ class AppTheme {
1867
return ThemeData(
1968
useMaterial3: true,
2069
brightness: brightness,
70+
extensions: [_bullThemeFrom(colors)],
2171
colorScheme: ColorScheme.fromSeed(
2272
seedColor: colors.primary,
2373
brightness: brightness,

makefile

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: all setup clean deps deps-update bootstrap analyze build-runner translations hooks ios-pod-update drift-migrations devcontainer container-tools container-app android release debug beta verify test unit-test integration-test fvm-check
1+
.PHONY: all setup clean deps deps-update bootstrap analyze build-runner translations hooks ios-pod-update drift-migrations devcontainer container-tools container-app android release debug beta verify test unit-test integration-test catalogue fvm-check
22

33
fvm-check:
44
@echo "🔍 Checking FVM"
@@ -190,6 +190,12 @@ test: unit-test integration-test
190190
unit-test:
191191
@echo "🏃‍ running unit tests"
192192
@fvm flutter test test/ --reporter=compact
193+
@for p in packages/*/; do \
194+
if [ -d "$${p}test" ]; then \
195+
echo "🏃‍ running $${p}test"; \
196+
( cd "$$p" && fvm flutter test --reporter=compact ); \
197+
fi; \
198+
done
193199

194200
# integration_test/all_test.dart is a single aggregator entrypoint: it runs
195201
# Bull.init() once, then every test file's main(isInitialized: true). On the
@@ -203,3 +209,12 @@ integration-test:
203209
@echo "🧪 integration tests"
204210
@fvm dart run tool/gen_all_test.dart
205211
@fvm flutter test integration_test/all_test.dart --reporter=expanded
212+
213+
# Build & render the bull_ui design-system catalogue (Widgetbook) locally in the
214+
# browser. Dev-only tooling — never shipped in the app. Regenerates the
215+
# @UseCase directories, then runs the catalogue app on Chrome (hot-reload).
216+
catalogue:
217+
@echo "📚 Building & rendering the bull_ui catalogue in the browser"
218+
@cd packages/bull_ui_catalogue && \
219+
fvm dart run build_runner build --delete-conflicting-outputs && \
220+
fvm flutter run -d chrome

packages/bull_ui/CHANGELOG.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Changelog
2+
3+
## Unreleased
4+
5+
- **Foundation tokens now follow the design system / official theme.** `BullTheme`
6+
is the full 1:1 `AppColors` mirror (all ~40 fields, official names); `BullRadius`
7+
adopts the design scale (`0/4/8/12/16/28/32/999`) and `BullSpacing` the design
8+
scale (`0/4/8/12/16/24/32/48/64`); `BullTextStyles` is **removed** — type comes
9+
from the Material `TextTheme` (`AppFonts`). All `Bull*` components were remapped
10+
(`context.bull.red→primary`, `btc→onTertiary`, `muted→textMuted`,
11+
`card→cardBackground`, radius/spacing → new scales). Tokens are fixed (not
12+
screen-scaled); responsiveness is a layout concern.
13+
- `BullSwipeAction` action panel wrapped in `FittedBox(scaleDown)` so the
14+
icon+label never overflows a short row.
15+
16+
- Expand `BullTheme` with `secondary`, `onSecondary`, `secondaryFixedDim`,
17+
`border`, `onSurface`, `onSurfaceVariant` and `scrim` (plus `copyWith`/`lerp`
18+
and the app-side `_bullThemeFrom` builder), sourced from `AppColors`.
19+
- Duplicate the dependency-clean set of `lib/core/widgets/**` as `Bull*`
20+
copies: `BullInputText`, `BullPasteInput`, `BullDropdown`,
21+
`BullSelectableList`, `BullDialPad`, `BullAmountInputFormatter`,
22+
`BullLowerCaseTextFormatter`, `BullCountdown`, `BullFadingLinearProgress`,
23+
`BullScrollableColumn`, `BullStackedPage`, `BullPullableBody`,
24+
`BullOptionsTag`, `BullInfoCard`, `BullPriceCard`, `BullBackupOptionCard`,
25+
`BullBorderedTile`, `BullTransactionDirectionBadge`, `BullSettingsEntryItem`,
26+
`BullTabMenuVerticalButton`, `BullViewerActionButton`. See the README
27+
"Components" / "Not yet migrated" tables.
28+
- Duplicate the remaining dependency-clean widgets: `BullDetailsTable` +
29+
`BullDetailsTableItem` (`DetailsTable` / `DetailsTableItem`),
30+
`BullPickerSheet` (`BBPickerSheet`) and `BullInstructionsSheet`
31+
(`InstructionsBottomSheet`). No new `BullTheme` fields were required — they
32+
reuse the existing `surface`, `border`, `onSurface`, `red` and `text` colours.
33+
- Widget tests for `BullDropdown`, `BullCountdown` and `BullDialPad`.
34+
35+
## 0.0.1
36+
37+
- Seed the `bull_ui` design-system package: `BullTheme` (`ThemeExtension`),
38+
`BullRadius`/`BullSpacing`/`BullTextStyles`/`BullIcon` tokens, and the first
39+
set of `Bull*` components for the Coins view (issue #760).

packages/bull_ui/README.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# bull_ui
2+
3+
The Bull Bitcoin design-system component library — the go-forward source of truth for
4+
shared UI primitives. It is the first melos workspace member (`packages/bull_ui`).
5+
6+
Every public widget is prefixed `Bull*` (e.g. `BullText`, `BullButton`, `BullScaffold`).
7+
This prefix is provenance: **`BB*` = legacy widgets in `lib/core/widgets`, `Bull*` = here**.
8+
The two coexist during the incremental migration; `BB*` originals are retired
9+
feature-by-feature in later scoped PRs as usages migrate. Nothing is moved or renamed —
10+
`bull_ui` components are duplicated copies, so existing app code is untouched.
11+
12+
## Theme injection
13+
14+
`bull_ui` is **brightness-agnostic** and never hardcodes a colour. The app injects the
15+
palette: it builds a `BullTheme` (a `ThemeExtension`) from `AppColors.light` and another
16+
from `AppColors.dark`, and registers each on the matching `ThemeData` via `extensions:`.
17+
Components read colours through `context.bull` (e.g. `context.bull.primary`). `BullTheme` is a
18+
**1:1 mirror of the app's `AppColors`** — same field names — so the app wires every field through
19+
without translation. Derived fills use `tokenColor.withValues(alpha: …)` so they adapt to both
20+
light and dark automatically.
21+
22+
## Foundation tokens
23+
24+
Brightness-invariant tokens are static consts, from the design system:
25+
26+
- **`BullRadius`**`zero·xs·sm·md·lg·xl·xxl·full` = `0·4·8·12·16·28·32·999`.
27+
- **`BullSpacing`**`zero·xxs·xs·sm·md·lg·xl·xxl·xxxl` = `0·4·8·12·16·24·32·48·64`.
28+
- **Type** comes from the Material `TextTheme` (`Theme.of(context).textTheme`, sourced from
29+
`AppFonts`) — there is no separate text-token class.
30+
- **Icons** via `BullIcon(BullIcons.…)`.
31+
32+
**Tokens are fixed — never scaled by screen size.** Responsiveness is a *layout* concern
33+
(breakpoints, `LayoutBuilder`, max-width wrappers, adaptive columns), not a token concern; text
34+
already honours the user's `MediaQuery.textScaler`. The catalogue (`packages/bull_ui_catalogue`)
35+
has a `Foundation/` section showcasing colours, radius, spacing and the text scale.
36+
37+
Fonts (Golos Text, Bebas Neue) are declared at the app root and resolve by family name
38+
across the workspace — `bull_ui` references them by name and does not re-ship the `.ttf`s.
39+
40+
## Import surface
41+
42+
Consumers import a single barrel:
43+
44+
```dart
45+
import 'package:bull_ui/bull_ui.dart';
46+
```
47+
48+
It re-exports a curated `show` list of `package:flutter/widgets.dart` layout/foundation
49+
symbols plus every `Bull*` component and the theme. Internals live under `lib/src/`.
50+
51+
## Components
52+
53+
Duplicated from `lib/core/widgets/**` as dependency-clean `Bull*` copies (the
54+
`BB*`/core originals are left untouched). Grouped by barrel category:
55+
56+
**Buttons**`BullButton`, `BullToolButton`, `BullTabMenuVerticalButton`
57+
(`TabMenuVerticalButton`), `BullViewerActionButton` (`ViewerActionButton`).
58+
59+
**Inputs**`BullCheckbox`, `BullFilterChip`, `BullInputText` (`BBInputText`),
60+
`BullPasteInput` (`PasteInput`), `BullDropdown` (`BBDropdown`),
61+
`BullSelectableList` + `BullSelectableListItem` (`SelectableList`),
62+
`BullDialPad` (`DialPad`), `BullAmountInputFormatter` (`AmountInputFormatter`),
63+
`BullLowerCaseTextFormatter` (`LowerCaseTextFormatter`).
64+
65+
**Controls**`BullSegmented`, `BullSwipeAction`, `BullSwitch` (`BBSwitch`).
66+
67+
**Feedback**`BullRefreshIndicator` (`BBRefreshIndicator`), `BullShimmerBox`/
68+
`BullShimmerLine`, `BullSnackBar`, `BullCountdown` (`Countdown`),
69+
`BullFadingLinearProgress` (`FadingLinearProgress`).
70+
71+
**Layout**`BullScrollableColumn` (`ScrollableColumn`), `BullStackedPage`
72+
(`StackedPage`), `BullPullableBody` (`BBPullableBody`).
73+
74+
**Data display**`BullAddressText`, `BullBadge`, `BullInfoBar`,
75+
`BullLabelChip`, `BullStatTile`, `BullText` (`BBText`), `BullOptionsTag`
76+
(`OptionsTag`), `BullInfoCard` (`InfoCard`), `BullPriceCard` (`PriceCard`),
77+
`BullBackupOptionCard` (`BackupOptionCard`), `BullBorderedTile`
78+
(`BorderedTappableTile`), `BullTransactionDirectionBadge`
79+
(`TransactionDirectionBadge`), `BullSettingsEntryItem` (`SettingsEntryItem`),
80+
`BullDetailsTable` + `BullDetailsTableItem` (`DetailsTable` / `DetailsTableItem`).
81+
82+
**Overlays**`BullBottomSheet`, `BullDialog`, `BullPickerSheet`
83+
(`BBPickerSheet`), `BullInstructionsSheet` (`InstructionsBottomSheet`).
84+
85+
**Chrome**`BullScaffold`, `BullTopBar`, `BullSelectionActionBar`.
86+
87+
## Not yet migrated (needs dep abstraction)
88+
89+
These `core/widgets` widgets still reach into `package:bb_mobile/*` (or otherwise
90+
can't preserve their public API on top of the clean kit) and are **deferred**
91+
until the dependency is abstracted out of the widget:
92+
93+
| Widget | Blocker |
94+
| --- | --- |
95+
| `MultiTapTrigger` | `package:bb_mobile/core/widgets/snackbar_utils.dart` — its public `tapsReachedMessageTextColor` / `tapsReachedMessageBackgroundColor` API can't be honoured by `BullSnackBar.show` (String-only), so migrating would lose API. |
96+
| `CopyInput`, `BBKeyboardActions` | depend on `package:bb_mobile/*` localization / app utils. |
97+
| `BBButton` (`buttons/button.dart`) | already superseded by `BullButton`; not a 1:1 copy. |
98+
| Cards: `ActionCard`, `AutoswapWarningCard`, `BackupCard`, `BalanceCard`, `ProviderCart`, `WalletCard` | `package:bb_mobile/*` (router, l10n, feature models, `Assets`). |
99+
| `BBKeyboardActions` | needs `package:keyboard_actions/keyboard_actions.dart`, not declared in `bull_ui/pubspec.yaml` (no new deps rule). |
100+
| Bottom sheets: `AdvancedOptions`, `ComingSoon`, `Warning`, `NotLoggedIn`, `DeleteAccount*`, `Logout*`, `TranslationWarning` | `context.loc` localization and/or `package:bb_mobile/*` router & assets. |
101+
| Cards: `AutoswapWarningCard` | `context.loc` (`autoswapWarningCard*` strings) + `context.font` from `package:bb_mobile/core/utils/build_context_x.dart`. |
102+
| Loading: `ProgressScreen`, `StatusScreen` | `ProgressScreen` imports `package:bb_mobile/generated/flutter_gen/assets.gen.dart`; `StatusScreen` uses `context.loc` + `BBButton`. |
103+
| Viewers: `AddressViewer`, `TransactionViewer`, `InvoiceViewer`, `LogViewer`, `QrScanner`, `NfcScanner`, `ShareLogs`, `Bip85Derivation`, `MnemonicWidget`, `CoinSelectionBottomSheet`, `AppLanguagePicker`, `BackupSuccessScreen`, `PriceInput`, `TransactionsByDayList`, `BalanceRow`, `RecoverbullVaultProviderSelector` | `package:bb_mobile/*` (entities, l10n, assets, feature blocs). |
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
include: package:lints/recommended.yaml
2+
3+
linter:
4+
rules:
5+
# A design-system package is the foundation other features build on; hold it
6+
# to a stricter bar than the recommended set.
7+
- prefer_const_constructors
8+
- prefer_const_constructors_in_immutables
9+
- prefer_const_declarations
10+
- prefer_const_literals_to_create_immutables
11+
- require_trailing_commas
12+
- prefer_final_locals
13+
- prefer_single_quotes
14+
- sort_child_properties_last
15+
- use_super_parameters
16+
- unnecessary_parenthesis

packages/bull_ui/lib/bull_ui.dart

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/// The Bull Bitcoin design-system component library.
2+
///
3+
/// Import this single barrel; it re-exports a curated `show` list of Flutter
4+
/// layout/foundation primitives plus every `Bull*` component and the theme.
5+
/// Internals live under `lib/src/`.
6+
library;
7+
8+
// Curated re-export of Flutter foundation/layout primitives (Decision D5).
9+
// A blanket `export 'package:flutter/widgets.dart'` is deliberately avoided —
10+
// the list grows on demand as components need more symbols.
11+
export 'package:flutter/widgets.dart'
12+
show
13+
Align,
14+
Alignment,
15+
AnimatedContainer,
16+
AnimatedPositioned,
17+
AspectRatio,
18+
Axis,
19+
BorderRadius,
20+
BoxConstraints,
21+
BoxDecoration,
22+
BuildContext,
23+
Center,
24+
Color,
25+
Column,
26+
ConstrainedBox,
27+
CrossAxisAlignment,
28+
EdgeInsets,
29+
EdgeInsetsGeometry,
30+
Expanded,
31+
Flexible,
32+
FractionallySizedBox,
33+
GestureDetector,
34+
HitTestBehavior,
35+
IconData,
36+
Key,
37+
ListView,
38+
MainAxisAlignment,
39+
MainAxisSize,
40+
Opacity,
41+
Padding,
42+
Positioned,
43+
Radius,
44+
Row,
45+
SafeArea,
46+
SingleChildScrollView,
47+
SizedBox,
48+
Spacer,
49+
Stack,
50+
State,
51+
StatefulWidget,
52+
StatelessWidget,
53+
Text,
54+
TextAlign,
55+
TextBaseline,
56+
TextDirection,
57+
TextEditingController,
58+
TextOverflow,
59+
TextStyle,
60+
ValueChanged,
61+
VerticalDirection,
62+
VoidCallback,
63+
Widget,
64+
Wrap;
65+
66+
// Material/services symbols required by component public APIs.
67+
export 'package:flutter/material.dart'
68+
show DropdownMenuItem, FormFieldValidator, RefreshCallback;
69+
export 'package:flutter/services.dart' show TextInputFormatter;
70+
export 'package:flutter/widgets.dart' show FocusNode;
71+
72+
export 'package:gap/gap.dart' show Gap;
73+
74+
// Theme.
75+
export 'src/theme/bull_icon.dart';
76+
export 'src/theme/bull_theme.dart';
77+
export 'src/theme/bull_tokens.dart';
78+
79+
// Chrome.
80+
export 'src/chrome/bull_scaffold.dart';
81+
export 'src/chrome/bull_selection_action_bar.dart';
82+
export 'src/chrome/bull_top_bar.dart';
83+
84+
// Buttons.
85+
export 'src/buttons/bull_button.dart';
86+
export 'src/buttons/bull_tab_menu_vertical_button.dart';
87+
export 'src/buttons/bull_tool_button.dart';
88+
export 'src/buttons/bull_viewer_action_button.dart';
89+
90+
// Inputs.
91+
export 'src/inputs/bull_amount_input_formatter.dart';
92+
export 'src/inputs/bull_checkbox.dart';
93+
export 'src/inputs/bull_dial_pad.dart';
94+
export 'src/inputs/bull_dropdown.dart';
95+
export 'src/inputs/bull_filter_chip.dart';
96+
export 'src/inputs/bull_input_text.dart';
97+
export 'src/inputs/bull_lowercase_input_formatter.dart';
98+
export 'src/inputs/bull_paste_input.dart';
99+
export 'src/inputs/bull_selectable_list.dart';
100+
101+
// Controls.
102+
export 'src/controls/bull_segmented.dart';
103+
export 'src/controls/bull_swipe_action.dart';
104+
export 'src/controls/bull_switch.dart';
105+
106+
// Feedback.
107+
export 'src/feedback/bull_countdown.dart';
108+
export 'src/feedback/bull_fading_linear_progress.dart';
109+
export 'src/feedback/bull_refresh_indicator.dart';
110+
export 'src/feedback/bull_shimmer.dart';
111+
export 'src/feedback/bull_snack_bar.dart';
112+
113+
// Layout.
114+
export 'src/layout/bull_pullable_body.dart';
115+
export 'src/layout/bull_scrollable_column.dart';
116+
export 'src/layout/bull_stacked_page.dart';
117+
118+
// Data display.
119+
export 'src/data_display/bull_address_text.dart';
120+
export 'src/data_display/bull_backup_option_card.dart';
121+
export 'src/data_display/bull_badge.dart';
122+
export 'src/data_display/bull_bordered_tile.dart';
123+
export 'src/data_display/bull_details_table.dart';
124+
export 'src/data_display/bull_info_bar.dart';
125+
export 'src/data_display/bull_info_card.dart';
126+
export 'src/data_display/bull_label_chip.dart';
127+
export 'src/data_display/bull_options_tag.dart';
128+
export 'src/data_display/bull_price_card.dart';
129+
export 'src/data_display/bull_settings_entry_item.dart';
130+
export 'src/data_display/bull_stat_tile.dart';
131+
export 'src/data_display/bull_text.dart';
132+
export 'src/data_display/bull_transaction_direction_badge.dart';
133+
134+
// Overlays.
135+
export 'src/overlays/bull_bottom_sheet.dart';
136+
export 'src/overlays/bull_dialog.dart';
137+
export 'src/overlays/bull_instructions_sheet.dart';
138+
export 'src/overlays/bull_picker_sheet.dart';

0 commit comments

Comments
 (0)