mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-30 19:54:16 -04:00
Fix infinite scroll behavior of details page
This commit is contained in:
parent
5d377654aa
commit
039c644453
@ -169,14 +169,16 @@ const TitleLine = ({
|
|||||||
})}
|
})}
|
||||||
{...tooltip(t("show.play"))}
|
{...tooltip(t("show.play"))}
|
||||||
/>
|
/>
|
||||||
{trailerUrl && <IconButton
|
{trailerUrl && (
|
||||||
icon={Theaters}
|
<IconButton
|
||||||
as={Link}
|
icon={Theaters}
|
||||||
href={trailerUrl}
|
as={Link}
|
||||||
target="_blank"
|
href={trailerUrl}
|
||||||
color={{ xs: theme.user.contrast, md: theme.colors.white }}
|
target="_blank"
|
||||||
{...tooltip(t("show.trailer"))}
|
color={{ xs: theme.user.contrast, md: theme.colors.white }}
|
||||||
/>}
|
{...tooltip(t("show.trailer"))}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@ -249,7 +251,7 @@ const Description = ({
|
|||||||
{t("show.genre")}:{" "}
|
{t("show.genre")}:{" "}
|
||||||
{(isLoading ? [...Array(3)] : genres!).map((genre, i) => (
|
{(isLoading ? [...Array(3)] : genres!).map((genre, i) => (
|
||||||
<Fragment key={genre?.slug ?? i.toString()}>
|
<Fragment key={genre?.slug ?? i.toString()}>
|
||||||
<P>{i !== 0 && ", "}</P>
|
<P {...css({ m: 0 })}>{i !== 0 && ", "}</P>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Skeleton {...css({ width: rem(5) })} />
|
<Skeleton {...css({ width: rem(5) })} />
|
||||||
) : (
|
) : (
|
||||||
|
@ -41,7 +41,7 @@ export const EpisodeList = ({
|
|||||||
return (
|
return (
|
||||||
<InfiniteFetch
|
<InfiniteFetch
|
||||||
query={EpisodeList.query(slug, season)}
|
query={EpisodeList.query(slug, season)}
|
||||||
placeholderCount={15}
|
placeholderCount={10}
|
||||||
layout={EpisodeLine.layout}
|
layout={EpisodeLine.layout}
|
||||||
empty={t("show.episode-none")}
|
empty={t("show.episode-none")}
|
||||||
divider
|
divider
|
||||||
|
@ -26,6 +26,7 @@ import { EpisodeList } from "./season";
|
|||||||
import { Header } from "./header";
|
import { Header } from "./header";
|
||||||
import Svg, { Path, SvgProps } from "react-native-svg";
|
import Svg, { Path, SvgProps } from "react-native-svg";
|
||||||
import { Container, SwitchVariant } from "@kyoo/primitives";
|
import { Container, SwitchVariant } from "@kyoo/primitives";
|
||||||
|
import { forwardRef } from "react";
|
||||||
|
|
||||||
const SvgWave = (props: SvgProps) => {
|
const SvgWave = (props: SvgProps) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
@ -52,38 +53,41 @@ const query = (slug: string): QueryIdentifier<Show> => ({
|
|||||||
export const ShowDetails: QueryPage<{ slug: string; season: string }> = ({ slug, season }) => {
|
export const ShowDetails: QueryPage<{ slug: string; season: string }> = ({ slug, season }) => {
|
||||||
const { css, theme } = useYoshiki();
|
const { css, theme } = useYoshiki();
|
||||||
|
|
||||||
const ShowHeader = ({ children, ...props }: ViewProps) => (
|
const ShowHeader = forwardRef<View, ViewProps>(function _ShowHeader({ children, ...props }, ref) {
|
||||||
<View
|
return (
|
||||||
{...css(
|
<View
|
||||||
[
|
ref={ref}
|
||||||
{ bg: (theme) => theme.background },
|
{...css(
|
||||||
Platform.OS === "web" && {
|
[
|
||||||
flexGrow: 1,
|
{ bg: (theme) => theme.background },
|
||||||
flexShrink: 1,
|
Platform.OS === "web" && {
|
||||||
// @ts-ignore Web only property
|
flexGrow: 1,
|
||||||
overflow: "auto" as any,
|
flexShrink: 1,
|
||||||
// @ts-ignore Web only property
|
// @ts-ignore Web only property
|
||||||
overflowX: "hidden",
|
overflow: "auto" as any,
|
||||||
// @ts-ignore Web only property
|
// @ts-ignore Web only property
|
||||||
overflowY: "overlay",
|
overflowX: "hidden",
|
||||||
},
|
// @ts-ignore Web only property
|
||||||
],
|
overflowY: "overlay",
|
||||||
props,
|
},
|
||||||
)}
|
],
|
||||||
>
|
props,
|
||||||
{/* TODO: Remove the slug quickfix for the play button */}
|
)}
|
||||||
<Header slug={`${slug}-s1e1`} query={query(slug)} />
|
>
|
||||||
{/* <Staff slug={slug} /> */}
|
{/* TODO: Remove the slug quickfix for the play button */}
|
||||||
<SvgWave
|
<Header slug={`${slug}-s1e1`} query={query(slug)} />
|
||||||
fill={theme.variant.background}
|
{/* <Staff slug={slug} /> */}
|
||||||
{...css({ flexShrink: 0, flexGrow: 1, display: "flex" })}
|
<SvgWave
|
||||||
/>
|
fill={theme.variant.background}
|
||||||
{/* <SeasonTab slug={slug} season={season} /> */}
|
{...css({ flexShrink: 0, flexGrow: 1, display: "flex" })}
|
||||||
<View {...css({ bg: theme.variant.background })}>
|
/>
|
||||||
<Container>{children}</Container>
|
{/* <SeasonTab slug={slug} season={season} /> */}
|
||||||
|
<View {...css({ bg: theme.variant.background })}>
|
||||||
|
<Container>{children}</Container>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
);
|
||||||
);
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SwitchVariant>
|
<SwitchVariant>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
||||||
import { HR } from "@kyoo/primitives";
|
import { HR } from "@kyoo/primitives";
|
||||||
import { ComponentType, Fragment, ReactElement, useMemo, useRef } from "react";
|
import { ComponentType, Fragment, isValidElement, ReactElement, useMemo, useRef } from "react";
|
||||||
import { Stylable, useYoshiki } from "yoshiki";
|
import { Stylable, useYoshiki } from "yoshiki";
|
||||||
import { EmptyView, ErrorView, Layout, WithLoading } from "./fetch";
|
import { EmptyView, ErrorView, Layout, WithLoading } from "./fetch";
|
||||||
|
|
||||||
@ -31,6 +31,7 @@ const InfiniteScroll = ({
|
|||||||
loadMore,
|
loadMore,
|
||||||
hasMore = true,
|
hasMore = true,
|
||||||
isFetching,
|
isFetching,
|
||||||
|
Header,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
children?: ReactElement | (ReactElement | null)[] | null;
|
children?: ReactElement | (ReactElement | null)[] | null;
|
||||||
@ -39,23 +40,25 @@ const InfiniteScroll = ({
|
|||||||
loadMore: () => void;
|
loadMore: () => void;
|
||||||
hasMore: boolean;
|
hasMore: boolean;
|
||||||
isFetching: boolean;
|
isFetching: boolean;
|
||||||
|
Header: ComponentType<{ children: JSX.Element }> | ReactElement | undefined;
|
||||||
} & Stylable) => {
|
} & Stylable) => {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
|
|
||||||
return (
|
const onScroll = () => {
|
||||||
<div
|
if (!ref.current || !hasMore || isFetching) return;
|
||||||
ref={ref}
|
const scroll =
|
||||||
onScroll={() => {
|
layout === "horizontal"
|
||||||
if (!ref.current || !hasMore || isFetching) return;
|
? ref.current.scrollWidth - ref.current.scrollLeft
|
||||||
const scroll =
|
: ref.current.scrollHeight - ref.current.scrollTop;
|
||||||
layout === "horizontal"
|
const offset = layout === "horizontal" ? ref.current.offsetWidth : ref.current.offsetHeight;
|
||||||
? ref.current.scrollWidth - ref.current.scrollLeft
|
|
||||||
: ref.current.scrollHeight - ref.current.scrollTop;
|
|
||||||
const offset = layout === "horizontal" ? ref.current.offsetWidth : ref.current.offsetHeight;
|
|
||||||
|
|
||||||
if (scroll <= offset * 1.2) loadMore();
|
if (scroll <= offset * 1.2) loadMore();
|
||||||
}}
|
};
|
||||||
|
const scrollProps = { ref, onScroll };
|
||||||
|
|
||||||
|
const list = (props: object) => (
|
||||||
|
<div
|
||||||
{...css(
|
{...css(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -84,6 +87,15 @@ const InfiniteScroll = ({
|
|||||||
{hasMore && isFetching && loader}
|
{hasMore && isFetching && loader}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!Header) return list({ ...scrollProps, ...props });
|
||||||
|
if (!isValidElement(Header)) return <Header {...scrollProps}>{list(props)}</Header>;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{Header}
|
||||||
|
{list({ ...scrollProps, ...props })}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InfiniteFetch = <Data,>({
|
export const InfiniteFetch = <Data,>({
|
||||||
@ -125,7 +137,7 @@ export const InfiniteFetch = <Data,>({
|
|||||||
return <EmptyView message={empty} />;
|
return <EmptyView message={empty} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const list = (
|
return (
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
layout={grid ? "grid" : horizontal ? "horizontal" : "vertical"}
|
layout={grid ? "grid" : horizontal ? "horizontal" : "vertical"}
|
||||||
loadMore={fetchNextPage}
|
loadMore={fetchNextPage}
|
||||||
@ -137,6 +149,7 @@ export const InfiniteFetch = <Data,>({
|
|||||||
{children({ isLoading: true } as any, i)}
|
{children({ isLoading: true } as any, i)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
|
Header={Header}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{items?.map((item, i) => (
|
{items?.map((item, i) => (
|
||||||
@ -147,7 +160,6 @@ export const InfiniteFetch = <Data,>({
|
|||||||
))}
|
))}
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
);
|
);
|
||||||
return addHeader(Header, list);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const addHeader = (
|
const addHeader = (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user