import React from 'react'; 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 } from '../utils/downloadActions'; import { useTranslation } from 'react-i18next'; import { downloadProgressColorClass, formatDownloadTotal, resolveDownloadSizeDisplay } from '../utils/downloadProgress'; import { COLUMN_ALIGNMENT_JUSTIFY, type DownloadColumnAlignment, type DownloadTableColumnKey } from '../utils/downloadTableColumns'; interface DownloadItemProps { download: DownloadItemType; index: number; queueIndex: number; queueLength: number; columnOrder: DownloadTableColumnKey[]; columnAlignments: Record; tableGridTemplate: string; tableMinWidth: number; setContextMenu: (menu: { x: number; y: number; id: string }) => void; handlePause: (id: string, skipConfirm?: boolean) => void; handleResume: (item: DownloadItemType) => void; getCategoryIcon: (category: string) => React.ReactNode; isSelected: boolean; onMoveInQueue: (id: string, direction: 'up' | 'down') => void; onClick: (e: React.MouseEvent, item: DownloadItemType) => void; } export const DownloadItem = React.memo(({ download, index, queueIndex, queueLength, columnOrder, columnAlignments, tableGridTemplate, tableMinWidth, setContextMenu, handlePause, handleResume, getCategoryIcon, isSelected, onMoveInQueue, onClick, }) => { const { t } = useTranslation(); const liveProgress = useDownloadProgressStore(state => state.progressMap[download.id]); 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' ? t($ => $.downloads.values.processing) : '-'; const displayEta = download.status === 'downloading' ? liveProgress?.eta ?? download.eta : download.status === 'processing' ? t($ => $.downloads.values.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 = (() => { const value = download.status === 'completed' ? formatDownloadTotal(sizeDisplay) : sizeDisplay.fallback; return value === 'Unknown' ? t($ => $.addDownloads.unknown) : value; })(); const downloadStatusLabel = t($ => $.downloads.status[download.status]); const downloadedSizeLabel = sizeDisplay.totalIsEstimate ? t($ => $.downloads.size.downloadedOfApproximate, { downloaded: sizeDisplay.downloaded ?? '', total: sizeDisplay.total ?? '', unit: sizeDisplay.unit ?? '', }) : t($ => $.downloads.size.downloadedOf, { downloaded: sizeDisplay.downloaded ?? '', total: sizeDisplay.total ?? '', unit: sizeDisplay.unit ?? '', }); const columnStyle = (key: DownloadTableColumnKey): React.CSSProperties => ({ '--column-justify': COLUMN_ALIGNMENT_JUSTIFY[columnAlignments[key]], } as React.CSSProperties); const cells: Record = { 'File Name': (
{getCategoryIcon(download.category)} {download.fileName}
), Size: (
{hasDownloadedAmount ? ( {sizeDisplay.downloaded} / ) : null} {hasDownloadedAmount ? `${sizeDisplay.totalIsEstimate ? '~' : ''}${sizeDisplay.total} ${sizeDisplay.unit}` : completedSizeLabel}
), Status: (
{download.status === 'completed' ? ( {downloadStatusLabel} ) : (
{(download.status === 'queued' || download.status === 'staged') && queueIndex !== -1 ? ( <> {downloadStatusLabel} #{queueIndex + 1} ) : download.status === 'downloading' ? ( displayPercent ) : download.status === 'processing' ? ( downloadStatusLabel ) : ( downloadStatusLabel )}
)}
), Speed: (
{displaySpeed}
), ETA: (
{displayEta}
), 'Date Added': (
{download.dateAdded ? new Date(download.dateAdded).toLocaleDateString() : '-'}
), }; const rowActions = (
e.stopPropagation()} onDoubleClick={(e) => e.stopPropagation()} > {(download.status === 'queued' || download.status === 'staged') && queueIndex !== -1 && ( <> )} {canPauseDownload(download.status) && ( )} {canStartDownload(download.status) && ( )}
); return (
onClick(e, download)} onContextMenu={(e) => { e.preventDefault(); setContextMenu({ x: e.clientX, y: e.clientY, id: download.id }); }} > {columnOrder.map(columnKey => ( {cells[columnKey]} ))} {rowActions}
); });