feat(player): the YouTube player and the file viewer are named in the address
The player names what it plays in its own history entry (watch, wrel, wtab): a reload or a
bookmark reopens it on the page that hosts it, with that page's list as the queue, or alone
from the catalog (GET /api/videos/{id}/row); a page that hosts none gets the shell's. Back
lands on the page's address without it (useBackToClose's url; ui/Modal passes it on). The
Files viewer and player do the same (fview, fplay). The Plex and channel-manager views are
always written in full, as their fallback is remembered state.
This commit is contained in:
@@ -45,9 +45,11 @@ vi.mock("react-i18next", async (importOriginal) => {
|
||||
|
||||
const discover = vi.fn();
|
||||
const discoverPick = vi.fn();
|
||||
const videoRow = vi.fn();
|
||||
vi.mock("../../lib/api", () => ({
|
||||
api: {
|
||||
discover: (...a: unknown[]) => discover(...a),
|
||||
videoRow: (...a: unknown[]) => videoRow(...a),
|
||||
discoverPick: (...a: unknown[]) => discoverPick(...a),
|
||||
setState: () => Promise.resolve(),
|
||||
watchLaterAdd: () => Promise.resolve(),
|
||||
@@ -70,6 +72,11 @@ vi.mock("../plex/plexContext", () => ({
|
||||
usePlexActions: () => ({ setJumpTo: (t: unknown) => setJumpTo(t) }),
|
||||
}));
|
||||
|
||||
// The player itself is pinned in its own tests: here, what Home opens it on.
|
||||
vi.mock("../../features/player/PlayerModal", () => ({
|
||||
default: ({ video }: { video: { id: string } }) => <p>playing {video.id}</p>,
|
||||
}));
|
||||
|
||||
import Home from "./Home";
|
||||
import { requestSurprise, takeSurprise } from "../../lib/homeIntent";
|
||||
|
||||
@@ -179,6 +186,17 @@ beforeEach(() => {
|
||||
});
|
||||
afterEach(cleanup);
|
||||
|
||||
describe("Home — a player the address names", () => {
|
||||
it("reopens on its video, alone as Home plays it", async () => {
|
||||
window.history.replaceState(null, "", "/?page=home&watch=v9");
|
||||
videoRow.mockResolvedValue({ id: "v9", title: "Nine" });
|
||||
mount();
|
||||
expect(await screen.findByText("playing v9")).toBeTruthy();
|
||||
expect(videoRow).toHaveBeenCalledWith("v9");
|
||||
window.history.replaceState(null, "", "/");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Home", () => {
|
||||
it("labels the hero from the server's tier, not from the card", async () => {
|
||||
// The same card shape is served under a `surprise` tier: a client that inferred "where you left
|
||||
|
||||
@@ -78,6 +78,7 @@ import {
|
||||
mediaTitleClass,
|
||||
} from "../../components/ui/mediaCardStyles";
|
||||
import RemoteImage from "../../components/ui/RemoteImage";
|
||||
import { useOpenLinkedPlayer } from "../../features/player/useOpenLinkedPlayer";
|
||||
|
||||
// The Home surface — "Mit nézzek most?".
|
||||
//
|
||||
@@ -729,6 +730,12 @@ export default function Home() {
|
||||
window.history.replaceState({ ...window.history.state, [SAVED_KEY]: question }, "");
|
||||
}, [budget, seed, press, seen]);
|
||||
const [player, setPlayer] = useState<{ video: Video; startAt: number | null } | null>(null);
|
||||
// A reload or a bookmark of the player reopens it: the video alone, as Home plays it.
|
||||
useOpenLinkedPlayer(
|
||||
true,
|
||||
() => undefined,
|
||||
(video) => setPlayer({ video, startAt: null }),
|
||||
);
|
||||
|
||||
// A Plex card's title is in the reader's language, so the answer is cached per language.
|
||||
const lang = plexLang(i18n.language);
|
||||
|
||||
@@ -14,4 +14,5 @@ export const homeModule: ModuleDef = {
|
||||
// Nothing of its own: the question is an answer, not a setting — the same question draws other
|
||||
// cards once what you have watched moves on.
|
||||
urlKeys: [],
|
||||
playsVideos: true,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user