1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Backport pull request #5517 from jellyfin-web/release-10.9.z

Fix video osd not hiding in experimental layout

Original-merge: ea1d069e90

Merged-by: thornbill <thornbill@users.noreply.github.com>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
This commit is contained in:
thornbill 2024-05-17 13:52:45 -04:00 committed by Joshua M. Boniface
parent cb01afce02
commit 017734a0bb
7 changed files with 117 additions and 29 deletions

View file

@ -18,17 +18,30 @@ interface AppToolbarProps {
onDrawerButtonClick: (event: React.MouseEvent<HTMLElement>) => void onDrawerButtonClick: (event: React.MouseEvent<HTMLElement>) => void
} }
const PUBLIC_PATHS = [
'/addserver.html',
'/selectserver.html',
'/login.html',
'/forgotpassword.html',
'/forgotpasswordpin.html'
];
const ExperimentalAppToolbar: FC<AppToolbarProps> = ({ const ExperimentalAppToolbar: FC<AppToolbarProps> = ({
isDrawerAvailable, isDrawerAvailable,
isDrawerOpen, isDrawerOpen,
onDrawerButtonClick onDrawerButtonClick
}) => { }) => {
const location = useLocation(); const location = useLocation();
// The video osd does not show the standard toolbar
if (location.pathname === '/video') return null;
const isTabsAvailable = isTabPath(location.pathname); const isTabsAvailable = isTabPath(location.pathname);
const isPublicPath = PUBLIC_PATHS.includes(location.pathname);
return ( return (
<AppToolbar <AppToolbar
buttons={ buttons={!isPublicPath && (
<> <>
<SyncPlayButton /> <SyncPlayButton />
<RemotePlayButton /> <RemotePlayButton />
@ -45,10 +58,11 @@ const ExperimentalAppToolbar: FC<AppToolbarProps> = ({
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</> </>
} )}
isDrawerAvailable={isDrawerAvailable} isDrawerAvailable={isDrawerAvailable}
isDrawerOpen={isDrawerOpen} isDrawerOpen={isDrawerOpen}
onDrawerButtonClick={onDrawerButtonClick} onDrawerButtonClick={onDrawerButtonClick}
isUserMenuAvailable={!isPublicPath}
> >
{isTabsAvailable && (<AppTabs isDrawerOpen={isDrawerOpen} />)} {isTabsAvailable && (<AppTabs isDrawerOpen={isDrawerOpen} />)}
</AppToolbar> </AppToolbar>

View file

@ -49,16 +49,6 @@ export const LEGACY_USER_ROUTES: LegacyRoute[] = [
controller: 'user/subtitles/index', controller: 'user/subtitles/index',
view: 'user/subtitles/index.html' view: 'user/subtitles/index.html'
} }
}, {
path: 'video',
pageProps: {
controller: 'playback/video/index',
view: 'playback/video/index.html',
type: 'video-osd',
isFullscreen: true,
isNowPlayingBarEnabled: false,
isThemeMediaSupported: true
}
}, { }, {
path: 'queue', path: 'queue',
pageProps: { pageProps: {

View file

@ -7,8 +7,10 @@ import { toAsyncPageRoute } from 'components/router/AsyncRoute';
import { toViewManagerPageRoute } from 'components/router/LegacyRoute'; import { toViewManagerPageRoute } from 'components/router/LegacyRoute';
import { toRedirectRoute } from 'components/router/Redirect'; import { toRedirectRoute } from 'components/router/Redirect';
import AppLayout from '../AppLayout'; import AppLayout from '../AppLayout';
import { ASYNC_USER_ROUTES } from './asyncRoutes'; import { ASYNC_USER_ROUTES } from './asyncRoutes';
import { LEGACY_PUBLIC_ROUTES, LEGACY_USER_ROUTES } from './legacyRoutes'; import { LEGACY_PUBLIC_ROUTES, LEGACY_USER_ROUTES } from './legacyRoutes';
import VideoPage from './video';
export const EXPERIMENTAL_APP_ROUTES: RouteObject[] = [ export const EXPERIMENTAL_APP_ROUTES: RouteObject[] = [
{ {
@ -20,7 +22,13 @@ export const EXPERIMENTAL_APP_ROUTES: RouteObject[] = [
element: <ConnectionRequired isUserRequired />, element: <ConnectionRequired isUserRequired />,
children: [ children: [
...ASYNC_USER_ROUTES.map(toAsyncPageRoute), ...ASYNC_USER_ROUTES.map(toAsyncPageRoute),
...LEGACY_USER_ROUTES.map(toViewManagerPageRoute) ...LEGACY_USER_ROUTES.map(toViewManagerPageRoute),
// The video page is special since it combines new controls with the legacy view
{
path: 'video',
element: <VideoPage />
}
] ]
}, },

View file

@ -0,0 +1,72 @@
import Box from '@mui/material/Box/Box';
import Fade from '@mui/material/Fade/Fade';
import React, { useRef, type FC, useEffect, useState } from 'react';
import RemotePlayButton from 'apps/experimental/components/AppToolbar/RemotePlayButton';
import SyncPlayButton from 'apps/experimental/components/AppToolbar/SyncPlayButton';
import AppToolbar from 'components/toolbar/AppToolbar';
import ViewManagerPage from 'components/viewManager/ViewManagerPage';
import { EventType } from 'types/eventType';
import Events, { type Event } from 'utils/events';
/**
* Video player page component that renders mui controls for the top controls and the legacy view for everything else.
*/
const VideoPage: FC = () => {
const documentRef = useRef<Document>(document);
const [ isVisible, setIsVisible ] = useState(true);
const onShowVideoOsd = (_e: Event, isShowing: boolean) => {
setIsVisible(isShowing);
};
useEffect(() => {
const doc = documentRef.current;
if (doc) Events.on(doc, EventType.SHOW_VIDEO_OSD, onShowVideoOsd);
return () => {
if (doc) Events.off(doc, EventType.SHOW_VIDEO_OSD, onShowVideoOsd);
};
}, []);
return (
<>
<Fade
in={isVisible}
easing='fade-out'
>
<Box sx={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
color: 'white'
}}>
<AppToolbar
isDrawerAvailable={false}
isDrawerOpen={false}
isUserMenuAvailable={false}
buttons={
<>
<SyncPlayButton />
<RemotePlayButton />
</>
}
/>
</Box>
</Fade>
<ViewManagerPage
controller='playback/video/index'
view='playback/video/index.html'
type='video-osd'
isFullscreen
isNowPlayingBarEnabled={false}
isThemeMediaSupported
/>
</>
);
};
export default VideoPage;

View file

@ -5,7 +5,6 @@ import IconButton from '@mui/material/IconButton';
import Toolbar from '@mui/material/Toolbar'; import Toolbar from '@mui/material/Toolbar';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { FC, ReactNode } from 'react'; import React, { FC, ReactNode } from 'react';
import { useLocation } from 'react-router-dom';
import { appRouter } from 'components/router/appRouter'; import { appRouter } from 'components/router/appRouter';
import { useApi } from 'hooks/useApi'; import { useApi } from 'hooks/useApi';
@ -17,7 +16,8 @@ interface AppToolbarProps {
buttons?: ReactNode buttons?: ReactNode
isDrawerAvailable: boolean isDrawerAvailable: boolean
isDrawerOpen: boolean isDrawerOpen: boolean
onDrawerButtonClick: (event: React.MouseEvent<HTMLElement>) => void onDrawerButtonClick?: (event: React.MouseEvent<HTMLElement>) => void,
isUserMenuAvailable?: boolean
} }
const onBackButtonClick = () => { const onBackButtonClick = () => {
@ -32,17 +32,14 @@ const AppToolbar: FC<AppToolbarProps> = ({
children, children,
isDrawerAvailable, isDrawerAvailable,
isDrawerOpen, isDrawerOpen,
onDrawerButtonClick onDrawerButtonClick = () => { /* no-op */ },
isUserMenuAvailable = true
}) => { }) => {
const { user } = useApi(); const { user } = useApi();
const isUserLoggedIn = Boolean(user); const isUserLoggedIn = Boolean(user);
const currentLocation = useLocation();
const isBackButtonAvailable = appRouter.canGoBack(); const isBackButtonAvailable = appRouter.canGoBack();
// Handles a specific case to hide the user menu on the select server page while authenticated
const isUserMenuAvailable = currentLocation.pathname !== '/selectserver.html';
return ( return (
<Toolbar <Toolbar
variant='dense' variant='dense'
@ -84,16 +81,14 @@ const AppToolbar: FC<AppToolbarProps> = ({
{children} {children}
{isUserLoggedIn && isUserMenuAvailable && (
<>
<Box sx={{ display: 'flex', flexGrow: 1, justifyContent: 'flex-end' }}> <Box sx={{ display: 'flex', flexGrow: 1, justifyContent: 'flex-end' }}>
{buttons} {buttons}
</Box> </Box>
{isUserLoggedIn && isUserMenuAvailable && (
<Box sx={{ flexGrow: 0 }}> <Box sx={{ flexGrow: 0 }}>
<UserMenuButton /> <UserMenuButton />
</Box> </Box>
</>
)} )}
</Toolbar> </Toolbar>
); );

View file

@ -28,6 +28,7 @@ import LibraryMenu from '../../../scripts/libraryMenu';
import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components/backdrop/backdrop'; import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components/backdrop/backdrop';
import { pluginManager } from '../../../components/pluginManager'; import { pluginManager } from '../../../components/pluginManager';
import { PluginType } from '../../../types/plugin.ts'; import { PluginType } from '../../../types/plugin.ts';
import { EventType } from 'types/eventType';
const TICKS_PER_MINUTE = 600000000; const TICKS_PER_MINUTE = 600000000;
const TICKS_PER_SECOND = 10000000; const TICKS_PER_SECOND = 10000000;
@ -280,12 +281,14 @@ export default function (view) {
let mouseIsDown = false; let mouseIsDown = false;
function showOsd(focusElement) { function showOsd(focusElement) {
Events.trigger(document, EventType.SHOW_VIDEO_OSD, [ true ]);
slideDownToShow(headerElement); slideDownToShow(headerElement);
showMainOsdControls(focusElement); showMainOsdControls(focusElement);
resetIdle(); resetIdle();
} }
function hideOsd() { function hideOsd() {
Events.trigger(document, EventType.SHOW_VIDEO_OSD, [ false ]);
slideUpToHide(headerElement); slideUpToHide(headerElement);
hideMainOsdControls(); hideMainOsdControls();
mouseManager.hideCursor(); mouseManager.hideCursor();

6
src/types/eventType.ts Normal file
View file

@ -0,0 +1,6 @@
/**
* Custom event types.
*/
export enum EventType {
SHOW_VIDEO_OSD = 'SHOW_VIDEO_OSD'
}