import type { ReactElement } from "react"; import { RollingMetricValue } from "../../ui/RollingMetricValue"; import { SlidingSelection } from "../../ui/SlidingSelection"; import type { DownloadPackageRow, DownloadsViewModelCore, DownloadDisplayMode, DownloadSidebarFilter } from "./downloads-model"; import { DownloadsTableHeader, ItemRow, PackageCard, type DownloadSortColumn, type DownloadsTableActions } from "./DownloadsTable"; import "./downloads.css"; export interface DownloadsStatusModel { packages: number; links: number; session: string; sessionBytes: number; total: string; totalBytes: number; hosters: number; speed: string; eta: string; } export interface DownloadsViewModel extends DownloadsViewModelCore { running: boolean; paused: boolean; canStart: boolean; canPause: boolean; canStop: boolean; actionBusy: boolean; reconnectSeconds: number; reconnectReason: string; clipboardWatcher: boolean; scheduleActive: boolean; scheduleOpen: boolean; scheduleTime: string; scheduleLabel: string; packageSpeedBps: Record; editingPackageId: string | null; editingName: string; columnOrder: readonly string[]; gridTemplate: string; sortColumn?: DownloadSortColumn; sortDirection?: "asc" | "desc"; status: DownloadsStatusModel; } export interface DownloadsViewActions extends DownloadsTableActions { onDisplayModeChange: (mode: DownloadDisplayMode) => void; onFilterChange: (filter: DownloadSidebarFilter) => void; onProviderFilterChange: (provider: string) => void; onQueryChange: (query: string) => void; onAddLinks: () => void; onStartDownloads: () => void; onPauseDownloads: () => void; onStopDownloads: () => void; onToggleSchedule: () => void; onScheduleTimeChange: (value: string) => void; onActivateSchedule: () => void; onCancelSchedule: () => void; onMoveSelectionUp: () => void; onMoveSelectionDown: () => void; onRenameSelection: () => void; onRemoveSelection: () => void; onToggleClipboardWatcher: () => void; onClearAll: () => void; onToggleAllPackages: () => void; onShowAllPackages: () => void; onPackageDragStart: (packageId: string) => void; onPackageDrop: (packageId: string) => void; onPackageDragEnd: () => void; } const filters: Array<{ id: DownloadSidebarFilter; label: string }> = [ { id: "all", label: "Alle" }, { id: "active", label: "Aktiv" }, { id: "queued", label: "Wartend" }, { id: "paused", label: "Pausiert" }, { id: "completed", label: "Fertig" }, { id: "failed", label: "Fehler" } ]; export function DownloadsSidebar({ actions, model }: { actions: DownloadsViewActions; model: DownloadsViewModel }): ReactElement { return ( ); } export function DownloadsSidebarStatus({ model }: { model: DownloadsViewModel }): ReactElement { const speed = model.status.speed.replace(/^Geschwindigkeit:\s*/i, ""); const eta = model.status.eta.replace(/^ETA:\s*/i, ""); const entries = [ { label: "Pakete", metric: "packages", numericValue: model.status.packages, value: String(model.status.packages) }, { label: "Links", metric: "links", numericValue: model.status.links, value: String(model.status.links) }, { label: "Sitzung", metric: "session", numericValue: model.status.sessionBytes, value: model.status.session }, { label: "Gesamt", metric: "total", numericValue: model.status.totalBytes, value: model.status.total }, { label: "Hoster", metric: "hosters", numericValue: model.status.hosters, value: String(model.status.hosters) } ]; return
{entries.map((entry) =>
{entry.label}
)}
Geschwindigkeit{speed}
ETA{eta}
; } export function DownloadsToolbar({ actions, model }: { actions: DownloadsViewActions; model: DownloadsViewModel }): ReactElement { const hasSelection = model.actionableSelectedIds.length > 0; const hasSelectedPackage = model.actionableSelectedPackageIds.length > 0; const onePackage = model.actionableSelectedPackageIds.length === 1 && model.actionableSelectedIds.length === 1; return (
{model.scheduleActive ? Geplant: {model.scheduleLabel} : <>{model.scheduleOpen ? actions.onScheduleTimeChange(event.target.value)} type="time" value={model.scheduleTime} /> : null}}
); } function tableState(model: DownloadsViewModel): ReactElement | null { if (model.empty) return
Noch keine DownloadsFüge Links hinzu, um den ersten Download zu starten.
; if (model.filteredEmpty) return
Keine passenden DownloadsPasse Filter oder Suche an.
; return null; } function packageRows(model: DownloadsViewModel, actions: DownloadsViewActions): ReactElement[] { return model.packageRows.map((row: DownloadPackageRow) => ( )); } export function DownloadsContent({ actions, model }: { actions: DownloadsViewActions; model: DownloadsViewModel }): ReactElement { return (
{tableState(model)} {!model.empty && !model.filteredEmpty && model.displayMode === "packages" ? packageRows(model, actions) : null} {!model.empty && !model.filteredEmpty && model.displayMode === "files" ? model.fileRows.map((item) => ) : null}
); } export function DownloadsFooter({ actions, model }: { actions: DownloadsViewActions; model: DownloadsViewModel }): ReactElement { return (
{model.paginationLabel} {model.limited ? : null} {model.running ? model.paused ? "Pausiert" : "Download läuft" : "Bereit"}
); } export function DownloadsView({ actions, model }: { actions: DownloadsViewActions; model: DownloadsViewModel }): ReactElement { return (
); }