chore: Apply linting rules and add git hok (#611)

Co-authored-by: Fredrik Burmester <fredrik.burmester@gmail.com>
This commit is contained in:
lostb1t
2025-03-16 18:01:12 +01:00
committed by GitHub
parent 2688e1b981
commit 92513e234f
268 changed files with 9197 additions and 8394 deletions

View File

@@ -2,7 +2,7 @@ import { Text } from "@/components/common/Text";
import { useDownload } from "@/providers/DownloadProvider";
import { DownloadMethod, useSettings } from "@/utils/atoms/settings";
import { storage } from "@/utils/mmkv";
import { JobStatus } from "@/utils/optimize-server";
import type { JobStatus } from "@/utils/optimize-server";
import { formatTimeString } from "@/utils/time";
import { Ionicons } from "@expo/vector-icons";
import { useMutation, useQueryClient } from "@tanstack/react-query";
@@ -14,9 +14,9 @@ import {
ActivityIndicator,
Platform,
TouchableOpacity,
TouchableOpacityProps,
type TouchableOpacityProps,
View,
ViewProps,
type ViewProps,
} from "react-native";
import { toast } from "sonner-native";
import { Button } from "../Button";
@@ -33,22 +33,22 @@ export const ActiveDownloads: React.FC<Props> = ({ ...props }) => {
const { processes } = useDownload();
if (processes?.length === 0)
return (
<View {...props} className="bg-neutral-900 p-4 rounded-2xl">
<Text className="text-lg font-bold">
<View {...props} className='bg-neutral-900 p-4 rounded-2xl'>
<Text className='text-lg font-bold'>
{t("home.downloads.active_download")}
</Text>
<Text className="opacity-50">
<Text className='opacity-50'>
{t("home.downloads.no_active_downloads")}
</Text>
</View>
);
return (
<View {...props} className="bg-neutral-900 p-4 rounded-2xl">
<Text className="text-lg font-bold mb-2">
<View {...props} className='bg-neutral-900 p-4 rounded-2xl'>
<Text className='text-lg font-bold mb-2'>
{t("home.downloads.active_downloads")}
</Text>
<View className="space-y-2">
<View className='space-y-2'>
{processes?.map((p: JobStatus) => (
<DownloadCard key={p.item.Id} process={p} />
))}
@@ -89,7 +89,7 @@ const DownloadCard = ({ process, ...props }: DownloadCardProps) => {
} else {
FFmpegKitProvider.FFmpegKit.cancel(Number(id));
setProcesses((prev: any[]) =>
prev.filter((p: { id: string }) => p.id !== id)
prev.filter((p: { id: string }) => p.id !== id),
);
}
},
@@ -117,7 +117,7 @@ const DownloadCard = ({ process, ...props }: DownloadCardProps) => {
return (
<TouchableOpacity
onPress={() => router.push(`/(auth)/items/page?id=${process.item.Id}`)}
className="relative bg-neutral-900 border border-neutral-800 rounded-2xl overflow-hidden"
className='relative bg-neutral-900 border border-neutral-800 rounded-2xl overflow-hidden'
{...props}
>
{(process.status === "optimizing" ||
@@ -133,10 +133,10 @@ const DownloadCard = ({ process, ...props }: DownloadCardProps) => {
}}
></View>
)}
<View className="px-3 py-1.5 flex flex-col w-full">
<View className="flex flex-row items-center w-full">
<View className='px-3 py-1.5 flex flex-col w-full'>
<View className='flex flex-row items-center w-full'>
{base64Image && (
<View className="w-14 aspect-[10/15] rounded-lg overflow-hidden mr-4">
<View className='w-14 aspect-[10/15] rounded-lg overflow-hidden mr-4'>
<Image
source={{
uri: `data:image/jpeg;base64,${base64Image}`,
@@ -149,51 +149,51 @@ const DownloadCard = ({ process, ...props }: DownloadCardProps) => {
/>
</View>
)}
<View className="shrink mb-1">
<Text className="text-xs opacity-50">{process.item.Type}</Text>
<Text className="font-semibold shrink">{process.item.Name}</Text>
<Text className="text-xs opacity-50">
<View className='shrink mb-1'>
<Text className='text-xs opacity-50'>{process.item.Type}</Text>
<Text className='font-semibold shrink'>{process.item.Name}</Text>
<Text className='text-xs opacity-50'>
{process.item.ProductionYear}
</Text>
<View className="flex flex-row items-center space-x-2 mt-1 text-purple-600">
<View className='flex flex-row items-center space-x-2 mt-1 text-purple-600'>
{process.progress === 0 ? (
<ActivityIndicator size={"small"} color={"white"} />
) : (
<Text className="text-xs">{process.progress.toFixed(0)}%</Text>
<Text className='text-xs'>{process.progress.toFixed(0)}%</Text>
)}
{process.speed && (
<Text className="text-xs">{process.speed?.toFixed(2)}x</Text>
<Text className='text-xs'>{process.speed?.toFixed(2)}x</Text>
)}
{eta(process) && (
<Text className="text-xs">
<Text className='text-xs'>
{t("home.downloads.eta", { eta: eta(process) })}
</Text>
)}
</View>
<View className="flex flex-row items-center space-x-2 mt-1 text-purple-600">
<Text className="text-xs capitalize">{process.status}</Text>
<View className='flex flex-row items-center space-x-2 mt-1 text-purple-600'>
<Text className='text-xs capitalize'>{process.status}</Text>
</View>
</View>
<TouchableOpacity
disabled={cancelJobMutation.isPending}
onPress={() => cancelJobMutation.mutate(process.id)}
className="ml-auto"
className='ml-auto'
>
{cancelJobMutation.isPending ? (
<ActivityIndicator size="small" color="white" />
<ActivityIndicator size='small' color='white' />
) : (
<Ionicons name="close" size={24} color="red" />
<Ionicons name='close' size={24} color='red' />
)}
</TouchableOpacity>
</View>
{process.status === "completed" && (
<View className="flex flex-row mt-4 space-x-4">
<View className='flex flex-row mt-4 space-x-4'>
<Button
onPress={() => {
startDownload(process);
}}
className="w-full"
className='w-full'
>
Download now
</Button>

View File

@@ -1,8 +1,9 @@
import { Text } from "@/components/common/Text";
import { useDownload } from "@/providers/DownloadProvider";
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import React, { useEffect, useMemo, useState } from "react";
import { TextProps } from "react-native";
import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import type React from "react";
import { useEffect, useMemo, useState } from "react";
import type { TextProps } from "react-native";
interface DownloadSizeProps extends TextProps {
items: BaseItemDto[];
@@ -39,7 +40,7 @@ export const DownloadSize: React.FC<DownloadSizeProps> = ({
return (
<>
<Text className="text-xs text-neutral-500" {...props}>
<Text className='text-xs text-neutral-500' {...props}>
{sizeText}
</Text>
</>

View File

@@ -1,22 +1,27 @@
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { useHaptic } from "@/hooks/useHaptic";
import React, { useCallback, useMemo } from "react";
import { TouchableOpacity, TouchableOpacityProps, View } from "react-native";
import {
ActionSheetProvider,
useActionSheet,
} from "@expo/react-native-action-sheet";
import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import type React from "react";
import { useCallback, useMemo } from "react";
import {
TouchableOpacity,
type TouchableOpacityProps,
View,
} from "react-native";
import { Text } from "@/components/common/Text";
import { DownloadSize } from "@/components/downloads/DownloadSize";
import { useDownloadedFileOpener } from "@/hooks/useDownloadedFileOpener";
import { useDownload } from "@/providers/DownloadProvider";
import { storage } from "@/utils/mmkv";
import { Image } from "expo-image";
import { Ionicons } from "@expo/vector-icons";
import { Text } from "@/components/common/Text";
import { runtimeTicksToSeconds } from "@/utils/time";
import { DownloadSize } from "@/components/downloads/DownloadSize";
import { TouchableItemRouter } from "../common/TouchableItemRouter";
import { Ionicons } from "@expo/vector-icons";
import { Image } from "expo-image";
import ContinueWatchingPoster from "../ContinueWatchingPoster";
import { TouchableItemRouter } from "../common/TouchableItemRouter";
interface EpisodeCardProps extends TouchableOpacityProps {
item: BaseItemDto;
@@ -67,7 +72,7 @@ export const EpisodeCard: React.FC<EpisodeCardProps> = ({ item, ...props }) => {
// Cancelled
break;
}
}
},
);
}, [showActionSheetWithOptions, handleDeleteFile]);
@@ -76,27 +81,27 @@ export const EpisodeCard: React.FC<EpisodeCardProps> = ({ item, ...props }) => {
onPress={handleOpenFile}
onLongPress={showActionSheet}
key={item.Id}
className="flex flex-col mb-4"
className='flex flex-col mb-4'
>
<View className="flex flex-row items-start mb-2">
<View className="mr-2">
<ContinueWatchingPoster size="small" item={item} useEpisodePoster />
<View className='flex flex-row items-start mb-2'>
<View className='mr-2'>
<ContinueWatchingPoster size='small' item={item} useEpisodePoster />
</View>
<View className="shrink">
<Text numberOfLines={2} className="">
<View className='shrink'>
<Text numberOfLines={2} className=''>
{item.Name}
</Text>
<Text numberOfLines={1} className="text-xs text-neutral-500">
<Text numberOfLines={1} className='text-xs text-neutral-500'>
{`S${item.ParentIndexNumber?.toString()}:E${item.IndexNumber?.toString()}`}
</Text>
<Text className="text-xs text-neutral-500">
<Text className='text-xs text-neutral-500'>
{runtimeTicksToSeconds(item.RunTimeTicks)}
</Text>
<DownloadSize items={[item]} />
</View>
</View>
<Text numberOfLines={3} className="text-xs text-neutral-500 shrink">
<Text numberOfLines={3} className='text-xs text-neutral-500 shrink'>
{item.Overview}
</Text>
</TouchableOpacity>
@@ -105,7 +110,7 @@ export const EpisodeCard: React.FC<EpisodeCardProps> = ({ item, ...props }) => {
// Wrap the parent component with ActionSheetProvider
export const EpisodeCardWithActionSheet: React.FC<EpisodeCardProps> = (
props
props,
) => (
<ActionSheetProvider>
<EpisodeCard {...props} />

View File

@@ -1,10 +1,11 @@
import { useHaptic } from "@/hooks/useHaptic";
import {
ActionSheetProvider,
useActionSheet,
} from "@expo/react-native-action-sheet";
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { useHaptic } from "@/hooks/useHaptic";
import React, { useCallback, useMemo } from "react";
import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import type React from "react";
import { useCallback, useMemo } from "react";
import { TouchableOpacity, View } from "react-native";
import { DownloadSize } from "@/components/downloads/DownloadSize";
@@ -69,14 +70,14 @@ export const MovieCard: React.FC<MovieCardProps> = ({ item }) => {
// Cancelled
break;
}
}
},
);
}, [showActionSheetWithOptions, handleDeleteFile]);
return (
<TouchableOpacity onPress={handleOpenFile} onLongPress={showActionSheet}>
{base64Image ? (
<View className="w-28 aspect-[10/15] rounded-lg overflow-hidden mr-2 border border-neutral-900">
<View className='w-28 aspect-[10/15] rounded-lg overflow-hidden mr-2 border border-neutral-900'>
<Image
source={{
uri: `data:image/jpeg;base64,${base64Image}`,
@@ -89,16 +90,16 @@ export const MovieCard: React.FC<MovieCardProps> = ({ item }) => {
/>
</View>
) : (
<View className="w-28 aspect-[10/15] rounded-lg bg-neutral-900 mr-2 flex items-center justify-center">
<View className='w-28 aspect-[10/15] rounded-lg bg-neutral-900 mr-2 flex items-center justify-center'>
<Ionicons
name="image-outline"
name='image-outline'
size={24}
color="gray"
className="self-center mt-16"
color='gray'
className='self-center mt-16'
/>
</View>
)}
<View className="w-28">
<View className='w-28'>
<ItemCardText item={item} />
</View>
<DownloadSize items={[item]} />

View File

@@ -1,16 +1,17 @@
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import {TouchableOpacity, View} from "react-native";
import { DownloadSize } from "@/components/downloads/DownloadSize";
import { useDownload } from "@/providers/DownloadProvider";
import { storage } from "@/utils/mmkv";
import { useActionSheet } from "@expo/react-native-action-sheet";
import { Ionicons } from "@expo/vector-icons";
import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { Image } from "expo-image";
import { router } from "expo-router";
import type React from "react";
import { useCallback, useMemo } from "react";
import { TouchableOpacity, View } from "react-native";
import { Text } from "../common/Text";
import React, {useCallback, useMemo} from "react";
import {storage} from "@/utils/mmkv";
import {Image} from "expo-image";
import {Ionicons} from "@expo/vector-icons";
import {router} from "expo-router";
import {DownloadSize} from "@/components/downloads/DownloadSize";
import {useDownload} from "@/providers/DownloadProvider";
import {useActionSheet} from "@expo/react-native-action-sheet";
export const SeriesCard: React.FC<{ items: BaseItemDto[] }> = ({items}) => {
export const SeriesCard: React.FC<{ items: BaseItemDto[] }> = ({ items }) => {
const { deleteItems } = useDownload();
const { showActionSheetWithOptions } = useActionSheet();
@@ -18,16 +19,14 @@ export const SeriesCard: React.FC<{ items: BaseItemDto[] }> = ({items}) => {
return storage.getString(items[0].SeriesId!);
}, []);
const deleteSeries = useCallback(
async () => deleteItems(items),
[items]
);
const deleteSeries = useCallback(async () => deleteItems(items), [items]);
const showActionSheet = useCallback(() => {
const options = ["Delete", "Cancel"];
const destructiveButtonIndex = 0;
showActionSheetWithOptions({
showActionSheetWithOptions(
{
options,
destructiveButtonIndex,
},
@@ -35,7 +34,7 @@ export const SeriesCard: React.FC<{ items: BaseItemDto[] }> = ({items}) => {
if (selectedIndex == destructiveButtonIndex) {
deleteSeries();
}
}
},
);
}, [showActionSheetWithOptions, deleteSeries]);
@@ -45,7 +44,7 @@ export const SeriesCard: React.FC<{ items: BaseItemDto[] }> = ({items}) => {
onLongPress={showActionSheet}
>
{base64Image ? (
<View className="w-28 aspect-[10/15] rounded-lg overflow-hidden mr-2 border border-neutral-900">
<View className='w-28 aspect-[10/15] rounded-lg overflow-hidden mr-2 border border-neutral-900'>
<Image
source={{
uri: `data:image/jpeg;base64,${base64Image}`,
@@ -56,25 +55,26 @@ export const SeriesCard: React.FC<{ items: BaseItemDto[] }> = ({items}) => {
resizeMode: "cover",
}}
/>
<View
className="bg-purple-600 rounded-full h-6 w-6 flex items-center justify-center absolute bottom-1 right-1">
<Text className="text-xs font-bold">{items.length}</Text>
<View className='bg-purple-600 rounded-full h-6 w-6 flex items-center justify-center absolute bottom-1 right-1'>
<Text className='text-xs font-bold'>{items.length}</Text>
</View>
</View>
) : (
<View className="w-28 aspect-[10/15] rounded-lg bg-neutral-900 mr-2 flex items-center justify-center">
<View className='w-28 aspect-[10/15] rounded-lg bg-neutral-900 mr-2 flex items-center justify-center'>
<Ionicons
name="image-outline"
name='image-outline'
size={24}
color="gray"
className="self-center mt-16"
color='gray'
className='self-center mt-16'
/>
</View>
)}
<View className="w-28 mt-2 flex flex-col">
<Text numberOfLines={2} className="">{items[0].SeriesName}</Text>
<Text className="text-xs opacity-50">{items[0].ProductionYear}</Text>
<View className='w-28 mt-2 flex flex-col'>
<Text numberOfLines={2} className=''>
{items[0].SeriesName}
</Text>
<Text className='text-xs opacity-50'>{items[0].ProductionYear}</Text>
<DownloadSize items={items} />
</View>
</TouchableOpacity>