From 4c23643b5e1b8d3a722d14ce60f3cf075d13e13e Mon Sep 17 00:00:00 2001 From: DC Date: Mon, 28 Mar 2016 18:49:15 -0700 Subject: [PATCH] Show spinner when audio/video is stalled Fixes #243 --- renderer/index.css | 13 ++++++++++--- renderer/index.js | 9 +++++++++ renderer/state.js | 2 ++ renderer/views/player.js | 34 +++++++++++++++++++++++++++++++--- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/renderer/index.css b/renderer/index.css index 814b74bd..67b7ea28 100644 --- a/renderer/index.css +++ b/renderer/index.css @@ -436,7 +436,8 @@ input { padding-top: 8px; } -.torrent.requested .play { +.torrent.requested .play, +.loading-spinner { border-top: 6px solid rgba(255, 255, 255, 0.2); border-right: 6px solid rgba(255, 255, 255, 0.2); border-bottom: 6px solid rgba(255, 255, 255, 0.2); @@ -708,10 +709,10 @@ body.drag .torrent-placeholder span { } /* - * AUDIO DETAILS + * MEDIA OVERLAY / AUDIO DETAILS */ -.audio-metadata { +.media-overlay { width: 500px; max-width: 100%; white-space: nowrap; @@ -723,6 +724,12 @@ body.drag .torrent-placeholder span { line-height: 2; } +.media-stalled .loading-spinner { + width: 40px; + height: 40px; + margin: 0 auto; +} + .audio-metadata .audio-title { font-size: 32px; } diff --git a/renderer/index.js b/renderer/index.js index 4f11476e..5b2f9445 100644 --- a/renderer/index.js +++ b/renderer/index.js @@ -284,6 +284,15 @@ function dispatch (action, ...args) { state.playing.isPaused = true ipcRenderer.send('unblockPowerSave') } + if (action === 'mediaStalled') { + state.playing.isStalled = true + update() + } + if (action === 'mediaTimeUpdate') { + state.playing.lastTimeUpdate = new Date().getTime() + state.playing.isStalled = false + update() + } if (action === 'toggleFullScreen') { ipcRenderer.send('toggleFullScreen', args[0] /* optional bool */) } diff --git a/renderer/state.js b/renderer/state.js index 7d731b1c..8d642424 100644 --- a/renderer/state.js +++ b/renderer/state.js @@ -28,6 +28,8 @@ module.exports = { currentTime: 0, /* seconds */ duration: 1, /* seconds */ isPaused: true, + isStalled: false, + lastTimeUpdate: 0, /* Unix time in ms */ mouseStationarySince: 0 /* Unix time in ms */ }, audioInfo: null, /* set whenever an audio file is playing */ diff --git a/renderer/views/player.js b/renderer/views/player.js index 4991bf91..285b9538 100644 --- a/renderer/views/player.js +++ b/renderer/views/player.js @@ -40,7 +40,7 @@ function renderMedia (state) { mediaElement.currentTime = state.playing.jumpToTime state.playing.jumpToTime = null } - // set volume + // Set volume if (state.playing.setVolume !== null && isFinite(state.playing.setVolume)) { mediaElement.volume = state.playing.setVolume state.playing.setVolume = null @@ -60,6 +60,8 @@ function renderMedia (state) { onended=${onEnded} onplay=${dispatcher('mediaPlaying')} onpause=${dispatcher('mediaPaused')} + onstalling=${dispatcher('mediaStalled')} + ontimeupdate=${dispatcher('mediaTimeUpdate')} autoplay> ` @@ -78,7 +80,7 @@ function renderMedia (state) { style=${style} onmousemove=${dispatcher('mediaMouseMoved')}> ${mediaTag} - ${renderAudioMetadata(state)} + ${renderOverlay(state)} ` @@ -99,6 +101,18 @@ function renderMedia (state) { } } +function renderOverlay (state) { + var audioMetadataElem = renderAudioMetadata(state) + var spinnerElem = renderLoadingSpinner(state) + + var elems = [] + if (audioMetadataElem) elems.push(audioMetadataElem) + if (spinnerElem) elems.push(spinnerElem) + if (elems.length === 0) return + + return hx`
${elems}
` +} + function renderAudioMetadata (state) { if (!state.playing.audioInfo) return var info = state.playing.audioInfo @@ -127,6 +141,20 @@ function renderAudioMetadata (state) { return hx`
${elems}
` } +function renderLoadingSpinner (state) { + if (state.playing.isPaused) return + var isProbablyStalled = state.playing.isStalled || + (new Date().getTime() - state.playing.lastTimeUpdate > 2000) + console.log("STALLED? " + isProbablyStalled) + if (!isProbablyStalled) return + + return hx` +
+
 
+
+ ` +} + function renderCastScreen (state) { var isChromecast = state.playing.location.startsWith('chromecast') var isAirplay = state.playing.location.startsWith('airplay') @@ -282,7 +310,7 @@ function renderLoadingBar (state) { lastPartPresent = partPresent } - // Output an list of rectangles to show loading progress + // Output some bars to show which parts of the file are loaded return hx`
${parts.map(function (part) {