Merge branch 'livekit' into valere/auto_fit_based_on_video_ratio
This commit is contained in:
@@ -20,6 +20,10 @@ import {
|
||||
CollapseIcon,
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
VolumeOffIcon,
|
||||
VolumeOnIcon,
|
||||
VolumeOffSolidIcon,
|
||||
VolumeOnSolidIcon,
|
||||
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import { animated } from "@react-spring/web";
|
||||
import { type Observable, map } from "rxjs";
|
||||
@@ -27,6 +31,7 @@ import { useObservableRef } from "observable-hooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import classNames from "classnames";
|
||||
import { type TrackReferenceOrPlaceholder } from "@livekit/components-core";
|
||||
import { Menu, MenuItem } from "@vector-im/compound-web";
|
||||
|
||||
import FullScreenMaximiseIcon from "../icons/FullScreenMaximise.svg?react";
|
||||
import FullScreenMinimiseIcon from "../icons/FullScreenMinimise.svg?react";
|
||||
@@ -45,6 +50,8 @@ import { type UserMediaViewModel } from "../state/media/UserMediaViewModel";
|
||||
import { type ScreenShareViewModel } from "../state/media/ScreenShareViewModel";
|
||||
import { type RemoteScreenShareViewModel } from "../state/media/RemoteScreenShareViewModel";
|
||||
import { type MediaViewModel } from "../state/media/MediaViewModel";
|
||||
import { Slider } from "../Slider";
|
||||
import { platform } from "../Platform";
|
||||
|
||||
interface SpotlightItemBaseProps {
|
||||
ref?: Ref<HTMLDivElement>;
|
||||
@@ -240,6 +247,73 @@ const SpotlightItem: FC<SpotlightItemProps> = ({
|
||||
|
||||
SpotlightItem.displayName = "SpotlightItem";
|
||||
|
||||
interface ScreenShareVolumeButtonProps {
|
||||
vm: RemoteScreenShareViewModel;
|
||||
}
|
||||
|
||||
const ScreenShareVolumeButton: FC<ScreenShareVolumeButtonProps> = ({ vm }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const audioEnabled = useBehavior(vm.audioEnabled$);
|
||||
const playbackMuted = useBehavior(vm.playbackMuted$);
|
||||
const playbackVolume = useBehavior(vm.playbackVolume$);
|
||||
|
||||
const VolumeIcon = playbackMuted ? VolumeOffIcon : VolumeOnIcon;
|
||||
const VolumeSolidIcon = playbackMuted
|
||||
? VolumeOffSolidIcon
|
||||
: VolumeOnSolidIcon;
|
||||
|
||||
const [volumeMenuOpen, setVolumeMenuOpen] = useState(false);
|
||||
const onMuteButtonClick = useCallback(() => vm.togglePlaybackMuted(), [vm]);
|
||||
const onVolumeChange = useCallback(
|
||||
(v: number) => vm.adjustPlaybackVolume(v),
|
||||
[vm],
|
||||
);
|
||||
const onVolumeCommit = useCallback(() => vm.commitPlaybackVolume(), [vm]);
|
||||
|
||||
return (
|
||||
audioEnabled && (
|
||||
<Menu
|
||||
open={volumeMenuOpen}
|
||||
onOpenChange={setVolumeMenuOpen}
|
||||
title={t("video_tile.screen_share_volume")}
|
||||
side="top"
|
||||
align="end"
|
||||
trigger={
|
||||
<button
|
||||
className={styles.expand}
|
||||
aria-label={t("video_tile.screen_share_volume")}
|
||||
>
|
||||
<VolumeSolidIcon aria-hidden width={20} height={20} />
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<MenuItem
|
||||
as="div"
|
||||
className={styles.volumeMenuItem}
|
||||
onSelect={null}
|
||||
label={null}
|
||||
hideChevron={true}
|
||||
>
|
||||
<button className={styles.menuMuteButton} onClick={onMuteButtonClick}>
|
||||
<VolumeIcon aria-hidden width={24} height={24} />
|
||||
</button>
|
||||
<Slider
|
||||
className={styles.volumeSlider}
|
||||
label={t("video_tile.volume")}
|
||||
value={playbackVolume}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
onValueChange={onVolumeChange}
|
||||
onValueCommit={onVolumeCommit}
|
||||
/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
interface Props {
|
||||
ref?: Ref<HTMLDivElement>;
|
||||
vm: SpotlightTileViewModel;
|
||||
@@ -274,6 +348,7 @@ export const SpotlightTile: FC<Props> = ({
|
||||
const latestMedia = useLatest(media);
|
||||
const latestVisibleId = useLatest(visibleId);
|
||||
const visibleIndex = media.findIndex((vm) => vm.id === visibleId);
|
||||
const visibleMedia = media.at(visibleIndex);
|
||||
const canGoBack = visibleIndex > 0;
|
||||
const canGoToNext = visibleIndex !== -1 && visibleIndex < media.length - 1;
|
||||
|
||||
@@ -381,16 +456,21 @@ export const SpotlightTile: FC<Props> = ({
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className={styles.bottomRightButtons}>
|
||||
<button
|
||||
className={classNames(styles.expand)}
|
||||
aria-label={"maximise"}
|
||||
onClick={onToggleFullscreen}
|
||||
tabIndex={focusable ? undefined : -1}
|
||||
>
|
||||
<FullScreenIcon aria-hidden width={20} height={20} />
|
||||
</button>
|
||||
|
||||
<div className={styles.bottomRightButtons}>
|
||||
{visibleMedia?.type === "screen share" && !visibleMedia.local && (
|
||||
<ScreenShareVolumeButton vm={visibleMedia} />
|
||||
)}
|
||||
{platform === "desktop" && (
|
||||
<button
|
||||
className={classNames(styles.expand)}
|
||||
aria-label={"maximise"}
|
||||
onClick={onToggleFullscreen}
|
||||
tabIndex={focusable ? undefined : -1}
|
||||
>
|
||||
<FullScreenIcon aria-hidden width={20} height={20} />
|
||||
</button>
|
||||
)}
|
||||
{onToggleExpanded && (
|
||||
<button
|
||||
className={classNames(styles.expand)}
|
||||
|
||||
Reference in New Issue
Block a user