From 7c5336fc40f832632cf058a56b7a42ca2833c03b Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 12 Jun 2025 19:15:43 -0400 Subject: [PATCH] Remove the switch camera button --- src/button/Button.tsx | 18 ------- src/room/InCallView.module.css | 1 - src/room/InCallView.tsx | 12 ----- src/room/LobbyView.tsx | 14 +---- src/room/useSwitchCamera.ts | 93 ---------------------------------- src/state/CallViewModel.ts | 14 ----- 6 files changed, 1 insertion(+), 151 deletions(-) delete mode 100644 src/room/useSwitchCamera.ts diff --git a/src/button/Button.tsx b/src/button/Button.tsx index 4caa9c4f..c11c92dd 100644 --- a/src/button/Button.tsx +++ b/src/button/Button.tsx @@ -16,7 +16,6 @@ import { EndCallIcon, ShareScreenSolidIcon, SettingsSolidIcon, - SwitchCameraSolidIcon, } from "@vector-im/compound-design-tokens/assets/web/icons"; import styles from "./Button.module.css"; @@ -67,23 +66,6 @@ export const VideoButton: FC = ({ muted, ...props }) => { ); }; -export const SwitchCameraButton: FC> = ( - props, -) => { - const { t } = useTranslation(); - - return ( - - - - ); -}; - interface ShareScreenButtonProps extends ComponentPropsWithoutRef<"button"> { enabled: boolean; } diff --git a/src/room/InCallView.module.css b/src/room/InCallView.module.css index 24dfbe5c..41d48db1 100644 --- a/src/room/InCallView.module.css +++ b/src/room/InCallView.module.css @@ -115,7 +115,6 @@ Please see LICENSE in the repository root for full details. @media (max-width: 340px) { .invite, - .switchCamera, .shareScreen { display: none; } diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index 452e8572..53fc0667 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -44,7 +44,6 @@ import { ShareScreenButton, SettingsButton, ReactionToggleButton, - SwitchCameraButton, } from "../button"; import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header"; import { type HeaderStyle, useUrlParams } from "../UrlParams"; @@ -94,7 +93,6 @@ import { useReactionsSender, } from "../reactions/useReactionsSender"; import { ReactionsAudioRenderer } from "./ReactionAudioRenderer"; -import { useSwitchCamera } from "./useSwitchCamera"; import { ReactionsOverlay } from "./ReactionsOverlay"; import { CallEventAudioRenderer } from "./CallEventAudioRenderer"; import { @@ -311,7 +309,6 @@ export const InCallView: FC = ({ const showFooter = useObservableEagerState(vm.showFooter$); const earpieceMode = useObservableEagerState(vm.earpieceMode$); const audioOutputSwitcher = useObservableEagerState(vm.audioOutputSwitcher$); - const switchCamera = useSwitchCamera(vm.localVideo$); // Ideally we could detect taps by listening for click events and checking // that the pointerType of the event is "touch", but this isn't yet supported @@ -672,15 +669,6 @@ export const InCallView: FC = ({ data-testid="incall_videomute" />, ); - if (switchCamera !== null) - buttons.push( - , - ); if (canScreenshare && !hideScreensharing) { buttons.push( = ({ }, [devices, videoInputId, videoTrack]); useTrackProcessorSync(videoTrack); - const showSwitchCamera = useShowSwitchCamera( - useObservable( - (inputs$) => inputs$.pipe(map(([video]) => video)), - [videoTrack], - ), - ); // TODO: Unify this component with InCallView, so we can get slick joining // animations and don't have to feel bad about reusing its CSS @@ -257,9 +248,6 @@ export const LobbyView: FC = ({ onClick={onVideoPress} disabled={muteStates.video.setEnabled === null} /> - {showSwitchCamera && ( - - )} {!confineToRoom && } diff --git a/src/room/useSwitchCamera.ts b/src/room/useSwitchCamera.ts deleted file mode 100644 index 975776ae..00000000 --- a/src/room/useSwitchCamera.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. - -SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -Please see LICENSE in the repository root for full details. -*/ - -import { - fromEvent, - map, - merge, - type Observable, - of, - startWith, - switchMap, -} from "rxjs"; -import { - facingModeFromLocalTrack, - type LocalVideoTrack, - TrackEvent, -} from "livekit-client"; -import { useObservable, useObservableEagerState } from "observable-hooks"; -import { logger } from "matrix-js-sdk/lib/logger"; - -import { useMediaDevices } from "../MediaDevicesContext"; -import { platform } from "../Platform"; -import { useLatest } from "../useLatest"; - -/** - * Determines whether the user should be shown a button to switch their camera, - * producing a callback if so. - */ -export function useSwitchCamera( - video$: Observable, -): (() => void) | null { - const mediaDevices = useMediaDevices(); - const setVideoInput = useLatest(mediaDevices.videoInput.select); - - // Produce an observable like the input 'video' observable, except make it - // emit whenever the track is muted or the device changes - const videoTrack$: Observable = useObservable( - (inputs$) => - inputs$.pipe( - switchMap(([video$]) => video$), - switchMap((video) => { - if (video === null) return of(null); - return merge( - fromEvent(video, TrackEvent.Restarted).pipe( - startWith(null), - map(() => video), - ), - fromEvent(video, TrackEvent.Muted).pipe(map(() => null)), - ); - }), - ), - [video$], - ); - - const switchCamera$: Observable<(() => void) | null> = useObservable( - (inputs$) => - platform === "desktop" - ? of(null) - : inputs$.pipe( - switchMap(([track$]) => track$), - map((track) => { - if (track === null) return null; - const facingMode = facingModeFromLocalTrack(track).facingMode; - // If the camera isn't front or back-facing, don't provide a switch - // camera shortcut at all - if (facingMode !== "user" && facingMode !== "environment") - return null; - // Restart the track with a camera facing the opposite direction - return (): void => - void track - .restartTrack({ - facingMode: facingMode === "user" ? "environment" : "user", - }) - .then(() => { - // Inform the MediaDeviceContext which camera was chosen - const deviceId = - track.mediaStreamTrack.getSettings().deviceId; - if (deviceId !== undefined) setVideoInput.current(deviceId); - }) - .catch((e) => - logger.error("Failed to switch camera", facingMode, e), - ); - }), - ), - [videoTrack$], - ); - - return useObservableEagerState(switchCamera$); -} diff --git a/src/state/CallViewModel.ts b/src/state/CallViewModel.ts index fc1222c4..ae7b78c1 100644 --- a/src/state/CallViewModel.ts +++ b/src/state/CallViewModel.ts @@ -13,10 +13,8 @@ import { import { type Room as LivekitRoom, type LocalParticipant, - LocalVideoTrack, ParticipantEvent, type RemoteParticipant, - Track, } from "livekit-client"; import { RoomStateEvent, type Room, type RoomMember } from "matrix-js-sdk"; import { @@ -60,7 +58,6 @@ import { import { LocalUserMediaViewModel, type MediaViewModel, - observeTrackReference$, RemoteUserMediaViewModel, ScreenShareViewModel, type UserMediaViewModel, @@ -382,17 +379,6 @@ function getRoomMemberFromRtcMember( // TODO: Move wayyyy more business logic from the call and lobby views into here export class CallViewModel extends ViewModel { - public readonly localVideo$: Observable = - observeTrackReference$( - of(this.livekitRoom.localParticipant), - Track.Source.Camera, - ).pipe( - map((trackRef) => { - const track = trackRef?.publication?.track; - return track instanceof LocalVideoTrack ? track : null; - }), - ); - /** * The raw list of RemoteParticipants as reported by LiveKit */