mirror of
https://github.com/vector-im/element-call.git
synced 2024-11-15 00:04:59 +08:00
Improve the visual experience of joining a call
Because useMeasure always returns a width and height of zero on the first render, various call UI elements would flash in and out of existence or animate in from the wrong place when joining a call. This poses an accessibility issue, and is generally unpleasant.
This commit is contained in:
parent
db66700595
commit
2d5f413a1f
@ -126,6 +126,7 @@ export function InCallView({
|
||||
|
||||
const containerRef1 = useRef<HTMLDivElement | null>(null);
|
||||
const [containerRef2, bounds] = useMeasure({ polyfill: ResizeObserver });
|
||||
const boundsValid = bounds.height > 0;
|
||||
// Merge the refs so they can attach to the same element
|
||||
const containerRef = useCallback(
|
||||
(el: HTMLDivElement) => {
|
||||
@ -238,15 +239,15 @@ export function InCallView({
|
||||
const maximisedParticipant = useMemo(
|
||||
() =>
|
||||
fullscreenParticipant ??
|
||||
(bounds.height <= 400 && bounds.width <= 400
|
||||
(boundsValid && bounds.height <= 400 && bounds.width <= 400
|
||||
? items.find((item) => item.focused) ??
|
||||
items.find((item) => item.callFeed) ??
|
||||
null
|
||||
: null),
|
||||
[fullscreenParticipant, bounds, items]
|
||||
[fullscreenParticipant, boundsValid, bounds, items]
|
||||
);
|
||||
|
||||
const reducedControls = bounds.width <= 400;
|
||||
const reducedControls = boundsValid && bounds.width <= 400;
|
||||
|
||||
const renderAvatar = useCallback(
|
||||
(roomMember: RoomMember, width: number, height: number) => {
|
||||
|
@ -859,73 +859,103 @@ export function VideoGrid({
|
||||
});
|
||||
}, [items, gridBounds, layout, isMounted, pipXRatio, pipYRatio]);
|
||||
|
||||
const tilePositionsValid = useRef(false);
|
||||
|
||||
const animate = useCallback(
|
||||
(tiles: Tile[]) => (tileIndex: number) => {
|
||||
const tile = tiles[tileIndex];
|
||||
const tilePosition = tilePositions[tile.order];
|
||||
const draggingTile = draggingTileRef.current;
|
||||
const dragging = draggingTile && tile.key === draggingTile.key;
|
||||
const remove = tile.remove;
|
||||
(tiles: Tile[]) => {
|
||||
// Whether the tile positions were valid at the time of the previous
|
||||
// animation
|
||||
const tilePositionsWereValid = tilePositionsValid.current;
|
||||
|
||||
if (dragging) {
|
||||
return {
|
||||
width: tilePosition.width,
|
||||
height: tilePosition.height,
|
||||
x: draggingTile.offsetX + draggingTile.x,
|
||||
y: draggingTile.offsetY + draggingTile.y,
|
||||
scale: 1.1,
|
||||
opacity: 1,
|
||||
zIndex: 2,
|
||||
shadow: 15,
|
||||
immediate: (key: string) =>
|
||||
disableAnimations ||
|
||||
key === "zIndex" ||
|
||||
key === "x" ||
|
||||
key === "y" ||
|
||||
key === "shadow",
|
||||
from: {
|
||||
shadow: 0,
|
||||
scale: 0,
|
||||
opacity: 0,
|
||||
},
|
||||
reset: false,
|
||||
};
|
||||
} else {
|
||||
const isMobile = isMobileBreakpoint(
|
||||
gridBounds.width,
|
||||
gridBounds.height
|
||||
);
|
||||
return (tileIndex: number) => {
|
||||
const tile = tiles[tileIndex];
|
||||
const tilePosition = tilePositions[tile.order];
|
||||
const draggingTile = draggingTileRef.current;
|
||||
const dragging = draggingTile && tile.key === draggingTile.key;
|
||||
const remove = tile.remove;
|
||||
tilePositionsValid.current = tilePosition.height > 0;
|
||||
|
||||
return {
|
||||
x:
|
||||
if (dragging) {
|
||||
return {
|
||||
width: tilePosition.width,
|
||||
height: tilePosition.height,
|
||||
x: draggingTile.offsetX + draggingTile.x,
|
||||
y: draggingTile.offsetY + draggingTile.y,
|
||||
scale: 1.1,
|
||||
opacity: 1,
|
||||
zIndex: 2,
|
||||
shadow: 15,
|
||||
immediate: (key: string) =>
|
||||
disableAnimations ||
|
||||
key === "zIndex" ||
|
||||
key === "x" ||
|
||||
key === "y" ||
|
||||
key === "shadow",
|
||||
from: {
|
||||
shadow: 0,
|
||||
scale: 0,
|
||||
opacity: 0,
|
||||
},
|
||||
reset: false,
|
||||
};
|
||||
} else {
|
||||
const isMobile = isMobileBreakpoint(
|
||||
gridBounds.width,
|
||||
gridBounds.height
|
||||
);
|
||||
|
||||
const x =
|
||||
tilePosition.x +
|
||||
(layout === "spotlight" && tile.order !== 0 && isMobile
|
||||
? scrollPosition
|
||||
: 0),
|
||||
y:
|
||||
: 0);
|
||||
const y =
|
||||
tilePosition.y +
|
||||
(layout === "spotlight" && tile.order !== 0 && !isMobile
|
||||
? scrollPosition
|
||||
: 0),
|
||||
width: tilePosition.width,
|
||||
height: tilePosition.height,
|
||||
scale: remove ? 0 : 1,
|
||||
opacity: remove ? 0 : 1,
|
||||
zIndex: tilePosition.zIndex,
|
||||
shadow: 1,
|
||||
from: {
|
||||
: 0);
|
||||
const from: {
|
||||
shadow: number;
|
||||
scale: number;
|
||||
opacity: number;
|
||||
x?: number;
|
||||
y?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
} = { shadow: 1, scale: 0, opacity: 0 };
|
||||
let reset = false;
|
||||
|
||||
if (!tilePositionsWereValid) {
|
||||
// This indicates that the component just mounted. We discard the
|
||||
// previous keyframe by resetting the tile's position, so that it
|
||||
// animates in from the right place on screen, rather than wherever
|
||||
// the zero-height grid placed it.
|
||||
from.x = x;
|
||||
from.y = y;
|
||||
from.width = tilePosition.width;
|
||||
from.height = tilePosition.height;
|
||||
reset = true;
|
||||
}
|
||||
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
width: tilePosition.width,
|
||||
height: tilePosition.height,
|
||||
scale: remove ? 0 : 1,
|
||||
opacity: remove ? 0 : 1,
|
||||
zIndex: tilePosition.zIndex,
|
||||
shadow: 1,
|
||||
scale: 0,
|
||||
opacity: 0,
|
||||
},
|
||||
reset: false,
|
||||
immediate: (key: string) =>
|
||||
disableAnimations || key === "zIndex" || key === "shadow",
|
||||
// If we just stopped dragging a tile, give it time for its animation
|
||||
// to settle before pushing its z-index back down
|
||||
delay: (key: string) => (key === "zIndex" ? 500 : 0),
|
||||
};
|
||||
}
|
||||
from,
|
||||
reset,
|
||||
immediate: (key: string) =>
|
||||
disableAnimations || key === "zIndex" || key === "shadow",
|
||||
// If we just stopped dragging a tile, give it time for the
|
||||
// animation to settle before pushing its z-index back down
|
||||
delay: (key: string) => (key === "zIndex" ? 500 : 0),
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
[tilePositions, disableAnimations, scrollPosition, layout, gridBounds]
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user