import React from 'react'; import { useShallow } from 'zustand/react/shallow'; import { useDownloadStore } from '../store/useDownloadStore'; import { useDownloadProgressStore } from '../store/downloadProgressStore'; import { Play, Pause, MoreVertical, Clock, ArrowUp, ArrowDown } from 'lucide-react'; import type { DownloadItem as DownloadItemType } from '../bindings/DownloadItem'; import { canPauseDownload, canStartDownload, startActionLabel } from '../utils/downloadActions'; import { isActiveDownloadStatus } from '../utils/downloads'; import { downloadProgressColorClass, formatDownloadTotal, resolveDownloadSizeDisplay } from '../utils/downloadProgress'; interface DownloadItemProps { downloadId: string; index: number; tableGridTemplate: string; setContextMenu: (menu: { x: number; y: number; id: string }) => void; handlePause: (id: string, skipConfirm?: boolean) => void; handleResume: (item: DownloadItemType) => void; getCategoryIcon: (category: string) => React.ReactNode; selectedIds: Set; onClick: (e: React.MouseEvent, item: DownloadItemType) => void; } export const DownloadItem = React.memo(({ downloadId, index, tableGridTemplate, setContextMenu, handlePause, handleResume, getCategoryIcon, selectedIds, onClick, }) => { const download = useDownloadStore(state => state.downloads.find(d => d.id === downloadId)); const queueItems = useDownloadStore(useShallow(state => { const item = state.downloads.find(candidate => candidate.id === downloadId); if (!item) return []; const queueId = item.queueId; return state.downloads .filter(candidate => candidate.queueId === queueId && candidate.status !== 'completed' && !(isActiveDownloadStatus(candidate.status) && candidate.status !== 'queued') ) .sort((left, right) => (left.queuePosition ?? 0) - (right.queuePosition ?? 0)) .map(candidate => candidate.id); })); const moveInQueue = useDownloadStore(state => state.moveInQueue); const liveProgress = useDownloadProgressStore(state => state.progressMap[downloadId]); const queueIndex = queueItems.indexOf(downloadId); if (!download) return null; const displayFraction = download.status === 'downloading' ? liveProgress?.fraction ?? download.fraction ?? 0 : download.fraction ?? 0; const displayPercent = `${(displayFraction * 100).toFixed(0)}%`; const displaySpeed = download.status === 'downloading' ? liveProgress?.speed ?? download.speed : download.status === 'processing' ? 'Processing...' : '-'; const displayEta = download.status === 'downloading' ? liveProgress?.eta ?? download.eta : download.status === 'processing' ? 'Muxing...' : '-'; const sizeDisplay = resolveDownloadSizeDisplay({ downloadedBytes: liveProgress?.downloaded_bytes ?? download.downloadedBytes, totalBytes: liveProgress?.total_bytes ?? download.totalBytes, totalIsEstimate: liveProgress?.total_is_estimate ?? download.totalIsEstimate, fallbackSize: download.size }); const hasDownloadedAmount = download.status !== 'completed' && Boolean(sizeDisplay.downloaded && sizeDisplay.total); const completedSizeLabel = download.status === 'completed' ? formatDownloadTotal(sizeDisplay) : sizeDisplay.fallback; return (
onClick(e, download)} onContextMenu={(e) => { e.preventDefault(); setContextMenu({ x: e.clientX, y: e.clientY, id: download.id }); }} >
{getCategoryIcon(download.category)} {download.fileName}
{hasDownloadedAmount ? ( <> {sizeDisplay.downloaded} / {sizeDisplay.totalIsEstimate ? '~' : ''}{sizeDisplay.total} {sizeDisplay.unit} ) : completedSizeLabel}
{download.status === 'completed' ? ( Completed ) : ( <>
{(download.status === 'queued' || download.status === 'staged') && queueIndex !== -1 ? ( <> {download.status === 'staged' ? 'In queue' : 'Queued'} #{queueIndex + 1} ) : download.status === 'downloading' ? ( displayPercent ) : download.status === 'processing' ? ( 'Processing' ) : ( download.status.charAt(0).toUpperCase() + download.status.slice(1) )} )}
{displaySpeed}
{displayEta}
{download.dateAdded ? new Date(download.dateAdded).toLocaleDateString() : '-'}
e.stopPropagation()} onDoubleClick={(e) => e.stopPropagation()} > {(download.status === 'queued' || download.status === 'staged') && queueIndex !== -1 && ( <> )} {canPauseDownload(download.status) && ( )} {canStartDownload(download.status) && ( )}
); });