mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Fix browse layout switch
This commit is contained in:
parent
0ad9c86756
commit
552926d2cb
@ -187,7 +187,7 @@ ItemGrid.Loader = (props: object) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ItemGrid.layout = {
|
ItemGrid.layout = {
|
||||||
size: px(150),
|
size: 150,
|
||||||
numColumns: { xs: 3, sm: 4, md: 5, lg: 6, xl: 8 },
|
numColumns: { xs: 3, sm: 4, md: 5, lg: 6, xl: 8 },
|
||||||
gap: { xs: ts(1), sm: ts(2), md: ts(4) },
|
gap: { xs: ts(1), sm: ts(2), md: ts(4) },
|
||||||
layout: "grid",
|
layout: "grid",
|
||||||
|
@ -3,6 +3,7 @@ import { Platform, View } from "react-native";
|
|||||||
import { percent, px, rem, useYoshiki } from "yoshiki/native";
|
import { percent, px, rem, useYoshiki } from "yoshiki/native";
|
||||||
import type { KImage, WatchStatusV } from "~/models";
|
import type { KImage, WatchStatusV } from "~/models";
|
||||||
import {
|
import {
|
||||||
|
ContrastArea,
|
||||||
GradientImageBackground,
|
GradientImageBackground,
|
||||||
Heading,
|
Heading,
|
||||||
important,
|
important,
|
||||||
@ -39,10 +40,11 @@ export const ItemList = ({
|
|||||||
watchStatus: WatchStatusV | null;
|
watchStatus: WatchStatusV | null;
|
||||||
unseenEpisodesCount: number | null;
|
unseenEpisodesCount: number | null;
|
||||||
}) => {
|
}) => {
|
||||||
const { css } = useYoshiki("line");
|
|
||||||
const [moreOpened, setMoreOpened] = useState(false);
|
const [moreOpened, setMoreOpened] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<ContrastArea>
|
||||||
|
{({ css }) => (
|
||||||
<Link
|
<Link
|
||||||
href={moreOpened ? undefined : href}
|
href={moreOpened ? undefined : href}
|
||||||
onLongPress={() => setMoreOpened(true)}
|
onLongPress={() => setMoreOpened(true)}
|
||||||
@ -61,22 +63,22 @@ export const ItemList = ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
<GradientImageBackground
|
<GradientImageBackground
|
||||||
src={thumbnail}
|
src={thumbnail}
|
||||||
alt={name}
|
alt={name}
|
||||||
quality="medium"
|
quality="medium"
|
||||||
layout={{ width: percent(100), height: ItemList.layout.size }}
|
layout={{ width: percent(100), height: ItemList.layout.size }}
|
||||||
{...(css(
|
gradientStyle={{
|
||||||
{
|
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-evenly",
|
justifyContent: "space-evenly",
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
|
}}
|
||||||
|
{...(css({
|
||||||
borderRadius: px(10),
|
borderRadius: px(10),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
},
|
}) as any)}
|
||||||
props,
|
|
||||||
) as any)}
|
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
{...css({
|
{...css({
|
||||||
@ -147,6 +149,8 @@ export const ItemList = ({
|
|||||||
</PosterBackground>
|
</PosterBackground>
|
||||||
</GradientImageBackground>
|
</GradientImageBackground>
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
|
</ContrastArea>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,7 +52,9 @@ export const PosterBackground = ({
|
|||||||
...props
|
...props
|
||||||
}: Omit<ComponentProps<typeof ImageBackground>, "layout"> & {
|
}: Omit<ComponentProps<typeof ImageBackground>, "layout"> & {
|
||||||
style?: ImageStyle;
|
style?: ImageStyle;
|
||||||
layout: YoshikiEnhanced<{ width: ImageStyle["width"] } | { height: ImageStyle["height"] }>;
|
layout: YoshikiEnhanced<
|
||||||
|
{ width: ImageStyle["width"] } | { height: ImageStyle["height"] }
|
||||||
|
>;
|
||||||
}) => {
|
}) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
|
|
||||||
@ -67,10 +69,12 @@ export const PosterBackground = ({
|
|||||||
|
|
||||||
export const GradientImageBackground = ({
|
export const GradientImageBackground = ({
|
||||||
gradient,
|
gradient,
|
||||||
|
gradientStyle,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: ComponentProps<typeof ImageBackground> & {
|
}: ComponentProps<typeof ImageBackground> & {
|
||||||
gradient?: Partial<LinearGradientProps>;
|
gradient?: Partial<LinearGradientProps>;
|
||||||
|
gradientStyle?: Parameters<ReturnType<typeof useYoshiki>["css"]>[0];
|
||||||
}) => {
|
}) => {
|
||||||
const { css, theme } = useYoshiki();
|
const { css, theme } = useYoshiki();
|
||||||
|
|
||||||
@ -81,6 +85,7 @@ export const GradientImageBackground = ({
|
|||||||
end={{ x: 0, y: 1 }}
|
end={{ x: 0, y: 1 }}
|
||||||
colors={["transparent", theme.darkOverlay]}
|
colors={["transparent", theme.darkOverlay]}
|
||||||
{...css(
|
{...css(
|
||||||
|
[
|
||||||
{
|
{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 0,
|
top: 0,
|
||||||
@ -88,6 +93,8 @@ export const GradientImageBackground = ({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
},
|
},
|
||||||
|
gradientStyle,
|
||||||
|
],
|
||||||
typeof gradient === "object" ? gradient : undefined,
|
typeof gradient === "object" ? gradient : undefined,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
import { type ReactNode, forwardRef } from "react";
|
import type { ReactNode } from "react";
|
||||||
import {
|
import {
|
||||||
Linking,
|
Linking,
|
||||||
Platform,
|
Platform,
|
||||||
@ -7,7 +7,6 @@ import {
|
|||||||
type PressableProps,
|
type PressableProps,
|
||||||
Text,
|
Text,
|
||||||
type TextProps,
|
type TextProps,
|
||||||
type View,
|
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { useTheme, useYoshiki } from "yoshiki/native";
|
import { useTheme, useYoshiki } from "yoshiki/native";
|
||||||
import { alpha } from "./theme";
|
import { alpha } from "./theme";
|
||||||
@ -26,7 +25,9 @@ function useLinkTo({
|
|||||||
onPress: (e) => {
|
onPress: (e) => {
|
||||||
if (e?.defaultPrevented) return;
|
if (e?.defaultPrevented) return;
|
||||||
if (href.startsWith("http")) {
|
if (href.startsWith("http")) {
|
||||||
Platform.OS === "web" ? window.open(href, "_blank") : Linking.openURL(href);
|
Platform.OS === "web"
|
||||||
|
? window.open(href, "_blank")
|
||||||
|
: Linking.openURL(href);
|
||||||
} else {
|
} else {
|
||||||
replace ? router.replace(href) : router.push(href);
|
replace ? router.replace(href) : router.push(href);
|
||||||
}
|
}
|
||||||
@ -65,25 +66,26 @@ export const A = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PressableFeedback = forwardRef<View, PressableProps>(function Feedback(
|
export const PressableFeedback = ({ children, ...props }: PressableProps) => {
|
||||||
{ children, ...props },
|
|
||||||
ref,
|
|
||||||
) {
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
ref={ref}
|
|
||||||
// TODO: Enable ripple on tv. Waiting for https://github.com/react-native-tvos/react-native-tvos/issues/440
|
// TODO: Enable ripple on tv. Waiting for https://github.com/react-native-tvos/react-native-tvos/issues/440
|
||||||
{...(Platform.isTV
|
{...(Platform.isTV
|
||||||
? {}
|
? {}
|
||||||
: { android_ripple: { foreground: true, color: alpha(theme.contrast, 0.5) as any } })}
|
: {
|
||||||
|
android_ripple: {
|
||||||
|
foreground: true,
|
||||||
|
color: alpha(theme.contrast, 0.5) as any,
|
||||||
|
},
|
||||||
|
})}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
export const Link = ({
|
export const Link = ({
|
||||||
href,
|
href,
|
||||||
|
@ -48,11 +48,19 @@ export const InfiniteFetch = <Data, Props, _, Kind extends number | string>({
|
|||||||
const { numColumns, size, gap } = useBreakpointMap(layout);
|
const { numColumns, size, gap } = useBreakpointMap(layout);
|
||||||
const [setOffline, clearOffline] = useSetError("offline");
|
const [setOffline, clearOffline] = useSetError("offline");
|
||||||
const oldItems = useRef<Data[] | undefined>(undefined);
|
const oldItems = useRef<Data[] | undefined>(undefined);
|
||||||
let { items, isPaused, error, fetchNextPage, isFetching, refetch, isRefetching } =
|
let {
|
||||||
useInfiniteFetch(query);
|
items,
|
||||||
|
isPaused,
|
||||||
|
error,
|
||||||
|
fetchNextPage,
|
||||||
|
isFetching,
|
||||||
|
refetch,
|
||||||
|
isRefetching,
|
||||||
|
} = useInfiniteFetch(query);
|
||||||
if (incremental && items) oldItems.current = items;
|
if (incremental && items) oldItems.current = items;
|
||||||
|
|
||||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
if (!query.infinite)
|
||||||
|
console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||||
|
|
||||||
if (isPaused) setOffline();
|
if (isPaused) setOffline();
|
||||||
else clearOffline();
|
else clearOffline();
|
||||||
@ -60,10 +68,13 @@ export const InfiniteFetch = <Data, Props, _, Kind extends number | string>({
|
|||||||
if (error) return <ErrorView error={error} />;
|
if (error) return <ErrorView error={error} />;
|
||||||
|
|
||||||
if (incremental) items ??= oldItems.current;
|
if (incremental) items ??= oldItems.current;
|
||||||
const count = items ? numColumns - (items.length % numColumns) : placeholderCount;
|
const count = items
|
||||||
console.log(numColumns, count);
|
? numColumns - (items.length % numColumns)
|
||||||
|
: placeholderCount;
|
||||||
const placeholders = [...Array(count === 0 ? numColumns : count)].fill(null);
|
const placeholders = [...Array(count === 0 ? numColumns : count)].fill(null);
|
||||||
const data = isFetching || !items ? [...(items || []), ...placeholders] : items;
|
const data =
|
||||||
|
isFetching || !items ? [...(items || []), ...placeholders] : items;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LegendList
|
<LegendList
|
||||||
data={data}
|
data={data}
|
||||||
@ -71,9 +82,8 @@ export const InfiniteFetch = <Data, Props, _, Kind extends number | string>({
|
|||||||
renderItem={({ item, index }) =>
|
renderItem={({ item, index }) =>
|
||||||
item ? <Render index={index} item={item} /> : <Loader index={index} />
|
item ? <Render index={index} item={item} /> : <Loader index={index} />
|
||||||
}
|
}
|
||||||
// keyExtractor={(item: any, index) => (item ? item.id : index)}
|
keyExtractor={(item: any, index) => (item ? item.id : index)}
|
||||||
// estimatedItemSize={size}
|
estimatedItemSize={size}
|
||||||
|
|
||||||
horizontal={layout.layout === "horizontal"}
|
horizontal={layout.layout === "horizontal"}
|
||||||
numColumns={layout.layout === "horizontal" ? 1 : numColumns}
|
numColumns={layout.layout === "horizontal" ? 1 : numColumns}
|
||||||
onEndReached={fetchMore ? () => fetchNextPage() : undefined}
|
onEndReached={fetchMore ? () => fetchNextPage() : undefined}
|
||||||
@ -81,7 +91,9 @@ export const InfiniteFetch = <Data, Props, _, Kind extends number | string>({
|
|||||||
onRefresh={layout.layout !== "horizontal" ? refetch : undefined}
|
onRefresh={layout.layout !== "horizontal" ? refetch : undefined}
|
||||||
refreshing={isRefetching}
|
refreshing={isRefetching}
|
||||||
ListHeaderComponent={Header}
|
ListHeaderComponent={Header}
|
||||||
ItemSeparatorComponent={divider === true ? HR : (divider as any) || undefined}
|
ItemSeparatorComponent={
|
||||||
|
divider === true ? HR : (divider as any) || undefined
|
||||||
|
}
|
||||||
ListEmptyComponent={Empty}
|
ListEmptyComponent={Empty}
|
||||||
contentContainerStyle={{ gap, marginHorizontal: gap }}
|
contentContainerStyle={{ gap, marginHorizontal: gap }}
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -149,7 +149,9 @@ export const BrowseSettings = ({
|
|||||||
{Object.keys(MediaTypeIcons).map((x) => (
|
{Object.keys(MediaTypeIcons).map((x) => (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key={x}
|
key={x}
|
||||||
label={t(`browse.mediatypekey.${x}`)}
|
label={t(
|
||||||
|
`browse.mediatypekey.${x as keyof typeof MediaTypeIcons}`,
|
||||||
|
)}
|
||||||
selected={mediaType === x}
|
selected={mediaType === x}
|
||||||
icon={MediaTypeIcons[x as keyof typeof MediaTypeIcons]}
|
icon={MediaTypeIcons[x as keyof typeof MediaTypeIcons]}
|
||||||
onSelect={() => setMediaType(x)}
|
onSelect={() => setMediaType(x)}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import { ItemGrid, ItemList, itemMap } from "~/components/items";
|
import { ItemGrid, ItemList, itemMap } from "~/components/items";
|
||||||
import { Show } from "~/models";
|
import { Show } from "~/models";
|
||||||
import { InfiniteFetch, type QueryIdentifier } from "~/query";
|
import { InfiniteFetch, type QueryIdentifier } from "~/query";
|
||||||
@ -17,6 +16,7 @@ export const BrowsePage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InfiniteFetch
|
<InfiniteFetch
|
||||||
|
key={layout}
|
||||||
query={BrowsePage.query(filter, sortBy, sortOrd)}
|
query={BrowsePage.query(filter, sortBy, sortOrd)}
|
||||||
layout={LayoutComponent.layout}
|
layout={LayoutComponent.layout}
|
||||||
Header={
|
Header={
|
||||||
|
Loading…
x
Reference in New Issue
Block a user