diff --git a/front/packages/ui/src/browse/header.tsx b/front/packages/ui/src/browse/header.tsx index ba75cabd..52ee29e6 100644 --- a/front/packages/ui/src/browse/header.tsx +++ b/front/packages/ui/src/browse/header.tsx @@ -34,12 +34,14 @@ import ArrowUpward from "@material-symbols/svg-400/rounded/arrow_upward.svg"; import GridView from "@material-symbols/svg-400/rounded/grid_view.svg"; import Sort from "@material-symbols/svg-400/rounded/sort.svg"; import Style from "@material-symbols/svg-400/rounded/style.svg"; +import FilterList from "@material-symbols/svg-400/rounded/filter_list.svg"; import ViewList from "@material-symbols/svg-400/rounded/view_list.svg"; -import { forwardRef } from "react"; +import {type ComponentType, forwardRef} from "react"; import { useTranslation } from "react-i18next"; import { type PressableProps, View } from "react-native"; import { useYoshiki } from "yoshiki/native"; -import { Layout, SearchSort, SortOrd } from "./types"; +import {AllMediaTypes, Layout, SearchSort, SortOrd} from "./types"; +import type {SvgProps} from "react-native-svg"; const SortTrigger = forwardRef(function SortTrigger( { sortKey, ...props }, @@ -60,11 +62,38 @@ const SortTrigger = forwardRef(funct ); }); +const MediaTypeTrigger = forwardRef(function MediaTypeTrigger( + { mediaType, ...props }, + ref, +) { + const { css } = useYoshiki(); + const { t } = useTranslation(); + const labelKey = mediaType ? `browse.mediatypekey.${mediaType.key}` : "browse.mediatypelabel"; + return ( + + +

{t(labelKey as any)}

+
+ ); +}); + +export interface MediaType { + key: string; + icon: ComponentType; +} + export const BrowseSettings = ({ availableSorts, sortKey, sortOrd, setSort, + availableMediaTypes, + mediaType, + setMediaType, layout, setLayout, }: { @@ -72,6 +101,9 @@ export const BrowseSettings = ({ sortKey: string; sortOrd: SortOrd; setSort: (sort: string, ord: SortOrd) => void; + availableMediaTypes: MediaType[]; + mediaType?: MediaType; + setMediaType: (mediaType?: MediaType) => void; layout: Layout; setLayout: (layout: Layout) => void; }) => { @@ -81,58 +113,91 @@ export const BrowseSettings = ({ // TODO: implement filters in the front. return ( - - {filters.length !== 0 && ( - - - {filters.map((x) => ( - - ))} + <> + + + + {availableSorts.map((x) => ( + + setSort(x, sortKey === x && sortOrd === SortOrd.Asc ? SortOrd.Desc : SortOrd.Asc) + } + /> + ))} + +
+ setLayout(Layout.Grid)} + color={layout === Layout.Grid ? theme.accent : undefined} + {...tooltip(t("browse.switchToGrid"))} + {...css({ padding: ts(0.5), marginY: "auto" })} + /> + setLayout(Layout.List)} + color={layout === Layout.List ? theme.accent : undefined} + {...tooltip(t("browse.switchToList"))} + {...css({ padding: ts(0.5), marginY: "auto" })} + /> +
+ + + {availableMediaTypes.map((x) => ( + { + if (mediaType === x || x === AllMediaTypes) { + setMediaType(undefined) + } else { + setMediaType(x) + } + }} + /> + ))} + - )} - - - {availableSorts.map((x) => ( - - setSort(x, sortKey === x && sortOrd === SortOrd.Asc ? SortOrd.Desc : SortOrd.Asc) - } - /> - ))} - -
- setLayout(Layout.Grid)} - color={layout === Layout.Grid ? theme.accent : undefined} - {...tooltip(t("browse.switchToGrid"))} - {...css({ padding: ts(0.5), marginY: "auto" })} - /> - setLayout(Layout.List)} - color={layout === Layout.List ? theme.accent : undefined} - {...tooltip(t("browse.switchToList"))} - {...css({ padding: ts(0.5), marginY: "auto" })} - />
-
+ + {filters.length !== 0 && ( + + {/**/} + {filters.map((x) => ( +
+ +
+ ))} +
+ )} +
+ ); }; diff --git a/front/packages/ui/src/browse/index.tsx b/front/packages/ui/src/browse/index.tsx index be1be7c9..5c5736b7 100644 --- a/front/packages/ui/src/browse/index.tsx +++ b/front/packages/ui/src/browse/index.tsx @@ -32,9 +32,9 @@ import { DefaultLayout } from "../layout"; import { ItemGrid } from "./grid"; import { BrowseSettings } from "./header"; import { ItemList } from "./list"; -import { Layout, SortBy, SortOrd } from "./types"; +import {Layout, MediaTypes, SortBy, SortOrd} from "./types"; -const { useParam } = createParam<{ sortBy?: string }>(); +const { useParam } = createParam<{ sortBy?: string, mediaType?: string }>(); export const itemMap = ( item: LibraryItem, @@ -52,27 +52,30 @@ export const itemMap = ( item.kind === "show" ? item.watchStatus?.unseenEpisodesCount ?? item.episodesCount! : null, }); -const query = (sortKey?: SortBy, sortOrd?: SortOrd): QueryIdentifier => ({ +const query = (sortKey?: SortBy, sortOrd?: SortOrd, mediaTypeKey?: string): QueryIdentifier => ({ parser: LibraryItemP, path: ["items"], infinite: true, params: { sortBy: sortKey ? `${sortKey}:${sortOrd ?? "asc"}` : "name:asc", + filter: mediaTypeKey && mediaTypeKey !== "none" ? `kind eq ${mediaTypeKey}` : undefined, fields: ["watchStatus", "episodesCount"], }, }); export const BrowsePage: QueryPage = () => { const [sort, setSort] = useParam("sortBy"); + const [mediaTypeKey, setMediaTypeKey] = useParam("mediaType"); const sortKey = (sort?.split(":")[0] as SortBy) || SortBy.Name; const sortOrd = (sort?.split(":")[1] as SortOrd) || SortOrd.Asc; + const mediaType = mediaTypeKey !== undefined ? MediaTypes.find(t => t.key === mediaTypeKey) : undefined; const [layout, setLayout] = useState(Layout.Grid); const LayoutComponent = layout === Layout.Grid ? ItemGrid : ItemList; return ( { setSort={(key, ord) => { setSort(`${key}:${ord}`); }} + mediaType={mediaType} + availableMediaTypes={MediaTypes} + setMediaType={(mediaType) => { + setMediaTypeKey(mediaType?.key); + }} layout={layout} setLayout={setLayout} /> diff --git a/front/packages/ui/src/browse/types.ts b/front/packages/ui/src/browse/types.ts index f44181e0..8153b26f 100644 --- a/front/packages/ui/src/browse/types.ts +++ b/front/packages/ui/src/browse/types.ts @@ -18,6 +18,12 @@ * along with Kyoo. If not, see . */ +import {MediaType} from "./header"; +import Collection from "@material-symbols/svg-400/rounded/collections_bookmark.svg"; +import TV from "@material-symbols/svg-400/rounded/tv.svg"; +import Movie from "@material-symbols/svg-400/rounded/movie.svg"; +import All from "@material-symbols/svg-400/rounded/view_headline.svg"; + export enum SortBy { Name = "name", StartAir = "startAir", @@ -42,3 +48,24 @@ export enum Layout { Grid, List, } + +export const AllMediaTypes: MediaType = { + key: "all", + icon: All +} + +export const MediaTypes: MediaType[] = [ + AllMediaTypes, + { + key: "movie", + icon: Movie + }, + { + key: "show", + icon: TV, + }, + { + key: "collection", + icon: Collection + } +]; diff --git a/front/translations/en.json b/front/translations/en.json index 059f58f0..38004535 100644 --- a/front/translations/en.json +++ b/front/translations/en.json @@ -43,6 +43,14 @@ "season": "Season {{number}}" }, "browse": { + "mediatypekey": { + "all": "All", + "movie": "Movies", + "show": "Series", + "collection": "Collection" + }, + "mediatype-tt": "Media Type", + "mediatypelabel": "Media Type", "sortby": "Sort by {{key}}", "sortby-tt": "Sort by", "sortkey": {