mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add an infinite scroll on web and native
This commit is contained in:
parent
1cd418991c
commit
47ca25fe1c
@ -10,6 +10,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@kyoo/ui": "workspace:^",
|
||||
"@shopify/flash-list": "1.3.1",
|
||||
"@tanstack/react-query": "^4.19.1",
|
||||
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
|
||||
"expo": "^47.0.0",
|
||||
|
@ -13,6 +13,7 @@
|
||||
"typescript": "^4.9.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@shopify/flash-list": "^1.4.0",
|
||||
"@tanstack/react-query": "*",
|
||||
"expo-linear-gradient": "*",
|
||||
"i18next": "*",
|
||||
|
78
front/packages/ui/src/fetch-infinite.tsx
Normal file
78
front/packages/ui/src/fetch-infinite.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Kyoo - A portable and vast media library solution.
|
||||
* Copyright (c) Kyoo.
|
||||
*
|
||||
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
*
|
||||
* Kyoo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Kyoo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
||||
import { FlashList } from "@shopify/flash-list";
|
||||
import { ReactElement } from "react";
|
||||
import { ErrorView, WithLoading } from "./fetch";
|
||||
|
||||
export const InfiniteFetch = <Data,>({
|
||||
query,
|
||||
placeholderCount = 15,
|
||||
children,
|
||||
size,
|
||||
numColumns,
|
||||
...props
|
||||
}: {
|
||||
query: QueryIdentifier<Data>;
|
||||
placeholderCount?: number;
|
||||
numColumns: number;
|
||||
children: (
|
||||
item: Data extends Page<infer Item> ? WithLoading<Item> : WithLoading<Data>,
|
||||
key: string | undefined,
|
||||
i: number,
|
||||
) => ReactElement | null;
|
||||
size: number;
|
||||
}): JSX.Element | null => {
|
||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||
|
||||
const { items, error, fetchNextPage, hasNextPage, refetch, isRefetching } =
|
||||
useInfiniteFetch(query);
|
||||
|
||||
if (error) return <ErrorView error={error} />;
|
||||
|
||||
return (
|
||||
<FlashList
|
||||
renderItem={({ item, index }) =>
|
||||
children({ isLoading: false, ...item } as any, undefined, index)
|
||||
}
|
||||
data={
|
||||
hasNextPage
|
||||
? [
|
||||
...(items || []),
|
||||
...[
|
||||
...Array(
|
||||
items ? numColumns - (items.length % numColumns) + numColumns : placeholderCount,
|
||||
),
|
||||
].map((_, i) => ({ id: `gen${i}`, isLoading: true } as Data)),
|
||||
]
|
||||
: items
|
||||
}
|
||||
keyExtractor={(item: any) => item.id?.toString()}
|
||||
numColumns={numColumns}
|
||||
estimatedItemSize={size}
|
||||
onEndReached={fetchNextPage}
|
||||
onEndReachedThreshold={0.5}
|
||||
onRefresh={refetch}
|
||||
refreshing={isRefetching}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
69
front/packages/ui/src/fetch-infinite.web.tsx
Normal file
69
front/packages/ui/src/fetch-infinite.web.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Kyoo - A portable and vast media library solution.
|
||||
* Copyright (c) Kyoo.
|
||||
*
|
||||
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
*
|
||||
* Kyoo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Kyoo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
||||
import { ReactElement } from "react";
|
||||
import InfiniteScroll from "react-infinite-scroll-component";
|
||||
import { useYoshiki } from "yoshiki";
|
||||
import { ErrorView, WithLoading } from "./fetch";
|
||||
|
||||
export const InfiniteFetch = <Data,>({
|
||||
query,
|
||||
placeholderCount = 15,
|
||||
children,
|
||||
...props
|
||||
}: {
|
||||
query: QueryIdentifier<Data>;
|
||||
placeholderCount?: number;
|
||||
children: (
|
||||
item: Data extends Page<infer Item> ? WithLoading<Item> : WithLoading<Data>,
|
||||
key: string | undefined,
|
||||
i: number,
|
||||
) => ReactElement | null;
|
||||
}): JSX.Element | null => {
|
||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||
|
||||
const { items, error, fetchNextPage, hasNextPage } = useInfiniteFetch(query);
|
||||
const { css } = useYoshiki();
|
||||
|
||||
if (error) return <ErrorView error={error} />;
|
||||
|
||||
return (
|
||||
<InfiniteScroll
|
||||
dataLength={items?.length ?? 0}
|
||||
next={fetchNextPage}
|
||||
hasMore={hasNextPage!}
|
||||
loader={[...Array(12)].map((_, i) => children({ isLoading: true } as any, i.toString(), i))}
|
||||
{...css(
|
||||
{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "center",
|
||||
},
|
||||
props,
|
||||
)}
|
||||
>
|
||||
{items?.map((item, i) =>
|
||||
children({ ...item, isLoading: false } as any, (item as any).id?.toString(), i),
|
||||
)}
|
||||
</InfiniteScroll>
|
||||
);
|
||||
};
|
@ -18,7 +18,7 @@
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Page, QueryIdentifier, useFetch, KyooErrors, useInfiniteFetch } from "@kyoo/models";
|
||||
import { Page, QueryIdentifier, useFetch, KyooErrors } from "@kyoo/models";
|
||||
import { P } from "@kyoo/primitives";
|
||||
import { View } from "react-native";
|
||||
import { useYoshiki } from "yoshiki/native";
|
||||
@ -54,29 +54,6 @@ export const Fetch = <Data,>({
|
||||
return <>{data.items.map((item, i) => children({ ...item, isLoading: false } as any, i))}</>;
|
||||
};
|
||||
|
||||
export const InfiniteFetch = <Data,>({
|
||||
query,
|
||||
placeholderCount = 15,
|
||||
children,
|
||||
}: {
|
||||
query: QueryIdentifier<Data>;
|
||||
placeholderCount?: number;
|
||||
children: (
|
||||
item: Data extends Page<infer Item> ? WithLoading<Item> : WithLoading<Data>,
|
||||
i: number,
|
||||
) => JSX.Element | null;
|
||||
}): JSX.Element | null => {
|
||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||
const { items, error } = useInfiniteFetch(query);
|
||||
|
||||
if (error) return <ErrorView error={error} />;
|
||||
if (!items)
|
||||
return (
|
||||
<>{[...Array(placeholderCount)].map((_, i) => children({ isLoading: true } as any, i))}</>
|
||||
);
|
||||
return <>{items.map((item, i) => children({ ...item, isLoading: false } as any, i))}</>;
|
||||
};
|
||||
|
||||
export const ErrorView = ({ error }: { error: KyooErrors }) => {
|
||||
const { css } = useYoshiki();
|
||||
|
||||
|
@ -2326,6 +2326,7 @@ __metadata:
|
||||
react-native-svg: ^13.6.0
|
||||
typescript: ^4.9.3
|
||||
peerDependencies:
|
||||
"@shopify/flash-list": ^1.4.0
|
||||
"@tanstack/react-query": "*"
|
||||
expo-linear-gradient: "*"
|
||||
i18next: "*"
|
||||
@ -3141,6 +3142,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@shopify/flash-list@npm:1.3.1":
|
||||
version: 1.3.1
|
||||
resolution: "@shopify/flash-list@npm:1.3.1"
|
||||
dependencies:
|
||||
recyclerlistview: 4.1.2
|
||||
tslib: 2.4.0
|
||||
peerDependencies:
|
||||
"@babel/runtime": "*"
|
||||
react: "*"
|
||||
react-native: "*"
|
||||
checksum: 49a82512bf2b3622e1d7f1a86dc2837f7ee8809131fde0ffe0ced41ede001f77bf81741ea5d65b803ad76d669f146f8cd53702daf3387c9f89402b32f9667110
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sideway/address@npm:^4.1.3":
|
||||
version: 4.1.4
|
||||
resolution: "@sideway/address@npm:4.1.4"
|
||||
@ -4280,6 +4295,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"babel-plugin-transform-inline-environment-variables@npm:^0.4.4":
|
||||
version: 0.4.4
|
||||
resolution: "babel-plugin-transform-inline-environment-variables@npm:0.4.4"
|
||||
checksum: fa361287411301237fd8ce332aff4f8e8ccb8db30e87a2ddc7224c8bf7cd792eda47aca24dc2e09e70bce4c027bc8cbe22f4999056be37a25d2472945df21ef5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"babel-preset-expo@npm:~9.2.2":
|
||||
version: 9.2.2
|
||||
resolution: "babel-preset-expo@npm:9.2.2"
|
||||
@ -8600,7 +8622,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.debounce@npm:^4.0.8":
|
||||
"lodash.debounce@npm:4.0.8, lodash.debounce@npm:^4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "lodash.debounce@npm:4.0.8"
|
||||
checksum: a3f527d22c548f43ae31c861ada88b2637eb48ac6aa3eb56e82d44917971b8aa96fbb37aa60efea674dc4ee8c42074f90f7b1f772e9db375435f6c83a19b3bc6
|
||||
@ -9636,9 +9658,11 @@ __metadata:
|
||||
dependencies:
|
||||
"@babel/core": ^7.19.3
|
||||
"@kyoo/ui": "workspace:^"
|
||||
"@shopify/flash-list": 1.3.1
|
||||
"@tanstack/react-query": ^4.19.1
|
||||
"@types/react": ~18.0.24
|
||||
"@types/react-native": ~0.70.6
|
||||
babel-plugin-transform-inline-environment-variables: ^0.4.4
|
||||
expo: ^47.0.0
|
||||
expo-constants: ~14.0.2
|
||||
expo-linear-gradient: ~12.0.1
|
||||
@ -10708,7 +10732,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"prop-types@npm:^15.6.2, prop-types@npm:^15.8.1":
|
||||
"prop-types@npm:15.8.1, prop-types@npm:^15.6.2, prop-types@npm:^15.8.1":
|
||||
version: 15.8.1
|
||||
resolution: "prop-types@npm:15.8.1"
|
||||
dependencies:
|
||||
@ -11196,6 +11220,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"recyclerlistview@npm:4.1.2":
|
||||
version: 4.1.2
|
||||
resolution: "recyclerlistview@npm:4.1.2"
|
||||
dependencies:
|
||||
lodash.debounce: 4.0.8
|
||||
prop-types: 15.8.1
|
||||
ts-object-utils: 0.0.5
|
||||
peerDependencies:
|
||||
react: ">= 15.2.1"
|
||||
react-native: ">= 0.30.0"
|
||||
checksum: e18e36c0783b528b5244ed0b7eabf231c49ec7b0a97c947a6f596900165a4d7bbc3216b23084a8a2cb8d33b98fb38fc4a64254cf0b6431a0d0fa3ca2e7129fbc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"regenerate-unicode-properties@npm:^10.1.0":
|
||||
version: 10.1.0
|
||||
resolution: "regenerate-unicode-properties@npm:10.1.0"
|
||||
@ -12718,6 +12756,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ts-object-utils@npm:0.0.5":
|
||||
version: 0.0.5
|
||||
resolution: "ts-object-utils@npm:0.0.5"
|
||||
checksum: 83c48fbdaba392fb2c01cea53b267ed5538d2bb44fc6c3eecc10bcfabc1780bfa6ec8569b52bbf0140d9b521d9049d5f15884e12286918244d463d854dbc73cb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tsconfig-paths@npm:^3.14.1":
|
||||
version: 3.14.1
|
||||
resolution: "tsconfig-paths@npm:3.14.1"
|
||||
@ -12730,6 +12775,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tslib@npm:2.4.0":
|
||||
version: 2.4.0
|
||||
resolution: "tslib@npm:2.4.0"
|
||||
checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tslib@npm:^1.8.1":
|
||||
version: 1.14.1
|
||||
resolution: "tslib@npm:1.14.1"
|
||||
|
Loading…
x
Reference in New Issue
Block a user