mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-30 19:54:16 -04:00
Clean up kind handling in the front
This commit is contained in:
parent
7b035411c0
commit
2e0a0e5eb0
@ -17,7 +17,6 @@
|
|||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
using Kyoo.Abstractions.Models.Attributes;
|
using Kyoo.Abstractions.Models.Attributes;
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
using Kyoo.Abstractions.Models;
|
using Kyoo.Abstractions.Models;
|
||||||
|
@ -25,6 +25,7 @@ using Kyoo.Abstractions.Models.Attributes;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Serialization;
|
using Newtonsoft.Json.Serialization;
|
||||||
|
using static System.Text.Json.JsonNamingPolicy;
|
||||||
|
|
||||||
namespace Kyoo.Core.Api
|
namespace Kyoo.Core.Api
|
||||||
{
|
{
|
||||||
@ -99,7 +100,7 @@ namespace Kyoo.Core.Api
|
|||||||
PropertyName = "kind",
|
PropertyName = "kind",
|
||||||
UnderlyingName = "kind",
|
UnderlyingName = "kind",
|
||||||
PropertyType = typeof(string),
|
PropertyType = typeof(string),
|
||||||
ValueProvider = new FixedValueProvider(type.Name),
|
ValueProvider = new FixedValueProvider(CamelCase.ConvertName(type.Name)),
|
||||||
Readable = true,
|
Readable = true,
|
||||||
Writable = false,
|
Writable = false,
|
||||||
TypeNameHandling = TypeNameHandling.None,
|
TypeNameHandling = TypeNameHandling.None,
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ReactNode, createContext, useContext, useEffect, useMemo, useRef } from "react";
|
import { ReactNode, createContext, useContext, useEffect, useMemo, useRef } from "react";
|
||||||
import { UserP } from "./resources";
|
import { User, UserP } from "./resources";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { zdate } from "./utils";
|
import { zdate } from "./utils";
|
||||||
import { removeAccounts, setAccountCookie, updateAccount } from "./account-internal";
|
import { removeAccounts, setAccountCookie, updateAccount } from "./account-internal";
|
||||||
@ -38,13 +38,13 @@ export const TokenP = z.object({
|
|||||||
});
|
});
|
||||||
export type Token = z.infer<typeof TokenP>;
|
export type Token = z.infer<typeof TokenP>;
|
||||||
|
|
||||||
export const AccountP = UserP.and(
|
export const AccountP = UserP.merge(z.object({
|
||||||
z.object({
|
// set it optional for accounts logged in before the kind was present
|
||||||
token: TokenP,
|
kind: z.literal("user").optional(),
|
||||||
apiUrl: z.string(),
|
token: TokenP,
|
||||||
selected: z.boolean(),
|
apiUrl: z.string(),
|
||||||
}),
|
selected: z.boolean(),
|
||||||
);
|
}));
|
||||||
export type Account = z.infer<typeof AccountP>;
|
export type Account = z.infer<typeof AccountP>;
|
||||||
|
|
||||||
const AccountContext = createContext<(Account & { select: () => void; remove: () => void })[]>([]);
|
const AccountContext = createContext<(Account & { select: () => void; remove: () => void })[]>([]);
|
||||||
@ -100,7 +100,7 @@ export const AccountProvider = ({
|
|||||||
const user = useFetch({
|
const user = useFetch({
|
||||||
path: ["auth", "me"],
|
path: ["auth", "me"],
|
||||||
parser: UserP,
|
parser: UserP,
|
||||||
placeholderData: selected,
|
placeholderData: selected as User,
|
||||||
enabled: !!selected,
|
enabled: !!selected,
|
||||||
timeout: 5_000,
|
timeout: 5_000,
|
||||||
});
|
});
|
||||||
|
@ -22,7 +22,7 @@ import { z } from "zod";
|
|||||||
import { withImages, ResourceP } from "../traits";
|
import { withImages, ResourceP } from "../traits";
|
||||||
|
|
||||||
export const CollectionP = withImages(
|
export const CollectionP = withImages(
|
||||||
ResourceP.extend({
|
ResourceP("collection").extend({
|
||||||
/**
|
/**
|
||||||
* The title of this collection.
|
* The title of this collection.
|
||||||
*/
|
*/
|
||||||
@ -31,8 +31,7 @@ export const CollectionP = withImages(
|
|||||||
* The summary of this show.
|
* The summary of this show.
|
||||||
*/
|
*/
|
||||||
overview: z.string().nullable(),
|
overview: z.string().nullable(),
|
||||||
}),
|
})
|
||||||
"collections",
|
|
||||||
).transform((x) => ({
|
).transform((x) => ({
|
||||||
...x,
|
...x,
|
||||||
href: `/collection/${x.slug}`,
|
href: `/collection/${x.slug}`,
|
||||||
|
@ -24,7 +24,7 @@ import { withImages, imageFn } from "../traits";
|
|||||||
import { ResourceP } from "../traits/resource";
|
import { ResourceP } from "../traits/resource";
|
||||||
|
|
||||||
export const BaseEpisodeP = withImages(
|
export const BaseEpisodeP = withImages(
|
||||||
ResourceP.extend({
|
ResourceP("episode").extend({
|
||||||
/**
|
/**
|
||||||
* The season in witch this episode is in.
|
* The season in witch this episode is in.
|
||||||
*/
|
*/
|
||||||
@ -72,7 +72,6 @@ export const BaseEpisodeP = withImages(
|
|||||||
*/
|
*/
|
||||||
showId: z.string(),
|
showId: z.string(),
|
||||||
}),
|
}),
|
||||||
"episodes",
|
|
||||||
)
|
)
|
||||||
.transform((x) => ({
|
.transform((x) => ({
|
||||||
...x,
|
...x,
|
||||||
|
@ -23,28 +23,19 @@ import { CollectionP } from "./collection";
|
|||||||
import { MovieP } from "./movie";
|
import { MovieP } from "./movie";
|
||||||
import { ShowP } from "./show";
|
import { ShowP } from "./show";
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of item, ether a show, a movie or a collection.
|
|
||||||
*/
|
|
||||||
export enum ItemKind {
|
|
||||||
Show = "Show",
|
|
||||||
Movie = "Movie",
|
|
||||||
Collection = "Collection",
|
|
||||||
}
|
|
||||||
|
|
||||||
export const LibraryItemP = z.union([
|
export const LibraryItemP = z.union([
|
||||||
/*
|
/*
|
||||||
* Either a Show
|
* Either a Show
|
||||||
*/
|
*/
|
||||||
ShowP.and(z.object({ kind: z.literal(ItemKind.Show) })),
|
ShowP,
|
||||||
/*
|
/*
|
||||||
* Or a Movie
|
* Or a Movie
|
||||||
*/
|
*/
|
||||||
MovieP.and(z.object({ kind: z.literal(ItemKind.Movie) })),
|
MovieP,
|
||||||
/*
|
/*
|
||||||
* Or a Collection
|
* Or a Collection
|
||||||
*/
|
*/
|
||||||
CollectionP.and(z.object({ kind: z.literal(ItemKind.Collection) })),
|
CollectionP,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,7 +29,7 @@ import { MetadataP } from "./metadata";
|
|||||||
import { WatchStatusP } from "./watch-status";
|
import { WatchStatusP } from "./watch-status";
|
||||||
|
|
||||||
export const MovieP = withImages(
|
export const MovieP = withImages(
|
||||||
ResourceP.extend({
|
ResourceP("movie").extend({
|
||||||
/**
|
/**
|
||||||
* The title of this movie.
|
* The title of this movie.
|
||||||
*/
|
*/
|
||||||
@ -105,7 +105,6 @@ export const MovieP = withImages(
|
|||||||
*/
|
*/
|
||||||
watchStatus: WatchStatusP.optional().nullable(),
|
watchStatus: WatchStatusP.optional().nullable(),
|
||||||
}),
|
}),
|
||||||
"movies",
|
|
||||||
)
|
)
|
||||||
.transform((x) => ({
|
.transform((x) => ({
|
||||||
...x,
|
...x,
|
||||||
|
@ -22,23 +22,15 @@ import { z } from "zod";
|
|||||||
import { MovieP } from "./movie";
|
import { MovieP } from "./movie";
|
||||||
import { EpisodeP } from "./episode";
|
import { EpisodeP } from "./episode";
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of item, ether a a movie or an episode.
|
|
||||||
*/
|
|
||||||
export enum NewsKind {
|
|
||||||
Episode = "Episode",
|
|
||||||
Movie = "Movie",
|
|
||||||
}
|
|
||||||
|
|
||||||
export const NewsP = z.union([
|
export const NewsP = z.union([
|
||||||
/*
|
/*
|
||||||
* Either an episode
|
* Either an episode
|
||||||
*/
|
*/
|
||||||
EpisodeP.and(z.object({ kind: z.literal(NewsKind.Episode) })),
|
EpisodeP,
|
||||||
/*
|
/*
|
||||||
* Or a Movie
|
* Or a Movie
|
||||||
*/
|
*/
|
||||||
MovieP.and(z.object({ kind: z.literal(NewsKind.Movie) })),
|
MovieP,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +23,7 @@ import { withImages } from "../traits";
|
|||||||
import { ResourceP } from "../traits/resource";
|
import { ResourceP } from "../traits/resource";
|
||||||
|
|
||||||
export const PersonP = withImages(
|
export const PersonP = withImages(
|
||||||
ResourceP.extend({
|
ResourceP("people").extend({
|
||||||
/**
|
/**
|
||||||
* The name of this person.
|
* The name of this person.
|
||||||
*/
|
*/
|
||||||
@ -40,7 +40,6 @@ export const PersonP = withImages(
|
|||||||
*/
|
*/
|
||||||
role: z.string().optional(),
|
role: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
"people",
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +24,7 @@ import { withImages } from "../traits";
|
|||||||
import { ResourceP } from "../traits/resource";
|
import { ResourceP } from "../traits/resource";
|
||||||
|
|
||||||
export const SeasonP = withImages(
|
export const SeasonP = withImages(
|
||||||
ResourceP.extend({
|
ResourceP("season").extend({
|
||||||
/**
|
/**
|
||||||
* The name of this season.
|
* The name of this season.
|
||||||
*/
|
*/
|
||||||
@ -50,7 +50,6 @@ export const SeasonP = withImages(
|
|||||||
*/
|
*/
|
||||||
episodesCount: z.number(),
|
episodesCount: z.number(),
|
||||||
}),
|
}),
|
||||||
"seasons",
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,10 +22,8 @@ import { z } from "zod";
|
|||||||
import { zdate } from "../utils";
|
import { zdate } from "../utils";
|
||||||
import { withImages, ResourceP } from "../traits";
|
import { withImages, ResourceP } from "../traits";
|
||||||
import { Genre } from "./genre";
|
import { Genre } from "./genre";
|
||||||
import { SeasonP } from "./season";
|
|
||||||
import { StudioP } from "./studio";
|
import { StudioP } from "./studio";
|
||||||
import { BaseEpisodeP } from "./episode.base";
|
import { BaseEpisodeP } from "./episode.base";
|
||||||
import { CollectionP } from "./collection";
|
|
||||||
import { MetadataP } from "./metadata";
|
import { MetadataP } from "./metadata";
|
||||||
import { ShowWatchStatusP } from "./watch-status";
|
import { ShowWatchStatusP } from "./watch-status";
|
||||||
|
|
||||||
@ -40,7 +38,7 @@ export enum Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ShowP = withImages(
|
export const ShowP = withImages(
|
||||||
ResourceP.extend({
|
ResourceP("show").extend({
|
||||||
/**
|
/**
|
||||||
* The title of this show.
|
* The title of this show.
|
||||||
*/
|
*/
|
||||||
@ -106,7 +104,6 @@ export const ShowP = withImages(
|
|||||||
*/
|
*/
|
||||||
episodesCount: z.number().int().gte(0).optional(),
|
episodesCount: z.number().int().gte(0).optional(),
|
||||||
}),
|
}),
|
||||||
"shows",
|
|
||||||
)
|
)
|
||||||
.transform((x) => {
|
.transform((x) => {
|
||||||
if (!x.thumbnail && x.poster) {
|
if (!x.thumbnail && x.poster) {
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { ResourceP } from "../traits/resource";
|
import { ResourceP } from "../traits/resource";
|
||||||
|
|
||||||
export const StudioP = ResourceP.extend({
|
export const StudioP = ResourceP("studio").extend({
|
||||||
/**
|
/**
|
||||||
* The name of this studio.
|
* The name of this studio.
|
||||||
*/
|
*/
|
||||||
|
@ -21,10 +21,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { ResourceP } from "../traits/resource";
|
import { ResourceP } from "../traits/resource";
|
||||||
|
|
||||||
/**
|
export const UserP = ResourceP("user").extend({
|
||||||
* The library that will contain Shows, Collections...
|
|
||||||
*/
|
|
||||||
export const UserP = ResourceP.extend({
|
|
||||||
/**
|
/**
|
||||||
* The name of this user.
|
* The name of this user.
|
||||||
*/
|
*/
|
||||||
|
@ -22,23 +22,15 @@ import { z } from "zod";
|
|||||||
import { MovieP } from "./movie";
|
import { MovieP } from "./movie";
|
||||||
import { ShowP } from "./show";
|
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([
|
export const WatchlistP = z.union([
|
||||||
/*
|
/*
|
||||||
* Either a show
|
* Either a show
|
||||||
*/
|
*/
|
||||||
ShowP.and(z.object({ kind: z.literal(WatchlistKind.Show) })),
|
ShowP,
|
||||||
/*
|
/*
|
||||||
* Or a Movie
|
* Or a Movie
|
||||||
*/
|
*/
|
||||||
MovieP.and(z.object({ kind: z.literal(WatchlistKind.Movie) })),
|
MovieP,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,13 +62,13 @@ const addQualities = (x: object | null | undefined, href: string) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const withImages = <T extends ZodRawShape>(parser: ZodObject<T>, type: string) => {
|
export const withImages = <T extends ZodRawShape>(parser: ZodObject<T>) => {
|
||||||
return parser.merge(ImagesP).transform((x) => {
|
return parser.merge(ImagesP).transform((x) => {
|
||||||
return {
|
return {
|
||||||
...x,
|
...x,
|
||||||
poster: addQualities(x.poster, `/${type}/${x.slug}/poster`),
|
poster: addQualities(x.poster, `/${x.kind}/${x.slug}/poster`),
|
||||||
thumbnail: addQualities(x.thumbnail, `/${type}/${x.slug}/thumbnail`),
|
thumbnail: addQualities(x.thumbnail, `/${x.kind}/${x.slug}/thumbnail`),
|
||||||
logo: addQualities(x.logo, `/${type}/${x.slug}/logo`),
|
logo: addQualities(x.logo, `/${x.kind}/${x.slug}/logo`),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -20,20 +20,26 @@
|
|||||||
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const ResourceP = z.object({
|
export const ResourceP = <T extends string>(kind: T) =>
|
||||||
/**
|
z.object({
|
||||||
* A unique ID for this type of resource. This can't be changed and duplicates are not allowed.
|
/**
|
||||||
*/
|
* A unique ID for this type of resource. This can't be changed and duplicates are not allowed.
|
||||||
id: z.string(),
|
*/
|
||||||
|
id: z.string(),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A human-readable identifier that can be used instead of an ID. A slug must be unique for a type
|
* A human-readable identifier that can be used instead of an ID. A slug must be unique for a type
|
||||||
* of resource but it can be changed.
|
* of resource but it can be changed.
|
||||||
*/
|
*/
|
||||||
slug: z.string(),
|
slug: z.string(),
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* The type of resource
|
||||||
|
*/
|
||||||
|
kind: z.literal(kind),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base trait used to represent identifiable resources.
|
* The base trait used to represent identifiable resources.
|
||||||
*/
|
*/
|
||||||
export type Resource = z.infer<typeof ResourceP>;
|
export type Resource = z.infer<ReturnType<typeof ResourceP>>;
|
||||||
|
@ -71,7 +71,7 @@ export const ImageBackground = <AsProps = ViewProps,>({
|
|||||||
}: {
|
}: {
|
||||||
as?: ComponentType<AsProps>;
|
as?: ComponentType<AsProps>;
|
||||||
gradient?: Partial<LinearGradientProps> | boolean;
|
gradient?: Partial<LinearGradientProps> | boolean;
|
||||||
children: ReactNode;
|
children?: ReactNode;
|
||||||
containerStyle?: YoshikiEnhanced<ViewStyle>;
|
containerStyle?: YoshikiEnhanced<ViewStyle>;
|
||||||
imageStyle?: YoshikiEnhanced<ImageStyle>;
|
imageStyle?: YoshikiEnhanced<ImageStyle>;
|
||||||
hideLoad?: boolean;
|
hideLoad?: boolean;
|
||||||
|
@ -23,7 +23,6 @@ import {
|
|||||||
QueryPage,
|
QueryPage,
|
||||||
LibraryItem,
|
LibraryItem,
|
||||||
LibraryItemP,
|
LibraryItemP,
|
||||||
ItemKind,
|
|
||||||
getDisplayDate,
|
getDisplayDate,
|
||||||
} from "@kyoo/models";
|
} from "@kyoo/models";
|
||||||
import { ComponentProps, useState } from "react";
|
import { ComponentProps, useState } from "react";
|
||||||
@ -47,16 +46,16 @@ export const itemMap = (
|
|||||||
isLoading: item.isLoading,
|
isLoading: item.isLoading,
|
||||||
slug: item.slug,
|
slug: item.slug,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
subtitle: item.kind !== ItemKind.Collection ? getDisplayDate(item) : undefined,
|
subtitle: item.kind !== "collection" ? getDisplayDate(item) : undefined,
|
||||||
href: item.href,
|
href: item.href,
|
||||||
poster: item.poster,
|
poster: item.poster,
|
||||||
thumbnail: item.thumbnail,
|
thumbnail: item.thumbnail,
|
||||||
watchStatus: item.kind !== ItemKind.Collection ? item.watchStatus?.status ?? null : null,
|
watchStatus: item.kind !== "collection" ? item.watchStatus?.status ?? null : null,
|
||||||
type: item.kind.toLowerCase() as any,
|
type: item.kind,
|
||||||
watchPercent:
|
watchPercent:
|
||||||
item.kind !== ItemKind.Collection ? item.watchStatus?.watchedPercent ?? null : null,
|
item.kind !== "collection" ? item.watchStatus?.watchedPercent ?? null : null,
|
||||||
unseenEpisodesCount:
|
unseenEpisodesCount:
|
||||||
item.kind === ItemKind.Show
|
item.kind === "show"
|
||||||
? item.watchStatus?.unseenEpisodesCount ?? item.episodesCount!
|
? item.watchStatus?.unseenEpisodesCount ?? item.episodesCount!
|
||||||
: null,
|
: null,
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
import {
|
import {
|
||||||
Collection,
|
Collection,
|
||||||
CollectionP,
|
CollectionP,
|
||||||
ItemKind,
|
|
||||||
LibraryItem,
|
LibraryItem,
|
||||||
LibraryItemP,
|
LibraryItemP,
|
||||||
QueryIdentifier,
|
QueryIdentifier,
|
||||||
@ -161,20 +160,20 @@ export const CollectionPage: QueryPage<{ slug: string }> = ({ slug }) => {
|
|||||||
<ItemDetails
|
<ItemDetails
|
||||||
isLoading={x.isLoading as any}
|
isLoading={x.isLoading as any}
|
||||||
slug={x.slug}
|
slug={x.slug}
|
||||||
type={x.kind?.toLowerCase() as any}
|
type={x.kind}
|
||||||
name={x.name}
|
name={x.name}
|
||||||
tagline={"tagline" in x ? x.tagline : null}
|
tagline={"tagline" in x ? x.tagline : null}
|
||||||
overview={x.overview}
|
overview={x.overview}
|
||||||
poster={x.poster}
|
poster={x.poster}
|
||||||
subtitle={x.kind !== ItemKind.Collection && !x.isLoading ? getDisplayDate(x) : undefined}
|
subtitle={x.kind !== "collection" && !x.isLoading ? getDisplayDate(x) : undefined}
|
||||||
genres={"genres" in x ? x.genres : null}
|
genres={"genres" in x ? x.genres : null}
|
||||||
href={x.href}
|
href={x.href}
|
||||||
playHref={x.kind !== ItemKind.Collection && !x.isLoading ? x.playHref : undefined}
|
playHref={x.kind !== "collection" && !x.isLoading ? x.playHref : undefined}
|
||||||
watchStatus={
|
watchStatus={
|
||||||
!x.isLoading && x.kind !== ItemKind.Collection ? x.watchStatus?.status ?? null : null
|
!x.isLoading && x.kind !== "collection" ? x.watchStatus?.status ?? null : null
|
||||||
}
|
}
|
||||||
unseenEpisodesCount={
|
unseenEpisodesCount={
|
||||||
x.kind === ItemKind.Show ? x.watchStatus?.unseenEpisodesCount ?? x.episodesCount! : null
|
x.kind === "show" ? x.watchStatus?.unseenEpisodesCount ?? x.episodesCount! : null
|
||||||
}
|
}
|
||||||
{...css({ marginX: ItemGrid.layout.gap })}
|
{...css({ marginX: ItemGrid.layout.gap })}
|
||||||
/>
|
/>
|
||||||
|
@ -37,7 +37,7 @@ import { percent, rem, Stylable, Theme, useYoshiki } from "yoshiki/native";
|
|||||||
import { KyooImage, WatchStatusV } from "@kyoo/models";
|
import { KyooImage, WatchStatusV } from "@kyoo/models";
|
||||||
import { ItemProgress } from "../browse/grid";
|
import { ItemProgress } from "../browse/grid";
|
||||||
import { EpisodesContext } from "../components/context-menus";
|
import { EpisodesContext } from "../components/context-menus";
|
||||||
import { useRef, useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export const episodeDisplayNumber = (
|
export const episodeDisplayNumber = (
|
||||||
episode: {
|
episode: {
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Genre, ItemKind, QueryPage } from "@kyoo/models";
|
import { Genre, QueryPage } from "@kyoo/models";
|
||||||
import { Fetch } from "../fetch";
|
import { Fetch } from "../fetch";
|
||||||
import { Header } from "./header";
|
import { Header } from "./header";
|
||||||
import { DefaultLayout } from "../layout";
|
import { DefaultLayout } from "../layout";
|
||||||
@ -40,7 +40,7 @@ export const HomePage: QueryPage<{}, Genre> = ({ randomItems }) => {
|
|||||||
tagline={"tagline" in x ? x.tagline : null}
|
tagline={"tagline" in x ? x.tagline : null}
|
||||||
overview={x.overview}
|
overview={x.overview}
|
||||||
thumbnail={x.thumbnail}
|
thumbnail={x.thumbnail}
|
||||||
link={x.kind !== ItemKind.Collection && !x.isLoading ? x.playHref : undefined}
|
link={x.kind !== "collection" && !x.isLoading ? x.playHref : undefined}
|
||||||
infoLink={x.href}
|
infoLink={x.href}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { News, NewsKind, NewsP, QueryIdentifier, getDisplayDate } from "@kyoo/models";
|
import { News, NewsP, QueryIdentifier, getDisplayDate } from "@kyoo/models";
|
||||||
import { ItemGrid } from "../browse/grid";
|
import { ItemGrid } from "../browse/grid";
|
||||||
import { InfiniteFetch } from "../fetch-infinite";
|
import { InfiniteFetch } from "../fetch-infinite";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -37,13 +37,13 @@ export const NewsList = () => {
|
|||||||
query={NewsList.query()}
|
query={NewsList.query()}
|
||||||
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
|
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
|
||||||
getItemType={(x, i) =>
|
getItemType={(x, i) =>
|
||||||
x.kind === NewsKind.Movie || (x.isLoading && i % 2) ? "movie" : "episode"
|
x.kind === "movie" || (x.isLoading && i % 2) ? "movie" : "episode"
|
||||||
}
|
}
|
||||||
getItemSize={(kind) => (kind === "episode" ? 2 : 1)}
|
getItemSize={(kind) => (kind === "episode" ? 2 : 1)}
|
||||||
empty={t("home.none")}
|
empty={t("home.none")}
|
||||||
>
|
>
|
||||||
{(x, i) =>
|
{(x, i) =>
|
||||||
x.kind === NewsKind.Movie || (x.isLoading && i % 2) ? (
|
x.kind === "movie" || (x.isLoading && i % 2) ? (
|
||||||
<ItemGrid
|
<ItemGrid
|
||||||
isLoading={x.isLoading as any}
|
isLoading={x.isLoading as any}
|
||||||
href={x.href}
|
href={x.href}
|
||||||
@ -58,9 +58,9 @@ export const NewsList = () => {
|
|||||||
<EpisodeBox
|
<EpisodeBox
|
||||||
isLoading={x.isLoading as any}
|
isLoading={x.isLoading as any}
|
||||||
slug={x.slug}
|
slug={x.slug}
|
||||||
showSlug={x.kind === NewsKind.Episode ? x.showId : null}
|
showSlug={x.kind === "episode" ? x.showId : null}
|
||||||
name={
|
name={
|
||||||
x.kind === NewsKind.Episode
|
x.kind === "episode"
|
||||||
? `${x.show!.name} ${episodeDisplayNumber(x)}`
|
? `${x.show!.name} ${episodeDisplayNumber(x)}`
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Genre,
|
Genre,
|
||||||
ItemKind,
|
|
||||||
KyooImage,
|
KyooImage,
|
||||||
LibraryItem,
|
LibraryItem,
|
||||||
LibraryItemP,
|
LibraryItemP,
|
||||||
@ -258,24 +257,20 @@ export const Recommanded = () => {
|
|||||||
<ItemDetails
|
<ItemDetails
|
||||||
isLoading={x.isLoading as any}
|
isLoading={x.isLoading as any}
|
||||||
slug={x.slug}
|
slug={x.slug}
|
||||||
type={x.kind?.toLowerCase() as any}
|
type={x.kind}
|
||||||
name={x.name}
|
name={x.name}
|
||||||
tagline={"tagline" in x ? x.tagline : null}
|
tagline={"tagline" in x ? x.tagline : null}
|
||||||
overview={x.overview}
|
overview={x.overview}
|
||||||
poster={x.poster}
|
poster={x.poster}
|
||||||
subtitle={
|
subtitle={x.kind !== "collection" && !x.isLoading ? getDisplayDate(x) : undefined}
|
||||||
x.kind !== ItemKind.Collection && !x.isLoading ? getDisplayDate(x) : undefined
|
|
||||||
}
|
|
||||||
genres={"genres" in x ? x.genres : null}
|
genres={"genres" in x ? x.genres : null}
|
||||||
href={x.href}
|
href={x.href}
|
||||||
playHref={x.kind !== ItemKind.Collection && !x.isLoading ? x.playHref : undefined}
|
playHref={x.kind !== "collection" && !x.isLoading ? x.playHref : undefined}
|
||||||
watchStatus={
|
watchStatus={
|
||||||
!x.isLoading && x.kind !== ItemKind.Collection ? x.watchStatus?.status ?? null : null
|
!x.isLoading && x.kind !== "collection" ? x.watchStatus?.status ?? null : null
|
||||||
}
|
}
|
||||||
unseenEpisodesCount={
|
unseenEpisodesCount={
|
||||||
x.kind === ItemKind.Show
|
x.kind === "show" ? x.watchStatus?.unseenEpisodesCount ?? x.episodesCount! : null
|
||||||
? x.watchStatus?.unseenEpisodesCount ?? x.episodesCount!
|
|
||||||
: null
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
import {
|
import {
|
||||||
QueryIdentifier,
|
QueryIdentifier,
|
||||||
Watchlist,
|
Watchlist,
|
||||||
WatchlistKind,
|
|
||||||
WatchlistP,
|
WatchlistP,
|
||||||
getDisplayDate,
|
getDisplayDate,
|
||||||
useAccount,
|
useAccount,
|
||||||
@ -48,7 +47,7 @@ export const WatchlistList = () => {
|
|||||||
query={WatchlistList.query()}
|
query={WatchlistList.query()}
|
||||||
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
|
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
|
||||||
getItemType={(x, i) =>
|
getItemType={(x, i) =>
|
||||||
(x.kind === WatchlistKind.Show && x.watchStatus?.nextEpisode) || (x.isLoading && i % 2)
|
(x.kind === "show" && x.watchStatus?.nextEpisode) || (x.isLoading && i % 2)
|
||||||
? "episode"
|
? "episode"
|
||||||
: "item"
|
: "item"
|
||||||
}
|
}
|
||||||
@ -56,8 +55,8 @@ export const WatchlistList = () => {
|
|||||||
empty={t("home.none")}
|
empty={t("home.none")}
|
||||||
>
|
>
|
||||||
{(x, i) => {
|
{(x, i) => {
|
||||||
const episode = x.kind === WatchlistKind.Show ? x.watchStatus?.nextEpisode : null;
|
const episode = x.kind === "show" ? x.watchStatus?.nextEpisode : null;
|
||||||
return (x.kind === WatchlistKind.Show && x.watchStatus?.nextEpisode) ||
|
return (x.kind === "show" && x.watchStatus?.nextEpisode) ||
|
||||||
(x.isLoading && i % 2) ? (
|
(x.isLoading && i % 2) ? (
|
||||||
<EpisodeBox
|
<EpisodeBox
|
||||||
isLoading={x.isLoading as any}
|
isLoading={x.isLoading as any}
|
||||||
@ -83,9 +82,9 @@ export const WatchlistList = () => {
|
|||||||
watchStatus={x.watchStatus?.status || null}
|
watchStatus={x.watchStatus?.status || null}
|
||||||
watchPercent={x.watchStatus?.watchedPercent || null}
|
watchPercent={x.watchStatus?.watchedPercent || null}
|
||||||
unseenEpisodesCount={
|
unseenEpisodesCount={
|
||||||
x.kind === WatchlistKind.Show ? x.watchStatus?.unseenEpisodesCount : null
|
x.kind === "show" ? x.watchStatus?.unseenEpisodesCount : null
|
||||||
}
|
}
|
||||||
type={x.kind === WatchlistKind.Movie ? "movie" : "show"}
|
type={x.kind}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user