Commit Graph

12665 Commits

Author SHA1 Message Date
Vitor Pamplona 8f843be41b Merge pull request #2679 from vitorpamplona/claude/audio-transmission-tests-zKzlB
Claude/audio transmission tests z kzl b
2026-04-30 22:31:07 -04:00
Claude a97f494735 Reproduce per-frame send-outcome trace against the local moq-relay
Mirror NostrnestsProdAudioTransmissionTest.sustained_per_frame_send_outcomes_two_users
but drive the local Docker-backed kixelated/moq reference relay via
NostrNestsHarness. Lets us reproduce the production "82/100" cliff
without nostrnests.com so we can attribute the loss to client code
(`:nestsClient` / `:quic`) vs. the production deployment.

Same per-frame instrumentation: bypass NestMoqLiteBroadcaster, call
publisher.send() / publisher.endGroup() directly, record the boolean
return per frame plus any endGroup exception, dump a per-frame
send/recv table on failure.
2026-05-01 02:17:48 +00:00
Claude d143053796 Add per-frame send-outcome trace to isolate moq-lite vs downstream loss
Test 4 showed a hard 82/100 cliff at 20 ms cadence two-users, all 18
trailing groups lost permanently. Root-cause-narrowing requires knowing
whether MoqLitePublisherHandle.send returned false (frame dropped at the
moq-lite layer due to inboundSubs.isEmpty() / publisherClosed) or true
(frame queued by moq-lite and lost downstream — uni-stream write error
swallowed by runCatching, QUIC flow control wedged, or relay drop).

The production NestMoqLiteBroadcaster wraps everything in
runCatching {…}.onFailure {…} and ignores the boolean, so frame loss is
structurally invisible to the app. This new test bypasses the broadcaster
and calls publisher.send / publisher.endGroup directly while mirroring
the auth + transport + session setup that connectNestsSpeaker performs.

Records sendOutcomes[i] and endGroupErrors[i] per frame; on failure
prints a per-frame send/recv table so we can see exactly when send
flips false (or whether all 100 sends report true and the loss is
strictly downstream of moq-lite).
2026-05-01 02:13:27 +00:00
Vitor Pamplona 02f5a31c9f Merge pull request #2678 from vitorpamplona/claude/audio-transmission-tests-zKzlB
Sustained-cadence test: dump partial arrivals + gap pattern
2026-04-30 22:06:37 -04:00
Claude 7e3d622399 Sustained-cadence test: dump partial arrivals + gap pattern
Previously test 4 used .take(N).toList() inside withTimeoutOrNull, so a
timeout discarded every received frame and the only failure signal was
"only got partial audio". When the production run flagged frame loss,
we couldn't tell whether the stream stalled mid-flight, never started
fanning out, or dropped scattered groups.

Drain into an external CopyOnWriteArrayList via .onEach { } so the
partial contents survive the timeout, then on failure surface:
  - received N/100 with first/last arrival timestamps
  - missingGroups summary as run-length ranges (e.g. [3-7,42,90-99])
  - first/last 20 arrivals so the front and tail of the sequence are
    visible without flooding stdout

The gap pattern alone narrows the diagnosis: front-loaded losses point
to subscribe-settle being too short, tail-loaded losses point to a
broadcaster shutdown race, scattered drops point to per-subscription
buffer overflow / datagram loss.
2026-05-01 02:05:40 +00:00
Vitor Pamplona 68b19633d2 Merge pull request #2677 from vitorpamplona/claude/audio-transmission-tests-zKzlB
Add prod nostrnests.com audio transmission diagnostic tests
2026-04-30 22:01:15 -04:00
Vitor Pamplona 5ec25c6013 Merge pull request #2676 from vitorpamplona/claude/fix-chat-scroll-behavior-Ig1YE
Auto-scroll to newest messages in chat when new messages arrive
2026-04-30 21:17:40 -04:00
Claude 9f1b32f40d Add prod nostrnests.com audio transmission diagnostic tests
Four progressively-narrower JVM tests that drive the production
connectNestsSpeaker / connectNestsListener / OkHttpNestsClient /
QuicWebTransportFactory / NestMoqLiteBroadcaster code paths against
the real moq.nostrnests.com + moq-auth.nostrnests.com infrastructure
(no Docker harness, no Nostr events) so we can isolate why audio is
not flowing between two real users:

  1. auth_minting_works_for_publish_and_listen_paths
  2. same_user_speaker_and_listener_round_trip
  3. two_users_speaker_publishes_listener_subscribes
  4. sustained_real_time_cadence_two_users (~2s @ 20ms cadence)

Skipped by default; opt in with -DnestsProd=true and (optionally)
override URLs via -DnestsProdEndpoint=... / -DnestsProdAuth=...
2026-05-01 01:08:14 +00:00
Claude f6f2559d31 Auto-scroll nest chat to newest message when at bottom
Both NestFullScreen and NestLobbyScreen render the kind-1311
transcript with LazyColumn(reverseLayout = true). When a new message
is prepended, LazyColumn preserves visual position by shifting
firstVisibleItemIndex from 0 to 1, leaving the new message just below
the viewport — the user has to scroll down to see it.

If the user is at (or one item from) the bottom when a new message
arrives, scroll back to item 0 so the newest message is visible. If
they are reading older history, leave them where they are.
2026-04-30 23:59:25 +00:00
Vitor Pamplona 6ee15ee6ec Planned rooms should go to the lobby 2026-04-30 19:44:24 -04:00
Vitor Pamplona 9ff9a4b4e2 Better align the scheduled flag 2026-04-30 19:41:20 -04:00
Vitor Pamplona bad3cfa8f6 Makes sure relays stay connected in the room activity 2026-04-30 19:33:52 -04:00
Vitor Pamplona 55ec5b910b Merge branch 'main' of https://github.com/vitorpamplona/amethyst 2026-04-30 19:22:05 -04:00
Vitor Pamplona cc194273a3 Passing the Note, not the event to the Nest viewmodel 2026-04-30 19:20:53 -04:00
David Kaspar abe1043c8e Merge pull request #2668 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-05-01 01:12:42 +02:00
Vitor Pamplona 2fe585096f Fixes after merge 2026-04-30 19:06:27 -04:00
Vitor Pamplona 5c78b0dfcd Merge 2026-04-30 19:05:44 -04:00
Crowdin Bot cbc2a5943a New Crowdin translations by GitHub Action 2026-04-30 23:02:38 +00:00
Vitor Pamplona 39344afe81 Merge pull request #2675 from vitorpamplona/claude/prevent-lock-nest-screen-GKcSS
Keep screen on during active nest room connections
2026-04-30 19:00:56 -04:00
Vitor Pamplona 83913f743d Merge pull request #2674 from vitorpamplona/claude/fix-nestfeedcard-lobby-vvoVP
Gate Nest room launches by liveness status
2026-04-30 19:00:36 -04:00
Claude 4715ae6b66 Keeps the screen on while connected to a Nest room
Holds FLAG_KEEP_SCREEN_ON via the existing KeepScreenOn composable
while ConnectionUiState is Connected, so the device doesn't lock
and interrupt an active audio-room session.
2026-04-30 22:28:33 +00:00
Claude 897e036b3a fix(nests): only gate room re-entry through lobby when card reads closed
NestFeedCard previously routed every tap on a joinable MeetingSpaceEvent
through NestLobbyScreen. The lobby exists to keep an accidental tap on
a stale room from booting the audio pipeline (and the host-side
kind-30312 republish path) — once the badge says the room is live with
fresh presence, that gating is just extra friction. Mirror the badge's
liveness heuristic in the click handler and launch NestActivity
directly for cards rendering as LIVE / PLANNED / PRIVATE; only EndedFlag
cards (status = ENDED, status = LIVE with stale presence, or unknown
status) keep flowing through the read-only lobby.
2026-04-30 22:25:39 +00:00
Vitor Pamplona 3dceb194dc Removes the disappearing bar from the TwoPane messages 2026-04-30 17:59:28 -04:00
Vitor Pamplona fa8892b6a4 Merge pull request #2673 from vitorpamplona/claude/fix-chatroom-list-reuse-Wkz10
Fix double padding in two-pane chat layout
2026-04-30 17:46:45 -04:00
Vitor Pamplona 4c4a28dbe9 Removing unnecessary label 2026-04-30 17:42:44 -04:00
Vitor Pamplona 4003b735dd Adds an isNewThread to the TextNote 2026-04-30 17:40:16 -04:00
Vitor Pamplona 2f9c6bddeb simplifying the readme 2026-04-30 17:37:29 -04:00
Claude 089261420c refactor(chats): apply scaffold padding to two-pane left pane
Move the workaround out of ChatroomList: use the DisappearingScaffold's
padding lambda parameter (previously unused) to position the left pane
below the top bar and above the bottom bar. Reset
LocalDisappearingScaffoldPadding to zero only at that boundary so the
inner LazyColumn inside ChatroomListFeedView doesn't double-count the
bar inset and produce a gap below the TabRow.

The right pane keeps systemBarsPadding because ChatroomView /
PublicChatChannelView bring their own DisappearingScaffold; layering the
outer padding there would stack the chat header below the outer search
bar.

ChatroomList stays a flat Column with no scaffold awareness.
2026-04-30 21:32:10 +00:00
Vitor Pamplona 479f14cbd4 additional info 2026-04-30 17:28:20 -04:00
Vitor Pamplona acb36adfa3 Merge branch 'main' of https://github.com/vitorpamplona/amethyst
# Conflicts:
#	quartz/README.md
2026-04-30 17:26:28 -04:00
Vitor Pamplona 43dc925b74 Updates readme to look more like a guide 2026-04-30 17:22:58 -04:00
Claude 2db8dc99a8 fix(chats): drop scaffold top inset for inner feed in two-pane
In MessagesSinglePane the MessagesTabHeader sits inside the
DisappearingScaffold's topBar slot, so LocalDisappearingScaffoldPadding's
top component already covers the bar + tabs and the inner LazyColumn's
contentPadding lines the first row up flush below the tabs.

In MessagesTwoPane the tabs are part of the column content rather than
the scaffold's top slot. The scaffold still publishes its top-app-bar
height as the top inset, so rememberFeedContentPadding inside the feed
double-counts it and renders a top-app-bar-tall gap between the TabRow
and the first chatroom row.

Override LocalDisappearingScaffoldPadding around MessagesPager to zero
the top component while preserving start/end/bottom, so the feed still
clears the bottom bar.
2026-04-30 21:15:54 +00:00
Vitor Pamplona 4c9ccbadbd Merge pull request #2672 from vitorpamplona/claude/quartz-docs-update
Refactor relay integration docs: EventCollector pattern and lifecycle management
2026-04-30 16:57:10 -04:00
Vitor Pamplona 6aa24c5ef2 Merge pull request #2671 from vitorpamplona/claude/fix-nestlobby-layout-ofVC0
Refactor NestLobbyScreen layout: move header outside LazyColumn
2026-04-30 16:56:35 -04:00
Claude 61bed279fc fix: lift NestLobby header out of the chat LazyColumn
The room metadata (RoomHeader) and live listener count were items
inside the reverse-layout LazyColumn, so they scrolled with the chat
and forced the chat to share its viewport. Move them to a regular
Column above the LazyColumn so the chat list owns most of the screen
and the header sits as a fixed row on top.

Drop the redundant "Recent chat" label that was only there to
separate the in-list header from messages.
2026-04-30 20:50:53 +00:00
Claude c4a38bb899 docs(quartz): align tutorials with the layered patterns demoApp uses
The README's "Wiring relays into the store" tutorial used a
per-subscription SubscriptionListener.onEvent callback to feed the
store. EventCollector landed exactly to remove that boilerplate, so
update the example to register one connection-level collector at app
init and stop wiring listeners per subscribe() call.

The "Building a reactive feed UI" example showed project() ->
stateIn(WhileSubscribed) but never opened the relay subscription.
Bind it to the projection's collection lifecycle with .onStart {
client.subscribe } / .onCompletion { client.unsubscribe }, so the
relay subscription's lifetime equals the UI collector's. Also
demonstrate ProjectionState.filterItems for narrowing without a
re-query.

Drop the redundant client.connect() call from the wiring example
and add an explicit note (in both README and CLIENT) that
NostrClient connects on demand from subscribe()/publish() — connect()
is only useful after disconnect().

Other small fixes:
  - client.send(...) -> client.publish(...) (the actual API name).
  - Rename the variable from `observable` to `db` to match the demoApp
    code and the conceptual "this is the local database" framing.
  - Wrap the publish path in a viewModelScope.launch so the snippet
    is copy-pasteable into a ViewModel.
2026-04-30 20:50:00 +00:00
Vitor Pamplona 276b25a448 Removes the stop broadcast button, user must leave the stage to stop 2026-04-30 16:38:47 -04:00
Vitor Pamplona 2a0ea98df2 Merge pull request #2670 from vitorpamplona/claude/update-nestlobby-chat-layout-JimqW
Claude/update nestlobby chat layout jimq w
2026-04-30 16:22:38 -04:00
Claude 8f4474c8a7 fix(nests): make Open lobby action a prominent filled button
A TextButton in the AppBar actions slot read as too subtle and small
next to the title. Switch to a filled Button so the primary CTA is
unmistakable. The actions Row already centers children vertically;
trim the trailing modifier padding so the button sits flush with
the bar's edge.
2026-04-30 20:13:28 +00:00
Claude 8f7c0eac47 refactor(nests): lobby chat reuses NestFullScreen list shape
Replace the static Column-based CachedChatList with the same
LazyColumn(reverseLayout = true) the in-room screen uses
(NestChatPanel.NestChatMessageList). Items are keyed by note id,
and the room metadata header / listener count / "Recent chat"
label are stacked above the oldest message so the user can scroll
up through history into the room info.

Wire onSendNewMessage to animateScrollToItem(0) so a freshly sent
message snaps the list back to the newest entry — same behaviour
the in-room composer has.
2026-04-30 20:12:45 +00:00
Vitor Pamplona c249765c51 Merge pull request #2669 from vitorpamplona/claude/update-nestlobby-chat-layout-JimqW
Add chat composer to nest lobby screen
2026-04-30 16:04:02 -04:00
Vitor Pamplona 12ed2af028 Moves java.util.SortedSet to an arrayList. 2026-04-30 15:57:26 -04:00
Claude 02d34ed74f feat: active chat composer on NestLobby with Open action in top bar
- Replace bottom Open Room button with a TextButton "Open" action in
  the top app bar, freeing the screen bottom for the chat composer.
- Mount NestEditFieldRow + NestNewMessageViewModel on the lobby so
  users can post kind-1311 messages without joining the audio plane;
  in-room composer features (mentions, file upload, drafts, emojis)
  carry over.
- Switch the Scaffold to contentWindowInsets=0 and use imePadding +
  navigation-bar inset on the composer so the chat list draws behind
  the 3-button system navigation while the composer stays reachable
  above it (and rises above the IME when the keyboard opens).
- Drop the now-unused OpenNestRoomButton helper and its string.
2026-04-30 19:53:41 +00:00
Vitor Pamplona 728a396ff2 Merge pull request #2667 from vitorpamplona/claude/fix-mute-button-height-6Vfip
Refactor NestActionBar UI layout and state handling
2026-04-30 15:24:13 -04:00
Claude 951f6c37f0 refactor(nests): extract action bar affordances and refresh KDoc
NestActionBar.kt had grown to ~470 lines with most of the volume in
OnStageControls, where four broadcast-state branches each inlined a
56dp filled icon button, a tonal toggle button, and an outlined
"Leave the Stage" button. The result was hard to scan for state
coverage, and the top-level KDoc still described the pre-cleanup
layout.

Changes:

* Rewrote the top-level KDoc as a state-by-state table matching the
  current UI.
* Extracted reusable affordances:
  ConnectButton, StatusChip, LeaveStageButton, TalkButton,
  StopBroadcastButton, MicMuteToggle, HandRaiseToggle,
  LeaveRoomButton.
* Merged the duplicate Connect button branches in StartCluster
  (Idle / Closed / Failed all share one). The failure reason already
  appears in the status strip above.
* Split OnStageControls: kept the dispatcher thin and moved the
  permission state + Settings deep-link into OnStageIdleControls,
  which is the only state that needs them.
* Replaced the inline qualified Settings Intent with a
  Context.openAppSettings() helper, plus a Context.hasMicPermission()
  helper for the two RECORD_AUDIO checks.
* Pulled the status-strip text resolution into a small
  NestUiState.statusStripText() so ActionBarStatusStrip is one Text.

No behavior changes — just structure, naming, and docs.
2026-04-30 19:22:52 +00:00
Claude 7be8ac5106 fix(nests): drop redundant Live chip while broadcasting
The red Mic-on FilledIconButton already conveys "you are live, tap
to stop" — the AssistChip labelled "Live" beside it was duplicate
visual noise. Removed the chip and its now-orphan string. Mute toggle
+ red Mic + Leave the Stage are sufficient to express the broadcasting
state.
2026-04-30 19:14:17 +00:00
Claude 640e7904e4 fix(nests): tighten action bar state coverage
Several gaps in the action bar were causing dead-end UI states or
making non-actionable controls visible:

* Hand-raise was rendered while disconnected / connecting / failed.
  Raising can't be delivered to the room until we're Connected, so
  hide it until the connection state agrees. Threaded `isConnected`
  into `EndCluster` from the root composable.
* Audience listen-mute toggle (Volume Up/Off) removed. System volume
  keys cover local volume; the on-screen control was redundant and
  shared the same speaker glyph as the broadcasting mic-mute toggle,
  which made the two affordances easy to confuse.
* On-stage user without `canBroadcast` had no way to step down without
  leaving the whole room. Show a "Leave the Stage" outlined button
  in that branch so the speaker slot can be released.
* Broadcast `Connecting` and `Failed` substates also had no
  step-down affordance — forcing the user to either retry the mic or
  leave the room. Added "Leave the Stage" to both. `stopBroadcast()`
  cancels the in-flight `speakerConnectJob` (NestViewModel
  `teardownBroadcast`), so cancelling mid-handshake is safe.
* `BroadcastUiState.Broadcasting.muteError` was tracked in state but
  never surfaced. Route it through `ActionBarStatusStrip`.
* Permission denial pill said "Open settings"; renamed to
  "No permissions" so the label communicates the *state* (the tap
  still deep-links to the system settings page).
2026-04-30 19:02:25 +00:00
Vitor Pamplona 48523c2903 Merge pull request #2666 from vitorpamplona/claude/fix-nest-room-status-3Mmq9
Add NestLobbyScreen for read-only room preview before joining
2026-04-30 14:04:35 -04:00
Vitor Pamplona 2b4064df96 Merge pull request #2665 from vitorpamplona/claude/tor-connection-fallback-uJM2E
Add Tor connection timeout with graceful fallback to regular connection
2026-04-30 14:03:10 -04:00
Claude b86219b1e1 fix(nests): match mute toggle height with action bar buttons
Material3 expressive defaults the FilledTonalIconToggleButton container
shorter than ButtonDefaults.MinHeight, leaving the audience listen-mute
and on-stage mic-mute toggles visibly shorter than the neighboring
"Leave the Stage" / "Leave" outlined buttons. Pin the toggle height to
ButtonDefaults.MinHeight so the row aligns.
2026-04-30 17:57:45 +00:00