Skip to content
This repository was archived by the owner on Nov 5, 2023. It is now read-only.

Commit 28db2c8

Browse files
committed
Add ability to sign in and save settings. Add terms of service page.
1 parent 09f0c49 commit 28db2c8

File tree

19 files changed

+1704
-400
lines changed

19 files changed

+1704
-400
lines changed

app/.env.sample

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,11 @@ DISABLE_SSL_REDIRECT=true
1818

1919
REDIS_URL=//localhost:6379
2020

21+
FIREBASE_API_KEY=
22+
FIREBASE_AUTH_DOMAIN=
23+
FIREBASE_DATABASE_URL=
24+
FIREBASE_PROJECT_ID=
25+
FIREBASE_STORAGE_BUCKET=
26+
FIREBASE_MESSAGING_SENDER_ID=
27+
2128
ADMIN_TOKEN=

app/assets/scss/app.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ $modal-content-box-shadow-xs: $modal-content-box-shadow-sm-up;
124124
@import '~bootstrap/scss/_breadcrumb.scss';
125125
@import '~bootstrap/scss/_pagination.scss';
126126
@import '~bootstrap/scss/_badge.scss';
127+
@import '~bootstrap/scss/_toasts.scss';
127128
//@import "~bootstrap/scss/_jumbotron.scss";
128129
@import '~bootstrap/scss/_alert.scss';
129130
@import '~bootstrap/scss/_progress.scss';

app/components/CastButton.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ export default {
228228
229229
// Restore settings and current transcript
230230
self.sendMessage({
231-
action: 'RESTORE_SETTINGS',
231+
action: 'RESTORE_SETTINGS_OBJECT',
232232
payload: {
233233
settings: self.$store.state.settings,
234234
},

app/components/Navbar.vue

Lines changed: 115 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,6 @@
8585
<span v-else>{{$t('navbar.captioner.stopCaptioning')}}</span>
8686
<kbd v-show="largerLayout" class="small ml-3">c</kbd>
8787
</div>
88-
89-
<!-- <b-popover
90-
id="captioningPreviewPopover"
91-
target="startCaptioningDropdown"
92-
placement="top"
93-
>
94-
{{transcriptExcerpt}}
95-
</b-popover>-->
9688
</b-btn>
9789
<b-btn
9890
v-show="experiments.includes('typingMode') && !typingModeOn"
@@ -110,10 +102,9 @@
110102
<b-popover
111103
target="navbar-settings-button"
112104
placement="top"
113-
:show.sync="showMenu"
105+
:show.sync="showSettingsMenu"
114106
triggers="click blur"
115107
boundary="viewport"
116-
title
117108
>
118109
<b-btn-group vertical class="d-flex">
119110
<b-btn
@@ -185,26 +176,109 @@
185176
{{$t('navbar.menu.settings')}}
186177
</b-btn>
187178
</b-popover>
179+
<b-tooltip target="navbar-settings-button" :title="$t('navbar.menu.menu')"></b-tooltip>
188180
<b-btn
189181
id="navbar-settings-button"
190-
@click="showMenu = !showMenu"
182+
@click="showSettingsMenu = !showSettingsMenu"
191183
v-b-tooltip.top
192184
:variant="captioningToggleButtonVariant"
193-
:title="$t('navbar.menu.menu')"
194185
>
195186
<fa icon="bars"/>
196187
</b-btn>
197188
</b-btn-group>
189+
<b-popover
190+
target="navbar-profile-button-logged-in"
191+
placement="top"
192+
:show.sync="showProfileMenu"
193+
triggers="click blur"
194+
boundary="viewport"
195+
title
196+
>
197+
<div style="min-width:300px">
198+
<img
199+
:src="$store.state.user.photoURL"
200+
v-if="$store.state.user.photoURL"
201+
class="rounded-circle float-left p-1 pr-2"
202+
style="max-width:50px"
203+
>
204+
<fa v-else icon="user-circle" class="rounded-circle float-left p-1 pr-2 text-muted"/>
205+
206+
<div class="pt-1" style="line-height:1.25rem">
207+
<span class="text-muted">
208+
Signed in
209+
<span v-if="$store.state.user.email || $store.state.user.displayName">as</span>
210+
</span>
211+
<div
212+
v-if="$store.state.user.email || $store.state.user.displayName"
213+
>{{$store.state.user.email || $store.state.user.displayName}}</div>
214+
</div>
215+
<div class="clearfix"></div>
216+
<hr>
217+
<b-btn variant="link" class="d-block" @click="signOut()">Sign out</b-btn>
218+
</div>
219+
</b-popover>
220+
221+
<!-- if logged in -->
222+
<b-tooltip target="navbar-profile-button-logged-in" title="Profile"></b-tooltip>
223+
<b-btn
224+
id="navbar-profile-button-logged-in"
225+
v-show="$store.state.user.signedIn"
226+
@click="showProfileMenu = !showProfileMenu"
227+
v-b-tooltip.top
228+
class="ml-2 text-white px-2 profile-button"
229+
style="position:relative"
230+
variant="link"
231+
>
232+
<transition name="fade">
233+
<img
234+
:src="$store.state.user.photoURL"
235+
v-if="$store.state.user.photoURL"
236+
class="rounded-circle"
237+
style="max-width: 30px;position: absolute;margin-left: -2px;margin-top: -2px;"
238+
>
239+
</transition>
240+
<fa icon="user-circle"/>
241+
</b-btn>
242+
243+
<!-- not logged in -->
244+
<b-tooltip target="navbar-profile-button-logged-out" title="Sign in or sign up"></b-tooltip>
245+
<b-btn
246+
id="navbar-profile-button-logged-out"
247+
v-show="!$store.state.user.signedIn && experiments.includes('signin')"
248+
v-b-tooltip.top
249+
class="ml-2 text-white px-2 profile-button"
250+
variant="link"
251+
:to="localePath('captioner-sign-in')"
252+
>
253+
<fa icon="user-circle"/>
254+
</b-btn>
198255
</div>
199256
</nav>
200257
</div>
201258
</template>
202259

203260
<style>
261+
.firebaseui-title {
262+
text-align: center !important;
263+
}
264+
</style>
265+
266+
267+
<style scoped>
204268
.button-only-disabled > .btn-primary:first-child {
205269
opacity: 0.6;
206270
cursor: default;
207271
}
272+
.profile-button {
273+
font-size: 1.5rem;
274+
line-height: 1.5rem;
275+
opacity: 0.7;
276+
}
277+
.profile-button:hover,
278+
.profile-button:active,
279+
.profile-button:focus {
280+
opacity: 1;
281+
}
208282
</style>
209283

210284

@@ -217,7 +291,8 @@ import saveToFile from '~/mixins/saveToFile';
217291
import dateFormat from '~/mixins/dateFormat';
218292
import bBtn from 'bootstrap-vue/es/components/button/button';
219293
import bBtnGroup from 'bootstrap-vue/es/components/button-group/button-group';
220-
import bTooltip from 'bootstrap-vue/es/directives/tooltip/tooltip';
294+
import bTooltipDirective from 'bootstrap-vue/es/directives/tooltip/tooltip';
295+
import bTooltipComponent from 'bootstrap-vue/es/components/tooltip/tooltip';
221296
import bPopover from 'bootstrap-vue/es/components/popover/popover';
222297
223298
export default {
@@ -229,14 +304,16 @@ export default {
229304
bBtn,
230305
bBtnGroup,
231306
bPopover,
307+
bTooltip: bTooltipComponent,
232308
},
233309
directives: {
234-
bTooltip,
310+
bTooltip: bTooltipDirective,
235311
},
236312
data: function() {
237313
return {
238314
vmixNotFullySetUpMessageDismissed: false,
239-
showMenu: false,
315+
showSettingsMenu: false,
316+
showProfileMenu: false,
240317
};
241318
},
242319
computed: {
@@ -299,22 +376,31 @@ export default {
299376
},
300377
},
301378
watch: {
302-
showMenu: function() {
303-
// Hide all tooltips
304-
this.$root.$emit('bv::hide::tooltip');
379+
showProfileMenu: function() {
380+
this.hideAllTooltips();
381+
},
382+
showSettingsMenu: function() {
383+
this.hideAllTooltips();
305384
},
306-
// transcriptExcerpt: function(transcriptExcerpt) {
307-
// if (this.$router.currentRoute.name.startsWith('captioner-settings')) {
308-
// if (transcriptExcerpt) {
309-
// this.$root.$emit('bv::show::popover', 'startCaptioningDropdown');
310-
// }
311-
// else {
312-
// this.$root.$emit('bv::hide::popover', 'startCaptioningDropdown');
313-
// }
314-
// }
315-
// },
316385
},
317386
methods: {
387+
hideAllTooltips: function() {
388+
this.$root.$emit('bv::hide::tooltip');
389+
},
390+
signOut: function() {
391+
this.showProfileMenu = false;
392+
setTimeout(() => {
393+
this.$firebase
394+
.auth()
395+
.signOut()
396+
.then(() => {
397+
// Success signing out
398+
// INIT_CHECK_AUTH_STATUS_WATCHER handles
399+
// updating the store and removing the user
400+
this.$store.commit('SHOW_TOAST', { toastName: 'signedOut' });
401+
});
402+
}, 350); // let popover fade out first to get around positioning issue on close
403+
},
318404
captioningToggleButtonClick: function() {
319405
if (this.captioningOn) {
320406
this.stopCaptioning();
@@ -324,6 +410,7 @@ export default {
324410
},
325411
startCaptioning: function() {
326412
this.$store.dispatch('captioner/startManual');
413+
this.$router.push('/captioner');
327414
},
328415
stopCaptioning: function() {
329416
this.$store.dispatch('captioner/stopManual');

app/components/Transcript.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<fa icon="chevron-down" class="backToLatestIcon mr-2"/>Back to Latest
4343
</b-btn>
4444
</transition>
45-
<font-stylesheet v-if="$store.state.settings.loaded" v-model="fontFamily"/>
45+
<font-stylesheet v-if="$store.state.settingsLoaded" v-model="fontFamily"/>
4646
</div>
4747
</template>
4848

app/mixins/ChromelessWindowManager.js

Lines changed: 67 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,73 @@
11
function commitToWindow(windowInstance, type, payload) {
2-
windowInstance.dispatchEvent(new CustomEvent('processVuexMutation', {detail: {type, payload}}));
2+
windowInstance.dispatchEvent(new CustomEvent('processVuexMutation', {
3+
detail: {
4+
type,
5+
payload
6+
}
7+
}));
38
}
9+
410
function actionToWindow(windowInstance, type, payload) {
5-
windowInstance.dispatchEvent(new CustomEvent('processVuexAction', {detail: {type, payload}}));
11+
windowInstance.dispatchEvent(new CustomEvent('processVuexAction', {
12+
detail: {
13+
type,
14+
payload
15+
}
16+
}));
617
}
718

819
export default {
9-
methods: {
10-
start(RemoteEventBus, {settings, transcriptInterim, transcriptFinal, transcriptTyped}, onClose) {
11-
let chromelessWindow = window.open('/receivers/chromeless', 'WebCaptionerChild', 'height=700,width=900,toolbar=0,location=0,menubar=0');
12-
13-
if (!chromelessWindow) {
14-
alert('Unable to open a new window.');
15-
return;
16-
}
17-
18-
RemoteEventBus.$on('sendMutationToReceivers', ({mutation, payload}) => {
19-
commitToWindow(chromelessWindow, mutation, payload);
20-
});
21-
22-
function restoreSettings() {
23-
actionToWindow(chromelessWindow, 'RESTORE_SETTINGS', { settings });
24-
commitToWindow(chromelessWindow, 'captioner/SET_TRANSCRIPT_INTERIM', { transcriptInterim });
25-
commitToWindow(chromelessWindow, 'captioner/SET_TRANSCRIPT_FINAL', { transcriptFinal });
26-
commitToWindow(chromelessWindow, 'captioner/SET_TRANSCRIPT_TYPED', { transcriptTyped });
27-
28-
// Only do it once for this window
29-
window.removeEventListener('receiverIsReadyToReceiveMutations', restoreSettings);
30-
}
31-
window.addEventListener('receiverIsReadyToReceiveMutations', restoreSettings);
32-
33-
// I wanted to check for the unload event here, but it also fires on reload
34-
// and the load event didn't fire reliably when refreshing. So for now this interval
35-
// seemed more reliable.
36-
let checkOpenInterval;
37-
38-
checkOpenInterval = setInterval(function(){
39-
if (!chromelessWindow || chromelessWindow.closed) {
40-
onClose();
41-
clearInterval(checkOpenInterval);
42-
}
43-
},500);
44-
},
45-
}
46-
}
20+
methods: {
21+
start(RemoteEventBus, {
22+
settings,
23+
transcriptInterim,
24+
transcriptFinal,
25+
transcriptTyped
26+
}, onClose) {
27+
let chromelessWindow = window.open('/receivers/chromeless', 'WebCaptionerChild', 'height=700,width=900,toolbar=0,location=0,menubar=0');
28+
29+
if (!chromelessWindow) {
30+
alert('Unable to open a new window.');
31+
return;
32+
}
33+
34+
RemoteEventBus.$on('sendMutationToReceivers', ({
35+
mutation,
36+
payload
37+
}) => {
38+
commitToWindow(chromelessWindow, mutation, payload);
39+
});
40+
41+
function restoreSettings() {
42+
actionToWindow(chromelessWindow, 'RESTORE_SETTINGS_OBJECT', {
43+
settings
44+
});
45+
commitToWindow(chromelessWindow, 'captioner/SET_TRANSCRIPT_INTERIM', {
46+
transcriptInterim
47+
});
48+
commitToWindow(chromelessWindow, 'captioner/SET_TRANSCRIPT_FINAL', {
49+
transcriptFinal
50+
});
51+
commitToWindow(chromelessWindow, 'captioner/SET_TRANSCRIPT_TYPED', {
52+
transcriptTyped
53+
});
54+
55+
// Only do it once for this window
56+
window.removeEventListener('receiverIsReadyToReceiveMutations', restoreSettings);
57+
}
58+
window.addEventListener('receiverIsReadyToReceiveMutations', restoreSettings);
59+
60+
// I wanted to check for the unload event here, but it also fires on reload
61+
// and the load event didn't fire reliably when refreshing. So for now this interval
62+
// seemed more reliable.
63+
let checkOpenInterval;
64+
65+
checkOpenInterval = setInterval(function () {
66+
if (!chromelessWindow || chromelessWindow.closed) {
67+
onClose();
68+
clearInterval(checkOpenInterval);
69+
}
70+
}, 500);
71+
},
72+
}
73+
}

0 commit comments

Comments
 (0)