diff --git a/src/components/AudioTrack/AudioTrack.vue b/src/components/AudioTrack/AudioTrack.vue index 0ca07e007f..6e946a6679 100644 --- a/src/components/AudioTrack/AudioTrack.vue +++ b/src/components/AudioTrack/AudioTrack.vue @@ -26,12 +26,13 @@ @toggle="setPlayerState" />
@@ -120,7 +122,7 @@ export default { player: null, // HTMLAudioElement currentTime: 0, duration: 0, - isReady: false, + message: 'loading', isPlaying: false, }), computed: { @@ -135,6 +137,10 @@ export default { date.setSeconds(seconds) return date.toISOString().substr(11, 8).replace(/^00:/, '') }, + + isReady() { + return this.message === null + }, }, mounted() { this.player = this.$refs.audio @@ -172,11 +178,28 @@ export default { // HTMLAudioElement events setIsReady() { - this.isReady = true + this.message = null }, setIsPlaying(isPlaying) { this.isPlaying = isPlaying }, + handleError(event) { + const error = event.target.error + switch (error.code) { + case error.MEDIA_ERR_ABORTED: + this.message = 'err_aborted' + break + case error.MEDIA_ERR_NETWORK: + this.message = 'err_network' + break + case error.MEDIA_ERR_DECODE: + this.message = 'err_decode' + break + case error.MEDIA_ERR_SRC_NOT_SUPPORTED: + this.message = 'err_unsupported' + break + } + }, }, } diff --git a/src/components/AudioTrack/Waveform.vue b/src/components/AudioTrack/Waveform.vue index aba52a898e..656be152e1 100644 --- a/src/components/AudioTrack/Waveform.vue +++ b/src/components/AudioTrack/Waveform.vue @@ -71,12 +71,12 @@ - +
- {{ $t('waveform.loading') }} + {{ message }}
@@ -108,11 +108,11 @@ export default { validator: (val) => val.every((item) => item >= 0 && item <= 1), }, /** - * whether the audio metadata has been loaded and is ready to display + * the message to display instead of the waveform; This is useful when + * displaying a loading or error state. */ - isReady: { - type: Boolean, - default: false, + message: { + type: String, }, /** * the current play time of the audio track @@ -185,6 +185,10 @@ export default { observer.disconnect() }) + /* State */ + + const isReady = computed(() => !props.message) + /* Resampling */ const barWidth = 2 @@ -221,7 +225,7 @@ export default { /* Progress bar */ const currentFrac = computed(() => - props.isReady ? props.currentTime / props.duration : 0 + isReady.value ? props.currentTime / props.duration : 0 ) const progressBarWidth = computed(() => { const frac = isDragging.value ? seekFrac.value : currentFrac.value @@ -248,10 +252,10 @@ export default { * the seek jump length as a % of the track */ const seekDeltaFrac = computed(() => { - return props.isReady ? seekDelta / props.duration : 0 + return isReady.value ? seekDelta / props.duration : 0 }) const modSeekDeltaFrac = computed(() => - props.isReady ? modSeekDelta / props.duration : 0 + isReady.value ? modSeekDelta / props.duration : 0 ) const setSeekProgress = (event) => { seekFrac.value = getPositionFrac(event) @@ -307,6 +311,8 @@ export default { el, // template ref + isReady, + barWidth, normalizedPeaks, diff --git a/src/components/AudioTrack/meta/Waveform.stories.mdx b/src/components/AudioTrack/meta/Waveform.stories.mdx index 65ff03644c..54dc8e7193 100644 --- a/src/components/AudioTrack/meta/Waveform.stories.mdx +++ b/src/components/AudioTrack/meta/Waveform.stories.mdx @@ -45,7 +45,6 @@ Here 9 points are upsampled to as many as required to fill the viewport. name="Upsampling" args={{ peaks: [0.5, 1, 0.5, 0, 0.5, 1, 0.5, 0, 0.5], // triangular wave with 9 points - isReady: true, currentTime: 2, duration: 10, showDuration: true, @@ -67,7 +66,6 @@ Here 1000 points are downsampled to as many as required to fill the viewport. { length: 1000 }, (_, k) => 0.5 * Math.sin((k * 2 * Math.PI) / 500) + 0.5 ), // sine wave with 1000 points - isReady: true, currentTime: 2, duration: 10, showDuration: true, @@ -87,16 +85,16 @@ The waveform always takes the height and width of its container. Thus the `barWidth` and `barGap` will be maintained even in the case of horizontal scaling. -## Loading state +## Message state -The waveform bars are set to zero height when loading. They will animate up to -their actual height when the `isReady` prop is set to `true`. +The waveform bars are set to zero height when the `message` prop is passed. They +will animate up to their actual height when the prop is unset. {Template.bind({})} diff --git a/src/locales/en.json b/src/locales/en.json index 7936ca8c2f..c275e9b974 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -571,12 +571,18 @@ }, "waveform": { "label": "Audio seek bar", - "loading": "Loading...", "current-time": "{time} seconds" }, "audio-track": { "title": "{title} by {creator}", - "aria-label": "Audio Player" + "aria-label": "Audio Player", + "messages": { + "err_aborted": "You aborted playback.", + "err_network": "A network error occurred.", + "err_decode": "Could not decode audio.", + "err_unsupported": "This audio format is not supported by your browser.", + "loading": "Loading..." + } }, "play-pause": { "play": "Play",