diff --git a/src/apps/experimental/components/AppToolbar/index.tsx b/src/apps/experimental/components/AppToolbar/index.tsx index 950fb638413..e8626fd3971 100644 --- a/src/apps/experimental/components/AppToolbar/index.tsx +++ b/src/apps/experimental/components/AppToolbar/index.tsx @@ -18,17 +18,30 @@ interface AppToolbarProps { onDrawerButtonClick: (event: React.MouseEvent) => void } +const PUBLIC_PATHS = [ + '/addserver.html', + '/selectserver.html', + '/login.html', + '/forgotpassword.html', + '/forgotpasswordpin.html' +]; + const ExperimentalAppToolbar: FC = ({ 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 ( @@ -45,10 +58,11 @@ const ExperimentalAppToolbar: FC = ({ - } + )} isDrawerAvailable={isDrawerAvailable} isDrawerOpen={isDrawerOpen} onDrawerButtonClick={onDrawerButtonClick} + isUserMenuAvailable={!isPublicPath} > {isTabsAvailable && ()} diff --git a/src/apps/experimental/routes/legacyRoutes/user.ts b/src/apps/experimental/routes/legacyRoutes/user.ts index 12e137bc96f..2045495a10c 100644 --- a/src/apps/experimental/routes/legacyRoutes/user.ts +++ b/src/apps/experimental/routes/legacyRoutes/user.ts @@ -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: { diff --git a/src/apps/experimental/routes/routes.tsx b/src/apps/experimental/routes/routes.tsx index 718aaf10b62..47e0a9f7f52 100644 --- a/src/apps/experimental/routes/routes.tsx +++ b/src/apps/experimental/routes/routes.tsx @@ -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: , 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: + } ] }, diff --git a/src/apps/experimental/routes/video/index.tsx b/src/apps/experimental/routes/video/index.tsx new file mode 100644 index 00000000000..f9322352d50 --- /dev/null +++ b/src/apps/experimental/routes/video/index.tsx @@ -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); + 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 ( + <> + + + + + + + } + /> + + + + + + ); +}; + +export default VideoPage; diff --git a/src/components/toolbar/AppToolbar.tsx b/src/components/toolbar/AppToolbar.tsx index be6cf36e8b5..8283860f3c2 100644 --- a/src/components/toolbar/AppToolbar.tsx +++ b/src/components/toolbar/AppToolbar.tsx @@ -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) => void + onDrawerButtonClick?: (event: React.MouseEvent) => void, + isUserMenuAvailable?: boolean } const onBackButtonClick = () => { @@ -32,17 +32,14 @@ const AppToolbar: FC = ({ 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 ( = ({ {children} - {isUserLoggedIn && isUserMenuAvailable && ( - <> - - {buttons} - + + {buttons} + - - - - + {isUserLoggedIn && isUserMenuAvailable && ( + + + )} ); diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index 5f3b1018774..6fa5798f79d 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -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(); diff --git a/src/types/eventType.ts b/src/types/eventType.ts new file mode 100644 index 00000000000..929893ccbca --- /dev/null +++ b/src/types/eventType.ts @@ -0,0 +1,6 @@ +/** + * Custom event types. + */ +export enum EventType { + SHOW_VIDEO_OSD = 'SHOW_VIDEO_OSD' +}