mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Create watchlist on the homepage
This commit is contained in:
parent
4cf9609153
commit
c87001d91e
@ -30,4 +30,5 @@ export * from "./episode";
|
||||
export * from "./season";
|
||||
export * from "./watch-info";
|
||||
export * from "./watch-status";
|
||||
export * from "./watchlist";
|
||||
export * from "./user";
|
||||
|
47
front/packages/models/src/resources/watchlist.ts
Normal file
47
front/packages/models/src/resources/watchlist.ts
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<typeof WatchlistP>;
|
@ -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 }}
|
||||
|
@ -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 }) => {
|
||||
/>
|
||||
)}
|
||||
</Fetch>
|
||||
<WatchlistList />
|
||||
<NewsList />
|
||||
{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(),
|
||||
|
92
front/packages/ui/src/home/watchlist.tsx
Normal file
92
front/packages/ui/src/home/watchlist.tsx
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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 (
|
||||
<>
|
||||
<Header title={t("home.watchlist")} />
|
||||
<InfiniteFetch
|
||||
query={WatchlistList.query()}
|
||||
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
|
||||
getItemType={(x, i) =>
|
||||
(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) ? (
|
||||
<EpisodeBox
|
||||
isLoading={x.isLoading as any}
|
||||
name={episode ? `${x.name} ${episodeDisplayNumber(episode)}` : undefined}
|
||||
overview={episode?.name}
|
||||
thumbnail={episode?.thumbnail ?? x.thumbnail}
|
||||
href={episode?.href}
|
||||
watchedPercent={x.watchStatus?.watchedPercent || null}
|
||||
watchedStatus={x.watchStatus?.status || null}
|
||||
// TODO: support this on mobile too
|
||||
// @ts-expect-error This is a web only property
|
||||
{...css({ gridColumnEnd: "span 2" })}
|
||||
/>
|
||||
) : (
|
||||
<ItemGrid
|
||||
isLoading={x.isLoading as any}
|
||||
href={x.href}
|
||||
name={x.name!}
|
||||
subtitle={!x.isLoading ? getDisplayDate(x) : undefined}
|
||||
poster={x.poster}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</InfiniteFetch>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
WatchlistList.query = (): QueryIdentifier<Watchlist> => ({
|
||||
parser: WatchlistP,
|
||||
infinite: true,
|
||||
path: ["watchlist"],
|
||||
params: {
|
||||
// Limit the inital numbers of items
|
||||
limit: 10,
|
||||
fields: ["watchStatus"],
|
||||
},
|
||||
});
|
@ -2,6 +2,7 @@
|
||||
"home": {
|
||||
"recommanded": "Recommanded",
|
||||
"news": "News",
|
||||
"watchlist": "Continue watching",
|
||||
"info": "See more",
|
||||
"none": "No episodes"
|
||||
},
|
||||
|
@ -2,6 +2,7 @@
|
||||
"home": {
|
||||
"recommanded": "Recommandé",
|
||||
"news": "Nouveautés",
|
||||
"watchlist": "Continuer de regarder",
|
||||
"info": "Voir plus",
|
||||
"none": "Aucun episode"
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user