202 lines
7.4 KiB
TypeScript
202 lines
7.4 KiB
TypeScript
'use client';
|
|
|
|
import { Monitor, MonitorPlay, Users } from 'lucide-react';
|
|
import Link from 'next/link';
|
|
import { useRouter } from 'next/navigation';
|
|
import { useEffect } from 'react';
|
|
|
|
import { useWatchRoomContext } from '@/components/WatchRoomProvider';
|
|
import { useScreenShare } from '@/hooks/useScreenShare';
|
|
|
|
const NEW_TAB_KEY_PREFIX = 'watch_room_screen_home_opened_';
|
|
|
|
export default function WatchRoomScreenPage() {
|
|
const router = useRouter();
|
|
const watchRoom = useWatchRoomContext();
|
|
const { currentRoom, members, leaveRoom } = watchRoom;
|
|
const {
|
|
currentRoom: screenRoom,
|
|
isOwner,
|
|
isSharing,
|
|
isStarting,
|
|
error,
|
|
localVideoRef,
|
|
remoteVideoRef,
|
|
startSharing,
|
|
stopSharing,
|
|
} = useScreenShare();
|
|
|
|
useEffect(() => {
|
|
if (!currentRoom) {
|
|
router.replace('/watch-room');
|
|
return;
|
|
}
|
|
|
|
if (currentRoom.roomType !== 'screen') {
|
|
router.replace('/watch-room');
|
|
}
|
|
}, [currentRoom, router]);
|
|
|
|
useEffect(() => {
|
|
if (!screenRoom || !isOwner) return;
|
|
|
|
const key = `${NEW_TAB_KEY_PREFIX}${screenRoom.id}`;
|
|
if (sessionStorage.getItem(key)) return;
|
|
|
|
sessionStorage.setItem(key, '1');
|
|
window.open('/?watchRoomNoConnect=1', '_blank', 'noopener,noreferrer');
|
|
}, [isOwner, screenRoom?.id]);
|
|
|
|
if (!screenRoom || screenRoom.roomType !== 'screen') {
|
|
return null;
|
|
}
|
|
|
|
const handleLeave = () => {
|
|
if (isOwner && isSharing) {
|
|
stopSharing(true);
|
|
}
|
|
leaveRoom();
|
|
router.push('/watch-room');
|
|
};
|
|
|
|
return (
|
|
<div className='min-h-screen bg-white text-gray-900 dark:bg-black dark:text-gray-200'>
|
|
<div className='mx-auto flex min-h-screen max-w-7xl flex-col gap-4 px-4 py-4 lg:px-8'>
|
|
<div className='flex items-center justify-between gap-4 rounded-2xl border border-gray-200 bg-white/90 px-5 py-4 shadow-sm dark:border-gray-800 dark:bg-gray-900/80'>
|
|
<div>
|
|
<h1 className='flex items-center gap-2 text-2xl font-semibold'>
|
|
<Monitor className='h-6 w-6 text-blue-500' />
|
|
屏幕共享观影室
|
|
</h1>
|
|
<p className='mt-1 text-sm text-gray-600 dark:text-gray-400'>
|
|
房间:{screenRoom.name} · 房主:{screenRoom.ownerName}
|
|
</p>
|
|
</div>
|
|
<div className='flex items-center gap-2'>
|
|
{isOwner && (
|
|
<Link
|
|
href='/?watchRoomNoConnect=1'
|
|
target='_blank'
|
|
rel='noreferrer'
|
|
className='rounded-lg bg-blue-500 px-4 py-2 text-white'
|
|
>
|
|
新开主页
|
|
</Link>
|
|
)}
|
|
<button
|
|
onClick={handleLeave}
|
|
className='rounded-lg bg-gray-200 px-4 py-2 text-gray-900 dark:bg-gray-700 dark:text-gray-100'
|
|
>
|
|
离开房间
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className='grid flex-1 grid-cols-1 gap-4 xl:grid-cols-[1fr_320px]'>
|
|
<div className='relative flex min-h-[420px] items-center justify-center overflow-hidden rounded-2xl border border-gray-200 bg-black dark:border-gray-800'>
|
|
{isOwner ? (
|
|
<video
|
|
ref={localVideoRef}
|
|
autoPlay
|
|
muted
|
|
playsInline
|
|
className='h-full w-full bg-black object-contain'
|
|
/>
|
|
) : (
|
|
<video
|
|
ref={remoteVideoRef}
|
|
autoPlay
|
|
playsInline
|
|
controls
|
|
className='h-full w-full bg-black object-contain'
|
|
/>
|
|
)}
|
|
|
|
{!isSharing && (
|
|
<div className='absolute px-6 text-center text-white'>
|
|
<MonitorPlay className='mx-auto mb-3 h-12 w-12 text-white/70' />
|
|
<p className='text-lg font-medium'>
|
|
{isOwner ? '点击开始共享,向房员推送浏览器画面' : '等待房主开始共享屏幕'}
|
|
</p>
|
|
{isOwner && (
|
|
<p className='mt-2 text-sm text-white/70'>
|
|
本页不要关闭;已尝试为你新开一个主页标签页方便继续浏览。
|
|
</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className='space-y-4'>
|
|
<div className='rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900'>
|
|
<h2 className='mb-3 font-semibold'>共享状态</h2>
|
|
<div className='space-y-2 text-sm text-gray-600 dark:text-gray-400'>
|
|
<p>类型:屏幕共享</p>
|
|
<p>状态:{isSharing ? '共享中' : '未开始'}</p>
|
|
<p>成员:{members.length} 人</p>
|
|
</div>
|
|
|
|
{error && (
|
|
<div className='mt-3 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-800 dark:bg-red-900/20 dark:text-red-300'>
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<div className='mt-4 flex gap-3'>
|
|
{isOwner ? (
|
|
<>
|
|
<button
|
|
onClick={() => startSharing()}
|
|
disabled={isStarting || isSharing}
|
|
className='flex-1 rounded-lg bg-blue-500 px-4 py-2 text-white disabled:bg-gray-400'
|
|
>
|
|
{isStarting ? '启动中...' : isSharing ? '共享中' : '开始共享'}
|
|
</button>
|
|
<button
|
|
onClick={() => stopSharing(true)}
|
|
disabled={!isSharing}
|
|
className='rounded-lg bg-red-500 px-4 py-2 text-white disabled:bg-gray-400'
|
|
>
|
|
停止
|
|
</button>
|
|
</>
|
|
) : (
|
|
<div className='rounded-lg bg-blue-50 px-3 py-2 text-sm text-blue-700 dark:bg-blue-900/20 dark:text-blue-300'>
|
|
房员无需操作,房主开始共享后会自动显示画面。
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className='rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900'>
|
|
<h2 className='mb-3 flex items-center gap-2 font-semibold'>
|
|
<Users className='h-4 w-4' />
|
|
房间成员
|
|
</h2>
|
|
<div className='space-y-2'>
|
|
{members.map((member) => (
|
|
<div
|
|
key={member.id}
|
|
className='flex items-center justify-between rounded-lg bg-gray-50 px-3 py-2 dark:bg-gray-800/70'
|
|
>
|
|
<span className='text-sm'>{member.name}</span>
|
|
{member.isOwner && (
|
|
<span className='rounded bg-yellow-100 px-2 py-1 text-xs text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-300'>
|
|
房主
|
|
</span>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className='rounded-xl border border-blue-200 bg-blue-50 p-4 text-sm text-blue-800 dark:border-blue-800 dark:bg-blue-900/20 dark:text-blue-200'>
|
|
本页不再包裹站点导航,便于直接共享。建议使用桌面版 Chrome / Edge,并优先共享标签页。
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|