Where the host can't delegate the user's click (Firefox, Safari, WebKitGTK), lotus.20 showed EC's own screenshare button floating in the frame's corner, apart from the host's call bar. Now the host keeps its bar button and sends the new toWidget io.lotus.prompt_screenshare; the fork shows a small "Share your screen?" card inside the frame, just above the bar, and its Share button starts the share with the frame's own click. Same two clicks as the host's confirm on Chromium. - The card focuses Share; Cancel and Escape close it; it closes if a share starts some other way or the room's call policy stops allowing sharing, and never opens where the policy forbids it (set_frame_screenshare). - Picture-in-picture (~158 px tall): compact card without the description. - controls_state: frameScreenshare is now always false (the corner button is gone), screensharePrompt says the host should use the prompt, and screensharePromptOpen lets the host stop covering the frame meanwhile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
/*
|
|
Copyright 2026 Lotus Guild
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
import { type FC, useCallback, useEffect, useId, useRef } from "react";
|
|
import { Button, Text } from "@vector-im/compound-web";
|
|
|
|
import { type CallViewModel } from "../state/CallViewModel/CallViewModel";
|
|
import { useBehavior } from "../useBehavior";
|
|
import {
|
|
lotusFrameScreenshareEnabled,
|
|
lotusFrameScreenshareVisible$,
|
|
lotusScreensharePrompt$,
|
|
} from "./lotusControls";
|
|
import styles from "./LotusScreensharePrompt.module.css";
|
|
|
|
/**
|
|
* [cinny #43] "Share your screen?" asked inside the call frame, for hosts that
|
|
* can't hand the user's click to this frame (Firefox, Safari, WebKitGTK). The
|
|
* host's call-bar button sends `io.lotus.prompt_screenshare`; the Share click
|
|
* lands here, so getDisplayMedia runs with this frame's own activation. Same
|
|
* two clicks as the host's own confirm on Chromium.
|
|
*/
|
|
export const LotusScreensharePrompt: FC<{ vm: CallViewModel }> = ({ vm }) => {
|
|
const open = useBehavior(lotusScreensharePrompt$);
|
|
const sharing = useBehavior(vm.sharingScreen$);
|
|
const allowed = useBehavior(lotusFrameScreenshareVisible$);
|
|
const shareRef = useRef<HTMLButtonElement>(null);
|
|
const titleId = useId();
|
|
const descriptionId = useId();
|
|
|
|
const close = useCallback(() => lotusScreensharePrompt$.next(false), []);
|
|
|
|
// Stale once a share is running (started some other way) or the room's
|
|
// policy stops allowing it.
|
|
useEffect(() => {
|
|
if (open && (sharing || !allowed)) close();
|
|
}, [open, sharing, allowed, close]);
|
|
|
|
useEffect(() => {
|
|
if (open) shareRef.current?.focus();
|
|
}, [open]);
|
|
|
|
useEffect(() => {
|
|
if (!open) return undefined;
|
|
const onKeyDown = (e: KeyboardEvent): void => {
|
|
if (e.key !== "Escape") return;
|
|
e.preventDefault();
|
|
close();
|
|
};
|
|
window.addEventListener("keydown", onKeyDown, true);
|
|
return (): void => window.removeEventListener("keydown", onKeyDown, true);
|
|
}, [open, close]);
|
|
|
|
const toggle = vm.toggleScreenSharing;
|
|
if (!open || !lotusFrameScreenshareEnabled() || !toggle) return null;
|
|
|
|
const onShare = (): void => {
|
|
close();
|
|
// Synchronously inside this click: getDisplayMedia needs its activation.
|
|
toggle();
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className={styles.prompt}
|
|
role="alertdialog"
|
|
aria-labelledby={titleId}
|
|
aria-describedby={descriptionId}
|
|
data-testid="lotus_screenshare_prompt"
|
|
>
|
|
<Text
|
|
as="h2"
|
|
id={titleId}
|
|
size="md"
|
|
weight="semibold"
|
|
className={styles.title}
|
|
>
|
|
Share your screen?
|
|
</Text>
|
|
<Text id={descriptionId} size="md" className={styles.description}>
|
|
Your screen will be visible to everyone in this call.
|
|
</Text>
|
|
<div className={styles.buttons}>
|
|
<Button
|
|
ref={shareRef}
|
|
size="md"
|
|
onClick={onShare}
|
|
data-testid="lotus_screenshare_prompt_share"
|
|
>
|
|
Share
|
|
</Button>
|
|
<Button size="md" kind="secondary" onClick={close}>
|
|
Cancel
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|