Commit Graph

13754 Commits

Author SHA1 Message Date
nrobi144 935ad84ac3 fix(desktop): fix release build ProGuard rules that crash app on launch
ProGuard in release builds (packageReleaseDmg/Deb/Rpm) strips classes
accessed via reflection, JNI, or service loading — causing multiple
runtime failures:

- Jackson ExceptionInInitializerError: enum constants stripped, NPE in
  MapperConfig.collectFeatureDefaults() (#2929, 5000 sats bounty)
- JNA/VLCJ: static methods stripped, SIGABRT in native callbacks
- secp256k1/SQLite/kmp-tor: JNI loader classes stripped
- Coil/okhttp/okio: image loading and networking broken
- Kotlin metadata stripped: Jackson can't call default constructors

Changes:
- Upgrade ProGuard 7.7.0 → 7.9.1 (Kotlin 2.3 metadata support)
- Disable optimization (-dontoptimize) to prevent bytecode rewriting
  that produces VerifyError (Guardsquare/proguard#460)
- Add -keep rules for all JNI/reflection-dependent libraries
- Keep Kotlin @Metadata annotations for Jackson deserialization
- Suppress Kotlin 2.3 compile-time stub warnings

Tested: release DMG builds and launches without crash on macOS.

Closes #2929

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-18 16:52:27 +03:00
Vitor Pamplona 34f5dcac69 Merge pull request #2959 from greenart7c3/claude/fix-blossom-cache-url-8zolt
fix(blossom): only bridge to local cache when URL is BUD-01 layout
2026-05-18 08:49:22 -04:00
Vitor Pamplona 447c662dff Merge pull request #2954 from vitorpamplona/claude/fix-illegal-argument-exception-b572Q
Fix public chat deduplication by channel ID extraction
2026-05-17 22:12:58 -04:00
Claude cc83c24427 fix: dedupe public-channel rows in chatroom list updates
When the initial chatroom list picked a ChannelMetadataEvent or
ChannelCreateEvent as the representative note for a public channel
(because no ChannelMessageEvent had been seen yet), the arrival of a
later ChannelMessageEvent caused updateListWith to append a second
entry for the same channel — its match check only recognized old
notes whose event was a ChannelMessageEvent. Two notes for the same
channelId then produced the same PublicChannelLazyKey in the LazyColumn
and crashed with IllegalArgumentException: Key was already used.

Extract the channel id from any of the three public-chat event types
when matching the existing entry so the new message replaces the
placeholder instead of duplicating it.
2026-05-18 01:43:08 +00:00
Vitor Pamplona 51e136abdd Merge pull request #2953 from greenart7c3/claude/fix-payment-targets-loading-fx9jo
fix: subscribe and observe PaymentTargetsEvent for other users
2026-05-17 21:03:59 -04:00
Claude 27488f8f34 fix: subscribe and observe PaymentTargetsEvent for other users
PaymentButton and DisplayPaymentTargets read note?.event inside a
remember(note) keyed on the AddressableNote reference, which is stable
across event arrival. They also rely solely on LoadAddressableNote's
cache lookup with no relay subscription, so when viewing a profile
outside the path that activates UserProfileMetadataFilterSubAssembler
(or before the event arrives) the UI never updates.

Match the canonical pattern from ProfileBadgesScreen: pair
LoadAddressableNote with EventFinderFilterAssemblerSubscription to
request the event from relays, and observeNoteEvent<PaymentTargetsEvent>
to recompose when it arrives.
2026-05-17 22:20:48 +00:00
David Kaspar 358bd6a325 Merge pull request #2952 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-17 22:36:21 +02:00
Crowdin Bot 7b6293b945 New Crowdin translations by GitHub Action 2026-05-17 15:49:38 +00:00
David Kaspar 4044c9341c Merge pull request #2951 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-17 17:48:02 +02:00
Crowdin Bot 92a25e3a38 New Crowdin translations by GitHub Action 2026-05-17 12:34:52 +00:00
davotoula 53c6d5d14d i18n: translate call-permission and git-repo strings (cs, pt-BR, sv, de)
17 strings: 5 for the call-permission-denied dialog plus 12 for the new
git repository overview / issues / patches screen and status pills.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 14:26:26 +02:00
Vitor Pamplona 0cf8ecef13 Merge pull request #2949 from vitorpamplona/claude/add-zaps-to-stats-Z2qHO
feat(notifications): include onchain zaps in summary stats
2026-05-16 19:07:39 -04:00
Vitor Pamplona 57acfe200a Merge pull request #2948 from vitorpamplona/claude/change-hashtag-limit-Jujia
Raises the default maximum hashtag limit from 5 to 8
2026-05-16 19:06:22 -04:00
Vitor Pamplona 55802fa21b Merge pull request #2947 from vitorpamplona/claude/restore-lightning-url-field-LdXOc
feat(profile): restore Lightning Address + LNURL fields in Edit Profile
2026-05-16 19:05:53 -04:00
Claude 09c4d70048 fix(blossom): only bridge to local cache when URL is BUD-01 layout
`bridgeUrl` accepted the imeta `x` hash as a sufficient signal to route
a media URL through the local Blossom cache, even when the URL itself
didn't have the sha256 in its last path segment. For URLs like
https://i.nostr.build/M5AwJ.gif the upstream serves the blob under an
opaque filename, so the resulting `xs=https://i.nostr.build` hint sent
the local cache after https://i.nostr.build/<sha>.gif on miss — which
404s because the real blob isn't at that path.

Match the behaviour `bridgeProfilePictureUrl` already had: require
`extractSha256FromUrlPath(url)` to succeed before bridging. The imeta
hash is still preferred for canonical casing when present, but is no
longer enough on its own.
2026-05-16 22:45:06 +00:00
Claude 92b1930228 feat(notifications): include onchain zaps in summary stats
Add OnchainZapEvent handling to NotificationSummaryState so NIP-BC
onchain zaps targeting the current user contribute their claimed sats
to the daily zap total and chart alongside LnZapEvent receipts.
2026-05-16 22:28:30 +00:00
Claude 44234aa648 feat(profile): inline Lightning Address + LNURL fields in Edit Profile
Promote the two lightning fields out of an expandable section so they
sit alongside name/about/nip05/website as regular always-visible inputs.

https://claude.ai/code/session_01R2E6rMfhxKA8csVarjxKJd
2026-05-16 22:16:52 +00:00
Claude 7e750d2517 feat(profile): restore Lightning Address + LNURL fields in Edit Profile
Lightning fields had moved entirely into the NWC wallet setup screen
(NIP47SetupScreen), so a user with no NWC connection had no way to set
their lud16/lud06 — required for receiving zaps. Add an expandable
Lightning section in the profile editor that reads/writes lud16 and
lud06, auto-expanded when either is set. NIP47SetupScreen keeps its
lud16 field; both flows go through sendNewUserMetadata which already
no-ops null params, so editing only one side never wipes the other.

https://claude.ai/code/session_01R2E6rMfhxKA8csVarjxKJd
2026-05-16 22:00:30 +00:00
Claude 4a23ecf7ef Raises the default maximum hashtag limit from 5 to 8 2026-05-16 21:38:58 +00:00
Vitor Pamplona 280f21159f v1.10.0 2026-05-16 16:53:00 -04:00
Vitor Pamplona 463c61c61e Removes marmot debug lines 2026-05-16 16:31:27 -04:00
Vitor Pamplona b96f1b5847 Merge pull request #2944 from vitorpamplona/claude/nip88-polls-quartz-p5fBa
Add NIP-BC onchain Bitcoin zaps support (send, receive, display)
2026-05-16 16:27:31 -04:00
Claude 627b75681f feat(wallet): redesign onchain card to match NWC WalletCard
OnchainSection now mirrors WalletCard's layout structurally so both
payment rails read as the same kind of object on the wallet screen,
with bitcoin-orange (BitcoinDark #F7931A / BitcoinLight #B66605)
replacing NWC's primary purple to keep them distinct at a glance:

  - RoundedCornerShape(16.dp), 2.dp bitcoinColor border,
    bitcoinColor.copy(alpha = 0.12f) container — same idiom NWC uses
    for the 'default wallet' card.
  - Header row: small orange ₿ chip + 'Bitcoin' title + 'Onchain ·
    Taproot' subtitle on the left, big 24sp bold balance + 'sats'
    label on the right (same typography as NWC).
  - Loading shows an orange CircularProgressIndicator in the balance
    slot. Error / no-backend states render an em-dash placeholder
    with a small status caption.
  - Address block: 'Your Taproot address' caption + monospace
    truncated address.
  - Action row: outlined 'Copy' with copy icon on the left, filled
    bitcoin-orange 'Send' with send icon on the right — same 36dp
    height + RoundedCornerShape(8.dp) as the NWC card actions.
2026-05-16 20:21:25 +00:00
Claude e4b8e7ccc8 feat(onchain-zaps): redesign send sheet + render in thread NoteMaster
OnchainZapSendDialog moves from AlertDialog to ModalBottomSheet —
matches the design language already used by CreateNestSheet,
EditNestSheet and the participant-action sheets. The form gets
imePadding + navigationBarsPadding, a scrollable content area, and a
sticky full-width Send button at the bottom.

Layout changes:
  - Header with Bitcoin ₿ glyph + title + close.
  - Recipient picker: the suggestion dropdown now sits flush under
    its text field (was: separated by the outer Column's spacedBy gap).
  - Amount section: big number field with 'sats' suffix + FlowRow of
    SuggestionChips bound to AccountViewModel.zapAmountChoices (same
    quick picks the LN zap dialog uses, formatted with showAmount).
  - Fee priority: FlowRow of FilterChips with explicit vertical
    padding around the row and inside each chip; each chip shows
    'Slow / Normal / Fast', the sat/vB rate, and a rough ETA.
    Selected chip uses bitcoinColor.
  - State machine: idle → sending (orange spinner) → success
    (bitcoinColor checkmark) / failure (error tint), each with a
    'Done' / 'Close' bottom button.

Also wire RenderOnchainZap into ThreadFeedView.NoteMaster's event-type
dispatch right after RenderLnZap, so kind 8333 receipts get the full
rich render on the thread screen instead of the default text body.
2026-05-16 20:16:21 +00:00
Claude 5aedcd0a19 feat(onchain-zaps): user search + chip wrapping in send dialog
Recipient field now uses ShowUserSuggestionList + UserSuggestionState
(same plumbing as the post composer @-mention and AwardBadgeScreen).
The user can type a display name, NIP-05, or paste an npub/hex; picked
recipients render as a chip with avatar + name + clear button. Raw
npub paste still works as a fallback when no result is picked.

Fee tier chips moved from Row to FlowRow so 'Slow · 1 sat/vB',
'Normal · 12 sat/vB', 'Fast · 50 sat/vB' wrap to a second line on
narrow dialog widths instead of clipping the rightmost chip.
2026-05-16 20:05:09 +00:00
Vitor Pamplona 3f12bdc2d7 Merge pull request #2943 from vitorpamplona/claude/fix-show-more-gradient-WruXm
Fix gradient rendering with transparent background colors
2026-05-16 15:59:04 -04:00
Claude 1d5ce994a6 fix(onchain-zaps): UserProfileZapsViewModel crashed casting kind 8333 as LnZapEvent
observeEvents<LnZapEvent>(filterAcceptingBothKinds) is generic-erased
at runtime, so an OnchainZapEvent landing in the cache (e.g. right
after sending an onchain zap from the wallet) flowed through and
crashed in sumAmountsByUser's forEach checkcast.

Observe as <Event> and dispatch on type: LnZapEvent keeps its
private-zap decryption path; OnchainZapEvent attributes the
claimedAmountInSats to event.pubKey (no zap-request envelope).
2026-05-16 19:56:22 +00:00
Claude e6a5ba9e15 fix: use theme background when ShowMore gradient color is transparent
Several callers pass Color.Transparent as the rich-text backgroundColor.
getGradient was copying that color and forcing alpha=1, which produced
opaque black (Color(0,0,0,1)) as the gradient end — so on a light theme
the fade behind the "Show more" button looked pitch black.

Fall back to MaterialTheme.colorScheme.background when the supplied
background has alpha 0, so the gradient fades from transparent into the
actual surface color.
2026-05-16 19:46:39 +00:00
Claude 6361fb1c9d feat(onchain-zaps): rich NoteCompose render for kind 8333
Adds RenderOnchainZap, dispatched from RenderNoteRow alongside
RenderLnZap. The card shows a pulsing Bitcoin badge, sender→recipient
avatars, big sats amount in Bitcoin orange, an animated 'ON-CHAIN'
pill, a live confirmation pill (Verifying → In mempool → Confirmed at
block N) sourced from LocalCache.onchainBackend.getTx, and a
tap-to-copy mempool.space tx link.
2026-05-16 19:42:01 +00:00
Vitor Pamplona f1d02f3c60 Merge pull request #2942 from vitorpamplona/claude/fix-call-button-permission-63OLL
Handle denied call permissions with settings dialog
2026-05-16 15:18:18 -04:00
Claude 8a5d0019c1 Merge remote-tracking branch 'origin/main' into claude/nip88-polls-quartz-p5fBa 2026-05-16 19:15:32 +00:00
Vitor Pamplona 05467582b4 Merge pull request #2941 from vitorpamplona/claude/fix-notecompose-read-status-rslby
Sync inner note highlight fade with parent background color
2026-05-16 15:14:31 -04:00
Vitor Pamplona f901db699d Merge pull request #2940 from vitorpamplona/claude/fix-ci-build-desktop-2qHSV
Replace linuxdeploy with appimagetool for AppImage packaging
2026-05-16 15:08:44 -04:00
Claude 19309c4587 fix: also fade reply previews together with the parent NoteCompose
Restores ReplyNoteComposition's parentBackgroundColor parameter (reverting
part of the previous commit). With calculateBackgroundColor now returning
the parent State directly when routeForLastRead is null, every inner
NoteCompose call site (replies, reposts, reactions, reports, approvals,
attestations, multi-set / message-set notification cards, and rich-text
nostr:event/nostr:note quotes) shares the level-0 bgColor State and fades
in lockstep with the outer note.
2026-05-16 19:07:26 +00:00
Claude 7ed93bcbc2 fix(desktop): package AppImage with appimagetool, not linuxdeploy
linuxdeploy auto-walks every binary in the staged AppDir with ldd to
bundle their shared-library deps. That fights jpackage's self-contained
output on two axes and aborts the createReleaseAppImage task before any
AppImage is produced:

  - The bundled JRE puts libjvm.so at usr/lib/runtime/lib/server/, while
    its sibling libs (libmanagement.so, libawt_xawt.so, libfontmanager.so
    and others in usr/lib/runtime/lib/) have RPATH=$ORIGIN. ldd cannot
    resolve libjvm.so from those libs without help, so linuxdeploy errors:
        ERROR: Could not find dependency: libjvm.so
        ERROR: Failed to deploy dependencies for existing files

  - The bundled libvlc plugins under usr/lib/app/resources/vlc/ are
    UPX-compressed by the vlc-setup plugin. patchelf cannot read their
    section headers, so linuxdeploy aborts:
        ERROR: Call to patchelf failed:
        patchelf: no section headers. The input file is probably a
        statically linked, self-decompressing binary

  - Even after working around libjvm.so via LD_LIBRARY_PATH, several VLC
    libs have RUNPATH pointing at the wrong directory, so ldd fails on
    libva.so.2 / libvlccore.so.9 next.

This is why v1.09.2 shipped .deb + .rpm from the linux leg but no
.AppImage and no linux .tar.gz from the linux-portable leg — the gradle
step failed on linuxdeploy, so the subsequent "Build portable archives"
step never ran.

Swap to appimagetool, which only embeds the AppDir as-is into a
SquashFS-backed, runtime-prepended AppImage and never touches the
contents. jpackage already bundles a complete, self-contained app —
we don't need linuxdeploy's dep-discovery. AppRun continues to handle
LD_LIBRARY_PATH at launch.

Verified locally on ubuntu-24.04: a fresh
:desktopApp:createReleaseAppImage now produces a valid 254 MB
Amethyst-1.09.2-x86_64.AppImage in ~30 s on top of an up-to-date
createReleaseDistributable.

Side changes:
- Workflow installs desktop-file-utils (appimagetool 1.9.0 calls
  desktop-file-validate on the .desktop entry).
- BUILDING.md updated with the new local-dev fetch command.
- .gitignore replaces the linuxdeploy paths with appimagetool's.
2026-05-16 19:04:07 +00:00
Claude e885192f51 fix: surface call-permission denial instead of silent failure
When the user denied RECORD_AUDIO or CAMERA for a DM call, rememberCallWithPermission's
launcher callback only re-checked permissions and called onCall() on success — the denial
branch was empty. On the next button press Android skips the system dialog (permanently
denied) and immediately returns deny, so the call button appeared dead with no UI feedback.

Now the denial path opens an AlertDialog with an "Open settings" deep-link, matching the
NestActionBar pattern. Also splits the optional BLUETOOTH_CONNECT request onto its own
launcher so its result callback no longer triggers a second onCall().
2026-05-16 18:49:26 +00:00
Claude 523b0616cf fix: quoted NoteCompose stuck on the "new item" purple background
calculateBackgroundColor captured parentBackgroundColor?.value once inside
remember(createdAt), so an inner NoteCompose (repost or reply preview) that
first composed while the outer was still highlighted would snapshot the
purple color and never observe the outer's fade back to the default
background.

- Repost inner notes now share the parent's bgColor State directly when
  they have no own read-tracking, so they fade in lockstep with the outer.
- Reply previews no longer receive parentBackgroundColor at all; they rely
  on replyModifier for their own visual style and never inherit the
  purple "new item" highlight from the surrounding post.
2026-05-16 18:45:26 +00:00
Vitor Pamplona 63ddb5159f Merge pull request #2939 from vitorpamplona/claude/remove-mac-13-cio-1mGRB
ci: remove macos-13 x64 build legs
2026-05-16 14:41:01 -04:00
Claude 25a49d1050 ci: remove macos-13 x64 build legs
GitHub's macos-13 runner image is being retired. Drop the x64 macOS
legs from both the desktop and CLI release matrices; macos-14 arm64
continues to ship the macOS builds.
2026-05-16 17:18:51 +00:00
Vitor Pamplona f108ba9050 - Spotless 8.4.0 with ktlint() (no version pinned) was resolving ktlint 1.8.0.
- ktlint 1.8.0 changed how rule providers are loaded, and spotless 8.4.0 ends up handing the engine an empty ruleProviders set — so every file fails with IllegalArgumentException: A non-empty set of 'ruleProviders' need to be provided.
2026-05-16 12:43:40 -04:00
Vitor Pamplona 7e922692d5 removes ammolite from plans 2026-05-16 12:37:14 -04:00
Vitor Pamplona 8a498695a9 v1.09.2 2026-05-16 12:06:32 -04:00
Vitor Pamplona ac1d4ae16d Merge pull request #2938 from vitorpamplona/claude/investigate-kotlin-compile-speed-tl7Zn
Remove unused ammolite module and optimize build config
2026-05-16 12:03:46 -04:00
Vitor Pamplona 32b9a06612 Ignores duplicated hashtags in different char cases when processing hashtag spam 2026-05-16 11:34:11 -04:00
Claude 66df23fc2c build: right-size Kotlin daemon heap from 12g/4g to 8g/2g
Measured the actual Kotlin daemon peak RSS during a full cold compile
of :amethyst:compilePlayDebugKotlin (which transitively compiles
:quartz, :commons, :quic, :nestsClient as well, in parallel after the
earlier parallel-mode change). Peak RSS was ~6.3 GB at the previous
12g/4g setting, meaning heap usage peaked around 4-5 GB plus
metaspace and native memory.

Drops to -Xmx8g -XX:MaxMetaspaceSize=2g, which:

- Cuts committed-virtual-memory ask from 18 GB (Gradle 6g + Kotlin 12g)
  to 14 GB, comfortably under typical CI runner RAM and well under the
  15 GB available in this dev environment.
- Frees ~4 GB of headroom for the OS file cache, which speeds up
  classpath snapshot I/O on incremental builds.
- Leaves clear headroom over peak usage so GC pressure stays low; we
  re-measured cold compile after the change at 3m30s vs 3m34s before,
  well within run-to-run noise.
- Peak Kotlin daemon RSS at the new setting: 4.96 GB, confirming the
  daemon right-sizes itself rather than pinning the ceiling.

If a much larger codebase target lands later (e.g. iOS framework
compilation in this same daemon), bump back up — the value is not
sacred, it just shouldn't request more than the host can afford.
2026-05-16 14:54:44 +00:00
Claude 2e8bf0d45d build: remove unused :ammolite module
The :ammolite module contained no production Kotlin/Java sources (just
a manifest, build.gradle, and proguard stubs) and no module in the
codebase imports com.vitorpamplona.ammolite.*.

Removes:
- ammolite/ directory (5 files)
- :ammolite project include in settings.gradle
- implementation project(':ammolite') from :amethyst
- androidTestImplementation project(':ammolite') from :benchmark
- :ammolite:testDebugUnitTest from CI workflow and pre-push hook
- -keep class com.vitorpamplona.ammolite.** rules from
  :amethyst, :commons, and :desktopApp proguard files
- Stale references in CONTRIBUTING.md, CLAUDE.md, and the
  gradle-expert skill dependency-graph doc

Small build-graph win: one fewer module to configure, compile, lint,
and spotless-check on every build, and one fewer unit-test target in
both CI and the local pre-push hook.
2026-05-16 14:40:03 +00:00
Vitor Pamplona 3bf3157b17 Merge pull request #2937 from vitorpamplona/claude/binary-persistence-format-gUspB
perf(dns-cache): hand-rolled binary persistence format for SurgeDnsStore
2026-05-16 10:34:17 -04:00
Claude f0ee1221cb refactor(dns-cache): drop data from DnsCacheRecord
Auto-generated equals/hashCode would compare the ByteArray-list of
addresses by reference identity — a footgun no caller needs. No code
uses ==, copy, componentN, or hashing on records, so the class is now
plain with no synthesized methods.
2026-05-16 14:30:09 +00:00
Claude 424d750aea refactor(dns-cache): drop legacy DNS migration paths
Removes the json-blob and SharedPreferences reclaim routines now that
the binary format is the first persisted shape — no users carry the
older blobs.
2026-05-16 14:30:09 +00:00
Claude 435aa3e7df fix(dns-cache): defer legacy-blob reclaim to load() and clean partial tmp writes
The legacy `.json` reclaim was running in the constructor, which fires
on Application#onCreate (main thread) — a strict-mode regression vs the
prior no-op constructor. Moved into load(), which is documented as
background-only.

Also wraps the tmp-file write/rename in a try/finally so a writeRecords
crash partway (corrupt record, disk-full mid-write) or a copyTo
fallback can't leave an orphaned `.tmp` sibling behind.
2026-05-16 14:30:09 +00:00