Add support for blurring streams

This commit is contained in:
Max Goodman
2020-06-22 13:31:18 -07:00
committed by Max Goodhart
parent 3759b05915
commit e861071599
6 changed files with 108 additions and 34 deletions

View File

@@ -31,10 +31,14 @@ function Overlay({ views, streams, customStreams }) {
const data = [...streams, ...customStreams].find(
(d) => content.url === d.Link,
)
const isListening = viewState.matches('displaying.running.listening')
const isListening = viewState.matches(
'displaying.running.audio.listening',
)
const isBlurred = viewState.matches('displaying.running.video.blurred')
const isLoading = viewState.matches('displaying.loading')
return (
<SpaceBorder pos={pos} isListening={isListening}>
<BlurCover isBlurred={isBlurred} />
{data && (
<StreamTitle isListening={isListening}>
<StreamIcon url={content.url} />
@@ -186,4 +190,13 @@ const ListeningIndicator = styled(SoundIcon)`
}
`
const BlurCover = styled.div`
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
backdrop-filter: ${({ isBlurred }) => (isBlurred ? 'blur(30px)' : 'blur(0)')};
`
render(<App />, document.body)

View File

@@ -223,16 +223,23 @@ export default class StreamWindow extends EventEmitter {
)
}
reloadView(viewIdx) {
sendViewEvent(viewIdx, event) {
const view = this.findViewByIdx(viewIdx)
if (view) {
view.send('RELOAD')
view.send(event)
}
}
setViewBlurred(viewIdx, blurred) {
this.sendViewEvent(viewIdx, blurred ? 'BLUR' : 'UNBLUR')
}
reloadView(viewIdx) {
this.sendViewEvent(viewIdx, 'RELOAD')
}
openDevTools(viewIdx, inWebContents) {
const view = this.findViewByIdx(viewIdx)
view.send({ type: 'DEVTOOLS', inWebContents })
this.sendViewEvent(viewIdx, { type: 'DEVTOOLS', inWebContents })
}
send(...args) {

View File

@@ -83,6 +83,8 @@ async function main() {
streamWindow.setViews(new Map(msg.views))
} else if (msg.type === 'set-listening-view') {
streamWindow.setListeningView(msg.viewIdx)
} else if (msg.type === 'set-view-blurred') {
streamWindow.setViewBlurred(msg.viewIdx, msg.blurred)
} else if (msg.type === 'set-custom-streams') {
const customIDGen = new StreamIDGenerator(idGen)
clientState.customStreams = customIDGen.process(msg.streams)

View File

@@ -102,7 +102,7 @@ const viewStateMachine = Machine(
},
},
running: {
initial: 'muted',
type: 'parallel',
entry: 'positionView',
on: {
DISPLAY: {
@@ -114,15 +114,33 @@ const viewStateMachine = Machine(
],
cond: 'contentUnchanged',
},
MUTE: '.muted',
UNMUTE: '.listening',
},
states: {
muted: {
entry: 'muteAudio',
audio: {
initial: 'muted',
on: {
MUTE: '.muted',
UNMUTE: '.listening',
},
states: {
muted: {
entry: 'muteAudio',
},
listening: {
entry: 'unmuteAudio',
},
},
},
listening: {
entry: 'unmuteAudio',
video: {
initial: 'normal',
on: {
BLUR: '.blurred',
UNBLUR: '.normal',
},
states: {
normal: {},
blurred: {},
},
},
},
},

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="video-slash" class="svg-inline--fa fa-video-slash fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M633.8 458.1l-55-42.5c15.4-1.4 29.2-13.7 29.2-31.1v-257c0-25.5-29.1-40.4-50.4-25.8L448 177.3v137.2l-32-24.7v-178c0-26.4-21.4-47.8-47.8-47.8H123.9L45.5 3.4C38.5-2 28.5-.8 23 6.2L3.4 31.4c-5.4 7-4.2 17 2.8 22.4L42.7 82 416 370.6l178.5 138c7 5.4 17 4.2 22.5-2.8l19.6-25.3c5.5-6.9 4.2-17-2.8-22.4zM32 400.2c0 26.4 21.4 47.8 47.8 47.8h288.4c11.2 0 21.4-4 29.6-10.5L32 154.7v245.5z"></path></svg>

After

Width:  |  Height:  |  Size: 617 B

View File

@@ -8,6 +8,7 @@ import styled, { css } from 'styled-components'
import '../index.css'
import { GRID_COUNT } from '../constants'
import SoundIcon from '../static/volume-up-solid.svg'
import NoVideoIcon from '../static/video-slash-solid.svg'
import ReloadIcon from '../static/redo-alt-solid.svg'
import LifeRingIcon from '../static/life-ring-regular.svg'
import WindowIcon from '../static/window-maximize-regular.svg'
@@ -42,7 +43,10 @@ function App({ wsEndpoint }) {
const stream = allStreams.find((d) => d.Link === content.url)
const streamId = stream?._id
const state = State.from(viewState.state)
const isListening = state.matches('displaying.running.listening')
const isListening = state.matches(
'displaying.running.audio.listening',
)
const isBlurred = state.matches('displaying.running.video.blurred')
for (const space of pos.spaces) {
if (!newStateIdxMap.has(space)) {
newStateIdxMap.set(space, {})
@@ -52,6 +56,7 @@ function App({ wsEndpoint }) {
content,
state,
isListening,
isBlurred,
})
}
}
@@ -102,6 +107,16 @@ function App({ wsEndpoint }) {
)
}, [])
const handleSetBlurred = useCallback((idx, blurred) => {
wsRef.current.send(
JSON.stringify({
type: 'set-view-blurred',
viewIdx: idx,
blurred: blurred,
}),
)
}, [])
const handleReloadView = useCallback((idx) => {
wsRef.current.send(
JSON.stringify({
@@ -166,6 +181,7 @@ function App({ wsEndpoint }) {
const {
streamId = '',
isListening = false,
isBlurred = false,
content = { url: '' },
state,
} = stateIdxMap.get(idx) || {}
@@ -177,8 +193,10 @@ function App({ wsEndpoint }) {
isError={state && state.matches('displaying.error')}
isDisplaying={state && state.matches('displaying')}
isListening={isListening}
isBlurred={isBlurred}
onChangeSpace={handleSetView}
onSetListening={handleSetListening}
onSetBlurred={handleSetBlurred}
onReloadView={handleReloadView}
onBrowse={handleBrowse}
onDevTools={handleDevTools}
@@ -255,7 +273,9 @@ function GridInput({
isDisplaying,
isError,
isListening,
isBlurred,
onSetListening,
onSetBlurred,
onReloadView,
onBrowse,
onDevTools,
@@ -279,6 +299,11 @@ function GridInput({
() => onSetListening(idx, !isListening),
[idx, onSetListening, isListening],
)
const handleBlurClick = useCallback(() => onSetBlurred(idx, !isBlurred), [
idx,
onSetBlurred,
isBlurred,
])
const handleReloadClick = useCallback(() => onReloadView(idx), [
idx,
onReloadView,
@@ -295,23 +320,32 @@ function GridInput({
<StyledGridContainer>
{isDisplaying && (
<StyledGridButtons side="left">
<StyledButton onClick={handleReloadClick}>
<StyledSmallButton onClick={handleReloadClick} tabIndex={1}>
<ReloadIcon />
</StyledButton>
<StyledButton onClick={handleBrowseClick}>
</StyledSmallButton>
<StyledSmallButton onClick={handleBrowseClick} tabIndex={1}>
<WindowIcon />
</StyledButton>
<StyledButton onClick={handleDevToolsClick}>
</StyledSmallButton>
<StyledSmallButton onClick={handleDevToolsClick} tabIndex={1}>
<LifeRingIcon />
</StyledButton>
</StyledSmallButton>
</StyledGridButtons>
)}
<StyledGridButtons side="right">
<ListeningButton
isListening={isListening}
<StyledToggleButton
isActive={isBlurred}
onClick={handleBlurClick}
tabIndex={1}
>
<NoVideoIcon />
</StyledToggleButton>
<StyledToggleButton
isActive={isListening}
onClick={handleListeningClick}
tabIndex={1}
/>
>
<SoundIcon />
</StyledToggleButton>
</StyledGridButtons>
<StyledGridInput
name={idx}
@@ -365,14 +399,6 @@ function CustomStreamInput({ idx, onChange, ...props }) {
)
}
function ListeningButton(props) {
return (
<StyledListeningButton {...props}>
<SoundIcon />
</StyledListeningButton>
)
}
const StyledDataContainer = styled.div`
opacity: ${({ isConnected }) => (isConnected ? 1 : 0.5)};
`
@@ -400,9 +426,16 @@ const StyledButton = styled.button`
}
`
const StyledListeningButton = styled(StyledButton)`
${({ isListening }) =>
isListening &&
const StyledSmallButton = styled(StyledButton)`
svg {
width: 14px;
height: 14px;
}
`
const StyledToggleButton = styled(StyledButton)`
${({ isActive }) =>
isActive &&
`
border-color: red;
background: #c77;
@@ -426,7 +459,7 @@ const StyledGridButtons = styled.div`
`
const StyledGridInput = styled.input`
width: 150px;
width: 160px;
height: 50px;
padding: 20px;
border: 2px solid ${({ isError }) => (isError ? 'red' : 'black')};