Commit Graph
1259 Commits
Author SHA1 Message Date
Barry DeenandGitHub ddbebad120 Merge pull request #58 from barrydeen/fix/blurhash-zero-dim-crash
Fix crash on zero/negative blurhash dimensions
2026-07-23 11:00:58 -04:00
Barry DeenandClaude Sonnet 5 fc7eda8f01 fix: guard blurhash/thumbhash decode against zero/negative dimensions
Parsed width/height from the "dim" tag could be zero or negative,
crashing the decoder. Clamp to positive values and bail out early
in both decoders as a defense-in-depth backstop.

Bump version to 1.2.1 (versionCode 4).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 10:55:11 -04:00
Barry DeenandGitHub 16fd1f1538 Merge pull request #55 from dmnyc/feat/collapsible-threads
feat: collapsible reply threads + iOS-parity UI polish
2026-07-23 10:54:14 -04:00
Barry DeenandGitHub 80456103e6 Merge pull request #56 from dmnyc/feat/app-icon
feat(branding): dark-wisp launcher icon + welcome-screen branding
2026-07-23 10:53:40 -04:00
The Daniel 029abd6b99 feat(splash): dark-circle brand logo, glowing wordmark, visible cancel pill
Welcome-screen branding pass to match the new launcher icon:
- Logo: swap ic_wisp_logo + the drawn radial-gradient disc for the
  dark-wisp round mark on a solid black circle, delivered via a raster
  drawable (ic_brand_logo). The mipmap can't be used directly because
  R.mipmap.ic_launcher_round resolves to the adaptive-icon XML on
  API 26+, which Compose's painterResource cannot render.
- Wordmark: restyle "dark wisp" from flat white to black text ringed in
  an orange glow (brand orange #FF9800).
- Cancel (add-account flow): move out from under the logo/buttons
  column, where it was painted over, to a visible pill in the top-start
  corner (mirroring the Tor button at top-end).
2026-07-20 18:53:55 -04:00
The Daniel 153ba333b3 feat(icon): replace launcher icon set with dark-wisp artwork
Swap the inherited wisp launcher icons for the dark-wisp set: new
foreground artwork across all five density buckets (mdpi→xxxhdpi),
shipped as PNG. The adaptive-icon background moves from a vector
drawable to a flat black color resource (res/values/
ic_launcher_background.xml), matching dark-wisp's dark identity.
Removes the now-unreferenced ic_launcher_background drawable.
2026-07-20 18:05:01 -04:00
The Daniel 2a8f0cb028 feat: collapsible reply threads + iOS-parity UI polish
Ports wisp #622 (collapsible threads) and #624 (iOS-parity timestamps,
NIP-05 badge, follow badge) to dark-wisp.

Collapsible threads:
- Typed ThreadItem model + pure, unit-tested ThreadFlattener replace the
  flat Pair<NostrEvent, Int> list, shared by note threads and article
  comments.
- Replies deeper than 3 levels fold behind a "Show N more replies"
  affordance that expands inline, holding the viewport on the note above.
- Shared threadIndentDp/threadConnector draw a single L-shaped depth-guide
  rail; orphaned rails dash their top.
- Sticky "Reply…" bar targets the note at the top of the viewport.
- Reply order purely oldest-first; iOS-style "Replying to X" above the
  commenter row, de-linked and secondary-colored; NIP-05 badge hidden on
  reply rows.

iOS-parity polish:
- Timestamps: compact "1d".."6d" instead of "yesterday".
- NIP-05 badge: scalloped Verified seal, icon-only next to the username
  everywhere (handle text reserved for the profile screen); added to
  quoted-note previews too.
- Follow badge: orange circle with a mode-adaptive checkmark (black in
  dark mode, white in light mode).
2026-07-20 14:42:09 -04:00
Barry DeenandGitHub 19769f3fdf Merge pull request #53 from dmnyc/nsec-paste-guard
fix(security): extend nsec paste guard to every remaining text input
2026-07-20 10:00:13 -04:00
Barry DeenandGitHub e223a752ed Merge pull request #54 from barrydeen/chore/bump-v1.2.0
chore: bump version to 1.2.0
2026-07-20 09:58:56 -04:00
Barry Deen 63483685e3 chore: bump version to 1.2.0 (versionCode 3) 2026-07-20 09:58:37 -04:00
The Daniel 0e9324cc42 fix(security): extend nsec paste guard to every remaining text input
NsecPasteGuard existed but was only wired into MainActivity and a
handful of ProfileEditScreen/WalletScreen fields — most of the app's
text inputs (drawer status, list names, relay URLs, DM/group/compose
message boxes, safety mute words, search fields, custom emoji fields,
and the rest of the wallet screen) would silently accept a pasted nsec
instead of blocking it. Wire the guard into every remaining input,
matching wisp's existing full-coverage implementation, and cover
dark-wisp's local-relay tab (which wisp no longer has) too.
2026-07-17 23:39:04 -04:00
Barry DeenandGitHub 3cb6f3bc09 Merge pull request #49 from dmnyc/feat/wallet-improvements
feat(wallet): Receive redesign, tx history sheet, on-chain tx display
2026-07-15 12:52:16 -04:00
Barry DeenandGitHub f6f0b25e19 Merge pull request #52 from dmnyc/feat/account-switcher-sheet
feat(drawer): account switcher as a modal sheet + reordering
2026-07-15 12:51:55 -04:00
The Daniel 70720e415b fix(accounts): sync account registry for any known account's kind 0
Previously the drawer's account registry (used by the account switcher
to show a name/avatar) was only updated once, during the active
account's startup sequence, via a one-shot snapshot check. A newly
imported key whose kind 0 hadn't arrived by that exact moment would
show a bare npub in the switcher forever, even after its profile
loaded moments later elsewhere in the app.

Now any fresh kind 0 for any account in the registry — not just the
active one — updates it immediately, from all three places a profile
event can land: live relay subscription, direct event cache, and
ObjectBox local seed.
2026-07-11 22:12:25 -04:00
The Daniel c01a67dcc3 feat(drawer): account switcher as a modal sheet + reordering
Replace the inline expand/collapse account picker with a proper bottom
sheet (AccountSwitcherSheet), matching the sheet conventions already
used elsewhere in the app (e.g. ProfileQrSheet). The drawer header's
account affordance is now a single icon-only People glyph with a "+N"
badge for other signed-in accounts, instead of a count-dependent
icon-vs-chip toggle.

Accounts can now be reordered from the sheet via up/down buttons,
persisted through a new KeyRepository.moveAccount. The Anon Mode
toggle, which previously only rendered inside the account picker's
expanded state, now always renders in the drawer body since it's
unrelated to account switching.
2026-07-11 15:05:44 -04:00
Barry DeenandGitHub b3cbaa9cc2 Merge pull request #27 from dmnyc/feat/ui-polish
feat(ui): profile/QR sheet iOS alignment, zap spam collapse, bolt glow pulse
2026-07-04 15:53:32 -04:00
Barry DeenandGitHub c77b956767 Merge pull request #41 from dmnyc/search-segmented-tabs
feat(search): segmented People | Notes pill tabs (port wisp 4934338)
2026-07-04 15:52:32 -04:00
Barry DeenandGitHub 3c3c06ba6b Merge pull request #48 from Letdown2491/feat/render-custom-nip-30817
feat: render kind 30817 (custom NIPs / NUDs) like articles
2026-07-04 15:52:15 -04:00
Barry DeenandGitHub 67deda6ddf Merge pull request #50 from dmnyc/fix/unicode-hashtags
fix(content): parse hashtags with non-ASCII Unicode letters
2026-07-04 15:51:40 -04:00
Barry DeenandGitHub f18538ff5c Merge pull request #51 from dmnyc/feat/instant-zap-in-sheet
feat(zap): move instant-zap settings into the zap sheet
2026-07-04 15:51:18 -04:00
The Daniel bd7a862833 feat(zap): move instant-zap settings from Interface settings into the zap sheet
Instant-zap configuration was buried in Settings → Interface. Move it into
the zap sheet where it's used, matching the Zap Cooking layout:

- ZapDialog section 7: when enabled, the toggle now shows the configured
  amount + message and a "configure in Presets" hint; the bolt tints accent
  when on.
- EditPresetsSheet: adds an "Instant zaps" toggle plus a per-row radio to
  designate which preset is the instant amount. Done persists enabled state
  and the selected preset's amount/message. Deleting the selected row moves
  the selection safely.
- InterfaceScreen: remove the instant-zap enable/amount/message block. Fiat
  mode's app-wide units toggle is untouched; the "Zaps" header is retained
  for the remaining Zap Icon toggle.

Default stays off. Long-press instant zap continues to fire the configured
amount unchanged.
2026-07-01 19:34:11 -04:00
The Daniel 358013836c fix(content): parse hashtags with non-ASCII Unicode letters
Hashtags containing accented or non-Latin letters (ä, ü, ö, é, ñ, etc.)
were truncated at the first non-ASCII character because the hashtag
character class was ASCII-only ([a-zA-Z0-9_-]). Switch to Unicode letter
(\p{L}) and combining-mark (\p{M}) property classes so the full tag is
parsed and highlighted as one token, and so composed notes tag it
correctly.
2026-07-01 18:32:22 -04:00
The Daniel d12895c8e6 fix(wallet): correctly settle on-chain payments made from another Spark wallet on the same seed
On-chain deposits sit unclaimed until explicitly claimed once they have
enough confirmations; the SDK emits SdkEvent.UnclaimedDeposits when a
deposit becomes claimable, and we weren't calling claimDeposit at all.
Now claims automatically on that event and once more on connect (in
case a deposit became claimable while the app was closed).

Also stops trusting PaymentStatus.PENDING for on-chain rows in general:
transactions made through another wallet app on the same seed aren't
tracked by this SDK session, so the status can stay stuck at PENDING
long after the underlying transaction is confirmed on-chain. The
mempool.space link already lets users verify actual confirmation
status for on-chain transactions.
2026-06-30 22:13:36 -04:00
The Daniel f877d7eb47 feat(wallet): inline lightning address QR toggle in Receive sheet
Tapping the QR icon on the Receive sheet's lightning address row now
expands an inline QR card in place instead of navigating to a separate
page, and auto-scrolls it into view. Also stops the invoice-creation
spinner from appearing just because the shared isLoading flag happened
to be true when the sheet opened — it now only shows after the Create
invoice button is pressed.
2026-06-30 22:11:49 -04:00
The Daniel 8ebe0be8d4 feat(wallet): present Send/Receive as full-page bottom sheets
Match the Transactions sheet treatment so Send and Receive overlay the
Home dashboard instead of replacing it, and keep the swipe-down-to-
dismiss gesture consistent across all three flows. Also pushes each
sheet's grab handle below the status bar so it doesn't get clipped by
the clock/camera cutout when the sheet expands to full height.
2026-06-30 19:13:18 -04:00
The Daniel ca7414704d refactor(wallet): remove on-chain send/receive, keep on-chain tx display
We are not supporting on-chain send/receive in-app. Detection and
display of on-chain transactions in history remains so deposits/
withdrawals made from another app on the same Spark seed still show
correctly (type, txId, mempool.space link).
2026-06-30 19:01:15 -04:00
Letdown2491 c720666216 feat: render kind 30817 (custom NIPs / NUDs) like articles
Community-authored NIPs (NUDs, kind 30817) are structurally NIP-23 long-form
articles, so render them through the existing article machinery: inline naddr
embed card, full reader, and comments keyed by the kind:pubkey:d coordinate.

- nostr/CustomNip.kt: KIND constant + k-tag (defined-kinds) parsing
- Navigation: route 30817 naddr into the article reader; pass kind to comments
- ArticleViewModel: kind-parameterized comment/engagement coordinate
  (was hardcoded 30023); expose defined-kinds for the reader chips
- ArticleScreen: defined-kind chips; NIP label/fallback for 30817
- RichContent: embed dispatch + ArticleCard kind-aware (fetch/lookup/click,
  NIP kicker instead of ARTICLE)
2026-06-30 16:26:25 -06:00
The Daniel 9b6e3501e9 fix(wallet): correctly detect on-chain Spark transactions in history
Use PaymentDetails.Deposit/Withdraw to set isOnchain and surface the
real txId instead of the internal payment UUID. Set pending from
PaymentStatus.PENDING so the detail drawer shows accurate Status,
Type, and Transaction ID / mempool.space link for on-chain rows.
2026-06-30 18:26:25 -04:00
The Daniel 974698bfec fix(wallet): remove duplicate lightning address divider/caption on Receive 2026-06-30 18:26:25 -04:00
The Daniel 476f65a3a7 feat(wallet): expandable transaction detail drawer in history
Tapping any row in the transaction history sheet expands an animated
detail panel showing Status, Type, Amount, Network fee, Date, Note,
and Payment hash with a one-tap copy icon. On-chain transactions get
a mempool.space deep-link. Pending transactions surface a "Pending"
badge before the timestamp.

Adds pending and isOnchain fields to WalletTransaction (both default
false; wire-up per backend can follow).
2026-06-30 18:26:25 -04:00
The Daniel 9d2640e832 feat(wallet): iOS-style send input, lightning address QR, on-chain Send icon
Send screen:
- Replace OutlinedTextField with tall BasicTextField in a dark card
  (min 120dp, top-aligned placeholder, nsec guard on all paste paths)
- Scan QR · Paste · Gallery action row beneath the field (iOS parity)
- Accent-colored Next button with proper disabled state
- Spark hint now includes CLINK offer alongside Bitcoin address

Receive screen:
- Lightning address row: compact bolt icon + address + QR + copy icon
  replacing the two-button Copy/Share card; QR icon navigates to the
  existing LightningAddressQR page

On-chain send:
- Replace ArrowUpward direction indicator and button icons with the
  AutoMirrored Send (paper airplane) icon on both Amount and Confirm
  screens; remove redundant inline back buttons (TopAppBar handles back)
2026-06-30 18:26:25 -04:00
The Daniel fe967dc4d3 feat(wallet): on-chain receive/send, Receive redesign, tx history sheet
On-chain receive (Spark):
- Two-tab Receive screen: Lightning | Bitcoin (Spark only)
- Bitcoin tab fetches and displays a deposit address with QR and copy/share
- WalletProvider interface extended with getDepositAddress()

On-chain send (Spark):
- Bitcoin address detection in processInput() (bc1…, 1…, 3… prefixes)
- Amount screen with inline fee quote (amount → Get Fee Quote → breakdown
  card with Amount / Network Fee / Total → Continue)
- "Use All" shortcut fills balance
- Confirm screen: large amount hero, chunked alternating-color address
  block, irreversibility warning, side-by-side Back/Confirm buttons
- Result screen: Check/Close icon, mempool.space link on success
- WalletProvider extended with prepareOnchainSend() and sendOnchain()
- NWC stubs return UnsupportedOperationException; calls gated on SPARK mode

Receive screen redesign:
- Invoice expiry selector: 1 hour / 24 hours / Custom (expands hours field)
- Lightning address shown below invoice form as "or receive via" row
- expirySecs threaded through generateInvoice → makeInvoice interface

Transaction history as swipe-up bottom sheet:
- ModalBottomSheet overlays the home dashboard (home stays visible behind)
- Swipe up 40px on the RECENT footer triggers the sheet
- Swipe down from drag handle dismisses; back button eliminated
- hideAppBar updated to include WalletPage.Transactions

NIP-47: makeInvoice gains optional expiry field (NwcRepository + Nip47.kt)
SparkRepository: transactionsChanged SharedFlow emits on payment events
2026-06-30 18:26:25 -04:00
Barry DeenandGitHub 819963e00e Merge pull request #45 from dmnyc/feat/multi-account-switcher
feat(accounts): multi-account switcher + cancel add-account flow
2026-06-30 17:38:41 -04:00
Barry DeenandGitHub 76bb997ed1 Merge pull request #43 from dmnyc/feat/remote-signer-keys-screen
feat(keys): show signer card for REMOTE accounts, fix missing npub
2026-06-30 17:37:32 -04:00
Barry DeenandGitHub bd71a211a1 Merge pull request #44 from dmnyc/fix/linebreaks-before-mentions
fix(richcontent): preserve blank lines before inline profile/hashtag segments
2026-06-30 17:36:56 -04:00
The Daniel bd8d7e4579 feat(accounts): add/switch account affordances + cancel add-account flow
- Drawer header: show + circle (solo) or + N pill+chevron (multi) next to avatar for immediate account switcher access; remove redundant chevron beside username
- SplashScreen: accept onCancel param and render frosted Cancel pill when adding an account over an existing session
- Navigation: save previousAccountPubkey before navigating to splash, restore it fully on cancel (account switch + vm reload)
- AuthViewModel: add previousAccountPubkey field to support cancel-and-restore
2026-06-27 17:44:58 -04:00
The Daniel 0e348ad95f fix(richcontent): preserve blank lines before inline profile/hashtag segments
The trimBlankLines pass was stripping \n\n before NostrProfileSegment and
HashtagSegment, treating them as block-level elements. They are inline —
they share a Text() composable with surrounding text and get no extra Column
spacing — so blank lines before them must be preserved.

Notes whose paragraphs start with a nostr: mention lost all paragraph
spacing on Android as a result.
2026-06-27 00:06:31 -04:00
The Daniel da5e8b989d fix(keys): show npub for REMOTE and READ_ONLY accounts
Derive npub from getPubkeyHex() first so accounts without a keypair
(REMOTE/READ_ONLY) still display their public key.
2026-06-26 22:50:42 -04:00
The Daniel 3f166bbfb1 feat(keys): show signer card for REMOTE accounts instead of reveal button
REMOTE signing mode (NIP-55/Amber) has no private key on device.
Replace the reveal button with an OutlinedCard explaining that signing
is handled externally. READ_ONLY accounts get a plain text note.
LOCAL accounts are unaffected.
2026-06-26 22:49:04 -04:00
Barry DeenandGitHub 8083521e04 Merge pull request #38 from dmnyc/fix/compose-uploading-pill
fix(compose): move uploading indicator to its own line as a capsule pill
2026-06-26 14:11:35 -04:00
Barry DeenandGitHub 2ae8a3a1af Merge pull request #39 from dmnyc/user-profile-bio-update
feat(profile): clean up payment targets, CLINK offer & zap interface
2026-06-26 14:11:16 -04:00
Barry DeenandGitHub a91df75554 Merge pull request #42 from Letdown2491/feat/strip-link-trackers
feat: strip tracking params from links in note content
2026-06-26 14:10:59 -04:00
Letdown2491 70704cda75 feat: strip tracking params from links in note content
Removes share/analytics tracking params from URLs as they're rendered:
- utm_* and well-known click-ids (fbclid, gclid, msclkid, igshid, etc.)
  on every host
- YouTube share params (si/feature/pp) scoped to YouTube hosts, covering
  video, playlist, and channel links

Meaningful params (v, list, t, q, fragments) are preserved, and the URL
is returned untouched when nothing is stripped.
2026-06-25 22:05:42 -06:00
Barry DeenandGitHub ae03b930dc Merge pull request #37 from Letdown2491/perf/hotpath-and-startup
Perf/hotpath and startup
2026-06-18 12:35:54 -04:00
The Daniel 78ed63a1ab feat(search): segmented People | Notes pill tabs (port wisp 4934338)
Replaces the search filter dropdown (ArrowDropDown button + menu) with a
two-tab segmented pill control (People | Notes, each with an icon) to match
iOS. The search field moves below the tabs into its own row with a leading
search icon and the Tune advanced-filter toggle alongside it.
2026-06-17 14:14:05 -04:00
The Daniel 474f956a5f feat(profile): clean up payment targets, CLINK offer & zap interface
Consolidates the profile's payment surfaces so each method appears once and
the layout is consistent.

- Action row: uniform 40dp circle buttons (send, zap, follow, mute); the zap
  button routes straight to the zap composer
- Bio: long bios clip to ~5 lines with Read more / Show less; a CLINK noffer
  in the bio renders as a compact " CLINK offer" label instead of the full
  Pay-offer card (new plainNoffer flag on RichContent, scoped to the bio)
- Payment methods list: shared row layout with a fixed-width leading icon
  column for alignment and 10dp tap padding for separation; raw addresses
  (long Monero / noffer strings) dropped from the rows — the copyable value
  lives in the sheet that opens on tap
- Lightning address is now tappable: zaps when a wallet is connected,
  otherwise opens a QR + copy pay sheet (reuses PaymentTargetSheet)
- CLINK offer gets one explicit "Pay CLINK Offer" row (styled like the other
  payment rows) instead of being duplicated across a button chooser, an
  inline bio card, and a NIP-A3 target row
2026-06-17 14:07:46 -04:00
The Daniel a4a096fd38 Merge remote-tracking branch 'upstream/main' into feat/ui-polish
# Conflicts:
#	app/src/main/kotlin/com/darkwisp/app/ui/component/ProfileQrSheet.kt
#	app/src/main/kotlin/com/darkwisp/app/ui/component/ReactionDetailsSection.kt
2026-06-17 12:27:14 -04:00
The Daniel ba13d53279 fix(compose): move uploading indicator to its own line as a capsule pill
The "Uploading…" label was crammed into the compose toolbar's icon row
alongside six icon buttons, leaving no horizontal space — so the text
wrapped to three lines ("Uplo / ading / …"). Pull the spinner + label out
of the icon row into a dedicated line below it, wrapped in a rounded
surfaceVariant capsule with maxLines = 1 so it can never wrap. Animates
in/out with the upload lifecycle.
2026-06-17 12:19:21 -04:00
Letdown2491 4d3e62af86 perf: defer exchange-rate init off the main thread
ExchangeRateRepository.init does disk I/O (loadCached) plus kicks off a network
refresh; move it off the main thread in WispApp.onCreate so it no longer gates
first frame. Rates populate asynchronously regardless and consumers already
handle the empty initial map. Startup-path win; matters more under GrapheneOS
exec-based spawning.
2026-06-16 09:47:33 -06:00
Letdown2491 5c0002b76b perf: verify worker pool + single-pass event decode + thread hygiene
- RelayPool: replace per-event coroutine-per-signature-verify with a small
  fixed worker pool fed by a bounded Channel. Reuses the RelayEvent already
  built for _relayEvents so there's no extra per-event allocation; falls back
  to an inline launch if the buffer is momentarily full so verification is
  never skipped. Cuts thousands of coroutine+closure allocations/sec on the
  hottest path (extra costly under GrapheneOS hardened_malloc).
- Event/RelayMessage: decode object-form events via fromJsonObject instead of
  the generated serializer, removing one walk over the parsed tree per message.
- WispApp: baseline-profile-check executor is now a daemon and shut down after
  its one-shot run instead of lingering for the app lifetime.
2026-06-16 08:55:20 -06:00