mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-24 15:25:23 -07:00
Cleanup UX
This commit is contained in:
parent
4c34c61ce5
commit
00823d8417
2 changed files with 70 additions and 19 deletions
|
@ -1,9 +1,12 @@
|
|||
<template>
|
||||
<span class="v-btn__content">
|
||||
<i v-if="!playing" aria-hidden="true" class="v-icon notranslate mdi mdi-play theme--dark" @click.stop="play"></i>
|
||||
<i v-if="playing" aria-hidden="true" class="v-icon notranslate mdi mdi-pause theme--dark" @click.stop="pause"></i>
|
||||
<i v-if="playing" aria-hidden="true" class="v-icon notranslate mdi mdi-pause theme--dark" @click.stop="resume"></i>
|
||||
</span>
|
||||
<div v-if="ttsSupported" class="v-btn__content">
|
||||
<i v-if="canPlay" aria-hidden="true" class="v-icon notranslate mdi mdi-play theme--dark" @click.stop="play"></i>
|
||||
<i v-if="canPause" aria-hidden="true" class="v-icon notranslate mdi mdi-pause theme--dark" @click.stop="pause"></i>
|
||||
<i v-if="canResume" aria-hidden="true" class="v-icon notranslate mdi mdi-play theme--dark" @click.stop="resume"></i>
|
||||
<i v-if="canStartAgain" aria-hidden="true" class="v-icon notranslate mdi mdi-restart theme--dark" @click.stop="play"></i>
|
||||
|
||||
<small @click.stop="pauseOrResume">{{ currentSentence }}</small>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -20,7 +23,9 @@ export default defineComponent({
|
|||
},
|
||||
setup() {
|
||||
onUnmounted(() => {
|
||||
speechSynthesis.stop();
|
||||
if (speechSynthesis) {
|
||||
speechSynthesis.cancel();
|
||||
}
|
||||
});
|
||||
},
|
||||
data() {
|
||||
|
@ -28,19 +33,57 @@ export default defineComponent({
|
|||
playing: false,
|
||||
played: false,
|
||||
paused: false,
|
||||
utterance: null,
|
||||
utterance: SpeechSynthesisUtterance,
|
||||
currentIndex: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
ttsSupported() {
|
||||
return !!speechSynthesis;
|
||||
},
|
||||
canPlay() {
|
||||
return !this.playing && !this.paused;
|
||||
},
|
||||
canPause() {
|
||||
return this.playing && !this.paused;
|
||||
},
|
||||
canResume() {
|
||||
return !this.playing && this.paused;
|
||||
},
|
||||
canStartAgain() {
|
||||
return this.playing || this.paused;
|
||||
},
|
||||
nextIndex() {
|
||||
// TODO: i18n stopwords in sync with the browser's implementation? Assumes . and ! are boundaries, may not be true for all languages.
|
||||
const match = this.step.text.slice(this.currentIndex).search(/[\.\!]/)
|
||||
if (match === -1) {
|
||||
return this.currentIndex;
|
||||
}
|
||||
return this.currentIndex + match;
|
||||
},
|
||||
currentSentence() {
|
||||
if (this.playing || this.paused) {
|
||||
return this.step.text.slice(this.currentIndex, this.nextIndex);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pauseOrResume() {
|
||||
if (this.paused) {
|
||||
this.resume();
|
||||
} else {
|
||||
this.pause();
|
||||
}
|
||||
},
|
||||
play() {
|
||||
const self = this;
|
||||
if (this.utterance && this.playing) {
|
||||
speechSynthesis.cancel();
|
||||
}
|
||||
|
||||
this.utterance = new SpeechSynthesisUtterance(this.step.text);
|
||||
this.utterance.onstart = (event) => {
|
||||
const utterance = new SpeechSynthesisUtterance(this.step.text);
|
||||
utterance.onstart = (event) => {
|
||||
self.playing = true;
|
||||
self.played = false;
|
||||
self.paused = false;
|
||||
|
@ -48,26 +91,26 @@ export default defineComponent({
|
|||
|
||||
console.debug("Now playing: " + this.step.text);
|
||||
};
|
||||
this.utterance.onend = () => {
|
||||
utterance.onend = () => {
|
||||
self.playing = false;
|
||||
self.played = true;
|
||||
self.paused = false;
|
||||
// self.$emit("playing", false);
|
||||
self.$emit("ttscompleted", true);
|
||||
|
||||
console.debug("Playback complete");
|
||||
};
|
||||
|
||||
this.utterance.onpause = () => {
|
||||
utterance.onpause = () => {
|
||||
self.playing = false;
|
||||
self.paused = true;
|
||||
};
|
||||
|
||||
this.utterance.onresume = () => {
|
||||
utterance.onresume = () => {
|
||||
self.playing = true;
|
||||
self.paused = false;
|
||||
};
|
||||
|
||||
this.utterance.onboundary = (event) => {
|
||||
utterance.onboundary = (event) => {
|
||||
// Update the start of the current sentence.
|
||||
if (event.name === "sentence") {
|
||||
self.currentIndex = event.charIndex;
|
||||
|
@ -78,13 +121,20 @@ export default defineComponent({
|
|||
// console.log("mark")
|
||||
// console.log(event)
|
||||
// };
|
||||
this.utterance.onerror = (event) => {
|
||||
console.error("Error in playback")
|
||||
console.debug(event)
|
||||
utterance.onerror = (event) => {
|
||||
if (event.error == "interrupted") {
|
||||
this.playing = false;
|
||||
this.played = false;
|
||||
this.paused = false;
|
||||
} else {
|
||||
console.error("Error in playback")
|
||||
console.debug(event);
|
||||
}
|
||||
};
|
||||
|
||||
speechSynthesis.speak(this.utterance);
|
||||
return true;
|
||||
speechSynthesis.speak(utterance);
|
||||
|
||||
this.utterance = utterance;
|
||||
},
|
||||
pause() {
|
||||
speechSynthesis.pause();
|
||||
|
|
|
@ -122,6 +122,7 @@
|
|||
:ripple="false"
|
||||
@click="toggleDisabled(index)"
|
||||
>
|
||||
<!-- TODO: Should a ttscompleted event mark the step 'done'? Or auto scroll? -->
|
||||
<v-card-title :class="{ 'pb-0': !isChecked(index) }">
|
||||
<v-text-field
|
||||
v-if="isEditForm"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue