From a6d010958d9d82410f34c893d969b911f4a8e78e Mon Sep 17 00:00:00 2001 From: shvl Date: Sat, 20 Apr 2024 14:52:17 +0200 Subject: [PATCH 1/3] fix #213. Added throttling for audio events to reduce UI updates. Added logic to disable the animation when the loading overlay is fading out. --- hugo/layouts/partials/player.html | 2 +- hugo/src/js/controllers/player_controller.js | 27 ++++++++++++++----- .../podcast_progress_controller.js | 8 +++--- hugo/src/scss/_player.scss | 4 +++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/hugo/layouts/partials/player.html b/hugo/layouts/partials/player.html index 631e42aa..507273ec 100644 --- a/hugo/layouts/partials/player.html +++ b/hugo/layouts/partials/player.html @@ -6,7 +6,7 @@ data-turbolinks-permanent >
-
+
diff --git a/hugo/src/js/controllers/player_controller.js b/hugo/src/js/controllers/player_controller.js index dfc76633..bceda2cc 100644 --- a/hugo/src/js/controllers/player_controller.js +++ b/hugo/src/js/controllers/player_controller.js @@ -1,5 +1,4 @@ -import debounce from 'lodash/debounce'; -import capitalize from 'lodash/capitalize'; +import { debounce, capitalize, throttle } from 'lodash'; import { Events } from '../events'; import Controller from '../base_controller'; @@ -28,6 +27,7 @@ export default class extends Controller { 'mute', 'unmute', 'rate', + 'container', ]; static getState() { @@ -74,15 +74,18 @@ export default class extends Controller { // https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events addEventListeners() { - ['timeupdate', 'durationchange', 'play', 'pause', 'ended'].forEach((event) => { + ['durationchange', 'play', 'pause', 'ended'].forEach((event) => { const handlerName = `on${capitalize(event)}`; if (this[handlerName]) this.audioTarget.addEventListener(event, this[handlerName].bind(this)); }); - const updateLoadingState = debounce( - (isLoading) => this.element.classList.toggle('player-loading', isLoading), - 500 - ); + this.audioTarget.addEventListener('timeupdate', throttle(this.onTimeupdate.bind(this), 500)); + + const updateLoadingState = debounce((isLoading) => { + this.element.classList.toggle('player-loading', isLoading); + this.element.classList.remove('player-loading-completed'); + }, 500); + const eventsLoadingOn = ['seeking', 'waiting', 'loadstart']; const eventsLoadingOff = ['playing', 'seeked', 'canplay', 'loadeddata', 'error']; eventsLoadingOn.forEach((event) => @@ -136,6 +139,16 @@ export default class extends Controller { }) ); }); + + this.containerTarget.addEventListener('transitionend', (e) => { + if (e.pseudoElement !== '::after' || e.propertyName !== 'opacity') { + return; + } + const style = window.getComputedStyle(e.target, ':after'); + if (style.opacity === '0') { + this.element.classList.add('player-loading-completed'); + } + }); } playPodcast(detail) { diff --git a/hugo/src/js/controllers/podcast_progress_controller.js b/hugo/src/js/controllers/podcast_progress_controller.js index a078cb25..8ec1d1d7 100644 --- a/hugo/src/js/controllers/podcast_progress_controller.js +++ b/hugo/src/js/controllers/podcast_progress_controller.js @@ -1,3 +1,4 @@ +import { throttle } from 'lodash'; import Controller from '../base_controller'; import { composeTime, getLocalStorage } from '../utils'; @@ -6,9 +7,10 @@ export default class extends Controller { initialize() { super.initialize(); - this.subscribe(`playing-progress-${this.numberTarget.innerText}`, (podcast) => { - this.renderProgress(podcast); - }); + this.subscribe( + `playing-progress-${this.numberTarget.innerText}`, + throttle(this.renderProgress.bind(this), 1000) + ); } connect() { diff --git a/hugo/src/scss/_player.scss b/hugo/src/scss/_player.scss index aecd824d..43fa18f2 100644 --- a/hugo/src/scss/_player.scss +++ b/hugo/src/scss/_player.scss @@ -36,6 +36,10 @@ $podcast-player-cover-margin: 0.5rem; opacity: 1; transition-delay: 200ms; } + + .player-loading-completed & { + animation: none; + } } } .podcast-player { From bb29cc56606dc6303a7ff23ecde3fac98eda1c6d Mon Sep 17 00:00:00 2001 From: shvl Date: Sat, 20 Apr 2024 17:19:53 +0200 Subject: [PATCH 2/3] 213 Added transform to avoid full-page repaint. Added logic to reduce change width. --- hugo/src/js/controllers/podcast_progress_controller.js | 9 +++++++-- hugo/src/scss/main.scss | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hugo/src/js/controllers/podcast_progress_controller.js b/hugo/src/js/controllers/podcast_progress_controller.js index 8ec1d1d7..f2ceea5c 100644 --- a/hugo/src/js/controllers/podcast_progress_controller.js +++ b/hugo/src/js/controllers/podcast_progress_controller.js @@ -26,11 +26,16 @@ export default class extends Controller { } this.data.set('init', '1'); + this.lastPercentage = 0; } renderProgress(podcast) { this.progressTarget.style.display = 'block'; - this.durationTarget.innerText = composeTime(podcast.duration); - this.barTarget.style.width = `${(podcast.currentTime / podcast.duration) * 100}%`; + this.durationTarget.innerText = composeTime(podcast.currentTime); + const percentage = (podcast.currentTime / podcast.duration) * 100; + if (Math.abs(percentage - this.lastPercentage) > 0.2) { + this.barTarget.style.width = `${percentage}%`; + this.lastPercentage = percentage; + } } } diff --git a/hugo/src/scss/main.scss b/hugo/src/scss/main.scss index 2fabb376..422be47e 100644 --- a/hugo/src/scss/main.scss +++ b/hugo/src/scss/main.scss @@ -840,6 +840,7 @@ $ripple-scale-out: 3.4; [data-target='online.time'] { cursor: default; user-select: none; + transform: translateZ(0); } .podcast-progress { position: absolute; @@ -850,6 +851,7 @@ $ripple-scale-out: 3.4; background-color: $gray-300; z-index: 3; pointer-events: none; + transform: translateZ(0); } .podcast-progress-bar { position: absolute; From 71bbc747f4c665699810a2316e7cdce49fc8c6c5 Mon Sep 17 00:00:00 2001 From: Konstantin L Date: Sun, 28 Apr 2024 00:41:48 +0200 Subject: [PATCH 3/3] fixup --- hugo/src/js/controllers/player_controller.js | 62 +++++++++---------- .../podcast_progress_controller.js | 7 ++- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/hugo/src/js/controllers/player_controller.js b/hugo/src/js/controllers/player_controller.js index bceda2cc..c669b302 100644 --- a/hugo/src/js/controllers/player_controller.js +++ b/hugo/src/js/controllers/player_controller.js @@ -95,37 +95,37 @@ export default class extends Controller { this.audioTarget.addEventListener(event, updateLoadingState.bind(this, false)) ); - const debugEvents = [ - 'abort', - 'canplay', - 'canplaythrough', - 'durationchange', - 'emptied', - 'encrypted', - 'ended', - 'error', - 'interruptbegin', - 'interruptend', - 'loadeddata', - 'loadedmetadata', - 'loadstart', - 'mozaudioavailable', - 'pause', - 'play', - 'playing', - 'progress', - 'ratechange', - 'seeked', - 'seeking', - 'stalled', - 'suspend', - 'timeupdate', - 'volumechange', - 'waiting', - ]; - debugEvents.forEach((event) => - this.audioTarget.addEventListener(event, (e) => this.debug('audio event', event, e)) - ); + // const debugEvents = [ + // 'abort', + // 'canplay', + // 'canplaythrough', + // 'durationchange', + // 'emptied', + // 'encrypted', + // 'ended', + // 'error', + // 'interruptbegin', + // 'interruptend', + // 'loadeddata', + // 'loadedmetadata', + // 'loadstart', + // 'mozaudioavailable', + // 'pause', + // 'play', + // 'playing', + // 'progress', + // 'ratechange', + // 'seeked', + // 'seeking', + // 'stalled', + // 'suspend', + // 'timeupdate', + // 'volumechange', + // 'waiting', + // ]; + // debugEvents.forEach((event) => + // this.audioTarget.addEventListener(event, (e) => this.debug('audio event', event, e)) + // ); window.addEventListener('beforeunload', () => { const isPlaying = this.constructor.state.src && !this.constructor.state.paused; diff --git a/hugo/src/js/controllers/podcast_progress_controller.js b/hugo/src/js/controllers/podcast_progress_controller.js index f2ceea5c..1c05189c 100644 --- a/hugo/src/js/controllers/podcast_progress_controller.js +++ b/hugo/src/js/controllers/podcast_progress_controller.js @@ -1,10 +1,12 @@ import { throttle } from 'lodash'; import Controller from '../base_controller'; -import { composeTime, getLocalStorage } from '../utils'; +import { getLocalStorage } from '../utils'; export default class extends Controller { static targets = ['bar', 'number', 'duration', 'progress']; + lastPercentage = 0; + initialize() { super.initialize(); this.subscribe( @@ -26,12 +28,11 @@ export default class extends Controller { } this.data.set('init', '1'); - this.lastPercentage = 0; } renderProgress(podcast) { this.progressTarget.style.display = 'block'; - this.durationTarget.innerText = composeTime(podcast.currentTime); + // this.durationTarget.innerText = composeTime(podcast.duration); const percentage = (podcast.currentTime / podcast.duration) * 100; if (Math.abs(percentage - this.lastPercentage) > 0.2) { this.barTarget.style.width = `${percentage}%`;