diff --git a/src/tile/SpotlightTile.tsx b/src/tile/SpotlightTile.tsx index 77a3526f..fccc5235 100644 --- a/src/tile/SpotlightTile.tsx +++ b/src/tile/SpotlightTile.tsx @@ -16,6 +16,7 @@ limitations under the License. import { ComponentProps, + RefAttributes, forwardRef, useCallback, useEffect, @@ -28,17 +29,20 @@ import CollapseIcon from "@vector-im/compound-design-tokens/icons/collapse.svg?r import ChevronLeftIcon from "@vector-im/compound-design-tokens/icons/chevron-left.svg?react"; import ChevronRightIcon from "@vector-im/compound-design-tokens/icons/chevron-right.svg?react"; import { animated } from "@react-spring/web"; -import { Observable, map, of } from "rxjs"; +import { Observable, map } from "rxjs"; import { useObservableEagerState } from "observable-hooks"; import { useTranslation } from "react-i18next"; import classNames from "classnames"; +import { TrackReferenceOrPlaceholder } from "@livekit/components-core"; +import { RoomMember } from "matrix-js-sdk"; import { MediaView } from "./MediaView"; import styles from "./SpotlightTile.module.css"; import { LocalUserMediaViewModel, MediaViewModel, - RemoteUserMediaViewModel, + ScreenShareViewModel, + UserMediaViewModel, useNameData, } from "../state/MediaViewModel"; import { useInitial } from "../useInitial"; @@ -47,12 +51,63 @@ import { useObservableRef } from "../state/useObservable"; import { useReactiveState } from "../useReactiveState"; import { useLatest } from "../useLatest"; -// Screen share video is always enabled -const videoEnabledDefault = of(true); -// Never mirror screen share video -const mirrorDefault = of(false); -// Never crop screen share video -const cropVideoDefault = of(false); +interface SpotlightItemBaseProps { + className?: string; + "data-id": string; + targetWidth: number; + targetHeight: number; + video: TrackReferenceOrPlaceholder; + member: RoomMember | undefined; + unencryptedWarning: boolean; + nameTag: string; + displayName: string; +} + +interface SpotlightUserMediaItemBaseProps extends SpotlightItemBaseProps { + videoEnabled: boolean; + videoFit: "contain" | "cover"; +} + +interface SpotlightLocalUserMediaItemProps + extends SpotlightUserMediaItemBaseProps { + vm: LocalUserMediaViewModel; +} + +const SpotlightLocalUserMediaItem = forwardRef< + HTMLDivElement, + SpotlightLocalUserMediaItemProps +>(({ vm, ...props }, ref) => { + const mirror = useObservableEagerState(vm.mirror); + return ; +}); + +SpotlightLocalUserMediaItem.displayName = "SpotlightLocalUserMediaItem"; + +interface SpotlightUserMediaItemProps extends SpotlightItemBaseProps { + vm: UserMediaViewModel; +} + +const SpotlightUserMediaItem = forwardRef< + HTMLDivElement, + SpotlightUserMediaItemProps +>(({ vm, ...props }, ref) => { + const videoEnabled = useObservableEagerState(vm.videoEnabled); + const cropVideo = useObservableEagerState(vm.cropVideo); + + const baseProps: SpotlightUserMediaItemBaseProps = { + videoEnabled, + videoFit: cropVideo ? "cover" : "contain", + ...props, + }; + + return vm instanceof LocalUserMediaViewModel ? ( + + ) : ( + + ); +}); + +SpotlightUserMediaItem.displayName = "SpotlightUserMediaItem"; interface SpotlightItemProps { vm: MediaViewModel; @@ -71,21 +126,6 @@ const SpotlightItem = forwardRef( const ref = useMergedRefs(ourRef, theirRef); const { displayName, nameTag } = useNameData(vm); const video = useObservableEagerState(vm.video); - const videoEnabled = useObservableEagerState( - vm instanceof LocalUserMediaViewModel || - vm instanceof RemoteUserMediaViewModel - ? vm.videoEnabled - : videoEnabledDefault, - ); - const mirror = useObservableEagerState( - vm instanceof LocalUserMediaViewModel ? vm.mirror : mirrorDefault, - ); - const cropVideo = useObservableEagerState( - vm instanceof LocalUserMediaViewModel || - vm instanceof RemoteUserMediaViewModel - ? vm.cropVideo - : cropVideoDefault, - ); const unencryptedWarning = useObservableEagerState(vm.unencryptedWarning); // Hook this item up to the intersection observer @@ -103,22 +143,28 @@ const SpotlightItem = forwardRef( }; }, [intersectionObserver]); - return ( + const baseProps: SpotlightItemBaseProps & RefAttributes = { + ref, + "data-id": vm.id, + className: classNames(styles.item, { [styles.snap]: snap }), + targetWidth, + targetHeight, + video, + member: vm.member, + unencryptedWarning, + nameTag, + displayName, + }; + + return vm instanceof ScreenShareViewModel ? ( + ) : ( + ); }, );