diff --git a/front/packages/primitives/src/image/index.tsx b/front/packages/primitives/src/image/index.tsx index 8471570c..6fe56f97 100644 --- a/front/packages/primitives/src/image/index.tsx +++ b/front/packages/primitives/src/image/index.tsx @@ -21,7 +21,7 @@ import { ImageStyle, View, ViewProps, ViewStyle } from "react-native"; import { Props, ImageLayout, YoshikiEnhanced } from "./base-image"; import { Image } from "./image"; -import { ComponentType, ReactNode } from "react"; +import { ComponentProps, ComponentType, ReactNode } from "react"; import { LinearGradient, LinearGradientProps } from "expo-linear-gradient"; import { ContrastArea } from "../themes"; import { percent } from "yoshiki/native"; @@ -37,6 +37,22 @@ export const Poster = ({ layout: YoshikiEnhanced<{ width: ImageStyle["width"] } | { height: ImageStyle["height"] }>; }) => {alt!}; +export const PosterBackground = ({ + alt, + layout, + ...props +}: Omit, "layout"> & { style?: ImageStyle } & { + layout: YoshikiEnhanced<{ width: ImageStyle["width"] } | { height: ImageStyle["height"] }>; +}) => ( + +); + export const ImageBackground = ({ src, alt, diff --git a/front/packages/primitives/src/text.tsx b/front/packages/primitives/src/text.tsx index 4f9c6bdb..ee339f82 100644 --- a/front/packages/primitives/src/text.tsx +++ b/front/packages/primitives/src/text.tsx @@ -18,7 +18,7 @@ * along with Kyoo. If not, see . */ -import { ComponentType, ComponentProps, ReactNode } from "react"; +import { ComponentType, ComponentProps } from "react"; import { Platform, Text, TextProps, TextStyle, StyleProp } from "react-native"; import { percent, rem, useYoshiki } from "yoshiki/native"; import { diff --git a/front/packages/primitives/src/themes/catppuccin.ts b/front/packages/primitives/src/themes/catppuccin.ts index d09286d4..c06f889d 100644 --- a/front/packages/primitives/src/themes/catppuccin.ts +++ b/front/packages/primitives/src/themes/catppuccin.ts @@ -18,7 +18,7 @@ * along with Kyoo. If not, see . */ -import { ThemeBuilder, alpha } from "./theme"; +import { ThemeBuilder } from "./theme"; // Ref: https://github.com/catppuccin/catppuccin export const catppuccin: ThemeBuilder = { diff --git a/front/packages/ui/src/browse/grid.tsx b/front/packages/ui/src/browse/grid.tsx index 03106289..4f24c280 100644 --- a/front/packages/ui/src/browse/grid.tsx +++ b/front/packages/ui/src/browse/grid.tsx @@ -18,11 +18,22 @@ * along with Kyoo. If not, see . */ -import { KyooImage } from "@kyoo/models"; -import { Link, Skeleton, Poster, ts, focusReset, P, SubP } from "@kyoo/primitives"; -import { ImageStyle } from "react-native"; -import { percent, px, Stylable, Theme, useYoshiki } from "yoshiki/native"; +import { KyooImage, WatchStatusV } from "@kyoo/models"; +import { + Link, + Skeleton, + Poster, + ts, + focusReset, + P, + SubP, + PosterBackground, + Icon, +} from "@kyoo/primitives"; +import { ImageStyle, View } from "react-native"; +import { percent, px, rem, Stylable, Theme, useYoshiki } from "yoshiki/native"; import { Layout, WithLoading } from "../fetch"; +import Done from "@material-symbols/svg-400/rounded/done-fill.svg"; export const ItemGrid = ({ href, @@ -30,12 +41,14 @@ export const ItemGrid = ({ subtitle, poster, isLoading, + watchInfo, ...props }: WithLoading<{ href: string; name: string; subtitle?: string; poster?: KyooImage | null; + watchInfo: WatchStatusV | string | null; }> & Stylable<"text">) => { const { css } = useYoshiki("grid"); @@ -68,14 +81,37 @@ export const ItemGrid = ({ props, )} > - + > + {watchInfo && ( + theme.darkOverlay, + borderRadius: 999999, + })} + > + {watchInfo === WatchStatusV.Completed ? ( + + ) : ( +

{watchInfo}

+ )} +
+ )} + {isLoading || (

diff --git a/front/packages/ui/src/browse/index.tsx b/front/packages/ui/src/browse/index.tsx index 6960591e..9de6c1cb 100644 --- a/front/packages/ui/src/browse/index.tsx +++ b/front/packages/ui/src/browse/index.tsx @@ -25,6 +25,7 @@ import { LibraryItemP, ItemKind, getDisplayDate, + WatchStatusV, } from "@kyoo/models"; import { ComponentProps, useState } from "react"; import { createParam } from "solito"; @@ -43,6 +44,15 @@ export const itemMap = ( ): WithLoading & ComponentProps> => { if (item.isLoading) return item; + let watchInfo: string | WatchStatusV | null = null; + if (item.kind !== ItemKind.Collection && item.watchStatus?.status === WatchStatusV.Completed) + watchInfo = WatchStatusV.Completed; + else if (item.kind === ItemKind.Show) { + if (!item.watchStatus) watchInfo = item.episodesCount!.toString(); + else if (item.watchStatus.status === WatchStatusV.Watching) + watchInfo = item.watchStatus.unseenEpisodesCount.toString(); + } + return { isLoading: item.isLoading, name: item.name, @@ -50,6 +60,7 @@ export const itemMap = ( href: item.href, poster: item.poster, thumbnail: item.thumbnail, + watchInfo: watchInfo, }; }; @@ -59,6 +70,7 @@ const query = (sortKey?: SortBy, sortOrd?: SortOrd): QueryIdentifier { const { css } = useYoshiki(); @@ -85,13 +86,7 @@ export const GenreGrid = ({ genre }: { genre: Genre }) => { return ( ); }} @@ -105,6 +100,7 @@ GenreGrid.query = (genre: Genre): QueryIdentifier => ({ infinite: true, path: ["items"], params: { + fields: ["watchStatus", "episodesCount"], filter: `genres has ${genre}`, sortBy: "random", // Limit the inital numbers of items