feat(lotus): in-frame "Share your screen?" prompt replaces the corner button (cinny #43)
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
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
9e4ddb3eb6
commit
bb675fa50e
@@ -26,23 +26,39 @@ export interface LotusControlsState {
|
||||
/** This fork handles `io.lotus.set_hotkeys` (always true). */
|
||||
hotkeys: true;
|
||||
/**
|
||||
* EC's own screenshare button is shown inside the frame (see
|
||||
* `lotusFrameScreenshare`), so the host should hide its own.
|
||||
* EC's own screenshare button is shown inside the frame, so the host should
|
||||
* hide its own. Always false since the prompt replaced that button; kept so
|
||||
* a host that still reads it doesn't hide its button.
|
||||
*/
|
||||
frameScreenshare: boolean;
|
||||
frameScreenshare: false;
|
||||
/**
|
||||
* The host should start a share with `io.lotus.prompt_screenshare` (the
|
||||
* in-frame prompt) instead of `set_screenshare`: see
|
||||
* `lotusFrameScreenshareEnabled`.
|
||||
*/
|
||||
screensharePrompt: boolean;
|
||||
/**
|
||||
* The prompt is showing. The host must let clicks through to this frame
|
||||
* meanwhile (e.g. its picture-in-picture overlay).
|
||||
*/
|
||||
screensharePromptOpen: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* [cinny #43] `lotusFrameScreenshare=1` (with `lotusHostControls`): the host
|
||||
* can't hand the user's click into this frame (no Capability Delegation:
|
||||
* Firefox, Safari, WebKitGTK), and `getDisplayMedia` needs that click here.
|
||||
* So EC's own screenshare button stays visible in the frame, where the click
|
||||
* is native, instead of the host clicking it through the DOM.
|
||||
* The host's call-bar button then asks for `io.lotus.prompt_screenshare`, and
|
||||
* the "Share your screen?" prompt is drawn inside this frame, where the Share
|
||||
* click is native.
|
||||
*/
|
||||
export function lotusFrameScreenshareEnabled(): boolean {
|
||||
return lotusFlag("lotusHostControls") && lotusFlag("lotusFrameScreenshare");
|
||||
}
|
||||
|
||||
/** Whether the in-frame "Share your screen?" prompt is showing. */
|
||||
export const lotusScreensharePrompt$ = new BehaviorSubject(false);
|
||||
|
||||
/**
|
||||
* Host-controlled visibility of the in-frame screenshare button
|
||||
* (`io.lotus.set_frame_screenshare`): the host hides it while the room's
|
||||
@@ -50,6 +66,21 @@ export function lotusFrameScreenshareEnabled(): boolean {
|
||||
*/
|
||||
export const lotusFrameScreenshareVisible$ = new BehaviorSubject(true);
|
||||
|
||||
/**
|
||||
* Whether `io.lotus.prompt_screenshare` should show the prompt: only in
|
||||
* prompt mode, where the room's policy allows sharing, EC can share, and no
|
||||
* share is running (stopping goes through `set_screenshare`, which needs no
|
||||
* click). Exported for tests.
|
||||
*/
|
||||
export function shouldPromptScreenshare(s: {
|
||||
enabled: boolean;
|
||||
allowed: boolean;
|
||||
canShare: boolean;
|
||||
sharing: boolean;
|
||||
}): boolean {
|
||||
return s.enabled && s.allowed && s.canShare && !s.sharing;
|
||||
}
|
||||
|
||||
/** `{ visible }` payload → the visibility to apply, or undefined. Exported for tests. */
|
||||
export function parseFrameScreensharePayload(
|
||||
data: unknown,
|
||||
@@ -138,30 +169,51 @@ export function startLotusControls(vm: CallViewModel): () => void {
|
||||
if (visible !== undefined) lotusFrameScreenshareVisible$.next(visible);
|
||||
};
|
||||
|
||||
const onPromptScreenshare = (ev: CustomEvent<IWidgetApiRequest>): void => {
|
||||
w.api.transport.reply(ev.detail, {});
|
||||
if (
|
||||
shouldPromptScreenshare({
|
||||
enabled: lotusFrameScreenshareEnabled(),
|
||||
allowed: lotusFrameScreenshareVisible$.value,
|
||||
canShare: !!vm.toggleScreenSharing,
|
||||
sharing: vm.sharingScreen$.value,
|
||||
})
|
||||
) {
|
||||
lotusScreensharePrompt$.next(true);
|
||||
}
|
||||
};
|
||||
|
||||
w.lazyActions.on(LotusWidgetActions.SetScreenshare, onSetScreenshare);
|
||||
w.lazyActions.on(
|
||||
LotusWidgetActions.SetFrameScreenshare,
|
||||
onSetFrameScreenshare,
|
||||
);
|
||||
w.lazyActions.on(LotusWidgetActions.PromptScreenshare, onPromptScreenshare);
|
||||
|
||||
const sub: Subscription = combineLatest([
|
||||
vm.sharingScreen$,
|
||||
vm.layoutSwitchVm$.pipe(
|
||||
switchMap((l) => (l ? l.layout$ : of<LayoutMode | null>(null))),
|
||||
),
|
||||
lotusScreensharePrompt$,
|
||||
])
|
||||
.pipe(
|
||||
map(
|
||||
([screensharing, layout]): LotusControlsState => ({
|
||||
([screensharing, layout, promptOpen]): LotusControlsState => ({
|
||||
screensharing,
|
||||
layout,
|
||||
screenshareAction: true,
|
||||
hotkeys: true,
|
||||
frameScreenshare: lotusFrameScreenshareEnabled(),
|
||||
frameScreenshare: false,
|
||||
screensharePrompt: lotusFrameScreenshareEnabled(),
|
||||
screensharePromptOpen: promptOpen,
|
||||
}),
|
||||
),
|
||||
distinctUntilChanged(
|
||||
(a, b) => a.screensharing === b.screensharing && a.layout === b.layout,
|
||||
(a, b) =>
|
||||
a.screensharing === b.screensharing &&
|
||||
a.layout === b.layout &&
|
||||
a.screensharePromptOpen === b.screensharePromptOpen,
|
||||
),
|
||||
)
|
||||
.subscribe((state) => {
|
||||
@@ -178,5 +230,10 @@ export function startLotusControls(vm: CallViewModel): () => void {
|
||||
LotusWidgetActions.SetFrameScreenshare,
|
||||
onSetFrameScreenshare,
|
||||
);
|
||||
w.lazyActions.off(
|
||||
LotusWidgetActions.PromptScreenshare,
|
||||
onPromptScreenshare,
|
||||
);
|
||||
lotusScreensharePrompt$.next(false);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user