mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-22 22:29:30 +00:00
Size the device list to the call as it changes
- The bound was taken once when the menu opened, so a host resizing the space Element Call is drawn in while the menu is open left it describing a call area that no longer exists. - Follow it with observeElementSize$, which was already here and already used by useRootSizeMatches, and only while the menu is open. - Quantised before it reaches React, so a drag-resize re-renders only when the bound itself moves. - 160 and 0.6 are named now, with the reason each exists.
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
|||||||
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { distinctUntilChanged, map } from "rxjs";
|
||||||
|
|
||||||
import styles from "./MediaMuteAndSwitchButton.module.css";
|
import styles from "./MediaMuteAndSwitchButton.module.css";
|
||||||
import { MicButton, VideoButton } from "../button";
|
import { MicButton, VideoButton } from "../button";
|
||||||
@@ -37,6 +38,7 @@ import {
|
|||||||
} from "../state/MediaDevices";
|
} from "../state/MediaDevices";
|
||||||
import { useMediaDevices } from "../MediaDevicesContext";
|
import { useMediaDevices } from "../MediaDevicesContext";
|
||||||
import { useRootElement } from "../RootElementContext";
|
import { useRootElement } from "../RootElementContext";
|
||||||
|
import { observeElementSize$ } from "../utils/elementSize";
|
||||||
import { MicrophoneLevelMeter } from "./MicrophoneLevelMeter";
|
import { MicrophoneLevelMeter } from "./MicrophoneLevelMeter";
|
||||||
import { useMicrophoneLevel } from "./useMicrophoneLevel";
|
import { useMicrophoneLevel } from "./useMicrophoneLevel";
|
||||||
|
|
||||||
@@ -93,6 +95,23 @@ const BLUR_ID = "blur";
|
|||||||
*/
|
*/
|
||||||
const DEFAULT_OUTPUT_ID = "default";
|
const DEFAULT_OUTPUT_ID = "default";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The share of the call area the device list may fill.
|
||||||
|
*
|
||||||
|
* The menu carries its headings and the level meter as well, and a list that
|
||||||
|
* took the whole call would hide the call it belongs to.
|
||||||
|
*/
|
||||||
|
const LIST_SHARE_OF_CALL = 0.6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The shortest the device list may be, whatever the call measures.
|
||||||
|
*
|
||||||
|
* A share alone collapses in a small call to a list that shows one device and
|
||||||
|
* gives no sign that there are others. Scrolling a short list is the better
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
const MIN_LIST_HEIGHT = 160;
|
||||||
|
|
||||||
export const MediaMuteAndSwitchButton: FC<MediaMuteAndSwitchButtonProps> = ({
|
export const MediaMuteAndSwitchButton: FC<MediaMuteAndSwitchButtonProps> = ({
|
||||||
title,
|
title,
|
||||||
enabled,
|
enabled,
|
||||||
@@ -153,11 +172,25 @@ export const MediaMuteAndSwitchButton: FC<MediaMuteAndSwitchButtonProps> = ({
|
|||||||
if (menuOpen) setFocusModality("pointer");
|
if (menuOpen) setFocusModality("pointer");
|
||||||
}, [menuOpen]);
|
}, [menuOpen]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (menuOpen)
|
if (!menuOpen) return;
|
||||||
setListMaxHeight(
|
// Followed rather than measured once: a host can resize the space Element
|
||||||
Math.max(160, Math.round(rootElement.clientHeight * 0.6)),
|
// Call is drawn in while the menu is open — a panel animating, a window
|
||||||
);
|
// dragged, a phone turned — and a bound taken on opening then describes a
|
||||||
|
// call area that no longer exists. Quantised before it reaches React, so a
|
||||||
|
// resize re-renders only when the bound itself moves.
|
||||||
|
const subscription = observeElementSize$(rootElement)
|
||||||
|
.pipe(
|
||||||
|
map(({ height }) =>
|
||||||
|
Math.max(MIN_LIST_HEIGHT, Math.round(height * LIST_SHARE_OF_CALL)),
|
||||||
|
),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
)
|
||||||
|
.subscribe(setListMaxHeight);
|
||||||
|
return (): void => subscription.unsubscribe();
|
||||||
}, [menuOpen, rootElement]);
|
}, [menuOpen, rootElement]);
|
||||||
|
|
||||||
|
// Only while the menu is open, so nothing holds a second capture of the
|
||||||
|
// microphone for the length of a call.
|
||||||
const microphoneState = useMicrophoneLevel(
|
const microphoneState = useMicrophoneLevel(
|
||||||
selectedOption,
|
selectedOption,
|
||||||
menuOpen && iconsAndLabels === "audio",
|
menuOpen && iconsAndLabels === "audio",
|
||||||
|
|||||||
Reference in New Issue
Block a user