import { Ionicons } from "@expo/vector-icons";
import { useQueryClient } from "@tanstack/react-query";
import { Image } from "expo-image";
import { useRouter } from "expo-router";
import { t } from "i18next";
import { useMemo } from "react";
import {
ActivityIndicator,
TouchableOpacity,
type TouchableOpacityProps,
View,
} from "react-native";
import { toast } from "sonner-native";
import { Text } from "@/components/common/Text";
import { useDownload } from "@/providers/DownloadProvider";
import { JobStatus } from "@/providers/Downloads/types";
import { storage } from "@/utils/mmkv";
import { formatTimeString } from "@/utils/time";
import { Button } from "../Button";
const bytesToMB = (bytes: number) => {
return bytes / 1024 / 1024;
};
interface ActiveDownloadsProps extends TouchableOpacityProps {}
export default function ActiveDownloads({ ...props }: ActiveDownloadsProps) {
const { processes } = useDownload();
if (processes?.length === 0)
return (
{t("home.downloads.active_download")}
{t("home.downloads.no_active_downloads")}
);
return (
{t("home.downloads.active_downloads")}
{processes?.map((p: JobStatus) => (
))}
);
}
interface DownloadCardProps extends TouchableOpacityProps {
process: JobStatus;
}
const DownloadCard = ({ process, ...props }: DownloadCardProps) => {
const { startDownload, pauseDownload, resumeDownload, removeProcess } =
useDownload();
const router = useRouter();
const queryClient = useQueryClient();
const handlePause = async (id: string) => {
try {
await pauseDownload(id);
toast.success(t("home.downloads.toasts.download_paused"));
} catch (error) {
console.error("Error pausing download:", error);
toast.error(t("home.downloads.toasts.could_not_pause_download"));
}
};
const handleResume = async (id: string) => {
try {
await resumeDownload(id);
toast.success(t("home.downloads.toasts.download_resumed"));
} catch (error) {
console.error("Error resuming download:", error);
toast.error(t("home.downloads.toasts.could_not_resume_download"));
}
};
const handleDelete = async (id: string) => {
try {
await removeProcess(id);
toast.success(t("home.downloads.toasts.download_deleted"));
queryClient.invalidateQueries({ queryKey: ["downloads"] });
} catch (error) {
console.error("Error deleting download:", error);
toast.error(t("home.downloads.toasts.could_not_delete_download"));
}
};
const eta = (p: JobStatus) => {
if (!p.speed || p.speed <= 0 || !p.estimatedTotalSizeBytes) return null;
const bytesRemaining = p.estimatedTotalSizeBytes - (p.bytesDownloaded || 0);
if (bytesRemaining <= 0) return null;
const secondsRemaining = bytesRemaining / p.speed;
return formatTimeString(secondsRemaining, "s");
};
const base64Image = useMemo(() => {
return storage.getString(process.item.Id!);
}, []);
return (
router.push(`/(auth)/items/page?id=${process.item.Id}`)}
className='relative bg-neutral-900 border border-neutral-800 rounded-2xl overflow-hidden'
{...props}
>
{process.status === "downloading" && (
)}
{base64Image && (
)}
{process.item.Type}
{process.item.Name}
{process.item.ProductionYear}
{process.progress === 0 ? (
) : (
{process.progress.toFixed(0)}%
)}
{process.speed && process.speed > 0 && (
{bytesToMB(process.speed).toFixed(2)} MB/s
)}
{eta(process) && (
{t("home.downloads.eta", { eta: eta(process) })}
)}
{process.status}
{process.status === "downloading" && (
handlePause(process.id)}
className='p-2 rounded-full bg-yellow-600'
>
)}
{process.status === "paused" && (
handleResume(process.id)}
className='p-2 rounded-full bg-green-600'
>
)}
handleDelete(process.id)}
className='p-2 rounded-full bg-red-600'
>
{process.status === "completed" && (
)}
);
};