From 6602be87d1bbdace15130354a68493e4ad11d9b6 Mon Sep 17 00:00:00 2001 From: Alexander Knott <156598583+alexykn@users.noreply.github.com> Date: Sat, 24 May 2025 23:43:20 +0200 Subject: [PATCH] refactor: move watchers logic to stores --- frontend/src/App.vue | 44 +++++++++++-------------- frontend/src/composables/usePlayback.js | 7 ++-- frontend/src/composables/useTTS.js | 18 +++++----- frontend/src/stores/fileUploadStore.js | 9 ++++- frontend/src/stores/ttsStore.js | 19 ++++++++++- frontend/src/utils/generalHelpers.js | 16 ++++++--- 6 files changed, 69 insertions(+), 44 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 6ec2cbe..9744691 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -153,12 +153,13 @@ const showTabSwitchDialog = ref(false) const pendingTabSwitch = ref(null) // Add this watch effect after the state declarations -watch(text, (newValue) => { - // If text is edited and differs from original file content, clear the file association - if (currentFileId.value && newValue !== originalFileContent.value) { - currentFileId.value = null - } -}, { deep: true }) +watch( + text, + (newValue) => { + fileUploadStore.clearCurrentFileIfTextEdited(newValue) + }, + { deep: true } +) // --- PROFILE MANAGEMENT FUNCTIONS --- async function onProfileSelect(profileId) { @@ -169,7 +170,9 @@ async function onProfileSelect(profileId) { voice.value = val // Pipeline will be automatically updated via the watch in SpeakerSelection }, - setVolume: (val) => { volume.value = val }, + setVolume: (val) => { + ttsStore.setVolumeAndApply(val, setVolume) + }, setFiles: (files) => { setFiles(files) } }) } catch (error) { @@ -184,7 +187,9 @@ async function onProfileCreate(data) { data.volume / 100, { setVoice: (val) => { voice.value = val }, - setVolume: (val) => { volume.value = val }, + setVolume: (val) => { + ttsStore.setVolumeAndApply(val, setVolume) + }, setFiles: (files) => { setFiles(files) } } ) @@ -248,15 +253,6 @@ function handleSeek(event) { if (!isNaN(pos)) { seekToPosition(pos) } } -watch(volume, (newVal) => { - setVolume(newVal / 100) -}) -watch(unifiedBuffer, (newBuffer) => { - if (newBuffer) { - setTotalDuration(newBuffer.duration) - ttsStore.setUnifiedBuffer(newBuffer) - } -}) onMounted(() => { const slider = mainContent.value?.audioControls?.volumeSlider @@ -272,13 +268,13 @@ onMounted(async () => { }) const keydownHandler = event => { - globalHandleKeydown(event, { - currentSource, - togglePlayback, - volume, - setVolume, - isDownloadComplete, - seekRelative + globalHandleKeydown(event, { + currentSource, + togglePlayback, + volume, + applyVolume: (val) => ttsStore.setVolumeAndApply(val, setVolume), + isDownloadComplete, + seekRelative }); } onMounted(() => { diff --git a/frontend/src/composables/usePlayback.js b/frontend/src/composables/usePlayback.js index d18d217..c1c6a54 100644 --- a/frontend/src/composables/usePlayback.js +++ b/frontend/src/composables/usePlayback.js @@ -5,7 +5,7 @@ export function usePlayback(audioContext, gainNode) { const ttsStore = useTTSStore() const { volume, - setVolume: updateVolume, + setVolumeAndApply, isPlaying, currentSource, playbackProgress, @@ -115,9 +115,8 @@ export function usePlayback(audioContext, gainNode) { } function handleVolumeChange(event, setVolume) { - const newVol = parseFloat(event.target.value) / 100 - updateVolume(parseInt(event.target.value)) - setVolume(newVol) + const newVol = parseInt(event.target.value) + setVolumeAndApply(newVol, setVolume) event.target.style.setProperty('--volume-percentage', `${volume.value}%`) } diff --git a/frontend/src/composables/useTTS.js b/frontend/src/composables/useTTS.js index c6660b7..6e0e37a 100644 --- a/frontend/src/composables/useTTS.js +++ b/frontend/src/composables/useTTS.js @@ -21,7 +21,7 @@ export function useTTS() { currentTime, isDownloadComplete, downloadProgress, - setUnifiedBuffer, + updateUnifiedBuffer, setIsPlaying, setCurrentSource, setPlaybackProgress, @@ -84,7 +84,7 @@ export function useTTS() { setIsDownloadComplete(false) setDownloadProgress(0) audioQueue.length = 0 - setUnifiedBuffer(null) + updateUnifiedBuffer(null, setTotalDuration) // make sure we start in streaming mode for new generations: streamingMode = true @@ -114,8 +114,7 @@ export function useTTS() { } if (totalChunks === 1) { - setUnifiedBuffer(firstChunk.buffer) - setTotalDuration(unifiedBuffer.value.duration) + updateUnifiedBuffer(firstChunk.buffer, setTotalDuration) setIsDownloadComplete(true) } else { fetchNextChunks(text, voice, isGenerating, unifiedBuffer, audioQueue, isDownloadComplete) @@ -240,7 +239,7 @@ export function useTTS() { setDownloadProgress(0) audioQueue.length = 0 chunkCache.clear() - setUnifiedBuffer(null) + updateUnifiedBuffer(null, setTotalDuration) // For multi-speaker we immediately get a full WAV; so switch to unifiedBuffer mode: streamingMode = false @@ -265,9 +264,10 @@ export function useTTS() { const sessionId = multiResponse.sessionId const arrayBuffer = multiResponse.arrayBuffer - setUnifiedBuffer(await audioContext.value.decodeAudioData(arrayBuffer)) - - setTotalDuration(unifiedBuffer.value.duration) + updateUnifiedBuffer( + await audioContext.value.decodeAudioData(arrayBuffer), + setTotalDuration + ) setIsDownloadComplete(true) currentSource.value = audioContext.value.createBufferSource() @@ -347,7 +347,7 @@ export function useTTS() { resetChunks() audioQueue.length = 0 currentChunkIndex.value = 0 - setUnifiedBuffer(null) + updateUnifiedBuffer(null, setTotalDuration) setDownloadProgress(0) setPlaybackProgress(0) setIsDownloadComplete(false) diff --git a/frontend/src/stores/fileUploadStore.js b/frontend/src/stores/fileUploadStore.js index e029e7b..b69cf81 100644 --- a/frontend/src/stores/fileUploadStore.js +++ b/frontend/src/stores/fileUploadStore.js @@ -184,6 +184,12 @@ export const useFileUploadStore = defineStore('fileUpload', () => { } } + function clearCurrentFileIfTextEdited(newText) { + if (currentFileId.value && newText !== originalFileContent.value) { + currentFileId.value = null + } + } + return { uploadedFiles, progressMessage, @@ -204,6 +210,7 @@ export const useFileUploadStore = defineStore('fileUpload', () => { processFile, handleFileSelect, handleFileDrop, - handleFileClick + handleFileClick, + clearCurrentFileIfTextEdited } }) diff --git a/frontend/src/stores/ttsStore.js b/frontend/src/stores/ttsStore.js index 53ebd22..b5af9df 100644 --- a/frontend/src/stores/ttsStore.js +++ b/frontend/src/stores/ttsStore.js @@ -57,6 +57,21 @@ export const useTTSStore = defineStore('tts', () => { downloadProgress.value = val } + function setVolumeAndApply(val, applyFn) { + volume.value = val + if (typeof applyFn === 'function') { + applyFn(val / 100) + } + } + + function updateUnifiedBuffer(buffer, setDuration) { + setUnifiedBuffer(buffer) + if (typeof setDuration === 'function') { + const duration = buffer ? buffer.duration : 0 + setDuration(duration) + } + } + return { volume, isGenerating, @@ -76,6 +91,8 @@ export const useTTSStore = defineStore('tts', () => { setPlaybackProgress, setCurrentTime, setIsDownloadComplete, - setDownloadProgress + setDownloadProgress, + setVolumeAndApply, + updateUnifiedBuffer } }) diff --git a/frontend/src/utils/generalHelpers.js b/frontend/src/utils/generalHelpers.js index 88b20ea..16786a6 100644 --- a/frontend/src/utils/generalHelpers.js +++ b/frontend/src/utils/generalHelpers.js @@ -52,7 +52,7 @@ export function cancelTabSwitch({ pendingTabSwitch, showTabSwitchDialog }) { // --- New keydown handler helper function --- -export function handleKeydown(event, { currentSource, togglePlayback, volume, setVolume, seekRelative }) { +export function handleKeydown(event, { currentSource, togglePlayback, volume, applyVolume, seekRelative }) { if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') return; switch (event.code) { @@ -65,14 +65,20 @@ export function handleKeydown(event, { currentSource, togglePlayback, volume, se case 'ArrowUp': event.preventDefault(); const newVolUp = Math.min(100, volume.value + 5); - volume.value = newVolUp; - setVolume(newVolUp / 100); + if (applyVolume) { + applyVolume(newVolUp); + } else { + volume.value = newVolUp; + } break; case 'ArrowDown': event.preventDefault(); const newVolDown = Math.max(0, volume.value - 5); - volume.value = newVolDown; - setVolume(newVolDown / 100); + if (applyVolume) { + applyVolume(newVolDown); + } else { + volume.value = newVolDown; + } break; case 'ArrowLeft': event.preventDefault();