source: main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/App.vue@ 35442

Last change on this file since 35442 was 35442, checked in by cstephen, 3 years ago

Improve color theming

File size: 5.3 KB
Line 
1<template>
2 <div class="app-bar theme-primary-l1">
3 <div class="app-bar-content">
4 <span class="heading1">{{ translations.get("Title") }}</span>
5
6 <a class="btn-primary theme-accent" href="https://koreromaori.io" target="_blank">
7 <span class="material-icons mdi-m">open_in_new</span>
8 <u>koreromaori.io</u>
9 </a>
10
11 <toggle-button class="theme-accent" v-model="showInfo" :reverseState="true">
12 <span class="material-icons mdi-l">info</span>
13 </toggle-button>
14 </div>
15
16 <div v-if="showInfo" class="paper">
17 A tool to transcribe audio recordings of spoken Māori. Basic support for editing the transcriptions is provided,
18 and they can be downloaded in multiple formats.
19 <br />
20 The actual transcriptions are produced with gratitude by using <a href="https://koreromaori.io">koreromaori.io's</a> service.
21 </div>
22 </div>
23
24 <div class="paper content">
25 <AudioUpload />
26 </div>
27
28 <ul id="transcription-list" class="list-view content">
29 <transition-group name="transcription-list">
30 <li class="list-item transcription-list-item" v-for="[id, transcription] in transcriptions" :key="id">
31 <TranscriptionItem :transcription="transcription" />
32 </li>
33 </transition-group>
34 </ul>
35</template>
36
37<style lang="scss">
38#transcription-list {
39 margin-bottom: 1em;
40}
41
42.app-bar {
43 display: flex;
44 flex-direction: column;
45 gap: 1em;
46
47 background-color: var(--bg-color);
48 color: var(--fg-color);
49 box-shadow: 0px 0px 4px 3px #6d6d6d;
50
51 padding: 1em;
52 margin-bottom: 1em;
53}
54
55.app-bar-content {
56 display: flex;
57 align-items: center;
58 gap: 1em;
59
60 width: 100%;
61
62 & :first-child {
63 flex-grow: 1;
64 }
65}
66
67.content {
68 margin: 1em;
69}
70
71.transcription-list-item {
72 transition: all 0.8s ease;
73 margin-bottom: 1em;
74
75 &:last-child {
76 margin-bottom: 0;
77 }
78}
79
80.transcription-list-leave-to {
81 opacity: 0;
82 transform: translateX(30%);
83}
84
85.transcription-list-leave-active {
86 position: absolute;
87}
88</style>
89
90<script>
91import { mapState } from "vuex";
92import AudioUpload from "./components/AudioUpload.vue"
93import ToggleButton from "./components/ToggleButton.vue";
94import TranscriptionItem from "./components/TranscriptionItem.vue"
95
96export default {
97 name: "App",
98 components: {
99 AudioUpload,
100 TranscriptionItem,
101 ToggleButton
102 },
103 data() {
104 return {
105 /** @type {{id: String, url: String} | null} */
106 currentlyLoadedAudio: null,
107 player: new Audio(),
108 showInfo: false
109 }
110 },
111 computed: mapState({
112 translations: state => state.translations,
113 transcriptions: state => state.rawTranscriptions,
114 playbackState: state => state.playbackState,
115 shouldPlayAudio: state => state.playbackState.isPlaying
116 }),
117 watch: {
118 async playbackState(newValue) {
119 if (!newValue.isPlaying) {
120 return;
121 }
122
123 const transcription = this.transcriptions.get(newValue.id);
124 loadTranscriptionAudio(this.player, transcription, this.currentlyLoadedAudio);
125
126 let playbackTime = 0;
127 if (newValue.currentTime > 0) {
128 playbackTime = newValue.currentTime;
129 }
130
131 this.player.currentTime = playbackTime;
132 await this.player.play();
133
134 this.playbackState.length = this.player.duration;
135 }//,
136 // shouldPlayAudio(newValue) {
137 // if (newValue && this.$refs.audioPlayer.paused) {
138 // this.$refs.audioPlayer.play();
139 // }
140 // else if (!newValue && !this.$refs.audioPlayer.paused) {
141 // this.$refs.audioPlayer.pause();
142 // }
143 // }
144 },
145 mounted() {
146 pollAudioTime(this.player, this.$store);
147 }
148}
149
150// Adapted from https://davidwalsh.name/javascript-polling
151function pollAudioTime(audioElement, store) {
152 var lastTime = 0;
153 (function p() {
154 if (audioElement.currentTime !== lastTime) {
155 lastTime = audioElement.currentTime;
156 store.commit("setCurrentPlaybackTime", lastTime);
157 store.commit("setCurrentlyPlaying", true);
158 }
159 else {
160 store.commit("setCurrentlyPlaying", false);
161 }
162
163 setTimeout(p, 33); // Slightly more than 30hz
164 })();
165}
166
167/**
168 * Loads an audio file.
169 * @param {Audio} player The audio player.
170 * @param {TranscriptionViewModel} transcription The name of the requested audio file.
171 * @param {{id: String, url: String} | null} current The currently loaded audio.
172 * @returns {{id: String, url: String}} If a new audio file was loaded, a new audio tracking object, else the current one.
173 */
174function loadTranscriptionAudio(player, transcription, current) {
175 if (current == null || current.id !== transcription.id) {
176 // TODO: Need to profile on some larger tracks; this may not be worth it? Better to cache a URL object instead?
177 if (current !== null) {
178 URL.revokeObjectURL(current.url);
179 }
180
181 const urlObject = URL.createObjectURL(transcription.file);
182 player.src = urlObject;
183 player.load();
184
185 return { id: transcription.id, url: urlObject };
186 }
187
188 return current;
189}
190</script>
Note: See TracBrowser for help on using the repository browser.