mirror of
https://github.com/streamwall/streamwall.git
synced 2026-01-31 01:12:48 -05:00
Add reload button to control interface
This commit is contained in:
@@ -175,6 +175,17 @@ export default class StreamWindow extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reloadView(viewIdx) {
|
||||||
|
const view = this.views.find(
|
||||||
|
(v) =>
|
||||||
|
v.state.matches('displaying') &&
|
||||||
|
v.state.context.pos.spaces.includes(viewIdx),
|
||||||
|
)
|
||||||
|
if (view) {
|
||||||
|
view.send('RELOAD')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
send(...args) {
|
send(...args) {
|
||||||
this.overlayView.webContents.send(...args)
|
this.overlayView.webContents.send(...args)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ async function main() {
|
|||||||
streamWindow.setViews(new Map(msg.views))
|
streamWindow.setViews(new Map(msg.views))
|
||||||
} else if (msg.type === 'set-listening-view') {
|
} else if (msg.type === 'set-listening-view') {
|
||||||
streamWindow.setListeningView(msg.viewIdx)
|
streamWindow.setListeningView(msg.viewIdx)
|
||||||
|
} else if (msg.type === 'reload-view') {
|
||||||
|
streamWindow.reloadView(msg.viewIdx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,11 @@ const viewStateMachine = Machine(
|
|||||||
},
|
},
|
||||||
states: {
|
states: {
|
||||||
empty: {
|
empty: {
|
||||||
entry: [
|
entry: assign({
|
||||||
assign({
|
|
||||||
pos: {},
|
pos: {},
|
||||||
info: {},
|
info: {},
|
||||||
url: null,
|
url: null,
|
||||||
}),
|
}),
|
||||||
'hideView',
|
|
||||||
],
|
|
||||||
invoke: {
|
invoke: {
|
||||||
src: 'clearView',
|
src: 'clearView',
|
||||||
onError: {
|
onError: {
|
||||||
@@ -45,6 +42,7 @@ const viewStateMachine = Machine(
|
|||||||
}),
|
}),
|
||||||
cond: 'urlUnchanged',
|
cond: 'urlUnchanged',
|
||||||
},
|
},
|
||||||
|
RELOAD: '.loading',
|
||||||
},
|
},
|
||||||
states: {
|
states: {
|
||||||
loading: {
|
loading: {
|
||||||
@@ -80,6 +78,7 @@ const viewStateMachine = Machine(
|
|||||||
running: {
|
running: {
|
||||||
initial: 'muted',
|
initial: 'muted',
|
||||||
entry: 'positionView',
|
entry: 'positionView',
|
||||||
|
exit: 'hideView',
|
||||||
on: {
|
on: {
|
||||||
DISPLAY: {
|
DISPLAY: {
|
||||||
actions: [
|
actions: [
|
||||||
|
|||||||
1
src/static/redo-alt-solid.svg
Normal file
1
src/static/redo-alt-solid.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="redo-alt" class="svg-inline--fa fa-redo-alt fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256.455 8c66.269.119 126.437 26.233 170.859 68.685l35.715-35.715C478.149 25.851 504 36.559 504 57.941V192c0 13.255-10.745 24-24 24H345.941c-21.382 0-32.09-25.851-16.971-40.971l41.75-41.75c-30.864-28.899-70.801-44.907-113.23-45.273-92.398-.798-170.283 73.977-169.484 169.442C88.764 348.009 162.184 424 256 424c41.127 0 79.997-14.678 110.629-41.556 4.743-4.161 11.906-3.908 16.368.553l39.662 39.662c4.872 4.872 4.631 12.815-.482 17.433C378.202 479.813 319.926 504 256 504 119.034 504 8.001 392.967 8 256.002 7.999 119.193 119.646 7.755 256.455 8z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 781 B |
@@ -2,11 +2,13 @@ import range from 'lodash/range'
|
|||||||
import ReconnectingWebSocket from 'reconnecting-websocket'
|
import ReconnectingWebSocket from 'reconnecting-websocket'
|
||||||
import { h, render } from 'preact'
|
import { h, render } from 'preact'
|
||||||
import { useEffect, useState, useCallback, useRef } from 'preact/hooks'
|
import { useEffect, useState, useCallback, useRef } from 'preact/hooks'
|
||||||
import styled from 'styled-components'
|
import { State } from 'xstate'
|
||||||
|
import styled, { css } from 'styled-components'
|
||||||
|
|
||||||
import '../index.css'
|
import '../index.css'
|
||||||
import { GRID_COUNT } from '../constants'
|
import { GRID_COUNT } from '../constants'
|
||||||
import SoundIcon from '../static/volume-up-solid.svg'
|
import SoundIcon from '../static/volume-up-solid.svg'
|
||||||
|
import ReloadIcon from '../static/redo-alt-solid.svg'
|
||||||
|
|
||||||
function emptyStateIdxMap() {
|
function emptyStateIdxMap() {
|
||||||
return new Map(
|
return new Map(
|
||||||
@@ -15,7 +17,7 @@ function emptyStateIdxMap() {
|
|||||||
{
|
{
|
||||||
streamId: null,
|
streamId: null,
|
||||||
url: null,
|
url: null,
|
||||||
state: {},
|
state: State.from({}),
|
||||||
isListening: false,
|
isListening: false,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
@@ -47,13 +49,13 @@ function App({ wsEndpoint }) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const streamId = streams.find((d) => d.Link === url)?._id
|
const streamId = streams.find((d) => d.Link === url)?._id
|
||||||
const isListening =
|
const state = State.from(viewState.state)
|
||||||
viewState.state.displaying?.running === 'listening'
|
const isListening = state.matches('displaying.running.listening')
|
||||||
for (const space of pos.spaces) {
|
for (const space of pos.spaces) {
|
||||||
Object.assign(newStateIdxMap.get(space), {
|
Object.assign(newStateIdxMap.get(space), {
|
||||||
streamId,
|
streamId,
|
||||||
url,
|
url,
|
||||||
state: viewState.state,
|
state,
|
||||||
isListening,
|
isListening,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -102,6 +104,15 @@ function App({ wsEndpoint }) {
|
|||||||
)
|
)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const handleReloadView = useCallback((idx) => {
|
||||||
|
wsRef.current.send(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'reload-view',
|
||||||
|
viewIdx: idx,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Stream Wall</h1>
|
<h1>Stream Wall</h1>
|
||||||
@@ -120,9 +131,11 @@ function App({ wsEndpoint }) {
|
|||||||
idx={idx}
|
idx={idx}
|
||||||
onChangeSpace={handleSetView}
|
onChangeSpace={handleSetView}
|
||||||
spaceValue={streamId}
|
spaceValue={streamId}
|
||||||
isError={state === 'error'}
|
isError={state.matches('error')}
|
||||||
|
isDisplaying={state.matches('displaying')}
|
||||||
isListening={isListening}
|
isListening={isListening}
|
||||||
onSetListening={handleSetListening}
|
onSetListening={handleSetListening}
|
||||||
|
onReloadView={handleReloadView}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -154,9 +167,11 @@ function GridInput({
|
|||||||
idx,
|
idx,
|
||||||
onChangeSpace,
|
onChangeSpace,
|
||||||
spaceValue,
|
spaceValue,
|
||||||
|
isDisplaying,
|
||||||
isError,
|
isError,
|
||||||
isListening,
|
isListening,
|
||||||
onSetListening,
|
onSetListening,
|
||||||
|
onReloadView,
|
||||||
}) {
|
}) {
|
||||||
const [editingValue, setEditingValue] = useState()
|
const [editingValue, setEditingValue] = useState()
|
||||||
const handleFocus = useCallback((ev) => {
|
const handleFocus = useCallback((ev) => {
|
||||||
@@ -177,16 +192,29 @@ function GridInput({
|
|||||||
() => onSetListening(idx, !isListening),
|
() => onSetListening(idx, !isListening),
|
||||||
[idx, onSetListening, isListening],
|
[idx, onSetListening, isListening],
|
||||||
)
|
)
|
||||||
|
const handleReloadClick = useCallback(() => onReloadView(idx), [
|
||||||
|
idx,
|
||||||
|
onReloadView,
|
||||||
|
])
|
||||||
const handleClick = useCallback((ev) => {
|
const handleClick = useCallback((ev) => {
|
||||||
ev.target.select()
|
ev.target.select()
|
||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
<StyledGridContainer>
|
<StyledGridContainer>
|
||||||
|
{isDisplaying && (
|
||||||
|
<StyledGridButtons side="left">
|
||||||
|
<StyledButton onClick={handleReloadClick}>
|
||||||
|
<ReloadIcon />
|
||||||
|
</StyledButton>
|
||||||
|
</StyledGridButtons>
|
||||||
|
)}
|
||||||
|
<StyledGridButtons side="right">
|
||||||
<ListeningButton
|
<ListeningButton
|
||||||
isListening={isListening}
|
isListening={isListening}
|
||||||
onClick={handleListeningClick}
|
onClick={handleListeningClick}
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
/>
|
/>
|
||||||
|
</StyledGridButtons>
|
||||||
<StyledGridInput
|
<StyledGridInput
|
||||||
name={idx}
|
name={idx}
|
||||||
value={editingValue || spaceValue || ''}
|
value={editingValue || spaceValue || ''}
|
||||||
@@ -216,12 +244,12 @@ const StyledGridLine = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
`
|
`
|
||||||
|
|
||||||
const StyledListeningButton = styled.button`
|
const StyledButton = styled.button`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border: 2px solid gray;
|
border: 2px solid gray;
|
||||||
border-color: ${({ isListening }) => (isListening ? 'red' : 'gray')};
|
border-color: gray;
|
||||||
background: ${({ isListening }) => (isListening ? '#c77' : '#ccc')};
|
background: #ccc;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
@@ -235,13 +263,27 @@ const StyledListeningButton = styled.button`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const StyledListeningButton = styled(StyledButton)`
|
||||||
|
${({ isListening }) =>
|
||||||
|
isListening &&
|
||||||
|
`
|
||||||
|
border-color: red;
|
||||||
|
background: #c77;
|
||||||
|
`};
|
||||||
|
`
|
||||||
|
|
||||||
const StyledGridContainer = styled.div`
|
const StyledGridContainer = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
|
`
|
||||||
|
|
||||||
${StyledListeningButton} {
|
const StyledGridButtons = styled.div`
|
||||||
|
display: flex;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 5px;
|
bottom: 0;
|
||||||
right: 5px;
|
${({ side }) => (side === 'left' ? 'left: 0' : 'right: 0')};
|
||||||
|
|
||||||
|
${StyledButton} {
|
||||||
|
margin: 5px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user