fix: make progress bars work again

Part-of: <https://dev.funkwhale.audio/funkwhale/funkwhale/-/merge_requests/2346>
This commit is contained in:
Kasper Seweryn 2023-03-01 01:17:16 +01:00 committed by Georg krause
parent 665e001087
commit 502773b7b4
13 changed files with 37 additions and 56 deletions

View File

@ -38,7 +38,6 @@ module.exports = {
'@intlify/vue-i18n/valid-message-syntax': 'error', '@intlify/vue-i18n/valid-message-syntax': 'error',
'@intlify/vue-i18n/no-i18n-t-path-prop': 'error', '@intlify/vue-i18n/no-i18n-t-path-prop': 'error',
'@intlify/vue-i18n/no-missing-keys': 'error', '@intlify/vue-i18n/no-missing-keys': 'error',
'@intlify/vue-i18n/no-dynamic-keys': 'error',
'@intlify/vue-i18n/no-unused-keys': ['error', { '@intlify/vue-i18n/no-unused-keys': ['error', {
extensions: ['.ts', '.vue'], extensions: ['.ts', '.vue'],
enableFix: true enableFix: true

View File

@ -58,7 +58,7 @@
}, },
"devDependencies": { "devDependencies": {
"@intlify/eslint-plugin-vue-i18n": "2.0.0", "@intlify/eslint-plugin-vue-i18n": "2.0.0",
"@intlify/unplugin-vue-i18n": "^0.8.1", "@intlify/unplugin-vue-i18n": "^0.8.2",
"@types/diff": "5.0.2", "@types/diff": "5.0.2",
"@types/dompurify": "2.4.0", "@types/dompurify": "2.4.0",
"@types/howler": "2.2.7", "@types/howler": "2.2.7",
@ -72,7 +72,7 @@
"@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/eslint-plugin": "5.48.2",
"@vitejs/plugin-vue": "4.0.0", "@vitejs/plugin-vue": "4.0.0",
"@vitest/coverage-c8": "0.25.8", "@vitest/coverage-c8": "0.25.8",
"@vue/compiler-sfc": "3.2.45", "@vue/compiler-sfc": "3.2.47",
"@vue/eslint-config-standard": "8.0.1", "@vue/eslint-config-standard": "8.0.1",
"@vue/eslint-config-typescript": "11.0.2", "@vue/eslint-config-typescript": "11.0.2",
"@vue/test-utils": "2.2.7", "@vue/test-utils": "2.2.7",

View File

@ -79,15 +79,15 @@ export class HTMLSound implements Sound {
}) })
useEventListener(this.#audio, 'waiting', () => { useEventListener(this.#audio, 'waiting', () => {
console.log('>> AUDIO WAITING', this.__track?.title) console.log('>> AUDIO WAITING', this)
}) })
useEventListener(this.#audio, 'playing', () => { useEventListener(this.#audio, 'playing', () => {
console.log('>> AUDIO PLAYING', this.__track?.title) console.log('>> AUDIO PLAYING', this)
}) })
useEventListener(this.#audio, 'stalled', () => { useEventListener(this.#audio, 'stalled', () => {
console.log('>> AUDIO STALLED', this.__track?.title) console.log('>> AUDIO STALLED', this)
}) })
useEventListener(this.#audio, 'loadeddata', () => { useEventListener(this.#audio, 'loadeddata', () => {
@ -96,7 +96,7 @@ export class HTMLSound implements Sound {
}) })
useEventListener(this.#audio, 'error', (err) => { useEventListener(this.#audio, 'error', (err) => {
console.error('>> AUDIO ERRORED', err, this.__track?.title) console.error('>> AUDIO ERRORED', err, this)
this.isErrored.value = true this.isErrored.value = true
this.isLoaded.value = true this.isLoaded.value = true
}) })
@ -104,7 +104,7 @@ export class HTMLSound implements Sound {
async preload () { async preload () {
this.isErrored.value = false this.isErrored.value = false
console.log('CALLING PRELOAD ON', this.__track?.title) console.log('CALLING PRELOAD ON', this)
this.#audio.load() this.#audio.load()
} }

View File

@ -2,7 +2,7 @@
import type { QueueItemSource } from '~/types' import type { QueueItemSource } from '~/types'
import { whenever, watchDebounced, useCurrentElement, useScrollLock, useFullscreen, useIdle, refAutoReset, useStorage } from '@vueuse/core' import { whenever, watchDebounced, useCurrentElement, useScrollLock, useFullscreen, useIdle, refAutoReset, useStorage } from '@vueuse/core'
import { nextTick, ref, computed, watchEffect, watch, defineAsyncComponent } from 'vue' import { nextTick, ref, computed, watchEffect, defineAsyncComponent } from 'vue'
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap' import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
@ -27,7 +27,6 @@ const {
isPlaying, isPlaying,
currentTime, currentTime,
duration, duration,
progress,
bufferProgress, bufferProgress,
seekTo, seekTo,
loading: isLoadingAudio, loading: isLoadingAudio,
@ -108,13 +107,6 @@ const touchProgress = (event: MouseEvent) => {
seekTo(time) seekTo(time)
} }
const animated = ref(false)
watch(currentTrack, async track => {
animated.value = false
await nextTick()
animated.value = true
})
const play = async (index: number) => { const play = async (index: number) => {
isPlaying.value = true isPlaying.value = true
return playTrack(index) return playTrack(index)
@ -368,7 +360,7 @@ if (!isWebGLSupported) {
:style="{ 'transform': `translateX(${bufferProgress - 100}%)` }" :style="{ 'transform': `translateX(${bufferProgress - 100}%)` }"
/> />
<div <div
:class="['position bar', { animated }]" class="position bar"
:style="{ :style="{
animationDuration: duration + 's', animationDuration: duration + 's',
animationPlayState: isPlaying animationPlayState: isPlaying
@ -416,23 +408,21 @@ if (!isWebGLSupported) {
<h2 class="ui header"> <h2 class="ui header">
<div class="content"> <div class="content">
<button <button
v-t="'components.Queue.button.close'"
class="ui right floated basic button" class="ui right floated basic button"
@click="$store.commit('ui/queueFocused', null)" @click="$store.commit('ui/queueFocused', null)"
> />
{{ $t('components.Queue.button.close') }}
</button>
<button <button
v-t="'components.Queue.button.clear'"
class="ui right floated basic button danger" class="ui right floated basic button danger"
@click="clear" @click="clear"
> />
{{ $t('components.Queue.button.clear') }}
</button>
{{ labels.queue }} {{ labels.queue }}
<div class="sub header"> <div class="sub header">
<div> <div>
{{ $t('components.Queue.meta.queuePosition', {index: currentIndex +1, length: queue.length}) }} <span v-t="{ path: 'components.Queue.meta.queuePosition', args: { index: currentIndex + 1, length: queue.length } }" />
<span class="middle pipe symbol" /> <span class="middle pipe symbol" />
{{ $t('components.Queue.meta.end') }} <span v-t="'components.Queue.meta.end'" />
<span :title="labels.duration"> <span :title="labels.duration">
{{ endsIn }} {{ endsIn }}
</span> </span>

View File

@ -27,7 +27,6 @@ const {
seekTo, seekTo,
currentTime, currentTime,
duration, duration,
progress,
bufferProgress, bufferProgress,
loading: isLoadingAudio loading: isLoadingAudio
} = usePlayer() } = usePlayer()
@ -131,10 +130,9 @@ const hideArtist = () => {
> >
<h1 <h1
id="player-label" id="player-label"
v-t="'components.audio.Player.header.player'"
class="visually-hidden" class="visually-hidden"
> />
{{ $t('components.audio.Player.header.player') }}
</h1>
<div <div
class="ui inverted segment fixed-controls" class="ui inverted segment fixed-controls"
@click.prevent.stop="toggleMobilePlayer" @click.prevent.stop="toggleMobilePlayer"
@ -305,18 +303,14 @@ const hideArtist = () => {
@click.stop="toggleMobilePlayer" @click.stop="toggleMobilePlayer"
> >
<i class="stream icon" /> <i class="stream icon" />
<span> <span v-t="{ path: 'components.audio.Player.meta.position', args: { index: currentIndex + 1, length: queue.length } }" />
{{ $t('components.audio.Player.meta.position', { index: currentIndex + 1, length: queue.length }) }}
</span>
</button> </button>
<button <button
class="position circular control button desktop-and-below" class="position circular control button desktop-and-below"
@click.stop="switchTab" @click.stop="switchTab"
> >
<i class="stream icon" /> <i class="stream icon" />
<span> <span v-t="{ path: 'components.audio.Player.meta.position', args: { index: currentIndex + 1, length: queue.length } }" />
{{ $t('components.audio.Player.meta.position', { index: currentIndex + 1, length: queue.length }) }}
</span>
</button> </button>
<button <button

View File

@ -167,7 +167,13 @@ export const usePlayer = createGlobalState(() => {
}, 1000) }, 1000)
// Progress // Progress
const progress = ref(0) useRafFn(() => {
const sound = currentSound.value
document.documentElement.style.setProperty('--fw-track-progress', sound
? `${(sound.currentTime / sound.duration * 100).toFixed(Math.log(window.innerWidth))}%`
: '0'
)
})
// Loading // Loading
const loading = computed(() => { const loading = computed(() => {
@ -207,7 +213,6 @@ export const usePlayer = createGlobalState(() => {
seekBy, seekBy,
seekTo, seekTo,
bufferProgress, bufferProgress,
progress,
loading, loading,
errored errored
} }

View File

@ -1,6 +1,6 @@
import type { Track, Upload } from '~/types' import type { Track, Upload } from '~/types'
import { createGlobalState, useNow, useStorage, useTimeAgo, whenever } from '@vueuse/core' import { createGlobalState, useStorage, useTimeAgo, whenever } from '@vueuse/core'
import { computed, ref, shallowReactive, watchEffect } from 'vue' import { computed, ref, shallowReactive, watchEffect } from 'vue'
import { shuffle as shuffleArray, sum } from 'lodash-es' import { shuffle as shuffleArray, sum } from 'lodash-es'
import { useClamp } from '@vueuse/math' import { useClamp } from '@vueuse/math'

View File

@ -127,7 +127,6 @@ export const useTracks = createGlobalState(() => {
// Preload next track // Preload next track
const { start: preload, stop: abortPreload } = useTimeoutFn(async (track: QueueTrack) => { const { start: preload, stop: abortPreload } = useTimeoutFn(async (track: QueueTrack) => {
const sound = await createSound(track) const sound = await createSound(track)
sound.__track = track
await sound.preload() await sound.preload()
}, 100, { immediate: false }) }, 100, { immediate: false })

View File

@ -48,7 +48,7 @@
.ui.progress .bar { .ui.progress .bar {
transition: none; transition: none;
width: 100%; width: 100%;
transform: translateX(-100%); transform: translateX(calc(var(--fw-track-progress) - 100%));
transform-origin: top left; transform-origin: top left;
will-change: transform; will-change: transform;
position: absolute; position: absolute;

View File

@ -160,7 +160,7 @@
.ui.progress .bar { .ui.progress .bar {
transition: none; transition: none;
width: 100%; width: 100%;
transform: translateX(-100%); transform: translateX(calc(var(--fw-track-progress) - 100%));
transform-origin: top left; transform-origin: top left;
will-change: transform; will-change: transform;
} }
@ -171,18 +171,6 @@
.ui.progress:not(.indeterminate) .ui.progress:not(.indeterminate)
.bar.position:not(.buffer) { .bar.position:not(.buffer) {
background: var(--vibrant-color); background: var(--vibrant-color);
will-change: transform;
&.animated {
@keyframes progress {
0% { transform: translate3d(-100%, 0, 0) }
100% { transform: translate3d(0, 0, 0) }
}
animation-name: progress;
animation-timing-function: linear;
}
} }
.indicating.progress .bar { .indicating.progress .bar {

View File

@ -2,6 +2,11 @@
html { html {
scroll-behavior: smooth; scroll-behavior: smooth;
} }
:root {
--fw-track-progress: 0;
}
@media screen and (prefers-reduced-motion: reduce) { @media screen and (prefers-reduced-motion: reduce) {
html { html {
scroll-behavior: auto; scroll-behavior: auto;

View File

@ -6,6 +6,7 @@ import { resolve } from 'path'
import { visualizer } from 'rollup-plugin-visualizer' import { visualizer } from 'rollup-plugin-visualizer'
import manifest from './pwa-manifest.json' import manifest from './pwa-manifest.json'
import Vue from '@vitejs/plugin-vue'
const port = +(process.env.VUE_PORT ?? 8080) const port = +(process.env.VUE_PORT ?? 8080)

View File

@ -1331,7 +1331,7 @@
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.3.0-beta.17.tgz#1180dcb0b30741555fad0b62e4621802e8272ee5" resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.3.0-beta.17.tgz#1180dcb0b30741555fad0b62e4621802e8272ee5"
integrity sha512-mscf7RQsUTOil35jTij4KGW1RC9SWQjYScwLxP53Ns6g24iEd5HN7ksbt9O6FvTmlQuX77u+MXpBdfJsGqizLQ== integrity sha512-mscf7RQsUTOil35jTij4KGW1RC9SWQjYScwLxP53Ns6g24iEd5HN7ksbt9O6FvTmlQuX77u+MXpBdfJsGqizLQ==
"@intlify/unplugin-vue-i18n@^0.8.1": "@intlify/unplugin-vue-i18n@^0.8.2":
version "0.8.2" version "0.8.2"
resolved "https://registry.yarnpkg.com/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-0.8.2.tgz#4196cb5bee4243bb3a33af76ce9663f3e106809a" resolved "https://registry.yarnpkg.com/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-0.8.2.tgz#4196cb5bee4243bb3a33af76ce9663f3e106809a"
integrity sha512-cRnzPqSEZQOmTD+p4pwc3RTS9HxreLqfID0keoqZDZweCy/CGRMLLTNd15S4TUf1vSBhPF03DItEFDr1F+8MDA== integrity sha512-cRnzPqSEZQOmTD+p4pwc3RTS9HxreLqfID0keoqZDZweCy/CGRMLLTNd15S4TUf1vSBhPF03DItEFDr1F+8MDA==
@ -2226,7 +2226,7 @@
postcss "^8.1.10" postcss "^8.1.10"
source-map "^0.6.1" source-map "^0.6.1"
"@vue/compiler-sfc@^3.2.45": "@vue/compiler-sfc@3.2.47", "@vue/compiler-sfc@^3.2.45":
version "3.2.47" version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d" resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d"
integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ== integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==