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

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

Add app bar and basic information

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