feat: Implement single audio playback functionality across components (#12226)
## Description Introduces a global single-audio playback helper and hooks it into dashboard and widget entrypoints. Adds play/pause event handlers in the Audio chip to sync UI state. The helper enforces one audio playing at a time and auto-advances to the next adjacent audio on end. Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: iamsivin <iamsivin@gmail.com>
This commit is contained in:
@@ -1,8 +1,16 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, useTemplateRef, ref } from 'vue';
|
import {
|
||||||
|
computed,
|
||||||
|
onMounted,
|
||||||
|
useTemplateRef,
|
||||||
|
ref,
|
||||||
|
getCurrentInstance,
|
||||||
|
} from 'vue';
|
||||||
import Icon from 'next/icon/Icon.vue';
|
import Icon from 'next/icon/Icon.vue';
|
||||||
import { timeStampAppendedURL } from 'dashboard/helper/URLHelper';
|
import { timeStampAppendedURL } from 'dashboard/helper/URLHelper';
|
||||||
import { downloadFile } from '@chatwoot/utils';
|
import { downloadFile } from '@chatwoot/utils';
|
||||||
|
import { useEmitter } from 'dashboard/composables/emitter';
|
||||||
|
import { emitter } from 'shared/helpers/mitt';
|
||||||
|
|
||||||
const { attachment } = defineProps({
|
const { attachment } = defineProps({
|
||||||
attachment: {
|
attachment: {
|
||||||
@@ -27,6 +35,8 @@ const currentTime = ref(0);
|
|||||||
const duration = ref(0);
|
const duration = ref(0);
|
||||||
const playbackSpeed = ref(1);
|
const playbackSpeed = ref(1);
|
||||||
|
|
||||||
|
const { uid } = getCurrentInstance();
|
||||||
|
|
||||||
const onLoadedMetadata = () => {
|
const onLoadedMetadata = () => {
|
||||||
duration.value = audioPlayer.value?.duration;
|
duration.value = audioPlayer.value?.duration;
|
||||||
};
|
};
|
||||||
@@ -43,6 +53,18 @@ onMounted(() => {
|
|||||||
audioPlayer.value.playbackRate = playbackSpeed.value;
|
audioPlayer.value.playbackRate = playbackSpeed.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Listen for global audio play events and pause if it's not this audio
|
||||||
|
useEmitter('pause_playing_audio', currentPlayingId => {
|
||||||
|
if (currentPlayingId !== uid && isPlaying.value) {
|
||||||
|
try {
|
||||||
|
audioPlayer.value.pause();
|
||||||
|
} catch {
|
||||||
|
/* ignore pause errors */
|
||||||
|
}
|
||||||
|
isPlaying.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const formatTime = time => {
|
const formatTime = time => {
|
||||||
if (!time || Number.isNaN(time)) return '00:00';
|
if (!time || Number.isNaN(time)) return '00:00';
|
||||||
const minutes = Math.floor(time / 60);
|
const minutes = Math.floor(time / 60);
|
||||||
@@ -70,6 +92,8 @@ const playOrPause = () => {
|
|||||||
audioPlayer.value.pause();
|
audioPlayer.value.pause();
|
||||||
isPlaying.value = false;
|
isPlaying.value = false;
|
||||||
} else {
|
} else {
|
||||||
|
// Emit event to pause all other audio
|
||||||
|
emitter.emit('pause_playing_audio', uid);
|
||||||
audioPlayer.value.play();
|
audioPlayer.value.play();
|
||||||
isPlaying.value = true;
|
isPlaying.value = true;
|
||||||
}
|
}
|
||||||
@@ -101,6 +125,7 @@ const downloadAudio = async () => {
|
|||||||
ref="audioPlayer"
|
ref="audioPlayer"
|
||||||
controls
|
controls
|
||||||
class="hidden"
|
class="hidden"
|
||||||
|
playsinline
|
||||||
@loadedmetadata="onLoadedMetadata"
|
@loadedmetadata="onLoadedMetadata"
|
||||||
@timeupdate="onTimeUpdate"
|
@timeupdate="onTimeUpdate"
|
||||||
@ended="onEnd"
|
@ended="onEnd"
|
||||||
|
|||||||
Reference in New Issue
Block a user