Commit Graph
1264 Commits
Author SHA1 Message Date
Barry Deen 23b11104c3 fix: remove stale wallet translation keys blocking release build
Six wallet string keys (wallet_connect_wallet, wallet_choose_how,
wallet_create_new, wallet_create_description, wallet_nwc_description,
wallet_spark) were renamed in the default locale but left behind in
10 translation files, causing 60 ExtraTranslation lint errors that
failed lintVitalRelease.
2026-06-05 17:30:12 -04:00
Barry DeenandGitHub fa82ac2a1a Merge pull request #583 from barrydeen/feat/wot-filter-threads
feat: apply web of trust filter to thread replies
2026-06-05 17:17:09 -04:00
Barry Deen 2e19a69249 chore: bump version to 1.1.1 2026-06-05 17:14:58 -04:00
Barry Deen 198313e6b3 feat: apply web of trust filter to thread replies
The WoT filter was already silently dropping events at EventRepository
ingestion and in NotificationRepository, but thread replies bypassed
both paths — ThreadViewModel keeps its own threadEvents map seeded via
cacheEvent() and getCachedThreadEvents(), neither of which checks WoT.

Apply isWotFiltered in rebuildTree() alongside the existing block /
mute / spam filters. The root note is always shown (user explicitly
navigated to it); replies from authors outside the qualified network
are silently dropped, matching how WoT behaves in the feed and
notifications.
2026-06-05 17:09:30 -04:00
Barry DeenandGitHub a7020603d2 Merge pull request #566 from dmnyc/fix/spark-default-wallet-banner
fix(wallet): refresh Spark display state on mnemonic swap + banner copy
2026-05-25 12:59:28 -04:00
Barry DeenandGitHub 14f237b6a1 Merge pull request #559 from dmnyc/feat/zap-with-image
feat(zap): render zap messages as mini-posts in the engagement drawer
2026-05-25 12:58:49 -04:00
Barry DeenandGitHub b0a9eb379d Merge pull request #561 from dmnyc/fix/nwc-connect-screen-ios-parity
fix(wallet): NWC connect screen — iOS 1:1 redesign
2026-05-25 12:58:01 -04:00
Barry DeenandGitHub bdef0b2748 Merge pull request #565 from dmnyc/feat/android-dark-mode-backgrounds
feat(theme): iOS-parity dark-mode polish for Android
2026-05-25 12:57:43 -04:00
Barry DeenandGitHub 6416a8353e Merge pull request #562 from dmnyc/feat/wallet-balance-toggle
feat(wallet): cycle balance display between sats, fiat, and hidden
2026-05-25 12:57:21 -04:00
dmnyc b790d4e40e fix(wallet): tighten default-wallet banner copy
Mirrors iOS — title shortens from "Your default wallet is secured
by your key" (wrapped to two lines on most phones) to "Secured by
your Nostr key", and the body drops the redundant "Derived from
your Nostr key —" prefix now that the title carries the same idea.
Net effect: same information, one-line title, less wall-of-text
under it.
2026-05-23 17:47:40 -04:00
dmnyc 106c6568de fix(wallet): surface default-wallet banner after restore and match iOS ack semantics
Two related issues on the Spark wallet banner state:

1. After restoring the nsec-derived default wallet via NIP-78,
   no banner showed at all. The "Your default wallet is secured
   by your key" welcome banner is gated on
   `isDefaultWallet && !seedBackupAcked`, and `seedBackupAcked`
   was sticky from a prior generateDefaultFromPrivkey call (or
   prior tap-through) — so a returning user saw nothing.
2. restoreSparkWallet hard-coded `_isDefaultWallet.value = false`
   regardless of what was restored. Users restoring their default
   nsec-derived seed silently lost the "default wallet" surface
   (banner, non-nag delete confirmation, NIP-78 publish gate).

Fixes:

- SparkRepository.saveMnemonic now clears the `seed_backup_acked`
  prefs key. Mirrors iOS SparkWallet.saveMnemonic which clears the
  equivalent UserDefaults key — every mnemonic save is treated as
  a fresh wallet that needs its own acknowledgement.
- SparkRepository.generateDefaultFromPrivkey no longer auto-acks
  the seed backup. Routes through saveMnemonic for consistency.
  Matches iOS's behaviour of leaving the welcome banner visible
  until the user taps through.
- WalletViewModel.restoreSparkWallet now sets `_isDefaultWallet`
  via `computeIsDefaultWallet()` instead of hard-coding false —
  restoring the nsec-derived seed correctly resolves to true.
- WalletViewModel.startDefaultWallet drops its `_seedBackupAcked
  = true` auto-set. Banner now shows after default generation
  like iOS.
- clearWalletDisplayState also resets `_seedBackupAcked` to false
  so the ViewModel-side StateFlow doesn't carry the previous
  wallet's acked value across a mnemonic swap.
2026-05-23 17:43:19 -04:00
dmnyc 22a63a5cfd fix(wallet): clear transaction history on Spark mnemonic swap
The transactions list, lightning address, and pagination state were
cached on the WalletViewModel and never reset when the underlying
Spark mnemonic was replaced (restore from backup, paste a new seed,
swap to default, disconnect, delete). The user saw the previous
wallet's transactions briefly — or persistently if the new wallet's
first fetch hadn't completed yet — sitting above the new wallet's
balance / address.

Add a private `clearWalletDisplayState()` helper that wipes the
per-wallet ViewModel-side display state (transactions, transactions
error, hasMoreTransactions, lightningAddress + its error/loading
flags). Mirrors iOS `WalletStore.clearDisplayState`, called from
every mnemonic-replace and disconnect path:

- generateSparkWallet (new mnemonic)
- restoreSparkWallet (paste / NIP-78 restore)
- useDefaultWallet (switch to nsec-derived default)
- disconnectWallet (logout-style disconnect)
- deleteWallet (the destructive path)
- suspendForAccountSwitch (account swap mid-session)

The repo-side balance flow already clears on clearMnemonic; only the
ViewModel-side display state needed explicit clearing.
2026-05-23 17:38:26 -04:00
dmnyc 4326199a45 fix(wallet): suppress default-wallet banner for restored non-default seeds
Mirrors iOS barrydeen/wisp-ios#175. The Wallet screen kept showing
the "default wallet is secured by your key" banner even after the
user restored a non-default Spark wallet from a NIP-78 backup.
That banner's claim ("derives from your Nostr key — restores on
any device") is false for any restored wallet whose seed isn't the
deterministic nsec-derived mnemonic, so the user saw a misleading
"you're backed up" affordance over a wallet that actually needs a
manual seed-phrase backup.

Root cause: SparkRepository.isDefaultWallet() returned a sticky
encPrefs flag (`spark_is_default`) that was set by
generateDefaultFromPrivkey when the initial nsec-derived wallet
was created and never cleared on the restore path. saveMnemonic
overwrote the keychain mnemonic without touching the flag, so the
banner kept rendering against the new (non-default) seed.

Replace the flag with a computed check: compare the currently-saved
mnemonic against entropyToMnemonic(Keys.deriveSparkEntropy(privkey))
for the active account. The flag becomes unnecessary and is dropped
— generateDefaultFromPrivkey no longer writes it, clearMnemonic no
longer removes it. The `spark_is_default` encPrefs entry becomes
orphaned data; safe to leave as-is and ignore on future loads.

Call sites:
- WalletViewModel gains a `computeIsDefaultWallet()` private helper
  that resolves the active keypair via keyRepo and delegates to the
  new SparkRepository.isDefaultWallet(privkey:). Used everywhere the
  ViewModel needed the answer (StateFlow init, settings-page backup
  status check, delete-confirmation gate, post-connect backup check,
  refreshState).
- OnboardingViewModel's non-default-backup-publish gate decodes
  keyRepo.getKeypair()?.privkey and passes it through.

Watch-only accounts (no privkey) fall through to false naturally.
2026-05-23 17:32:35 -04:00
The Daniel 6f97c42b14 fix(theme): inset-aware chrome compaction (no first-frame snap)
Previous attempt computed total chrome height as
`Modifier.height(content + insetReadViaPaddingValues)`. The inset is
read at composition time and arrives as 0 on the very first frame
before the system-bar inset connection delivers its value — the bar
laid out at the shorter (no-inset) height, then re-measured once the
inset arrived. Visible as a one-frame snap on app cold start.

Switch to a layout-time pattern that subscribes to inset changes
correctly:

    Modifier
        .windowInsetsPadding(insets)   // reserves the inset via padding
        .height(contentHeight)         // content area only

`windowInsetsPadding` is a Modifier.Node that re-layouts (not re-
composes) on inset arrival, so the bar measures at the right total
height on the first frame. The bar's own `windowInsets` is set to
`WindowInsets(0)` so it doesn't double-pad.

Applied to:
- `BottomBar` NavigationBar — content height 56dp + navigation-bars inset
- `FeedScreen` CenterAlignedTopAppBar — content height 48dp + status-bars
  inset
2026-05-23 16:53:13 -04:00
The Daniel 45ce719af9 feat(theme): iOS-red error color, darken profile tab strip
Two more iOS-parity tweaks:

- `WispTheme` sets `error = #FF3B30` (and `onError = white`) explicitly
  on every color-scheme variant (custom dark/light + preset dark/light).
  Material 3's defaults for `error` render pinkish in dark mode and a
  muted brick red in light mode — neither matches the iOS systemRed used
  by the rest of the destructive UI in this app. With this override,
  every `MaterialTheme.colorScheme.error` consumer (logout button,
  destructive labels, error text) now matches the iOS counterpart and
  the existing #FF3B30 used directly on Disconnect/Switch wallet flows.
- `UserProfileScreen` sticky-header tab strip + the sort-pill row below
  it use `background` (#0A0A0B) instead of `surface` (#1C1C1E). The two
  grey tiers stacked above each other read as visually noisy on the
  profile; the iOS profile uses one near-black across both. Body posts
  below still render with the elevated tier where they need to.
2026-05-23 16:53:13 -04:00
The Daniel 8800a9c1f5 feat(theme): full-width post divider, hide zero-value action counters
Two post-card refinements that move the feed toward the iOS look:

- `PostCard` now wraps content + the inter-post `HorizontalDivider`
  in an outer Column. The content Column keeps its 16dp horizontal
  padding (so post body / action bar / metadata stay inset), but the
  divider sits outside that padding and runs edge-to-edge. Matches
  iOS where the separator spans the full viewport width.
- `ActionBar` gates each of the four counters (`replyCount`,
  `likeCount`, `repostCount`, `zapSats`) on `> 0`. Empty engagement
  no longer shows "0" beside the icon — matches iOS where the
  count text only appears when there's something to show. As soon
  as the count crosses 1, the number reappears.
2026-05-23 16:53:13 -04:00
The Daniel aeeb982ee4 feat(theme): compact chrome heights, drop tab pill, iOS badge red
iOS-style cleanup on the home screen's top + bottom chrome:

- `FeedScreen` `CenterAlignedTopAppBar` clamps to 48dp content +
  status-bar inset (was Material's default ~64dp + inset). Drops the
  gap below the icon row that pushed the feed down.
- `BottomBar` `NavigationBar` clamps to 56dp content + gesture inset
  (was Material's default 80dp). The 80dp slot reserves space for the
  label text we don't render — pure waste on small phones.
- Tab indicator pill is suppressed (`indicatorColor = Color.Transparent`).
  The selected-icon orange tint is enough signal; matches iOS where
  the tab bar has no rounded background on the active tab.
- Notification dot uses iOS systemRed (#FF3B30) instead of the app's
  primary accent so it reads as "alert" rather than "branded highlight"
  — same red iOS shows on the bell.
- Filter icon for "All" content types switches from
  `Icons.Outlined.Dashboard` (1 large + 3 small panels) to
  `Icons.Outlined.GridView` (2x2 of equal squares) to match the iOS
  toolbar icon.
2026-05-23 16:53:13 -04:00
The Daniel 87479fbbcf feat(theme): match TopAppBar chrome to body color across screens
Default `TopAppBarDefaults.topAppBarColors` uses `MaterialTheme.color
Scheme.surface`, which sat noticeably lighter than the body after the
preceding dark-mode background darken. iOS uses one near-black across
body + chrome and reserves the lighter "surface" tone for elevated
controls (pills, cards). Switch every screen's TopAppBar container
to `background` so chrome reads as part of the page, not as a raised
layer above it.

30 screens touched; only `containerColor` lines inside
`TopAppBarDefaults.topAppBarColors(...)` blocks are changed, so other
surface usages (cards, dialogs, sheets, the elevated pills the home
top bar overlays) keep their existing tone.
2026-05-23 16:53:13 -04:00
The Daniel 1fccd39132 feat(theme): darken default dark-mode backgrounds to match iOS
The default ("custom") Android dark theme rendered noticeably lighter
than iOS, which uses near-black backgrounds. Align with iOS HIG dark
system colors (slight off-black for the base, iOS secondary/tertiary
greys for elevated surfaces) so the two platforms feel like the same
app in dark mode.

- background: #131215 → #0A0A0B  (slight off-black, OLED-friendly
  without the harsh #000 step on LCD)
- surface:    #1F1E21 → #1C1C1E  (iOS secondarySystemBackground)
- surfaceVariant: #2B2A2E → #2C2C2E  (iOS tertiarySystemBackground)
- outline:    #343338 → #38383A  (iOS separator on dark)

Named presets (Nord, Dracula, Gruvbox, …) are left untouched — their
distinctive backgrounds are part of each preset's identity.
2026-05-23 16:50:16 -04:00
The Daniel 521562be15 fix(wallet): drop TopAppBar on setup screens, add NWC Close pill
iOS 1:1 entry-path polish on top of the NWC connect redesign:

- `WalletScreen` hides the "Wallet" TopAppBar on `NwcSetup`,
  `SparkSetup`, and `SparkRestoreSeed` in addition to `Home` /
  `ModeSelection`. The setup screens render their own top-right
  Close pill (SparkSetup already had one; this commit adds the
  matching pill to `WalletConnectionContent`). Frees up headroom
  for the centered logo + title layout to match iOS exactly.
- Setup-screen Column now applies `.statusBarsPadding()` so the
  Close pill clears the device status bar / notch.
- 12dp top spacer above both Close pills for breathing room.
2026-05-22 19:40:20 -04:00
The Daniel ca18158ec5 feat(wallet): cycle balance display between sats, fiat, and hidden
Ports iOS PR barrydeen/wisp-ios#166 to Android. Tapping the wallet
dashboard balance now cycles through three states instead of the
prior plain hide/show toggle:

1. SATS   — current default rendering ("21,000 sats" or app-wide
            fiat when [FiatPreferences.isFiatMode] is on).
2. FIAT   — wallet-screen-scoped fiat. Renders the balance + each tx
            row's amount/fee in the user's currently-selected fiat
            currency without flipping the app-wide fiat-mode flag, so
            feed sat counts elsewhere stay in sats.
3. HIDDEN — masks the dashboard balance AND every per-row amount +
            fee in the transaction history, useful for screenshots /
            shoulder-surfing scenarios.

Storage: new per-pubkey key `walletBalanceDisplay_<pubkey>` in the
existing `wisp_settings` SharedPreferences. The legacy global
`balance_hidden` Bool is read once per pubkey when no per-pubkey
entry exists (true → HIDDEN, false → SATS) and then a migrated value
is written; legacy key is left in place so older builds rolled back
keep their preference.

Storage-key format matches iOS, so the cross-platform port doc lives
on the iOS side (see PR #166). Companion enum
`WalletBalanceDisplayMode` carries the `next()` cycle helper and the
read/write helpers; both `WalletHomeContent` and the transaction
history `TransactionRow` read the same key.
2026-05-22 17:18:34 -04:00
The Daniel 5bc914ecb6 fix(wallet): NWC connect screen — iOS 1:1 redesign
Drops the Recommended-wallets stack and rewrites the screen layout to
match iOS exactly: centered NWC logo + title + subtitle, a single
paste/scan card with the connection string area on top and Paste +
Scan QR buttons split by a vertical divider on the bottom, an
info-icon helper line ("Connection string starts with
nostr+walletconnect://"), then a full-width Connect button.

Paste reads `LocalClipboardManager` directly when tapped (with the
existing `NsecPasteGuard` check so an accidental nsec can't slip
through). Scan QR opens the existing `QrScanner` dialog and
populates the connection string on success. The previous
OutlinedTextField + trailing-icon + Recommended-Cards layout is
gone — keeping zero overlap with the iOS view.

Two new strings:
- `wallet_nwc_paste_prompt`  — "Paste the connection string from
  your NWC-compatible wallet."
- `wallet_nwc_connection_hint` — "Connection string starts with
  nostr+walletconnect://"
2026-05-22 17:10:10 -04:00
The Daniel 71d4228601 feat(zap): render image URLs inline in zap drawer, collapse to [image] on top banner
Two surfaces render zap-receipt messages, each with a different
treatment to suit its constraints.

Engagement-drawer zap row (mini-post)
- Now renders the message through the same `RichContent` pipeline a
  regular post body uses. Body text, plain links, hashtags, profile
  / note mentions, and inline images all render the way they would
  in a feed post. The row grows vertically rather than truncating —
  long zapvertising payloads stay readable.
- Layout: avatar (top-aligned, 30dp) + right-side column (display
  name + private icon + bolt + sats on top; RichContent body below).
- `eventRepo` is plumbed from `ReactionDetailsSection` into `ZapRow`
  so RichContent can resolve profile mentions.

Top-zap banner above the action bar
- Single-line preview. Image URLs collapse to the literal token
  `[image]` (helpers in `ui/util/ZapMessageImage.kt`) so the sats
  amount stays visible. Surrounding text is preserved
  ("nice post [image]"). No image is loaded in the banner — the
  drawer handles that.

Cross-platform: `ZAP_IMAGE_PARITY.md` documents the contract — banner
uses URL-collapse, drawer uses the full post-body renderer; iOS port
checklist + visual test included.
2026-05-22 12:20:39 -04:00
Barry DeenandGitHub 6833fba03e Merge pull request #555 from dmnyc/feat/profile-ux-polish
feat(profile): circle action buttons, tighter tabs, quoted note navigation
2026-05-20 10:47:04 -04:00
Barry Deen bd5fa0d684 Merge branch 'main' into feat/profile-ux-polish 2026-05-20 10:46:14 -04:00
Barry DeenandGitHub d0ff54d530 Merge pull request #554 from dmnyc/feat/search-segmented-tabs
feat: segmented pill tabs on search screen
2026-05-20 10:41:48 -04:00
Barry DeenandGitHub 1dc4ef0cfe Merge pull request #553 from dmnyc/feat/nsec-paste-guard
feat: nsec paste guard — block accidental private key pasting app-wide
2026-05-20 10:39:06 -04:00
Barry Deen 895c105848 Merge branch 'main' into feat/nsec-paste-guard
Resolved conflicts in Navigation.kt, AuthScreen.kt, and ComposeScreen.kt
to combine the nsec paste guard with the CompositionLocalProvider
read-only signing wrapper, QR scanner on AuthScreen, and the compose
gallery placeholder change.
2026-05-20 10:36:46 -04:00
Barry DeenandGitHub 1fe7f219a0 Merge pull request #552 from dmnyc/feat/qr-scan-watch-only-mode
feat(login): QR scan + watch-only mode for npub/nprofile
2026-05-20 10:32:36 -04:00
Barry Deen 493102d762 Merge remote-tracking branch 'origin/main' into feat/qr-scan-watch-only-mode
# Conflicts:
#	app/src/main/kotlin/com/wisp/app/ui/component/WispDrawerContent.kt
2026-05-20 10:31:47 -04:00
Barry DeenandGitHub ab9c31be57 Merge pull request #551 from dmnyc/feat/update-nostr-icon
feat(auth): swap Nostr ostrich icon for new pixel logo
2026-05-20 10:28:52 -04:00
Barry DeenandGitHub d4b5881e59 Merge pull request #550 from dmnyc/feat/wallet-derivation-test-vectors
test(wallet): cross-platform parity spec + Spark derivation test vectors
2026-05-20 10:28:34 -04:00
Barry DeenandGitHub 30b9966115 Merge pull request #549 from dmnyc/feat/wallet-dashboard-parity
feat(wallet): dashboard parity — top bar, welcome banner, pill, inline tx
2026-05-20 10:25:58 -04:00
Barry Deen e39e1f7943 Merge remote-tracking branch 'origin/main' into feat/wallet-dashboard-parity
# Conflicts:
#	app/src/main/kotlin/com/wisp/app/ui/screen/WalletScreen.kt
2026-05-20 10:25:25 -04:00
Barry DeenandGitHub 33dd703235 Merge pull request #548 from dmnyc/feat/wallet-connect-two-tier
feat(wallet): two-tier Connect screen + Spark sub-screen
2026-05-20 10:20:22 -04:00
Barry DeenandGitHub 68a959a31d Merge pull request #547 from dmnyc/feat/wallet-icon-credit-card
feat(wallet): universal credit-card wallet icon
2026-05-20 10:19:30 -04:00
Barry DeenandGitHub b476dcda24 Merge pull request #546 from dmnyc/feat/compose-countdown-progress
feat(compose): countdown progress bar + auto-scroll preview
2026-05-20 10:18:29 -04:00
The Daniel e5bc321765 feat(profile): circle action buttons, tighter tabs, quoted note navigation
- Replace Follow/Mute/DM/Zap profile buttons with uniform 40dp circle
  Surface icons matching iOS-style action bar
- Add Mute/Unmute button to profile header (VolumeOff/VolumeUp icons)
- Fix quoted note tap-through: outer PostCard uses Final-pass pointer
  detection so inner clickable wins and tapping opens the thread view
- Wire NoteActions.onProfileClick so tapping an author avatar inside
  an embedded/quoted note navigates to their profile directly
- Add onProfileClick to PostCard calls so repost card original-author
  avatars navigate to their profile
- Replace M3 Tab composable (90dp min-width enforced) with plain Box
  + clickable for text-proportional tab widths and a custom narrow
  indicator underline — eliminates uneven tab spacing
- Add transparent spacer and right-side gradient fade below sticky tab bar
- Add "no replies" empty state illustration to ThreadScreen
- Mute action wired through Navigation → FeedViewModel.blockUser
- Circular post FAB with edit icon
2026-05-20 07:49:57 -04:00
The Daniel 4934338b6d feat: replace search filter dropdown with segmented pill tabs
Redesigns the search screen header to match iOS — a two-tab pill
control (People | Notes) replaces the old ArrowDropDown button, and
the search field moves below the tabs in its own row alongside the
Tune filter toggle.
2026-05-18 22:07:32 -04:00
The Daniel fdc1832bf0 fix: display npub instead of raw hex pubkey in all fallback locations
Adds String.toNpub() extension (bech32 via Nip19) and updates ProfileData.displayString
to use it. All screens and components that fell back to a truncated hex pubkey when no
display name or NIP-05 was available now show the bech32 npub form instead.
2026-05-18 21:59:42 -04:00
The Daniel ab529ea6b0 feat: add nsec paste guard — block accidental private key pasting app-wide
Intercepts all text field input to detect nsec1... patterns and block them
before they reach the field state. A red warning pill floats above all
content (including dialogs and the keyboard) using a non-touchable,
non-focusable Dialog window. The keyboard is force-closed on block via
InputMethodManager so the pill is always visible.

The login/import screen is the only exception — it sets nsecPasteAllowed=true
via DisposableEffect for the duration of its lifecycle.

Also changes the onboarding "Publishing…" button label to "Creating account…".
2026-05-18 21:59:42 -04:00
The Daniel 36c2d014f6 feat(login): QR scan + watch-only mode for npub/nprofile
- QR scan button on the Nostr login sheet (eye icon first, QR second)
  scans nsec/npub/nprofile and auto-logs in; scanner rendered at
  Activity level so CameraX binds to the correct lifecycle owner

- nprofile1 login support: decodes TLV, extracts pubkey, saves as
  READ_ONLY alongside existing npub and hex-pubkey paths

- Watch-only onboarding: READ_ONLY logins skip the profile-setup flow
  and go to a two-step WatchOnlyOnboardingScreen (info + relay-wait
  spinner) before landing on the feed

- LocalCanSign CompositionLocal propagates signing capability through
  the entire nav tree; consumed by:
    - PostCard: hides full ActionBar (reply/react/repost/zap)
    - FeedScreen: hides compose FAB; reply callback is no-op
    - WispBottomBar: filters out Messages and Wallet tabs
    - WispDrawerContent: hides Messages and Wallet rows
    - UserProfileScreen: hides edit-profile, follow, zap, DM buttons

- Sidebar account picker shows eye icon next to watch-only accounts

- Keys screen branches: READ_ONLY shows "No private key is stored on
  this device" instead of the reveal button; LOCAL shows QR and copy
  buttons for both npub and nsec (nsec QR requires biometric reveal
  first; user avatar overlaid on both QR codes when available)

- Logout dialog swaps private-key backup warning for
  "Sign back in with your npub anytime" on watch-only accounts
2026-05-18 19:01:33 -04:00
The Daniel 7d35322bc1 fix(wallet): restore status-bar inset on Home dashboard
Hiding the app-bar removed the only thing providing top-edge spacing,
so the brand logo + refresh + settings row collided with the system
status icons. Reintroduce a clean inset on the Home content's root
Column via `statusBarsPadding()`; sub-pages keep their own app-bar,
which already supplies the equivalent gap.
2026-05-18 08:54:38 -04:00
The Daniel d87f7a9a66 feat(auth): swap Nostr ostrich icon for new pixel logo
Replace the curved ostrich vector with the new pixel-style Nostr mark
(purple #A223E9 body, orange #FD962C accents) on a 240x270 viewport.
2026-05-18 08:41:59 -04:00
The Daniel d466fb6840 feat(wallet): hide app-bar on home, NWC node alias on dashboard, Wallet Info expandable
Three iOS-parity additions to the wallet dashboard + settings.

1. Hide the top "← Wallet" app-bar on the Home dashboard. The bottom
   nav is the entry point, the dashboard's own logo + refresh +
   settings row plays the role of a toolbar, and the iOS app doesn't
   carry a redundant title strip either. Sub-pages still render the
   app-bar so back-nav stays reachable.

2. Render the NWC node alias to the right of the NWC logo in the
   dashboard top bar. The alias is fetched once post-connect via
   NIP-47 `get_info` (new request type in `Nip47.kt`), cached on
   `NwcRepository.nodeAlias`. NWC drawable also painted in its
   brand palette (warm orange + purple accent) so the top-bar mark
   matches iOS instead of rendering as a tinted black silhouette.

3. New Wallet Info expandable card in settings for both modes.
   Collapsed shows just the brand mark (+ alias on NWC) with a
   chevron; tap expands the per-mode detail rows:
   • Spark — Wallet ID (identity pubkey, truncated, copy), Network,
     SDK version.
   • NWC — Service pubkey, Client pubkey, Relay, Encryption,
     Lightning address (if set), Supported methods (chips).
   Spark identity pubkey is captured from the existing `getInfo()`
   call so no extra SDK roundtrip is needed. NWC connection metadata
   is exposed via a new `NwcRepository.ConnectionInfo` data class,
   updated whenever the connection string is parsed or encryption
   is renegotiated.
2026-05-18 08:09:43 -04:00
The Daniel 4496b31114 feat(wallet): outlined credit-card variant for unselected nav + drawer
Add `ic_wallet_outlined.xml` as the inactive twin of `ic_wallet.xml`
— identical card / stripe / chip geometry, the body switched from
a filled silhouette to a 1.5dp stroke. Stripe and chip stay solid
so the glyph still reads as a card-with-magstripe-and-chip when
hollow.

Where it's used:

  • Bottom nav wallet tab — solid icon when the tab is selected,
    outlined when not. Mirrors how the other tabs swap Material
    Filled/Outlined variants on selection.
  • Sidebar drawer wallet row — always outlined to match iOS,
    which renders the drawer wallet glyph hollow regardless of
    nav state.
  • Logout-warning embedded-wallet bullet — switched to outlined
    too so the icon vocabulary stays consistent inside the drawer.

Bottom-bar enum gains a second drawable slot so the
`selectedIconRes` / `unselectedIconRes` pair drives the swap
without per-tab branching in the composable.
2026-05-18 07:26:35 -04:00
The Daniel ae400abc23 fix(wallet): NWC brand colors + bottom-anchored mode picker rows
Two issues in the new two-tier connect screen:

  1. NWC logo rendered in the mode picker as a flat monochrome
     silhouette. The drawable was all #FF000000 and Compose had no
     explicit tint, so it fell through as black on the dark theme.
     Paint the two paths with their brand colors (warm orange + a
     purple accent on the upper sliver). The desaturated footer /
     settings renders continue to apply a colorFilter so the
     brand colors only show where the logo is the focal element.

  2. The mode picker's Spark + NWC rows rode up near the top of the
     screen instead of anchoring near the bottom. Root cause: the
     wallet routing wrapped every page in a verticalScroll Column,
     which gives the inner content unbounded height — so the
     fillMaxSize + weighted Spacer layout I built for the mode
     picker collapsed and the rows pinned to the copy stack.

     Fix: route the mode picker case through a separate non-
     scrolling Column. The other Spark setup screens (NwcSetup,
     SparkSetup, SparkRestoreSeed, SparkBackup) keep their
     verticalScroll wrapper because they have text inputs and
     status output that can grow.
2026-05-17 23:34:29 -04:00
The Daniel def48dc854 feat(wallet): dashboard parity with iOS — top bar, welcome banner, pill, inline transactions
Reshape the wallet home screen to match the iOS layout per
WALLET_PARITY.md §3.

Changes:

  • Top bar — Spark+Breez (or NWC) brand logo on the left, refresh
    + settings icons on the right. The wallet branding moves up from
    the bottom "powered by" footer; the standalone refresh button
    that used to live under the balance number is gone.
  • Welcome banner — default (nsec-derived) wallets get a tappable
    card with a key icon, title "Your default wallet is secured by
    your key", and body explaining the nsec-as-backup property. Tap
    routes to the recovery-phrase screen so users can also save the
    seed locally. Hides once seedBackupAcked flips. Custom wallets
    keep the existing amber seed-not-viewed nudge and red backup-
    missing warning.
  • Lightning address pill — collapsed surface chip with bolt icon
    prefix, tap-to-copy. Replaces the bare primary-color text line.
    Setup CTA (when no address is registered) renders as the same
    pill shape with an outlined accent border.
  • Send / Receive — circular 64dp accent-tinted buttons in a single
    centered row (was 72dp on primary container). Extracted as
    WalletActionButton.
  • Recent transactions footer — anchored to the bottom of the
    dashboard. "RECENT" header + "View all ^" affordance with the
    most-recent transaction visible inline. Tap any of it to expand
    to the full transactions screen.

The dashboard preloads recent transactions on connect via a
LaunchedEffect so the inline footer has data without the user
having to visit the transactions screen first.

iOS counterpart: this layout already ships on iOS; brings Android
visually in line.
2026-05-17 23:26:40 -04:00
The Daniel e2d64c9b32 feat(wallet): universal credit-card wallet icon
Replace the Material AccountBalanceWallet glyph with a credit-card
silhouette vector drawable per WALLET_PARITY.md §3.1. Used uniformly
in:

  • Bottom nav wallet tab
  • Sidebar drawer wallet row
  • Logout-warning embedded-wallet bullet

The drawer wallet row previously switched between three icons based
on the user's zap-icon preference / fiat-mode setting (CurrencyBitcoin
/ ic_bolt / AccountBalanceWallet). That conditional is removed — the
wallet icon is fixed per spec because wallet ≠ zap glyph; the two
settings control different visuals.

The new vector uses `?attr/colorControlNormal` for fill so it tints
correctly in both selected/unselected nav states and works across
themes without per-call colorFilter rewiring.
2026-05-17 23:17:05 -04:00
The Daniel 7c94dfd250 feat(wallet): two-tier Connect screen + Spark sub-screen
Restructure the wallet connect UX per WALLET_PARITY.md §2.6 to match
the iOS flow. Top-level screen is a minimal mode picker (Spark wallet
/ Nostr Wallet Connect) with a centered logo + intro copy; tapping
Spark navigates to a sub-screen with four explicit options:

  • Use my default wallet (gated on hasKeypair)
  • Create new wallet
  • Restore from seed phrase
  • Restore from relays

This fixes the long-standing discoverability gap where the
nsec-derived-wallet recovery path was only reachable via a button
labeled "Create a New Wallet" — actively misleading users trying to
recover an existing wallet. The "Use my default wallet" CTA is now a
first-class row in the Spark sub-screen.

Two behavioral changes required to make the new flow reachable:

  • Remove the silent maybeAutoCreateDefaultWallet() trigger from
    navigateHome(). Before, returning users with an nsec but no
    local wallet were auto-derived behind the scenes and never saw
    the mode picker. Now they see it and opt in via "Use my default
    wallet" — matches iOS §2.2. Fresh signups still auto-derive via
    the existing onboarding path (OnboardingViewModel.generate-
    DefaultFromPrivkey), so account-create is unchanged.
  • Remove the auto-fire of autoCheckRelayBackup() from
    selectSparkMode(). Per §2.6 Screen 2 the sub-screen has no
    surprise UI — users explicitly tap "Restore from relays" to
    search.

Seed-entry moves to its own WalletPage.SparkRestoreSeed sub-screen
with a back arrow, replacing the inline OutlinedTextField that was
mixed into the old SparkSetupContent.

Strings updated to match the §2.6 copy reference verbatim. Orphan
strings (wallet_connect_wallet, wallet_choose_how, etc.) removed.
2026-05-17 22:50:22 -04:00