import React, { useState, useEffect } from 'react'; import { useDownloadStore, DownloadItem } from '../store/useDownloadStore'; import { useSettingsStore } from '../store/useSettingsStore'; import { SidebarFilter } from './Sidebar'; import { Play, Pause, Plus, Trash2, FileText, Image as ImageIcon, Music, Film, Box, Archive, FileQuestion, MoreVertical, PanelLeft } from 'lucide-react'; import { invoke } from '@tauri-apps/api/core'; import { homeDir } from '@tauri-apps/api/path'; import { getCurrentWindow } from '@tauri-apps/api/window'; interface DownloadTableProps { filter: SidebarFilter; } export const DownloadTable: React.FC = ({ filter }) => { const { downloads, toggleAddModal, updateDownload, removeDownload, clearFinished, redownload } = useDownloadStore(); const { isSidebarVisible, toggleSidebar, listRowDensity } = useSettingsStore(); const getPaddingY = () => { switch (listRowDensity) { case 'compact': return 'py-1'; case 'spacious': return 'py-4'; default: return 'py-3'; } }; const py = getPaddingY(); const [contextMenu, setContextMenu] = useState<{ x: number; y: number; id: string } | null>(null); useEffect(() => { const handleCloseMenu = () => setContextMenu(null); window.addEventListener('click', handleCloseMenu); return () => window.removeEventListener('click', handleCloseMenu); }, []); const resolvePath = async (dir: string, file: string) => { let resolvedDir = dir; if (dir.startsWith('~/')) { const home = await homeDir(); resolvedDir = home + '/' + dir.slice(2); } else if (dir === '~') { resolvedDir = await homeDir(); } return resolvedDir + '/' + file; }; const filteredDownloads = downloads.filter((d: DownloadItem) => { switch (filter) { case 'all': return true; case 'active': return d.status === 'downloading'; case 'completed': return d.status === 'completed'; case 'unfinished': return d.status !== 'completed'; default: return d.category === filter; } }); const getFilterTitle = () => { switch (filter) { case 'all': return 'All Downloads'; case 'active': return 'Active'; case 'completed': return 'Completed'; case 'unfinished': return 'Unfinished'; default: return filter; } }; const handlePause = async (id: string) => { try { await invoke('pause_download', { id }); updateDownload(id, { status: 'paused', speed: '-', eta: '-' }); } catch (e) { console.error("Failed to pause:", e); } }; const handleResume = (item: DownloadItem) => { useDownloadStore.setState((state) => ({ downloads: state.downloads.map(d => d.id === item.id ? { ...d, status: 'queued', speed: '-', eta: '-' } : d) })); useDownloadStore.getState().processQueue(); }; const handleDelete = async (id: string) => { try { await removeDownload(id); } catch (e) { console.error("Failed to delete download:", e); } }; const contextItem = contextMenu ? downloads.find(d => d.id === contextMenu.id) : null; const getCategoryIcon = (category: string) => { switch(category) { case 'Documents': return ; case 'Images': return ; case 'Audio': return ; case 'Video': return ; case 'Apps': return ; case 'Archives': return ; default: return ; } } return (
{/* Modern Toolbar */}
{ if (e.button === 0 && (e.target as HTMLElement).closest('.no-drag') === null) { getCurrentWindow().startDragging(); } }} >

{getFilterTitle()}

{/* Table */}
{filteredDownloads.length === 0 ? ( ) : ( filteredDownloads.map(d => ( { e.preventDefault(); setContextMenu({ x: e.clientX, y: e.clientY, id: d.id }); }} > )) )}
FILE SIZE STATUS SPEED ETA DATE ADDED
No downloads in this view
{getCategoryIcon(d.category)}
{d.fileName}
{d.status === 'downloading' || d.status === 'paused' ? (
{((d.fraction || 0) * 100).toFixed(1)}%
) : ( {d.size || '-'} )}
{d.status} {d.speed} {d.eta}
{d.dateAdded ? new Date(d.dateAdded).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }) : '-'}
{d.status === 'downloading' && ( )} {d.status === 'paused' && ( )}
{/* Status Bar */}
{downloads.length} Item{downloads.length !== 1 ? 's' : ''}
{/* Floating Context Menu */} {contextMenu && contextItem && (
e.stopPropagation()} > {contextItem.status === 'completed' && ( )}
{(contextItem.status === 'downloading' || contextItem.status === 'queued') && ( )} {(contextItem.status === 'paused' || contextItem.status === 'failed') && ( )} {['completed', 'failed', 'paused'].includes(contextItem.status) && ( )}
{contextItem.status === 'completed' && ( )}
)}
); };