Commit Graph
13997 Commits
Author SHA1 Message Date
nrobi144andClaude Opus 4.6 5bf4db4582 fix(desktop): wire zap types, relay hints, and add testing sheet
- Map Desktop ZapType (Public/Private/Anonymous) through to
  LnZapEvent.ZapType and pass to ZapAction.fetchZapInvoice
- Add relayHint + authorRelayHint params to NoteActionsRow;
  FeedScreen now passes Note.relayHintUrl() for reactions/reposts
- Replace metadata preload TODO with design rationale comment
- Add 70-test manual testing sheet for wallet & zapping features

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 09:31:39 +03:00
nrobi144andClaude Opus 4.6 a15ce33807 refactor(desktop): use dialogs for wallet actions, center home content
Send, Receive, and Connect are now AlertDialogs instead of full-screen
sub-pages. The wallet home content is centered with widthIn(max=360.dp)
for a polished desktop look. Dialogs are the native desktop pattern
(consistent with zap dialog, bookmark dialog, tor settings dialog).

- ConnectWalletDialog: NWC URI input with paste + validation
- SendDialog: BOLT11 invoice input with paste + progress
- ReceiveDialog: amount/description input, transitions to show
  generated invoice with copy button
- Home content: centered balance card + action buttons + connection info

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 09:31:39 +03:00
nrobi144andClaude Opus 4.6 420a10df50 fix(desktop): subscribe before publish in NWC RPC to avoid race condition
getBalance and makeInvoice were publishing the request event before
subscribing for the response. Fast wallet responses (like get_balance)
would arrive before the subscription was active, causing timeouts.

Fix: subscribe first via onSubscribed callback in waitForGenericResponse,
then publish. The original payInvoice wasn't affected because Lightning
routing takes long enough for the subscription to be ready.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 09:31:38 +03:00
nrobi144andClaude Opus 4.6 ed06bb2267 test(desktop): add wallet and zapping test coverage
- ZapDialogLogicTest: 12 tests for formatSats, DEFAULT_ZAP_AMOUNTS,
  ZapType enum (labels, descriptions, entries)
- NwcPaymentHandlerTest: 18 tests for PaymentResult, BalanceResult,
  InvoiceResult sealed types, NWC connection validation, response
  event structure
- NwcRpcIntegrationTest: 5 full round-trip tests using real crypto
  (pay_invoice, get_balance, make_invoice request/response cycles,
  NWC URI -> client pipeline)
- Make formatSats and DEFAULT_ZAP_AMOUNTS internal for test access

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 09:31:38 +03:00
nrobi144andClaude Opus 4.6 7bd5fb3122 feat(desktop): wire NWC wallet operations and AccountManager integration
- Wire AccountManager.setNwcConnection() and clearNwcConnection() into
  wallet column for persistent connect/disconnect
- Implement NwcPaymentHandler.getBalance() via NIP-47 get_balance RPC
- Implement NwcPaymentHandler.makeInvoice() via NIP-47 make_invoice RPC
- Add generic waitForGenericResponse() helper for NWC RPC operations
- Auto-fetch balance on wallet column load via LaunchedEffect
- Wire receive screen to generate real invoices via NWC
- All wallet column features now functional (no blocking TODOs)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 09:31:38 +03:00
nrobi144andClaude Opus 4.6 8313f0cf12 feat(desktop): add wallet column and enhanced zapping UX
Phase 1: Wallet deck column with NWC integration
- Add DeckColumnType.Wallet with full deck system integration
  (AppDrawer, ColumnHeader, DeckState persistence, MenuBar)
- WalletColumnScreen with 4 sub-screens: Home (balance + actions),
  Connect (NWC URI paste), Send (pay BOLT11), Receive (create invoice)
- Uses existing NwcPaymentHandler for payment execution

Phase 2: Zapping UX improvements
- Upgrade ZapAmountDialog with zap type selection
  (PUBLIC/PRIVATE/ANONYMOUS via FilterChips)
- Add custom amount input alongside preset chips
- One-click zap: left-click sends default amount via NWC,
  right-click opens custom zap dialog
- Configurable zap amounts parameter (no longer hardcoded)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 09:31:38 +03:00
Vitor PamplonaandGitHub 6cd4de51aa Merge pull request #3028 from vitorpamplona/claude/fix-send-split-mode-AE6gg
fix: keep Send button visible in onchain zap split mode
2026-05-20 20:37:47 -04:00
Claude 465f3687c1 fix: keep Send button visible in onchain zap split mode
The OnchainZapSendDialog promised a sticky bottom Send button, but the
inner scrollable Column had no weight and the outer Column did not fill
the sheet height. In split mode, SplitsRecipientSection grew the content
past the sheet viewport and pushed the Send button off-screen.
2026-05-21 00:02:38 +00:00
Vitor PamplonaandGitHub 6efee9f1f2 Merge pull request #3027 from vitorpamplona/claude/add-mention-notifications-PIhPf
feat(notifications): include public chat mentions in feed
2026-05-20 19:51:18 -04:00
Claude 39eedeeb17 feat(notifications): include public chat mentions in feed
Add ChannelMessageEvent.KIND (NIP-28 kind 42) to the Notifications feed's
allow-list so channel messages that p-tag the user surface in the in-app
Notifications screen, alongside text-note mentions and DMs.

The relay subscription already requests kind 42 with #p (see
FilterNotificationsToPubkey.NotificationsPerKeyKinds), and push notifications
already route ChannelMessageEvent through notifyMention. Only the in-app
feed filter was rejecting them at the kind check; the existing
tagsAnEventByUser gate handles the per-kind "is this for me" rule via the
BaseNoteEvent branch (reply-to-me, cited-author, citation-in-content).
2026-05-20 23:21:47 +00:00
Vitor Pamplona e0abc4a224 v1.11.0 v1.11.0 2026-05-20 18:59:05 -04:00
Vitor PamplonaandGitHub ee67ba6408 Merge pull request #3025 from vitorpamplona/claude/plan-onchain-zap-events-t1cPq
feat: tighten the zap UI
2026-05-20 18:28:50 -04:00
Vitor Pamplona 7415b1db39 Merge branch 'main' of https://github.com/vitorpamplona/amethyst 2026-05-20 18:27:15 -04:00
Vitor PamplonaandGitHub f19a47007e Merge pull request #3024 from vitorpamplona/claude/fix-illegal-argument-exception-H4omh
fix(ui): restore outlined visual on EditPostView + ForwardZapTo TextF…
2026-05-20 18:26:45 -04:00
Claude 55e536dfd0 feat: tighten the zap UI
ReactionsRow zap popup
- Merge the Lightning and on-chain chips into a single FlowRow so all
  amounts wrap together instead of stacking on two lines.
- Drop the on-chain row's own Tune (settings) button; the Lightning
  row's Tune is the single entry point to the settings screen.

UpdateZapAmountDialog
- Reorder sections: Quick Zap Amounts, Zap Privacy, Quick On-chain Zap
  Amounts, Nostr Wallet Connect — privacy now sits next to the
  Lightning amounts it actually applies to, and on-chain (which has no
  privacy concept) is grouped further down.

OnchainZapSendDialog
- Move the preset amount chips above the sats text field in
  AmountSection so the user sees the quick picks first and the
  free-form input second.

Defaults
- DefaultOnchainZapAmounts is now [10_000] (just one chip) so a fresh
  install / first-upgrade shows 4 chips total in the popup (3
  Lightning defaults + 1 on-chain default), not 6. kotlinx
  serialization defaults handle the back-compat for existing users
  who never set their on-chain choices explicitly.
2026-05-20 22:26:34 +00:00
Claude 05d958d182 fix(ui): restore outlined visual on EditPostView + ForwardZapTo TextFields
Migrating the mention TextFields to BasicTextField(state) routed them
through ThinPaddingTextField, which uses TextFieldDefaults.DecorationBox
(filled, surfaceVariant container). That replaced the original
OutlinedTextField look — visible rounded border + transparent inside —
with a filled gray rectangle. On ForwardZapTo the change was especially
visible since the original outlined border was the only visual cue that
the search row was an input.

Add OutlinedThinPaddingTextField, a sibling of ThinPaddingTextField that
wraps the same TextFieldState pipeline with
OutlinedTextFieldDefaults.DecorationBox + Container. Same thin padding,
same onTextChanged/inputTransformation/outputTransformation surface, but
genuinely outlined (notched label, transparent inside).

  - ForwardZapTo: switch to the new component, drop the
    focused/unfocusedIndicatorColor=Transparent overrides — defaults give
    the proper outlined border the original OutlinedTextField had.
  - EditPostView.MessageField: switch to the new component and use
    OutlinedTextFieldDefaults.colors(focusedBorderColor=Transparent,
    unfocusedBorderColor=Transparent) to keep the inner border invisible
    so the existing 1dp Modifier.border(surface, RoundedCornerShape(8.dp))
    remains the only visible frame, matching the original.
2026-05-20 22:21:20 +00:00
David KasparandGitHub a4310317a0 Merge pull request #3017 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-21 00:04:24 +02:00
Crowdin Bot 40eb0f0b61 New Crowdin translations by GitHub Action 2026-05-20 22:02:32 +00:00
davotoula b04cf3aedc i18n: convert calendar_reminder_settings_lead_choice to <plurals>
The lead-time chip label "%1$d min" pairs a count with a noun, which
inflects in Slavic / Baltic languages. Switch it from <string> to
<plurals> in the default locale and in the three locales that already
have a translation (pl-rPL, zh-rCN, hu-rHU), and update the single
caller in CalendarReminderSettingsScreen to use pluralStringResource.

The abbreviation "min" / "min." / "perc" / "分钟" doesn't decline with
the count in any of these specific languages, but the resource shape
is now correct for future locales that do (e.g. Russian, Ukrainian).
2026-05-20 23:59:28 +02:00
Vitor Pamplona 924101c3f4 Fixes follow list rendering in the top note 2026-05-20 17:56:54 -04:00
Vitor PamplonaandGitHub 0cc435aa02 Merge pull request #3023 from vitorpamplona/claude/add-notecompose-contactlist-sFMff
Add Contact List display and navigation screen
2026-05-20 17:49:40 -04:00
Vitor PamplonaandGitHub 4fba293d60 Merge pull request #3020 from davotoula/feat/calendar-plurals-i18n
i18n: convert calendar count + reminder strings to <plurals>
2026-05-20 17:40:21 -04:00
Claude a1cb5cb50d feat: add preview for DisplayContactList
Mocks a kind-3 ContactListEvent with nine p-tags and renders
DisplayContactList in a ThemeComparisonColumn so the card can be
inspected in the IDE preview pane.
2026-05-20 21:40:02 +00:00
Vitor PamplonaandGitHub 15474cfff4 Merge pull request #3022 from vitorpamplona/claude/fix-illegal-argument-exception-H4omh
Migrate text input to new Compose TextFieldState API
2026-05-20 17:39:06 -04:00
Vitor PamplonaandGitHub 8bf1040f18 Merge pull request #3021 from vitorpamplona/claude/add-public-chip-confirmation-2Q7sh
Add warning dialog for copying public onchain addresses
2026-05-20 17:38:45 -04:00
davotoulaandClaude Opus 4.7 63e6283354 docs(claude): add res/CLAUDE.md note on <plurals> for Slavic locales
Captures the rule we just hit twice in a row (hashtag-limit + calendar
count): any count-bearing string must be <plurals>, every locale must
include the CLDR categories it actually uses, and don't hardcode "1" in
quantity="one" items. Loads automatically whenever a file under res/ is
edited.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:32:24 +02:00
Claude d7a1b631b2 feat: confirm onchain copy with public-address warning
The Taproot address is derived from the Nostr pubkey, so copying it out
is the moment a user is about to share an account-linked, publicly
auditable wallet. Gate the Copy button on the Onchain card with the same
explanation shown by the Public chip, and offer a "Don't show again"
opt-out persisted in the existing UI preferences DataStore.
2026-05-20 21:26:02 +00:00
davotoulaandClaude Opus 4.7 c7226d3293 i18n: convert calendar count + reminder strings to <plurals>
The NIP-52 calendar feature shipped two count-bearing strings as <string>
resources ("%1$d events" and "Starts in %1$d minutes"), which forces the
wrong noun form in Slavic languages where the declension depends on the
threshold integer. Convert both to <plurals> in the default locale and in
zh-rCN/pl-rPL/hu-rHU (the locales that already have translations), and
update the 4 callsites — 3 Composables use pluralStringResource and the
CalendarReminderWorker uses the pluralStringRes helper.

pl-rPL and hu-rHU keep only the "other" quantity, preserving existing text
without regression; proper CLDR fan-out (one/few/many for Polish, one for
Hungarian) will come from Crowdin or a native translator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:25:14 +02:00
Claude 6ecedb72f5 feat: render ContactListEvent in NoteCompose with tap-through user list
Adds a NoteCompose render for kind-3 ContactListEvent showing a label with
follow count and a row of the first 6 user avatars (with a "+N" overflow
chip). Tapping the row opens a new ContactListUsersScreen that lists every
followed user with the same UserCompose row used on the search screen.
2026-05-20 21:18:14 +00:00
Vitor PamplonaandGitHub 995ec3dab2 Merge pull request #3018 from vitorpamplona/claude/plan-onchain-zap-events-t1cPq
Add on-chain split zap support with per-recipient distribution
2026-05-20 16:54:26 -04:00
Vitor PamplonaandGitHub b7e3ba27ac Merge pull request #3019 from vitorpamplona/claude/debug-metadata-relay-loading-opoto
Add fallback relay logic for abandoned users in metadata queries
2026-05-20 16:52:26 -04:00
Claude f6db678249 fix: audit follow-ups (fee retry, perf, self-pay gate)
From an independent audit + my own pass, addressing concrete issues:

OnchainZapSendDialog
- Fee estimate fetch now retries with bounded backoff (4 tries, 1/2/3s
  spacing) instead of giving up after one attempt. Covers two real
  boot races: LocalCache.onchainBackend not yet wired at first
  composition, and a flaky feeEstimates() call. Without retry the
  Send button stayed permanently disabled.
- SplitsRecipientSection now indexes preview shares by pubkey once
  via remember(previewShares) { associateBy { ... } } instead of an
  O(N²) firstOrNull lookup per split row.
- belowDustShares is now wrapped in remember(previewShares) so it
  doesn't re-filter the list on every recomposition.
- canSend now also requires resolvedRecipient != senderPubKey in
  single-recipient mode, so the user can't tap Send when the only
  fallback recipient is themselves (would fail at the builder's
  "cannot zap yourself" check).
- formatWeight no longer prints "50.0%" for whole-percent shares —
  trailing ".0" is stripped (was a Double->String artifact).

OnchainZapSplitter
- Added distributeUnchecked(): same allocation as distribute() but
  never throws on dust; returns every share so the UI preview can
  render the full shape in one pass. distribute() (used by the
  build/send path) still throws via DustRecipientException so the
  real send keeps its dust gate.
- Added check(remainder < splits.size) before the remainder loop to
  pin the invariant that bounds remainder.toInt() and the k % size
  defensive mod.
- Test for distributeUnchecked.

ReactionsRow / ReusableZapButton / ZapCustomDialog
- baseNote.toEventHint<Event>() is now wrapped in remember(baseNote)
  in all three dialog launchers so it's not allocated on every
  parent recomposition.
2026-05-20 20:49:33 +00:00
Claude b2959dcb75 refactor: migrate UrlUserTagTransformation to UrlUserTagOutputTransformation
The legacy VisualTransformation paired with TextField(value, onValueChange)
goes through Compose Foundation's LegacyCursorAnchorInfoBuilder, which
throws "endOffset must be greater than startOffset" when the IME has
requested CURSOR_UPDATE_MONITOR and the field's visible bounds momentarily
collapse to zero width. The OutputTransformation API paired with
BasicTextField(state: TextFieldState) routes through a different,
non-legacy cursor anchor info controller and does not hit that bug.

Migrate the two remaining VisualTransformation call sites
(EditPostView.MessageField and ForwardZapTo) to the OutputTransformation
+ TextFieldState path. This requires:

  - IZapField: forwardZapToEditting becomes TextFieldState; the
    TextFieldValue-shaped updateZapForwardTo() callback is replaced by
    onForwardZapTextChanged() which reads the current state.
  - 8 ViewModels (ChannelNewMessage, ChatNewMessage, NestNewMessage,
    NewProduct, LongFormPost, NewPublicMessage, ShortNotePost,
    CommentPost): clear via clearText() instead of reassigning a new
    TextFieldValue; rewrite onForwardZapTextChanged() to read from
    forwardZapToEditting directly.
  - ForwardZapTo: switch from OutlinedTextField to ThinPaddingTextField
    with MentionPreservingInputTransformation +
    UrlUserTagOutputTransformation.
  - EditPostViewModel: message becomes TextFieldState; updateMessage()
    becomes onMessageChanged() (the state updates itself); the in-place
    replaceCurrentWord/insertUrlAtCursor TextFieldState overloads
    replace the value-based ones.
  - EditPostView: MessageField now uses ThinPaddingTextField with the
    OutputTransformation. Also drops a stale commented-out subject row
    that still referenced the legacy transformation.
  - Delete UrlUserTagTransformation and its androidTest (no callers
    remain).
  - Remove MainThreadCrashGuard and its hook in Amethyst.onCreate: the
    legacy cursor-anchor-info crash surface is gone with the remaining
    mention TextFields, so the framework workaround is no longer
    earning its keep.
2026-05-20 20:46:09 +00:00
Claude e6b6269314 feat: include indexer and proxy relays in trusted relay union 2026-05-20 20:41:33 +00:00
Vitor Pamplona 9d0397080f Adds Payment target to the usual user download 2026-05-20 16:39:05 -04:00
Claude 85dfe93ea7 feat: on-chain handoff from the custom-zap dialog
Adds a "Send on-chain instead" link button at the bottom of
ZapCustomDialog. Tapping it opens OnchainZapSendDialog with the entered
amount and message prefilled, the note as zappedEvent, and the same
split-detection / dust-preview / fee-tier picker that the Reactions
zap chip uses.

This also fixes the participant zap path in nests audio rooms
(ParticipantHostActionsSheet long-press → "Zap") since that menu item
opens ZapCustomDialog under the hood — fixing the custom dialog covers
both entry points transitively.

OnchainZapSendDialog gains a `prefillComment: String = ""` parameter so
the message field carries over from the LN dialog.

Poll-note zaps (FilteredZapAmountChoicePopup) intentionally stay
Lightning-only — the poll_option vote is encoded in the kind:9734 zap
request and counted via kind:9735 receipts; kind:8333 on-chain
receipts have no poll_option analog and the count infrastructure
doesn't index them. This is a protocol design constraint, not a UI
oversight.

Coverage audit summary — every user-facing zap initiation point now
has on-chain support except the poll-voting path:
- ZapReaction (reactions row) 
- ZapAmountChoicePopup (popup chips) 
- ZapCustomDialog (custom amount + message)  (this commit)
- ReusableZapButton (Zap the Devs + DVM buttons) 
- NestActionBar (audio room) 
- ParticipantHostActionsSheet (audio room participant)  (transitive)
- ChatMessageCompose / live-activity headers (use ZapReaction) 
- FilteredZapAmountChoicePopup (poll votes) ⚠️ LN-only by protocol
2026-05-20 20:35:01 +00:00
Claude a90dd47ed4 feat: on-chain option on the Zap the Devs button
ReusableZapButton now passes the user's on-chain zap amount choices to
ZapAmountChoicePopup and renders OnchainZapSendDialog when a chip is
tapped. The dialog receives the release note as the zappedEvent, so
the existing split detection picks up the kind:1 release notes' zap
splits and pays the dev team via one Bitcoin tx with N receipts.

The donation card is the canonical multi-recipient on-chain zap flow —
release notes are tagged with weighted splits across the team, the
sender's own pubkey gets filtered out, and the per-recipient share
preview shows live as the amount is typed.

Other callers of ReusableZapButton (DVM zap buttons, etc.) get the
on-chain row automatically since it's driven by the user's settings;
empty on-chain amounts list hides the row, matching prior behavior.
2026-05-20 20:20:21 +00:00
Claude dfd06e0dfd fix: skip offline relays when fetching user metadata 2026-05-20 20:18:56 +00:00
Claude 45aa6044b7 fix: on-chain zap splits — drop sender from splits, merge duplicates, gate Send on dust
Audit findings from an independent code review:

- HIGH: When the user zaps their own post (a common flow), every split
  that included the post author put the sender on the recipient list,
  and OnchainZapBuilder.buildSplit refused the whole tx with "cannot
  zap yourself". Fix: new OnchainZapSplitter.prepare() filters the
  sender's pubkey out of the splits before they reach the builder.
- HIGH: NIP-57 lets the same pubkey appear in zap-split tags more than
  once (additive weights). buildSplit rejected duplicate recipients.
  Same prepare() helper merges duplicates by summing weights, in
  first-seen order.
- HIGH: The dialog's live preview only showed amounts for recipients
  whose share was BELOW dust (because DustRecipientException only
  carries belowDust). Fix: parent composable computes shares with a
  zero dust threshold for the preview, gating the Send button on a
  separate belowDustShares check so the user can see all amounts and
  can't tap Send into a guaranteed BUILDING-stage failure.
- MEDIUM: OnchainZapSendResult.Failure didn't carry the ids of
  receipts that successfully published before a partial-publish
  failure. Added publishedReceiptEventIds: List<HexKey>.
- LOW: useSplits state was keyed by zappedEvent reference; re-emitted
  bundles would silently reset the toggle. Now keyed on the event id.

Tests added:
- splitter: prepare() drops sender, merges duplicates, filters
  non-positive weights; floating-point weights (0.1 + 0.2) sum exactly
- builder: buildSplit produces N recipient outputs + 1 change at index
  N, conserves sats, rejects duplicates and below-dust shares
- sender: sendSplit publishes one receipt per recipient sharing the
  txid with correct per-recipient amount; partial-publish failure
  carries the broadcast txid and the ids of receipts that did publish
2026-05-20 20:14:44 +00:00
Claude 13a599e282 fix: keep listening on default index+search relays for users with no kind 10002
When pickRelaysToLoadUsers exhausts every candidate tier (outbox / hints /
index / search / connected / common) for a user without finding kind 10002,
it returns an empty map and the REQ closes. A late-published relay list
from that user would never reach the UI for the rest of the session
(unless EOSEAccountFast's LRU evicts the entry).

Compute the set of users we couldn't place this pass and add a permanent
fallback filter on DefaultIndexerRelayList + DefaultSearchRelayList. The
filter is deterministic (sorted authors, set-based relays) so the relay
client de-duplicates it across passes, keeping the REQ open without
re-sending — any future kind 0 / kind 10002 publication will be pushed
to us live.

Offline relays are subtracted via failureTracker.cannotConnectRelays.
2026-05-20 19:57:38 +00:00
Claude 3ed2245d8c feat: on-chain zap splits
Extends NIP-BC onchain zaps to honor a note's NIP-57 zap-split tags: one
Bitcoin transaction pays every pubkey-based recipient atomically, and
one kind:8333 receipt is published per recipient (each receipt carries
the recipient's pubkey + sat share and shares the same i:<txid>).

quartz / OnchainZapBuilder
- new buildSplit(recipients = listOf(pubkey to sats), ...) produces a
  PSBT with one output per recipient + optional change output
- existing build(...) now delegates to buildSplit; coin selection and
  change-vs-dust logic are unchanged for the single-recipient path

commons / new OnchainZapSplitter
- distribute(totalSats, splits, dustThreshold) does the weighted
  integer-math allocation, dropping the rounding remainder onto the
  largest-weight recipient first so the per-recipient sats sum exactly
  to totalSats
- throws DustRecipientException if any share lands below dust; the
  caller surfaces that as a build-stage failure before the tx is built
- unit tests cover equal weights, fractional weights, remainder
  distribution, dust rejection, and input-order preservation

commons / OnchainZapSender.sendSplit
- mirrors send() but takes the precomputed shares, builds via
  buildSplit, and publishes N receipts using the same txid; if one
  receipt publish fails the broadcast txid + already-published receipt
  ids are surfaced in the Failure result

amethyst / Account.sendOnchainZapWithSplits
- thin wrapper that hands off to OnchainZapSender.sendSplit using the
  signer's pubkey

amethyst / OnchainZapSendDialog
- detects pubkey-based zap splits on the zappedEvent and, when present,
  defaults to split mode: a SplitsRecipientSection renders one row per
  recipient with weight % and live per-recipient sats preview
- lnAddress-only splits are filtered out (no pubkey -> no Taproot
  address); a short note tells the user how many recipients were
  skipped
- the send button label switches to "Send X sats, N ways"; an opt-out
  button lets the user fall back to single-recipient mode
- on send: shares are recomputed via OnchainZapSplitter; below-dust
  configurations surface as a BUILDING-stage failure before signing
2026-05-20 19:55:15 +00:00
Vitor PamplonaandGitHub c19f0be57e Merge pull request #3013 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-20 15:53:53 -04:00
Vitor PamplonaandGitHub 96883dbec1 Merge pull request #3015 from quentintaranpino/add-nostrcheck-media-server
Re-add Nostrcheck.me Blossom server to defaults
2026-05-20 15:53:42 -04:00
Claude b0b0a13650 fix: swallow LegacyCursorAnchorInfo IllegalArgumentException
Compose Foundation's LegacyCursorAnchorInfoBuilder.addCharacterBounds
computes a TextRange(startOffset, endOffset) over the visible portion of
a TextField when the IME has requested CURSOR_UPDATE_MONITOR. During a
layout transition (sheet animation, keyboard insets settling, etc.) the
visible region can momentarily collapse so startOffset == endOffset, and
MultiParagraph.fillBoundingBoxes throws "endOffset must be greater than
startOffset". This is a framework bug we can't fix from app code, and
it crashes the whole process from an onGloballyPositioned callback
during dispatchDraw.

Install a main-thread crash guard at app startup that wraps Looper.loop()
and swallows only this very specific signature (IllegalArgumentException
with the exact message AND a stack frame in LegacyCursorAnchorInfo* /
MultiParagraph* / AndroidParagraph / TextLayout). Anything else
re-throws into the default uncaught handler so UnexpectedCrashSaver
still records real bugs. The IME just misses a cursor update on the
swallowed frame — no user-visible impact.
2026-05-20 19:36:33 +00:00
quentintaranpino 0f92abd633 Re-add Nostrcheck.me Blossom server to defaults
The Blossom entry for nostrcheck.me was dropped in bcd2bc06
("Removes nip96 and updates Blossom recommendations", v1.06.0,
Feb 2026) along with the NIP-96 cleanup. This re-adds only the
Blossom endpoint.
2026-05-20 21:35:14 +02:00
Claude 360dea9de9 feat: surface on-chain zaps from the reactions zap button
Adds a second row of bitcoin-orange chips to the zap amount popup that
opens the existing OnchainZapSendDialog prefilled with the chosen amount
and the note's author + zappedEvent. The on-chain stack (kind 8333,
OnchainZapSender, Account.sendOnchainZap, OnchainZapSendDialog) already
existed end-to-end; only the entry point from the reactions row and the
on-chain preset amounts were missing.

Settings:
- AccountZapPreferencesInternal: new onchainZapAmountChoices (defaults
  10k/50k/250k sats); back-compat via kotlinx.serialization defaults
- AccountSyncedSettings / AccountSettings / Account.updateZapAmounts:
  wired through end-to-end alongside the existing Lightning list
- UpdateZapAmountDialog: new "Quick On-chain Zap Amounts" section with
  its own chip list and add-amount field; the existing zap-privacy
  dropdown stays Lightning-only since on-chain has no zap type

Reactions UI:
- ZapAmountChoicePopup now collects both choice lists and offers an
  on-chain row in addition to the Lightning one
- New on-chain callback opens OnchainZapSendDialog with the prefilled
  amount; the existing dialog gains a prefillAmountSats parameter and
  now reads the on-chain preset list for its own quick-pick chips
- Other zap entry points (ReusableZapButton, NestActionBar,
  FilteredZapAmountChoicePopup) are unchanged: on-chain row defaults
  off so they keep their existing Lightning-only behavior
2026-05-20 19:24:10 +00:00
Crowdin Bot 030c982a01 New Crowdin translations by GitHub Action 2026-05-20 19:11:26 +00:00
Vitor PamplonaandGitHub 5962f7d659 Merge pull request #3014 from vitorpamplona/claude/add-icon-tool-instruction-oZv6P
docs: add Material Symbols font subset regeneration guide
2026-05-20 15:09:22 -04:00
Claude 9b6d65c9f1 docs: require running material-symbols-subset.sh when adding new icons
The bundled Material Symbols font ships only the codepoints referenced
from MaterialSymbols.kt. Without regenerating the subset, newly added
icons render as tofu at runtime. Document this as a mandatory step in
CLAUDE.md so agents pick it up automatically.
2026-05-20 19:00:38 +00:00
Vitor Pamplona 872bb4f245 Add new information icon 2026-05-20 14:44:59 -04:00