diff --git a/web/apps/cast/src/pages/slideshow.tsx b/web/apps/cast/src/pages/slideshow.tsx index 6d1eee605..24f1bb4c5 100644 --- a/web/apps/cast/src/pages/slideshow.tsx +++ b/web/apps/cast/src/pages/slideshow.tsx @@ -3,113 +3,57 @@ import { PairedSuccessfullyOverlay } from "components/PairedSuccessfullyOverlay" import { SlideView } from "components/Slide"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; -import { readCastData, renderableURLs } from "services/cast"; +import { readCastData, renderableImageURLs } from "services/cast"; export default function Slideshow() { const [loading, setLoading] = useState(true); - const [castToken, setCastToken] = useState(""); - // const [castCollection, setCastCollection] = useState< - // Collection | undefined - // >(); - // const [collectionFiles, setCollectionFiles] = useState([]); - // const [currentFileId, setCurrentFileId] = useState(); - const [currentFileURL, setCurrentFileURL] = useState(); - const [nextFileURL, setNextFileURL] = useState(); - const [urlGenerator, setURLGenerator] = useState< - AsyncGenerator | undefined - >(); - // const [canCast, setCanCast] = useState(false); + const [imageURL, setImageURL] = useState(); + const [nextImageURL, setNextImageURL] = useState(); const router = useRouter(); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const syncCastFiles = async (token: string) => { - try { - setURLGenerator(renderableURLs(readCastData())); - // setCanCast(true); - setLoading(false); - } catch (e) { - log.error("Failed to prepare URL generator", e); - // Go back to pairing page - router.push("/"); - } - }; - - const advance = async () => { - console.log("in advance"); - if (!urlGenerator) throw new Error("Unexpected state"); - const { value: urls, done } = await urlGenerator.next(); - if (done) { - log.warn("Empty collection"); - // Go back to pairing page - router.push("/"); - return; - } - setCurrentFileURL(urls[0]); - setNextFileURL(urls[1]); - }; - - /* - const syncCastFiles0 = async (token: string) => { - try { - const { castToken, collectionKey } = readCastData(); - const collection = await getCastCollection( - collectionKey, - castToken, - ); - if ( - castCollection === undefined || - castCollection.updationTime !== collection.updationTime - ) { - setCastCollection(collection); - await syncPublicFiles(token, collection, () => {}); - const files = await getLocalFiles(String(collection.id)); - setCollectionFiles( - files.filter((file) => isFileEligibleForCast(file)), - ); - } - } catch (e) { - log.error("error during sync", e); - // go back to preview page - router.push("/"); - } - }; - */ - - useEffect(() => { - if (castToken) { - const intervalId = setInterval(() => { - syncCastFiles(castToken); - }, 10000); - syncCastFiles(castToken); - - return () => clearInterval(intervalId); - } - }, [castToken]); + /** Go back to pairing page */ + const pair = () => router.push("/"); useEffect(() => { + let urlGenerator: AsyncGenerator<[string, string], void>; try { - const castToken = window.localStorage.getItem("castToken"); - // Wait 2 seconds to ensure the green tick and the confirmation - // message remains visible for at least 2 seconds before we start - // the slideshow. - const timeoutId = setTimeout(() => { - setCastToken(castToken); - }, 2000); - - return () => clearTimeout(timeoutId); + urlGenerator = renderableImageURLs(readCastData()); } catch (e) { - log.error("error during sync", e); - router.push("/"); + log.error("Failed to prepare generator", e); + pair(); } + + advance(urlGenerator); + + const interval = window.setInterval(() => { + advance(urlGenerator); + }, 10000); + + return () => clearInterval(interval); }, []); - /* - useEffect(() => { - if (collectionFiles.length < 1) return; - showNextSlide(); - }, [collectionFiles]); + const advance = async ( + urlGenerator: AsyncGenerator<[string, string], void>, + ) => { + try { + const { value: urls, done } = await urlGenerator.next(); + if (done) { + log.warn("Empty collection"); + pair(); + return; + } + setImageURL(urls[0]); + setNextImageURL(urls[1]); + setLoading(false); + } catch (e) { + log.error("Failed to generate image URL", e); + pair(); + } + }; + + /* const showNextSlide = async () => { try { console.log("showNextSlide"); @@ -168,25 +112,7 @@ export default function Slideshow() { }; */ - useEffect(() => { - if (loading) return; + if (loading) return ; - console.log("showing slide"); - const timeoutId = window.setTimeout(() => { - console.log("showing next slide timer"); - // showNextSlide(); - advance(); - }, 10000); - - return () => { - if (timeoutId) clearTimeout(timeoutId); - }; - }, [loading]); - - console.log({ a: "render", loading, currentFileURL, nextFileURL }); - - if (loading || !currentFileURL || !nextFileURL) - return ; - - return ; + return ; } diff --git a/web/apps/cast/src/services/cast.ts b/web/apps/cast/src/services/cast.ts index af069dfcf..a11c67e92 100644 --- a/web/apps/cast/src/services/cast.ts +++ b/web/apps/cast/src/services/cast.ts @@ -63,28 +63,31 @@ export const readCastData = (): CastData => { return { collectionKey, castToken }; }; +type RenderableImageURLPair = [url: string, nextURL: string]; + /** * An async generator function that loops through all the files in the * collection, returning renderable URLs to each that can be displayed in a * slideshow. * - * Each time it resolves with a pair of URLs, one for the current slideshow - * image, and one for the image to be displayed next. + * Each time it resolves with a pair of URLs (a {@link RenderableImageURLPair}), + * one for the current slideshow image, and one for the slideshow image that + * will be displayed next. + * + * If there are no renderable image in the collection, the sequence ends by + * yielding `{done: true}`. * * Once it reaches the end of the collection, it starts from the beginning - * again. + * again. So the sequence will continue indefinitely for non-empty collections. * * It ignores errors in the fetching and decoding of individual images in the * collection, and just moves onward to the next one. It will however throw if - * there are errors in getting the collection itself. - * - * If there are no renderable image in the collection, the sequence ends by - * yielding `done: true`. + * there are errors when getting the collection itself. * * @param castData The collection to show and credentials to fetch the files * within it. */ -export const renderableURLs = async function* (castData: CastData) { +export const renderableImageURLs = async function* (castData: CastData) { const { collectionKey, castToken } = castData; let previousURL: string | undefined; while (true) { @@ -93,15 +96,16 @@ export const renderableURLs = async function* (castData: CastData) { const allFiles = await getLocalFiles(String(collection.id)); const files = allFiles.filter((file) => isFileEligibleForCast(file)); + if (!files.length) return; + for (const file of files) { - console.log("in generator", previousURL); if (!previousURL) { previousURL = await createRenderableURL(castToken, file); continue; } const url = await createRenderableURL(castToken, file); - const urls = [previousURL, url]; + const urls: RenderableImageURLPair = [previousURL, url]; previousURL = url; yield urls; }