fix(call): fullscreen video layout — auto-fit, centre last row, self-view toggle, camera + screenshare coexist#609
fix(call): fullscreen video layout — auto-fit, centre last row, self-view toggle, camera + screenshare coexist#609HexaField wants to merge 1 commit into
Conversation
…view toggle, camera + screenshare coexist
Four related issues with the in-call video grid landed in one PR because
each one was a slice of the same per-participant layout pipeline:
1. **Tiles overflowed in fullscreen.** The grid used
`grid-auto-rows: min-content` and capped each tile via `max-height:
100%`, but `100%` of an overflowing parent is itself the overflowing
height, so the trailing rows scrolled off-screen. Added a
`fullscreen` class on `.video-grid` that switches to
`grid-template-rows: repeat(var(--number-of-rows), 1fr)` with
`overflow: hidden` and per-tile `align/justify-self: center`, so every
tile fits the available space while preserving the 16/9 aspect
ratio.
2. **Odd-numbered trailing rows were left-aligned.** Added a computed
`lastRowTiles` count and emit a `grid-column-start: <offset+1>` style
on the first tile of an incomplete trailing row. Subsequent tiles
flow naturally; no per-row wrapper or `:has(...)` selector required.
3. **Self-view couldn't be hidden.** Added `selfViewVisible` /
`toggleSelfViewVisible` on the UI store (persisted across sessions)
and a desktop-only "Hide my video / Show my video" button in
`MainCallControls.vue`. When off, the local camera tile is dropped
from `allParticipants` — the user remains in the call and is still
heard, the local screenshare tile (when present) is still shown so
the user can verify what they're broadcasting.
4. **Screenshare overrode the user's camera tile on both sides of the
call.** Three connected changes:
- `mediaDevicesStore.turnOnScreenShare` no longer removes the camera
track from `stream`. The screenshare is captured into its own
`screenShareStream` ref and sent to peers via a new
`webrtcStore.addScreenShareTrack` (a `peer.addTrack(track,
dedicatedStream)` instead of a `replaceTrack` swap), so the
receiving side fires a fresh `peer.on('track')` event with a
distinct stream id.
- `webrtcStore.ts` peer.on('track') handler used to wipe the per-peer
`streams` array on every new stream (`streams = [stream]`), which
silently dropped the camera tile the moment a screenshare track
arrived. Now appends a new stream entry and updates in place when
extra tracks land on an existing stream. Tracks that end clear
their stream from the array.
- `useVideoLayout.allParticipants` splits both the local user and
each remote peer into separate camera-tile / screenshare-tile
entries (`streamKind: 'camera' | 'screenshare'`). Remote
screenshares are identified as streams with video tracks but no
audio tracks — the camera stream always carries the mic track.
- Cleaned up the old `savedVideoTrack` swap-back bookkeeping in
`toggleVideo` / `resetMediaDevices` — superfluous now that camera
and screenshare run on independent streams.
Composite `did:streamKind` participant keys replace bare DIDs in
`focusOnVideo` / focused-layout, so the focus model handles the
camera-vs-screenshare split too. Bare DIDs from older persisted state
still match (first tile for that user, which is the camera tile).
✅ Deploy Preview for fluxsocial-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Warning Review limit reached
More reviews will be available in 46 minutes and 1 second. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Four related issues with the in-call video grid landed in one PR because each one was a slice of the same per-participant layout pipeline.
1. Tiles overflowed in fullscreen
The grid used
grid-auto-rows: min-contentand capped each tile viamax-height: 100%, but100%of an overflowing parent is the overflowing height itself, so trailing rows scrolled off-screen. Added a `fullscreen` class that switches the grid to `grid-template-rows: repeat(var(--number-of-rows), 1fr)` with `overflow: hidden` and per-tile `align/justify-self: center`. Every tile now fits on screen while preserving 16/9.2. Odd-numbered trailing rows left-aligned
Computed `lastRowTiles` from `allParticipants.length % numberOfColumns` and emit `grid-column-start: <offset+1>` on the first tile of an incomplete trailing row. Subsequent tiles flow naturally — no per-row wrapper required.
3. Self-view couldn't be hidden
Added `selfViewVisible` / `toggleSelfViewVisible` on the UI store and a desktop-only "Hide my video / Show my video" button in `MainCallControls.vue`. When off, the local camera tile is dropped from `allParticipants`. The user remains in the call and is still heard; the local screenshare tile (when present) is still shown so they can verify what they're broadcasting.
4. Screenshare overrode the user's camera tile
Three connected changes let camera + screenshare run side-by-side for the same user on both sides of the call:
Composite `did:streamKind` participant keys replace bare DIDs in `focusOnVideo` / focused-layout. Bare DIDs from older persisted state still match (first tile for that user, which is the camera tile).
Test plan