Skip to content

Commit

Permalink
Merge branch 'wip/backend-frontend'
Browse files Browse the repository at this point in the history
  • Loading branch information
nytamin committed Jan 18, 2024
2 parents 09073c0 + 8389fc0 commit 9c6f3c2
Show file tree
Hide file tree
Showing 12 changed files with 313 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export class OutputSettingsService extends EventEmitter<Definition.Events> imple
return service
}
private static setupPublications(app: Application<ServiceTypes, any>, service: OutputSettingsFeathersService) {
service.publish('created', (_data, _context) => {
return app.channel(PublishChannels.OutputSettings())
})
// service.publish('created', (_data, _context) => {
// return app.channel(PublishChannels.OutputSettings())
// })
service.publish('updated', (_data, _context) => {
return app.channel(PublishChannels.OutputSettings())
})
Expand All @@ -60,30 +60,28 @@ export class OutputSettingsService extends EventEmitter<Definition.Events> imple
}
}

public async find(_params?: Params & { paginate?: PaginationParams }): Promise<Data[]> {
return [this.store.outputSettings.outputSettings.get()]
}
public async get(id: Id, _params?: Params): Promise<Data> {
// public async find(_params?: Params & { paginate?: PaginationParams }): Promise<Data[]> {
// return [this.store.outputSettings.outputSettings.get()]
// }
public async get(id: null, _params?: Params): Promise<Data> {
const data = this.store.outputSettings.outputSettings.get()
if (!data) throw new NotFound(`OutputSettings "${id}" not found`)
return data
}
public async create(_data: Data, _params?: Params): Promise<Result> {
throw new NotImplemented(`TODO`)
}
public async update(id: NullId, data: Data, _params?: Params): Promise<Result> {
if (id === null) throw new BadRequest(`id must not be null`)

// public async create(_data: Data, _params?: Params): Promise<Result> {
// throw new NotImplemented(`TODO`)
// }
public async update(_id: null, data: Data, _params?: Params): Promise<Result> {
this.store.outputSettings.update(data)
return this.get('')
return this.get(null)
}

public async subscribeToController(_: unknown, params: Params): Promise<void> {
public async subscribe(_: unknown, params: Params): Promise<void> {
if (!params.connection) throw new Error('No connection!')
this.app.channel(PublishChannels.OutputSettings()).join(params.connection)
}
}
type Result = Definition.Result
type Id = Definition.Id
type NullId = Definition.NullId
// type Id = Definition.Id
// type NullId = Definition.NullId
type Data = Definition.Data
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { OutputSettings } from '@sofie-prompter-editor/shared-model'

export class OutputSettingsStore {
public outputSettings = observable.box<OutputSettings>({
_id: '',
// _id: '',

// TODO: load these from persistent store upon startup?
fontSize: 10,
Expand Down
10 changes: 10 additions & 0 deletions packages/apps/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ function App(): React.JSX.Element {
Editor playground
</Link>
</Nav.Item>
<Nav.Item>
<Link className="nav-link" to="/output">
Output
</Link>
</Nav.Item>
<Nav.Item>
<Link className="nav-link" to="/test-controller">
Test Controller
</Link>
</Nav.Item>
</Nav>
</Container>
</Navbar>
Expand Down
83 changes: 69 additions & 14 deletions packages/apps/client/src/Output/Output.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,47 @@
import React, { useEffect, useMemo, useReducer, useRef } from 'react'
import { observer } from 'mobx-react-lite'
import React from 'react'
import { AppStore } from '../stores/AppStore'

const Output = observer(function Output() {
const speed = useRef(0)

// On startup
useEffect(() => {
AppStore.outputSettingsStore.initialize() // load and subscribe

AppStore.connection.controller.on('message', (message) => {
console.log('received message', message)

speed.current = message.speed
})
AppStore.connection.controller.subscribeToMessages().catch(console.error)

// don't do this, it's just for testing:
const interval = setInterval(() => {
window.scrollBy(0, speed.current)
}, 1000 / 60)
return () => {
AppStore.connection.controller.off('message')
clearInterval(interval)
}
}, [])

const outputSettings = AppStore.outputSettingsStore.outputSettings

const activeRundownPlaylistId = outputSettings?.activeRundownPlaylistId

useEffect(() => {
if (activeRundownPlaylistId) {
AppStore.rundownStore.loadRundown(activeRundownPlaylistId)
} else {
// TODO: unload rundown?
}
}, [activeRundownPlaylistId])

const rundown = AppStore.rundownStore.openRundown

/*
Implementation notes:
appStore.outputSettings.loadSettings() // load and subscribe
const outputSettings = appStore.outputSettings.outputSettings
appStore.rundownStore.loadRundown(outputSettings.rundownId)
const rundown = appStore.rundownStore.openRundown
// maybe sy
appStore.controller.subscribe()
Expand All @@ -32,13 +61,13 @@ const Output = observer(function Output() {
// restore position on window reload
const viewPort = await appStore.viewPort.get()
handleControllerMessage(viewPort.lastKnownPosition)
if (!isPrimary) {
// Follow the primary viewport:
appStore.viewPort.subscribe()
appStore.viewPort.on('update', (viewPort) => {
// viewPort.lastKnownPosition.timestamp
// viewPort.lastKnownPosition.position
// viewPort.lastKnownPosition.speed
Expand Down Expand Up @@ -69,12 +98,38 @@ const Output = observer(function Output() {
reportViewPortState(viewPort)
}, [isPrimary, viewPort])
*/
const loremIpsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum`
const dummyContent: string[] = []
for (let i = 0; i < 100; i++) {
dummyContent.push(loremIpsum)
}

return <>Prompter Output</>
return (
<>
<h1>Prompter output</h1>
<div>Initialized: {AppStore.outputSettingsStore.initialized ? 'YES' : 'NO'}</div>
<div>{JSON.stringify(outputSettings)}</div>

<div>{rundown ? <>Rundown: {rundown.name}</> : <>No active rundown</>}</div>

<div>
{dummyContent.map((line, i) => (
<div
key={i}
style={{
margin: '1em',
}}
>
{line}
</div>
))}
</div>
</>
)
})
Output.displayName = 'Output'

Expand Down
159 changes: 106 additions & 53 deletions packages/apps/client/src/TestController.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,116 @@
import React from 'react'
import React, { useCallback, useEffect } from 'react'
import { observer } from 'mobx-react-lite'
import { APIConnection } from './api/ApiConnection.ts'
import { OutputSettings } from '@sofie-prompter-editor/shared-model'
import { EditObject, useApiConnection } from './TestUtil.tsx'
import { AppStore } from './stores/AppStore.ts'
import { computed } from 'mobx'

export const TestController: React.FC<{ api: APIConnection }> = ({ api }) => {
const [ready, setReady] = React.useState(false)
const [connected, setConnected] = React.useState(false)
const [outputSettings, setOutputSettings] = React.useState<OutputSettings | null>(null)

useApiConnection(
(connected) => {
if (!connected) {
setConnected(false)
return
}
setConnected(true)

api.outputSettings
.subscribeToController()
.then(() => {
setReady(true)
})
.catch(console.error)

api.outputSettings.on('created', (data) => {
setOutputSettings(data)
})
api.outputSettings.on('updated', (data) => {
setOutputSettings(data)
})
const TestController: React.FC = observer(() => {
// const [ready, setReady] = React.useState(false)
// const [connected, setConnected] = React.useState(false)
// const [outputSettings, setOutputSettings] = React.useState<OutputSettings | null>(null)

// Also fetch initial settings:
api.outputSettings
.get('')
.then((data) => {
setOutputSettings(data)
})
.catch(console.error)
},
api,
[]
)
// On startup
useEffect(() => {
AppStore.outputSettingsStore.initialize() // load and subscribe
}, [])
const outputSettings = computed(() => AppStore.outputSettingsStore.outputSettings).get()

return (
<div style={{ border: '1em solid #666' }}>
<h1>Controller</h1>
<div>Connection status: {connected ? <span>Connected</span> : <span>Not connected</span>}</div>
<div>Subscription status: {ready ? <span>Ready</span> : <span>Not ready</span>}</div>
console.log('outputSettings', outputSettings)

// useApiConnection(
// (connected) => {
// if (!connected) {
// setConnected(false)
// return
// }
// setConnected(true)

// api.outputSettings
// .subscribe()
// .then(() => {
// setReady(true)
// })
// .catch(console.error)

// // api.outputSettings.on('created', (data) => {
// // setOutputSettings(data)
// // })
// api.outputSettings.on('updated', (data) => {
// setOutputSettings(data)
// })

// // Also fetch initial settings:
// api.outputSettings
// .get('')
// .then((data) => {
// setOutputSettings(data)
// })
// .catch(console.error)
// },
// api,
// []
// )

{ready && outputSettings && (
// return (
// <div style={{ border: '1em solid #666' }}>
// <h1>Controller</h1>
// <div>Connection status: {connected ? <span>Connected</span> : <span>Not connected</span>}</div>
// <div>Subscription status: {ready ? <span>Ready</span> : <span>Not ready</span>}</div>

// {ready && outputSettings && (
// <div>
// <EditObject
// obj={outputSettings}
// onChange={(newData) => {
// api.outputSettings.update('', newData).catch(console.error)
// }}
// />
// </div>
// )}
// </div>
// )

const sendSpeed = useCallback((speed: number) => {
AppStore.connection.controller
.sendMessage({
offset: null,
speed: speed,
})
.catch(console.error)
}, [])

return (
<>
<h1>Test controller</h1>
<div>
<h3>Settings</h3>
<div>
{outputSettings ? (
<EditObject
obj={outputSettings}
onChange={(newData) => {
// console.log('newdata', newData)
AppStore.connection.outputSettings.update(null, newData).catch(console.error)
}}
/>
) : (
<span>loading...</span>
)}
</div>
</div>
<div>
<h3>Control the output</h3>
<div>
<EditObject
obj={outputSettings}
onChange={(newData) => {
api.outputSettings.update('', newData).catch(console.error)
}}
/>
<button onClick={() => sendSpeed(-3)}>Speed: -3</button>
<button onClick={() => sendSpeed(0)}>Speed: 0</button>
<button onClick={() => sendSpeed(3)}>Speed: 3</button>
</div>
)}
</div>
</div>
</>
)
}
})
TestController.displayName = 'TestController'

export default TestController
6 changes: 6 additions & 0 deletions packages/apps/client/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { RundownList } from './RundownList/RundownList.tsx'
const RundownScript = React.lazy(() => import('./RundownScript/RundownScript.tsx'))
// eslint-disable-next-line react-refresh/only-export-components
const Output = React.lazy(() => import('./Output/Output.tsx'))
// eslint-disable-next-line react-refresh/only-export-components
const TestController = React.lazy(() => import('./TestController.tsx')) // TODO: temp

const router = createBrowserRouter([
{
Expand All @@ -23,6 +25,10 @@ const router = createBrowserRouter([
path: '/output',
element: <Output />,
},
{
path: '/test-controller',
element: <TestController />,
},
{
path: '/',
element: <App />,
Expand Down
Loading

0 comments on commit 9c6f3c2

Please sign in to comment.