Asked for directly: a visible bottom toolbar for non-host members
instead of clicking your own small avatar circle (never a very
discoverable affordance), and a second request alongside pause -
"please resume".
- server/src/types.ts, server/src/realtime/SocketGateway.ts: new
requestResume/resumeRequested, byte-for-byte the same shape and
handler pattern as requestPause/pauseRequested, independently
throttled (its own lastResumeRequestUtc - not a shared budget with
pause). Kept as a plain broadcast signal, same as pause always was -
no accept/deny state tracked server-side, the host sees the same
banner/avatar highlight as everyone else and acts with their own
existing controls.
- client/src/api/party.ts, client/src/types.ts: requestResume() on
PartyConnection, onResumeRequested callback, a ResumeRequestedMsg type
(same shape as PauseRequestedMsg, kept separate so a callback's own
signature says which request it's for).
- client/src/views/player/Player.{html,css,ts}: the avatar is presence-
only now (no click handler, no "- demander une pause" title) - a new
.bottomOverlay wraps the request banner, the follower notice, and a
new .requestToolbar (Demander une pause / Demander une reprise) as one
flex column, same "stack in normal flow instead of hand-picking a
pixel offset per box" fix .topOverlay already needed. Pause and resume
share one showRequestBanner() - they only ever differed by which word
appears in the banner text. Renamed the shared CSS classes
(avatarPauseRequested/avatarPauseBadge -> avatarActionRequested/
avatarRequestBadge) since they're no longer pause-specific.
- server/test/socketGateway.test.ts: new case confirming requestResume's
throttle is independent from requestPause's own.
Verified against the real compiled bundle: the toolbar shows for a
follower and stays hidden for the host; each button's own client-side
cooldown collapses a rapid double-click to one emission; a pushed
resumeRequested shows the banner with the right text and highlights the
right avatar.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
45 lines
2 KiB
HTML
45 lines
2 KiB
HTML
<div class="playerWrap">
|
|
<video id="video" playsinline></video>
|
|
|
|
<p id="loadingNotice" class="loadingNotice">Chargement du flux...</p>
|
|
<div id="playerError" class="playerError hide">
|
|
<p id="playerErrorText"></p>
|
|
<button id="playerErrorRetry" class="linklike">Réessayer</button>
|
|
</div>
|
|
|
|
<div class="topOverlay">
|
|
<div class="actionBar">
|
|
<span id="itemTitle" class="itemTitle"></span>
|
|
<span id="members" class="members"></span>
|
|
<button id="nextBtn" class="linklike hide">Épisode suivant →</button>
|
|
|
|
<div id="settingsWrap" class="settingsWrap hide">
|
|
<button id="settingsBtn" class="iconBtn" title="Paramètres de lecture" aria-label="Paramètres de lecture">⚙</button>
|
|
<div id="settingsPanel" class="settingsPanel hide">
|
|
<label>Langue <select id="audioSelect"></select></label>
|
|
<label>Sous-titres <select id="subtitleSelect"><option value="">Aucun</option></select></label>
|
|
<label>Qualité <select id="qualitySelect"></select></label>
|
|
</div>
|
|
</div>
|
|
|
|
<button id="leaveBtn" class="linklike">Quitter</button>
|
|
</div>
|
|
|
|
<div id="presenceOverlay" class="presenceOverlay"></div>
|
|
</div>
|
|
|
|
<!-- Stacked as one column (same reasoning as .topOverlay's own
|
|
actionBar+presenceOverlay grouping - see Player.css) so the
|
|
transient banner, the passive notice and the request toolbar
|
|
always sit in the right order relative to each other regardless
|
|
of which are visible at a given moment, instead of each guessing
|
|
a fixed pixel offset from the bottom edge. -->
|
|
<div class="bottomOverlay">
|
|
<div id="requestBanner" class="requestBanner hide"></div>
|
|
<p id="followerNotice" class="followerNotice hide">L'hôte contrôle la lecture.</p>
|
|
<div id="requestToolbar" class="requestToolbar hide">
|
|
<button id="requestPauseBtn" class="requestBtn">Demander une pause</button>
|
|
<button id="requestResumeBtn" class="requestBtn">Demander une reprise</button>
|
|
</div>
|
|
</div>
|
|
</div>
|