Commit Graph
13823 Commits
Author SHA1 Message Date
Vitor PamplonaandGitHub 439331722a Merge pull request #2973 from vitorpamplona/claude/stop-video-background-timeout-jSLCO
Release MediaController after 30s background timeout
2026-05-19 10:34:44 -04:00
Vitor PamplonaandGitHub 7b720a9a8d Merge pull request #2977 from davotoula/feat/onchain-zaps-reactions-gallery
Show on-chain Bitcoin zappers as a dedicated ₿ row in the expanded reactions gallery
2026-05-19 10:34:19 -04:00
Vitor PamplonaandGitHub e94e1782c1 Merge pull request #2975 from nrobi144/fix/desktop-deb-launch-crash
test(desktop): add Compose UI smoke test + release .deb launch CI
2026-05-19 10:33:49 -04:00
Vitor PamplonaandGitHub a747e20c86 Merge pull request #2980 from vitorpamplona/claude/debug-longpress-root-note-4UR5I
Fix popup menu positioning and parameter naming
2026-05-19 10:01:12 -04:00
Claude f2f02ab5cb fix(thread): restore long-press on root note + anchor popup to the card
Two related fixes to the thread quick-action popup:

- ThreadFeedView.FullBleedNoteCompose declared a `modifier` parameter
  that NoteMaster used to attach `combinedClickable(onLongClick = showPopup)`,
  but the body built a fresh `Modifier.fillMaxWidth().padding(top = 10.dp)`
  for its root Column and discarded the incoming modifier. Long-press on
  the root note in thread view never fired. Spread the incoming modifier
  onto the Column.

- LongPressToQuickAction emitted the Popup as a sibling of the content
  with no wrapping layout. The Popup's `parentLayoutCoordinates` then
  resolved to the enclosing LazyColumn, so `alignment = Alignment.Center`
  centered the menu on the whole list (visually middle of the screen)
  instead of the long-pressed card. Wrap content + Popup in a Box so the
  popup's parent bounds match the note card.
2026-05-19 13:45:56 +00:00
David KasparandGitHub 5973429860 Merge pull request #2979 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-19 15:38:46 +02:00
Crowdin Bot e1e185a6f2 New Crowdin translations by GitHub Action 2026-05-19 13:26:50 +00:00
Vitor Pamplona de222d152b Merge branch 'main' of https://github.com/vitorpamplona/amethyst 2026-05-19 09:24:34 -04:00
davotoula cf44c092dd Code review:
- invalidate zaps flow when removeAllChildNotes clears onchainZaps
- simplify on-chain zap gallery after review
2026-05-19 13:10:02 +02:00
davotoula 91ded74636 Show on-chain zappers in expanded reactions gallery
- Add OnchainZappedIcon and PendingClockBadge
- move PendingClockBadge to TopStart to avoid follow-dot clash
2026-05-19 13:10:02 +02:00
David KasparandGitHub d41cf6d75b Merge pull request #2976 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-19 12:34:53 +02:00
nrobi144andClaude Opus 4.6 5ad21b6acd fix(desktop): disable ProGuard optimization entirely — fixes kmp-tor crash
Disabling individual sub-passes (method/specialization/returntype,
method/marking/static) was not sufficient. The interaction between
multiple optimization passes causes IncompatibleClassChangeError in
kmp-tor's AsyncFs.of() at launch. Shrink (dead code removal) stays
ON for the size win; only optimize is disabled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 10:11:11 +03:00
Crowdin Bot 7c3399438d New Crowdin translations by GitHub Action 2026-05-19 06:50:42 +00:00
David KasparandGitHub 733e2945bd Merge pull request #2972 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-19 08:49:16 +02:00
nrobi144andClaude Opus 4.6 487dd3f2ac fix(desktop): disable method/marking/static ProGuard optimization
The smoke test discovered that ProGuard's method/marking/static pass
converts kmp-tor's AsyncFs.of() from instance to static. The JVM
then throws IncompatibleClassChangeError at launch because callers
still use invokevirtual.

Also updates smoke-test-desktop.yml trigger: runs on any PR touching
desktopApp/ (not just build config files).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 09:48:01 +03:00
nrobi144andClaude Opus 4.6 c0c055e771 fix(desktop): restore java.management module — confirms #2819 fix
Reverts the intentional breakage from d0a6bbc96. The smoke test
proved it catches the crash: removing java.management from jlink
modules causes a fatal IncompatibleClassChangeError in kmp-tor
at launch (the module is needed for ManagementFactory + tor runtime).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 09:26:26 +03:00
nrobi144andClaude Opus 4.6 d0a6bbc96f test(ci): intentionally remove java.management to verify smoke test catches #2819
This commit should FAIL the release-deb-launch CI job, proving the
smoke test works. Will be reverted in the next commit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 09:05:10 +03:00
nrobi144andClaude Opus 4.6 2010e41b25 fix(ci): allow dpkg post-install error, verify binary extracted
dpkg -i exits non-zero when the post-install script fails even with
--force-all. Allow the error with || true, then verify the binary
was actually extracted to /opt before proceeding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 07:59:33 +03:00
nrobi144andClaude Opus 4.6 cca9c2ff3a fix(ci): use dpkg --force-all to skip xdg-desktop-menu error on runner
jpackage's post-install script calls xdg-desktop-menu which fails on
GitHub Actions runners with "No writable system menu directory found".
Menu registration is irrelevant for smoke testing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 07:39:34 +03:00
nrobi144andClaude Opus 4.6 cf6541a1e1 test(desktop): add Compose UI smoke test + release .deb launch CI
Fixes #2819 — v1.08.0 .deb crashed on Ubuntu with ManagementFactory
error because the build had no jlink modules() declaration. Current
main already has the fix; this PR adds CI to prevent regressions.

- Add compose.desktop.uiTestJUnit4 dependency
- DesktopLaunchSmokeTest: renders LoginScreen, asserts title text
- build.yml: xvfb for Linux leg so UI test runs on every PR
- smoke-test-desktop.yml: builds release .deb, installs it, launches
  under xvfb, verifies process stays alive 10s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 07:09:16 +03:00
Vitor PamplonaandClaude Opus 4.7 ab3d1dd7e5 fix(quartz/sqlite): set busy_timeout to deflake reader+writer races
Without busy_timeout SQLite returns SQLITE_BUSY immediately when
BEGIN IMMEDIATE can't acquire a lock — e.g. during a WAL
auto-checkpoint or a reader briefly upgrading its snapshot — instead
of retrying. ParallelInsertTest's reader+writer test hit this ~10%
of runs. 5s matches Room's default and adds no overhead in the
uncontended case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:02:35 -04:00
Crowdin Bot cfa19ce7da New Crowdin translations by GitHub Action 2026-05-18 23:22:26 +00:00
Vitor PamplonaandGitHub 0d91245e02 Merge pull request #2971 from vitorpamplona/claude/add-nowhere-links-LPMnM
Add Nowhere link detection and branded card rendering
2026-05-18 19:20:34 -04:00
Claude 4d428025d3 feat(voice): pause voice notes on background like videos
Voice notes go through GetVideoController, so the 30s background
release timer + warm-pool reattach already applied to them. What was
missing was the immediate ON_PAUSE handler: voice didn't use
ControlWhenPlayerIsActive, so playback kept running for the full 30s
before the release timer hit and cut it off via the warm-pool pause.

Extract a small PauseControllerWhenInBackground composable from the
ON_PAUSE arm of ControlWhenPlayerIsActive and call it from VoiceTrack.
Result matches video: pause on ON_PAUSE, release at 30s, reassemble
the controller (paused, position preserved) when the user returns —
no auto-resume since voice has no autoplay setting.

PiP exemption (BackgroundMedia.isMutex) is preserved.

https://claude.ai/code/session_01RoEUbAN8ejF21Ns3eM6xad
2026-05-18 23:18:51 +00:00
Claude b16d44721c perf(richtext): collapse nowhere-link classifier into the existing URL branches 2026-05-18 22:54:35 +00:00
Claude b71b7cb420 fix(video): skip background release timer for PiP
The 30s release timer fires on ON_PAUSE, but PipVideoActivity enters
PiP mode (which dispatches ON_PAUSE) immediately after onCreate. The
MediaController is built asynchronously and RegisterBackgroundMedia
runs only after inner() mounts, so there's a window where the timer's
BackgroundMedia.isMutex check sees a stale (or null) bgInstance and
releases a controller that was about to start background playback —
blanking the PiP window.

Add an opt-out parameter on GetVideoController and disable the timer
from PipVideoActivity. PiP IS the explicit background-playback opt-in,
so the timer doesn't apply by design.

https://claude.ai/code/session_01RoEUbAN8ejF21Ns3eM6xad
2026-05-18 22:50:33 +00:00
Vitor PamplonaandGitHub 8b31e60f52 Merge pull request #2965 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-18 18:36:46 -04:00
Claude a2da9ae2c6 i18n: extract NowhereLinkCard tool labels to string resources 2026-05-18 22:33:23 +00:00
Crowdin Bot 37f6f92c04 New Crowdin translations by GitHub Action 2026-05-18 22:14:57 +00:00
Vitor PamplonaandGitHub 68c081602f Merge pull request #2966 from vitorpamplona/claude/fix-video-mime-type-sqkiz
Fix MediaStore MIME type compatibility for video files
2026-05-18 18:13:19 -04:00
Claude 09857b8924 Merge remote-tracking branch 'origin/main' into claude/fix-video-mime-type-sqkiz 2026-05-18 22:04:15 +00:00
Vitor PamplonaandGitHub af4835aff3 Merge pull request #2967 from vitorpamplona/claude/notification-settings-refactor-FZ1bx
Extract notification settings to dedicated screen
2026-05-18 17:58:04 -04:00
Claude b2b4895570 refactor(notifications): cleaner Compose patterns in Categories section
- Replace `remember { side effect }` with lazy `entry.ensure(context)` in
  the row's onClick; the system per-channel page only needs the channel
  to exist at open time, not before, and the ensure call is idempotent.
- Replace the `refreshKey++` invalidation trick with a real
  `Map<channelId, ChannelStatus>` state holder updated inside
  `LifecycleResumeEffect`; downstream reads are direct map lookups.
- Replace `Triple`-with-destructuring in `ChannelStatusBadge` with three
  direct `when` branches calling `StatusChip` — no tuples, no
  temporaries.
- Drop the unused `notification_settings_open_system` string.
2026-05-18 21:53:32 +00:00
Claude b4ef70176e test: cover MIME type normalization for MediaStore
Verify video/x-m4v maps to video/mp4 (the failing case), normalization
is case-insensitive, and supported image/video/audio types pass through
unchanged. Required making normalizeMimeTypeForMediaStore internal.
2026-05-18 21:51:58 +00:00
Claude 4d88444a59 feat(notifications): split delivery vs display, add Categories section
Reorganize Notification settings into three sections that reflect what
each control actually does:

- Delivery: how notifications reach the device — push provider (fdroid)
  and the always-on relay service live together here.
- In-app display: how the notifications screen renders incoming activity —
  currently the Split-by-Follows toggle.
- Categories: one row per user-facing Android NotificationChannel (DMs,
  Mentions, Replies, Reactions, Zaps, Chess, Scheduled posts, Calls),
  showing the current importance (On / Silent / Off) and opening the
  system per-channel settings page on tap. Foreground-service channels
  are intentionally omitted — disabling them breaks the service contract.

The screen ensures every listed channel exists on first open and
re-reads importance via LifecycleResumeEffect so the badge reflects
changes made in system settings.

API surface bumped for the channel registry:
- CallNotifier.CALL_CHANNEL_ID is now public.
- ScheduledPostNotifier.ensureChannel is now public.
2026-05-18 21:49:09 +00:00
Vitor PamplonaandGitHub d3c9f5a4f0 Merge pull request #2970 from vitorpamplona/claude/fix-timedout-exception-TJ2te
Refactor media upload to use AccountViewModel.launchSigner
2026-05-18 17:47:47 -04:00
Vitor PamplonaandGitHub 54a6109d83 Merge pull request #2969 from vitorpamplona/claude/hashtag-limit-warning-FQwtJ
Add excessive hashtag detection to hidden note UI
2026-05-18 17:44:54 -04:00
Vitor PamplonaandGitHub 2fff2c137c Merge pull request #2968 from vitorpamplona/claude/fix-image-loading-layout-DlLYr
Support floating-point dimensions in NIP-92 imeta tags
2026-05-18 17:43:29 -04:00
Claude 6be26e1412 fix(media): route media-upload signing through launchSigner
Replaces the previous narrow try/catch fix. The earlier patch silently
swallowed SignerExceptions in NewMediaModel / EditPostViewModel — no
toast, no error dialog — so the user would tap Post, see the dialog
close, and never learn that the signer prompt timed out or was
rejected. It also bypassed the project's standard signer-error
pipeline.

This version routes the sign+publish phase through
AccountViewModel.launchSigner, which is the same path every other
signing entry point uses:
- ReadOnly / SignerNotFound / UnauthorizedDecryption / IllegalState →
  toastManager surfaces a localized alert.
- TimedOut / ManuallyUnauthorized / etc. → logged silently (no crash),
  matching the rest of the app's behavior when a user dismisses the
  external signer.

NewMediaModel.upload now takes an AccountViewModel parameter; the three
inner viewModelScope.launch(Dispatchers.IO) blocks become
accountViewModel.launchSigner { ... }. The joinAll wait is preserved
(launchSigner returns Job).

EditPostViewModel.uploadUnsafe routes its single launch the same way
and wraps the body in try/finally so mediaUploadTracker.finishUpload()
still runs if a signer throws mid-flow.

launchSigner is changed from Unit to Job (= viewModelScope.launch ...)
so callers can join — non-breaking for the ~190 existing callsites that
ignore the return value.
2026-05-18 21:35:38 +00:00
Claude 48d9e80e20 refactor: address self-audit on notification settings
- Promote the duplicate `SwitchTile` from SecurityFiltersScreen and
  NotificationSettingsScreen into a shared `SettingsSwitchTile` in
  SettingsSectionCard so all settings switches share one implementation.
- Render BatteryOptimizationBanner outside the in-app section card
  instead of nesting a Card inside a Card and splitting the section's
  divider away from the row it explains.
- Refresh the battery-optimization exemption on LifecycleResumeEffect
  so the banner disappears after the user returns from the system
  settings page; drop the racy post-button re-read.
- Demote `HasPushNotificationProvider` to a plain `hasPushNotificationProvider`
  since it returns a per-flavor constant and reads no Compose state.
2026-05-18 21:34:32 +00:00
Vitor PamplonaandGitHub 90272fea6f Merge pull request #2964 from vitorpamplona/claude/fix-classcastexception-android-CYKoy
Replace AtomicReference with LargeCache in RelayAuthenticator
2026-05-18 17:23:51 -04:00
Claude 669199ab7e refactor(quartz): use LargeCache for RelayAuthenticator authStatus
#2946 fixed the ClassCastException with a bespoke AtomicReference<Map>
+ CAS copy-on-write helper. Quartz already has a concurrent-map
abstraction for exactly this purpose — LargeCache — with platform-tuned
actuals (ConcurrentSkipListMap on jvmAndroid, CacheMap on Apple, custom
on Linux). Swap to it.

Removes the bespoke putAuthStatus/removeAuthStatus helpers, the
ExperimentalAtomicApi opt-in, and the AtomicReference imports.

The RelayAuthenticatorConcurrencyTest from #2946 still passes against
the new implementation.
2026-05-18 21:21:02 +00:00
Vitor PamplonaandGitHub a3b2d270c7 Merge pull request #2957 from mstrofnone/feat/search-bar-namecoin-resolution-indicator
feat(search): inline Namecoin resolution indicator in global search bar
2026-05-18 16:40:52 -04:00
m 1c5230cfc5 feat(search): inline Namecoin resolution indicator in global search bar
Reuses the NamecoinResolutionRow composable already shipping for the
onchain-zap recipient field, promoting it from
ui/screen/loggedIn/wallet/ to a generic ui/components/namecoin/
location so it can be mounted anywhere a .bit-shaped search input may
race the local-cache prefix search.

In the global search bar, typing a bare ".bit" host (e.g.
"testls.bit") used to surface a cached sibling profile like
"m@testls.bit" first (LocalCache.findUsersStartingWith hits the
prefix) and only several seconds later be corrected by the slower
on-chain ElectrumX resolution from
SearchBarViewModel.directNip05Resolver. No in-flight indicator and no
feedback on hard failures (timeout, malformed record, etc.).

Changes:

  - git-rename NamecoinResolutionRow.kt and its test from
    ui/screen/loggedIn/wallet/ to ui/components/namecoin/, updating
    the package declaration only.
  - Add an optional `modifier: Modifier = Modifier` parameter to the
    composable (standard Compose convention) and wrap the spinner /
    result / error rows in a Column taking the caller-provided
    modifier. No visual change in OnchainZapSendDialog.
  - Update OnchainZapSendDialog import to the new package location.
  - Mount NamecoinResolutionRow in SearchScreen.SearchBar between
    SearchTextField and SearchFilterRow, with horizontal padding to
    match the rest of the bar. onUserResolved navigates to the user
    and clears the field, matching the bech32 auto-resolve path in
    SearchBarViewModel.directRouteResolver.

State is held in the shared
commons.NamecoinResolveState (no new state class introduced) and
diagnostic wording comes from the existing mapOutcomeToResolveState
helper, so every Namecoin surface continues to produce the same
message for the same outcome.
2026-05-19 06:33:47 +10:00
Vitor PamplonaandGitHub 34cb4eb2ad Merge pull request #2956 from mstrofnone/feat/onchain-zap-namecoin-resolution-indicator
feat(onchain-zaps): inline Namecoin resolution indicator + result row
2026-05-18 16:26:02 -04:00
mstrofnoneandm 012dae31d0 feat(onchain-zaps): inline Namecoin resolution indicator + result row
The local-cache suggestion dropdown can momentarily show a stale match
when the user types a .bit identifier. For example, after resolving
"m@testls.bit" earlier in the session, typing the bare host
"testls.bit" causes findUsersStartingWith() to return the cached
m@... profile first; the correct _@testls.bit profile only appears a
few seconds later when ElectrumX resolution finishes. There is no
visual hint that a Namecoin lookup is in flight, and on hard failures
(timeout, malformed record, no nostr field, etc.) the user gets no
feedback at all.

This adds a dedicated NamecoinResolutionRow composable mounted between
the recipient field and the local-cache dropdown:

  - "Resolving <name> on Namecoin…" spinner while the on-chain
    lookup is in flight (after a 300 ms debounce that matches the
    dropdown's own debounce).
  - On success, a tappable row showing the resolved profile with a
    distinct "Namecoin" badge (MaterialSymbols.Link), so the user
    can pick the on-chain-verified profile unambiguously.
  - On failure, a single explanatory error line covering all
    NamecoinResolveOutcome variants the resolver already produces:
    NameNotFound, NoNostrField, MalformedRecord (with the underlying
    parser error verbatim), ServersUnreachable, InvalidIdentifier and
    Timeout.

State is held in the shared NamecoinResolveState sealed class already
used by NamecoinNameService and the desktop SearchScreen — no new
state model is introduced. A small mapOutcomeToResolveState() helper
mirrors the same wording desktop ships, so all Namecoin surfaces
produce the same diagnostic string for the same outcome.

The row owns its own LaunchedEffect keyed on the typed query, so it
cancels in-flight lookups whenever the user keeps typing, and it
unmounts cleanly once a recipient is selected. It uses the existing
Amethyst.instance.namecoinResolver instance, so no DI plumbing or new
network calls beyond what was already wired up for .bit resolution.

The dropdown is left untouched: local-cache results are still valid
hits (just not necessarily the *intended* on-chain identity), so they
remain available below the new row.

Pure helpers (looksLikeNamecoinIdentifier + the outcome-to-state
mapper) are covered by unit tests in NamecoinResolutionRowTest.
2026-05-19 06:11:39 +10:00
Vitor PamplonaandGitHub 67e2ee6bd7 Merge pull request #2955 from mstrofnone/feat/onchain-zap-bit-recipient
feat(onchain-zaps): enable Send when typed name resolves via NIP-05
2026-05-18 15:33:04 -04:00
Vitor PamplonaandGitHub 994923fb84 Merge pull request #2958 from mstrofnone/feat/profile-fields-long-press-copy
feat(profile): long-press to copy Nostr Address, Website, LN Address, identities, payment targets
2026-05-18 15:31:13 -04:00
Vitor PamplonaandGitHub 869447cfb1 Merge pull request #2962 from davotoula/fix/relay-authenticator-concurrent-map
Thread-safe authStatus in RelayAuthenticator (#2946)
2026-05-18 15:30:36 -04:00
Vitor PamplonaandGitHub f57facab06 Merge pull request #2963 from vitorpamplona/claude/fix-git-repo-ui-overlap-LWtb9
Apply scaffold padding to GitRepositoryOverview
2026-05-18 15:24:44 -04:00