Enhance SessionUsersPanel with responsive screen size tracking and dynamic grid column calculations for camera display. Update ControlsPopover to generate session-specific share links. Clean up SessionPage layout by removing unnecessary background styling.
This commit is contained in:
@@ -33,11 +33,59 @@ function SessionUsersPanel({
|
||||
const lastSentSpeakingRef = useRef<boolean>(false);
|
||||
const speakingStateTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// State для отслеживания размеров и ориентации экрана
|
||||
const [windowDimensions, setWindowDimensions] = useState({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
|
||||
// Callback для получения изменений состояния speaking от UserCamera
|
||||
const handleSpeakingChange = (isSpeaking: boolean) => {
|
||||
setLocalSpeaking(isSpeaking);
|
||||
};
|
||||
|
||||
// useEffect для отслеживания изменения ориентации и размеров экрана
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
setWindowDimensions({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
};
|
||||
|
||||
const handleOrientationChange = () => {
|
||||
// Небольшая задержка для корректного получения новых размеров после поворота
|
||||
setTimeout(() => {
|
||||
setWindowDimensions({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
// Слушаем событие resize (срабатывает при изменении размера окна)
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
// Слушаем событие orientationchange (срабатывает при повороте устройства)
|
||||
window.addEventListener("orientationchange", handleOrientationChange);
|
||||
|
||||
// Также слушаем изменения в screen.orientation API (современный способ)
|
||||
if (screen.orientation) {
|
||||
screen.orientation.addEventListener("change", handleOrientationChange);
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
window.removeEventListener("orientationchange", handleOrientationChange);
|
||||
if (screen.orientation) {
|
||||
screen.orientation.removeEventListener(
|
||||
"change",
|
||||
handleOrientationChange
|
||||
);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// useEffect для throttle и отправки состояния speaking через socket
|
||||
useEffect(() => {
|
||||
// Отправляем только если состояние действительно изменилось
|
||||
@@ -70,32 +118,48 @@ function SessionUsersPanel({
|
||||
participants.filter(
|
||||
(p) => p.stream != null && p.stream.getTracks().length > 0
|
||||
).length;
|
||||
|
||||
// Определяем количество колонок в зависимости от количества камер
|
||||
// 1-2 камеры: 1 колонка (друг под другом), 3-4: 2 колонки, 5-9: 3 колонки, 10-16: 4 колонки, 17-25: 5 колонок
|
||||
const getGridColumns = (count: number): number => {
|
||||
const getDesktopGridColumns = (count: number): number => {
|
||||
if (count <= 2) return 1;
|
||||
if (count <= 4) return 2;
|
||||
if (count <= 9) return 3;
|
||||
return 4;
|
||||
};
|
||||
|
||||
const gridColumns = getGridColumns(activeCamerasCount);
|
||||
const getMobilePortraitGridColumns = (count: number): number => {
|
||||
if (count <= 3) return 1;
|
||||
if (count <= 8) return 2;
|
||||
return 3;
|
||||
};
|
||||
|
||||
// Вычисляем количество рядов для правильного расчета высоты
|
||||
// const gridRows = Math.ceil(activeCamerasCount / gridColumns);
|
||||
const getMobileLandscapeGridColumns = (count: number): number => {
|
||||
if (count <= 3) return count;
|
||||
if (count <= 6) return 3;
|
||||
return 4;
|
||||
};
|
||||
|
||||
const gridColumns =
|
||||
windowDimensions.width >= 1440
|
||||
? getDesktopGridColumns(activeCamerasCount)
|
||||
: windowDimensions.height / windowDimensions.width < 1
|
||||
? getMobileLandscapeGridColumns(activeCamerasCount)
|
||||
: getMobilePortraitGridColumns(activeCamerasCount);
|
||||
|
||||
return (
|
||||
<DraggableContainer
|
||||
enableSnapping={mode === "full"}
|
||||
enabled={mode === "full"}
|
||||
autoAlign={true}
|
||||
initialCorner={innerWidth >= 640 ? "bottom-right" : "top-right"}
|
||||
initialCorner={
|
||||
windowDimensions.width >= 640 ? "bottom-right" : "top-right"
|
||||
}
|
||||
padding="1.111vw"
|
||||
className={clsx(
|
||||
"z-[999]",
|
||||
"z-[999] 2xl:gap-[0.556vw] gap-2",
|
||||
mode === "full"
|
||||
? "flex 2xl:gap-[0.556vw] gap-2"
|
||||
: `2xl:p-[5vw] w-full max- h-dvh grid grid-cols-${gridColumns} 2xl:gap-[0.556vw] gap-2`
|
||||
? "flex"
|
||||
: `2xl:p-[5vw] p-4 w-full 2xl:h-dvh max-2xl:portrait:h-[calc(100dvh-17.778vw)] max-2xl:landscape:h-[calc(100dvh-8.75vw)] grid grid-cols-${gridColumns}`
|
||||
)}
|
||||
>
|
||||
{localStream && (
|
||||
@@ -112,7 +176,10 @@ function SessionUsersPanel({
|
||||
onVideoOff={toggleVideo}
|
||||
onCanControl={() => console.log("Toggle control")}
|
||||
onSpeakingChange={handleSpeakingChange}
|
||||
className={activeCamerasCount <= 2 ? "m-auto" : " w-full"}
|
||||
className={clsx(
|
||||
mode === "mini" &&
|
||||
(activeCamerasCount <= 2 ? "2xl:m-auto" : "w-full")
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -125,7 +192,10 @@ function SessionUsersPanel({
|
||||
)
|
||||
.map((participant) => (
|
||||
<UserCamera
|
||||
className={activeCamerasCount <= 2 ? "m-auto" : " w-full"}
|
||||
className={clsx(
|
||||
mode === "mini" &&
|
||||
(activeCamerasCount <= 2 ? "2xl:m-auto" : "w-full")
|
||||
)}
|
||||
key={participant.id}
|
||||
mode={mode}
|
||||
name={participant.id}
|
||||
|
||||
@@ -45,7 +45,9 @@ function ControlsPopover({ session }: ControlsPopoverProps) {
|
||||
|
||||
function handleClickOpenSharePopup() {
|
||||
setIsOpened(false);
|
||||
setPopup(<SharePopup link="https://estate.stream/ahdy12jdco1" />);
|
||||
setPopup(
|
||||
<SharePopup link={`${window.location.origin}/sessions/${session?.id}`} />
|
||||
);
|
||||
}
|
||||
|
||||
function handleClickOpenSettingsModal() {
|
||||
|
||||
@@ -165,7 +165,7 @@ function SessionPage() {
|
||||
session.mode === "stream" &&
|
||||
session.server?.localIp &&
|
||||
session.playerPort && (
|
||||
<div className="absolute w-full h-full aspect-video bg-green-950">
|
||||
<div className="absolute w-full h-full aspect-video">
|
||||
<PixelStreamingWrapper
|
||||
initialSettings={{
|
||||
ss: `ws://${session.server.localIp}:${session.playerPort}`,
|
||||
|
||||
Reference in New Issue
Block a user