import type { ReactNode } from 'react';
import type { StatsBucket } from './shared';
import { ArrowDownToLine, ArrowUpFromLine, HardDrive, Loader2 } from 'lucide-react';
import { formatDuration, formatRatio, formatSize, formatSpeed } from './format';
import { useFreeSpace, useSession, useSessionStats, useTorrents } from './useTransmissionData';
// Session statistics. Two columns because Transmission keeps two counters and conflating them is a classic
// misreading — "this session" resets when the daemon restarts, "all time" never does.
export const StatsView = () => {
const { stats, isLoading } = useSessionStats();
const { session } = useSession();
const { torrents } = useTorrents();
const downloadDir = session?.['download-dir'];
const { bytes: freeBytes } = useFreeSpace(downloadDir);
if (isLoading && !stats) {
return (
Loading statistics…
);
}
if (!stats) {
return No statistics.
;
}
const totalSize = torrents.reduce((sum, t) => sum + (t.totalSize ?? 0), 0);
const onDisk = torrents.reduce((sum, t) => sum + (t.haveValid ?? 0), 0);
return (
}
label="Download"
value={formatSpeed(stats.downloadSpeed) || '0 B/s'}
/>
}
label="Upload"
value={formatSpeed(stats.uploadSpeed) || '0 B/s'}
/>
}
label="Free space"
value={freeBytes == null ? '—' : formatSize(freeBytes)}
hint={downloadDir}
/>
Local library
{/* haveValid, not totalSize: an unfinished or partially-wanted torrent occupies less than it
claims, and the difference is the whole reason to look. */}
);
};
const Bucket = ({ title, bucket }: { title: string; bucket: StatsBucket }) => (
{title}
0 ? bucket.uploadedBytes / bucket.downloadedBytes : -1)}
/>
);
type TileProps = { label: string; value: string; hint?: string; icon?: ReactNode };
const Tile = ({ label, value, hint, icon }: TileProps) => (
{icon}
{label}
{value}
{hint && (
{hint}
)}
);
const Row = ({ label, value }: { label: string; value: string }) => (
{label}
{value}
);