import type { NativeSyntheticEvent } from "react-native"; import type { ContextMenuOnPressNativeEvent } from "react-native-context-menu-view"; import React from "react"; import ContextMenu from "react-native-context-menu-view"; import { TouchableOpacity } from "react-native-gesture-handler"; import { Image, Text, View, XStack, YStack } from "tamagui"; import type { Download } from "~/contexts/DownloadManagerContext"; import { useDownloadManager } from "~/contexts/DownloadManagerContext"; import { MWProgress } from "./ui/Progress"; import { FlashingText } from "./ui/Text"; export interface DownloadItemProps { item: Download; onPress: (localPath?: string) => void; } enum ContextMenuActions { Cancel = "Cancel", Remove = "Remove", } const statusToTextMap: Record = { downloading: "Downloading", finished: "Finished", error: "Error", merging: "Merging", cancelled: "Cancelled", importing: "Importing", }; const formatBytes = (bytes: number, decimals = 2) => { if (bytes === 0) return "0 Bytes"; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]; }; export function DownloadItem(props: DownloadItemProps) { const percentage = props.item.progress * 100; const formattedFileSize = formatBytes(props.item.fileSize); const formattedDownloaded = formatBytes(props.item.downloaded); const { removeDownload, cancelDownload } = useDownloadManager(); const contextMenuActions = [ { title: ContextMenuActions.Remove, }, ...(props.item.status !== "finished" ? [{ title: ContextMenuActions.Cancel }] : []), ]; const onContextMenuPress = ( e: NativeSyntheticEvent, ) => { if (e.nativeEvent.name === ContextMenuActions.Cancel) { void cancelDownload(props.item.id); } else if (e.nativeEvent.name === ContextMenuActions.Remove) { removeDownload(props.item.id); } }; const isInProgress = !( props.item.status === "finished" || props.item.status === "error" || props.item.status === "cancelled" ); return ( props.onPress(props.item.localPath)} onLongPress={() => { return; }} activeOpacity={0.7} > {props.item.media.title} {props.item.type !== "hls" && ( {props.item.speed.toFixed(2)} MB/s )} {props.item.type === "hls" ? `${percentage.toFixed()}% - ${props.item.downloaded} of ${props.item.fileSize} segments` : `${percentage.toFixed()}% - ${formattedDownloaded} of ${formattedFileSize}`} {statusToTextMap[props.item.status]} ); }