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:
parent
cb01afce02
commit
017734a0bb
7 changed files with 117 additions and 29 deletions
|
@ -18,17 +18,30 @@ interface AppToolbarProps {
|
|||
onDrawerButtonClick: (event: React.MouseEvent<HTMLElement>) => void
|
||||
}
|
||||
|
||||
const PUBLIC_PATHS = [
|
||||
'/addserver.html',
|
||||
'/selectserver.html',
|
||||
'/login.html',
|
||||
'/forgotpassword.html',
|
||||
'/forgotpasswordpin.html'
|
||||
];
|
||||
|
||||
const ExperimentalAppToolbar: FC<AppToolbarProps> = ({
|
||||
isDrawerAvailable,
|
||||
isDrawerOpen,
|
||||
onDrawerButtonClick
|
||||
}) => {
|
||||
const location = useLocation();
|
||||
|
||||
// The video osd does not show the standard toolbar
|
||||
if (location.pathname === '/video') return null;
|
||||
|
||||
const isTabsAvailable = isTabPath(location.pathname);
|
||||
const isPublicPath = PUBLIC_PATHS.includes(location.pathname);
|
||||
|
||||
return (
|
||||
<AppToolbar
|
||||
buttons={
|
||||
buttons={!isPublicPath && (
|
||||
<>
|
||||
<SyncPlayButton />
|
||||
<RemotePlayButton />
|
||||
|
@ -45,10 +58,11 @@ const ExperimentalAppToolbar: FC<AppToolbarProps> = ({
|
|||
</IconButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
}
|
||||
)}
|
||||
isDrawerAvailable={isDrawerAvailable}
|
||||
isDrawerOpen={isDrawerOpen}
|
||||
onDrawerButtonClick={onDrawerButtonClick}
|
||||
isUserMenuAvailable={!isPublicPath}
|
||||
>
|
||||
{isTabsAvailable && (<AppTabs isDrawerOpen={isDrawerOpen} />)}
|
||||
</AppToolbar>
|
||||
|
|
|
@ -49,16 +49,6 @@ export const LEGACY_USER_ROUTES: LegacyRoute[] = [
|
|||
controller: 'user/subtitles/index',
|
||||
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',
|
||||
pageProps: {
|
||||
|
|
|
@ -7,8 +7,10 @@ import { toAsyncPageRoute } from 'components/router/AsyncRoute';
|
|||
import { toViewManagerPageRoute } from 'components/router/LegacyRoute';
|
||||
import { toRedirectRoute } from 'components/router/Redirect';
|
||||
import AppLayout from '../AppLayout';
|
||||
|
||||
import { ASYNC_USER_ROUTES } from './asyncRoutes';
|
||||
import { LEGACY_PUBLIC_ROUTES, LEGACY_USER_ROUTES } from './legacyRoutes';
|
||||
import VideoPage from './video';
|
||||
|
||||
export const EXPERIMENTAL_APP_ROUTES: RouteObject[] = [
|
||||
{
|
||||
|
@ -20,7 +22,13 @@ export const EXPERIMENTAL_APP_ROUTES: RouteObject[] = [
|
|||
element: <ConnectionRequired isUserRequired />,
|
||||
children: [
|
||||
...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 />
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
|
72
src/apps/experimental/routes/video/index.tsx
Normal file
72
src/apps/experimental/routes/video/index.tsx
Normal 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;
|
|
@ -5,7 +5,6 @@ import IconButton from '@mui/material/IconButton';
|
|||
import Toolbar from '@mui/material/Toolbar';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import React, { FC, ReactNode } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { appRouter } from 'components/router/appRouter';
|
||||
import { useApi } from 'hooks/useApi';
|
||||
|
@ -17,7 +16,8 @@ interface AppToolbarProps {
|
|||
buttons?: ReactNode
|
||||
isDrawerAvailable: boolean
|
||||
isDrawerOpen: boolean
|
||||
onDrawerButtonClick: (event: React.MouseEvent<HTMLElement>) => void
|
||||
onDrawerButtonClick?: (event: React.MouseEvent<HTMLElement>) => void,
|
||||
isUserMenuAvailable?: boolean
|
||||
}
|
||||
|
||||
const onBackButtonClick = () => {
|
||||
|
@ -32,17 +32,14 @@ const AppToolbar: FC<AppToolbarProps> = ({
|
|||
children,
|
||||
isDrawerAvailable,
|
||||
isDrawerOpen,
|
||||
onDrawerButtonClick
|
||||
onDrawerButtonClick = () => { /* no-op */ },
|
||||
isUserMenuAvailable = true
|
||||
}) => {
|
||||
const { user } = useApi();
|
||||
const isUserLoggedIn = Boolean(user);
|
||||
const currentLocation = useLocation();
|
||||
|
||||
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 (
|
||||
<Toolbar
|
||||
variant='dense'
|
||||
|
@ -84,16 +81,14 @@ const AppToolbar: FC<AppToolbarProps> = ({
|
|||
|
||||
{children}
|
||||
|
||||
{isUserLoggedIn && isUserMenuAvailable && (
|
||||
<>
|
||||
<Box sx={{ display: 'flex', flexGrow: 1, justifyContent: 'flex-end' }}>
|
||||
{buttons}
|
||||
</Box>
|
||||
|
||||
{isUserLoggedIn && isUserMenuAvailable && (
|
||||
<Box sx={{ flexGrow: 0 }}>
|
||||
<UserMenuButton />
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Toolbar>
|
||||
);
|
||||
|
|
|
@ -28,6 +28,7 @@ import LibraryMenu from '../../../scripts/libraryMenu';
|
|||
import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components/backdrop/backdrop';
|
||||
import { pluginManager } from '../../../components/pluginManager';
|
||||
import { PluginType } from '../../../types/plugin.ts';
|
||||
import { EventType } from 'types/eventType';
|
||||
|
||||
const TICKS_PER_MINUTE = 600000000;
|
||||
const TICKS_PER_SECOND = 10000000;
|
||||
|
@ -280,12 +281,14 @@ export default function (view) {
|
|||
let mouseIsDown = false;
|
||||
|
||||
function showOsd(focusElement) {
|
||||
Events.trigger(document, EventType.SHOW_VIDEO_OSD, [ true ]);
|
||||
slideDownToShow(headerElement);
|
||||
showMainOsdControls(focusElement);
|
||||
resetIdle();
|
||||
}
|
||||
|
||||
function hideOsd() {
|
||||
Events.trigger(document, EventType.SHOW_VIDEO_OSD, [ false ]);
|
||||
slideUpToHide(headerElement);
|
||||
hideMainOsdControls();
|
||||
mouseManager.hideCursor();
|
||||
|
|
6
src/types/eventType.ts
Normal file
6
src/types/eventType.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* Custom event types.
|
||||
*/
|
||||
export enum EventType {
|
||||
SHOW_VIDEO_OSD = 'SHOW_VIDEO_OSD'
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue