diff --git a/web/apps/cast/src/components/PairedSuccessfullyOverlay.tsx b/web/apps/cast/src/components/PairedSuccessfullyOverlay.tsx
deleted file mode 100644
index 88f4d7c1f..000000000
--- a/web/apps/cast/src/components/PairedSuccessfullyOverlay.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { FilledCircleCheck } from "./FilledCircleCheck";
-
-export const PairedSuccessfullyOverlay: React.FC = () => {
- return (
-
-
-
-
- Pairing Complete
-
-
- We're preparing your album.
-
This should only take a few seconds.
-
-
-
- );
-};
diff --git a/web/apps/cast/src/components/LargeType.tsx b/web/apps/cast/src/components/PairingCode.tsx
similarity index 75%
rename from web/apps/cast/src/components/LargeType.tsx
rename to web/apps/cast/src/components/PairingCode.tsx
index 42ccb65e9..fa1474baf 100644
--- a/web/apps/cast/src/components/LargeType.tsx
+++ b/web/apps/cast/src/components/PairingCode.tsx
@@ -1,6 +1,6 @@
import { styled } from "@mui/material";
-const colourPool = [
+const colors = [
"#87CEFA", // Light Blue
"#90EE90", // Light Green
"#F08080", // Light Coral
@@ -23,27 +23,34 @@ const colourPool = [
"#808000", // Light Olive
];
-export const LargeType = ({ chars }: { chars: string[] }) => {
+interface PairingCodeProps {
+ code: string;
+}
+
+export const PairingCode: React.FC = ({ code }) => {
return (
-
- {chars.map((char, i) => (
+
+ {code.split("").map((char, i) => (
{char}
))}
-
+
);
};
-const Container = styled("div")`
+const PairingCode_ = styled("div")`
+ border-radius: 10px;
+ overflow: hidden;
+
font-size: 4rem;
font-weight: bold;
font-family: monospace;
diff --git a/web/apps/cast/src/pages/index.tsx b/web/apps/cast/src/pages/index.tsx
index 175d75bbc..e703c879f 100644
--- a/web/apps/cast/src/pages/index.tsx
+++ b/web/apps/cast/src/pages/index.tsx
@@ -1,6 +1,7 @@
import log from "@/next/log";
import EnteSpinner from "@ente/shared/components/EnteSpinner";
-import { LargeType } from "components/LargeType";
+import { styled } from "@mui/material";
+import { PairingCode } from "components/PairingCode";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { storeCastData } from "services/cast";
@@ -65,65 +66,52 @@ export default function Index() {
};
return (
- <>
-
-
-

-
- Enter this code on Ente Photos to pair this
- screen
-
-
- {pairingCode ? (
-
- ) : (
-
- )}
-
-
- Visit{" "}
-
- ente.io/cast
- {" "}
- for help
-
-
-
- >
+
+
+
+ Enter this code on Ente Photos to pair this screen
+
+ {pairingCode ? : }
+
+ Visit{" "}
+
+ ente.io/cast
+ {" "}
+ for help
+
+
);
}
+
+const Container = styled("div")`
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+
+ h1 {
+ font-weight: normal;
+ }
+
+ p {
+ font-size: 1.2rem;
+ }
+ a {
+ text-decoration: none;
+ color: #87cefa;
+ font-weight: bold;
+ }
+`;
+
+const Spinner: React.FC = () => (
+
+
+
+);
+
+const Spinner_ = styled("div")`
+ /* Roughly same height as the pairing code section to roduce layout shift */
+ margin-block: 1.7rem;
+`;
diff --git a/web/apps/cast/src/pages/slideshow.tsx b/web/apps/cast/src/pages/slideshow.tsx
index 98426a857..d117f6da7 100644
--- a/web/apps/cast/src/pages/slideshow.tsx
+++ b/web/apps/cast/src/pages/slideshow.tsx
@@ -1,5 +1,6 @@
import log from "@/next/log";
-import { PairedSuccessfullyOverlay } from "components/PairedSuccessfullyOverlay";
+import { styled } from "@mui/material";
+import { FilledCircleCheck } from "components/FilledCircleCheck";
import { SlideView } from "components/Slide";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
@@ -9,6 +10,7 @@ export default function Slideshow() {
const [loading, setLoading] = useState(true);
const [imageURL, setImageURL] = useState();
const [nextImageURL, setNextImageURL] = useState();
+ const [isEmpty, setIsEmpty] = useState(false);
const router = useRouter();
@@ -24,8 +26,10 @@ export default function Slideshow() {
while (!stop) {
const { value: urls, done } = await urlGenerator.next();
if (done) {
- log.warn("Empty collection");
- pair();
+ // No items in this callection can be shown.
+ setIsEmpty(true);
+ // Go back to pairing screen after 3 seconds.
+ setTimeout(pair, 5000);
return;
}
@@ -48,7 +52,61 @@ export default function Slideshow() {
console.log("Rendering slideshow", { loading, imageURL, nextImageURL });
- if (loading) return ;
+ if (loading) return ;
+ if (isEmpty) return ;
return ;
}
+
+const PairingComplete: React.FC = () => {
+ return (
+
+
+ Pairing Complete
+
+ We're preparing your album.
+
This should only take a few seconds.
+
+
+ );
+};
+
+const Message: React.FC = ({ children }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const Message_ = styled("div")`
+ display: flex;
+ min-height: 100svh;
+ justify-content: center;
+ align-items: center;
+
+ line-height: 1.5rem;
+
+ h2 {
+ margin-block-end: 0;
+ }
+`;
+
+const MessageItems = styled("div")`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+`;
+
+const NoItems: React.FC = () => {
+ return (
+
+ Try another album
+
+ This album has no photos that can be shown here
+
Please try another album
+
+
+ );
+};
diff --git a/web/apps/cast/src/services/cast.ts b/web/apps/cast/src/services/cast.ts
index 8cb99c241..38f203db2 100644
--- a/web/apps/cast/src/services/cast.ts
+++ b/web/apps/cast/src/services/cast.ts
@@ -103,10 +103,10 @@ export const renderableImageURLs = async function* (castData: CastData) {
*/
let lastYieldTime = Date.now();
- // The first time around advance the lastYieldTime into the future so that
+ // The first time around regress the lastYieldTime into the past so that
// we don't wait around too long for the first slide (we do want to wait a
// bit, for the user to see the checkmark animation as reassurance).
- lastYieldTime += 7500; /* 7.5 s */
+ lastYieldTime -= slideDuration - 2500; /* wait at most 2.5 s */
while (true) {
const encryptedFiles = shuffled(
@@ -120,6 +120,7 @@ export const renderableImageURLs = async function* (castData: CastData) {
if (!isFileEligibleForCast(file)) continue;
+ console.log("will start createRenderableURL", new Date());
try {
urls.push(await createRenderableURL(castToken, file));
haveEligibleFiles = true;
@@ -128,6 +129,8 @@ export const renderableImageURLs = async function* (castData: CastData) {
continue;
}
+ console.log("did end createRenderableURL", new Date());
+
// Need at least a pair.
//
// There are two scenarios:
@@ -137,7 +140,7 @@ export const renderableImageURLs = async function* (castData: CastData) {
// - Subsequently, urls will have the "next" / "preloaded" URL left
// over from the last time. We'll promote that to being the one
// that'll get displayed, and preload another one.
- if (urls.length < 2) continue;
+ // if (urls.length < 2) continue;
// The last element of previousURLs is the URL that is currently
// being shown on screen.
@@ -150,15 +153,17 @@ export const renderableImageURLs = async function* (castData: CastData) {
// The URL that'll now get displayed on screen.
const url = ensure(urls.shift());
// The URL that we're preloading for next time around.
- const nextURL = ensure(urls[0]);
+ const nextURL = ""; //ensure(urls[0]);
previousURLs.push(url);
const urlPair: RenderableImageURLPair = [url, nextURL];
const elapsedTime = Date.now() - lastYieldTime;
- if (elapsedTime > 0 && elapsedTime < slideDuration)
+ if (elapsedTime > 0 && elapsedTime < slideDuration) {
+ console.log("waiting", slideDuration - elapsedTime);
await wait(slideDuration - elapsedTime);
+ }
lastYieldTime = Date.now();
yield urlPair;
diff --git a/web/apps/cast/src/services/pair.ts b/web/apps/cast/src/services/pair.ts
index 0364cf491..893681d32 100644
--- a/web/apps/cast/src/services/pair.ts
+++ b/web/apps/cast/src/services/pair.ts
@@ -118,11 +118,6 @@ export const advertiseCode = (
const options = new cast.framework.CastReceiverOptions();
// We don't use the media features of the Cast SDK.
options.skipPlayersLoad = true;
- // TODO:Is this required? The docs say "(The default type of a message bus
- // is JSON; if not provided here)."
- options.customNamespaces = Object.assign({});
- options.customNamespaces[namespace] =
- cast.framework.system.MessageType.JSON;
// Do not stop the casting if the receiver is unreachable. A user should be
// able to start a cast on their phone and then put it away, leaving the
// cast running on their big screen.