Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ Appending query parameter(s) to the URL will allow you to modify the behaviour o
| `vibrate=1` | Experimental feature that triggers the vibration API in the web browser 3 seconds before each planned _Take_. _Default value is `0`._ |
| `zoom=100,...` | Sets the scaling of the entire GUI. _The unit is a percentage where `100` is the default scaling._ **Passing any `zoom` parameter will cause it to be stored in the browser's local storage as `uiZoomLevel` and will then be used for future sessions without notifying the user that they are using the Sofie GUI at a non-standard size!** |
| `hideRundownHeader=1` | Hides header on [Rundown view](../user-guide/features/sofie-views-and-screens#rundown-view) and [Active Rundown screen](../user-guide/features/sofie-views-and-screens#active-rundown-screen). _Default value is `0`._ |
| `lockView=1` | Locks the [Active Rundown screen](../user-guide/features/sofie-views-and-screens#active-rundown-screen) for unattended or kiosk use: hides exit controls (header close button and context menu “Close Rundown”), disables the in-app navigation confirmation when a rundown is active, and shows the [Screensaver](../user-guide/features/sofie-views-and-screens#screensaver) when no rundown is active instead of a message with a link back to the lobby. Only applies on `/activeRundown/:studioId` routes (ignored on `/rundown/:playlistId`). _Default value is `0`._ |
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,20 @@ Example: [http://127.0.0.1/countdowns/studio0/camera?sourceLayerIds=camera0,dve0

A page which automatically displays the currently active rundown. Can be useful for the producer to have on a secondary screen.

When no rundown is active, a message is shown with a link back to the rundown list.

This screen can be configured using query parameters:

| Query parameter | Type | Description | Default |
| :-------------- | :---- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
| `lockView` | 0 / 1 | Locks the view for unattended or kiosk displays. Hides the header close button and the context menu “Close Rundown” action, and disables the in-app navigation confirmation when a rundown is active. When no rundown is active, shows the [Screensaver](#screensaver) instead of the default idle message. Does not block browser back, manual URL changes, or closing the tab. Only applies on Active Rundown routes (not on a specific `/rundown/:playlistId` URL). | `0` |

Example (locked Active Rundown for a secondary monitor):

`http://localhost:3000/activeRundown/studio0?lockView=1`

Other query parameters for the rundown view itself (such as `hideRundownHeader` and layout selection) can be combined with `lockView`. See [URL Query Parameters](../../for-developers/url-query-parameters.md).

### Active Rundown Shelf Screen

`/activeRundown/:studioId/shelf`
Expand All @@ -357,6 +371,10 @@ A screen which automatically displays the currently active rundown, and shows th

A shelf layout can be selected by modifying the query string, see [Shelf Layouts](#shelf-layouts).

The `lockView` parameter described above also applies to this route. Example:

`http://localhost:3000/activeRundown/studio0/shelf?lockView=1&layout=Stream`

### Specific Rundown Shelf Screen

`/rundown/:rundownId/shelf`
Expand All @@ -379,7 +397,7 @@ Each embedded screen shows a label to identify it. This screen is mostly intende

### Screensaver

When big screen displays \(like Prompter Screen and the Presenter Screen\) do not have any meaningful content to show, an animated screensaver showing the current time and the next planned show will be displayed. If no Rundown is upcoming, the Studio name will be displayed.
When big screen displays \(like Prompter Screen, the Presenter Screen, and the Active Rundown Screen with `lockView=1`\) do not have any meaningful content to show, an animated screensaver showing the current time and the next planned show will be displayed. If no Rundown is upcoming, the Studio name will be displayed.

![A screensaver showing the next scheduled show](/img/docs/main/features/next-scheduled-show-example.png)

Expand Down
9 changes: 8 additions & 1 deletion packages/webui/src/client/ui/ActiveRundownView.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { NavLink, Route, Switch, useRouteMatch } from 'react-router-dom'
import { NavLink, Route, Switch, useLocation, useRouteMatch } from 'react-router-dom'
import { parse as queryStringParse } from 'query-string'
import { useSubscription, useTracker } from '../lib/ReactMeteorData/ReactMeteorData.js'

import { Spinner } from '../lib/Spinner.js'
import { RundownView } from './RundownView.js'
import { StudioScreenSaver } from './StudioScreenSaver/StudioScreenSaver.js'
import { MeteorPubSub } from '@sofie-automation/meteor-lib/dist/api/pubsub'
import { UIStudios } from './Collections.js'
import type { StudioId } from '@sofie-automation/corelib/dist/dataModel/Ids'
Expand All @@ -14,6 +16,8 @@ export function ActiveRundownView({ studioId }: Readonly<{ studioId: StudioId }>
const { t } = useTranslation()

const { path } = useRouteMatch()
const { search } = useLocation()
const lockView = queryStringParse(search)['lockView'] === '1'

const studioReady = useSubscription(MeteorPubSub.uiStudio, studioId)
const playlistReady = useSubscription(MeteorPubSub.rundownPlaylistForStudio, studioId, true)
Expand Down Expand Up @@ -48,6 +52,9 @@ export function ActiveRundownView({ studioId }: Readonly<{ studioId: StudioId }>
</Switch>
)
} else if (studio) {
if (lockView) {
return <StudioScreenSaver studioId={studioId} ownBackground={true} screenName={t('Rundown View')} />
}
return <NotFoundMessage message={t('There is no rundown active in this studio.')} />
} else if (studioId) {
return <NotFoundMessage message={t("This studio doesn't exist.")} />
Expand Down
6 changes: 5 additions & 1 deletion packages/webui/src/client/ui/RundownView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ export function RundownView(props: Readonly<IProps>): JSX.Element {
)

const hideRundownHeader = params['hideRundownHeader'] === '1'
const lockView = props.inActiveRundownView && params['lockView'] === '1'

return (
<div
Expand All @@ -314,6 +315,7 @@ export function RundownView(props: Readonly<IProps>): JSX.Element {
uiSegmentMap={miniShelfData.uiSegmentMap}
miniShelfFilter={miniShelfData.miniShelfFilter}
hideRundownHeader={hideRundownHeader}
lockView={lockView}
/>
</div>
)
Expand All @@ -323,6 +325,7 @@ interface IPropsWithReady extends IProps {
subsReady: boolean
userPermissions: Readonly<UserPermissions>
hideRundownHeader?: boolean
lockView?: boolean
}

interface IRundownViewContentSnapshot {
Expand Down Expand Up @@ -1410,6 +1413,7 @@ const RundownViewContent = translateWithTracker<IPropsWithReady & ITrackedProps,
firstRundown={this.props.rundowns[0]}
currentRundown={currentRundown}
rundownCount={this.props.rundowns.length}
lockView={this.props.lockView}
/>
</ErrorBoundary>
)}
Expand Down Expand Up @@ -1516,7 +1520,7 @@ const RundownViewContent = translateWithTracker<IPropsWithReady & ITrackedProps,
<ErrorBoundary>
{this.props.userPermissions.studio && (
<Prompt
when={!!playlist.activationId}
when={!!playlist.activationId && !this.props.lockView}
message={t('This rundown is now active. Are you sure you want to exit this screen?')}
Comment thread
justandras marked this conversation as resolved.
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface RundownContextMenuProps {
playlist: DBRundownPlaylist
studio: UIStudio
firstRundown: Rundown | undefined
lockView?: boolean
onShow?: () => void
onHide?: () => void
}
Expand All @@ -39,6 +40,7 @@ export function RundownContextMenu({
playlist,
studio,
firstRundown,
lockView,
onShow,
onHide,
}: Readonly<RundownContextMenuProps>): JSX.Element {
Expand Down Expand Up @@ -133,8 +135,12 @@ export function RundownContextMenu({
})}
</MenuItem>
<MenuItem onClick={operations.takeRundownSnapshot}>{t('Store Snapshot')}</MenuItem>
<MenuItem divider />
<MenuItem onClick={() => history.push('/')}>{t('Close Rundown')}</MenuItem>
{!lockView && (
<>
<MenuItem divider />
<MenuItem onClick={() => history.push('/')}>{t('Close Rundown')}</MenuItem>
</>
)}
</React.Fragment>
) : (
<React.Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,11 @@
flex-shrink: 0;
transition: opacity 0.2s;

&--placeholder {
visibility: hidden;
pointer-events: none;
}

svg,
i {
filter: drop-shadow(0 0 0 rgba(255, 255, 255, 0));
Expand Down Expand Up @@ -578,7 +583,7 @@
color: #fff;
}

.rundown-header__close-btn {
.rundown-header__close-btn:not(.rundown-header__close-btn--placeholder) {
opacity: 1;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface IRundownHeaderProps {
studio: UIStudio
firstRundown: Rundown | undefined
rundownCount: number
lockView?: boolean
}

export function RundownHeader({
Expand All @@ -35,6 +36,7 @@ export function RundownHeader({
firstRundown,
currentRundown,
rundownCount,
lockView,
}: IRundownHeaderProps): JSX.Element {
const { t } = useTranslation()
const timingDurations = useTiming()
Expand Down Expand Up @@ -80,6 +82,7 @@ export function RundownHeader({
playlist={playlist}
studio={studio}
firstRundown={firstRundown}
lockView={lockView}
onShow={() => setIsContextMenuOpen(true)}
onHide={() => {
setIsMenuOpen(false)
Expand Down Expand Up @@ -157,9 +160,15 @@ export function RundownHeader({
<RundownHeaderDurations playlist={playlist} simplified={simplified} />
<RundownHeaderExpectedEnd playlist={playlist} simplified={simplified} />
</button>
<NavLink to="/" title={t('Exit')} aria-label={t('Exit')} className="rundown-header__close-btn">
<FontAwesomeIcon icon="close" size="xl" />
</NavLink>
{lockView ? (
<span className="rundown-header__close-btn rundown-header__close-btn--placeholder" aria-hidden="true">
<FontAwesomeIcon icon="close" size="xl" />
</span>
) : (
<NavLink to="/" title={t('Exit')} aria-label={t('Exit')} className="rundown-header__close-btn">
<FontAwesomeIcon icon="close" size="xl" />
</NavLink>
)}
</div>
</div>
</RundownHeaderContextMenuTrigger>
Expand Down
Loading