Commit Graph
15076 Commits
Author SHA1 Message Date
Claude 93b77348ac refactor: enlarge the Cashu sunglasses further
Bump the pixel sunglasses scale (1.45 -> 1.70) so the shades read bolder and
overhang the slimmed, rounded cashew body more prominently. Body outline and
1.2 stroke weight unchanged.
2026-05-29 23:30:48 +00:00
Claude 92b1af8a23 feat(zap settings): drag-and-drop reordering of quick-zap preset chips
Long-press a preset chip to pick it up and drag it to a new position in the
FlowRow; release to drop. Hand-rolled (no new dependency):

- VM gains moveAmount(from, to) to reorder the preset list.
- Each chip records its bounds (boundsInParent) and is wrapped in key(amount) so
  reordering doesn't restart the in-flight drag gesture; the dragged chip follows
  the finger via graphicsLayer translation and lifts with zIndex.
- The drop target is the chip whose bounds contain the pointer; on cross-over the
  list reorders and the drag offset is rebased so the chip stays under the finger.
  Identity (drag state, bounds map, target) is keyed by the amount value, not the
  slot index, to avoid stale-index bugs across reorders.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 23:11:49 +00:00
Claude c91ef86d4d refactor(zap/wallet): move NWC setup out of zap-amount settings to the Add-NWC screen
The Nostr Wallet Connect section (connect button, paste, QR, manual pubkey/relay/
secret) is removed from the zap-amount settings content. NWC setup now lives only
in the wallet area:

- The `nostr+walletconnect` connect deep link (`dlnwc`) now opens Wallet → Add NWC
  with the URI prefilled (Route.WalletAddNwc gained an optional nip47 arg), instead
  of the old shared NIP-47 setup screen.
- UpdateZapAmountContent loses its nip47uri parameter and the whole wallet-connect
  block; both callers (zap settings + NIP-47 setup) updated. The NIP-47 setup
  screen keeps its Lightning-address and payment-targets sections (both also
  reachable from profile edit / EditPaymentTargets) and is no longer the deep-link
  target.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 23:06:29 +00:00
Claude df33b99b07 refactor: round the Cashu nut body into a smooth outline
Replace the blocky pixel-stepped cashew silhouette with a smooth rounded
outline (corner-cut and emitted as a compact Bézier spline) so the nut reads
as a clean curved shape instead of a staircase. Use a round stroke cap/join at
the same 1.2 weight; the pixel "deal-with-it" sunglasses stay a solid fill.
2026-05-29 23:01:34 +00:00
Claude 5d6a0e542d feat(zap settings): preset chips mirror the live feed chip (rails + default), drop bolt emoji
Quick-zap preset chips now render like the real feed chip instead of a plain
" N" InputChip: the amount with the rails a preset of that size could use —
the amount-tier default rail in colour on the left, the alternatives (cashu /
Lightning / on-chain) in monochrome — with an X to remove. The bolt emoji is
gone; Lightning is the Material Symbols bolt, matching the feed.

Refactor: ZapRail, ZapRailIcon, the tier thresholds, and a new
previewRailsFor / previewPreferredRail / zapRailAccent are now internal so both
the feed chip and the settings preview share one source of truth for rail
choice, ordering, colouring, and the default highlight.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 22:54:08 +00:00
Claude 71bed1cf0a refactor: slim Cashu body and enlarge the sunglasses
Squeeze the cashew outline horizontally (~0.72) and scale the pixel sunglasses
up (~1.45) so the shades overhang the body for a bolder, more recognizable
mark. Stroke weight stays at 1.2 to match the shared Zap outline icon.
2026-05-29 22:51:54 +00:00
Claude d257749908 feat(zap): top-up screen — avatar header, multiple LN wallets, separate top-up amount
- Header is now a visual: your avatar → cashu zap glyph → arrow → the recipient's
  avatar, centered, replacing the explanatory subtitle text.
- Multiple Lightning wallets: each configured NWC wallet is its own "Funds from"
  option (by name), defaulting to the configured default wallet; the chosen
  wallet's URI is used to auto-pay. Falls back to a single external-invoice option
  when no NWC wallet is set up.
- Separated the two amounts: the send (zap) amount is fixed; the editable field is
  now the top-up amount, defaulting to the shortfall and adjustable upward.
  Funding mints/moves the top-up; the nutzap always sends the fixed amount.
- Muted the selected source styling — the radio button carries the signal, so the
  card uses a faint primary wash + a thin low-opacity border instead of a heavy
  2dp outline and filled container.
- Bottom summary now reads "Top up X sats to <mint> and zap <name> Y sats · fee ≈ Z
  sats" (and "Zap <name> Y sats from <mint>" when no top-up is needed), using the
  recipient's display name.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 22:41:27 +00:00
Claude 9010e85411 feat: monochrome outline Cashu icon for Material Symbols compatibility
Convert the multi-tone "deez nuts" Cashu/nutzap logo into a single-color,
tintable outline icon so it behaves like a Material Symbol glyph: the cashew
body is a hollow stroke (1.2 weight, matching the shared Zap outline icon) and
the pixel sunglasses stay a solid fill so they read at small sizes.

Drop the `tint = Color.Unspecified` overrides at every call site (zap chips,
nutzap rows/gallery, redeem, wallet screens) so the icon now tints with the
surrounding content colour instead of being locked to the brand browns, and
remove the imports/comments that only existed to preserve the old multi-tone
rendering.
2026-05-29 22:38:43 +00:00
Claude e1a651e72e fix: honor relay backoff during Tor bootstrap via per-relay config check
Before Tor is ready, relays were disconnecting and immediately
reconnecting, ignoring BasicRelayClient's exponential backoff.

RelayProxyClientConnector calls reconnect(ignoreRetryDelays = true) on
every infrastructure change. That flag flows pool-wide into
connectAndSyncFiltersIfDisconnected and unconditionally bypassed the
backoff gate. While Tor is still bootstrapping its SOCKS port isn't
listening, so each unrelated infra event (connectivity transitions,
self-heal restarts, Tor status churn) forced an immediate reconnect that
failed again — the backoff was computed (delay kept doubling) but never
consulted.

Make the bypass per-relay and conditional on the relay's transport
config actually changing since its last attempt:

- WebsocketBuilder gains connectionConfig(url): an opaque,
  value-comparable token of the transport config (proxy + timeouts).
  Default null = untracked, preserving legacy always-bypass behavior for
  in-process/standalone/test/desktop builders.
- BasicRelayClient records the token at each attempt and only lets a
  forced reconnect skip the backoff when the token changed. A Tor relay
  whose SOCKS config is unchanged keeps honoring its backoff; the moment
  Tor flips to active (proxy port appears) the token changes and it
  reconnects immediately. Clearnet relays still retry immediately
  whenever their own client changes.
- OkHttpWebSocket.Builder reports the proxy+timeout fingerprint, reused
  by needsReconnect() to avoid drift.

Adds BasicRelayClientBackoffTest covering the honored/bypassed/untracked
cases.

https://claude.ai/code/session_01SCz8kdYs2FwesEyzbhmRPY
2026-05-29 22:30:53 +00:00
Claude 4ffb69c459 fix(zap): shrink cashu chip logo further (15→13dp)
Second pass on the cashu logo size — it still read large next to the Material
symbol rails; drop to 13dp and scale the reload "+" badge to 9dp to match.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 22:18:31 +00:00
Claude c801b8e580 feat(zap): merge preferred logo into the amount tap-target; circular option buttons
- The default action is now one tap target: the preferred rail's logo hugs the
  amount (no separate button), and a tap anywhere on icon+amount fires that rail.
- Alternative rails render as distinct circular buttons (filled surfaceVariant
  circle) to their right, so it's clear they're individually tappable.
- The amount takes the preferred rail's accent colour (BitcoinOrange for
  Lightning/on-chain, primary for reload; neutral for the multi-tone cashu logo,
  which has no single brand colour).
- Reworked the preview to exercise every rail combination across the amount tiers
  (5 / 100 / 5k / 100k sats): all-rails, cashu-only, lightning-only, and a
  funds-split reload scenario.

Refactor: split the per-rail logo (ZapRailIcon, click-free) from the tap target
so it can be reused both inside the default area and inside RailButton.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 22:10:54 +00:00
Claude 9386aa6eb2 feat(zap): amount-tiered default rail + preferred logo left of the number
- Default rail is now amount-tiered: under 10 sats prefers cashu (Lightning
  min/fees make tiny zaps awkward), over 10k sats prefers an on-chain
  transaction, and the middle defaults to Lightning — each falling back through
  the remaining rails when the tier's rail isn't available. The tap action and
  the colored leftmost logo both follow this single `preferred` choice.
- The preferred rail's logo now sits to the LEFT of the amount (in colour); the
  alternative rails follow on the right in monochrome.
- Shrank the cashu logo to 15dp (~17%) so it no longer dwarfs the Material
  symbol rails it sits beside; the reload "+" badge scaled to match.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 22:04:36 +00:00
Claude c714eba482 feat(zap): rework top-up screen (rename, editable amount, clearer source, live balances) + chip ordering
Top-up (formerly "Reload Mint") screen:
- Renamed throughout to "Top up mint" / "Top up & send zap".
- Amount is now editable (numeric field, seeded from the tapped preset). The VM
  recomputes shortfall/sources/fees on every edit; if the chosen amount already
  fits the target mint, the screen drops the funding step and just sends.
- Selected funding source is now obvious: radio button + 2dp primary border +
  primaryContainer fill, instead of a faint 12%-alpha tint.
- Each source's balance/description moved to its own line under the title, so
  the Lightning explanation wraps instead of clipping.
- Removed the redundant "Your balances" list (it duplicated the per-mint balance
  the Funds-from rows already show); the target's current balance now sits in the
  destination card.
- Summary reads "Send AAA sats from XXX to YYY, fee Z sats" (or "Send AAA sats to
  YYY" when no top-up is needed).
- Balances are now reactive: the VM observes the wallet's tokenEntries/mints
  flows and rebuilds as proofs arrive from relays, instead of a one-time snapshot
  that could show only the first-loaded mint.

Zap chip:
- The preferred rail (what a plain tap triggers) is rendered first and in full
  colour; the alternative rails follow to its right in monochrome.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 21:53:37 +00:00
Claude bbec99af75 fix(zap): shrink reload cashu logo to one rail's footprint
The NEEDS_RELOAD affordance rendered two full 18dp icons side by side (cashu +
"+"), making the chip nearly twice as wide as the other rails. Overlay the "+"
as a small 11dp corner badge on the dimmed cashu logo so it occupies a single
logo's footprint like Lightning/on-chain.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 21:40:45 +00:00
Vitor PamplonaandGitHub 1ec5f559e6 Merge pull request #3105 from vitorpamplona/claude/eager-davinci-WxjiM
Add dedicated podcast screen with episode list and inline player
2026-05-29 17:32:55 -04:00
Claude ba35a4e527 feat(podcasts): translatable descriptions on the NoteCompose feed cards
RenderPodcastMetadata and RenderPodcastEpisode rendered their description
tag as a plain Text. Both now use TranslatableRichTextViewer (rich text +
translation), matching the podcast screen header. The metadata card finally
uses its previously-ignored canPreview/backgroundColor params; the episode
card gives its short description a distinct id so it doesn't share remember
state with the markdown body below it.
2026-05-29 21:30:44 +00:00
Claude 063ebbebce feat(podcasts): translatable show description + synthetic playback waveform
- The show description on the podcast screen now renders through
  TranslatableRichTextViewer (rich text + translation), matching how a
  profile's About is shown, instead of a plain Text. PodcastHeader takes a
  nav for the rich content's links.
- Audio playback now shows a decorative per-episode waveform when the
  source has none, instead of a flat strip — same behaviour as music
  tracks. Extracted MusicTrack's private syntheticWaveformFor into a shared
  wavefront/SyntheticWaveform.kt used by both music and podcast players; the
  podcast player still prefers a real IMeta waveform when one is present.
2026-05-29 21:21:54 +00:00
Claude 116ff33cd8 test(zap): assert merge preserves preset order instead of sorting
Follow-up to dropping .sorted() from mergeZapAmounts: update ZapAmountMergeTest
to lock in first-seen order (Lightning list, then on-chain extras) rather than
ascending, so a user's saved ordering is provably preserved.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 20:30:58 +00:00
Claude 594f86d1ce Merge remote-tracking branch 'origin/main' into claude/amazing-volta-UJrwo 2026-05-29 20:23:22 +00:00
Claude b1961ea19c fix(zap): address reload-mint audit findings (double-submit, premature done, fee/poll robustness)
Correctness:
- ReloadMintViewModel.confirm() now guards against re-entry (only starts from
  Configuring/Failed and flips to Working synchronously), so a double-tap or a
  Failed-state Retry can't launch two pipelines that double-spend the source /
  double-mint the target.
- sendNutzapAndFinish awaits the real CashuWalletState.sendNutzap (throws on
  failure) and reports Done only on success — a send that fails after a
  successful reload now surfaces as Failed instead of popping the screen on a
  premature "done" and silently stranding the moved funds.
- The reload pipeline runs on the long-lived AccountViewModel scope; the VM now
  holds its Job and cancels it in onCleared(), so leaving the screen stops the
  (up to 3-minute) Lightning poll instead of hammering the mint unobserved.
- rebalance() poll budget widened to a steady ~60s so a merely-slow mint no
  longer strands funds that already left the source.
- Mint a small headroom buffer (RELOAD_FEE_BUFFER_SATS) above the bare shortfall
  so the follow-up nutzap's own swap fee doesn't leave the target a sat short;
  the source-feasibility gate accounts for it.

Regressions from the settings merge:
- mergeZapAmounts / the picker no longer .sorted() the amounts — a user's saved
  preset order is preserved instead of being silently reordered ascending.
- The on-chain send dialog falls back to DEFAULT_ONCHAIN_ZAP_SATS when the
  unified list has nothing above the on-chain minimum, restoring the guaranteed
  quick-pick preset.
- zapClick's one-tap (single-amount) path now checks rail capability and opens
  the picker when the recipient can't receive Lightning, instead of firing a
  doomed Lightning zap.

Cleanup:
- Centralized the mint-quote "settled" predicate as MintQuoteBolt11ResponseDto
  .isSettled(); rebalance, ReloadMintViewModel and CashuWalletViewModel now
  share it instead of three copies of paid==true || PAID || ISSUED.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 20:23:00 +00:00
Claude 07855c2240 Merge remote-tracking branch 'origin/main' into claude/eager-davinci-WxjiM 2026-05-29 20:18:56 +00:00
Vitor Pamplona 936c96e342 Merge branch 'main' of https://github.com/vitorpamplona/amethyst 2026-05-29 16:08:38 -04:00
Claude c504b465e1 refactor(podcasts): share the episode audio player; fix list player height
Audit follow-ups on the podcast screen:

- Extract the duplicated GetMediaItem -> GetVideoController -> RenderVoicePlayer
  block (and the FLAT_WAVEFORM constants) from both PodcastEpisode and
  PodcastEpisodeListItem into one PodcastEpisodeAudioPlayer composable. The
  border shape stays a parameter (bottom-rounded under the cover vs. fully
  rounded in the list).
- Fix the list row clipping the 75dp play button: the row hard-coded 72dp,
  below the voice player's 80dp minimum. Height now lives in the shared
  player so both call sites stay identical.
- Header no longer flashes "0 episodes" while the relay request is in flight:
  episodeCount is nullable and the count/divider only render once loaded.
- Drop the odd uppercasing of the episode date (looked wrong on relative
  values like "3d").
2026-05-29 20:08:11 +00:00
Vitor Pamplona dd92098343 updates all libs 2026-05-29 16:07:49 -04:00
Claude ce32dc4fc3 feat(zap): Reload Mint screen to fund a recipient's mint, then nutzap
When the cashu logo on an amount chip is NEEDS_RELOAD (you hold enough cashu,
but not in the recipient's mint), it now shows a dimmed logo with a "+" badge
that opens a full Reload Mint screen instead of silently falling back to
Lightning.

The screen tells the whole story and auto-sends the nutzap on success:
- Destination ("mint to reload") with its shortfall; selectable when the
  recipient accepts several mints we hold.
- All cashu balances for context.
- Source ("funds from"): another mint (mint-to-mint rebalance, no new sats) or
  Lightning. Mint rows are disabled when they can't cover shortfall + fee.

Funding paths:
- Rebalance: CashuWalletState.rebalance moves cashu between mints.
- Lightning: mint a fresh quote at the destination, auto-pay via NWC when a
  wallet is configured (else show the invoice to copy), poll, then issue.

Wiring: new Route.ReloadMint + AppNavigation entry; a ReloadMintRequest handed
off via an LruCache on AccountViewModel (mirrors the manual-zap pattern);
onReloadNutzap threaded through the zap popup overloads and the chip; callers
(ReusableZapButton, ReactionsRow, NestActionBar) navigate to the screen.

IMPOSSIBLE (not enough cashu anywhere) keeps falling back to Lightning — the
reload screen is only for moving existing cashu.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 19:32:30 +00:00
Claude 46e618aabe feat(podcasts): tap a podcast to open a show screen with all episodes
Each item in the Podcasts feed (kind 10154 show metadata) now opens a
dedicated podcast screen built around the show's pubkey — per NIP-F4 a
podcast is its own keypair, so its metadata and every episode (kind 54)
share one author.

- New Route.Podcast(pubkey) + AppNavigation binding.
- PodcastScreen: modern hero header (cover art, title, websites, tappable
  expand/collapse description, "N episodes" section) followed by every
  episode in a LazyColumn.
- PodcastEpisodeListItem: compact "show list" row (date, title, summary)
  with an inline audio player so episodes play without leaving the list.
- OnePodcast datasource (per-user EOSE manager) fetches the show metadata
  and episodes from the podcast key's outbox relays.
- OnePodcastEpisodesFeedFilter + OnePodcastFeedViewModel scope LocalCache
  to a single podcast's episodes.
- Podcasts feed metadata card is now clickable with a "View episodes"
  affordance.
2026-05-29 19:24:50 +00:00
Claude c73e7924dd feat(cashu): add mint-balance queries and mint-to-mint rebalance orchestration
Foundation for the Reload Mint screen (NEEDS_RELOAD funding path):

- peekMintBalances(): per-mint spendable balance from in-memory proofs
  (synchronous; feeds the balances list and source-feasibility checks).
- recipientSharedMints(): the recipient's accepted mints we also hold —
  the candidate reload destinations.
- rebalance(source, target, sats): mints a fresh quote at the target and
  pays its invoice by melting at the source, moving cashu between mints with
  no new sats. Verifies the source covers amount + fee before spending,
  abandons the unpaid quote otherwise, and leaves a resumable kind:7374 if the
  target hasn't confirmed yet — money is never lost on failure.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 19:19:33 +00:00
Claude 6f7cacf84b refactor(zap): merge on-chain amount presets into the single zap-amount list
The on-chain rail no longer has its own editable preset list. There is now
one zap-amount list used by every rail; on-chain simply filters it by the
shared MIN_ONCHAIN_ZAP_SATS floor (1000 sat), and the unified chip already
gates each logo per amount.

- Settings: drop the public onchainZapAmountChoices StateFlow and its editor
  section in the Update Zap Amount dialog. The serialized field is kept for
  backward/cross-client (NIP-78) compatibility and migration: on load the two
  saved lists are unioned into zapAmountChoices (mergeZapAmounts), and on save
  the on-chain-eligible subset is written back so older clients still get
  sensible on-chain presets. The round-trip is idempotent.
- updateZapAmounts / changeOnchainZapAmounts lose the separate on-chain
  parameter throughout (Account, AccountViewModel, UpdateZapAmountViewModel).
- OnchainZapSendDialog draws its quick presets from the single list filtered
  by the minimum.
- MIN_ONCHAIN_ZAP_SATS is now a single shared constant in the model, replacing
  the copies previously private to OnchainZapSendDialog and ReactionsRow.
- Remove the now-unused on-chain amount strings; clarify the zap-amounts
  explainer to note amounts apply to all rails.

Adds ZapAmountMergeTest covering the union/dedup/idempotent-round-trip.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 18:28:48 +00:00
Claude c1c1a69148 feat(zap): unify zap picker into one chip per amount with per-rail logos
Replace the three parallel chip rows (cashu / lightning / on-chain) in the
zap amount popup with a single pill per amount that shows a tappable logo
for each rail that can actually pay it. Tapping the amount fires the
cheapest/fastest available rail (cashu funded -> lightning -> on-chain);
tapping a specific logo forces that rail.

Rail gating:
- Cashu: precise per-amount status (FUNDED / NEEDS_RELOAD / IMPOSSIBLE /
  UNAVAILABLE) computed from in-memory proofs — the one balance that is free
  to read synchronously. Only FUNDED is offered for now.
- Lightning: optimistic — an external wallet can pay any invoice, so it's
  offered whenever the recipient can receive, with no sender-balance fetch.
- On-chain: offered when a backend is configured and the amount clears the
  on-chain minimum; UTXO sufficiency stays a send-time check.

Also fixes the original "No proofs available at <mint>" failure: nutzap mint
selection now picks the shared mint where we hold the most balance instead of
the first one the recipient lists (peekNutzapFunding), so a zap no longer
fails when funds sit in a different shared mint. Cashu capability is now
resolved against the note author (who sendNutzap actually pays) rather than
split recipients.

Amount presets from the (still separate) lightning and on-chain settings are
merged into one sorted set for display.

https://claude.ai/code/session_01HNE2z7CSYZ2G8KwC5fziJn
2026-05-29 18:09:22 +00:00
Vitor PamplonaandGitHub c3b40c4369 Merge pull request #3075 from vitorpamplona/claude/cashu-wallet-amethyst-sdOWe
Add NIP-60 Cashu wallet and NIP-61 nutzap support
2026-05-29 12:59:20 -04:00
Claude 4e18906f9a feat(nutzap): progress bar during send, matching lightning UX
The cashu zap chip previously fired its async send and closed the
popup with no visible motion until the kind:9321 round-tripped
back (1-2 seconds of "did the tap register?" silence). Wire the
same zappingProgress channel the lightning path uses so the bar
visibly animates from tap to completion.

Pieces:

- CashuWalletOps.sendNutzap: optional `onProgress: (Float) -> Unit`
  emitting at the network checkpoints — 0.55 after the swap (the
  long mint round-trip), 0.80 after the kind:9321 publish (the
  recipient can see it), 0.95 after keep + delete, 1.0 after the
  kind:7376 history.

- CashuWalletState.sendNutzap: forwards onProgress to ops and
  also emits 0.20 after scrubLocallyStaleProofs so the bar moves
  before the slow swap call begins.

- AccountViewModel.sendNutzap: accepts an `onProgress: (Float) -> Unit`
  parameter (default no-op so existing callers compile unchanged)
  and threads it through to CashuWalletState.

- ReactionsRow.onNutzap callback: emits 0.05 immediately on tap
  for instant click feedback, then passes the same `onProgress`
  channel the lightning chip uses so zappingProgress drives the
  same progress indicator. The existing onError reset already
  zeroes the bar on failure.

Resulting cadence at the UI:
  tap → 0.05 (instant)
       → 0.20 (scrub done)
       → 0.55 (mint swap done)
       → 0.80 (kind:9321 out)
       → 0.95 (token rollover + NIP-09 out)
       → 1.00 (history out, bar hides).
2026-05-29 15:32:25 +00:00
Claude 30a845a6c1 Merge remote-tracking branch 'origin/main' into claude/cashu-wallet-amethyst-sdOWe
# Conflicts:
#	amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt
2026-05-29 13:32:49 +00:00
Vitor PamplonaandGitHub c22cd0d242 Merge pull request #3086 from carpedkm/bounty-1497-live-chat-broadcast
Fix live stream chat relay fallback
2026-05-29 09:18:38 -04:00
Vitor PamplonaandGitHub a49f57505a Merge pull request #3102 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-29 09:15:37 -04:00
Crowdin Bot b1f0f04bcc New Crowdin translations by GitHub Action 2026-05-29 13:02:55 +00:00
Vitor Pamplona c1dd59a068 Merge branch 'main' of https://github.com/vitorpamplona/amethyst
# Conflicts:
#	commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/subscriptions/LifecycleAwareKeyDataSourceSubscription.kt
2026-05-29 08:57:31 -04:00
Vitor Pamplona c1c4f7f72a Uses the parent note's p-tags to load children notes that cannot be found 2026-05-29 08:47:28 -04:00
Vitor Pamplona 90109c9095 Removes the need of idHex on the BlankNote 2026-05-29 08:40:31 -04:00
Vitor Pamplona ca8589b29c Quick check to make sure the gatherers are not duplicated 2026-05-29 08:37:08 -04:00
Vitor Pamplona 350aadc578 Pushes event hints for citations in Public Messages 2026-05-29 08:36:41 -04:00
Vitor PamplonaandGitHub fd88e2f8a5 Merge pull request #3095 from vitorpamplona/claude/amazing-ptolemy-26Nek
Use locale-aware date/time formatting throughout the app
2026-05-29 08:30:41 -04:00
Vitor PamplonaandGitHub 9a6400a6e3 Merge pull request #3103 from greenart7c3/claude/elegant-knuth-grbfU
Fix lifecycle-aware subscription grace timer starvation
2026-05-29 06:34:53 -04:00
Claude 5667bd53c3 fix(relays): keep lifecycle-aware grace timer running while backgrounded
The grace-period unsubscribe in LifecycleAwareKeyDataSourceSubscription ran
on the composition scope from rememberCoroutineScope(), whose dispatcher is
coupled to the UI frame clock. When the app is backgrounded the frame clock
stops ticking, so the pending unsubscribe could be starved and never fire.
Because closing the REQ is what drives the relay disconnect (via desiredRelays
-> RelayPool.updatePool), the connection could linger indefinitely. This is
most visible on the relay feed, whose dedicated one-off relay is kept alive by
nothing else.

Drive the grace timer from Lifecycle.currentStateFlow on a dedicated
Dispatchers.Default scope instead. collectLatest cancels the pending delay
automatically when the lifecycle returns to STARTED, preserving the 30s
app-switch grace while ensuring the timer fires reliably in the background.

https://claude.ai/code/session_01SesftJphLwvLtn1fJB5zx8
2026-05-29 09:29:48 +00:00
Vitor PamplonaandGitHub 8fcfbf8477 Merge pull request #3098 from nrobi144/feat/desktop-visual-personality
feat(desktop): Visual Personality Overhaul — Unified Theme, Sidebar, Search, Cards
2026-05-29 05:13:00 -04:00
nrobi144andClaude Opus 4.6 dd5b61a6f0 feat(desktop): add "All Screens" item before feeds in sidebar
Opens the App Drawer (same as Cmd+K) for quick access to all
available screen types. Positioned between main nav and FEEDS section.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 07:09:50 +03:00
nrobi144andClaude Opus 4.6 71a38674b0 fix(desktop): first feed item 16dp top padding via LazyColumn contentPadding
- Revert spacer change (back to 60dp)
- Add top = 16.dp to LazyColumn contentPadding so first card has
  extra spacing and slides nicely under the floating search header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 07:02:53 +03:00
nrobi144andClaude Opus 4.6 cc698c5e91 fix(desktop): sidebar starts expanded + extra 16dp feed margin
- Sidebar always starts expanded (ignores persisted collapsed state)
- Feed spacer 60dp → 76dp (extra 16dp gap between header card and first item)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 07:02:52 +03:00
nrobi144andClaude Opus 4.6 0e431d674c feat(desktop): branded loading screen instead of login flash on startup
- Add AccountState.Loading as initial state (was LoggedOut)
- Show centered "Amethyst" + spinner while accounts load from storage
- After loadSavedAccount(): transition to LoggedIn or LoggedOut
- No more 0.5s flash of login screen when account exists

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 07:02:52 +03:00
nrobi144andClaude Opus 4.6 da0aaaa281 fix(desktop): wider collapsed sidebar + filled Tor icon when connected
- COLLAPSED_WIDTH 56dp → 64dp so icons aren't truncated
- Tor connected: use Security icon (filled shield) instead of Shield
- Tor off/connecting/error: keep outlined Shield icon

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 07:02:52 +03:00
nrobi144andClaude Opus 4.6 12918e7045 feat(desktop): Tor/Bunker status as proper sidebar nav items
- Replace compact icon Row at bottom with SidebarNavItem-style items
- Tor: shows "Tor: Off/Connecting/Connected/Error" with Shield icon
- Bunker: shows "Bunker: OK" with Favorite icon (only when connected)
- Both use same shape, hover, and label pattern as other sidebar items
- Collapsed mode: icon-only with tooltip, same as nav items

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 07:02:52 +03:00