Commit Graph
16718 Commits
Author SHA1 Message Date
Vitor PamplonaandGitHub 107777369f Merge pull request #3548 from vitorpamplona/claude/user-nicknames-contactcard-mglbz8
Nickname users via NIP-85 contact cards (encrypted petname + private note, custom emojis)
2026-07-13 20:16:09 -04:00
Claude d2f02fbd32 style: double the nickname card's top margin, halve its bottom margin
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdvE4LvgkSewJXyFzyyAUY
2026-07-13 23:52:13 +00:00
Claude b76b37744e feat: nickname card on the user profile, above the real display name
The profile header no longer replaces the big display name with the petname.
Instead, when the account nicknamed the user (or kept a private note about
them), an outlined card renders above it — petname, divider, private summary —
with the standard Lock private marker in its top-right corner, since both
fields live NIP-44 encrypted in the account's contact card. Tapping the card
opens the shared nickname editor. The profile's own display name stays fully
visible underneath. Feeds, chats and mentions keep rendering the petname
instead of the display name.

To carry the summary into the UI, the commons PetName holder generalizes to
Nickname(petName?, summary?, tags), built when either field exists — so a
note-only card (no petname) now shows on the profile too, while the name
override everywhere else keys strictly off petName.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdvE4LvgkSewJXyFzyyAUY
2026-07-13 23:33:05 +00:00
Claude a6da2ee69d fix: record contact-card EOSEs from the d-tag so card syncs are incremental
UserCardsSubAssembler.newEose read the filter's p-tags to stamp each target
user's card EOSE, but kind:30382 filters address targets in the d-tag — so
no per-user EOSE was ever recorded, groupByRelayPresence always classified
users as never-checked, and every filter update re-downloaded the visible
users' cards with since = null. Read the d-tag instead, and use DTag.TAG_NAME
on both the filter builder and the EOSE reader so the two keys cannot drift
apart again. Pre-existing on main; surfaced while verifying that card syncs
are incremental from the account's outbox relays.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdvE4LvgkSewJXyFzyyAUY
2026-07-13 21:52:29 +00:00
Claude e8ecf429a2 refactor: move nickname policy, emoji autocomplete, filters and dialog to commons
Generalizes the remaining platform-bound pieces of the nickname feature so
the desktop app can adopt it:

- ContactCardsState.displayNameFlow/cachedDisplayName own the NIP-81 render
  policy (petname over profile name over npub); the Android observeUserName
  is now a thin wrapper around it
- EmojiSuggestionState.autocompleteInto completes the word under the cursor
  and closes the list — replaces the insert+reset pair copy-pasted in the 8
  composer ViewModels and the nickname dialog
- the kind:30382 filter builders move to commons relayClient/assemblers
  (cards about targets from trusted accounts, and the account's own cards by
  author), shared by the user watcher and the login subscription
- ShowEmojiSuggestionList moves to commons nip30CustomEmojis/ui using coil
  and commons string resources
- EditNicknameDialog moves to commons nip85TrustedAssertions/ui: it takes the
  ContactCardsState and an onSave callback, so each front end only wires its
  own publish path and menu entry; dialog strings move to commons resources

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdvE4LvgkSewJXyFzyyAUY
2026-07-13 21:20:36 +00:00
Vitor PamplonaandGitHub beaae90eb5 Merge pull request #3547 from vitorpamplona/claude/build-oom-investigation-ryd9u6
fix(ci): serialize :amethyst Kotlin compilations on CI to stop daemon OOMs
2026-07-13 16:50:39 -04:00
Claude 899ada61e4 fix(ci): apply the :amethyst Kotlin compile limiter only on CI
The daemon OOM needs a cache-cold compile of several :amethyst variants in
one invocation, which only CI's combined test/lint/assembleBenchmark run
produces; local builds are incremental and usually build a single variant,
and have never shown the problem. Gate the maxParallelUsages=1 service on
the CI env var (always set on GitHub Actions) so local multi-variant builds
keep their parallelism.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ifbUGCADckUb3zaox9wBo
2026-07-13 18:00:28 +00:00
Claude ed04c373b8 fix(ci): serialize :amethyst Kotlin compilations to stop daemon OOMs
CI runs die with java.lang.OutOfMemoryError (GC overhead limit exceeded /
Java heap space) inside the shared Kotlin compile daemon when two variant
compilations of :amethyst run at the same time — e.g. compilePlayDebugKotlin
and compilePlayBenchmarkKotlin in the test-and-build-android job, which
demands four :amethyst variants (unit tests, lint, assembleBenchmark) in one
invocation. KotlinCompile submits its work asynchronously via the Worker
API, so the project lock is released while compilation is still running in
the daemon and Gradle happily starts the next variant's compile task in
parallel; two full :amethyst codegen passes no longer fit the daemon's
-Xmx8g heap (see runs 29260711359 and 29248908870; removing Kover in #3539
helped but was not sufficient).

Register a no-op shared build service with maxParallelUsages = 1 and make
every :amethyst KotlinCompile task use it. The scheduler then runs this
module's Kotlin compilations one at a time — a task holding the service is
not complete until its async worker finishes — while all other work (other
modules' compilation, JVM tests, lint analysis, packaging) keeps running in
parallel. Verified with Worker-API probe tasks: unconstrained same-project
tasks start simultaneously; with usesService they run strictly one after
the other.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ifbUGCADckUb3zaox9wBo
2026-07-13 15:56:51 +00:00
Vitor PamplonaandGitHub b6560ab3f4 Merge pull request #3546 from vitorpamplona/claude/compose-chip-notification-toggle-6nmy6h
Replace remove-from-notify with mute/unmute bell toggle
2026-07-13 11:23:01 -04:00
Claude b69304c4a8 fix: import EmojiSuggestionState from commons in ShowEmojiSuggestionList
ShowEmojiSuggestionList sat in the same package as EmojiSuggestionState, so
it referenced the class without an import — moving the class to commons broke
the Android compile. Caught by an honest verification run: earlier gradle
invocations were targeting a nonexistent :amethyst:compileDebugKotlin task
(the app builds flavored compilePlayDebugKotlin/compileFdroidDebugKotlin)
with the failure masked behind a pipe, so the last three commits had never
actually been compiled.

Verified at this commit: quartz nip85 tests (13/13), :commons:compileKotlinJvm,
:cli:compileKotlin, :amethyst:compilePlayDebugKotlin, :desktopApp:compileKotlin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdvE4LvgkSewJXyFzyyAUY
2026-07-13 15:12:15 +00:00
Claude ab4b0b984d refactor: audit nickname code — dedupe emoji helpers into commons
Review pass over the nickname/contact-card feature for reuse, simplicity and
performance:

- EmojiSuggestionState moves to commons next to EmojiPackState and now takes
  the EmojiPackState directly instead of the whole Android Account, so the
  desktop app can reuse the :shortcode: autocomplete
- the findEmoji helper that was copy-pasted in 8 composer ViewModels is gone;
  everyone calls the shared EmojiPackState.findEmojiTags, which now resolves
  codes through a map lookup instead of a linear scan per code
- ContactCardsState owns the emoji resolution for nickname saves (Account
  just publishes), takes EmojiPackState, and drops its unused scope param
- new synchronous cachedPetName path (decryption-cache read, no crypto) seeds
  observeUserName/observeUserPetName initial values, removing the flash of
  the real name before the flow's first emission
- nickname dialog prefill no longer clobbers text typed while a slow external
  signer decrypts the existing card

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdvE4LvgkSewJXyFzyyAUY
2026-07-13 12:40:38 +00:00
Claude 184f0bfde7 refactor: align ContactCardEvent with the nip88Polls class structure
Replicates the PollEvent layout: all tag parsing moves to TagArray extensions
in TagArrayExt.kt with the event accessors delegating to them, builder
extensions use addUnique for single-instance tags, and construction goes
through template-returning builders instead of methods that sign internally.

- build() returns an EventTemplate<ContactCardEvent> (the signer is only used
  to NIP-44 encrypt the private tags, matching TrustProviderListEvent);
  create() remains as the signer.sign(build(...)) convenience and now takes
  the emoji list directly
- updatePetNameAndSummary() returns an unsigned EventTemplate; callers sign
  it (ContactCardsState and tests updated)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdvE4LvgkSewJXyFzyyAUY
2026-07-13 12:28:23 +00:00
Vitor PamplonaandGitHub 9d79d3bc7f Merge pull request #3545 from vitorpamplona/claude/amethyst-video-repeat-limit-bq2ut7
Add AutoReplayLimiter to cap video auto-loops in feed
2026-07-13 08:11:28 -04:00
Claude b282ac32af feat: turn Notify chips into bell mute-toggles listing all thread members
The composer's Notify row previously showed only the parent's p tags and
its author, each with an x that removed the user for good. It now lists
every thread member (authors along the reply chain plus the parent's
mentions), and each chip carries a bell instead: tapping it mutes the
notification for that user but keeps the chip — faded and with a
bell-off icon so the state is obvious — making it one tap to add them
back. Muted members are dropped from the outgoing event's p tags (and
from a private note's receivers), and drafts round-trip the muted state
by re-deriving thread members whose p tag the draft dropped.

The NIP-22 comment composer gets the same chip semantics; there the
mute is honored for the optional zap-sender tag, while the structural
root/reply scope tags stay as NIP-22 requires.

Adds the notifications_off glyph to the Material Symbols subset font.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eK8mGPcuKYXNyhKVJ8Wg7
2026-07-13 08:48:02 +00:00
Claude 5761f37d0f feat: pause looping videos after 5 automatic plays
Feed videos run under REPEAT_MODE_ONE and looped forever. AutoReplayLimiter
counts each MEDIA_ITEM_TRANSITION_REASON_REPEAT as one completed play and
pauses the player when the 5th play finishes, leaving the video on its first
frame with the play button showing. Pressing play (or the feed mutex resuming
a video scrolled back into view) grants a fresh 5-play allowance, and pooled
players reset the count when they switch to a different media item.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N9RXiM42yqznwTVjw8tLZv
2026-07-13 01:58:10 +00:00
Claude ebeecd1ee7 feat: custom emojis in contact card petnames
Nicknames can now use NIP-30 custom emojis: typing : in the nickname dialog
autocompletes from the account's emoji packs, and the emoji mappings for any
shortcode used are embedded in the card's NIP-44 encrypted content next to the
petname — so even the emoji set stays private. Renderers resolve the petname's
shortcodes against the card's decrypted tags instead of the profile's metadata
tags.

- quartz: updatePetNameAndSummary replaces the private emoji tag set wholesale
  and keeps it out of the public tags; round-trip test added
- commons: PetName(name, tags) holder with content equality, decryption cache
  returns the merged decrypted tag list, EmojiPackState.findEmojiTags resolves
  :codes: against the selected packs
- amethyst: Account embeds resolved emoji tags on save; all petname render
  sites pass the card tags to the WithEmoji composables; nickname dialog gets
  the : emoji autocomplete via EmojiSuggestionState

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdvE4LvgkSewJXyFzyyAUY
2026-07-13 01:39:59 +00:00
Vitor PamplonaandGitHub a2e858d7b4 Merge pull request #3544 from vitorpamplona/claude/pr-note-button-sizing-732r64
Clean up Git card styling and fix duplicated subject in content
2026-07-12 21:28:11 -04:00
Claude 8ee90907ca feat: nickname users via NIP-85 contact cards signed by the account key
Adds petnames/nicknames per https://github.com/nostr-protocol/nips/pull/761,
reusing the kind:30382 contact card already used for WoT scores — a card only
acts as a nickname when signed by the account's main key. Petname and summary
are always stored in the card's NIP-44 encrypted content.

quartz:
- ContactCardEvent.updatePetNameAndSummary edits both fields in the encrypted
  private tags, strips stray public copies, preserves every other tag
- TagArray.petName()/summary() parsers for decrypted tag lists + tests

commons:
- ContactCardDecryptionCache: LRU NIP-44 decrypt cache for own cards
- ContactCardsState: account-scoped access to the account's own cards,
  petname flow per target user, create/update entry point

amethyst:
- Account.updateContactCardPetName publishes through the extended outbox
  relays (NIP-65 write + private outbox + local + broadcast) and the login
  subscription now downloads the account's own kind:30382s from its relays
- petname renders instead of the display name in usernames, profile header,
  chats and @mentions (observeUserPetName)
- Edit-nickname action + dialog on the profile actions menu

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdvE4LvgkSewJXyFzyyAUY
2026-07-13 01:26:27 +00:00
Vitor PamplonaandGitHub 82fa652c19 Merge pull request #3543 from vitorpamplona/fix/inbox-nostr-wine-over-auth
fix(relay-auth): stop paid relays billing accounts that don't use them (inbox.nostr.wine over-AUTH)
2026-07-12 21:05:35 -04:00
Vitor PamplonaandClaude Opus 4.8 6a528a742c fix(relay-auth): show a relay's payment NOTIFY only under the billed account
The relay NOTIFY (payment prompt) went into a process-wide NotifyRequestsCache
and DisplayNotifyMessages showed it under any account whose relay list contained
the relay — so a prompt billed to Amethyst surfaced under Vitor, and stale
entries re-appeared on every account switch.

A NOTIFY doesn't reliably name a pubkey, so instead of parsing the message we
correlate it with the AUTH that triggered it: a paid relay answers an
unauthorized AUTH with `OK <authEventId> false …` right before the NOTIFY, and we
signed that auth event. NotifyCoordinator remembers each auth event's signer,
maps the failing OK back to it, and files the NOTIFY into THAT account's own
Account.relayNotifications. Unattributable NOTIFYs are dropped. DisplayNotifyMessages
now reads only the current account's cache.

Also removes the now-unused app-wide RelayAuthPermissionStore singleton and wires
NotifyCoordinator with the pubkey -> Account lookup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 19:32:24 -04:00
Vitor PamplonaandClaude Opus 4.8 0ec63958b8 fix(relay-auth): only AUTH a relay with accounts that actually use it
One shared NostrClient serves every logged-in account, so a relay's NIP-42 AUTH
challenge is not tied to any one of them. AuthCoordinator used to fold every
account's verdict into one decision and then sign with EVERY account (or a random
throwaway key), so a paid relay like inbox.nostr.wine billed and de-anonymized
accounts that never used it — including via a merged read filter that merely named
them, and via account switches / the background notification consumer.

Decide and sign PER ACCOUNT now: an account signs only if the relay is in its own
relay list, or it is publishing its own event there (RelayAuthFirstParty), AND its
own ledger verdict (Account.relayAuthLedger) allows it. A subscription merely
naming the account is NOT first-party — that is the merged-filter false positive.
The random-ephemeral-key fallback is removed. Own-inbox reads still qualify: the
relay serving them is by definition in the account's own list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 19:32:24 -04:00
Vitor PamplonaandClaude Opus 4.8 f8416f4940 feat(relay-auth): per-account NIP-42 override store + state on Account
Per-relay ALLOW/DENY AUTH overrides (and the policy ledger that reads them)
lived in one process-wide DataStore keyed only by relay URL, so a DENY set for
one account silently applied to every logged-in account. Move them to a
per-account file under accounts/<pubkey>/ and warm-cache the overrides in memory
on the Account (RelayAuthPermissionCache) so an AUTH challenge is answered
without a disk read.

DataStoreRelayAuthPermissionStore now shares one DataStore per file path —
DataStore v1 forbids two live instances on one file, and loadAccount can build
the store more than once per account.

Introduces the per-account state holders wired up by the following commits:
Account.relayAuthPermissions, relayAuthLedger and relayNotifications.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 19:32:24 -04:00
David KasparandGitHub c2714a2f9b Merge pull request #3542 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-12 23:18:17 +01:00
davotoulaandgithub-actions[bot] 8e46714fca chore: sync Crowdin translations and seed translator npub placeholders 2026-07-12 20:06:46 +00:00
David KasparandGitHub a1f470f1ec Merge pull request #3539 from davotoula/fix/ci-android-oom-and-kover-optin
Remove Kover coverage plugin to fix runner OOM
2026-07-12 21:04:36 +01:00
David KasparandGitHub 8689a409db Merge branch 'main' into fix/ci-android-oom-and-kover-optin 2026-07-12 19:39:56 +01:00
davotoulaandClaude Opus 4.8 d7e163111a build: remove Kover coverage plugin
Reverts the Kover coverage aggregation (introduced in dca345212b) from every
module, the root aggregation block, the Sonar coverage import, the version
catalog, and BUILDING.md. With the plugin present the 16 GB CI runner OOM-killed
during the Android test+build job even with Kover opt-in disabled; removing it
entirely clears the OOM. No other CI changes — the diff versus main is exactly
the inverse of dca345212b.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 16:52:29 +01:00
Claude e9899f95cb feat: remove border from git event cards
Try git patch/issue/PR/repo cards without the 1dp outline so they read
like regular posts; the container keeps only the full-width column.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01USiovhenaijgVEFFzASgfy
2026-07-12 15:20:55 +00:00
Claude 97c7fbfe80 fix: compact git-card action buttons and dedupe issue/PR subject heading
The NIP-34 status buttons (Mark merged / Close / Reopen) and the PR
View-changes button used default Material3 sizing, which reads oversized
inside a note card. They now use the same 32dp compact height, tighter
content padding and labelMedium text as the app-recommendation buttons.

Issue and PR cards also showed the title twice when the authoring client
duplicated the subject tag as a leading markdown heading in the content
(gitworkshop/ngit do this). The body renderer now strips that first
heading when it matches the subject already rendered as the card title.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01USiovhenaijgVEFFzASgfy
2026-07-12 02:59:08 +00:00
David KasparandGitHub c337c2353a Merge pull request #3540 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-11 23:06:21 +01:00
davotoulaandgithub-actions[bot] 82f1780b55 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 22:01:21 +00:00
David KasparandGitHub 768523143c Merge pull request #3538 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-11 22:59:12 +01:00
davotoulaandgithub-actions[bot] f2f8bdb765 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 16:13:04 +00:00
davotoula 0053edf2dd refactor: adopt androidx.core KTX helpers (Bitmap/Uri/SharedPreferences) 2026-07-11 17:00:40 +01:00
David KasparandGitHub 56e4b1ec7d Merge pull request #3537 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-11 16:24:08 +01:00
vitorpamplonaandgithub-actions[bot] 757f348a46 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 15:04:41 +00:00
Vitor PamplonaandGitHub 00e02048ea Merge pull request #3536 from davotoula/feat/kover-coverage
Aggregate Kover coverage (for SonarQube import)
2026-07-11 11:02:23 -04:00
David KasparandGitHub 4ceb8f78c2 Merge pull request #3532 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-11 15:38:48 +01:00
Vitor PamplonaandGitHub aff10df508 Merge pull request #3535 from vitorpamplona/claude/nostr-metadata-parse-errors-jmzlyl
fix: don't drop whole kind-0 profiles over one mistyped field
2026-07-11 10:38:07 -04:00
davotoula dca345212b build: aggregate Kover coverage for SonarQube import
- Apply Kover (Apache-2.0, build-time only) to the KMP/JVM modules and aggregate at the root
- include amethyst playDebug in the aggregated Kover coverage
2026-07-11 15:37:40 +01:00
Claude 0e1a14a62d fix: don't drop whole kind-0 profiles over one mistyped field
Clients in the wild publish structurally wrong values in profile
metadata — e.g. "nip05":{} — and the strict field serializers made
JsonMapper throw, so contactMetaData() returned null and the entire
profile (name, picture, about…) was discarded.

Generalize the BirthdayTolerantSerializer precedent: string fields now
use TolerantStringSerializer (accepts any JSON primitive, ignores
objects/arrays/null) and the bot flag uses TolerantBooleanSerializer,
so a single malformed field is skipped instead of being fatal.

Non-JSON content (e.g. "Relay initialized") remains unrecoverable and
still parses to null; a test pins that it does so without throwing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KSCGp6KgcnaepEMbxNroYe
2026-07-11 14:34:50 +00:00
davotoulaandgithub-actions[bot] 2edb22783c chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 14:32:20 +00:00
davotoula d1e5a4ef83 update cs,sv,de,pt 2026-07-11 15:29:23 +01:00
Vitor PamplonaandGitHub a5f9a234c1 Merge pull request #3534 from vitorpamplona/claude/auth-permission-message-text-moco75
Clarify relay auth descriptions for profile and engagement data
2026-07-11 10:28:13 -04:00
Claude 5365311e7d fix: describe relay auth read permission as profile, posts and engagement
The READ_OUTBOX relay-auth prompt and the settings toggle described the
permission as only loading posts, but authenticating to a follow's relay
also downloads their profile information and post engagement. Update the
prompt title, consequence line, reason label and toggle description to
say so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012VmzSAtkFv29KWDzPVBbxS
2026-07-11 14:22:09 +00:00
Vitor PamplonaandGitHub 8e38ea6607 Merge pull request #3533 from vitorpamplona/claude/amethyst-miner-performance-0rw1dn
Parallelize PoW mining with multi-worker nonce search
2026-07-11 09:54:01 -04:00
Claude 5683c74629 perf(amethyst): mine on half the device's cores in the Android app
Each PoW job now races PoWPolicy.minerWorkers(cores) = cores/2 parallel
searches (at least 1) instead of a single thread, so a post on an 8-core
phone mines ~4x faster while the other half of the cores stays free for
the UI, and the total CPU budget matches the old 2-job x 1-thread pool.

- PoWPolicy.minerWorkers(availableProcessors) is the single definition of
  the per-job worker budget.
- PoWPublishQueue gains minerThreads (used by its built-in miner and
  exposed for custom mine lambdas); AppModules wires maxConcurrent = 1 +
  minerThreads = half the cores.
- PoWNostrSigner gains a workers param (default 1), covering reactions,
  reposts and reports via Account.miningSigner; the anonymous-post paths
  in the short-note and comment composers pass the same budget.
- Gift-wrap envelope mining stays single-threaded: the template
  conversion is a non-suspend hook inside the synchronous NIP-59 build.
- UI time estimates (settings picker, composer chip, broadcast banner)
  now benchmark at the queue's worker count via deviceHashesPerSecond(),
  and PoWEstimator caches one rate per worker count.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhaF5scnAvhP9wr9R7bTWM
2026-07-11 12:13:32 +00:00
David KasparandGitHub 9d4e2c3ea6 Merge pull request #3531 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-11 12:15:30 +01:00
davotoulaandgithub-actions[bot] cc275ce62d chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 10:47:38 +00:00
davotoula b8570797fe refactor: extract no-reachability-cache flag name into a constant 2026-07-11 11:44:21 +01:00