diff --git a/front/apps/mobile/package.json b/front/apps/mobile/package.json
index 5212af2d..4f434d8a 100644
--- a/front/apps/mobile/package.json
+++ b/front/apps/mobile/package.json
@@ -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",
diff --git a/front/packages/ui/package.json b/front/packages/ui/package.json
index d8a4ea5b..d709c386 100644
--- a/front/packages/ui/package.json
+++ b/front/packages/ui/package.json
@@ -13,6 +13,7 @@
"typescript": "^4.9.3"
},
"peerDependencies": {
+ "@shopify/flash-list": "^1.4.0",
"@tanstack/react-query": "*",
"expo-linear-gradient": "*",
"i18next": "*",
diff --git a/front/packages/ui/src/fetch-infinite.tsx b/front/packages/ui/src/fetch-infinite.tsx
new file mode 100644
index 00000000..d09adf4e
--- /dev/null
+++ b/front/packages/ui/src/fetch-infinite.tsx
@@ -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 .
+ */
+
+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 = ({
+ query,
+ placeholderCount = 15,
+ children,
+ size,
+ numColumns,
+ ...props
+}: {
+ query: QueryIdentifier;
+ placeholderCount?: number;
+ numColumns: number;
+ children: (
+ item: Data extends Page ? WithLoading- : WithLoading,
+ 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 ;
+
+ return (
+
+ 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}
+ />
+ );
+};
diff --git a/front/packages/ui/src/fetch-infinite.web.tsx b/front/packages/ui/src/fetch-infinite.web.tsx
new file mode 100644
index 00000000..5a0c6999
--- /dev/null
+++ b/front/packages/ui/src/fetch-infinite.web.tsx
@@ -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 .
+ */
+
+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 = ({
+ query,
+ placeholderCount = 15,
+ children,
+ ...props
+}: {
+ query: QueryIdentifier;
+ placeholderCount?: number;
+ children: (
+ item: Data extends Page ? WithLoading
- : WithLoading,
+ 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 ;
+
+ return (
+ 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),
+ )}
+
+ );
+};
diff --git a/front/packages/ui/src/fetch.tsx b/front/packages/ui/src/fetch.tsx
index 925547ec..6ec4a2ca 100644
--- a/front/packages/ui/src/fetch.tsx
+++ b/front/packages/ui/src/fetch.tsx
@@ -18,7 +18,7 @@
* along with Kyoo. If not, see .
*/
-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 = ({
return <>{data.items.map((item, i) => children({ ...item, isLoading: false } as any, i))}>;
};
-export const InfiniteFetch = ({
- query,
- placeholderCount = 15,
- children,
-}: {
- query: QueryIdentifier;
- placeholderCount?: number;
- children: (
- item: Data extends Page ? WithLoading
- : WithLoading,
- 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 ;
- 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();
diff --git a/front/yarn.lock b/front/yarn.lock
index 50908e38..b00e603a 100644
--- a/front/yarn.lock
+++ b/front/yarn.lock
@@ -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"