Commit Graph
16711 Commits
Author SHA1 Message Date
Claude e684cb02a3 feat(ui): tap explainers for the PoW, private-rumor and expiration markers
Following the OTS pill's pattern, tapping now explains what the marker
means: PoW describes the mining difficulty as an anti-spam stamp
(pow_info_description), the private-rumor lock explains the unsigned
private delivery and its deniability (private_rumor_info_*), and the
expiration pill shows the request to delete plus the exact expiry
date/time (expiration_info_description).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-14 14:31:23 +00:00
Claude 500de62841 fix(ui): explain pending OTS on tap, render the stamp glyph and pill icons larger
Tapping the pending OTS pill now shows a toast explaining that the
attestation is waiting to be stamped into the Bitcoin blockchain (new
ots_info_pending_description). The OpenTimestamps glyph gets a
near-full-em content box — its fine outline read much lighter than
Material's solid shapes at the standard 80..880 bounds — and HeaderPill
icons go from 11dp to 13dp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-14 14:15:56 +00:00
Claude 568aa9b005 fix(ui): use middle ellipsis in HeaderPill labels
Truncated pill labels (capped city names, relay hosts) keep their
distinguishing endings, matching the codebase convention for URLs and
relay links.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-14 13:49:08 +00:00
Claude 811d9cf802 feat(ui): icon-only fork mark, pencil edit mark, tighter expiration and location pills
- The fork marker drops "Forked from <name>" for a bare fork-right icon
  (new MaterialSymbols.ForkRight, U+EBAC); tapping still opens the
  original version. Font regenerated via subset.sh, which also re-baked
  the custom OpenTimestamps glyph, proving the custom-glyph pipeline
  survives regeneration.
- The edited mark becomes a pencil: bare pencil for the latest edit,
  pencil + "#2"/"original" only while cycling versions on tap.
- The expiration pill clamps beyond one year to "1y+" instead of
  switching to a full date.
- The location pill caps at 110dp and ellipsizes, so unbounded city
  names cannot squeeze the author's name out of the row.
- Remove the now-unused existed_since string from all 35 locale files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-14 13:46:12 +00:00
Claude 170bc7c121 fix(ui): restore full-size quiet marks, tighten the dotted timestamp, drop Boosted
Quiet marks go back to the row's regular text size in bold with 16dp
icons; the hashtag/community soft links lose their 12sp override too
(the smaller tier read as too small). A new TimeAgoStyle.DottedTight
renders "• 5m" without the leading space for rows whose spacedBy
already provides the gap, removing the double space before the
timestamp. The OTS pending pill shrinks to the stamp icon plus an
ellipsis (the words move to the content description). The Boosted mark
is removed entirely — from the Android header, the commons component,
and the desktop feed — since the repost context is already visible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-14 13:30:38 +00:00
Claude 41ef1d89b3 feat(ui): add the OpenTimestamps logo as a custom glyph and use it in the OTS pill
Bake the official OpenTimestamps stamp logo (traced from
opentimestamps/logo vector.svg; monochrome outline, tinted at render
time like every other glyph) into the Material Symbols subset font at
U+F8F0. New tools/material-symbols-subset/add_custom_glyphs.py converts
the traced SVGs in custom/ into TrueType glyphs and is invoked by
subset.sh after pyftsubset, so font regenerations keep them.

With the logo identifying the pill, drop the verbose "OTS:" prefix:
the pill now reads icon + "2y" (or icon + "Pending", new
R.string.pending).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-14 12:59:30 +00:00
Vitor Pamplona efae1dec22 Adjustments 2026-07-14 08:21:44 -04:00
Claude 86da29fa78 fix(ui): mute the header pill wash, restore dotted timestamps, tighten menu gap
- HeaderPill's secondary-container background pulled too much attention;
  it now uses a faint onSurface wash (7%) with placeholderText content,
  so pills read as tappable metadata without competing with the note.
- Note-header timestamps go back to the original dotted format at the
  default size; the TimeAgo style/fontSize params are reverted.
- The timestamp + more-options pair renders unspaced again (the dot and
  the button's icon inset provide the separation), fixing the oversized
  gap the row-level spacedBy introduced before the 3-dot menu.
- The header preview now consumes its fabricated events as
  already-verified (they cannot pass id/sig checks, which left every row
  bare), gives the repost a parseable inner event, and fetches the draft
  through its AddressableNote (draft wraps are addressable events).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-14 01:26:33 +00:00
Claude 1d385cae0f refactor(ui): move HeaderPill and QuietMark to commons/ui/note
The two note-header marker primitives are pure Compose with no Android
dependencies, so they belong in the shared layer where the desktop app
(and future iOS) can render the same design system. QuietMark's gray
comes from a new commons ColorScheme.placeholderText extension
(onSurface at 42%, matching the Android theme's value).

The thin app-side wrappers (BoostedMark, DisplayPoW, DisplayDraft,
DisplayOts, DisplayLocation, DisplayReward, ...) stay in amethyst: they
bind the primitives to Android string resources (with existing
translations that commons' compose-resources catalog does not have) and
to app state (LocalCache loaders, AccountViewModel, navigation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-13 16:04:36 +00:00
Claude 3cba5d3b65 refactor(ui): drive header-marker previews through the real FirstUserInfoRow
Replace the hand-built preview rows and static stand-ins with the actual
FirstUserInfoRow over notes seeded into LocalCache (the ZapPollNote/Poll
preview pattern): metadata for usernames, a repost, an empty-sig rumor, a
draft wrap, a community post, and PoW ids with committed nonces plus
geohash/expiration tags. The geohash resolves through a seeded
CachedReversedGeoLocations entry and the OTS pill renders its real
pending branch via account.settings.pendingAttestations. Only the
followed-hashtag label and the confirmed OTS state stay out - both are
computed in effects that static previews never run, as documented in the
file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-13 15:53:03 +00:00
Claude b81116865c feat(ui): add density previews for the note-header marker system
NoteHeaderFirstRowDensityPreview stacks first-row samples from bare
(username + time + options) to fully loaded (hashtag, edited, draft,
lock, pin, location/PoW/OTS/expiration pills, jump-to-parent) under a
long username, in dark and light themes. Uses the real QuietMark/
HeaderPill components with static stand-ins only for the data-loading
markers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-13 15:32:01 +00:00
Claude 2fefc3a409 feat(ui): unify note-header markers into a two-tier pill/quiet-mark system
Tier 1 (HeaderPill): tappable or verifiable metadata now renders as the
squared secondary-container chip — location, PoW, OTS (already pills),
plus expiration and the bounty reward (bolt icon + amount, tap opens the
pledge dialog; icon turns orange once the user has pledged).

Tier 2 (QuietMark, new): passive state markers — Boosted, Draft, Edited/
Original, pinned, private rumor — share one spec: 12sp medium gray text
with an optional 12dp icon. Draft is no longer a hardcoded English
literal (new R.string.draft).

Cross-cutting cleanups:
- Header rows (NoteCompose First/SecondUserInfoRow, ThreadFeedView) own
  spacing via Arrangement.spacedBy(5dp) instead of per-marker paddings.
- Hashtag/community/fork links use the existing lessImportantLink theme
  color instead of ad-hoc primary.copy(alpha = 0.52f) (fork was full
  primary, louder than everything else on the line).
- NIP-05 badge drops hardcoded Color.Yellow/Color.Red for theme-aware
  placeholderText/error.
- Note-header timestamps switch to the Short style at 12sp; other
  TimeAgo callers keep the dotted default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-13 12:28:59 +00:00
Claude 718e2cba0b feat(ui): move PoW, OTS and location pills to the note header's first line
Restyle DisplayPoW, DisplayOts and DisplayLocation as compact squared
chips via a new shared HeaderPill composable, matching the relay
information pills in the NIP-29 chat headers (which now reuse the same
composable). Move the three pills from SecondUserInfoRow to
FirstUserInfoRow in NoteCompose, and shrink the secondary markers on
that line (boosted, hashtag, community, draft, edited, expiration,
pinned, private-rumor) to 12sp/smaller icons since the row now carries
more information.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgEpNtwnetPhETXQSdq4b5
2026-07-13 01:32:32 +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
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
davotoula cf95b07855 fix: document intentionally empty default no-op bodies 2026-07-11 11:12:20 +01:00
Claude ac98036a8e perf(pow): mine NIP-13 proof of work on all cores and drop per-hash allocations
The miner enumerates the nonce space deterministically (the random base is
overwritten before the first hash), so naively racing N copies of the search
duplicates the exact same candidate sequence N times. PoWMiner.mine() now
races workers over disjoint slices instead: each worker's nonce carries a
distinct fixed prefix while only the bytes after it are enumerated, making the
aggregate hash rate scale with cores (~3.8x on a 4-core box).

The hot loop also switches from sha256() to sha256Into() with a reused
32-byte buffer, so hashing no longer allocates per attempt.

amy wiring:
- `pow mine` and `post --pow` mine on all cores by default; `pow mine
  --threads N` overrides.
- `pow bench` measures the all-cores rate (what mining now uses, also the
  basis for expected_seconds) alongside a new hashes_per_second_single_core.
- PoWEstimator benchmarks with sha256Into to match the miner, and gains a
  workers overload that prices in cross-core contention.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhaF5scnAvhP9wr9R7bTWM
2026-07-11 04:04:28 +00:00
Vitor PamplonaandGitHub b64c378a9d Merge pull request #3519 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-10 23:20:26 -04:00
Vitor PamplonaandGitHub 5c8801082a Merge pull request #3513 from vitorpamplona/claude/amy-graperank-crawl-perf-jhmx0x
GrapeRank crawl: connect once, wait once — 38% faster at hop-3; hop-8 31% faster at +15% lists / +47% users
2026-07-10 23:19:58 -04:00
Vitor PamplonaandGitHub 4cc88cc0ae Merge pull request #3529 from vitorpamplona/claude/powdisplay-notecompose-sizing-x8ua7i
Reduce PoW badge size for better UI balance
2026-07-10 23:19:34 -04:00
vitorpamplonaandgithub-actions[bot] 835f1e5e85 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 03:16:54 +00:00
Vitor PamplonaandGitHub d6c046249e Merge pull request #3528 from vitorpamplona/claude/fix-signed-events-reference-vhrzsa
Mark DM rooms as read when wraps are mined in background
2026-07-10 23:14:35 -04:00