mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-05-10 07:11:48 +00:00
fix(fullscreen): consume FullscreenProvider, remove per-instance state
useFullscreen is now a thin useContext consumer of FullscreenProvider, so all callers share a single fullscreen state owned by the app root. Why this fixes the desync bug: stremio-router keeps multiple route layers mounted at once, and each top-level route (Board, Discover, Library, Calendar, Addons, Settings, Search) renders its own MainNavBars -> HorizontalNavBar -> useFullscreen. The previous hook held local useState plus its own listeners, so each route had an independent boolean. Entering fullscreen, then navigating to another tab, mounted a fresh hook initialized to false; the icon flipped back to "enter fullscreen" and clicking it re-requested fullscreen on top of the existing one, leaving the UI unresponsive until a route remount happened to coincide with reality. With one provider above the router, state outlives route remounts and listeners are attached exactly once. The hook's return tuple shape ([fullscreen, requestFullscreen, exitFullscreen, toggleFullscreen]) is preserved, so all three call sites (HorizontalNavBar, NavMenuContent, Player) keep working with no API change. Also removes the legacy src/common/useFullscreen.ts and routes its imports through stremio/common/Fullscreen (and the stremio/common barrel for App.js / Player). Note: MainNavBars is still rendered per-route. Lifting it to a single app-level layout above the router is a worthwhile follow-up (eliminates 6+ duplicate mounts) but carries non-trivial CSS / useRouteFocused / stacked-route risk and is out of scope for this PR; tracking separately. Made-with: Cursor
This commit is contained in:
parent
c97a9f1566
commit
b7f7a3d2ed
5 changed files with 5 additions and 91 deletions
|
|
@ -6,8 +6,7 @@ const { useTranslation } = require('react-i18next');
|
|||
const { Router } = require('stremio-router');
|
||||
const { Core, Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider } = require('stremio/services');
|
||||
const { NotFound } = require('stremio/routes');
|
||||
const { FileDropProvider, PlatformProvider, ToastProvider, TooltipProvider, ShortcutsProvider, CONSTANTS, withCoreSuspender, useShell, useBinaryState } = require('stremio/common');
|
||||
const { FullscreenProvider } = require('stremio/common/Fullscreen');
|
||||
const { FileDropProvider, FullscreenProvider, PlatformProvider, ToastProvider, TooltipProvider, ShortcutsProvider, CONSTANTS, withCoreSuspender, useShell, useBinaryState } = require('stremio/common');
|
||||
const ServicesToaster = require('./ServicesToaster');
|
||||
const DeepLinkHandler = require('./DeepLinkHandler');
|
||||
const SearchParamsHandler = require('./SearchParamsHandler');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const { FileDropProvider, onFileDrop } = require('./FileDrop');
|
||||
const { FullscreenProvider, useFullscreen } = require('./Fullscreen');
|
||||
const { PlatformProvider, usePlatform } = require('./Platform');
|
||||
const { ToastProvider, useToast } = require('./Toast');
|
||||
const { TooltipProvider, Tooltip } = require('./Tooltips');
|
||||
|
|
@ -14,7 +15,6 @@ const languages = require('./languages');
|
|||
const routesRegexp = require('./routesRegexp');
|
||||
const useAnimationFrame = require('./useAnimationFrame');
|
||||
const useBinaryState = require('./useBinaryState');
|
||||
const { default: useFullscreen } = require('./useFullscreen');
|
||||
const { default: useInterval } = require('./useInterval');
|
||||
const useLiveRef = require('./useLiveRef');
|
||||
const useModelState = require('./useModelState');
|
||||
|
|
@ -34,6 +34,7 @@ const { default: useLanguageSorting } = require('./useLanguageSorting');
|
|||
module.exports = {
|
||||
FileDropProvider,
|
||||
onFileDrop,
|
||||
FullscreenProvider,
|
||||
PlatformProvider,
|
||||
usePlatform,
|
||||
ShortcutsProvider,
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import useShell, { type WindowVisibility } from './useShell';
|
||||
import useSettings from './useSettings';
|
||||
|
||||
const useFullscreen = () => {
|
||||
const shell = useShell();
|
||||
const [settings] = useSettings();
|
||||
|
||||
const [fullscreen, setFullscreen] = useState(false);
|
||||
|
||||
const requestFullscreen = useCallback(async () => {
|
||||
if (shell.active) {
|
||||
shell.send('win-set-visibility', { fullscreen: true });
|
||||
} else {
|
||||
try {
|
||||
await document.documentElement.requestFullscreen();
|
||||
} catch (err) {
|
||||
console.error('Error enabling fullscreen', err);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const exitFullscreen = useCallback(() => {
|
||||
if (shell.active) {
|
||||
shell.send('win-set-visibility', { fullscreen: false });
|
||||
} else {
|
||||
if (document.fullscreenElement === document.documentElement) {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const toggleFullscreen = useCallback(() => {
|
||||
fullscreen ? exitFullscreen() : requestFullscreen();
|
||||
}, [fullscreen]);
|
||||
|
||||
useEffect(() => {
|
||||
const onWindowVisibilityChanged = (state: WindowVisibility) => {
|
||||
setFullscreen(state.isFullscreen === true);
|
||||
};
|
||||
|
||||
const onFullscreenChange = () => {
|
||||
setFullscreen(document.fullscreenElement === document.documentElement);
|
||||
};
|
||||
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
|
||||
const activeElement = document.activeElement as HTMLElement;
|
||||
|
||||
const inputFocused =
|
||||
activeElement &&
|
||||
(activeElement.tagName === 'INPUT' ||
|
||||
activeElement.tagName === 'TEXTAREA' ||
|
||||
activeElement.tagName === 'SELECT' ||
|
||||
activeElement.isContentEditable);
|
||||
|
||||
if (event.code === 'Escape' && settings.escExitFullscreen) {
|
||||
exitFullscreen();
|
||||
}
|
||||
|
||||
if (event.code === 'KeyF' && !inputFocused) {
|
||||
toggleFullscreen();
|
||||
}
|
||||
|
||||
if (event.code === 'F11' && shell.active) {
|
||||
toggleFullscreen();
|
||||
}
|
||||
};
|
||||
|
||||
shell.on('win-visibility-changed', onWindowVisibilityChanged);
|
||||
document.addEventListener('keydown', onKeyDown);
|
||||
document.addEventListener('fullscreenchange', onFullscreenChange);
|
||||
|
||||
return () => {
|
||||
shell.off('win-visibility-changed', onWindowVisibilityChanged);
|
||||
document.removeEventListener('keydown', onKeyDown);
|
||||
document.removeEventListener('fullscreenchange', onFullscreenChange);
|
||||
};
|
||||
}, [settings.escExitFullscreen, toggleFullscreen]);
|
||||
|
||||
return [fullscreen, requestFullscreen, exitFullscreen, toggleFullscreen];
|
||||
};
|
||||
|
||||
export default useFullscreen;
|
||||
|
|
@ -5,7 +5,7 @@ const PropTypes = require('prop-types');
|
|||
const classnames = require('classnames');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { Button, Image } = require('stremio/components');
|
||||
const { default: useFullscreen } = require('stremio/common/useFullscreen');
|
||||
const { useFullscreen } = require('stremio/common/Fullscreen');
|
||||
const usePWA = require('stremio/common/usePWA');
|
||||
const SearchBar = require('./SearchBar');
|
||||
const NavMenu = require('./NavMenu');
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const { useTranslation } = require('react-i18next');
|
|||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { Button } = require('stremio/components');
|
||||
const { default: useFullscreen } = require('stremio/common/useFullscreen');
|
||||
const { useFullscreen } = require('stremio/common/Fullscreen');
|
||||
const useProfile = require('stremio/common/useProfile');
|
||||
const usePWA = require('stremio/common/usePWA');
|
||||
const { default: usePlayUrl } = require('stremio/common/usePlayUrl');
|
||||
|
|
|
|||
Loading…
Reference in a new issue