From a369682a26dc3a51f55ac4cddf9a9d4d010e91e3 Mon Sep 17 00:00:00 2001 From: Jelle van Snik Date: Mon, 16 Jan 2023 21:19:49 +0100 Subject: [PATCH] add continue watching and bookmarks back --- src/components/media/MediaCard.tsx | 2 - src/index.tsx | 2 + src/state/bookmark/context.tsx | 10 +-- src/state/bookmark/store.ts | 1 - src/state/watched/context.tsx | 107 ++++++++++++++++------------- src/state/watched/store.ts | 2 - src/views/media/MediaView.tsx | 10 ++- src/views/search/HomeView.tsx | 62 ++++++++--------- 8 files changed, 99 insertions(+), 97 deletions(-) diff --git a/src/components/media/MediaCard.tsx b/src/components/media/MediaCard.tsx index 7b63bf7e..e51db836 100644 --- a/src/components/media/MediaCard.tsx +++ b/src/components/media/MediaCard.tsx @@ -8,8 +8,6 @@ export interface MediaCardProps { linkable?: boolean; } -// TODO add progress back - function MediaCardContent({ media, linkable }: MediaCardProps) { return (
diff --git a/src/state/bookmark/context.tsx b/src/state/bookmark/context.tsx index 977b4596..b4593be2 100644 --- a/src/state/bookmark/context.tsx +++ b/src/state/bookmark/context.tsx @@ -63,15 +63,7 @@ export function BookmarkContextProvider(props: { children: ReactNode }) { if (bookmarked) { const itemIndex = getBookmarkIndexFromMedia(data.bookmarks, media); if (itemIndex === -1) { - const item = { - id: media.id, - type: media.type, - // providerId: media.providerId, - title: media.title, - year: media.year, - // episodeId: media.episodeId, - // seasonId: media.seasonId, - }; + const item: MWMediaMeta = { ...media }; data.bookmarks.push(item); } } else { diff --git a/src/state/bookmark/store.ts b/src/state/bookmark/store.ts index 06456b78..089a6693 100644 --- a/src/state/bookmark/store.ts +++ b/src/state/bookmark/store.ts @@ -9,7 +9,6 @@ export const BookmarkStore = versionedStoreBuilder() version: 1, migrate() { return { - // TODO actually migrate bookmarks: [], }; }, diff --git a/src/state/watched/context.tsx b/src/state/watched/context.tsx index c434801e..cefec243 100644 --- a/src/state/watched/context.tsx +++ b/src/state/watched/context.tsx @@ -1,5 +1,6 @@ -import { MWMediaMeta, MWMediaType } from "@/backend/metadata/types"; -import React, { +import { DetailedMeta } from "@/backend/metadata/getmeta"; +import { MWMediaMeta } from "@/backend/metadata/types"; +import { createContext, ReactNode, useCallback, @@ -9,7 +10,16 @@ import React, { } from "react"; import { VideoProgressStore } from "./store"; -interface WatchedStoreItem extends MWMediaMeta { +interface MediaItem { + meta: MWMediaMeta; + series?: { + episode: number; + season: number; + }; +} + +interface WatchedStoreItem { + item: MediaItem; progress: number; percentage: number; } @@ -19,18 +29,11 @@ export interface WatchedStoreData { } interface WatchedStoreDataWrapper { - updateProgress(media: MWMediaMeta, progress: number, total: number): void; + updateProgress(media: MediaItem, progress: number, total: number): void; getFilteredWatched(): WatchedStoreItem[]; watched: WatchedStoreData; } -export function getWatchedFromPortable( - items: WatchedStoreItem[], - media: MWMediaMeta -): WatchedStoreItem | undefined { - return undefined; -} - const WatchedContext = createContext({ updateProgress: () => {}, getFilteredWatched: () => [], @@ -62,49 +65,39 @@ export function WatchedContextProvider(props: { children: ReactNode }) { const contextValue = useMemo( () => ({ - updateProgress( - media: MWMediaMeta, - progress: number, - total: number - ): void { - // setWatched((data: WatchedStoreData) => { - // let item = getWatchedFromPortable(data.items, media); - // if (!item) { - // item = { - // mediaId: media.mediaId, - // mediaType: media.mediaType, - // providerId: media.providerId, - // title: media.title, - // year: media.year, - // percentage: 0, - // progress: 0, - // episodeId: media.episodeId, - // seasonId: media.seasonId, - // }; - // data.items.push(item); - // } - // // update actual item - // item.progress = progress; - // item.percentage = Math.round((progress / total) * 100); - // return data; - // }); + updateProgress(media: MediaItem, progress: number, total: number): void { + setWatched((data: WatchedStoreData) => { + let item = data.items.find((v) => v.item.meta.id === media.meta.id); + if (!item) { + item = { + item: { + ...media, + meta: { ...media.meta }, + series: media.series ? { ...media.series } : undefined, + }, + progress: 0, + percentage: 0, + }; + data.items.push(item); + } + // update actual item + item.progress = progress; + item.percentage = Math.round((progress / total) * 100); + return data; + }); }, getFilteredWatched() { - // remove disabled providers - // let filtered = watched.items.filter( - // (item) => getProviderMetadata(item.providerId)?.enabled - // ); let filtered = watched.items; - // // get highest episode number for every anime/season + // get highest episode number for every anime/season const highestEpisode: Record = {}; const highestWatchedItem: Record = {}; filtered = filtered.filter((item) => { - if ([MWMediaType.ANIME, MWMediaType.SERIES].includes(item.type)) { - const key = `${item.type}-${item.id}`; + if (item.item.series) { + const key = item.item.meta.id; const current: [number, number] = [ - item.episodeId ? parseInt(item.episodeId, 10) : -1, - item.seasonId ? parseInt(item.seasonId, 10) : -1, + item.item.series.episode, + item.item.series.season, ]; let existing = highestEpisode[key]; if (!existing) { @@ -127,7 +120,7 @@ export function WatchedContextProvider(props: { children: ReactNode }) { }, watched, }), - [watched] + [watched, setWatched] ); return ( @@ -140,3 +133,23 @@ export function WatchedContextProvider(props: { children: ReactNode }) { export function useWatchedContext() { return useContext(WatchedContext); } + +export function useWatchedItem(meta: DetailedMeta | null) { + const { watched, updateProgress } = useContext(WatchedContext); + const item = useMemo( + () => watched.items.find((v) => meta && v.item.meta.id === meta?.meta.id), + [watched, meta] + ); + + const callback = useCallback( + (progress: number, total: number) => { + if (meta) { + // TODO add series support + updateProgress({ meta: meta.meta }, progress, total); + } + }, + [updateProgress, meta] + ); + + return { updateProgress: callback, watchedItem: item }; +} diff --git a/src/state/watched/store.ts b/src/state/watched/store.ts index 4ea10100..aada4131 100644 --- a/src/state/watched/store.ts +++ b/src/state/watched/store.ts @@ -8,7 +8,6 @@ export const VideoProgressStore = versionedStoreBuilder() .addVersion({ version: 1, migrate() { - // TODO add migration back return { items: [], }; @@ -17,7 +16,6 @@ export const VideoProgressStore = versionedStoreBuilder() .addVersion({ version: 2, migrate() { - // TODO actually migrate return { items: [], }; diff --git a/src/views/media/MediaView.tsx b/src/views/media/MediaView.tsx index b019e688..4c92fd4d 100644 --- a/src/views/media/MediaView.tsx +++ b/src/views/media/MediaView.tsx @@ -13,6 +13,8 @@ import { MWMediaType } from "@/backend/metadata/types"; import { useGoBack } from "@/hooks/useGoBack"; import { IconPatch } from "@/components/buttons/IconPatch"; import { Icons } from "@/components/Icon"; +import { useWatchedItem } from "@/state/watched"; +import { ProgressListenerControl } from "@/components/video/controls/ProgressListenerControl"; import { MediaFetchErrorView } from "./MediaErrorView"; import { MediaScrapeLog } from "./MediaScrapeLog"; import { NotFoundMedia, NotFoundWrapper } from "../notfound/NotFoundView"; @@ -102,6 +104,8 @@ export function MediaView() { }); const [stream, setStream] = useState(null); + const { updateProgress, watchedItem } = useWatchedItem(meta); + useEffect(() => { exec(params.media).then((v) => { setMeta(v ?? null); @@ -115,8 +119,6 @@ export function MediaView() { }); }, [exec, params.media]); - // TODO watched store - if (loading) return ; if (error) return ; if (!meta || !selected) @@ -142,6 +144,10 @@ export function MediaView() {
+
); diff --git a/src/views/search/HomeView.tsx b/src/views/search/HomeView.tsx index ac745ede..ffd9dd99 100644 --- a/src/views/search/HomeView.tsx +++ b/src/views/search/HomeView.tsx @@ -7,6 +7,7 @@ import { useBookmarkContext, } from "@/state/bookmark"; import { useWatchedContext } from "@/state/watched"; +import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; function Bookmarks() { const { t } = useTranslation(); @@ -21,52 +22,45 @@ function Bookmarks() { icon={Icons.BOOKMARK} > - {/* {bookmarks.map((v) => ( - - ))} */} + {bookmarks.map((v) => ( + + ))} ); } -// function Watched() { -// const { t } = useTranslation(); -// const { getFilteredBookmarks } = useBookmarkContext(); -// const { getFilteredWatched } = useWatchedContext(); +function Watched() { + const { t } = useTranslation(); + const { getFilteredBookmarks } = useBookmarkContext(); + const { getFilteredWatched } = useWatchedContext(); -// const bookmarks = getFilteredBookmarks(); -// const watchedItems = getFilteredWatched().filter( -// (v) => !getIfBookmarkedFromPortable(bookmarks, v) -// ); + const bookmarks = getFilteredBookmarks(); + const watchedItems = getFilteredWatched().filter( + (v) => !getIfBookmarkedFromPortable(bookmarks, v.item.meta) + ); -// if (watchedItems.length === 0) return null; + if (watchedItems.length === 0) return null; -// return ( -// -// -// {/* {watchedItems.map((v) => ( -// -// ))} */} -// -// -// ); -// } + return ( + + + {watchedItems.map((v) => ( + + ))} + + + ); +} export function HomeView() { return (
- {/* */} - {/* */} + +
); }