mirror of
https://github.com/MatrixSeven/file-transfer-go.git
synced 2026-02-04 03:25:03 +08:00
feat: 合并effect,优化逻辑
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React from 'react';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Upload, MessageSquare, Monitor, Users } from 'lucide-react';
|
||||
import Hero from '@/components/Hero';
|
||||
@@ -18,8 +18,6 @@ export default function HomePage() {
|
||||
const {
|
||||
activeTab,
|
||||
handleTabChange,
|
||||
getConnectionInfo,
|
||||
hasInitialized,
|
||||
confirmDialogState,
|
||||
closeConfirmDialog
|
||||
} = useTabNavigation();
|
||||
@@ -34,18 +32,6 @@ export default function HomePage() {
|
||||
showUnsupportedModalManually,
|
||||
} = useWebRTCSupport();
|
||||
|
||||
// 桌面共享功能的占位符函数(保持向后兼容)
|
||||
const handleStartSharing = async () => {
|
||||
console.log('开始桌面共享');
|
||||
};
|
||||
|
||||
const handleStopSharing = async () => {
|
||||
console.log('停止桌面共享');
|
||||
};
|
||||
|
||||
const handleJoinSharing = async (code: string) => {
|
||||
console.log('加入桌面共享:', code);
|
||||
};
|
||||
|
||||
// 处理Tabs组件的字符串参数
|
||||
const handleTabChangeWrapper = (value: string) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useWebRTCStore } from '@/hooks/index';
|
||||
|
||||
@@ -14,7 +14,7 @@ interface ConnectionStatusProps {
|
||||
}
|
||||
|
||||
// 连接状态枚举
|
||||
const getConnectionStatus = (connection: any, currentRoom: any) => {
|
||||
const getConnectionStatus = (connection: { isWebSocketConnected?: boolean; isPeerConnected?: boolean; isConnecting?: boolean; error?: string | null }, currentRoom: { code: string; role: 'sender' | 'receiver' } | null) => {
|
||||
const isWebSocketConnected = connection?.isWebSocketConnected || false;
|
||||
const isPeerConnected = connection?.isPeerConnected || false;
|
||||
const isConnecting = connection?.isConnecting || false;
|
||||
@@ -116,7 +116,7 @@ const StatusIcon = ({ type, className = 'w-3 h-3' }: { type: string; className?:
|
||||
};
|
||||
|
||||
// 获取连接状态文字描述
|
||||
const getConnectionStatusText = (connection: any) => {
|
||||
const getConnectionStatusText = (connection: { isWebSocketConnected?: boolean; isPeerConnected?: boolean; isConnecting?: boolean; error?: string | null }) => {
|
||||
const isWebSocketConnected = connection?.isWebSocketConnected || false;
|
||||
const isPeerConnected = connection?.isPeerConnected || false;
|
||||
const isConnecting = connection?.isConnecting || false;
|
||||
@@ -155,12 +155,14 @@ export function ConnectionStatus(props: ConnectionStatusProps) {
|
||||
error: webrtcState.error,
|
||||
};
|
||||
|
||||
const isConnected = webrtcState.isWebSocketConnected && webrtcState.isPeerConnected;
|
||||
|
||||
// 如果是内联模式,只返回状态文字
|
||||
if (inline) {
|
||||
return <span className={cn('text-sm text-slate-600', className)}>{getConnectionStatusText(connection)}</span>;
|
||||
}
|
||||
|
||||
const status = getConnectionStatus(connection, currentRoom);
|
||||
const status = getConnectionStatus(connection, currentRoom ?? null);
|
||||
|
||||
if (compact) {
|
||||
return (
|
||||
@@ -244,7 +246,7 @@ export function ConnectionStatus(props: ConnectionStatusProps) {
|
||||
}
|
||||
|
||||
// 简化版本的 Hook,用于快速集成 - 现在已经不需要了,但保留兼容性
|
||||
export function useConnectionStatus(webrtcConnection?: any) {
|
||||
export function useConnectionStatus(webrtcConnection?: { isWebSocketConnected?: boolean; isPeerConnected?: boolean; isConnecting?: boolean; currentRoom?: { code: string; role: 'sender' | 'receiver' } | null; error?: string | null }) {
|
||||
// 这个hook现在不再需要,因为ConnectionStatus组件直接使用底层连接
|
||||
// 但为了向后兼容,保留这个接口
|
||||
return useMemo(() => ({
|
||||
|
||||
@@ -6,26 +6,18 @@ import { Button } from '@/components/ui/button';
|
||||
import { Share, Monitor } from 'lucide-react';
|
||||
import WebRTCDesktopReceiver from '@/components/webrtc/WebRTCDesktopReceiver';
|
||||
import WebRTCDesktopSender from '@/components/webrtc/WebRTCDesktopSender';
|
||||
import { useWebRTCStore } from '@/hooks/index';
|
||||
|
||||
|
||||
interface DesktopShareProps {
|
||||
// 保留向后兼容性的props(已废弃,但保留接口)
|
||||
onStartSharing?: () => Promise<string>;
|
||||
onStopSharing?: () => Promise<void>;
|
||||
onJoinSharing?: (code: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export default function DesktopShare({
|
||||
onStartSharing,
|
||||
onStopSharing,
|
||||
onJoinSharing
|
||||
}: DesktopShareProps) {
|
||||
const [mode, setMode] = useState<'share' | 'view'>('share');
|
||||
|
||||
// 使用全局WebRTC状态
|
||||
const webrtcState = useWebRTCStore();
|
||||
|
||||
// 使用统一的URL处理器,带模式转换
|
||||
const { updateMode, getCurrentRoomCode } = useURLHandler({
|
||||
featureType: 'desktop',
|
||||
@@ -44,9 +36,8 @@ export default function DesktopShare({
|
||||
return code;
|
||||
}, [getCurrentRoomCode]);
|
||||
|
||||
// 连接状态变化处理 - 现在不需要了,因为使用全局状态
|
||||
const handleConnectionChange = useCallback((connection: any) => {
|
||||
// 这个函数现在可能不需要了,但为了兼容现有的子组件接口,保留它
|
||||
// 连接状态变化处理 - 为了兼容现有的子组件接口,保留它
|
||||
const handleConnectionChange = useCallback((connection: { isConnected: boolean; isWebSocketConnected: boolean }) => {
|
||||
console.log('桌面共享连接状态变化:', connection);
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ export const WebRTCFileTransfer: React.FC = () => {
|
||||
isPeerConnected: connection.isPeerConnected
|
||||
});
|
||||
|
||||
const { joinRoom: originalJoinRoom, isJoiningRoom } = useRoomConnection({
|
||||
const { joinRoom: originalJoinRoom } = useRoomConnection({
|
||||
connect,
|
||||
isConnecting,
|
||||
isConnected
|
||||
@@ -264,28 +264,33 @@ export const WebRTCFileTransfer: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('当前选中的文件列表:', selectedFiles.map(f => f.name));
|
||||
|
||||
// 在发送方的selectedFiles中查找对应文件
|
||||
const file = selectedFiles.find(f => f.name === fileName);
|
||||
|
||||
if (!file) {
|
||||
console.error('找不到匹配的文件:', fileName);
|
||||
console.log('可用文件:', selectedFiles.map(f => `${f.name} (${f.size} bytes)`));
|
||||
showToast(`无法找到文件: ${fileName}`, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('找到匹配文件,开始发送:', file.name, 'ID:', fileId, '文件大小:', file.size);
|
||||
|
||||
// 更新发送方文件状态为downloading
|
||||
// 更新发送方文件状态为downloading - 统一使用updateFileStatus
|
||||
updateFileStatus(fileId, 'downloading', 0);
|
||||
|
||||
// 发送文件
|
||||
try {
|
||||
sendFile(file, fileId);
|
||||
|
||||
// 移除不必要的Toast - 传输开始状态在UI中已经显示
|
||||
} catch (sendError) {
|
||||
console.error('发送文件失败:', sendError);
|
||||
showToast(`发送文件失败: ${fileName}`, "error");
|
||||
|
||||
// 重置文件状态
|
||||
// 重置文件状态 - 统一使用updateFileStatus
|
||||
updateFileStatus(fileId, 'ready', 0);
|
||||
}
|
||||
} else {
|
||||
@@ -340,86 +345,7 @@ export const WebRTCFileTransfer: React.FC = () => {
|
||||
}
|
||||
}, [error, mode, showToast, lastError]);
|
||||
|
||||
// 处理文件接收
|
||||
useEffect(() => {
|
||||
const cleanup = onFileReceived((fileData: { id: string; file: File }) => {
|
||||
console.log('=== 接收到文件 ===');
|
||||
console.log('文件:', fileData.file.name, 'ID:', fileData.id);
|
||||
|
||||
// 更新下载的文件
|
||||
setDownloadedFiles(prev => new Map(prev.set(fileData.id, fileData.file)));
|
||||
|
||||
// 更新文件状态
|
||||
setFileList(prev => prev.map(item =>
|
||||
item.id === fileData.id
|
||||
? { ...item, status: 'completed' as const, progress: 100 }
|
||||
: item
|
||||
));
|
||||
|
||||
// 移除不必要的Toast - 文件完成状态在UI中已经显示
|
||||
});
|
||||
|
||||
return cleanup;
|
||||
}, [onFileReceived]);
|
||||
|
||||
// 处理文件请求(发送方监听)
|
||||
useEffect(() => {
|
||||
const cleanup = onFileRequested((fileId: string, fileName: string) => {
|
||||
console.log('=== 收到文件请求 ===');
|
||||
console.log('文件:', fileName, 'ID:', fileId, '当前模式:', mode);
|
||||
|
||||
if (mode === 'send') {
|
||||
// 检查连接状态
|
||||
if (!isConnected || error) {
|
||||
console.log('连接已断开,无法发送文件');
|
||||
showToast('连接已断开,无法发送文件', "error");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('当前选中的文件列表:', selectedFiles.map(f => f.name));
|
||||
|
||||
// 在发送方的selectedFiles中查找对应文件
|
||||
const file = selectedFiles.find(f => f.name === fileName);
|
||||
|
||||
if (!file) {
|
||||
console.error('找不到匹配的文件:', fileName);
|
||||
console.log('可用文件:', selectedFiles.map(f => `${f.name} (${f.size} bytes)`));
|
||||
showToast(`无法找到文件: ${fileName}`, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('找到匹配文件,开始发送:', file.name, 'ID:', fileId, '文件大小:', file.size);
|
||||
|
||||
// 更新发送方文件状态为downloading
|
||||
setFileList(prev => prev.map(item =>
|
||||
item.id === fileId || item.name === fileName
|
||||
? { ...item, status: 'downloading' as const, progress: 0 }
|
||||
: item
|
||||
));
|
||||
|
||||
// 发送文件
|
||||
try {
|
||||
sendFile(file, fileId);
|
||||
|
||||
// 移除不必要的Toast - 传输开始状态在UI中已经显示
|
||||
} catch (sendError) {
|
||||
console.error('发送文件失败:', sendError);
|
||||
showToast(`发送文件失败: ${fileName}`, "error");
|
||||
|
||||
// 重置文件状态
|
||||
setFileList(prev => prev.map(item =>
|
||||
item.id === fileId || item.name === fileName
|
||||
? { ...item, status: 'ready' as const, progress: 0 }
|
||||
: item
|
||||
));
|
||||
}
|
||||
} else {
|
||||
console.warn('接收模式下收到文件请求,忽略');
|
||||
}
|
||||
});
|
||||
|
||||
return cleanup;
|
||||
}, [onFileRequested, mode, selectedFiles, sendFile, isConnected, error]);
|
||||
|
||||
// 监听连接状态变化和清理传输状态
|
||||
useEffect(() => {
|
||||
|
||||
@@ -115,40 +115,45 @@ export const useFileStateManager = ({
|
||||
|
||||
console.log('=== selectedFiles变化,同步文件列表 ===', {
|
||||
selectedFilesCount: selectedFiles.length,
|
||||
fileListCount: fileList.length,
|
||||
selectedFileNames: selectedFiles.map(f => f.name)
|
||||
});
|
||||
|
||||
// 根据selectedFiles创建新的文件信息列表
|
||||
const newFileInfos: FileInfo[] = selectedFiles.map(file => {
|
||||
// 尝试找到现有的文件信息,保持已有的状态
|
||||
const existingFileInfo = fileList.find(info => info.name === file.name && info.size === file.size);
|
||||
return existingFileInfo || {
|
||||
id: generateFileId(),
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
status: 'ready' as const,
|
||||
progress: 0
|
||||
};
|
||||
});
|
||||
|
||||
// 检查文件列表是否真正发生变化
|
||||
const fileListChanged =
|
||||
newFileInfos.length !== fileList.length ||
|
||||
newFileInfos.some(newFile =>
|
||||
!fileList.find(oldFile => oldFile.name === newFile.name && oldFile.size === newFile.size)
|
||||
);
|
||||
|
||||
if (fileListChanged) {
|
||||
console.log('文件列表发生变化,更新:', {
|
||||
before: fileList.map(f => f.name),
|
||||
after: newFileInfos.map(f => f.name)
|
||||
// 使用函数式更新获取当前fileList,避免依赖fileList
|
||||
setFileList(currentFileList => {
|
||||
// 根据selectedFiles创建新的文件信息列表
|
||||
const newFileInfos: FileInfo[] = selectedFiles.map(file => {
|
||||
// 尝试在当前fileList中找到现有的文件信息,保持已有的状态
|
||||
const existingFileInfo = currentFileList.find(info => info.name === file.name && info.size === file.size);
|
||||
return existingFileInfo || {
|
||||
id: generateFileId(),
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
status: 'ready' as const,
|
||||
progress: 0
|
||||
};
|
||||
});
|
||||
|
||||
setFileList(newFileInfos);
|
||||
}
|
||||
}, [selectedFiles, mode, pickupCode, fileList, generateFileId]);
|
||||
|
||||
// 检查文件列表是否真正发生变化
|
||||
const fileListChanged =
|
||||
newFileInfos.length !== currentFileList.length ||
|
||||
newFileInfos.some(newFile =>
|
||||
!currentFileList.find(oldFile => oldFile.name === newFile.name && oldFile.size === newFile.size)
|
||||
);
|
||||
|
||||
if (fileListChanged) {
|
||||
console.log('文件列表发生变化,更新:', {
|
||||
before: currentFileList.map(f => f.name),
|
||||
after: newFileInfos.map(f => f.name)
|
||||
});
|
||||
|
||||
return newFileInfos;
|
||||
}
|
||||
|
||||
// 如果没有变化,返回当前的fileList
|
||||
return currentFileList;
|
||||
});
|
||||
}, [selectedFiles, mode, pickupCode, generateFileId]); // 移除fileList依赖,避免无限循环
|
||||
|
||||
return {
|
||||
selectedFiles,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { WebRTCError, WebRTCMessage, ConnectionEvent, EventHandler } from './types';
|
||||
import { WebRTCError, ConnectionEvent, EventHandler } from './types';
|
||||
|
||||
interface WebSocketManagerConfig {
|
||||
url: string;
|
||||
|
||||
@@ -43,6 +43,7 @@ export function detectWebRTCSupport(): WebRTCSupport {
|
||||
pc.close();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
missing.push('DataChannel');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user