Skip to content

App-wide UI refresh: design system, components, and screen redesigns#233

Open
swedishfrenchpress wants to merge 166 commits intomainfrom
feat/app-ui-refresh
Open

App-wide UI refresh: design system, components, and screen redesigns#233
swedishfrenchpress wants to merge 166 commits intomainfrom
feat/app-ui-refresh

Conversation

@swedishfrenchpress
Copy link
Copy Markdown
Collaborator

@swedishfrenchpress swedishfrenchpress commented Mar 23, 2026

What this branch does

Pulls the app onto a shared UI vocabulary. Prior to this branch, most screens hand-rolled their own top bar, buttons, bottom sheets, input styles, and spacing. Every activity now pulls from the same set of components and tokens, which is why the diff is wide (~386 files, +6.7k / −8.9k net −2.1k lines) even though the behavior surface is mostly unchanged.

New shared primitives

  • NumoTopBar (ui/components/NumoTopBar.kt, layout/component_top_bar.xml) — 22+ activities migrated off ad-hoc title/back-button layouts onto this one component. Title is now R.id.top_bar_title; old per-screen title_text ids are gone.
  • SettingsRowView (ui/components/SettingsRowView.kt, component_settings_row.xml) — every clickable settings row now routes through this. Saves ~60 lines per row usage.
  • ConfirmationBottomSheet / InputBottomSheet — replaces assorted AlertDialogs and inline dialog builders. DialogHelper.kt shrinks from ~600 to ~300 lines as a result.
  • Empty statesEmptyStateHelper + component_empty_state.xml replace per-screen empty layouts.
  • MotionCheckmarkAnimationView, FadingImageView, LightningStrikeView, reduced-motion helpers. Welcome/onboarding and auto-withdraw screens were rebuilt around these.
  • BIP39 wordlist validation on the restore-wallet seed inputs (previously regex-only).

Design tokens

Hex colors and magic-number dimensions were pulled into values/colors.xml, values/styles.xml (+369 lines), and drawables. Many old single-use drawables (bg_chip_ribbon_*, bg_circle_*, bg_button_*) were deleted and replaced by a smaller shared set. If a module's style reference broke in a rebase, check here first.

Breadth / touched areas

Every user-visible screen has been touched at least cosmetically. Highest-risk files to spot-check:

  • PaymentRequestActivity.kt, NfcPaymentAnimationView, NfcPaymentProcessor.kt — payment happy-path.
  • feature/onboarding/* — full redesign (explainer carousel, wallet-setup teaser, Zero Fees illustration, auto-custody animation, mint selection). This was merged back and forth with main several times, hence the handful of "reset onboarding to match main" commits.
  • feature/settings/MintsSettingsActivity.kt and MintDetailsActivity.kt — restructured into hero-card layout with swap/undo interactions.
  • feature/autowithdraw/*, WithdrawLightningActivity.kt, WithdrawMeltQuoteActivity.kt — redesigned with shared toggles and segmented controls.
  • feature/items/*, BasketReceiptActivity.kt, TransactionDetailActivity.kt — Material-style outlined inputs, new receipt layout.

Risks & things to pay attention to in review

  1. Theme/status-bar regressions. ThemeManager.kt, MultiInsetEdgeToEdge.kt, and many activities still use deprecated statusBarColor/navigationBarColor APIs (compile warnings in CI). Previously fixed twice during this branch (fix: keep window background synced with theme, fix: resolve window insets on payment and withdraw screens). Worth checking dark-mode + edge-to-edge on at least one device per screen.
  2. Bottom sheet z-ordering. bba29e80 refactor: unify bottom sheets and the AddMintBottomSheet theme fix landed to resolve draw-order bugs — regressions here tend to show as a translucent strip over the sheet.
  3. Onboarding flow. Because of repeated resets against main, the onboarding diff is the messiest part of this branch. If something looks off in the welcome/explainer/mint-selection path, compare against main directly rather than reading history.
  4. Test coverage is thin on the UI changes. Only RestoreWalletActivityTest was updated (two NPEs fixed in the last commit after CI flagged them). Most screens have no Robolectric coverage, so QA should be manual.
  5. Build config. compileSdk/targetSdk → 35, AGP 9.1.0, Gradle 9.3.1, BouncyCastle bumped. gradle/libs.versions.toml is the source of truth.
  6. No behavior changes claimed — if you see a logic change (as opposed to a view/layout/style change), flag it. A couple of genuinely behavioral commits are mixed into the refactor (e.g. set default mint immediately on long-press, remove confirmation dialog, filter unreachable mints from onboarding defaults, BIP39 validation) — those are intentional.

Merge history

This branch has pulled main in four times. If git log looks chaotic, that's why. Diff against origin/main is the honest view of what's actually landing.

Test plan

  • Onboarding: fresh install → explainer → create wallet → default mint set (incl. swap/undo).
  • Restore wallet: valid 12-word seed, BIP39-invalid seed, paste path.
  • Payment request → NFC tap → success/failure screens.
  • Auto-withdraw toggle on/off, withdraw-now lightning flow.
  • Mints list: add, swap default, details page actions.
  • Settings: every row launches correct activity; top-bar back behavior consistent.
  • Dark mode pass on every screen (most regressions during this branch have been dark-mode-specific).
  • Language switch (en/es/pt) on a screen with new copy (e.g. item entry).
  • ./gradlew jacocoTestReport clean.

swedishfrenchpress and others added 30 commits March 19, 2026 23:59
…iable hit testing, adjust row padding to maintain visual alignment
…e is off

The screen title showed "Auto-Withdraw" everywhere — renamed to "Withdraw"
in the nav bar and hero section across all locales (en/es/pt). Destination
and Trigger Settings sections were always visible even with the toggle off;
they are now fully hidden when disabled and smoothly animate in/out when
the toggle changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
… mode

The disabled state used a 20% opacity background color compounded with
0.5 alpha on the view, resulting in ~10% visibility. Fixed at the
component level so all screens using Widget.Button.Primary.Green benefit:

- Disabled bg now uses color_bg_tertiary (theme-aware solid color)
- Added text color selector with proper disabled state via color_text_tertiary
- Removed redundant alpha hacks from XML layouts and Kotlin code
- Removed inconsistent textStyle="bold" overrides on withdraw buttons

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Both withdraw layouts had an explicit color_bg_surface background on the
ScrollView, creating a visible seam against the nav bar. Other settings
screens (Security, Language, Currency) inherit color_bg_white from the
root with no ScrollView background override. Removed the override so
both withdraw screens match.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
… spacing

The section headers (DESTINATION, TRIGGER SETTINGS, etc.) were using
inline styling with sans-serif (regular) and 0.03 letter spacing instead
of the shared Text.SectionHeader style used across 8+ other screens.
Refactored all 4 headers to use the shared style (sans-serif-medium,
0.05 letter spacing).

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Both rows used the same lightning bolt icon. Auto-Withdraw now uses a
Material Design autorenew icon to convey automatic/repeating behavior,
and Withdraw Now uses the down arrow icon consistent with withdraw line
items in the activity screen.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…ermark

Dialed back the gradient to barely-there warmth — light mode goes from
pure white to a ~3% orange tint, dark mode shifts subtly from default
surface to a faint ember tone. Removed the orange border stroke that
added to the warning-banner feel.

Added an oversized 120dp lightning bolt at the bottom-right corner at 6%
opacity as a brand watermark, clipped by the card edges.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Restructured layout so the bolt sits outside the padded content layer in
its own FrameLayout, flush against the card edges with -30dp margins and
clipped by the CardView corner radius. Added -15deg counter-clockwise
rotation, a vertical fade-out overlay (theme-aware, transparent to card
bg color), and bumped opacity from 6% to 12% for better visibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…ation on toggle

Renamed hero card title from "Withdraw" to "Auto-Withdraw" across all
locales. Added a LightningStrikeView that plays an orange lightning bolt
animation when the Auto-Withdraw toggle is switched on — forked bolt
path with amber glow, no screen flash, 400ms duration, auto-removes
after completion.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Reduced to a single bolt, added smooth fade-in/hold/fade-out timing
(550ms), lowered overall opacity to 70%, thinned stroke widths and glow
radii for a subtler effect. Removed the lightning bolt icon from the
Lightning Address input label.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Removed clock icon from recent activity empty state, made history card,
auto-withdraw toggle card, and withdraw now card backgrounds transparent
so they blend seamlessly in both themes — matching the borderless
appearance already seen in light mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The mint profile icon wasn't reliably loading, showing a fallback
bitcoin icon instead. Removed the icon container entirely for a cleaner
layout — mint items now show just name, URL, balance, and chevron.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Removed gray card backgrounds from invoice and address components (both
XML and programmatic setCardBackgroundColor). Removed lightning bolt and
envelope icons from section headers. Fixed SEND TO and CASHU TOKEN
headers to use shared Text.SectionHeader style. Applied hero gradient to
the balance card. Made cashu input and token result cards transparent.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Simplified Lightning Invoice and Address sections to match the
Auto-Withdraw screen's clean pattern (label, input, helper text).
Replaced QR scan icon with a Scan Invoice secondary button. Renamed
SEND TO header to DESTINATION. Removed lightning bolt icon from mint
name. Added real-time fiat balance below the BTC amount using
BitcoinPriceWorker. Removed address helper text.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Fixed cashu tab spacing to match destination section by removing extra
marginTop. Renamed "Amount (sats)" to "Amount" across all locales.
Fixed scan icon on Scan Invoice button — switched from drawableStart
(ignored by MaterialButton) to app:icon with textStart gravity.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Replaced the custom segment toggle (bg_input_pill container, 14sp medium
text, bg_segment_tab_selected) with the same implementation used on the
payment request screen (bg_button_secondary_pill container, 18sp bold
text, bg_button_primary_green selected state, 42dp height, 125dp min
width). Both screens now use identical toggle styling.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…ling

Updated history item icons to match the Activity screen — up arrow in
gray circle with green checkmark badge overlay for completed entries.
Removed redundant "Sent" badge. Fixed badge clipping with clipChildren.
Changed Withdraw Now icon from orange to gray to match. Centered share
icon vertically with text content for cashu token entries.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Updated history item text to match the Withdraw screen's row styles
instead of the Activity screen's styles. Amount now uses 17sp medium
(matching row titles like "Withdraw Now"), detail lines use 14sp
secondary (matching row descriptions). This makes Recent Activity feel
typographically unified with the rest of the Withdraw screen.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Inner circle was 40dp while Auto-Withdraw and Withdraw Now rows use
44dp. Expanded inner circle to 44dp and outer container to 50dp so the
green checkmark badge can still overflow the edge cleanly.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Removed elevation shadow from both withdraw screen title bars and
replaced inline 20sp title styling with shared Text.Title style (17sp)
to match Security & Privacy and other screens. Fixed centering with
textAlignment. Updated mint selection bottom sheet fonts to match
withdraw screen typography — mint name uses medium 17sp, URL uses 14sp
secondary, balance uses medium instead of bold.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Switched to explicit MaterialButton with app:strokeColor/strokeWidth for
visible border, since the style's android:background was being ignored.
Added insetTop/insetBottom="0dp" to match Continue button's 52dp height.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Removed gray background (color_bg_surface on root and ScrollView),
removed title bar elevation/divider, replaced inline 20sp title with
Text.Title style, updated TO label to use Text.SectionHeader, made card
backgrounds transparent, matched button width to other screens (40dp
margin), removed word "actual" from fee note text across all locales.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The history section header and card were appearing statically while
other elements above them had a staggered reveal. Added both to the
entrance animation sequence at 250ms and 300ms delays, continuing the
top-to-bottom stagger pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Hero card switches between orange/amber gradient (inactive) and green
gradient (active) when Auto-Withdraw is toggled, including the
lightning bolt watermark tint. Instant swap with no flicker. Replaced
blue accent color on the percentage slider and See All button with
Numo orange to match the app's brand palette.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Icon is now gray/neutral when off (matching Withdraw Now style) and
switches to green when toggled on. Changes in sync with the hero card
gradient transition.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
swedishfrenchpress and others added 18 commits April 7, 2026 16:55
…okens, standardized components

- Redesign payment failure screen: neutral background with contained red error
  indicator instead of full-screen red. Rewrites error copy to be specific and
  reassuring ("Payment not received", "No funds were transferred").
- Extract reusable dialog button styles (Confirm, Cancel, Destructive) and
  dialog typography styles (DialogTitle, DialogSubtitle) into styles.xml.
- Tokenize hardcoded corner radii: add radius_button (28dp) and row_subtitle_gap
  (2dp) to dimens.xml, replace 18 hardcoded instances across 13 layout files.
- Standardize all back button touch targets from 36dp to 48dp (icon_size_large)
  across 14 settings/detail screens.
- Fix non-uniform currency swap icon scaling on POS screen.
- Add brand-tinted section headers using navy color token.
- Improve empty state copy to teach the interface, not just acknowledge emptiness.
- Rewrite NFC error messages for merchant-friendly language (all 3 locales).
- Eliminate last hardcoded hex color in layouts.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Consolidate off-scale text sizes: 12sp → 11sp/13sp, 20sp → 18sp/22sp
  across 23 files to align with the defined type scale
- Standardize letter-spacing to the 5 defined values (-0.02, -0.012,
  -0.007, 0.03, 0.06), eliminating 13 non-standard instances
- Fix mint details page: match contact row styling to details rows
  (RowTitle labels, RowSubtitle values), replace inline typography with
  style references, use title case for contact labels instead of all-caps
- Remove all divider lines from details, contact, and action sections —
  section headers and row padding provide sufficient visual separation
- Standardize action row icon gap to row_icon_gap (14dp) matching Settings

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…olor

The top and bottom gradient fades on the "Add your first item" empty
state were fading to pure black (#000000) in dark mode, but the actual
background is #0B1215 (Numo Dark). This created a harsh visible border
where the gradient met the background. Changed both gradients to fade
to/from #0B1215 for a seamless blend.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…te duplicates

Replace 28 drawable files' hardcoded hex colors with semantic @color/ references
for proper dark mode support. Add missing tokens: status pill backgrounds, opacity
scale, hero gradient tints, dynamic island states, and badge backgrounds. Consolidate
duplicate dimension tokens (radius_l, card_corner_radius, card_elevation_small) and
expand elevation scale. Add color_brand_foreground as canonical alias for the
misleadingly-named color_primary_green tokens.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…act strings

Replace technical jargon with merchant-friendly language across EN/ES/PT:
- "Fiat" → "Local Currency", "GTIN" → "Barcode", "IDENTIFICATION" → "BARCODE & SKU"
- "INVENTORY" → "STOCK", "BASIC INFORMATION" → "DETAILS"
- VAT labels lead with "Tax" (universal term), parenthetical "(VAT)"
- "Total (incl. VAT)" → "Customer pays" — what merchants actually care about

Improve validation errors to be instructive rather than prohibitive:
- "Item name is required" → "Give your item a name"
- "Price must be positive" → "Price can't be negative"
- "Maximum 2 decimal places allowed" → "Use up to 2 decimal places"

Extract 11 hardcoded error strings from ItemFormValidator.kt into string
resources for localization. Extract "Edit Item" and "Delete Item" from
ItemEntryActivity.kt. Rewrite delete confirmation to state consequences
directly instead of "Are you sure?" pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…e, Material price inputs

Restructure the add item form for faster item entry:
- Move Save to a fixed bottom bar (always reachable)
- Collapse Identification/Inventory behind "Additional Options" toggle
- Separate Cancel from Delete in edit mode
- Replace standalone $/₿ symbols with Material TextInputLayout (OutlinedBox)
  using prefixText/suffixText for cleaner price inputs
- Add inline validation, save confirmation toasts, state preservation
- Shrink oversized VAT rate input, replace stock camera icon,
  normalize label widths, fix semantic token misuse

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add expandedHintEnabled=false to TextInputLayout style so $, ₿,
USD, and sats labels are visible even when the field is unfocused.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Replace 6+ inconsistent input field styles (filled, borderless, varying
radii/strokes) with a single outlined TextInputLayout pattern across all
screens. Converts 13 input fields to Material OutlinedBox, updates seed
word inputs and inline fields with matching outlined drawables, and
deletes 7 unused legacy drawables.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Receipt page: remove oversized hero icon, reduce amount to Heading1 scale,
replace heavy gray card sections with flat rows matching mint details
pattern, add Details section (payment type, mint, transaction ID), hide
redundant breakdown for simple single-currency payments, move print
action to primary bottom button.

Transaction detail: replace inline typography with style tokens
(Text.AmountSubtitle), hardcoded 2dp with row_subtitle_gap, hardcoded
28dp with icon_size_xs, align top bar padding with content rows.

Both pages now use consistent section headers, flat row patterns, and
design tokens from the shared type/spacing system.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…ty, i18n, polish

- Typography: replace 282 inline textSize/textStyle with textAppearance style refs (~30% → ~90% compliance), add Text.DisplayLarge (28sp) and Text.DisplayXL (32sp) to type scale
- Accessibility: add contentDescription or importantForAccessibility to 111 image elements (100% coverage), fix 8 touch targets below 48dp minimum
- i18n: extract ~50 hardcoded English strings to strings.xml with ES/PT translations, mark non-translatable strings
- Top bars: standardize padding to space_l (16dp) across 11 screens, fix android:tint → app:tint on 13 screens, zero out rogue elevation on 5 screens
- Buttons: apply canonical Widget.Numo.Button styles to 15 unstyled buttons, remove redundant inline attrs
- Dialogs: unify dialog_confirmation layout to match dialog_delete_confirmation pattern
- Elevation: replace 3 hardcoded values with @dimen/elevation_* tokens
- Layout: flatten nested LinearLayouts in 3 files (auto_withdraw, mints, mint_details)
- Settings: remove chevron forward disclosure icons from all settings rows

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…anges

Reverts all onboarding-specific changes from this branch back to main's
versions. Keeps AddMintBottomSheet and Bip39Wordlist (used by settings
and PIN reset). Restores drawables and strings that main's onboarding
layout depends on.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
# Conflicts:
#	app/src/main/java/com/electricdreams/numo/feature/baskets/BasketNamesSettingsActivity.kt
#	app/src/main/res/values/strings.xml
@swedishfrenchpress swedishfrenchpress changed the title [wip]feat/app UI refresh App-wide UI refresh: design system, components, and screen redesigns Apr 14, 2026
swedishfrenchpress and others added 9 commits April 17, 2026 08:58
…screen

- Enable edge-to-edge on Theme.Numo.BottomSheet so sheets fill to the
  screen bottom instead of leaving a dimmed strip above the gesture nav.
- Use Widget.Numo.Button.Dialog.Confirm for the AddMint and Receipt
  primary actions so their fill/text contrast correctly in dark mode
  instead of showing gray-on-gray.
- Skip system-bar padding on PaymentRequestActivity while the NFC result
  overlay is visible so the green/red fills under the status and nav
  bars instead of revealing the window background.
- Point color_nfc_success (and gradient stops) at @color/numo_green so
  the success screen matches the green theme's keypad color.
- Add enableEdgeToEdgeWithPill to TransactionDetailActivity so the top
  bar no longer clips behind the status bar on API 35+.
- Polish PIN entry / reset / setup layouts, confirmation dialogs, and
  shared styles for consistency with the refreshed system.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
…abulary, top bar component

Phase 1 — P0 dark-mode fixes:
- Add res/color-night/ with button_text_onboarding night variant (white text on
  dark-gray button fill in dark mode). Fixes the AddMint Add button + anywhere
  else onboarding uses bg_button_white.
- Rewrite button_text_obsidian to use theme-aware color_text_primary token so
  it inverts correctly in both modes (no separate night variant needed).

Phase 2 — fill button style vocabulary:
- New styles: Widget.Numo.Button.Onboarding.Primary / .Tertiary,
  Widget.Numo.Button.Secondary.Gray, Widget.Numo.Button.Primary.Black,
  Widget.Numo.Button.Charge, Widget.Numo.Button.EmptyState.Primary.
- Migrate 10 inline-background buttons in onboarding, modern_pos, payment
  failure/received, withdraw_success, tip_selection, empty_state_items to the
  shared styles. Drops 'backgroundTint="@null"' count in res/layout from 6 to 0.
- Convert the LinearLayout-as-button hack on onboarding's Create New Wallet
  action into a real MaterialButton using Onboarding.Primary.

Phase 3 — AddMint card + Scan QR:
- Convert the TextView-as-button add_button in component_add_mint_input to an
  AppCompatButton with Widget.Button.Primary.Green (AppCompatButton keeps the
  existing Kotlin setBackgroundResource swap in applyAddButtonStyle working —
  MaterialButton would have silently ignored those calls).
- Replace the Scan QR button's 11 inline styling attrs in bottom_sheet_add_mint
  with Widget.Button.Secondary.Outlined; override only the 3 intentional visual
  variants (17sp, primary text color, pill radius).

Phase 4 — component_top_bar (pilot):
- Add NumoTopBar custom view with declarative XML attrs (topBarTitle,
  topBarNavIcon, topBarActionIcon, topBarActionContentDescription).
- component_top_bar.xml holds the shared ConstraintLayout structure.
- Migrate activity_settings as the pilot — 33-line ConstraintLayout top bar
  collapses to 7 lines. Remaining 30 activities will migrate in a follow-up
  commit once the pilot is visually validated.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Completes Phase 4 — collapses the hand-rolled ConstraintLayout / LinearLayout
top bars across the app into the shared NumoTopBar custom view.

Activity layouts migrated (22): About, AutoWithdrawSettings, BasketArchive,
BasketNamesSettings, BasketReceipt, CurrencySettings, DeveloperSettings,
ErrorLogs, History (with overflow action), ItemEntry, LanguageSettings,
MintDetails, MintsSettings (with refresh action), RestoreWallet, Security,
SeedPhrase, ThemeSettings, TipsSettings, TransactionDetail (with overflow),
WebhookSettings, WithdrawLightning, WithdrawMeltQuote.

NumoTopBar enhancements discovered during migration:
- setTitle(text) for dynamic titles (RestoreWallet phases, ItemEntry edit mode)
- setNavEnabled(bool) for screens that disable back during async work
  (RestoreWallet, WithdrawMeltQuote)
- actionView getter so PopupMenu callers can anchor against the overflow icon
  (PaymentsHistoryActivity, TransactionDetailActivity)
- topBarActionTint attr for screens that need a non-default tint on the
  action icon (MintsSettings uses color_text_tertiary on refresh)

Intentionally deferred:
- activity_item_list — fab_add_item + done_reorder_button toggle between two
  trailing actions; NumoTopBar has a single action slot today.
- activity_item_selection, activity_saved_baskets — text-label actions
  (\"Saved Baskets\", \"View Archive\"); NumoTopBar only supports icon actions.
- activity_pin_entry/setup/reset — Phase 6 unifies these into a shared
  component_pin_screen layout, which will bring its own top bar treatment.
- activity_payment_failure, activity_payment_received — not a standard top
  bar (close-only icons or close + share without a title).

Net diff: ~600 LOC removed from layouts, ~60 LOC added in Kotlin activity
code updates. Every migrated screen renders status-bar-independent and
consistent-height top bars (56dp, Text.Title centered, 16dp horizontal
padding) without duplicating the ConstraintLayout structure.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Introduces a shared SettingsRowView custom view so settings rows stop
being open-coded as 27-line LinearLayouts. The declarative XML API
supports the patterns found across the settings screens:

    <com.electricdreams.numo.ui.components.SettingsRowView
        android:id="@+id/items_settings_item"
        app:rowIcon="@drawable/ic_catalog"
        app:rowTitle="@string/settings_item_items_title" />

    <com.electricdreams.numo.ui.components.SettingsRowView
        android:id="@+id/backup_mnemonic_item"
        app:rowIcon="@drawable/ic_key"
        app:rowTitle="@string/security_settings_backup_mnemonic_title"
        app:rowSubtitle="@string/security_settings_backup_mnemonic_subtitle"
        app:rowShowChevron="true" />

Attrs: rowIcon, rowIconTint, rowTitle, rowTitleColor, rowSubtitle,
rowTrailingIcon, rowTrailingText, rowShowChevron. Kotlin setters match
for dynamic updates (setTitle/setSubtitle/setTrailingText/etc).

Migrated:
- activity_settings.xml (12 rows) — every top-level settings nav row.
- activity_security_settings.xml (5 rows) — backup_mnemonic, setup_pin,
  change_pin, remove_pin (with rowTitleColor=color_warning_red for the
  destructive title), restore_wallet.

Net: ~400 LOC removed across those two layouts.

Deferred:
- activity_developer_settings.xml — mix of nav rows and a switch row
  (delay_lightning_invoice_item); the switch row needs a variant we
  don't have yet. Will migrate once SettingsRowView gains a trailing-
  switch slot, or via a separate SettingsSwitchRowView.
- activity_transaction_detail.xml — the 6 \"detail\" rows use different
  typography (Text.BodyBold/Text.Body), padding, and no ripple; a
  dedicated DetailRowView fits better than contorting SettingsRowView.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Phase 7 (color token sweep). Adds 4 new semantic tokens for opacity
variants used on onboarding's dark backdrop:

  color_text_on_dark_subtle  #99FFFFFF  (60% white — body copy)
  color_text_on_dark_faint   #73FFFFFF  (45% white — captions/hints)
  color_scrim_on_dark        #80FFFFFF  (50% white — touch scrim on dark)
  color_scrim_on_light       #80000000  (50% black — modal dim on light)

Migrates 36 hex values across 9 layouts to these + existing tokens
(color_text_on_dark, color_warning, color_error, color_text_primary,
color_text_secondary). After this pass:

    rg '#[0-9A-Fa-f]{6,8}' app/src/main/res/layout/   # zero matches

Files touched:
  activity_onboarding.xml — 20 hex sites across the full flow
  item_onboarding_mint_hero.xml — 4 sites (default mint card)
  item_onboarding_mint.xml, _header.xml, _add.xml — 4 sites (mint list)
  item_explainer_slide.xml — 1 (feature slide body copy)
  activity_pin_reset.xml — 3 sites (warning card; also dimens →
    @dimen/icon_size_small / space_m / text_button / text_chip)
  activity_restore_wallet.xml — 1 (error warning icon tint)
  activity_seed_phrase.xml — 1 (warning icon tint)

Phase 7 was scoped as a broad token sweep (hex + dimensions + inline
text attrs). This commit focuses on hex because that's the dark-mode
liability — a hardcoded #FFFFFF ignores the theme and can leak through
into dark mode. Dimension and text-attr tokenization in the remaining
screens is deferred (non-breaking, can be done incrementally).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Auto-withdraw: drop the decorative refresh icon next to the Auto-Withdraw
toggle row in activity_auto_withdraw_settings.xml. Removes the ImageView
from the layout and the corresponding toggleIcon field + findViewById +
no-op setColorFilter in AutoWithdrawSettingsActivity.

PIN screens: inset + layout + typography fixes.
- PinSetupActivity and PinResetActivity now call enableEdgeToEdgeWithPill
  in onCreate. PinEntryActivity already had its own inset listener. Fixes
  the back-button / progress-dot clipping against the status bar that was
  visible on targetSdk=35.
- activity_pin_setup and activity_pin_entry: content block (lock icon,
  title, subtitle, PIN dots, hint, error) is now a packed vertical chain
  anchored between the top anchor and the keypad, with bias=0.3 instead
  of flowing from the top. Removes the large dead-space gap that used to
  sit between the subtitle and the keypad.
- keypad_button_pin.xml: match POS keypad typography — Text.DisplayLarge
  (28sp) instead of inline 32sp, color_text_secondary instead of primary,
  @Dimen tokens for min-height and margin. Both keypads now render with
  identical numerals.

Kill default MaterialButton shadows. Every Widget.Numo.Button.* style
zeros stateListAnimator + elevation, but seven MaterialButtons were
using inline attributes and inherited the default raised-button shadow
animation. Migrated:
- pin_setup continue_button → Widget.Numo.Button.Dialog.Confirm
- pin_reset reset_button → Widget.Numo.Button.Dialog.Destructive
- restore_wallet continue_button → Widget.Numo.Button.Dialog.Confirm
- restore_wallet start_restore_button → Widget.Button.Primary.Green
- restore_wallet done_button → Widget.Button.Primary.Green
- seed_phrase copy_button → Widget.Numo.Button.Dialog.Confirm (kept
  icon overrides)
- onboarding accept_button (Get Started) keeps its unique 64dp/18sp/
  32dp-corner hero look but gets stateListAnimator=@null + elevation=0dp
  inline so it stays flat without pulling in the shared style.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Mints page — strip decorative boxes and redundant data so each row
does exactly one job.

- Lightning Mint section: drop the CardView + green-gradient FrameLayout
  and the decorative lightning bolt/fade overlay. Flatten to a plain
  LinearLayout with the same icon, name, URL, divider, balance, and
  swap-unknown-mints toggle. Clean up the now-dead heroBolt field,
  findViewById, and updateHeroBoltColor method + call sites in
  MintsSettingsActivity.
- Lightning Mint section: remove the two-sentence description
  ("All Lightning payments will be received to this mint. Tap any
  mint below...") — the section header already implies it, and spelling
  out the mechanism violates the invisible-technology principle.
- All Mints section: remove the \"Total Balance\" row + divider. A sum
  across mints doesn't help a merchant decide which mint to receive to;
  the individual balances in the list already carry that information.
  updateTotalBalance() and its three backing fields are gone.
- All Mints list: filter the active Lightning mint out so it stops
  appearing twice with the same balance. setLightningMint now rebuilds
  the list whenever the preferred mint changes, so the previous one
  reappears. If after filtering there's nothing left, the ALL MINTS
  header and container hide together.
- All Mints list: remove the CardView wrapper around the list so it
  matches the flat Lightning Mint section. The mintsCard field is
  merged into mintsContainer for visibility toggling.

Mint Details page:
- Drop the CardView + green-gradient hero. Icon, name, URL, and balance
  now sit on the page background.
- Remove the gray bg_pill_badge around the balance text so \"₿0\"
  renders plainly.

Auto-withdraw settings:
- Remove the down-arrow icon next to \"Withdraw Now\" in the Manual
  Withdraw row. Title and subtitle now align flush with the section
  header above.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
# Conflicts:
#	.gitignore
#	app/src/main/java/com/electricdreams/numo/PaymentRequestActivity.kt
#	app/src/main/java/com/electricdreams/numo/feature/settings/CurrencySettingsActivity.kt
#	app/src/main/res/layout/activity_currency_settings.xml
The restore-wallet layout no longer has a standalone R.id.title_text;
the title is hosted inside NumoTopBar (R.id.top_bar_title) and updated
via topBar.setTitle(). Update the two stale assertions that were causing
testDebugUnitTest NPEs in CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@swedishfrenchpress swedishfrenchpress marked this pull request as ready for review April 17, 2026 09:15
@swedishfrenchpress
Copy link
Copy Markdown
Collaborator Author

Sorry this PR is so big.

I tried to split it up but every time I tried to break it into a "top bar only" PR, or a "bottom sheets only" PR, or "just the settings rows," something broke. So I made a judgment call to submit this as one PR rather than keep ping-ponging. I should have stopped sooner and asked you guys for a better different strategy.

If you'd rather split this PR tell me which feature you want first and I'll try to open a new branch from and ask claude to cherry pick. fwiw I've tried that three times already but it didn't work.

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

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant