import { getItemsApi } from "@jellyfin/sdk/lib/utils/api"; import { useRoute } from "@react-navigation/native"; import { FlashList } from "@shopify/flash-list"; import { useInfiniteQuery } from "@tanstack/react-query"; import { useLocalSearchParams } from "expo-router"; import { useAtom } from "jotai"; import { useCallback, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { Dimensions, RefreshControl, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Text } from "@/components/common/Text"; import { Loader } from "@/components/Loader"; import { MusicAlbumCard } from "@/components/music/MusicAlbumCard"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; const ITEMS_PER_PAGE = 40; export default function AlbumsScreen() { const localParams = useLocalSearchParams<{ libraryId?: string | string[] }>(); const route = useRoute(); const libraryId = (Array.isArray(localParams.libraryId) ? localParams.libraryId[0] : localParams.libraryId) ?? route?.params?.libraryId; const [api] = useAtom(apiAtom); const [user] = useAtom(userAtom); const insets = useSafeAreaInsets(); const { t } = useTranslation(); const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage, refetch, } = useInfiniteQuery({ queryKey: ["music-albums", libraryId, user?.Id], queryFn: async ({ pageParam = 0 }) => { const response = await getItemsApi(api!).getItems({ userId: user?.Id, parentId: libraryId, includeItemTypes: ["MusicAlbum"], sortBy: ["SortName"], sortOrder: ["Ascending"], limit: ITEMS_PER_PAGE, startIndex: pageParam, recursive: true, }); return { items: response.data.Items || [], totalCount: response.data.TotalRecordCount || 0, startIndex: pageParam, }; }, getNextPageParam: (lastPage) => { const nextStart = lastPage.startIndex + ITEMS_PER_PAGE; return nextStart < lastPage.totalCount ? nextStart : undefined; }, initialPageParam: 0, enabled: !!api && !!user?.Id && !!libraryId, }); const albums = useMemo(() => { return data?.pages.flatMap((page) => page.items) || []; }, [data]); const numColumns = 2; const screenWidth = Dimensions.get("window").width; const gap = 12; const padding = 16; const itemWidth = (screenWidth - padding * 2 - gap * (numColumns - 1)) / numColumns; const handleEndReached = useCallback(() => { if (hasNextPage && !isFetchingNextPage) { fetchNextPage(); } }, [hasNextPage, isFetchingNextPage, fetchNextPage]); if (isLoading) { return ( ); } if (albums.length === 0) { return ( {t("music.no_albums")} ); } return ( } onEndReached={handleEndReached} onEndReachedThreshold={0.5} renderItem={({ item, index }) => ( )} keyExtractor={(item) => item.Id!} ListFooterComponent={ isFetchingNextPage ? ( ) : null } /> ); }