|
|
@@ -1,4 +1,4 @@
|
|
|
-import React, { ReactNode } from 'react';
|
|
|
+import React, { ReactNode, useEffect } from 'react';
|
|
|
import { Role, type Message } from './useClassroom';
|
|
|
import { useClassroomContext } from './ClassroomProvider';
|
|
|
import {
|
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
ShareIcon,
|
|
|
ClipboardDocumentIcon,
|
|
|
PaperAirplaneIcon,
|
|
|
+ ArrowsPointingOutIcon,
|
|
|
+ ArrowsPointingInIcon,
|
|
|
} from '@heroicons/react/24/outline';
|
|
|
import { Button } from '@/client/components/ui/button';
|
|
|
import { Textarea } from '@/client/components/ui/textarea';
|
|
|
@@ -30,6 +32,7 @@ interface ClassroomLayoutProps {
|
|
|
export const ClassroomLayout = ({ children, role }: ClassroomLayoutProps) => {
|
|
|
const [showVideo, setShowVideo] = React.useState(role !== Role.Teacher);
|
|
|
const [showShareLink, setShowShareLink] = React.useState(false);
|
|
|
+ const [isLandscape, setIsLandscape] = React.useState(false);
|
|
|
const {
|
|
|
remoteScreenContainer,
|
|
|
remoteCameraContainer,
|
|
|
@@ -52,11 +55,79 @@ export const ClassroomLayout = ({ children, role }: ClassroomLayoutProps) => {
|
|
|
showToast
|
|
|
} = useClassroomContext();
|
|
|
|
|
|
+ // 检测是否为移动设备
|
|
|
+ const isMobileDevice = () => {
|
|
|
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 横屏切换功能
|
|
|
+ const toggleLandscape = () => {
|
|
|
+ if (!isMobileDevice()) {
|
|
|
+ showToast('info', '横屏功能仅在移动设备上可用');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ setIsLandscape(!isLandscape);
|
|
|
+
|
|
|
+ if (!isLandscape) {
|
|
|
+ // 进入横屏模式
|
|
|
+ if (document.documentElement.requestFullscreen) {
|
|
|
+ document.documentElement.requestFullscreen();
|
|
|
+ }
|
|
|
+ // 尝试横屏旋转(需要设备支持)
|
|
|
+ // @ts-ignore
|
|
|
+ if (screen.orientation && screen.orientation.lock) {
|
|
|
+ // @ts-ignore
|
|
|
+ screen.orientation.lock('landscape').catch(() => {
|
|
|
+ showToast('info', '您的设备不支持自动横屏,请手动旋转设备');
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 退出横屏模式
|
|
|
+ if (document.exitFullscreen) {
|
|
|
+ document.exitFullscreen();
|
|
|
+ }
|
|
|
+ if (screen.orientation && screen.orientation.unlock) {
|
|
|
+ screen.orientation.unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 监听屏幕方向变化
|
|
|
+ useEffect(() => {
|
|
|
+ const handleOrientationChange = () => {
|
|
|
+ if (screen.orientation) {
|
|
|
+ setIsLandscape(screen.orientation.type.includes('landscape'));
|
|
|
+ } else {
|
|
|
+ // 备用方案:通过窗口尺寸判断
|
|
|
+ setIsLandscape(window.innerWidth > window.innerHeight);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ if (screen.orientation) {
|
|
|
+ screen.orientation.addEventListener('change', handleOrientationChange);
|
|
|
+ } else {
|
|
|
+ // 备用方案:监听窗口尺寸变化
|
|
|
+ window.addEventListener('resize', handleOrientationChange);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始检查
|
|
|
+ handleOrientationChange();
|
|
|
+
|
|
|
+ return () => {
|
|
|
+ if (screen.orientation) {
|
|
|
+ screen.orientation.removeEventListener('change', handleOrientationChange);
|
|
|
+ } else {
|
|
|
+ window.removeEventListener('resize', handleOrientationChange);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }, []);
|
|
|
+
|
|
|
return (
|
|
|
- <div className="flex flex-col md:flex-row h-screen bg-gray-100">
|
|
|
+ <div className={`flex ${isLandscape ? 'flex-row' : 'flex-col'} md:flex-row h-screen bg-gray-100`}>
|
|
|
{/* 视频区域 */}
|
|
|
{showVideo && (
|
|
|
- <div className="relative h-[300px] md:flex-[3] md:h-auto bg-black">
|
|
|
+ <div className={`relative ${isLandscape ? 'flex-[3] h-auto' : 'h-[300px]'} md:flex-[3] md:h-auto bg-black`}>
|
|
|
{/* 主屏幕共享容器 */}
|
|
|
<div
|
|
|
id="remoteScreenContainer"
|
|
|
@@ -91,7 +162,7 @@ export const ClassroomLayout = ({ children, role }: ClassroomLayoutProps) => {
|
|
|
)}
|
|
|
|
|
|
{/* 消息和控制面板列 */}
|
|
|
- <div className={`${showVideo ? 'w-full flex-1 md:w-96 md:flex-none' : 'flex-1'} flex flex-col`}>
|
|
|
+ <div className={`${showVideo ? `${isLandscape ? 'w-96 flex-none' : 'w-full flex-1'}` : 'flex-1'} md:w-96 md:flex-none flex flex-col ${isLandscape ? 'max-h-screen overflow-y-auto' : ''}`}>
|
|
|
{/* 消息区域 */}
|
|
|
<div className="flex flex-col h-full">
|
|
|
{/* 消息列表 - 填充剩余空间 */}
|
|
|
@@ -160,6 +231,24 @@ export const ClassroomLayout = ({ children, role }: ClassroomLayoutProps) => {
|
|
|
</Button>
|
|
|
)}
|
|
|
|
|
|
+ {/* 横屏按钮 - 仅在移动设备上显示 */}
|
|
|
+ {isMobileDevice() && (
|
|
|
+ <Button
|
|
|
+ type="button"
|
|
|
+ onClick={toggleLandscape}
|
|
|
+ className={`p-2 rounded-full ${isLandscape ? 'bg-green-500' : 'bg-blue-500'} text-white touch-manipulation`}
|
|
|
+ title={isLandscape ? '退出横屏' : '进入横屏'}
|
|
|
+ size="icon"
|
|
|
+ variant="ghost"
|
|
|
+ >
|
|
|
+ {isLandscape ? (
|
|
|
+ <ArrowsPointingInIcon className="w-4 h-4" />
|
|
|
+ ) : (
|
|
|
+ <ArrowsPointingOutIcon className="w-4 h-4" />
|
|
|
+ )}
|
|
|
+ </Button>
|
|
|
+ )}
|
|
|
+
|
|
|
{/* 图片选择按钮 */}
|
|
|
<ImageSelectorButton />
|
|
|
|