Skip to content

Commit 596c3ab

Browse files
committed
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.
1 parent db66700 commit 596c3ab

File tree

2 files changed

+92
-61
lines changed

2 files changed

+92
-61
lines changed

src/room/InCallView.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export function InCallView({
126126

127127
const containerRef1 = useRef<HTMLDivElement | null>(null);
128128
const [containerRef2, bounds] = useMeasure({ polyfill: ResizeObserver });
129+
const boundsValid = bounds.height > 0
129130
// Merge the refs so they can attach to the same element
130131
const containerRef = useCallback(
131132
(el: HTMLDivElement) => {
@@ -238,15 +239,15 @@ export function InCallView({
238239
const maximisedParticipant = useMemo(
239240
() =>
240241
fullscreenParticipant ??
241-
(bounds.height <= 400 && bounds.width <= 400
242+
(boundsValid && bounds.height <= 400 && bounds.width <= 400
242243
? items.find((item) => item.focused) ??
243244
items.find((item) => item.callFeed) ??
244245
null
245246
: null),
246-
[fullscreenParticipant, bounds, items]
247+
[fullscreenParticipant, boundsValid, bounds, items]
247248
);
248249

249-
const reducedControls = bounds.width <= 400;
250+
const reducedControls = boundsValid && bounds.width <= 400;
250251

251252
const renderAvatar = useCallback(
252253
(roomMember: RoomMember, width: number, height: number) => {

src/video-grid/VideoGrid.tsx

Lines changed: 88 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -859,73 +859,103 @@ export function VideoGrid({
859859
});
860860
}, [items, gridBounds, layout, isMounted, pipXRatio, pipYRatio]);
861861

862+
const tilePositionsValid = useRef(false);
863+
862864
const animate = useCallback(
863-
(tiles: Tile[]) => (tileIndex: number) => {
864-
const tile = tiles[tileIndex];
865-
const tilePosition = tilePositions[tile.order];
866-
const draggingTile = draggingTileRef.current;
867-
const dragging = draggingTile && tile.key === draggingTile.key;
868-
const remove = tile.remove;
869-
870-
if (dragging) {
871-
return {
872-
width: tilePosition.width,
873-
height: tilePosition.height,
874-
x: draggingTile.offsetX + draggingTile.x,
875-
y: draggingTile.offsetY + draggingTile.y,
876-
scale: 1.1,
877-
opacity: 1,
878-
zIndex: 2,
879-
shadow: 15,
880-
immediate: (key: string) =>
881-
disableAnimations ||
882-
key === "zIndex" ||
883-
key === "x" ||
884-
key === "y" ||
885-
key === "shadow",
886-
from: {
887-
shadow: 0,
888-
scale: 0,
889-
opacity: 0,
890-
},
891-
reset: false,
892-
};
893-
} else {
894-
const isMobile = isMobileBreakpoint(
895-
gridBounds.width,
896-
gridBounds.height
897-
);
865+
(tiles: Tile[]) => {
866+
// Whether the tile positions were valid at the time of the previous
867+
// animation
868+
const tilePositionsWereValid = tilePositionsValid.current;
898869

899-
return {
900-
x:
870+
return (tileIndex: number) => {
871+
const tile = tiles[tileIndex];
872+
const tilePosition = tilePositions[tile.order];
873+
const draggingTile = draggingTileRef.current;
874+
const dragging = draggingTile && tile.key === draggingTile.key;
875+
const remove = tile.remove;
876+
tilePositionsValid.current = tilePosition.height > 0;
877+
878+
if (dragging) {
879+
return {
880+
width: tilePosition.width,
881+
height: tilePosition.height,
882+
x: draggingTile.offsetX + draggingTile.x,
883+
y: draggingTile.offsetY + draggingTile.y,
884+
scale: 1.1,
885+
opacity: 1,
886+
zIndex: 2,
887+
shadow: 15,
888+
immediate: (key: string) =>
889+
disableAnimations ||
890+
key === "zIndex" ||
891+
key === "x" ||
892+
key === "y" ||
893+
key === "shadow",
894+
from: {
895+
shadow: 0,
896+
scale: 0,
897+
opacity: 0,
898+
},
899+
reset: false,
900+
};
901+
} else {
902+
const isMobile = isMobileBreakpoint(
903+
gridBounds.width,
904+
gridBounds.height
905+
);
906+
907+
const x =
901908
tilePosition.x +
902909
(layout === "spotlight" && tile.order !== 0 && isMobile
903910
? scrollPosition
904-
: 0),
905-
y:
911+
: 0);
912+
const y =
906913
tilePosition.y +
907914
(layout === "spotlight" && tile.order !== 0 && !isMobile
908915
? scrollPosition
909-
: 0),
910-
width: tilePosition.width,
911-
height: tilePosition.height,
912-
scale: remove ? 0 : 1,
913-
opacity: remove ? 0 : 1,
914-
zIndex: tilePosition.zIndex,
915-
shadow: 1,
916-
from: {
916+
: 0);
917+
const from: {
918+
shadow: number;
919+
scale: number;
920+
opacity: number;
921+
x?: number;
922+
y?: number;
923+
width?: number;
924+
height?: number;
925+
} = { shadow: 1, scale: 0, opacity: 0 };
926+
let reset = false;
927+
928+
if (!tilePositionsWereValid) {
929+
// This indicates that the component just mounted. We discard the
930+
// previous keyframe by resetting the tile's position, so that it
931+
// animates in from the right place on screen, rather than wherever
932+
// the zero-height grid placed it.
933+
from.x = x;
934+
from.y = y;
935+
from.width = tilePosition.width;
936+
from.height = tilePosition.height;
937+
reset = true;
938+
}
939+
940+
return {
941+
x,
942+
y,
943+
width: tilePosition.width,
944+
height: tilePosition.height,
945+
scale: remove ? 0 : 1,
946+
opacity: remove ? 0 : 1,
947+
zIndex: tilePosition.zIndex,
917948
shadow: 1,
918-
scale: 0,
919-
opacity: 0,
920-
},
921-
reset: false,
922-
immediate: (key: string) =>
923-
disableAnimations || key === "zIndex" || key === "shadow",
924-
// If we just stopped dragging a tile, give it time for its animation
925-
// to settle before pushing its z-index back down
926-
delay: (key: string) => (key === "zIndex" ? 500 : 0),
927-
};
928-
}
949+
from,
950+
reset,
951+
immediate: (key: string) =>
952+
disableAnimations || key === "zIndex" || key === "shadow",
953+
// If we just stopped dragging a tile, give it time for the
954+
// animation to settle before pushing its z-index back down
955+
delay: (key: string) => (key === "zIndex" ? 500 : 0),
956+
};
957+
}
958+
};
929959
},
930960
[tilePositions, disableAnimations, scrollPosition, layout, gridBounds]
931961
);

0 commit comments

Comments
 (0)