add episode download section

This commit is contained in:
Jorrin
2024-04-08 21:22:09 +02:00
parent ae5505da7f
commit 96b00064c6
10 changed files with 263 additions and 105 deletions

View File

@@ -3,10 +3,12 @@ import type { ContextMenuOnPressNativeEvent } from "react-native-context-menu-vi
import React from "react";
import ContextMenu from "react-native-context-menu-view";
import { TouchableOpacity } from "react-native-gesture-handler";
import { useRouter } from "expo-router";
import { Image, Text, View, XStack, YStack } from "tamagui";
import type { Download } from "~/hooks/useDownloadManager";
import type { Download, DownloadContent } from "~/hooks/useDownloadManager";
import { useDownloadManager } from "~/hooks/useDownloadManager";
import { mapSeasonAndEpisodeNumberToText } from "./player/utils";
import { MWProgress } from "./ui/Progress";
import { FlashingText } from "./ui/Text";
@@ -101,6 +103,11 @@ export function DownloadItem(props: DownloadItemProps) {
<YStack gap="$2">
<XStack gap="$6" maxWidth="65%">
<Text fontWeight="$bold" ellipse flexGrow={1}>
{props.item.media.type === "show" &&
mapSeasonAndEpisodeNumberToText(
props.item.media.season.number,
props.item.media.episode.number,
) + " "}
{props.item.media.title}
</Text>
{props.item.type !== "hls" && (
@@ -136,3 +143,54 @@ export function DownloadItem(props: DownloadItemProps) {
</ContextMenu>
);
}
export function ShowDownloadItem({ download }: { download: DownloadContent }) {
const router = useRouter();
return (
<TouchableOpacity
onPress={() =>
router.push({
pathname: "/(downloads)/[tmdbId]",
params: { tmdbId: download.media.tmdbId },
})
}
activeOpacity={0.7}
>
<XStack gap="$4" alignItems="center">
<View
aspectRatio={9 / 14}
width={70}
maxHeight={180}
overflow="hidden"
borderRadius="$2"
>
<Image
source={{
uri: "https://image.tmdb.org/t/p/original//or06FN3Dka5tukK1e9sl16pB3iy.jpg",
}}
width="100%"
height="100%"
/>
</View>
<YStack gap="$2">
<YStack gap="$1">
<Text fontWeight="$bold" ellipse flexGrow={1} fontSize="$5">
{download.media.title}
</Text>
<Text fontSize="$2">
{download.downloads.length} Episode
{download.downloads.length > 1 ? "s" : ""} |{" "}
{formatBytes(
download.downloads.reduce(
(acc, curr) => acc + curr.fileSize,
0,
),
)}
</Text>
</YStack>
</YStack>
</XStack>
</TouchableOpacity>
);
}

View File

@@ -124,6 +124,7 @@ export default function Item({ data }: { data: ItemData }) {
width="100%"
overflow="hidden"
borderRadius={24}
height="$14"
>
<Image source={{ uri: posterUrl }} width="100%" height="100%" />
</View>

View File

@@ -1,5 +1,4 @@
import { Linking } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import * as Haptics from "expo-haptics";
import { FontAwesome6, MaterialIcons } from "@expo/vector-icons";
import { Circle, View } from "tamagui";
@@ -8,20 +7,13 @@ import { DISCORD_LINK, GITHUB_LINK } from "~/constants/core";
import { BrandPill } from "../BrandPill";
export function Header() {
const insets = useSafeAreaInsets();
return (
<View
paddingTop={insets.top}
alignItems="center"
gap="$3"
flexDirection="row"
>
<View alignItems="center" gap="$3" flexDirection="row">
<BrandPill />
<Circle
backgroundColor="$pillBackground"
size="$4.5"
size="$3.5"
pressStyle={{
opacity: 1,
scale: 1.05,
@@ -33,11 +25,11 @@ export function Header() {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy)
}
>
<MaterialIcons name="discord" size={32} color="white" />
<MaterialIcons name="discord" size={28} color="white" />
</Circle>
<Circle
backgroundColor="$pillBackground"
size="$4.5"
size="$3.5"
pressStyle={{
opacity: 1,
scale: 1.05,
@@ -49,7 +41,7 @@ export function Header() {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy)
}
>
<FontAwesome6 name="github" size={32} color="white" />
<FontAwesome6 name="github" size={28} color="white" />
</Circle>
</View>
);

View File

@@ -1,3 +1,4 @@
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { ScrollView } from "tamagui";
import { LinearGradient } from "tamagui/linear-gradient";
@@ -7,6 +8,7 @@ interface Props {
children?: React.ReactNode;
onScrollBeginDrag?: () => void;
onMomentumScrollEnd?: () => void;
showHeader?: boolean;
scrollEnabled?: boolean;
keyboardDismissMode?: "none" | "on-drag" | "interactive";
keyboardShouldPersistTaps?: "always" | "never" | "handled";
@@ -17,11 +19,14 @@ export default function ScreenLayout({
children,
onScrollBeginDrag,
onMomentumScrollEnd,
showHeader = true,
scrollEnabled,
keyboardDismissMode,
keyboardShouldPersistTaps,
contentContainerStyle,
}: Props) {
const insets = useSafeAreaInsets();
return (
<LinearGradient
flex={1}
@@ -38,8 +43,9 @@ export default function ScreenLayout({
start={[0, 0]}
end={[1, 1]}
flexGrow={1}
paddingTop={showHeader ? insets.top : insets.top + 50}
>
<Header />
{showHeader && <Header />}
<ScrollView
onScrollBeginDrag={onScrollBeginDrag}
onMomentumScrollEnd={onMomentumScrollEnd}

View File

@@ -4,10 +4,7 @@ import { usePlayerStore } from "~/stores/player/store";
import { BrandPill } from "../BrandPill";
import { BackButton } from "./BackButton";
import { Controls } from "./Controls";
const mapSeasonAndEpisodeNumberToText = (season: number, episode: number) => {
return `S${season.toString().padStart(2, "0")}E${episode.toString().padStart(2, "0")}`;
};
import { mapSeasonAndEpisodeNumberToText } from "./utils";
export const Header = () => {
const isIdle = usePlayerStore((state) => state.interface.isIdle);

View File

@@ -16,3 +16,10 @@ export const mapMillisecondsToTime = (milliseconds: number): string => {
return formattedTime;
};
export const mapSeasonAndEpisodeNumberToText = (
season: number,
episode: number,
) => {
return `S${season.toString().padStart(2, "0")}E${episode.toString().padStart(2, "0")}`;
};