mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-01-15 23:59:08 +00:00
feat: add snap scroll to horizontal lists
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
|||||||
type QueryKey,
|
type QueryKey,
|
||||||
useInfiniteQuery,
|
useInfiniteQuery,
|
||||||
} from "@tanstack/react-query";
|
} from "@tanstack/react-query";
|
||||||
|
import { useMemo } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
@@ -64,6 +65,11 @@ export const InfiniteScrollingCollectionList: React.FC<Props> = ({
|
|||||||
// Flatten all pages into a single array
|
// Flatten all pages into a single array
|
||||||
const allItems = data?.pages.flat() || [];
|
const allItems = data?.pages.flat() || [];
|
||||||
|
|
||||||
|
const snapOffsets = useMemo(() => {
|
||||||
|
const itemWidth = orientation === "horizontal" ? 184 : 120; // w-44 (176px) + mr-2 (8px) or w-28 (112px) + mr-2 (8px)
|
||||||
|
return allItems.map((_, index) => index * itemWidth);
|
||||||
|
}, [allItems, orientation]);
|
||||||
|
|
||||||
if (hideIfEmpty === true && allItems.length === 0 && !isLoading) return null;
|
if (hideIfEmpty === true && allItems.length === 0 && !isLoading) return null;
|
||||||
if (disabled || !title) return null;
|
if (disabled || !title) return null;
|
||||||
|
|
||||||
@@ -126,6 +132,8 @@ export const InfiniteScrollingCollectionList: React.FC<Props> = ({
|
|||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
onScroll={handleScroll}
|
onScroll={handleScroll}
|
||||||
scrollEventThrottle={16}
|
scrollEventThrottle={16}
|
||||||
|
snapToOffsets={snapOffsets}
|
||||||
|
decelerationRate='fast'
|
||||||
>
|
>
|
||||||
<View className='px-4 flex flex-row'>
|
<View className='px-4 flex flex-row'>
|
||||||
{allItems.map((item) => (
|
{allItems.map((item) => (
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
useQuery,
|
useQuery,
|
||||||
} from "@tanstack/react-query";
|
} from "@tanstack/react-query";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { useCallback } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { View, type ViewProps } from "react-native";
|
import { View, type ViewProps } from "react-native";
|
||||||
import { useInView } from "@/hooks/useInView";
|
import { useInView } from "@/hooks/useInView";
|
||||||
import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
|
import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
|
||||||
@@ -67,6 +67,12 @@ export const MediaListSection: React.FC<Props> = ({
|
|||||||
[api, user?.Id, collection?.Id],
|
[api, user?.Id, collection?.Id],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const snapOffsets = useMemo(() => {
|
||||||
|
const itemWidth = 120; // w-28 (112px) + mr-2 (8px)
|
||||||
|
// Generate offsets for a reasonable number of items
|
||||||
|
return Array.from({ length: 50 }, (_, index) => index * itemWidth);
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (!collection) return null;
|
if (!collection) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -92,6 +98,8 @@ export const MediaListSection: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
queryFn={fetchItems}
|
queryFn={fetchItems}
|
||||||
queryKey={["media-list", collection.Id!]}
|
queryKey={["media-list", collection.Id!]}
|
||||||
|
snapToOffsets={snapOffsets}
|
||||||
|
decelerationRate='fast'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user