Custom audio player UI

For issue #122.
This commit is contained in:
N-Pex 2021-05-07 11:30:24 +02:00
parent 601e0d4a6c
commit b2a6a5d145
5 changed files with 241 additions and 11 deletions

View file

@ -185,10 +185,8 @@ $admin-fg: white;
background-color: $admin-bg;
}
.audio-bubble {
overflow: scroll;
display: inline-block;
width: fit-content;
max-width: 70%;
width: 70%;
height: 50px;
}
.bubble.image-bubble {
padding: 0px;
@ -252,10 +250,14 @@ $admin-fg: white;
max-width: 70%;
}
.audio-bubble {
overflow: scroll;
background-color: #e5e5e5;
border-radius: 10px 10px 0 10px;
padding: 8px;
display: inline-block;
width: fit-content;
position: relative;
max-width: 70%;
width: 70%;
height: 50px;
}
.video2-bubble {
background-color: #e5e5e5;
@ -384,6 +386,40 @@ $admin-fg: white;
user-select: text;
}
.audio-player {
width: 100%;
position: absolute;
.currentColor {
background-color: #000000 !important;
}
.v-icon {
color: black !important;
}
.from-admin & {
color: $admin-fg;
.currentColor {
background-color: #555555 !important;
}
.v-icon {
color: white !important;
}
}
.play-time {
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 13 * $chat-text-size;
}
.play-progress {
padding: 0px 10px;
.v-slider__thumb {
display: none;
}
&:hover .v-slider__thumb {
display: block;
}
}
}
.message-operations-strut {
position: relative;
height: 0px;

View file

@ -0,0 +1,185 @@
<template>
<div class="audio-player d-flex flex-row" style="align-items: center">
<audio ref="player" :src="src" @durationchange="updateDuration">
<slot></slot>
</audio>
<v-btn v-if="playing" @click.stop="pause" icon
><v-icon size="20">pause</v-icon></v-btn
>
<v-btn v-else @click.stop="play" icon
><v-icon size="20">play_arrow</v-icon></v-btn
>
<div class="play-time" style="flex: 1 1 80px">
{{ currentTime }} / {{ totalTime }}
</div>
<v-slider
color="currentColor"
track-color="#cccccc"
class="play-progress"
v-model="playheadPercent"
style="flex: 1 1 100%; height: 30px"
min="0"
max="100"
/>
</div>
</template>
<script>
import util from "../../plugins/utils";
export default {
props: {
src: {
type: String,
default: function () {
return null;
},
},
},
data() {
return {
player: null,
duration: 0,
playPercent: 0,
playTime: 0,
playing: false,
};
},
mounted() {
this.player = this.$refs.player;
this.player.addEventListener("timeupdate", this.updateProgressBar);
this.player.addEventListener("play", () => {
this.playing = true;
});
this.player.addEventListener("pause", () => {
this.playing = false;
});
this.player.addEventListener("ended", function () {
this.pause();
this.playing = false;
});
},
computed: {
currentTime() {
return util.formatDuration(this.playTime);
},
totalTime() {
return util.formatDuration(this.duration);
},
playheadPercent: {
get: function () {
return this.playPercent;
},
set: function (percent) {
if (this.player.src) {
this.playPercent = percent;
this.player.currentTime = (percent / 100) * this.player.duration;
}
},
},
},
methods: {
play() {
if (this.player.src) {
if (this.player.paused) {
this.player.play();
} else if (this.player.ended) {
// restart
this.player.currentTime = 0;
this.player.play();
}
}
},
pause() {
if (this.player.src) {
this.player.pause();
}
},
updateProgressBar() {
if (this.player.duration > 0) {
this.playPercent = Math.floor(
(100 / this.player.duration) * this.player.currentTime
);
} else {
this.playPercent = 0;
}
this.playTime = 1000 * this.player.currentTime;
},
updateDuration() {
this.duration = 1000 * this.player.duration;
},
},
};
</script>
<style lang="scss">
@import "@/assets/css/chat.scss";
</style>
function playPauseAudio() {
if (player.src) {
if (player.paused || player.ended) {
// Change the button to a pause button
changeButtonType(btnPlayPause, 'pause');
player.play();
}
else {
// Change the button to a play button
changeButtonType(btnPlayPause, 'play');
player.pause();
}
}
}
// Stop the current media from playing, and return it to the start position
function stopAudio() {
if (player.src) {
player.pause();
if (player.currentTime) player.currentTime = 0;
}
}
// Toggles the media player's mute and unmute status
function muteVolume() {
if (player.src) {
if (player.muted) {
// Change the button to a mute button
changeButtonType(btnMute, 'mute');
player.muted = false;
}
else {
// Change the button to an unmute button
changeButtonType(btnMute, 'unmute');
player.muted = true;
}
}
}
// Replays the media currently loaded in the player
function replayAudio() {
if (player.src) {
resetPlayer();
player.play();
}
}
// Updates a button's title, innerHTML and CSS class
function changeButtonType(btn, value) {
btn.title = value;
btn.innerHTML = value;
btn.className = value;
}
function resetPlayer() {
progressBar.value = 0;
//clear the current song
player.src = '';
// Move the media back to the start
player.currentTime = 0;
// Set the play/pause button to 'play'
changeButtonType(btnPlayPause, 'play');
}

View file

@ -1,7 +1,7 @@
<template>
<message-incoming v-bind="{...$props, ...$attrs}">
<div class="audio-bubble">
<audio controls :src="src">Audio file</audio>
<div class="bubble audio-bubble">
<audio-player :src="src">Audio file</audio-player>
</div>
</message-incoming>
</template>
@ -9,11 +9,12 @@
<script>
import attachmentMixin from "./attachmentMixin";
import MessageIncoming from './MessageIncoming.vue';
import AudioPlayer from './AudioPlayer.vue';
export default {
extends: MessageIncoming,
mixins: [attachmentMixin],
components: { MessageIncoming }
components: { MessageIncoming, AudioPlayer }
};
</script>

View file

@ -1,18 +1,19 @@
<template>
<message-outgoing v-bind="{ ...$props, ...$attrs }">
<div class="audio-bubble">
<audio controls :src="src">Audio file</audio>
<audio-player :src="src">Audio file</audio-player>
</div>
</message-outgoing>
</template>
<script>
import attachmentMixin from "./attachmentMixin";
import AudioPlayer from './AudioPlayer.vue';
import MessageOutgoing from "./MessageOutgoing.vue";
export default {
extends: MessageOutgoing,
components: { MessageOutgoing },
components: { MessageOutgoing, AudioPlayer },
mixins: [attachmentMixin],
};
</script>

View file

@ -565,6 +565,13 @@ class Util {
return dayjs.duration(ms).format("HH:mm:ss");
}
formatDuration(ms) {
if (ms >= (60 * 60000)) {
return dayjs.duration(ms).format("H:mm:ss");
}
return dayjs.duration(ms).format("m:ss");
}
formatRecordStartTime(timestamp) {
var then = dayjs(timestamp);
return then.format('lll');