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

Commit 8e43c17

Browse files
committed
Add ability to export and restore settings
1 parent 27c06e0 commit 8e43c17

File tree

6 files changed

+232
-66
lines changed

6 files changed

+232
-66
lines changed

app/mixins/saveToFile.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,12 @@ export default {
2020

2121
onDone();
2222
},
23+
saveToJSONFile({settings, onDone}) {
24+
var a = document.createElement('a');
25+
a.href = 'data:text/plain;base64,' + btoa(settings);
26+
a.textContent = 'download';
27+
a.download = 'web-captioner-settings.json';
28+
a.click();
29+
},
2330
}
2431
} ;

app/nuxt.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module.exports = {
3232
imports: [
3333
{
3434
set: '@fortawesome/free-solid-svg-icons',
35-
icons: ['faFileAlt', 'faFileWord', 'faExclamationTriangle', 'faTimes', 'faMicrophone', 'faDesktop', 'faExternalLinkAlt', 'faSave', 'faTrashAlt', 'faCog', 'faCheckCircle', 'faSpinner', 'faChevronRight', 'faMinusCircle', 'faPlusCircle', 'faArrowLeft', 'faFlask', 'faCaretRight', 'faCaretDown',],
35+
icons: ['faFileAlt', 'faFileWord', 'faExclamationTriangle', 'faTimes', 'faMicrophone', 'faDesktop', 'faExternalLinkAlt', 'faSave', 'faTrashAlt', 'faCog', 'faCheckCircle', 'faSpinner', 'faChevronRight', 'faMinusCircle', 'faPlusCircle', 'faArrowLeft', 'faFlask', 'faCaretRight', 'faCaretDown', ],
3636
},
3737
{
3838
set: '@fortawesome/free-regular-svg-icons',

app/pages/captioner/settings.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<h3 class="text-muted pl-3 pt-2 small">Integrations</h3>
3838
<b-list-group flush>
3939
<b-list-group-item to="/captioner/settings/vmix">vMix</b-list-group-item>
40+
<b-list-group-item to="/captioner/settings/webhooks">Webhooks</b-list-group-item>
4041
</b-list-group>
4142
</div>
4243

@@ -72,6 +73,10 @@
7273
<b-nav-item to="/captioner/settings/vmix">vMix</b-nav-item>
7374
<b-nav-item to="/captioner/settings/webhooks">Webhooks</b-nav-item>
7475
</b-nav>
76+
<hr/>
77+
<b-nav vertical pills>
78+
<b-nav-item class="small" to="/captioner/settings/export-restore">Export/Restore Settings</b-nav-item>
79+
</b-nav>
7580
</nav>
7681
</div>
7782
</div>
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<template>
2+
<div>
3+
<b-modal ref="invalidSettingsFile" class="text-center" hide-header @shown="focusInvalidSettingsFileModalOkButton()">
4+
<div class="py-2">
5+
<div class="pb-2 h4"><fa icon="exclamation-triangle" size="3x" /></div>
6+
<h2>Hmmm</h2>
7+
<p class="lead">It looks like something's wrong with that file.</p>
8+
</div>
9+
<div slot="modal-footer">
10+
<b-btn class="float-right" variant="secondary" ref="invalidSettingsFileModalOkButton" @click="hideInvalidSettingsFileModal()">Ok</b-btn>
11+
</div>
12+
</b-modal>
13+
<b-modal ref="confirmRestore" hide-header @shown="focusConfirmRestoreModalOkButton()">
14+
<div class="py-2">
15+
<h2>Restore settings from this file?</h2>
16+
<p class="lead">All of your current settings will be lost.</p>
17+
</div>
18+
<div slot="modal-footer">
19+
<b-btn class="float-right ml-2" variant="secondary" ref="confirmRestoreModalOkButton" @click="restoreSettings()">Restore</b-btn>
20+
<b-btn class="float-right" variant="primary" @click="cancelConfirmRestoreModal()">Cancel</b-btn>
21+
</div>
22+
</b-modal>
23+
<b-modal ref="confirmReset" hide-header @shown="focusConfirmResetModalOkButton()">
24+
<div class="py-2">
25+
<h2>Reset all your settings?</h2>
26+
<p class="lead">All of your current settings will be lost.</p>
27+
</div>
28+
<div slot="modal-footer">
29+
<b-btn class="float-right ml-2" variant="danger" ref="confirmResetModalOkButton" @click="resetSettings()">Reset</b-btn>
30+
<b-btn class="float-right" variant="primary" @click="cancelConfirmResetModal()">Cancel</b-btn>
31+
</div>
32+
</b-modal>
33+
<b-modal class="text-center" ref="restoreSuccessModal" ok-only hide-header>
34+
<div class="pb-2 h4"><fa icon="check-circle" size="3x" /></div>
35+
<h2>Settings Restored</h2>
36+
</b-modal>
37+
<b-modal class="text-center" ref="resetSuccessModal" ok-only hide-header>
38+
<div class="pb-2 h4"><fa icon="check-circle" size="3x" /></div>
39+
<h2>Settings Reset</h2>
40+
</b-modal>
41+
<div class="card mb-3">
42+
<div class="card-body">
43+
<h3>Export</h3>
44+
<p>Your settings will be saved locally as a JSON file.</p>
45+
<button class="btn btn-secondary d-inline-block" @click="exportSettings()">Export</button>
46+
</div>
47+
</div>
48+
<div class="card mb-3">
49+
<div class="card-body">
50+
<h3>Restore</h3>
51+
<p>Restore settings (appearance, censor settings, word replacements, vMix settings, etc.) from a settings file you previously exported.</p>
52+
<input ref="settingsFileUpload" type="file" accept=".json" @change="loadSettingsFile($event)" />
53+
</div>
54+
</div>
55+
<div class="card mb-3">
56+
<div class="card-body">
57+
<h3>Reset Everything</h3>
58+
<p>Reset all your settings.</p>
59+
<button class="btn btn-danger d-inline-block" @click="confirmReset()">Reset</button>
60+
</div>
61+
</div>
62+
</div>
63+
</template>
64+
65+
<script>
66+
import saveToFile from '~/mixins/saveToFile'
67+
import getDefaultSettings from '~/store/settingsState'
68+
69+
export default {
70+
transition: 'fade',
71+
middleware: [
72+
'settings-meta',
73+
],
74+
meta: {
75+
settingsPageTitle: 'Export/Restore Settings',
76+
},
77+
mixins: [
78+
saveToFile,
79+
],
80+
data: function() {
81+
return {
82+
importedSettings: {},
83+
};
84+
},
85+
methods: {
86+
exportSettings: function() {
87+
this.saveToJSONFile({
88+
settings: JSON.stringify(this.$store.state.settings)
89+
});
90+
},
91+
loadSettingsFile: function(event) {
92+
let input = event.target;
93+
94+
var reader = new FileReader();
95+
reader.onload = () => {
96+
let result = reader.result;
97+
try {
98+
this.importedSettings = JSON.parse(reader.result);
99+
this.$refs.confirmRestore.show();
100+
}
101+
catch (e) {
102+
this.$refs.invalidSettingsFile.show();
103+
}
104+
};
105+
reader.readAsText(input.files[0]);
106+
},
107+
restoreSettings: function() {
108+
this.$store.dispatch('RESTORE_SETTINGS', {settings: getDefaultSettings() })
109+
.then(() => {
110+
return this.$store.dispatch('RESTORE_SETTINGS', {settings: this.importedSettings });
111+
})
112+
.then(() => {
113+
this.cancelConfirmRestoreModal();
114+
this.$refs.restoreSuccessModal.show();
115+
});
116+
},
117+
resetSettings: function() {
118+
this.$store.dispatch('RESTORE_SETTINGS', {settings: getDefaultSettings() })
119+
.then(() => {
120+
this.$refs.confirmReset.hide();
121+
this.$refs.resetSuccessModal.show();
122+
});
123+
},
124+
focusInvalidSettingsFileModalOkButton: function() {
125+
this.$refs.invalidSettingsFileModalOkButton.focus();
126+
},
127+
hideInvalidSettingsFileModal: function() {
128+
this.$refs.invalidSettingsFile.hide();
129+
},
130+
focusConfirmRestoreModalOkButton: function() {
131+
this.$refs.confirmRestoreModalOkButton.focus();
132+
},
133+
cancelConfirmRestoreModal: function() {
134+
this.loadedSettings = null;
135+
this.$refs.settingsFileUpload.value = null;
136+
this.$refs.confirmRestore.hide();
137+
},
138+
confirmReset: function() {
139+
this.$refs.confirmReset.show();
140+
},
141+
focusConfirmResetModalOkButton: function() {
142+
this.$refs.confirmResetModalOkButton.focus();
143+
},
144+
cancelConfirmResetModal: function() {
145+
this.$refs.confirmReset.hide();
146+
},
147+
}
148+
}
149+
</script>

app/store/index.js

Lines changed: 2 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import actions from './actions'
44
import mutations from './mutations'
55
import getters from './getters'
66
import captioner from './modules/captioner'
7-
import fontChocies from '~/mixins/data/fontChoices'
87
import remoteMutationBlacklist from '~/mixins/data/remoteMutationBlacklist'
98
import RemoteEventBus from '~/mixins/RemoteEventBus'
9+
import getSettingsState from './settingsState'
1010

1111
Vue.use(Vuex)
1212

@@ -66,70 +66,7 @@ const createStore = () => {
6666
},
6767
state: {
6868
version: '2.0.0',
69-
settings: {
70-
roomMembershipId: null,
71-
roomLeaderToken: null,
72-
controls: {
73-
layout: {
74-
larger: false,
75-
},
76-
},
77-
appearance: {
78-
text: {
79-
textColor: '#ffffff',
80-
textColorInterim: '#ffffff',
81-
fontFamily: fontChocies[0].displayName, // first is default
82-
textSize: "4", // em
83-
lineHeight: "1.2", // em
84-
letterSpacing: "0", // em
85-
textTransform: "uppercase", // or "capitalize" or "initial"
86-
alignment: {
87-
horizontal: 'full', // left, middle, right
88-
vertical: 'full', // top, middle, bottom, lowerThird
89-
padding: "0.25", // em
90-
}
91-
},
92-
shadow: {
93-
color: '#000000',
94-
opacity: '100',
95-
blurRadius: '0',
96-
offsetX: '0.25',
97-
offsetY: '0.25',
98-
},
99-
background: {
100-
color: '#000000',
101-
},
102-
},
103-
wordReplacements: [],
104-
censor: {
105-
on: true,
106-
replaceWith: 'nothing', // or 'asterisks'
107-
},
108-
locale: {
109-
from: null,
110-
userDefault: null,
111-
},
112-
integrations: {
113-
vmix: {
114-
on: false,
115-
webControllerAddress: '',
116-
},
117-
webhooks: {
118-
on: false,
119-
interim: {
120-
url: '',
121-
method: 'POST',
122-
throttleMs: 500,
123-
},
124-
final: {
125-
url: '',
126-
method: 'POST',
127-
},
128-
},
129-
},
130-
lastWhatsNewVersionSeen: '',
131-
exp: [],
132-
},
69+
settings: getSettingsState(),
13370
receivers: {
13471
chromecast: {
13572
connected: false,

app/store/settingsState.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import fontChoices from '~/mixins/data/fontChoices'
2+
3+
export default () => {
4+
return {
5+
roomMembershipId: null,
6+
roomLeaderToken: null,
7+
controls: {
8+
layout: {
9+
larger: false,
10+
},
11+
},
12+
appearance: {
13+
text: {
14+
textColor: '#ffffff',
15+
textColorInterim: '#ffffff',
16+
fontFamily: fontChoices[0].displayName, // first is default
17+
textSize: "4", // em
18+
lineHeight: "1.2", // em
19+
letterSpacing: "0", // em
20+
textTransform: "uppercase", // or "capitalize" or "initial"
21+
alignment: {
22+
horizontal: 'full', // left, middle, right
23+
vertical: 'full', // top, middle, bottom, lowerThird
24+
padding: "0.25", // em
25+
}
26+
},
27+
shadow: {
28+
color: '#000000',
29+
opacity: '100',
30+
blurRadius: '0',
31+
offsetX: '0.25',
32+
offsetY: '0.25',
33+
},
34+
background: {
35+
color: '#000000',
36+
},
37+
},
38+
wordReplacements: [],
39+
censor: {
40+
on: true,
41+
replaceWith: 'nothing', // or 'asterisks'
42+
},
43+
locale: {
44+
from: null,
45+
userDefault: null,
46+
},
47+
integrations: {
48+
vmix: {
49+
on: false,
50+
webControllerAddress: '',
51+
},
52+
webhooks: {
53+
on: false,
54+
interim: {
55+
url: '',
56+
method: 'POST',
57+
throttleMs: 500,
58+
},
59+
final: {
60+
url: '',
61+
method: 'POST',
62+
},
63+
},
64+
},
65+
lastWhatsNewVersionSeen: '',
66+
exp: [],
67+
};
68+
};

0 commit comments

Comments
 (0)