Display spinner when media re-acquiring

This commit is contained in:
Max Goodhart
2026-01-26 00:29:30 -08:00
parent 3759273a16
commit c2aa59ef00
4 changed files with 24 additions and 3 deletions

View File

@@ -126,6 +126,9 @@ export default class StreamWindow extends EventEmitter<StreamWindowEventMap> {
ipcMain.on('view-loaded', (ev) => { ipcMain.on('view-loaded', (ev) => {
this.views.get(ev.sender.id)?.send?.({ type: 'VIEW_LOADED' }) this.views.get(ev.sender.id)?.send?.({ type: 'VIEW_LOADED' })
}) })
ipcMain.on('view-stalled', (ev) => {
this.views.get(ev.sender.id)?.send?.({ type: 'VIEW_STALLED' })
})
ipcMain.on('view-info', (ev, { info }) => { ipcMain.on('view-info', (ev, { info }) => {
this.views.get(ev.sender.id)?.send?.({ type: 'VIEW_INFO', info }) this.views.get(ev.sender.id)?.send?.({ type: 'VIEW_INFO', info })
}) })

View File

@@ -44,6 +44,7 @@ const viewStateMachine = setup({
} }
| { type: 'VIEW_INIT' } | { type: 'VIEW_INIT' }
| { type: 'VIEW_LOADED' } | { type: 'VIEW_LOADED' }
| { type: 'VIEW_STALLED' }
| { type: 'VIEW_INFO'; info: ContentViewInfo } | { type: 'VIEW_INFO'; info: ContentViewInfo }
| { type: 'VIEW_ERROR'; error: unknown } | { type: 'VIEW_ERROR'; error: unknown }
| { type: 'MUTE' } | { type: 'MUTE' }
@@ -290,6 +291,17 @@ const viewStateMachine = setup({
], ],
}, },
states: { states: {
playback: {
initial: 'playing',
on: {
VIEW_STALLED: '.stalled',
VIEW_LOADED: '.playing',
},
states: {
playing: {},
stalled: {},
},
},
audio: { audio: {
initial: 'muted', initial: 'muted',
on: { on: {

View File

@@ -300,6 +300,8 @@ async function main() {
const media = await findMedia(content.kind, elementTimeout) const media = await findMedia(content.kind, elementTimeout)
console.log('media acquired', media) console.log('media acquired', media)
ipcRenderer.send('view-loaded')
if (content.kind === 'video' && media instanceof HTMLVideoElement) { if (content.kind === 'video' && media instanceof HTMLVideoElement) {
rotationController = new RotationController(media) rotationController = new RotationController(media)
snapshotInterval = window.setInterval(() => { snapshotInterval = window.setInterval(() => {
@@ -311,7 +313,10 @@ async function main() {
'emptied', 'emptied',
async () => { async () => {
console.warn('media emptied, re-acquiring', media) console.warn('media emptied, re-acquiring', media)
ipcRenderer.send('view-stalled')
clearInterval(snapshotInterval) clearInterval(snapshotInterval)
const newMedia = await acquireMedia(REACQUIRE_ELEMENT_TIMEOUT) const newMedia = await acquireMedia(REACQUIRE_ELEMENT_TIMEOUT)
if (newMedia !== media) { if (newMedia !== media) {
media.remove() media.remove()
@@ -332,9 +337,8 @@ async function main() {
}) })
} else if (content.kind === 'web') { } else if (content.kind === 'web') {
webFrame.insertCSS(NO_SCROLL_STYLE, { cssOrigin: 'user' }) webFrame.insertCSS(NO_SCROLL_STYLE, { cssOrigin: 'user' })
}
ipcRenderer.send('view-loaded') ipcRenderer.send('view-loaded')
}
function updateOptions(options: ContentDisplayOptions) { function updateOptions(options: ContentDisplayOptions) {
if (rotationController) { if (rotationController) {

View File

@@ -62,7 +62,9 @@ function Overlay({
'displaying.running.video.blurred', 'displaying.running.video.blurred',
state, state,
) )
const isLoading = matchesState('displaying.loading', state) const isLoading =
matchesState('displaying.loading', state) ||
matchesState('displaying.running.playback.stalled', state)
const hasTitle = data && (data.label || data.source) const hasTitle = data && (data.label || data.source)
const position = data?.labelPosition ?? 'top-left' const position = data?.labelPosition ?? 'top-left'
return ( return (