zebra-spaces: drop screen-resume banner; richer picker hints on share
Reverts 35908cf's resume banner. The browser security model makes getDisplayMedia ALWAYS show the picker — selection can't be remembered across reload — so a resume banner adds an extra click without saving the user from anything. Single 'share screen' button stays the canonical path. Add picker hints on getDisplayMedia that Chrome honors (Firefox / Safari silently ignore — no behavior change): surfaceSwitching: 'include' — show the in-stream switcher widget selfBrowserSurface: 'include' — let the user pick this tab if useful systemAudio: 'include' — surface the tab-audio toggle by default Net result: same gesture flow as before the resume experiment, slightly friendlier picker on Chrome, no extra UI.
This commit is contained in:
parent
35908cf898
commit
b4e0c3d2d6
1 changed files with 15 additions and 43 deletions
|
|
@ -731,12 +731,6 @@ try {
|
|||
<select id="camera-select" title="camera device — applies on next start"><option value="">default camera</option></select>
|
||||
</div>
|
||||
</section>
|
||||
<section id="sec-screen-resume" class="hidden">
|
||||
<div class="notice-banner warn">
|
||||
<span>you were sharing your screen before this refresh — tap to resume (browsers need a fresh click to grant screen capture)</span>
|
||||
<button id="btn-screen-resume" class="small invert">resume screen share</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="sec-listener-actions" class="hidden">
|
||||
<h2>your hand</h2>
|
||||
|
|
@ -1292,14 +1286,13 @@ const THEME_KEY = 'zebra-theme-v1';
|
|||
* hard refresh auto-rejoins. Different tabs can sit in different
|
||||
* spaces because sessionStorage doesn't bleed across tabs. */
|
||||
const ACTIVE_CALL_KEY = 'zebra-spaces-active-call-v1';
|
||||
/* screen-share state is deliberately NOT tracked across reload. Even
|
||||
* with a click banner the user has to re-pick the surface (browser
|
||||
* security: getDisplayMedia always shows the picker; selection cannot
|
||||
* be remembered across a reload). A re-pick is the same friction as
|
||||
* just clicking 'share screen' again, so we keep the single canonical
|
||||
* button instead of adding a banner that adds zero net clicks. */
|
||||
const ACTIVE_CAM_KEY = 'zebra-spaces-active-cam-v1';
|
||||
/* screen-share resume — getDisplayMedia REQUIRES a fresh user gesture
|
||||
* (Chrome / Firefox block silent triggers after a hard refresh), so
|
||||
* unlike the camera we can't just re-acquire silently on welcome.
|
||||
* Instead we surface a one-click resume banner if the user was sharing
|
||||
* before the refresh — the click IS the gesture and counts toward the
|
||||
* getDisplayMedia call inside the same task. */
|
||||
const ACTIVE_SCREEN_KEY = 'zebra-spaces-active-screen-v1';
|
||||
/* mute state for the current tab — '1' means muted. Survives a hard
|
||||
* refresh via sessionStorage so the page reconnects in the same state
|
||||
* the user last set. Cleared on explicit leave. NOT cleared on role
|
||||
|
|
@ -2127,7 +2120,13 @@ async function sfuPublishScreen(){
|
|||
stream = await navigator.mediaDevices.getDisplayMedia({
|
||||
video: { width:{ideal:1920}, height:{ideal:1080}, frameRate:{ideal:30} },
|
||||
audio: { echoCancellation:false, noiseSuppression:false, autoGainControl:false,
|
||||
channelCount:2, sampleRate:48000 }
|
||||
channelCount:2, sampleRate:48000 },
|
||||
/* picker UX hints. Chrome respects these — biases toward the
|
||||
* previously-shared surface family and shows tab audio toggle by
|
||||
* default. Firefox / Safari currently ignore them. */
|
||||
surfaceSwitching: 'include',
|
||||
selfBrowserSurface: 'include',
|
||||
systemAudio: 'include',
|
||||
});
|
||||
} catch(e){ logLine('err','screen share cancelled: '+e.message); return; }
|
||||
sfuScreenStream = stream;
|
||||
|
|
@ -2188,8 +2187,6 @@ async function sfuPublishScreen(){
|
|||
renderScreenTile(myKeys.pubHex, stream, { local: true });
|
||||
$('btn-screen-share').classList.add('hidden');
|
||||
$('btn-screen-stop').classList.remove('hidden');
|
||||
try { sessionStorage.setItem(ACTIVE_SCREEN_KEY, '1'); } catch(_){}
|
||||
$('sec-screen-resume').classList.add('hidden');
|
||||
}
|
||||
async function sfuUnpublishScreen(){
|
||||
if (!sfuScreenPC && !sfuScreenStream) return;
|
||||
|
|
@ -2202,8 +2199,6 @@ async function sfuUnpublishScreen(){
|
|||
}
|
||||
$('btn-screen-share').classList.remove('hidden');
|
||||
$('btn-screen-stop').classList.add('hidden');
|
||||
try { sessionStorage.removeItem(ACTIVE_SCREEN_KEY); } catch(_){}
|
||||
$('sec-screen-resume').classList.add('hidden');
|
||||
logLine('', 'screen share stopped');
|
||||
}
|
||||
|
||||
|
|
@ -3011,20 +3006,8 @@ async function handleSignal(raw){
|
|||
});
|
||||
}, 250);
|
||||
}
|
||||
/* screen — getDisplayMedia requires a fresh user gesture per
|
||||
* browser security policy, so we surface a one-click resume
|
||||
* banner instead. The click IS the gesture. */
|
||||
let wantScreen = false;
|
||||
try { wantScreen = sessionStorage.getItem(ACTIVE_SCREEN_KEY) === '1'; } catch(_){}
|
||||
if (wantScreen){
|
||||
$('sec-screen-resume').classList.remove('hidden');
|
||||
} else {
|
||||
$('sec-screen-resume').classList.add('hidden');
|
||||
}
|
||||
} else {
|
||||
try { sessionStorage.removeItem(ACTIVE_CAM_KEY); } catch(_){}
|
||||
try { sessionStorage.removeItem(ACTIVE_SCREEN_KEY); } catch(_){}
|
||||
$('sec-screen-resume').classList.add('hidden');
|
||||
}
|
||||
renderShareUrl();
|
||||
onRoleEntered();
|
||||
|
|
@ -3514,17 +3497,6 @@ function renderRoom(){
|
|||
$('btn-raise').addEventListener('click', () => { send({ type:'raise-hand' }); });
|
||||
$('btn-lower').addEventListener('click', () => { send({ type:'lower-hand' }); });
|
||||
$('btn-screen-share').addEventListener('click', () => { logLine('', 'click: btn-screen-share'); sfuPublishScreen().catch(e => logLine('err','screen share: '+e.message)); });
|
||||
$('btn-screen-resume').addEventListener('click', () => {
|
||||
/* The user gesture from this click is what unlocks getDisplayMedia
|
||||
* after a refresh — chained directly into sfuPublishScreen so the
|
||||
* browser counts it toward the same task. */
|
||||
logLine('', 'click: btn-screen-resume');
|
||||
sfuPublishScreen().catch(e => {
|
||||
logLine('err', 'screen resume: ' + e.message);
|
||||
try { sessionStorage.removeItem(ACTIVE_SCREEN_KEY); } catch(_){}
|
||||
$('sec-screen-resume').classList.add('hidden');
|
||||
});
|
||||
});
|
||||
$('btn-screen-stop').addEventListener('click', () => {
|
||||
/* click telemetry — the 'screen share stopped' line lower in
|
||||
* sfuUnpublishScreen only fires AFTER the early-return, so logging
|
||||
|
|
@ -3943,8 +3915,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');
|
|||
|
||||
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
|
||||
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> · built <span class="stamp-date">2026-06-03</span><br>
|
||||
md5 <span class="stamp-md5">2439f48e2bbd34e36b34209e29d631df</span><br>
|
||||
sha256 <span class="stamp-sha">afb06260b27c0e1d2a0b76b228c3b7af5138b826fd6b123100d1ccd4d763543b</span><br>
|
||||
md5 <span class="stamp-md5">66a614bab55cb7b90c288e575177dc4a</span><br>
|
||||
sha256 <span class="stamp-sha">902f6be9372bc22eaa90e50e140efef9222c80ad30c92d093619c6d59a8c20a5</span><br>
|
||||
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
|
||||
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
|
||||
</footer>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue