Skip to content

VIDSOL-619: Mirror Self View Toggle#414

Closed
czoli1976 wants to merge 13 commits intodevelopfrom
czoli1976/VIDSOL-619-mirror-self-view-toggle
Closed

VIDSOL-619: Mirror Self View Toggle#414
czoli1976 wants to merge 13 commits intodevelopfrom
czoli1976/VIDSOL-619-mirror-self-view-toggle

Conversation

@czoli1976
Copy link
Copy Markdown
Contributor

Hi team! 👋

Resolves VIDSOL-619

Checklist

  • Branch is based on develop (not main).
  • Resolves a Known Issue.
  • If yes, did you remove the item from the docs/KNOWN_ISSUES.md?
  • Resolves an item reported in Issues.

What is this PR doing?

Adds a Mirror Self View toggle so users can choose whether their preview is mirrored. Default is ON (mirrored) and
persisted in localStorage.

Where it appears:

  • Waiting room: flip icon button on the self-view tile
  • Meeting room: toggle item in the camera device dropdown

Mirror behavior:

  • mirrorSelfView = true: use the SDK’s .OT_mirrored CSS when present; if the SDK isn’t mirroring, fall back to
    scaleX(-1) inline.
  • mirrorSelfView = false: force scaleX(1) to cancel any mirroring (SDK or inline).

Styling refactor:

  • Mirror controls and device menu now use Tailwind with Vera tokens (no MUI sx).

Manual test notes remain the same; ensure toggles update immediately and persist on refresh across browsers.

Mirror logic:

mirrorSelfView Transform applied
true (default) none — the SDK's .OT_mirrored class handles the flip
false scaleX(-1) — cancels the SDK mirror

Changes:

  • storage.ts — Added MIRROR_SELF_VIEW key
  • user.tsx — Added mirrorSelfView: boolean to UserContext / UserProvider, loaded from localStorage
  • MirrorSelfViewButton.tsx (new) — Waiting room icon button
  • MirrorSelfViewToggle.tsx (new) — Conference room toggle menu item
  • VideoContainer.tsx — Replaced static Tailwind child:-scale-x-100 with reactive useEffect; added MirrorSelfViewButton
  • Publisher.tsx — Dynamic transform via useEffect; objectFit: cover
  • BackgroundVideoContainer.tsx — Dynamic transform + objectFit: cover
  • en.json, es.json, es-MX.json, it.json — Added devices.video.mirrorSelfView i18n key
  • user.spec.tsx, BackgroundVideoContainer.spec.tsx, DeviceSettingsMenu.spec.tsx — Updated tests

How should this be manually tested?

Waiting room:

  1. Open the app and enter the waiting room
  2. Locate the flip icon button in the upper-right corner of the self-view video tile
  3. Click it — your self-view should switch from mirrored to un-mirrored (and back)
  4. Refresh the page and verify the last setting is remembered

Conference room:

  1. Join a call and click the camera device dropdown (chevron next to the camera button)
  2. Verify "Mirror Self View" toggle is visible at the bottom of the dropdown
  3. Click it — your publisher video should update immediately
  4. Verify the toggle is visible in Safari and Firefox (not gated by video effects support)

Tested on macOS Tahoe 26.3 (arm64):

Browser Waiting room toggle Conference room toggle Persistence
Chrome 145
Safari 26.3
Firefox 148.0 ✅ (camera list empty — pre-existing bug, see comments)

Instructions for Testing

Setup:

  • Use Node
    22.
  • Backend .env set (provider + keys) so sessions start.

Waiting room:

  1. Load waiting room.
  2. Click mirror button (top-right of self-view).
    - ON → video mirrored. OFF → unmirrored.
  3. Refresh: last setting persists.
  4. Ensure button hover/focus uses Vera tokens (no default MUI colors).

Meeting room:

  1. Join a call, open camera device dropdown.
  2. Toggle “Mirror Self View”.
    - ON → mirrored; OFF → unmirrored.
  3. Switch the toggle multiple times; video updates immediately.
  4. Verify dropdown styling matches Tailwind/Vera tokens.

Fallback:

  • If SDK doesn’t apply .OT_mirrored, ON still mirrors via scaleX(-1); OFF forces scaleX(1).

Cross-browser:

  • Chrome, Safari, Firefox: confirm toggle visibility and behavior; Safari/Firefox should show the dropdown item.

Persistence:

  • Toggle in meeting room, rejoin or reload; setting remains.

Regression:

  • Background effects preview respects mirror toggle.
  • Publisher/preview still object-fit cover (no letterboxing).

♻️ Replaces #390 (reopened from upstream branch to enable VCR deploy)

czoli1976 and others added 8 commits March 17, 2026 16:09
Adds a user-toggleable mirror (horizontal flip) for the self-view video.
Previously, the self-view was always mirrored via scaleX(-1). Now users
can toggle mirroring on/off, and the preference persists in localStorage.

The toggle is available in two places:
- Waiting Room: a badge-style Flip icon button in the upper-right corner
  of the video tile (aligned with the Background Effects badge)
- Conference Room: a toggle menu item in the camera device dropdown,
  always visible on all browsers (not gated by media processor support),
  following the same pattern as Advanced Noise Suppression in the audio menu

Key design decisions:
- Default: mirrored (true) — preserves existing behaviour
- Inverted transform logic: SDK mirrors via .OT_mirrored; when mirror is
  ON we set transform:none, when OFF we apply scaleX(-1) to cancel it
- objectFit changed from contain to cover across all three video components
- Preference stored as localStorage key mirrorSelfView
- i18n keys added for en, es, es-MX, it locales
- Fixed pre-existing no-floating-promises lint error in useSuspenseUntilAppConfigReady

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add mirrorSelfView: true to user.spec.tsx expected defaultSettings
- Add UserProvider wrapper to BackgroundVideoContainer.spec.tsx (component now uses useUserContext)
- Update DeviceSettingsMenu.spec.tsx: add providers.user and userContext to RenderOptions, use queryAllByTestId for dropdown-separator (two separators now rendered)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove providers.appConfig (does not exist in current codebase)
- Use providers.user only for MirrorSelfViewToggle context
- Restore env.partialUpdate for ALLOW_BACKGROUND_EFFECTS test
- Remove appConfigContext from RenderOptions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ainer

- Replace transform:'none' with removeProperty/'' so SDK's .OT_mirrored
  CSS (scale(-1,1) on .OT_video-element) is not inadvertently overridden
  when mirror is ON
- Use scaleX(1) when mirror is OFF to correctly cancel SDK's scale(-1,1)
- Remove unused isSMViewport hook and dep from BackgroundVideoContainer effect

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…line

The react-hooks/immutability rule fires on direct property assignments
(`element.style.transform = 'scaleX(1)'`) but not on method calls
(`removeProperty`) or ternary assignments. The disable comments were
placed on the wrong lines — moved to sit immediately above the
assignment that actually triggers the rule, and removed the now-unused
disable in BackgroundVideoContainer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@czoli1976
Copy link
Copy Markdown
Contributor Author

vcr:deploy

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a user-controlled “Mirror Self View” preference (default ON) persisted in localStorage, and wires it into waiting-room preview + in-call publisher rendering, along with UI controls in both rooms.

Changes:

  • Add MIRROR_SELF_VIEW storage key and new mirrorSelfView default setting in UserContext.
  • Introduce waiting-room icon button and meeting-room device-menu toggle to update/persist mirroring.
  • Apply mirror/object-fit behavior to preview publisher, in-call publisher, and background-effects preview; refactor parts of the device menu styling to Tailwind/Vera tokens.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
frontend/src/utils/storage.ts Adds MIRROR_SELF_VIEW key for persistence.
frontend/src/Context/user.tsx Loads mirrorSelfView from storage (default true) into UserContext.
frontend/src/Context/tests/user.spec.tsx Updates expected defaults to include mirrorSelfView.
frontend/src/Context/PublisherProvider/usePublisherQuality/usePublisherQuality.spec.tsx Updates mocked UserContextType with mirrorSelfView.
frontend/src/components/WaitingRoom/VideoContainerButton/VideoContainerButton.tsx Adds className support and moves sizing/padding toward Tailwind utilities.
frontend/src/components/WaitingRoom/VideoContainer/VideoContainer.tsx Applies object-fit: cover and conditional mirroring to the waiting-room preview; adds the mirror button to the tile.
frontend/src/components/WaitingRoom/MirrorSelfViewButton/index.tsx Exposes the new waiting-room mirror toggle button.
frontend/src/components/WaitingRoom/MirrorSelfViewButton/MirrorSelfViewButton.tsx New waiting-room mirror toggle UI + persistence via UserContext and storage.
frontend/src/components/Publisher/Publisher.tsx Applies object-fit: cover and conditional mirroring to the in-call publisher video element.
frontend/src/components/BackgroundEffects/BackgroundVideoContainer/BackgroundVideoContainer.tsx Applies conditional mirroring + object-fit: cover for background-effects preview.
frontend/src/components/BackgroundEffects/BackgroundVideoContainer/BackgroundVideoContainer.spec.tsx Wraps tests with UserProvider to satisfy new UserContext dependency.
frontend/src/components/MeetingRoom/MirrorSelfViewToggle/MirrorSelfViewToggle.tsx New menu-item toggle for mirroring in the camera device dropdown.
frontend/src/components/MeetingRoom/DeviceSettingsMenu/DeviceSettingsMenu.tsx Adds the mirror toggle to the video menu and refactors Popper/Paper styling to Tailwind classes.
frontend/src/components/MeetingRoom/DeviceSettingsMenu/DeviceSettingsMenu.spec.tsx Updates test expectations and ensures UserContext is provided.
frontend/src/locales/en.json Adds devices.video.mirrorSelfView string.
frontend/src/locales/de.json Adds devices.video.mirrorSelfView string.
frontend/src/locales/es.json Adds devices.video.mirrorSelfView string.
frontend/src/locales/es-MX.json Adds devices.video.mirrorSelfView string.
frontend/src/locales/it.json Adds devices.video.mirrorSelfView string.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +57 to +70
const isSdkMirroring = publisherVideoElement.classList.contains('OT_mirrored');
// The SDK mirrors the preview publisher via .OT_mirrored (scale(-1, 1) on .OT_video-element).
// When mirror is ON, prefer the SDK class; fall back to an inline mirror if the class is absent.
// When mirror is OFF, set scaleX(1) to override and cancel the SDK's mirror.
if (mirrorSelfView) {
if (isSdkMirroring) {
publisherVideoElement.style.removeProperty('transform');
} else {
// eslint-disable-next-line react-hooks/immutability
publisherVideoElement.style.transform = 'scaleX(-1)';
}
} else {
publisherVideoElement.style.transform = 'scaleX(1)';
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

@czoli1976
Copy link
Copy Markdown
Contributor Author

vcr:deploy

@github-actions
Copy link
Copy Markdown
Contributor

✅ Deployed to VCR

URL: https://neru-ca37991c-vonage-video-react-app-vera-pr-414.euw1.runtime.vonage.cloud

Commit: 635d622c33dd849542ff87aadfbe5df0c32c999d

View build logs

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@Vonage Vonage deleted a comment from github-actions bot Mar 18, 2026
czoli1976 and others added 4 commits March 18, 2026 15:19
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown

Copilot AI commented Mar 18, 2026

@czoli1976 I've opened a new pull request, #415, to work on those changes. Once the pull request is ready, I'll request review from you.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
78.2% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@czoli1976
Copy link
Copy Markdown
Contributor Author

@VZaphod I am dropping it, lack of consensus

@czoli1976 czoli1976 closed this Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants