fix(room): мини-окно игнорировало закрепление, а демонстрация слетала от реплики
Мини-плеер намеренно вёл себя иначе, чем основное окно: без удержания демонстрации экрана (holdScreenShare), без приоритета говорящего с включённой камерой, без антидребезга говорящего и с собственным чистым useState для закрепления. На практике это читалось как поломка — закрепление, сделанное в основном окне, в мини-окне не действовало, а демонстрация экрана пропадала, стоило кому-то сказать слово. Теперь pickStageFocus получает одинаковые правила в обоих вариантах сцены. Единственное сознательное отличие — localKey («показать себя» последним фолбэком), он остаётся только у мини-плеера: это защита от дефекта 0.0.11, когда мини-окно открывалось на самом пользователе. Закрепление переезжает между окнами тем же мостиком через RoomPage, что и фокус (initialPinnedKey/onPinnedKeyChange). Отдельный общий источник правды не нужен: экземпляр сцены в каждый момент ровно один — пока открыт Document PiP, основное окно показывает заглушку. Заодно в снятии закрепления «участник вышел из комнаты» добавлена охрана tracksKnown. На первом рендере нового экземпляра сцены useTracks отдаёт пустой массив, и пустой набор читался как «все вышли»: приехавшее через initialPinnedKey закрепление обнулялось прямо при монтировании, то есть мини-плеер терял его каждый раз. Надпись на булавке — «Закрепить» вместо «Закрепить в основном окне»: закрепление больше не ограничено основным окном.
This commit is contained in:
@@ -208,6 +208,12 @@ export function RoomPage() {
|
||||
// открывал мини-окно на самом пользователе. Подробнее — докстринг `RoomStage`.
|
||||
const [stageFocusKey, setStageFocusKey] = useState<string | null>(null)
|
||||
|
||||
// Закрепление участника (булавка на плитке) — по той же причине и тем же
|
||||
// мостиком, что и `stageFocusKey`: экземпляр `RoomStage` при открытии
|
||||
// мини-плеера пересоздаётся, и до 0.0.25 закрепление, сделанное в основном
|
||||
// окне, в мини-окно не попадало вовсе (там был свой чистый `useState`).
|
||||
const [stagePinnedKey, setStagePinnedKey] = useState<string | null>(null)
|
||||
|
||||
// Сохранённый выбор устройств — читаем через собственный вызов
|
||||
// usePersistentUserChoices (независимый от того, что использует
|
||||
// DeviceSettingsDialog: там свой вызов хука со своим состоянием). ВАЖНО:
|
||||
@@ -321,6 +327,8 @@ export function RoomPage() {
|
||||
onHideOthers={() => setHideOthers(true)}
|
||||
initialFocusKey={stageFocusKey}
|
||||
onFocusKeyChange={setStageFocusKey}
|
||||
initialPinnedKey={stagePinnedKey}
|
||||
onPinnedKeyChange={setStagePinnedKey}
|
||||
onPinFocus={handlePinFocus}
|
||||
raisedHandIdentities={raisedHandIdentities}
|
||||
conferenceId={joinState.conferenceId}
|
||||
@@ -373,10 +381,17 @@ export function RoomPage() {
|
||||
`variant="pip"` — мини-плеер
|
||||
показывает только активное окно (одну плитку), без карусели/грида
|
||||
основного окна. `initialFocusKey` — то, что было крупно в основном
|
||||
окне: без него мини-окно открывалось на самом пользователе. */}
|
||||
окне: без него мини-окно открывалось на самом пользователе;
|
||||
`initialPinnedKey` — закрепление оттуда же. */}
|
||||
{pip.pipWindow &&
|
||||
createPortal(
|
||||
<RoomStage variant="pip" initialFocusKey={stageFocusKey} onFocusKeyChange={setStageFocusKey} />,
|
||||
<RoomStage
|
||||
variant="pip"
|
||||
initialFocusKey={stageFocusKey}
|
||||
onFocusKeyChange={setStageFocusKey}
|
||||
initialPinnedKey={stagePinnedKey}
|
||||
onPinnedKeyChange={setStagePinnedKey}
|
||||
/>,
|
||||
pip.pipWindow.document.body,
|
||||
)}
|
||||
<ForcedMuteWatcher event={chat.lastForcedMute} />
|
||||
|
||||
Reference in New Issue
Block a user