diff --git a/front/packages/models/src/resources/index.ts b/front/packages/models/src/resources/index.ts index 8f5b9ce7..3d934384 100644 --- a/front/packages/models/src/resources/index.ts +++ b/front/packages/models/src/resources/index.ts @@ -30,4 +30,5 @@ export * from "./episode"; export * from "./season"; export * from "./watch-info"; export * from "./watch-status"; +export * from "./watchlist"; export * from "./user"; diff --git a/front/packages/models/src/resources/watchlist.ts b/front/packages/models/src/resources/watchlist.ts new file mode 100644 index 00000000..fd533afc --- /dev/null +++ b/front/packages/models/src/resources/watchlist.ts @@ -0,0 +1,47 @@ +/* + * 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 { z } from "zod"; +import { MovieP } from "./movie"; +import { ShowP } from "./show"; + +/** + * The type of item, ether a show, a movie or an episode. + */ +export enum WatchlistKind { + Show = "Show", + Movie = "Movie", +} + +export const WatchlistP = z.union([ + /* + * Either a show + */ + ShowP.and(z.object({ kind: z.literal(WatchlistKind.Show) })), + /* + * Or a Movie + */ + MovieP.and(z.object({ kind: z.literal(WatchlistKind.Movie) })), +]); + +/** + * A item in the user's watchlist. + */ +export type Watchlist = z.infer; diff --git a/front/packages/ui/src/details/episode.tsx b/front/packages/ui/src/details/episode.tsx index 6ed31620..82927f62 100644 --- a/front/packages/ui/src/details/episode.tsx +++ b/front/packages/ui/src/details/episode.tsx @@ -105,7 +105,7 @@ export const EpisodeBox = ({ src={thumbnail} quality="low" alt="" - graditent={false} + gradient={false} hideLoad={false} forcedLoading={isLoading} layout={{ width: percent(100), aspectRatio: 16 / 9 }} diff --git a/front/packages/ui/src/home/index.tsx b/front/packages/ui/src/home/index.tsx index bac76a50..fed6c3de 100644 --- a/front/packages/ui/src/home/index.tsx +++ b/front/packages/ui/src/home/index.tsx @@ -28,6 +28,7 @@ import { Recommanded } from "./recommanded"; import { VerticalRecommanded } from "./vertical"; import { NewsList } from "./news"; import { useEffect, useState } from "react"; +import { WatchlistList } from "./watchlist"; export const HomePage: QueryPage<{}, Genre> = ({ randomItems }) => { const [isClient, setClient] = useState(false); @@ -48,6 +49,7 @@ export const HomePage: QueryPage<{}, Genre> = ({ randomItems }) => { /> )} + {randomItems .filter((_, i) => i < 2) @@ -72,6 +74,7 @@ HomePage.getLayout = { Layout: DefaultLayout, props: { transparent: true } }; HomePage.getFetchUrls = (_, randomItems) => [ Header.query(), + WatchlistList.query(), NewsList.query(), ...randomItems.filter((_, i) => i < 6).map((x) => GenreGrid.query(x)), Recommanded.query(), diff --git a/front/packages/ui/src/home/watchlist.tsx b/front/packages/ui/src/home/watchlist.tsx new file mode 100644 index 00000000..56c05a35 --- /dev/null +++ b/front/packages/ui/src/home/watchlist.tsx @@ -0,0 +1,92 @@ +/* + * 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 { + QueryIdentifier, + Watchlist, + WatchlistKind, + WatchlistP, + getDisplayDate, +} from "@kyoo/models"; +import { useYoshiki } from "yoshiki/native"; +import { ItemGrid } from "../browse/grid"; +import { InfiniteFetch } from "../fetch-infinite"; +import { useTranslation } from "react-i18next"; +import { Header } from "./genre"; +import { EpisodeBox, episodeDisplayNumber } from "../details/episode"; + +export const WatchlistList = () => { + const { t } = useTranslation(); + const { css } = useYoshiki(); + + return ( + <> +
+ + (x.kind === WatchlistKind.Show && x.watchStatus?.nextEpisode) || (x.isLoading && i % 2) + ? "episode" + : "item" + } + empty={t("home.none")} + > + {(x, i) => { + const episode = x.kind === WatchlistKind.Show ? x.watchStatus?.nextEpisode : null; + return (x.kind === WatchlistKind.Show && x.watchStatus?.nextEpisode) || + (x.isLoading && i % 2) ? ( + + ) : ( + + ); + }} + + + ); +}; + +WatchlistList.query = (): QueryIdentifier => ({ + parser: WatchlistP, + infinite: true, + path: ["watchlist"], + params: { + // Limit the inital numbers of items + limit: 10, + fields: ["watchStatus"], + }, +}); diff --git a/front/translations/en.json b/front/translations/en.json index 98c8f484..b969458b 100644 --- a/front/translations/en.json +++ b/front/translations/en.json @@ -2,6 +2,7 @@ "home": { "recommanded": "Recommanded", "news": "News", + "watchlist": "Continue watching", "info": "See more", "none": "No episodes" }, diff --git a/front/translations/fr.json b/front/translations/fr.json index 00dc0c3b..bb28f436 100644 --- a/front/translations/fr.json +++ b/front/translations/fr.json @@ -2,6 +2,7 @@ "home": { "recommanded": "Recommandé", "news": "Nouveautés", + "watchlist": "Continuer de regarder", "info": "Voir plus", "none": "Aucun episode" },