Commit Graph
15672 Commits
Author SHA1 Message Date
Vitor PamplonaandGitHub db13633fcc Merge pull request #3315 from LubuSeb/lubu/url-comments-304
Add URL-scoped comment feeds
2026-06-25 09:13:19 -04:00
Vitor PamplonaandGitHub 2f240e0b87 Merge pull request #3358 from vitorpamplona/claude/always-on-service-logo-t2d2zy
Use hollow gem icon for relay service notification
2026-06-25 08:53:54 -04:00
Vitor PamplonaandGitHub 4b71649fcf Merge pull request #3357 from vitorpamplona/claude/fervent-darwin-r8i6dw
Add favorite toggle to web browser and embedded napplets
2026-06-25 08:45:00 -04:00
Vitor PamplonaandGitHub dda8f2d3f6 Merge pull request #3354 from vitorpamplona/claude/funny-clarke-nrzpq4
Extract MintPickerItem composable in CashuWalletScreen
2026-06-25 08:41:19 -04:00
Vitor PamplonaandGitHub 09ee225bf7 Merge pull request #3356 from davotoula/fix/note-grid-layout-issues
Fix/note grid layout issues
2026-06-25 08:38:00 -04:00
davotoula 020c08d561 Code review:
- reuse mediaSizingModifier in GifVideoView
2026-06-25 13:32:56 +02:00
Claudeanddavotoula 2ec072419a fix: keep animated media inside its gallery grid cell
Animated GIF/AVIF media in the multi-image gallery rendered with its own
intrinsic aspect ratio via fillMaxWidth(), ignoring the ContentScale.Crop
the grid asks for
2026-06-25 13:29:06 +02:00
davotoula d71c035669 fix(napplet): log failed temp-file cleanup in NappletBlobCache.put 2026-06-25 12:05:13 +02:00
David KasparandGitHub 67ffbaec86 Merge pull request #3355 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-06-25 09:21:57 +01:00
davotoulaandgithub-actions[bot] 8d036e0ac0 chore: sync Crowdin translations and seed translator npub placeholders 2026-06-25 08:12:20 +00:00
David KasparandGitHub 0f587eb918 Merge pull request #3351 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-06-25 09:09:55 +01:00
Claude 50138fe6cb feat: distinct status-bar icon for the always-on relay service
Notification small icons are rendered by the system as flat, alpha-only
silhouettes, so the always-on relay-connection service showed the exact
same solid gem as real notifications (DMs, zaps, mentions). The persistent
service therefore kept reading as a fresh notification.

Add an outlined (hollow) gem variant, `amethyst_service`, and point the
foreground service notification at it so it's clearly distinguishable at a
glance while staying on-brand.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141R1Km7YsA2miFoxLkXLQk
2026-06-25 03:27:36 +00:00
Claude 5662c89d11 fix: extract ConsoleLogRow to fix Kotlin compiler OOM in BottomConsoleSheet
The Text() calls inside the logs.forEach loop were 8 lambdas deep
(Box > Column > AnimatedVisibility > Surface > Column > Column > forEach > Row),
which caused java.lang.OutOfMemoryError in the Kotlin bytecode optimizer
(ConstantConditionEliminationMethodTransformer). This broke CI when
PR #3353 merged. Extract the Row content into a top-level ConsoleLogRow
composable to reduce nesting depth.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmiRNcMEync2rVVbrPzWt
2026-06-25 02:45:39 +00:00
Claude d33d1e36fd feat: move favorite to pull-down sheet, remove from OmniBar
Remove the star icon from the browser URL bar (OmniBar) and add a
favorite toggle row to both pull-down sheet surfaces instead:

- Compose TopControlSheet (embedded web tabs and napplets): shows
  filled/outline star with "Add to favorites" / "Remove from favorites"
  sourced from FavoriteAppsRegistry; isFavorite state flows reactively
  through EmbeddedTabChrome so the label updates without reopening.

- Native NappletControlSheet (full-screen NappletBrowserActivity): same
  toggle backed by a new MSG_TOGGLE_WEB_FAVORITE IPC message handled in
  NappletBrokerService; initial state is passed via intent so the star
  opens in the correct filled/outline state for the launch URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SBpBE7bQJ2JRni6sYG8UDo
2026-06-25 01:16:06 +00:00
Claude fe392402c3 fix: extract MintPickerItem to fix Kotlin compiler OOM in MintPicker
The deeply-nested Text() call inside DropdownMenu > forEach > DropdownMenuItem
generated bytecode with MAXSTACK=26, which caused java.lang.OutOfMemoryError in
the JVM bytecode frame analyzer (ConstantConditionEliminationMethodTransformer).
Extracting DropdownMenuItem into a top-level private composable breaks the lambda
nesting depth and lets the compiler succeed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmiRNcMEync2rVVbrPzWt
2026-06-25 01:03:29 +00:00
vitorpamplonaandgithub-actions[bot] 443bfba65c chore: sync Crowdin translations and seed translator npub placeholders 2026-06-25 00:31:29 +00:00
Vitor PamplonaandGitHub b1aef7d6ac Merge pull request #3353 from vitorpamplona/claude/serene-hypatia-48qdoz
Add JavaScript console logging to embedded and full-screen browsers
2026-06-24 20:29:33 -04:00
Vitor PamplonaandGitHub 2d1e9a9e1f Merge pull request #3352 from vitorpamplona/claude/eloquent-shannon-0fzkag
Implement tiered memory trimming with debug UI and feed size limits
2026-06-24 18:21:12 -04:00
Claude f2f80cd88d fix: stop clearing Robohash/richtext caches on every app background
TRIM_MEMORY_UI_HIDDEN fires on every app switch, not only under memory
pressure. Clearing Robohash (CPU-intensive SVG assembly) and
CachedRichTextParser to zero there forces a full rebuild on every
resume, causing visible jank.

Restructure the trim tiers to match Android's intent:

  UI_HIDDEN  (20) — just backgrounded, no pressure:
      trim Coil image cache to 1/2 only; leave parsed-text and
      avatar caches warm so resume is instant.

  BACKGROUND (40) — mild background pressure:
      trim images to 1/4, richtext→100, robohash→20, nip11→200.

  MODERATE   (60) — system is hurting:
      clear images, richtext→50, robohash→10, nip11→100.

  COMPLETE   (80) — kill imminent:
      clear everything including nip11.

Foreground levels (RUNNING_LOW/RUNNING_CRITICAL) are unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019h2c44rAwexuUEP3kky2F3
2026-06-24 22:00:52 +00:00
Claude ea2dbd9a77 fix: keep lastNotes intact on CardFeedContentState.trimToSize()
Clearing lastNotes caused the next additive update to call
refreshSuspended(), reloading the full filter limit (~500 notes) from
LocalCache and immediately undoing the trim.

With lastNotes intact the fast additive path stays active: only
genuinely new notifications are appended, so the card list remains near
maxItems until the next full feed key change or navigation event.

The Note refs in lastNotes are the same object instances already held
by LocalCache. They are freed when MemoryTrimmingService prunes
LocalCache and the following refreshSuspended() replaces lastNotes with
the pruned set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019h2c44rAwexuUEP3kky2F3
2026-06-24 21:42:14 +00:00
Claude e17c95eda1 fix: clear lastNotes on CardFeedContentState.trimToSize() to release Note refs
CardFeedContentState.lastNotes holds strong references to every raw Note
that passed the notification filter, used for additive dedup
(filteredNewList.minus(lastNotesCopy)). Trimming only the Card list left
all those Note objects pinned — they couldn't be GC'd even if LocalCache's
SoftCache had evicted them.

Fix: clear lastNotes/lastAccount alongside the Card list truncation.
The next additive update finds lastNotes == null, skips the fast path,
and calls refreshSuspended() — one controlled rebuild from LocalCache
that also resets the dedup set to the current state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019h2c44rAwexuUEP3kky2F3
2026-06-24 21:35:14 +00:00
Claude 101ca698d9 fix: polish BottomConsoleSheet UI
- Show source filename and line number as dimmed secondary text on each
  log entry (matches native NappletConsolePanel behaviour)
- Replace hardcoded #FF9800 orange with a dark-mode-aware amber pair:
  #E65100 in light mode, #FFB74D in dark mode
- Cap panel height at 40% of screen height (was fixed 240dp) so large
  phones display more log lines

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QXpdfwj2cujnEa7HPzQXj
2026-06-24 20:57:07 +00:00
Claude 57a63bd4b2 fix: stop wiping relay info cache on every app background
At UI_HIDDEN (fires on every app switch), nip11Cache.trimToSize(0)
was clearing all successfully-fetched NIP-11 relay documents, forcing
10–50 redundant HTTP fetches on the next foreground resume.

- Change UI_HIDDEN trim target from 0→100; the 100 most-recently-used
  relay docs are kept across a background/foreground cycle.
- Stop trimming relayInformationEmptyCache in Nip11CachedRetriever:
  it holds only lightweight display-name+favicon-url placeholder objects
  (no network data), so trimming saves negligible memory but silently
  re-triggers NIP-11 HTTP fetches for every relay on resume.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019h2c44rAwexuUEP3kky2F3
2026-06-24 20:44:00 +00:00
Claude 45f1fd91a3 feat: add console.log panel accessible from top pull-down control sheets
Captures JavaScript console output (log/warn/error/debug) from embedded
WebViews and surfaces it via a bottom pull-up sheet, triggered by a new
"Console (N)" row in the existing top pull-down control sheets.

Embedded browser (Compose):
- NappletBrowserService: attaches WebChromeClient to intercept console
  messages and forwards them to the client process via new MSG_CONSOLE_LOG
  IPC message in NappletBrowserContract
- EmbeddedBrowserController: implements new ConsoleBridge interface,
  stores up to 200 entries in a SnapshotStateList observable by Compose,
  handles the incoming IPC message
- TopControlSheet: adds optional consoleCount/onConsole params; shows a
  "Console (N)" row when onConsole is provided
- BottomConsoleSheet: new Compose pull-up panel anchored at the bottom,
  with level-coloured monospace log entries and a Clear button
- EmbeddedTabLayer: wires ConsoleBridge → TopControlSheet → BottomConsoleSheet

Full-screen activity browser (native Views):
- NappletBrowserActivity: attaches WebChromeClient, wires NappletConsolePanel
  and updates the control sheet count label on each new entry
- NappletControlSheet: adds optional onConsole callback and updateConsoleCount()
- NappletConsolePanel: new native-View bottom pull-up panel with scrollable
  log entries, grab-to-open gesture, and Clear button; capped at 200 entries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QXpdfwj2cujnEa7HPzQXj
2026-06-24 20:34:43 +00:00
Claude 5435345f7d feat: trim richtext, robohash, and relay-info caches under memory pressure
Add trimToSize(maxItems) to:
- CachedRichTextParser: trims richTextCache (500) and isMarkdownCache
  (200) proportionally
- CachedRobohash: trims the ImageVector LruCache (100)
- Nip11CachedRetriever: trims both the document and empty-placeholder
  caches (1000 each)

Wire all three into AppModules.trim() tiered by OS pressure level:
  RUNNING_LOW      → 50% capacity
  RUNNING_CRITICAL → 20% capacity
  UI_HIDDEN+       → evict all (app not visible, safe to clear)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019h2c44rAwexuUEP3kky2F3
2026-06-24 20:11:28 +00:00
Claude 8407684d9d feat: trim Coil memory cache and ExoPlayer warm pool under memory pressure
- ExoPlayerPool.releaseWarmPool(): evicts all paused-with-buffer (warm)
  players back to the cold pool. Safe under pressure because warm players
  are idle; active (checked-out) players are never in either pool.

- PlaybackService.onTrimMemory(): when level >= RUNNING_CRITICAL, drains
  both pool instances' warm slots via releaseWarmPool(). The Service
  receives onTrimMemory() directly from Android so no routing through
  AppModules is needed.

- AppModules.trim(): trims Coil's in-memory image cache proportional to
  OS pressure level:
    RUNNING_LOW  → trimToSize(maxSize / 2)
    RUNNING_CRITICAL → trimToSize(maxSize / 4)
    UI_HIDDEN+   → trimToSize(0)  [app backgrounded, safe to clear]

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019h2c44rAwexuUEP3kky2F3
2026-06-24 20:11:28 +00:00
Claude 5b5bc5c70c fix: raise critical memory feed trim size from 50 to 200
50 was too aggressive — users would lose most of their scroll history on
any critical-pressure event. 200 is a better balance: still releases
~60% of the 500-note strong references per feed while keeping a
reasonable amount of history visible without a reload.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 20:11:28 +00:00
Claude 057b6266d9 feat: trim feed lists to 50 items under critical memory pressure
Feed lists hold ImmutableList<Note> references. At 40+ feeds × 500 notes
each, that's 20k strong Note references that prevent GC from collecting
objects that LocalCache has already pruned. Under RUNNING_CRITICAL the
feeds are shrunk to 50 items, releasing ~19k references per account.

Implementation:
- FeedContentState.trimToSize(maxItems) — truncates the loaded list in-place
- CardFeedContentState.trimToSize(maxItems) — same for notification card feeds
- AccountFeedContentStates.trimFeedsToSize(maxItems) — fans out to all feeds
- AppModules.trimLevelEvents: SharedFlow<Int> — broadcasts the OS level
- AccountFeedContentStates subscribes and calls trimFeedsToSize(50) at
  RUNNING_CRITICAL, letting the next scroll/refresh repopulate from cache

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 20:11:27 +00:00
Claude 4eb195fa5e fix: reorder pruning tiers in MemoryTrimmingService
Tier 2 (medium, >= RUNNING_LOW): pruneHiddenEvents + pruneHiddenMessages
  — muted/blocked content is known-safe to drop at low pressure.

Tier 3 (critical, >= RUNNING_CRITICAL): pruneOldMessages + pruneRepliesAndReactions
  — these are more aggressive since they remove content the user may
  still scroll back to, so reserve them for genuine memory emergencies.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 20:11:27 +00:00
Claude 281955fb17 fix: move cleanObservers to Tier 1 in MemoryTrimmingService
cleanObservers() only removes flows not currently held by the UI, so
it carries no visible side effects and is safe to run on every trim
regardless of pressure level. Move it from Tier 3 (RUNNING_CRITICAL)
to Tier 1 (always) so unused observer links are freed even on mild
memory signals.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 20:11:27 +00:00
Claude f038e54fa2 feat: scale LocalCache pruning aggressiveness to OS memory-pressure level
MemoryTrimmingService.doTrim() previously ran the full pruning suite
regardless of how severe the OS signal was. Now it tiers the work by
ComponentCallbacks2 level so low-pressure signals don't pay the cost of
aggressive observer teardown:

  Tier 1 (always): cleanMemory + pruneExpiredEvents + prunePastVersionsOfReplaceables
  Tier 2 (>= RUNNING_LOW): + pruneOldMessages + pruneRepliesAndReactions
  Tier 3 (>= RUNNING_CRITICAL): + cleanObservers + pruneHiddenEvents/Messages

The `level` is now threaded from Amethyst.onTrimMemory → AppModules.trim(level)
→ MemoryTrimmingService.run(…, level) → doTrim(…, level). The existing
scheduled-trim call site (AppModules.trim) defaults to RUNNING_CRITICAL so
its behaviour is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 20:11:27 +00:00
Claude 21e61e48ae feat: add debug-only memory usage chip to top nav bar
Shows JVM heap used/max as a color-coded label (green/amber/red) in the
top bar actions on debug builds. Tapping opens a dialog with a full
breakdown: native heap, Coil memory/disk cache sizes, and LocalCache
counts (notes, users, addressables, chatrooms). Polls every 2 seconds
via produceState. Adds MemorySnapshot data class and
collectMemorySnapshot() to DebugUtils for reuse by future tooling.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 20:11:01 +00:00
Vitor PamplonaandGitHub 6539841e5e Merge pull request #3350 from vitorpamplona/claude/jolly-mccarthy-jyeu87
Browser: add visit history, omnibox suggestions, and favicon capture
2026-06-24 14:46:58 -04:00
Vitor PamplonaandClaude Opus 4.8 cad987a99e fix(embed): napplet/nsite load overlay + draw it over the surface
Mirrors the web-app load-recovery fix to the napplet/nsite path and fixes a
layer bug that kept the overlay from ever showing.

The embedded surface (SandboxedSdkView) is drawn by EmbeddedTabLayer, which
sits *above* the nav screens in the shell. So a loading/error overlay placed in
the favorite screen was covered by the surface's opaque pre-first-frame
background — the black void persisted. Move the overlay into EmbeddedTabLayer,
drawn over the active tab's bounds (where the chrome sheet already lives), so it
actually covers the surface. Also fixes the overlay sizing (fillMaxSize, not
matchParentSize, which collapsed to zero inside the reserved Box).

- Promote load state to the EmbeddedSurfaceController interface (loadStatus /
  onLoadStatusChanged / retry), so EmbeddedTabLayer renders one overlay for both
  the browser and napplet controllers. Shared EmbeddedLoadStatus +
  EmbeddedLoadOverlay.
- NappletHostService now reports main-frame load state (start/finish/error) over
  a new MSG_LOAD_STATE; EmbeddedNappletController relays it and exposes retry()
  (= reload the verified content).
- The web-app path keeps its about:blank → canonical-URL self-heal; the napplet
  path has no client-supplied URL to drop, so retry = reload.

Verified on device: with the network cut, the brainstorm tab shows
"Couldn't load this app." + Retry; restoring the network and tapping Retry loads
the page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 14:35:44 -04:00
Vitor PamplonaandClaude Opus 4.8 fb4a2e0858 fix(browser): recover embedded web-app tab stuck on about:blank
A favorite web app pinned to the bottom bar at runtime could come up on a
blank surface (black, then white after a manual reload) and never recover.
Its warm browser session settled on about:blank — its real URL was dropped on
the way in — and the chrome Reload button calls WebView.reload(), which just
re-loads about:blank instead of the favorite's page.

Fixes:
- The provider now reports main-frame load state (start/finish/error) over a
  new MSG_LOAD_STATE. When a favorite session settles on about:blank while it
  has a real URL, the controller re-navigates to the canonical URL once.
  Gated on a real startUrl, so the generic browser's intentional about:blank
  new-tab page is left alone. Adds controller.retry() (navigate-to-canonical,
  not reload) for the chrome retry path.
- FavoriteWebAppScreen now draws a loading spinner until a real page paints,
  and an error + Retry overlay when the main frame fails or the load stalls
  (12s) — so a slow, blank, or failed load is no longer a silent black/white
  void.

Scoped to the browser/WebUrl path; the napplet/nsite path is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 14:03:33 -04:00
Claude 2df0c4d6bb feat: favicons in bottom nav + 3-dot menu on recent rows
- Pinned web favorites in the bottom navigation now show the captured favicon
  instead of the generic globe (falling back to the globe until one is
  captured). Resolved via BrowserIconRegistry, same as the launcher cards.
- Each Recent row in the browser home gains a 3-dot overflow menu to add the
  URL to favorites (or remove it if already favorited) and to remove it from
  history. Replaces the prior long-press-to-remove with a discoverable menu;
  the row icon shows a star once the site is favorited.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017LyxWy2k3AT1LiZSvMsiDx
2026-06-24 16:04:46 +00:00
Vitor PamplonaandGitHub db99891c27 Merge pull request #3349 from vitorpamplona/claude/epic-carson-wjc0xm
Fix bottom bar fallback to use default entries instead of empty list
2026-06-24 11:43:36 -04:00
Claude 4f6a21c55d feat: favorites-first browser home + recents, with captured favicons
Builds on the omnibox work to modernize the launcher list now that favorites
and visit history both exist:

- Idle browser home (BrowserHome): pinned favorites on top under a "Favorites"
  header, then a "Recent" section from the visit history — all in one grid so
  they scroll together. Long-press a recent to drop it.
- Typed suggestions are grouped: a highlighted "Favorites" group first (subtle
  primary-container tint + medium weight), then "Recent". Favorites still rank
  first via the existing frecency boost.
- Real favicons: captured from the WebView that already loaded the page in the
  keyless :napplet browser host (so they ride the page's own Tor-routed network
  path — the main app never fetches host/favicon.ico itself), scaled and
  relayed as PNG bytes over a new MSG_RECORD_ICON IPC, and stored per-host by
  BrowserIconRegistry (main process, filesDir). Favorite cards, suggestion
  rows, and recent rows all show them, falling back to a glyph.

FavoriteAppIcon gains an optional iconModel; FavoriteAppCell is reusable via a
new LazyGridScope.favoriteAppItems extension so the browser home and the
Favorite Apps tab share one cell. Thumbnails deferred to a follow-up.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017LyxWy2k3AT1LiZSvMsiDx
2026-06-24 15:35:40 +00:00
Claude 851fb82735 fix: only reset bottom bar to defaults on parse errors, not intentional empty selection
The ifEmpty guard incorrectly reset a user-saved empty bar to defaults.
A successfully parsed empty list (user actively removed all items) is now
preserved. Only blank/unset keys and unrecognizable formats fall back to
DefaultBottomBarEntries.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 15:32:18 +00:00
Claude 4a907c750c fix: reset bottom bar to defaults when parsed config has 0 items
Blank stored strings and successfully-parsed empty JSON arrays both
left the bottom bar invisible. Now both cases fall back to
DefaultBottomBarEntries so navigation is never silently lost.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 15:14:22 +00:00
Claude 7a03a47d1d feat: omnibox autocomplete, visit history, and in-page address bar for the browser
Refines the browser URL-bar experience across the launcher and the in-page
browser chrome:

- Shared URL normalization (commons OmniboxInput): dedupes the logic that was
  copied between BrowserScreen and NappletBrowserService, recognizes bare
  domains/localhost/IPs, falls back to a (configurable) DuckDuckGo search, and
  flags .onion as Tor-only so the launcher forces Tor for it.
- Omnibox suggestions (commons OmniboxSuggestions): ranks favorites + visit
  history by prefix/substring match, favorite boost, and frecency; deduped by
  host. The launcher body turns into a suggestion list as you type.
- Inline ghost-text completion in the address field (TextFieldValue selection),
  completing a typed host fragment to the top-ranked host.
- Visit history (BrowserHistoryRegistry, main process): a device-local,
  bounded, DataStore-backed store. Pages are recorded ONLY on a clean
  main-frame load — relayed from the keyless :napplet browser host over a new
  MSG_RECORD_HISTORY IPC — so misspelled/unresolved addresses never enter it.
- In-page editable address bar (websites only) in NappletControlSheet, showing
  the live URL + a security glyph (Tor/https/plain) and loading what the user
  types. nsite/napplet hosts pass no navigate callback, so they never get one.

Pure logic is covered by unit tests in commons.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017LyxWy2k3AT1LiZSvMsiDx
2026-06-24 15:02:01 +00:00
Claude 4e6f6c104b fix: improve browser omnibar URL handling and keyboard behavior
- Disable autocorrect and autocapitalization in the URL bar so domain
  names are not mangled by the keyboard's spell-checker
- Align normalizeUrl with NappletBrowserService logic: bare domain
  names (no space, contains dot) get https:// prepended; everything
  else falls through to a DuckDuckGo search query

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017LyxWy2k3AT1LiZSvMsiDx
2026-06-24 14:25:45 +00:00
Vitor PamplonaandGitHub 048439201e Merge pull request #3347 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-06-24 10:05:25 -04:00
vitorpamplonaandgithub-actions[bot] 7b890a0eff chore: sync Crowdin translations and seed translator npub placeholders 2026-06-24 14:01:39 +00:00
Vitor PamplonaandGitHub f298750b79 Merge pull request #3348 from vitorpamplona/claude/webview-menu-custom-url-ikrgbz
Add full-screen direct-WebView browser and embedded napplet/nSite tabs
2026-06-24 09:58:59 -04:00
Claude 01ba2dc909 docs: document the final embedded-tab/browser/IME napplet architecture
This branch added a lot the existing napplet plans don't describe: embedded warm
bottom-bar tabs on a cross-process SurfaceControlViewHost, an arbitrary-URL
browser host, a soft-keyboard IME proxy, the :nappletHost module split, the
per-session service refactor, the two control-sheet twins, and per-site Tor
routing.

- Add amethyst/plans/2026-06-24-napplet-embedded-tabs.md capturing the final
  architecture and file map.
- Note on the 2026-06-19 sandbox-host plan that its rendering model is superseded
  (trust model unchanged), pointing at the new doc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgMpRcWj6y82LxLiwcuzmN
2026-06-24 13:48:41 +00:00
Claude 3460c58274 feat: show a back arrow in the Browser top bar when pushed from the drawer
The Browser is reachable both as a bottom-bar tab (top-level, no back arrow)
and from the navigation drawer (pushed onto the back stack). In the latter case
its omnibox now leads with a back arrow that pops, matching the convention the
other launcher/feed top bars already follow (NappletsTopBar et al.): show
ArrowBackIcon when nav.canPop(), nothing otherwise.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgMpRcWj6y82LxLiwcuzmN
2026-06-24 13:33:21 +00:00
Claude 8b9fa10a1b style: standardize the two top-sheet twins (spacing, colors, Tor switch)
The embedded surfaces' Compose TopControlSheet and the full-screen activities'
native NappletControlSheet are deliberate twins in different processes/modules
(Compose in the main app vs hand-built Views in the Compose-free :napplet
sandbox host), so they can't share a composable — but they should render
identically. Bring them in line:

- Uniform row rhythm: every action/Tor row now uses the same 10dp vertical
  padding in both. The Compose switch row was 6dp while items were 12dp; both
  are now 10dp, matching the native rows.
- Native Tor row now uses a real framework Switch as the state indicator (like
  the embedded row) instead of an icon whose tint/alpha encoded on/off; the icon
  is a steady muted tint and the whole row is the toggle target.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgMpRcWj6y82LxLiwcuzmN
2026-06-24 13:20:25 +00:00
Vitor PamplonaandGitHub 3fa17e1cb7 Merge pull request #3346 from greenart7c3/claude/nip-2381-bunker-connect-psiq2t
NIP-46: Add optional client metadata to connect requests
2026-06-24 08:58:28 -04:00
Claude da4207319b fix(nip46): pin client metadata to 4th connect param, backfill empties
Per NIP-46 (nostr-protocol/nips#2381), client metadata is the 4th
positional connect param. When it is present but the optional secret or
permissions are not, those slots are now back-filled with empty strings
so the metadata always lands at index 3. Parsing maps empty placeholders
back to null. When no metadata is sent, the array stays as short as
possible for backward compatibility.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYpupiVAq4VyHDdjrYyPdi
2026-06-24 12:08:06 +00:00