import { Ionicons } from "@expo/vector-icons"; import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; import { FlashList } from "@shopify/flash-list"; import { useLocalSearchParams, useNavigation, useRouter } from "expo-router"; import { useAtomValue } from "jotai"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { ActivityIndicator, Alert, RefreshControl, TouchableOpacity, useWindowDimensions, View, } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { HeaderBackButton } from "@/components/common/HeaderBackButton"; import { Text } from "@/components/common/Text"; import { TouchableItemRouter } from "@/components/common/TouchableItemRouter"; import { ItemCardText } from "@/components/ItemCardText"; import { ItemPoster } from "@/components/posters/ItemPoster"; import { useOrientation } from "@/hooks/useOrientation"; import { useDeleteWatchlist, useRemoveFromWatchlist, } from "@/hooks/useWatchlistMutations"; import { useWatchlistDetailQuery, useWatchlistItemsQuery, } from "@/hooks/useWatchlists"; import * as ScreenOrientation from "@/packages/expo-screen-orientation"; import { userAtom } from "@/providers/JellyfinProvider"; export default function WatchlistDetailScreen() { const { t } = useTranslation(); const router = useRouter(); const navigation = useNavigation(); const insets = useSafeAreaInsets(); const { watchlistId } = useLocalSearchParams<{ watchlistId: string }>(); const user = useAtomValue(userAtom); const { width: screenWidth } = useWindowDimensions(); const { orientation } = useOrientation(); const watchlistIdNum = watchlistId ? Number.parseInt(watchlistId, 10) : undefined; const nrOfCols = useMemo(() => { if (screenWidth < 300) return 2; if (screenWidth < 500) return 3; if (screenWidth < 800) return 5; if (screenWidth < 1000) return 6; if (screenWidth < 1500) return 7; return 6; }, [screenWidth]); const { data: watchlist, isLoading: watchlistLoading, refetch: refetchWatchlist, } = useWatchlistDetailQuery(watchlistIdNum); const { data: items, isLoading: itemsLoading, refetch: refetchItems, } = useWatchlistItemsQuery(watchlistIdNum); const deleteWatchlist = useDeleteWatchlist(); const removeFromWatchlist = useRemoveFromWatchlist(); const [refreshing, setRefreshing] = useState(false); const isOwner = useMemo( () => watchlist?.userId === user?.Id, [watchlist?.userId, user?.Id], ); // Set up header useEffect(() => { navigation.setOptions({ headerTitle: watchlist?.name || "", headerLeft: () => , headerRight: isOwner ? () => ( router.push(`/(auth)/(tabs)/(watchlists)/edit/${watchlistId}`) } className='p-2' > ) : undefined, }); }, [navigation, watchlist?.name, isOwner, watchlistId]); const handleRefresh = useCallback(async () => { setRefreshing(true); await Promise.all([refetchWatchlist(), refetchItems()]); setRefreshing(false); }, [refetchWatchlist, refetchItems]); const handleDelete = useCallback(() => { Alert.alert( t("watchlists.delete_confirm_title"), t("watchlists.delete_confirm_message", { name: watchlist?.name }), [ { text: t("watchlists.cancel_button"), style: "cancel" }, { text: t("watchlists.delete_button"), style: "destructive", onPress: async () => { if (watchlistIdNum) { await deleteWatchlist.mutateAsync(watchlistIdNum); router.back(); } }, }, ], ); }, [deleteWatchlist, watchlistIdNum, watchlist?.name, router, t]); const handleRemoveItem = useCallback( (item: BaseItemDto) => { if (!watchlistIdNum || !item.Id) return; Alert.alert( t("watchlists.remove_item_title"), t("watchlists.remove_item_message", { name: item.Name }), [ { text: t("watchlists.cancel_button"), style: "cancel" }, { text: t("watchlists.remove_button"), style: "destructive", onPress: async () => { await removeFromWatchlist.mutateAsync({ watchlistId: watchlistIdNum, itemId: item.Id!, watchlistName: watchlist?.name, }); }, }, ], ); }, [removeFromWatchlist, watchlistIdNum, watchlist?.name, t], ); const renderItem = useCallback( ({ item, index }: { item: BaseItemDto; index: number }) => ( handleRemoveItem(item) : undefined} > ), [isOwner, handleRemoveItem, orientation, nrOfCols], ); const ListHeader = useMemo( () => watchlist ? ( {watchlist.description && ( {watchlist.description} )} {items?.length ?? 0}{" "} {(items?.length ?? 0) === 1 ? t("watchlists.item") : t("watchlists.items")} {watchlist.isPublic ? t("watchlists.public") : t("watchlists.private")} {!isOwner && ( {t("watchlists.by_owner")} )} ) : null, [watchlist, items?.length, isOwner, t], ); const EmptyComponent = useMemo( () => ( {t("watchlists.empty_watchlist")} {isOwner && ( {t("watchlists.empty_watchlist_hint")} )} ), [isOwner, t], ); const keyExtractor = useCallback((item: BaseItemDto) => item.Id || "", []); if (watchlistLoading || itemsLoading) { return ( ); } if (!watchlist) { return ( {t("watchlists.not_found")} ); } return ( } renderItem={renderItem} ItemSeparatorComponent={() => ( )} /> ); }