diff --git a/frontend/components/ClipboardApp.tsx b/frontend/components/ClipboardApp.tsx index e000580..08da21c 100644 --- a/frontend/components/ClipboardApp.tsx +++ b/frontend/components/ClipboardApp.tsx @@ -18,7 +18,7 @@ const ClipboardApp = () => { const [retrieveRoomIdInput, setRetrieveRoomIdInput] = useState(""); const [activeTab, setActiveTab] = useState<"send" | "retrieve">("send"); - const retrieveJoinRoomBtnRef = useRef(null); //接收方--加入房间按钮ref + const retrieveJoinRoomBtnRef = useRef(null); // Ref for the receiver's "Join Room" button const { messages, isLoadingMessages } = usePageSetup({ setRetrieveRoomId: setRetrieveRoomIdInput, diff --git a/frontend/components/ClipboardApp/FileListDisplay.tsx b/frontend/components/ClipboardApp/FileListDisplay.tsx index ff5102a..b9343db 100644 --- a/frontend/components/ClipboardApp/FileListDisplay.tsx +++ b/frontend/components/ClipboardApp/FileListDisplay.tsx @@ -11,21 +11,20 @@ import { getDictionary } from "@/lib/dictionary"; import { useLocale } from "@/hooks/useLocale"; import type { Messages } from "@/types/messages"; -function formatFolderDis( - template: string, - num: number, - size: string -) { - return template.replace('{num}', num.toString()).replace('{size}', size); +function formatFolderDis(template: string, num: number, size: string) { + return template.replace("{num}", num.toString()).replace("{size}", size); } function formatFolderTips( - template: string, - name: string, - num: number, + template: string, + name: string, + num: number, size: string ) { - return template.replace('{name}', name).replace('{num}', num.toString()).replace('{size}', size); + return template + .replace("{name}", name) + .replace("{num}", num.toString()) + .replace("{size}", size); } interface FileListDisplayProps { @@ -37,15 +36,15 @@ interface FileListDisplayProps { }; }; onDownload?: (item: FileMeta) => void; - onRequest?: (item: FileMeta) => void; //请求文件 + onRequest?: (item: FileMeta) => void; // Request file onDelete?: (item: FileMeta) => void; onLocationPick?: () => Promise; - saveType?: { [fileId: string]: boolean }; //文件是存储在磁盘还是内存 + saveType?: { [fileId: string]: boolean }; // File stored on disk or in memory largeFileThreshold?: number; } -// 添加类型判断辅助函数 +// Add type guard helper function function isCustomFile(file: FileMeta | CustomFile): file is CustomFile { - return "lastModified" in file; // 使用 File 对象特有的属性来判断 + return "lastModified" in file; // Use a property specific to File objects to check } function isFileMetaArray( files: FileMeta[] | CustomFile[] @@ -68,21 +67,21 @@ const FileListDisplay: React.FC = ({ const [showFinished, setShowFinished] = useState<{ [fileId: string]: boolean; }>({}); - // 添加 ref 来存储上一次的 showFinished 状态 + // Add a ref to store the previous showFinished state const prevShowFinishedRef = useRef<{ [fileId: string]: boolean }>({}); - const [pickedLocation, setPickedLocation] = useState(false); //是否已经选取过保存目录 - const [needPickLocation, setNeedPickLocation] = useState(false); //是否需要选择保存目录--大文件或文件夹或用户主动选择 + const [pickedLocation, setPickedLocation] = useState(false); // Whether a save directory has been selected + const [needPickLocation, setNeedPickLocation] = useState(false); // Whether a save directory needs to be selected -- for large files, folders, or user choice - const [folders, setFolders] = useState([]); //将文件中属于 文件夹的 提取出来 - const [singleFiles, setSingleFiles] = useState([]); //保留单文件,不属于文件夹 - // 添加当前显示的接收端追踪 + const [folders, setFolders] = useState([]); // Extract folder items from files + const [singleFiles, setSingleFiles] = useState([]); // Keep single files, not part of a folder + // Add tracking for currently displayed receiver const [activeTransfers, setActiveTransfers] = useState<{ [fileId: string]: string; }>({}); - //对是否有文件传输状态进行跟踪 + // Track if any file transfer is in progress const [isAnyFileTransferring, setIsAnyFileTransferring] = useState(false); - // 添加下载次数的状态 + // Add state for download counts const [downloadCounts, setDownloadCounts] = useState<{ [fileId: string]: number; }>({}); @@ -91,7 +90,7 @@ const FileListDisplay: React.FC = ({ .then((dict) => setMessages(dict)) .catch((error) => console.error("Failed to load messages:", error)); }, [locale]); - //监控文件传输状态 + // Monitor file transfer status useEffect(() => { const hasActiveTransfer = Object.values(fileProgresses).some( (fileProgress) => @@ -103,12 +102,12 @@ const FileListDisplay: React.FC = ({ }, [fileProgresses]); useEffect(() => { - //分离出单文件和文件夹 + // Separate single files and folders const tempSingleFiles: FileMeta[] = []; let folders_: { [folderName: string]: FileMeta } = {}; let needPick = false; - // 如果是 CustomFile[] 类型,先转换为 FileMeta[] + // If it's a CustomFile[] type, convert it to FileMeta[] first const processedFiles: FileMeta[] = isFileMetaArray(files) ? files : files.map((file) => ({ @@ -123,10 +122,10 @@ const FileListDisplay: React.FC = ({ for (let file of processedFiles) { if (file.folderName !== "") { folders_[file.folderName] = folders_[file.folderName] || { - //如果对象不存在,则初始化 + // If the object doesn't exist, initialize it name: file.folderName, size: 0, - fullName: file.folderName, // 文件夹的 fullName 就是 folderName + fullName: file.folderName, // The fullName of a folder is its folderName fileType: "folder", fileId: file.folderName, folderName: file.folderName, @@ -135,7 +134,7 @@ const FileListDisplay: React.FC = ({ }; folders_[file.folderName].fileCount = - (folders_[file.folderName].fileCount ?? 0) + 1; //如果 fileCount 是 undefined,使用默认值 0 + (folders_[file.folderName].fileCount ?? 0) + 1; // If fileCount is undefined, use default value 0 folders_[file.folderName].size += file.size; folders_[file.folderName].fileNamesDis = folders_[file.folderName] .fileNamesDis @@ -151,7 +150,7 @@ const FileListDisplay: React.FC = ({ // console.log('Single files before setState:', tempSingleFiles); // console.log('Folders before setState:', Object.values(folders_)); - // 使用函数式更新确保状态正确更新 + // Use functional updates to ensure the state is updated correctly setSingleFiles((prev) => { // console.log('Previous single files:', prev); // console.log('New single files:', tempSingleFiles); @@ -162,32 +161,32 @@ const FileListDisplay: React.FC = ({ // console.log('New folders:', Object.values(folders_)); return [...Object.values(folders_)]; }); - setNeedPickLocation(needPick); //设置是否需要选择保存目录 + setNeedPickLocation(needPick); // Set whether a save directory needs to be selected }, [files, largeFileThreshold]); useEffect(() => { - //如果一个文件同时被多个接收端请求,会先显示第一个,等结束后再显示第二个 + // If a file is requested by multiple receivers simultaneously, the first one will be displayed, then the second after the first finishes. let fileIds = [...singleFiles, ...folders].map((file) => file.fileId); fileIds.forEach((fileId) => { const fileProgress = fileProgresses[fileId]; if (!fileProgress) return; - // 获取当前文件的所有传输进度 + // Get all transfer progresses for the current file const transfers = Object.entries(fileProgress); - // 如果没有活跃传输,选择第一个开始的传输 + // If there are no active transfers, select the first one that started let newPeerId = ""; if (!activeTransfers[fileId] && transfers.length > 0) { newPeerId = transfers[0][0]; setActiveTransfers((prev) => ({ ...prev, - [fileId]: newPeerId, // 设置第一个 peerId + [fileId]: newPeerId, // Set the first peerId })); } - // set是异步操作 直接使用 newPeerId 而不是从 activeTransfers 中读取 + // set is an async operation, use newPeerId directly instead of reading from activeTransfers const activePeerId = newPeerId || activeTransfers[fileId]; - // 检查当前活跃传输是否完成 + // Check if the current active transfer is complete if (activePeerId && fileProgress[activePeerId]?.progress >= 1) { - // 当前传输完成,等待2秒后切换到下一个未完成的传输 + // Current transfer is complete, wait 2 seconds before switching to the next incomplete transfer if (!showFinished[fileId]) { setShowFinished((prev) => ({ ...prev, [fileId]: true })); @@ -198,8 +197,8 @@ const FileListDisplay: React.FC = ({ return updated; }); - delete fileProgress[activePeerId]; //需要删掉这个peer的进度,否则下次相同文件被请求进度显示不正常 - // 找到下一个未完成的传输 + delete fileProgress[activePeerId]; //need to delete the progress of this peer, otherwise the progress will be displayed abnormally when the same file is requested next time. + // Find the next outstanding transfer const nextTransfer = transfers.find( ([pid, prog]) => pid !== activePeerId && prog.progress > 0 && prog.progress < 1 @@ -228,7 +227,7 @@ const FileListDisplay: React.FC = ({ ]); useEffect(() => { - //监控 Finished 从false/null跳变为true这个事件 来触发下载 + //Monitor the Finished event from false/null to true to trigger the download let files_ = [...singleFiles, ...folders]; files_.forEach((item: FileMeta) => { @@ -236,32 +235,32 @@ const FileListDisplay: React.FC = ({ const prevShowFinished = prevShowFinishedRef.current[item.fileId]; const isSaveToDisk = saveType ? saveType[item.fileId] : false; // console.log(`last:${prevShowFinished} --> cur:${currentShowFinished}`); - // 检测 false -> true 的跳变 + // Detecting false -> true transitions if (!prevShowFinished && currentShowFinished) { if (!isSaveToDisk && onDownload) { onDownload(item); } - // 增加下载次数 + // Increase download count setDownloadCounts((prevCounts) => ({ ...prevCounts, [item.fileId]: (prevCounts[item.fileId] || 0) + 1, })); } - // 更新上一次的状态 + // Update the last status prevShowFinishedRef.current[item.fileId] = currentShowFinished; }); }, [showFinished, singleFiles, folders, saveType, onDownload]); - //每一项文件 对应的动作--进度、下载、删除 + //Actions corresponding to each file - progress, download, delete const renderItemActions = (item: FileMeta) => { const fileProgress = fileProgresses[item.fileId]; const activePeerId = activeTransfers[item.fileId]; const progress = activePeerId ? fileProgress?.[activePeerId] : null; const showCompletion = showFinished[item.fileId]; const isSaveToDisk = saveType ? saveType[item.fileId] : false; - // 获取下载次数 + // Get download count const downloadCount = downloadCounts[item.fileId] || 0; if (messages === null) { @@ -269,7 +268,7 @@ const FileListDisplay: React.FC = ({ } return (
- {progress && progress.progress < 1 ? ( //显示进度或已完成 + {progress && progress.progress < 1 ? ( //Show progress or completed = ({ ) : null} {mode === "receiver" && onRequest && - onDownload && ( //请求 && 下载 + onDownload && ( //Request && Download onRequest(item)} isCurrentFileTransferring={ @@ -297,7 +296,7 @@ const FileListDisplay: React.FC = ({ isSavedToDisk={saveType ? saveType[item.fileId] : false} /> )} - {/* 展示下载次数 */} + {/* display download Num*/} {mode === "sender" && ( {messages.text.FileListDisplay.downloadNum_dis}: {downloadCount} @@ -321,7 +320,7 @@ const FileListDisplay: React.FC = ({
); }; - //每一项文件 对应的展示--meta信息 + //Display of each file --meta information const renderItem = (item: FileMeta, isFolder: boolean) => { const filenameDisplayLen = 30; const formatSize = formatFileSize(item.size); @@ -362,7 +361,7 @@ const FileListDisplay: React.FC = ({ <> {(singleFiles.length > 0 || folders.length > 0) && ( <> - {/* 自动弹窗组件,当有大文件和文件夹时 只提醒一次 */} + {/* Automatic pop-up component, only remind once when there are large files and folders */} {mode === "receiver" && (
= ({ } condition={() => needPickLocation} /> - {/* 常态化提醒选择保存目录 */} + {/* Regular reminder to select the save directory */}

{messages.text.FileListDisplay.chooseSavePath_tips} @@ -395,7 +394,6 @@ const FileListDisplay: React.FC = ({

)}
- {/* 确保文件列表确实被渲染 */}
{singleFiles.map((file) => (
{renderItem(file, false)}
diff --git a/frontend/components/ClipboardApp/FileTransferButton.tsx b/frontend/components/ClipboardApp/FileTransferButton.tsx index ab8e21f..33279b4 100644 --- a/frontend/components/ClipboardApp/FileTransferButton.tsx +++ b/frontend/components/ClipboardApp/FileTransferButton.tsx @@ -12,7 +12,7 @@ interface FileTransferButtonProps { isOtherFileTransferring: boolean; isSavedToDisk: boolean; } -//针对下载中不同状态的按键进行管理 +// Manage buttons for different download statuses const FileTransferButton = ({ onRequest, isCurrentFileTransferring, @@ -21,7 +21,7 @@ const FileTransferButton = ({ }: FileTransferButtonProps) => { const locale = useLocale(); const [messages, setMessages] = useState(null); - // 按钮状态判断 + // Button status judgment const isDisabled = isCurrentFileTransferring || isSavedToDisk || isOtherFileTransferring; useEffect(() => { @@ -29,7 +29,7 @@ const FileTransferButton = ({ .then(dict => setMessages(dict)) .catch(error => console.error('Failed to load messages:', error)); }, [locale]); - // 根据不同状态显示不同的提示信息 + // Display different tooltips based on status const getTooltipContent = () => { if (isSavedToDisk) return messages!.text.FileTransferButton.SavedToDisk_tips; if (isCurrentFileTransferring) return messages!.text.FileTransferButton.CurrentFileTransferring_tips; @@ -37,7 +37,7 @@ const FileTransferButton = ({ return messages!.text.FileTransferButton.download_tips; }; - // 根据状态设置不同的按钮样式和类名 + // Set different button styles and class names based on status const getButtonStyles = () => { if (isSavedToDisk) { return { @@ -71,7 +71,7 @@ const FileTransferButton = ({ - {/* 包装器确保禁用状态下tooltip仍然工作 */} +