Commit Graph
14953 Commits
Author SHA1 Message Date
Claude bb43fd97b8 feat: open app screenshots fullscreen via ZoomableContentView
ScreenshotsStrip now renders each screenshot through ZoomableContentView,
so tapping one opens the standard fullscreen zoomable viewer with paging
across all of the app's screenshots. Tiles keep a fixed height and take
their width from the image's cached aspect ratio (portrait fallback
before first load).

https://claude.ai/code/session_01RJSke6d4dpSZgdtXAmGMmp
2026-06-12 19:31:31 +00:00
Claude 8c7430038d fix: letter-avatar fallback for app icons while loading or on failure
AppIcon used to render an empty bordered box when the icon url was
missing, still downloading, or failed to load. It now draws the app
name's first letter on a surfaceVariant background underneath the
image, so all three states show a meaningful placeholder.

https://claude.ai/code/session_01RJSke6d4dpSZgdtXAmGMmp
2026-06-12 18:19:20 +00:00
Claude 7072da5286 feat: show screenshots in app feed cards, drop platform chips
Feed cards now render the app's screenshots in a horizontal LazyRow at
200dp so the images are big enough to convey what the app is about.
The platform/license chips were removed from the card since they add
little at feed level (still shown on the detail screen).

https://claude.ai/code/session_01RJSke6d4dpSZgdtXAmGMmp
2026-06-12 18:07:24 +00:00
Claude 7743d2a82a feat: show 'by <author>' under the app name in feed cards and detail header
Replaces the standalone author row on the detail screen with a shared
AppAuthorLine ('by' + clickable profile picture + username) rendered
right under the app name, and adds the same line to the app feed cards.

https://claude.ai/code/session_01RJSke6d4dpSZgdtXAmGMmp
2026-06-12 18:05:44 +00:00
Claude b9a1d198c2 feat: show app author on the app detail screen
Adds a clickable author row (profile picture + username) below the
app header, matching the owner row pattern used by community and
long-form screens.

https://claude.ai/code/session_01RJSke6d4dpSZgdtXAmGMmp
2026-06-12 17:26:27 +00:00
Claude 41055c7769 fix: align app detail screen with thread UI conventions
- Add 12dp horizontal padding to all app detail sections (header,
  screenshots, about, platforms, topics, links, releases) so content
  no longer touches the screen edges like other screens
- Render comments with the reply-level indentation bars used by the
  regular thread feed (drawReplyLevel + levelFlowForItem)
- Move the reactions row below the releases, matching the master-note
  layout of thread screens, and follow it with a divider
- Drop the Comments section label since the reactions row + threaded
  replies already follow the standard screen pattern

https://claude.ai/code/session_01RJSke6d4dpSZgdtXAmGMmp
2026-06-12 15:36:35 +00:00
Vitor PamplonaandGitHub 1927ce1ef0 Merge pull request #3191 from vitorpamplona/claude/elegant-allen-9mt4he
Unify payment card UI with PaymentCard component
2026-06-12 10:59:49 -04:00
David KasparandGitHub f161cfce77 Merge pull request #3190 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-06-12 16:56:31 +02:00
Crowdin Bot 061da30553 New Crowdin translations by GitHub Action 2026-06-12 13:33:32 +00:00
Vitor PamplonaandGitHub b37e62cd62 Merge pull request #3186 from nrobi144/feat/unhealthy-relay-review
feat(desktop): unhealthy-relay review banner + popup
2026-06-12 09:31:34 -04:00
Vitor PamplonaandGitHub da8dca29d7 Merge pull request #3188 from davotoula/feat/onchain-failure-translations
Localize onchain zap send UI and failure messages
2026-06-12 09:20:18 -04:00
davotoula a593ec35f4 Code review:
- Account.kt: collapse three identical backend-not-configured Failure
  constructions into one helper
- OnchainZapSendError: declare causeIsUserFacing on the enum so the
  sender owns which failures carry a human-readable cause, instead of
  the UI mapper hardcoding the list
- SendPaymentScreen: fee chip label is now a single format resource
  instead of manual string concatenation
2026-06-12 14:05:12 +02:00
davotoula 97f9cca43e feat(l10n): localize onchain zap send dialog and failure messages 2026-06-12 14:04:55 +02:00
davotoula 7265a9da36 refactor: extract duplicated string literals into constants (sonar) 2026-06-12 14:04:47 +02:00
David KasparandGitHub 078ceac846 Merge pull request #3187 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-06-12 10:22:48 +02:00
Crowdin Bot bbd039cd74 New Crowdin translations by GitHub Action 2026-06-12 08:21:53 +00:00
davotoulaandClaude Fable 5 5bfe20b673 feat: add cs, de, sv, pt-BR translations for CLINK, Send Payment, workouts, and pin strings
Source-identical values (Cashu, Lightning, On-chain, and per-locale
loanwords like Meditation/Yoga/Workouts in de) are intentionally left
to the English fallback since Crowdin strips them on export anyway.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 10:16:11 +02:00
nrobi144 a46a72a89f feat(desktop): unhealthy-relay review banner + popup
Surfaces relays unresponsive for 7+ days across the user's NIP-65 (10002),
DM (10050), and Search (10007) relay lists. A non-modal banner appears
above feed columns (and above the single-pane content) whenever the
classifier finds anything; tapping it opens an anchored Popup with one
row per unhealthy relay and per-row Remove / Open Dashboard / Snooze 7d
actions plus a banner-level "Snooze all 7d".

Quartz
- RelayStat gains best-effort lastConnectAt + lastIncomingAt timestamps
  (epoch seconds, 0 = never observed). RelayStats listener pushes them
  on onConnected / onIncomingMessage. Durable per-relay history lives
  outside quartz in the commons RelayHealthStore.

Commons (new commons/relays/health/ package)
- classifyRelayHealth() pure function with the v1 gates:
  * first-run grace (don't flag for 7d after firstScanAt)
  * offline grace (don't flag if no relay anywhere has responded)
  * Tor-mode skip (relay timing is intentionally lossy through Tor)
  * per-relay snooze (snoozedUntil > now)
  * 10006 (blocked) excluded from detection but still part of the
    multi-list Remove action
- RelayHealthStore (account-scoped, supervised scope, 5s debounced
  persist, 60s ticker for snooze expiry).
- RelayHealthListener wires the quartz lifecycle into the store.
- RelayHealthPersistence interface (no expect/actual — single impl per
  platform via injection).
- RelayListMutator interface + RelayRemovalResult sealed type.
- Shared UnhealthyRelayBanner (errorContainer @ 50% alpha) and
  UnhealthyRelayRow (static outlined tag chips, no ripple) composables.
- 8 classifier unit tests covering each gate + multi-list membership.

Desktop wiring
- PreferencesRelayHealthPersistence (java.util.prefs.Preferences, per
  account via 8-char pubkey prefix).
- DesktopRelayListMutator runs the 4 sign-and-broadcast jobs in
  parallel via async/awaitAll so a slow NIP-46 bunker doesn't multiply
  latency by 4.
- Banner placed in DeckColumnContainer + SinglePaneLayout, store +
  listener + per-account scan trigger wired in Main.kt's MainContent.

Scope: Desktop only for v1. Android wiring is intentionally not in
this PR — the commons module is platform-neutral and ready for Android
to follow whenever someone wants to pick it up.
2026-06-12 06:40:46 +03:00
Claude 275c53ad7b feat: modernize inline payment cards and surface their descriptions
Redesign the three payment cards rendered in the middle of a post
(Lightning invoice, CLINK Offer, Cashu token) around a shared PaymentCard
scaffold that follows the wallet screens' Material3 idiom: tonal card,
icon + label header with a copy action, centered headline amount, and a
full-width themed Pay/Redeem button (no more hardcoded white text or
7sp mint lines).

Descriptions were not being rendered at all:
- BOLT-11: LnInvoiceUtil only decoded the amount from the HRP. Add
  tagged-field parsing (description 'd', expiry 'x', timestamp) with
  BOLT-11 spec-vector tests; the invoice card now shows the memo and
  flags expired invoices (Pay disabled). Desktop card shows it too.
- Cashu: V3 'memo'/'unit' and V4 'd'/'u' were parsed then dropped.
  CashuToken now carries them; the card shows the memo and no longer
  mislabels non-sat units (usd/eur cents formatted as decimals).
- CLINK Offers: the card now shows who gets paid (avatar + name from
  the pointer's pubkey, tappable to the profile).

https://claude.ai/code/session_019VuZ4y3ij6Ly4VVExE1W1W
2026-06-12 00:05:30 +00:00
Vitor PamplonaandGitHub d91988b26b Merge pull request #3185 from vitorpamplona/claude/focused-einstein-6jjqmj
Add unified profile payment screen with multi-rail support
2026-06-11 19:14:43 -04:00
Claude 98d8a73337 fix(profile): move the payment rail chips below the identity claims
The chip row now renders after the website link and external identities
(GitHub/Twitter/etc.) instead of between NIP-05 and the website.
2026-06-11 23:07:05 +00:00
Claude 86cd1315c2 fix(profile): equalize wrapped-row spacing across all Send Payment chip groups
Pay from, zap receipt, amount preset, and on-chain fee chips wrap with
the same 8dp row gap as the Receive-on pills. Material chips reserve a
48dp interactive height around their 32dp visual, inflating wrapped-row
gaps to ~24dp; the new shared ChipFlowRow drops that enforcement inside
the chip groups so the spacing matches.
2026-06-11 23:05:39 +00:00
Claude a311ffec22 fix(profile): wrap spacing on Send Payment chip rows + cashu mark on its chips
- All chip FlowRows on the Send Payment screen (Receive on, Pay from,
  zap types, amount presets, fee tiers) now declare an 8dp vertical
  arrangement so wrapped lines get the same gap as the in-row spacing —
  the custom Receive-on pills had no intrinsic padding and touched when
  the row broke.
- The cashu rail chip and the cashu 'Pay from' wallet chip use the Cashu
  vector mark (tinted with the chip content color) instead of the
  generic wallet symbol.
2026-06-11 22:34:39 +00:00
Vitor PamplonaandGitHub 1e23b14ff2 Merge pull request #3184 from vitorpamplona/claude/beautiful-turing-j0czsm
Add NIP-101e fitness workout support (Kind 1301)
2026-06-11 18:26:36 -04:00
Claude 5635f89f3a feat(profile): drop Receive-on detail line; long-press chips copy destinations
The detail text under the Send Payment rail selector (e.g. the lightning
address, already visible in the recipient header) is gone. Instead every
chip carries its destination via long-press copy:

- Send Payment 'Receive on' chips copy the lightning address, the
  noffer pointer, the on-chain destination (announced target address or
  the pubkey-derived Taproot address — otherwise invisible), and the
  shared cashu mint URL. The chips are now custom selectable pills since
  M3 FilterChip has no long-press support.
- Profile rail chips gain the same copy values (clink noffer, derived
  taproot address, mint URL) alongside the existing lightning and
  payment-target copies.
- The announced bitcoin address moved from the detail line into the
  on-chain receipt note so it stays visible when it differs from the
  derived address.
2026-06-11 22:15:07 +00:00
Claude dcb6c6a2ba fix(profile): render rail and payment-target chips in one FlowRow
The wallet-rail chips and the NIP-A3 payment-target chips were two
separately padded FlowRows, so the gap between the two rows was about
double the in-row spacing. The target chips now render inside the same
FlowRow as the rail chips, wrapping together with uniform 6dp spacing.
DisplayPaymentTargets is gone; PaymentTargetChip is rendered by
DisplayPaymentRailChips directly.
2026-06-11 22:09:42 +00:00
Claude 1883f1b032 refactor: full-screen NewWorkout route + audit fixes
- Replace the NewWorkoutDialog with a Route.NewWorkout full screen
  (NewGoalScreen pattern: NewWorkoutViewModel + PostingTopBar), which
  also fixes the audit-found race where the dialog closed before the
  signer finished — the screen now pops back only after a successful
  sign/broadcast, keeping external-signer (Amber) flows alive.
- Move template building from Account.sendWorkout into the ViewModel.
- Render workout cards in thread view (ThreadFeedView fall-through gap).
- Snapshot parsed workout tags once per note (remember + WorkoutInfo)
  instead of re-scanning the tag array on every recomposition.
- Fix Double.trimmed() Int overflow on absurd distances.
- Flatten the distance-unit chip layout.

https://claude.ai/code/session_01Kpx53UEeJqqR7CASzMu6GB
2026-06-11 22:09:12 +00:00
David KasparandGitHub 8b9176bc02 Merge pull request #3179 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-06-12 00:08:29 +02:00
Claude adb59eb276 fix(profile): tint the cashu chip icon and brighten its purple
The Cashu vector is a monochrome black outline meant to be tinted like a
Material Symbol — with Color.Unspecified it rendered black and vanished
on dark backgrounds. Tint it with the chip color and lift the purple
from 0xFF7E57C2 to 0xFFA855F7 so the chip reads on both themes.
2026-06-11 22:06:43 +00:00
Crowdin Bot 344797ce87 New Crowdin translations by GitHub Action 2026-06-11 22:01:40 +00:00
Claude e7b4f8edbb feat(profile): unified payment rail chips on the profile header
Replaces the lightning-address icon+text row with a chip and completes
the rail set, so every way to pay a profile reads as one chip row:

- Lightning chip shows the lud16 (long-press still copies it) and opens
  the Send Payment screen on the Lightning rail.
- CLINK Offer chip moves into the same row (same look as before).
- New On-chain chip (when the chain backend is configured) and Cashu
  chip (when the logged-in user's cashu wallet shares a mint the
  recipient accepts), each opening their rail on the Send Payment
  screen.
- All four render through a shared ProfilePaymentChip pill that matches
  the NIP-A3 payment-target chips, replacing the old DisplayLNAddress
  row and the one-off clink chip in DrawAdditionalInfo.

https://claude.ai/code/session_01UERRsbDoRPz46Qx5HCXgAa
2026-06-11 21:59:47 +00:00
Vitor PamplonaandGitHub ae17c2378b Merge pull request #3183 from vitorpamplona/claude/friendly-lovelace-aw7vfj
Add pinned chatrooms feature with NIP-78 sync
2026-06-11 17:59:24 -04:00
Claude afa341f2fc fix(profile): rename rail selector label from 'Pay with' to 'Receive on'
The rail chips describe how the recipient receives the funds, not which
wallet pays — that's the 'Pay from' row below.
2026-06-11 21:51:09 +00:00
Claude 4361f95a17 feat: NIP-101e workout records (kind 1301) + Workouts feed screen
Quartz: new experimental/fitness/workout package shaped like nip88Polls —
WorkoutRecordEvent with per-tag classes (exercise, duration, distance,
elevation, calories, steps, heart rate, splits, strength sets/reps/weight,
source, workout_start_time), TagArrayBuilder/TagArray extensions, lax
RUNSTR-dialect parsing (unit defaults, HH:MM:SS or raw seconds), and
EventFactory + LocalCache registration. Covered by fixture tests.

Amethyst: new Workouts feed (drawer entry, route, follow-list top bar,
per-relay filter assemblers mirroring the Pictures feed) with a + FAB
opening a manual workout composer that publishes canonical kind-1301
events. Workout cards render stats chips and also display inside threads
via NoteCompose. Adds fitness Material Symbols glyphs and regenerates the
subset font.

https://claude.ai/code/session_01Kpx53UEeJqqR7CASzMu6GB
2026-06-11 21:48:32 +00:00
Claude a3a938253f feat(chat): sync pinned DM rooms via the NIP-78 AppSpecificData event
Pinned chatrooms were stored local-only in encrypted SharedPreferences, so
they were lost on uninstall and never reached other devices. Move them into
AccountSyncedSettings as a new 'chats' group in the encrypted settings blob
(each room serialized as its member pubkeys sorted ascending), publishing a
new AppSpecificData event on every pin/unpin like the other synced settings.

Local persistence now comes from the existing latestAppSpecificData event
backup, so the dedicated pinned_chatrooms preference is removed (the local
format never shipped, so no migration is needed). Pins arriving from another
device flow through AccountSyncedSettings.updateFrom and re-sort the chat
list via the existing pinnedChatrooms feed invalidation collector.

https://claude.ai/code/session_0131YwG6bE3yH8Kk9MxjMA5i
2026-06-11 21:47:17 +00:00
Vitor PamplonaandGitHub 3044e430ab Merge pull request #3182 from vitorpamplona/claude/awesome-gauss-hd9xjn
Add kotlinx-serialization support for CLINK protocol DTOs
2026-06-11 17:47:16 -04:00
Claude 9999d92bca fix: register CLINK DTO serializers in KotlinSerializationMapper for native targets
All CLINK tests failed on iosSimulatorArm64 with IllegalArgumentException
because OptimizedJsonMapper on native dispatches through
KotlinSerializationMapper, whose fromJsonTo/toJson type lists did not
include the CLINK payload DTOs (Jackson handles them reflectively on
JVM/Android, which is why only iOS failed).

Adds hand-written kotlinx serializers for OfferRequest/OfferResponse/
OfferReceipt, DebitRequest/DebitResponse, and ManageRequest/ManageResponse,
mirroring Jackson behavior: ManageResponse.details coerces a lone object
into a one-element list (ACCEPT_SINGLE_VALUE_AS_ARRAY) and
OfferRequest.payer_data round-trips as a free-form JSON object.

Covered by a JVM test driving KotlinSerializationMapper directly and
cross-checking against Jackson, since the native path shares this code.

https://claude.ai/code/session_01SevV4fUCumKZ1UscSz85vS
2026-06-11 21:33:49 +00:00
Claude e62bef8610 perf(chat): defer pinned-room state reads to the row and menu slots
Reading pinnedChatrooms.value in the UserRoomCompose body invalidated the
whole function scope on every pin toggle. Keep the single subscription but
read the set only inside the firstRow slot (pin icon) and the dropdown
menu-item text, so those two small scopes are the only ones that recompose.

https://claude.ai/code/session_0131YwG6bE3yH8Kk9MxjMA5i
2026-06-11 21:22:25 +00:00
Claude 23605ef630 feat(profile): 'Pay from' wallet selector on the Send Payment screen
The screen now shows which wallet the payment will come from and lets
the user switch before paying:

- Lightning and CLINK-offer rails list every configured wallet (NWC +
  CLINK debit, via PaymentSourceResolver.all) plus an 'Another wallet
  app' entry that hands the invoice to the system via intent. The
  selection defaults to the account's default payment source and
  re-resolves if the picked wallet is removed while the screen is open.
- On-chain and cashu rails show a fixed, disabled chip naming their
  intrinsic wallet so the money's origin is always visible.
- payBolt11 now charges the picked source instead of silently using the
  account default.

https://claude.ai/code/session_01UERRsbDoRPz46Qx5HCXgAa
2026-06-11 21:18:11 +00:00
Claude 02e0d9a4be feat(profile): pay bitcoin payment targets through the in-app on-chain wallet
Lightning payment targets already route into the Send Payment screen;
this extends the same treatment to bitcoin targets. Tapping a profile's
bitcoin payment-target chip (or its pay action in the wallet-button
dialog) now opens the Send Payment screen with the on-chain rail locked
to that announced address, paid directly from the user's NIP-BC Taproot
wallet — falling back to the external bitcoin: URI when the chain
backend is missing or the address isn't a payable native-segwit mainnet
address.

- quartz: SegwitAddress.scriptPubKeyFor/isPayableMainnetAddress;
  OnchainZapBuilder.buildToScripts core shared by the pubkey paths.
- commons: OnchainZapSender.sendToAddress — plain wallet send with the
  same fund-safety signing contract but no kind:8333 receipt (the
  destination isn't pubkey-derived, so none is possible); the signing
  block is now a single shared helper across send/sendSplit/sendToAddress
  and Success.receiptEventId is nullable for receipt-less sends.
- amethyst: Account.sendOnchainToAddress; Route.SendPayment gains
  btcAddressOverride; a shared inAppPaymentRouteFor() decides which
  payment targets the user's wallets can pay in-app (used by both the
  target chips and the payment-targets dialog).
- Send Payment screen: with an address override the on-chain rail shows
  the target address, hides the message field (no receipt to carry it),
  explains that no zap receipt is published, and dispatches the plain
  address send.

https://claude.ai/code/session_01UERRsbDoRPz46Qx5HCXgAa
2026-06-11 21:01:07 +00:00
Vitor PamplonaandGitHub e8ed9379b8 Merge pull request #3181 from vitorpamplona/claude/focused-knuth-4zi90p
Fix ThumbnailDiskCache to recreate cache dir if cleared at runtime
2026-06-11 16:45:43 -04:00
Vitor PamplonaandGitHub 77a26ed131 Merge pull request #3180 from vitorpamplona/claude/dazzling-sagan-1c0ncz
Optimize string resource loading in WalletScreen
2026-06-11 16:40:07 -04:00
Claude 9ebee56dba fix: recreate thumbnail cache dir before writing temp file
The profile_thumbnails_v2 dir was only created in ThumbnailDiskCache's
constructor, but Android can delete cache subdirectories while the app
runs (system cache trim under storage pressure, or the user tapping
Clear cache in Settings). After that, every generateFromFile call
failed with ENOENT on the temp-file write until process restart,
silently disabling thumbnail caching.

Recreate the dir right before the write, and add instrumented
regression tests covering the cleared-at-runtime path.

https://claude.ai/code/session_01RQinCw5QKpaYXqtyb4gf3h
2026-06-11 20:16:37 +00:00
Claude 4563bf872d fix(profile): harden Send Payment screen after audit
Audit fixes for the unified payment screen:
- Re-peek cashu nutzap funding when the profile data refreshes so a
  late-arriving kind:10019 doesn't keep the Cashu rail hidden, and read
  the on-chain backend availability live instead of freezing it at first
  composition.
- Seed the active CLINK offer only while unset so a kind:0 refresh
  mid-flow can't discard an expired-or-moved redirect; drop the !!
  derefs in the offer range check.
- Marshal payment-callback stage updates to the Main scope (matching the
  app's progress-callback convention) and run the on-chain send off the
  Main thread since the sender signs the PSBT on the calling thread.
- Launch the external-wallet intent from the Main scope instead of the
  invoice fetcher's IO callback.
- Restore the old LN-address error affordance: payment failures now
  offer 'Message the recipient about this', opening a DM prefilled with
  the failure detail.
- Reuse the wallet sheet's FeeTier instead of a duplicated enum, memoize
  the zap-type options, and hoist the lightning target-type set.

https://claude.ai/code/session_01UERRsbDoRPz46Qx5HCXgAa
2026-06-11 20:15:05 +00:00
Claude 6775ad8e62 docs: add RUNSTR interop research plan (kind 1301 + related events)
Catalogs every Nostr kind the RUNSTR app publishes/consumes, the exact
1301 tag dialect, the Supabase-migration caveats, and a phased plan for
Quartz event classes and Amethyst fitness screens.

https://claude.ai/code/session_01Kpx53UEeJqqR7CASzMu6GB
2026-06-11 20:12:30 +00:00
Claude 38023dac45 fix: resolve iOS test-name compile error and LocalContext lint error
- Rename Nip05Test backticked test name to drop parentheses, which are
  illegal identifier characters on Kotlin/Native (iosSimulatorArm64).
- Resolve CLINK budget toast strings at composition time via stringRes
  instead of context.getString inside the async callback, fixing the
  LocalContextGetResourceValueCall lint errors in WalletScreen.

https://claude.ai/code/session_01UgP8ErzBbQYkTDtkJx5nrt
2026-06-11 20:10:20 +00:00
Vitor PamplonaandGitHub 6c8dea755d Merge pull request #3178 from vitorpamplona/claude/kind-lamport-dwtzh8
Marmot: seed subscription since from stored messages on restart
2026-06-11 16:08:39 -04:00
Claude 73a63cf43a fix: address audit findings on the MLS unread/restore changes
- Clamp the seeded kind:445 subscription since at wall-clock now: the
  inner createdAt is sender-controlled, so a single future-dated message
  could push since past the present and silently skip genuinely new
  events on every restart. Covered by a new regression test.

- Drop the remember() around the group-list unread count: the chatroom's
  message set can shrink without newestMessage or lastReadTime changing
  (pruning, kind:5 deletion of an older message), which left the cached
  count stale. The set is pruned to ~100 entries, so counting per
  recomposition is cheap.

- Extract marmotGroupLastReadRoute(): the "MarmotGroup/<id>" last-read
  key was inlined at three call sites; a prefix drift between the
  mark-as-read side and the unread checks would silently reintroduce
  the bug this branch fixes.

- Derive GROUP_EVENT_REFETCH_OVERLAP_SEC from TimeUtils.ONE_DAY instead
  of re-deriving 24*60*60.
2026-06-11 20:05:25 +00:00
Claude 7d7f2f275f refactor(quartz): dedicated NutzapEvent.buildToUser for profile nutzaps
Restores the non-null zappedEvent on NutzapEvent.build and adds a
separate buildToUser builder (p tag only, no e/k tags) for nutzaps that
target a profile instead of an event — mirroring NIP-57's profile zap
convention. CashuWalletOps.sendNutzap dispatches between the two.

https://claude.ai/code/session_01UERRsbDoRPz46Qx5HCXgAa
2026-06-11 19:48:56 +00:00
Claude f2702f9299 feat(profile): unified Send Payment screen for lightning, clink, on-chain and cashu zaps
Replaces the click-to-expand payment cards on the profile page with a
dedicated Send Payment screen that collects amount, optional message and
zap type, pays on the spot through the selected rail, and shows the
invoice-request + payment progress in the screen itself before closing.

- New Route.SendPayment(userHex, method, lnAddressOverride) with a
  stateless SendPaymentContent (previews for editing, fixed-price clink,
  in-progress, success and failure states).
- Rails offered per profile: Lightning (lud16/lud06 or a lightning
  payment target), CLINK offer (kind-0 / NIP-05, with expired-or-moved
  redirect), on-chain NIP-BC (fee tier selector), and NIP-61 cashu
  nutzaps gated on a shared funded mint.
- Lightning rail keeps the Public/Private/Anonymous zap types and adds
  the Non-Zap (plain payment) option; clink is a direct payment; cashu
  and on-chain receipts are inherent to their protocols and noted as such.
- Paying from this screen skips the extra in-app wallet confirmation
  dialog: the explicit amount + Pay tap is the confirmation.
- Profile LN-address row, CLINK chip, lightning payment-target chips and
  the wallet button's pay action now navigate to the new screen; other
  target types keep their external payto/URI behavior.
- NutzapEvent.build / CashuWalletState.sendNutzap now accept a null
  zapped event so nutzaps can target a profile (p-tag only), and
  AccountViewModel gains sendNutzapToUser + a zapType override on
  sendSats.

https://claude.ai/code/session_01UERRsbDoRPz46Qx5HCXgAa
2026-06-11 19:28:02 +00:00