Merge pull request #122 from samuelthomas2774/add-core-settings-storage

Add core settings storage
This commit is contained in:
Alexei Stukov 2018-02-12 21:22:10 +02:00 committed by GitHub
commit 80ce233e6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 418 additions and 476 deletions

3
.gitignore vendored
View File

@ -21,4 +21,5 @@ Installers/**/*/obj
Installers/**/*/packages
.vs
dist/
user.config.json
user.config.json
tests/data

View File

@ -2,54 +2,85 @@
{
"id": "core",
"text": "Core",
"headertext": "Core Settings",
"settings": [
{
"id": "test-setting",
"text": "Test Setting",
"hint": "Test Setting",
"enabled": false,
"disabled": false
"category": "default",
"settings": [
{
"id": "test-setting",
"type": "bool",
"text": "Test Setting",
"hint": "Test Setting",
"value": false,
"disabled": false
},
{
"id": "test-setting2",
"type": "bool",
"text": "Test Setting 2",
"hint": "Test Setting 2",
"value": true,
"disabled": false
},
{
"id": "voice-disconnect",
"type": "bool",
"text": "Voice Disconnect",
"hint": "Disconnect from voice server when Discord closes",
"value": false,
"disabled": true
}
]
},
{
"id": "test-setting2",
"text": "Test Setting 2",
"hint": "Test Setting 2",
"enabled": true,
"disabled": false
},
{
"id": "voice-disconnect",
"text": "Voice Disconnect",
"hint": "Disconnect from voice server when Discord closes",
"enabled": false,
"disabled": true
},
{
"id": "developer-mode",
"text": "Developer Mode",
"hint": "BetterDiscord developer mode",
"enabled": false,
"disabled": true
"category": "Advanced",
"type": "drawer",
"settings": [
{
"id": "developer-mode",
"type": "bool",
"text": "Developer Mode",
"hint": "BetterDiscord developer mode",
"value": false,
"disabled": true
}
]
}
]
},
{
"id": "ui",
"text": "UI",
"headertext": "UI Settings",
"settings": [
{
"category": "default",
"settings": [
{
"id": "hide-button",
"type": "bool",
"text": "Hide the BetterDiscord button",
"hint": "When this is enabled you can use Ctrl/Cmd + B to open the BetterDiscord settings menu.",
"value": false,
"disabled": false
}
]
}
]
},
{
"id": "emotes",
"text": "Emotes",
"headertext": "Emote Settings",
"settings": []
},
{
"id": "security",
"text": "Security",
"headertext": "Security Settings",
"settings": [
]
}
]
]

View File

@ -10,7 +10,7 @@
import { DOM, BdUI } from 'ui';
import BdCss from './styles/index.scss';
import { Events, CssEditor, Globals, PluginManager, ThemeManager, ModuleManager, WebpackModules } from 'modules';
import { Events, CssEditor, Globals, PluginManager, ThemeManager, ModuleManager, WebpackModules, Settings } from 'modules';
import { ClientLogger as Logger, ClientIPC } from 'common';
class BetterDiscord {
@ -21,11 +21,13 @@ class BetterDiscord {
window.pm = PluginManager;
window.events = Events;
window.wpm = WebpackModules;
window.bdsettings = Settings;
DOM.injectStyle(BdCss, 'bdmain');
Events.on('global-ready', this.globalReady.bind(this));
}
async init() {
await Settings.loadSettings();
await ModuleManager.initModules();
await PluginManager.loadAllPlugins();
await ThemeManager.loadAllThemes();

View File

@ -9,9 +9,125 @@
*/
import defaultSettings from '../data/user.settings.default';
import { default as Globals } from './globals';
import { FileUtils, ClientLogger as Logger } from 'common';
import path from 'path';
export default class {
static async loadSettings() {
try {
await FileUtils.ensureDirectory(this.dataPath);
const settingsPath = path.resolve(this.dataPath, 'user.settings.json');
const user_config = await FileUtils.readJsonFromFile(settingsPath);
const { settings } = user_config;
this.settings = defaultSettings;
for (let newSet of settings) {
let set = this.settings.find(s => s.id === newSet.id);
if (!set) continue;
for (let newCategory of newSet.settings) {
let category = this.settings.find(c => c.category === newCategory.category);
if (!category) continue;
for (let newSetting of newCategory.settings) {
let setting = category.settings.find(s => s.id === newSetting.id);
if (!setting) continue;
setting.value = newSetting.value;
}
}
}
} catch (err) {
// There was an error loading settings
// This probably means that the user doesn't have any settings yet
Logger.err('Settings', err);
}
}
static async saveSettings() {
try {
await FileUtils.ensureDirectory(this.dataPath);
const settingsPath = path.resolve(this.dataPath, 'user.settings.json');
await FileUtils.writeJsonToFile(settingsPath, {
settings: this.getSettings.map(set => {
return {
id: set.id,
settings: set.settings.map(category => {
return {
category: category.category,
settings: category.settings.map(setting => {
return {
id: setting.id,
value: setting.value
};
})
};
})
};
})
});
} catch (err) {
// There was an error loading settings
// This probably means that the user doesn't have any settings yet
Logger.err('Settings', err);
}
}
static getSet(set_id) {
return this.getSettings.find(s => s.id === set_id);
}
static getCategory(set_id, category_id) {
const set = this.getSet(set_id);
if (!set) return;
return set.settings.find(c => c.category === category_id);
}
static getSetting(set_id, category_id, setting_id) {
const category = this.getCategory(set_id, category_id);
if (!category) return;
const setting = category.settings.find(s => s.id === setting_id);
if (!setting) return;
return setting.value;
}
static setSetting(set_id, category_id, setting_id, value) {
for (let set of this.getSettings) {
if (set.id !== set_id) continue;
for (let category of set.settings) {
if (category.category !== category_id) continue;
for (let setting of category.settings) {
if (setting.id !== setting_id) continue;
if (setting.value === value) return true;
setting.value = value;
this.settingUpdated(set_id, category_id, setting_id, value);
return true;
}
}
}
return false;
}
static settingUpdated(set_id, category_id, setting_id, value) {
Logger.log('Settings', `${set_id}/${category_id}/${setting_id} was set to ${value}`);
}
static get getSettings() {
return defaultSettings;
return this.settings ? this.settings : defaultSettings;
}
static get dataPath() {
return this._dataPath ? this._dataPath : (this._dataPath = Globals.getObject('paths').find(p => p.id === 'data').path);
}
}

View File

@ -73,54 +73,12 @@
}
.bd-switch-wrapper {
flex: 0 0 auto;
user-select: none;
position: relative;
width: 40px;
height: 20px;
display: block;
input {
position: absolute;
opacity: 0;
cursor: pointer;
width: 100%;
height: 100%;
z-index: 1;
}
.bd-switch {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #72767d;
border-radius: 14px;
transition: background .15s ease-in-out,box-shadow .15s ease-in-out,border .15s ease-in-out;
&:before {
content: "";
display: block;
width: 14px;
height: 14px;
position: absolute;
top: 3px;
left: 3px;
bottom: 3px;
background: #f6f6f7;
border-radius: 10px;
transition: all .15s ease;
box-shadow: 0 3px 1px 0 rgba(0,0,0,.05), 0 2px 2px 0 rgba(0,0,0,.1), 0 3px 3px 0 rgba(0,0,0,.05);
}
&.bd-checked {
background: $colbdblue;
&::before {
transform: translateX(20px);
}
}
.bd-switch::before {
width: 14px;
height: 14px;
}
}
}

View File

@ -12,57 +12,13 @@
.bd-plugin-settings-body {
padding: 0 15px;
.bd-setting-switch {
.bd-switch-wrapper {
flex: 0 0 auto;
user-select: none;
position: relative;
width: 40px;
height: 20px;
display: block;
.bd-switch-wrapper {
width: 40px;
height: 20px;
input {
position: absolute;
opacity: 0;
cursor: pointer;
width: 100%;
height: 100%;
z-index: 1;
}
.bd-switch {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #72767d;
border-radius: 14px;
transition: background .15s ease-in-out,box-shadow .15s ease-in-out,border .15s ease-in-out;
&:before {
content: "";
display: block;
width: 14px;
height: 14px;
position: absolute;
top: 3px;
left: 3px;
bottom: 3px;
background: #f6f6f7;
border-radius: 10px;
transition: all .15s ease;
box-shadow: 0 3px 1px 0 rgba(0,0,0,.05), 0 2px 2px 0 rgba(0,0,0,.1), 0 3px 3px 0 rgba(0,0,0,.05);
}
&.bd-checked {
background: $colbdblue;
&::before {
transform: translateX(20px);
}
}
}
.bd-switch::before {
width: 14px;
height: 14px;
}
}
}

View File

@ -27,6 +27,7 @@
.bd-drawer-contents-wrap {
overflow: hidden;
min-height: 5px;
}
.bd-drawer-contents {

View File

@ -4,3 +4,4 @@
@import './dropdowns.scss';
@import './radios.scss';
@import './sliders.scss';
@import './switches.scss';

View File

@ -28,4 +28,12 @@
line-height: 20px;
border-bottom: 0px solid rgba(114, 118, 126, 0.1);
}
.bd-disabled & {
opacity: 0.6;
&, input {
cursor: not-allowed !important;
}
}
}

View File

@ -0,0 +1,62 @@
.bd-setting-switch {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
-webkit-box-pack: start;
justify-content: flex-start;
-webkit-box-align: stretch;
align-items: stretch;
transition: opacity 0.2s ease;
}
.bd-switch-wrapper {
flex: 0 0 auto;
user-select: none;
position: relative;
width: 44px;
height: 24px;
display: block;
input {
position: absolute;
opacity: 0;
cursor: pointer;
width: 100%;
height: 100%;
z-index: 1;
}
.bd-switch {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #72767d;
border-radius: 14px;
transition: background .15s ease-in-out, box-shadow .15s ease-in-out, border .15s ease-in-out;
&::before {
content: "";
display: block;
width: 18px;
height: 18px;
position: absolute;
top: 3px;
left: 3px;
bottom: 3px;
background: #f6f6f7;
border-radius: 10px;
transition: all .15s ease;
box-shadow: 0 3px 1px 0 rgba(0,0,0,.05), 0 2px 2px 0 rgba(0,0,0,.1), 0 3px 3px 0 rgba(0,0,0,.05);
}
&.bd-checked {
background: $colbdblue;
&::before {
transform: translateX(20px);
}
}
}
}

View File

@ -1,4 +1,3 @@
@import './switches.scss';
@import './spinners/index.scss';
@import './scrollable.scss';
@import './buttons.scss';

View File

@ -1,73 +0,0 @@
.bd-setting-switch {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
-webkit-box-pack: start;
justify-content: flex-start;
-webkit-box-align: stretch;
align-items: stretch;
.bd-switch-wrapper {
flex: 0 0 auto;
user-select: none;
position: relative;
width: 44px;
height: 24px;
display: block;
input {
position: absolute;
opacity: 0;
cursor: pointer;
width: 100%;
height: 100%;
z-index: 1;
}
.bd-switch {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #72767d;
border-radius: 14px;
transition: background .15s ease-in-out, box-shadow .15s ease-in-out, border .15s ease-in-out;
&::before {
content: "";
display: block;
width: 18px;
height: 18px;
position: absolute;
top: 3px;
left: 3px;
bottom: 3px;
background: #f6f6f7;
border-radius: 10px;
transition: all .15s ease;
box-shadow: 0 3px 1px 0 rgba(0,0,0,.05), 0 2px 2px 0 rgba(0,0,0,.1), 0 3px 3px 0 rgba(0,0,0,.05);
}
&.bd-checked {
background: $colbdblue;
&::before {
transform: translateX(20px);
}
}
}
}
.bd-setting-switch-wrap {
transition: opacity 0.2s ease;
}
&.bd-disabled .bd-setting-switch-wrap {
opacity: 0.6;
&, input {
cursor: not-allowed !important;
}
}
}

View File

@ -34,18 +34,14 @@
</div>
</div>
<ContentColumn slot="content">
<div v-if="activeContent('core') || animatingContent('core')" :class="{active: activeContent('core'), animating: animatingContent('core')}">
<CoreSettings :settings="coreSettings" :enableSetting="enableSetting" :disableSetting="disableSetting" />
</div>
<div v-if="activeContent('ui') || animatingContent('ui')" :class="{active: activeContent('ui'), animating: animatingContent('ui')}">
<UISettings />
<div v-for="set in settings" v-if="activeContent(set.id) || animatingContent(set.id)" :class="{active: activeContent(set.id), animating: animatingContent(set.id)}">
<SettingsWrapper :headertext="set.headertext">
<SettingsPanel :settings="set.settings" :change="(c, s, v) => changeSetting(set.id, c, s, v)" />
</SettingsWrapper>
</div>
<div v-if="activeContent('css') || animatingContent('css')" :class="{active: activeContent('css'), animating: animatingContent('css')}">
<CssEditorView />
</div>
<div v-if="activeContent('emotes') || animatingContent('emotes')" :class="{active: activeContent('emotes'), animating: animatingContent('emotes')}">
<EmoteSettings />
</div>
<div v-if="activeContent('plugins') || animatingContent('plugins')" :class="{active: activeContent('plugins'), animating: animatingContent('plugins')}">
<PluginsView />
</div>
@ -61,7 +57,7 @@
import { shell } from 'electron';
import { Settings } from 'modules';
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
import { CoreSettings, UISettings, EmoteSettings, CssEditorView, PluginsView, ThemesView } from './bd';
import { SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView } from './bd';
import { SvgX, MiGithubCircle, MiWeb, MiClose, MiTwitterCircle } from './common';
// Constants
@ -88,14 +84,9 @@
}
},
props: ['active', 'close'],
computed: {
coreSettings() {
return this.settings.find(settingset => settingset.id === 'core').settings;
}
},
components: {
SidebarView, Sidebar, SidebarItem, ContentColumn,
CoreSettings, UISettings, EmoteSettings, CssEditorView, PluginsView, ThemesView,
SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView,
MiGithubCircle, MiWeb, MiClose, MiTwitterCircle
},
methods: {
@ -123,20 +114,11 @@
if (!item) return false;
return item.id === this.lastActiveIndex;
},
enableSetting(cat, id) {
switch (cat) {
case 'core':
return this.coreSettings.find(setting => setting.id === id).enabled = true;
}
},
disableSetting(cat, id) {
switch (cat) {
case 'core':
return this.coreSettings.find(setting => setting.id === id).enabled = false;
}
changeSetting(set_id, category_id, setting_id, value) {
Settings.setSetting(set_id, category_id, setting_id, value);
Settings.saveSettings();
},
openGithub() {
console.log('open github?');
shell.openExternal('https://github.com/JsSucks/BetterDiscordApp');
},
openWebsite() {

View File

@ -1,45 +0,0 @@
/**
* BetterDiscord Core Settings Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
<template>
<SettingsWrapper headertext="Core Settings">
<div class="bd-form-item" v-for="setting in settings" :key="setting.id">
<SettingSwitch key="setting.id" :setting="setting" :onClick="settingOnClick" :disabled="setting.disabled" />
<div class="bd-form-divider" />
</div>
</SettingsWrapper>
</template>
<script>
// Imports
import { SettingsWrapper } from './';
import { SettingSwitch } from '../common';
/*Methods*/
function settingOnClick(setting) {
if (setting.enabled) return this.disableSetting('core', setting.id);
this.enableSetting('core', setting.id);
}
const methods = { settingOnClick };
export default {
props: ['settings', 'enableSetting', 'disableSetting'],
components: {
SettingsWrapper, SettingSwitch
},
methods: {
settingOnClick(setting) {
if (setting.enabled) return this.disableSetting('core', setting.id);
this.enableSetting('core', setting.id);
}
}
}
</script>

View File

@ -15,17 +15,13 @@
<h5>Custom Editor</h5>
<div class="bd-form-warning">
<div class="bd-text">Custom Editor is not installed!</div>
<FormButton>
Install
</FormButton>
<FormButton>Install</FormButton>
</div>
<span style="color: #FFF; font-size: 12px; font-weight: 700;">*This is displayed if editor is not installed</span>
<FormButton :onClick="openInternalEditor">
Open
</FormButton>
<FormButton :onClick="openInternalEditor">Open</FormButton>
</div>
<div class="bd-form-divider"></div>
<SettingSwitch :setting="dummySetting" :onClick="settingClicked" />
<Setting :setting="liveUpdateSetting" :change="enabled => liveUpdateSetting.value = enabled" />
<div class="bd-form-item">
<h5>System Editor</h5>
<FormButton>
@ -33,12 +29,8 @@
</FormButton>
</div>
<div class="bd-form-divider"></div>
<FormButton :onClick="settingClicked">
Enabled
</FormButton>
<FormButton :disabled="true">
<span>Disabled</span>
</FormButton>
<FormButton :onClick="() => {}">Enabled</FormButton>
<FormButton :disabled="true"><span>Disabled</span></FormButton>
<FormButton :loading="true" />
</div>
</SettingsWrapper>
@ -48,27 +40,29 @@
// Imports
import { CssEditor } from 'modules';
import { SettingsWrapper } from './';
import { SettingSwitch, FormButton } from '../common';
import { FormButton } from '../common';
import Setting from './setting/Setting.vue';
export default {
components: {
SettingsWrapper,
SettingSwitch, FormButton
Setting,
FormButton
},
data() {
return {
liveUpdateSetting: {
id: "live-update",
type: "bool",
text: "Live Update",
hint: "Automatically update client css when saved.",
value: true
}
}
},
methods: {
openInternalEditor() {
CssEditor.show();
},
settingClicked() {
}
},
data() {
return {
dummySetting: {
title: "Live Update",
hint: "Automatically update client css when saved.",
checked: true
}
}
}
}

View File

@ -1,27 +0,0 @@
/**
* BetterDiscord Emote Settings Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
<template>
<SettingsWrapper headertext="Emote Settings">
</SettingsWrapper>
</template>
<script>
// Imports
import { SettingsWrapper } from './';
import { SettingSwitch } from '../common';
export default {
components: {
SettingsWrapper,
SettingSwitch
}
}
</script>

View File

@ -10,10 +10,7 @@
<template>
<Card :item="plugin">
<label slot="toggle" class="bd-switch-wrapper" @click="() => { togglePlugin(plugin); this.$forceUpdate(); }">
<input type="checkbox" class="bd-switch-checkbox" />
<div class="bd-switch" :class="{'bd-checked': plugin.enabled}" />
</label>
<SettingSwitch slot="toggle" :checked="plugin.enabled" :change="() => plugin.enabled ? plugin.stop() : plugin.start()" />
<ButtonGroup slot="controls">
<Button v-tooltip="'Settings'" v-if="plugin.hasSettings" :onClick="() => showSettings(plugin)">
<MiSettings size="18" />

View File

@ -9,37 +9,16 @@
*/
<template>
<div class="bd-plugin-settings-modal">
<div class="bd-plugin-settings-modal" :class="{'bd-edited': changed}">
<div class="bd-backdrop" @click="attemptToClose" :class="{'bd-backdrop-out': closing}"></div>
<Modal :headerText="plugin.name + ' Settings'" :close="attemptToClose" :class="{'bd-modal-out': closing}">
<div slot="body" class="bd-plugin-settings-body">
<template v-for="category in configCache">
<div v-if="category.category === 'default' || !category.type">
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
</div>
<div v-else-if="category.type === 'static'">
<div class="bd-form-header">
<span class="bd-form-header-text">{{category.category}} static with header</span>
</div>
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
</div>
<Drawer v-else-if="category.type === 'drawer'" :label="category.category + ' drawer'">
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
</Drawer>
<div v-else>
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
</div>
</template>
</div>
<SettingsPanel :settings="configCache" :change="settingChange" slot="body" class="bd-plugin-settings-body" />
<div slot="footer" class="bd-footer-alert" :class ="{'bd-active': changed, 'bd-warn': warnclose}">
<div class="bd-footer-alert-text">Unsaved changes</div>
<div class="bd-button bd-reset-button bd-tp" :class="{'bd-disabled': saving}" @click="resetSettings">Reset</div>
<div class="bd-button bd-ok" :class="{'bd-disabled': saving}" @click="saveSettings">
<div v-if="saving" class="bd-spinner-7"></div>
<template v-else>
Save Changes
</template>
<template v-else>Save Changes</template>
</div>
</div>
</Modal>
@ -47,9 +26,9 @@
</template>
<script>
// Imports
import Vue from 'vue';
import { Modal } from '../common';
import PluginSetting from './pluginsetting/PluginSetting.vue';
import Drawer from '../common/Drawer.vue';
import SettingsPanel from './SettingsPanel.vue';
export default {
props: ['plugin','close'],
@ -64,8 +43,7 @@
},
components: {
Modal,
PluginSetting,
Drawer
SettingsPanel,
},
methods: {
checkForChanges() {
@ -75,22 +53,23 @@
for (let setting of category.settings) {
if (cat.settings.find(s => s.id === setting.id).value !== setting.value) {
changed = true;
setting.changed = true;
Vue.set(setting, 'changed', true);
} else {
setting.changed = false;
Vue.set(setting, 'changed', false);
}
}
}
return changed;
},
settingChange(settingId, newValue) {
for (let category of this.configCache) {
const found = category.settings.find(s => s.id === settingId);
if (found) {
found.value = newValue;
break;
}
}
settingChange(category_id, setting_id, value) {
const category = this.configCache.find(c => c.category === category_id);
if (!category) return;
const setting = category.settings.find(s => s.id === setting_id);
if (!setting) return;
setting.value = value;
this.changed = this.checkForChanges();
this.$forceUpdate();
},

View File

@ -0,0 +1,51 @@
/**
* BetterDiscord Settings Panel Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
<template>
<div>
<template v-for="category in settings">
<div v-if="category.category === 'default' || !category.type">
<Setting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="v => settingChange(category, setting, v)" />
</div>
<div v-else-if="category.type === 'static'">
<div class="bd-form-header">
<span class="bd-form-header-text">{{category.category}} static with header</span>
</div>
<Setting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="v => settingChange(category, setting, v)" />
</div>
<Drawer v-else-if="category.type === 'drawer'" :label="category.category">
<Setting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="v => settingChange(category, setting, v)" />
</Drawer>
<div v-else>
<Setting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="v => settingChange(category, setting, v)" />
</div>
</template>
</div>
</template>
<script>
// Imports
import Setting from './setting/Setting.vue';
import Drawer from '../common/Drawer.vue';
export default {
props: ['settings', 'change'],
components: {
Setting,
Drawer
},
methods: {
settingChange(category, setting, value) {
if (setting.disabled) return;
this.change(category.category, setting.id, value);
}
}
}
</script>

View File

@ -10,10 +10,7 @@
<template>
<Card :item="theme">
<label slot="toggle" class="bd-switch-wrapper" @click="() => { toggleTheme(theme); this.$forceUpdate(); }">
<input type="checkbox" class="bd-switch-checkbox" />
<div class="bd-switch" :class="{'bd-checked': theme.enabled}" />
</label>
<SettingSwitch slot="toggle" :checked="theme.enabled" :change="() => theme.enabled ? theme.disable() : theme.enable()" />
<ButtonGroup slot="controls">
<Button v-tooltip="'Settings'" v-if="theme.hasSettings" :onClick="() => showSettings(theme)">
<MiSettings size="18" />

View File

@ -12,26 +12,7 @@
<div class="bd-plugin-settings-modal" :class="{'bd-edited': changed}">
<div class="bd-backdrop" @click="attemptToClose" :class="{'bd-backdrop-out': closing}"></div>
<Modal :headerText="theme.name + ' Settings'" :close="attemptToClose" :class="{'bd-modal-out': closing}">
<div slot="body" class="bd-plugin-settings-body">
<template v-for="category in configCache">
<div v-if="category.category === 'default' || !category.type">
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
</div>
<div v-else-if="category.type === 'static'">
<div class="bd-form-header">
<span class="bd-form-header-text">{{category.category}} static with header</span>
</div>
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
</div>
<Drawer v-else-if="category.type === 'drawer'" :label="category.category + ' drawer'">
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
</Drawer>
<div v-else>
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
</div>
</template>
</div>
<SettingsPanel :settings="configCache" :change="settingChange" slot="body" class="bd-plugin-settings-body" />
<div slot="footer" class="bd-footer-alert" :class ="{'bd-active': changed, 'bd-warn': warnclose}">
<div class="bd-footer-alert-text">Unsaved changes</div>
<div class="bd-button bd-reset-button bd-tp" :class="{'bd-disabled': saving}" @click="resetSettings">Reset</div>
@ -45,9 +26,9 @@
</template>
<script>
// Imports
import Vue from 'vue';
import { Modal } from '../common';
import PluginSetting from './pluginsetting/PluginSetting.vue';
import Drawer from '../common/Drawer.vue';
import SettingsPanel from './SettingsPanel.vue';
export default {
props: ['theme', 'close'],
@ -62,8 +43,7 @@
},
components: {
Modal,
PluginSetting,
Drawer
SettingsPanel
},
methods: {
checkForChanges() {
@ -73,22 +53,23 @@
for (let setting of category.settings) {
if (cat.settings.find(s => s.id === setting.id).value !== setting.value) {
changed = true;
setting.changed = true;
Vue.set(setting, 'changed', true);
} else {
setting.changed = false;
Vue.set(setting, 'changed', false);
}
}
}
return changed;
},
settingChange(settingId, newValue) {
for (let category of this.configCache) {
const found = category.settings.find(s => s.id === settingId);
if (found) {
found.value = newValue;
break;
}
}
settingChange(category_id, setting_id, value) {
const category = this.configCache.find(c => c.category === category_id);
if (!category) return;
const setting = category.settings.find(s => s.id === setting_id);
if (!setting) return;
setting.value = value;
this.changed = this.checkForChanges();
this.$forceUpdate();
},

View File

@ -1,27 +0,0 @@
/**
* BetterDiscord UI Settings Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
<template>
<SettingsWrapper headertext="UI Settings">
</SettingsWrapper>
</template>
<script>
// Imports
import { SettingsWrapper } from './';
import { SettingSwitch } from '../common';
export default {
components: {
SettingsWrapper,
SettingSwitch
}
}
</script>

View File

@ -1,7 +1,5 @@
export { default as SettingsWrapper } from './SettingsWrapper.vue';
export { default as CoreSettings } from './CoreSettings.vue';
export { default as UISettings } from './UISettings.vue';
export { default as EmoteSettings } from './EmoteSettings.vue';
export { default as SettingsPanel } from './SettingsPanel.vue';
export { default as CssEditorView } from './CssEditor.vue';
export { default as PluginsView } from './PluginsView.vue';
export { default as ThemesView } from './ThemesView.vue';

View File

@ -1,5 +1,5 @@
/**
* BetterDiscord Plugin Setting Bool Component
* BetterDiscord Setting Bool Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
@ -12,21 +12,18 @@
<div class="bd-setting-switch">
<div class="bd-title">
<h3>{{setting.text}}</h3>
<label class="bd-switch-wrapper" @click="toggle">
<input type="checkbox" class="bd-switch-checkbox" />
<div class="bd-switch" :class="{'bd-checked': setting.value}" />
</label>
<SettingSwitch :checked="setting.value" :change="change" />
</div>
<div class="bd-hint">{{setting.hint}}</div>
</div>
</template>
<script>
import SettingSwitch from '../../common/SettingSwitch.vue';
export default {
props: ['setting', 'change'],
methods: {
toggle() {
this.change(this.setting.id, !this.setting.value);
}
components: {
SettingSwitch
}
}
</script>

View File

@ -1,5 +1,5 @@
/**
* BetterDiscord Plugin Setting Dropdown Component
* BetterDiscord Setting Dropdown Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
@ -13,7 +13,7 @@
<div class="bd-title">
<h3>{{setting.text}}</h3>
<div class="bd-dropdown" :class="{'bd-active': active}">
<div class="bd-dropdown-current" @click="() => active = !active">
<div class="bd-dropdown-current" @click="() => active = !active && !setting.disabled">
<span class="bd-dropdown-text">{{getOptionText(setting.value)}}</span>
<span class="bd-dropdown-arrow-wrap">
<span class="bd-dropdown-arrow"></span>
@ -43,7 +43,7 @@
},
selectOption(option) {
this.active = false;
this.change(this.setting.id, option.id);
this.change(option.id);
}
},
mounted() {

View File

@ -1,5 +1,5 @@
/**
* BetterDiscord Plugin Setting File Component
* BetterDiscord Setting File Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
@ -12,7 +12,7 @@
<div class="bd-form-fileinput">
<div class="bd-title">
<h3>{{ setting.text }}</h3>
<button class="bd-button bd-button-primary" @click="openDialog">Select</button>
<button class="bd-button bd-button-primary" :class="{'bd-disabled': setting.disabled}" @click="openDialog">Select</button>
</div>
<div class="bd-hint">{{ setting.hint }}</div>
<div class="bd-selected-files">
@ -39,9 +39,11 @@
},
methods: {
async openDialog(e) {
if (this.setting.disabled) return;
const filenames = await ClientIPC.send('bd-native-open', this.setting.dialogOptions);
if (filenames)
this.change(this.setting.id, filenames);
this.change(filenames);
},
openItem(file_path) {
shell.openItem(file_path);

View File

@ -1,5 +1,5 @@
/**
* BetterDiscord Plugin Setting Multiline Text Component
* BetterDiscord Setting Multiline Text Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
@ -26,7 +26,7 @@
props: ['setting', 'change'],
methods: {
input(e) {
this.change(this.setting.id, e.target.textContent);
this.change(e.target.textContent);
}
}
}

View File

@ -1,5 +1,5 @@
/**
* BetterDiscord Plugin Setting Number Component
* BetterDiscord Setting Number Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
@ -31,11 +31,11 @@
let number = parseFloat(e.target.value)
if (Number.isNaN(number)) return;
this.change(this.setting.id, number);
this.change(number);
},
changeBy(positive) {
let step = this.setting.step == undefined ? 1 : this.settings.step;
this.change(this.setting.id, this.setting.value + (positive ? step : -step));
this.change(this.setting.value + (positive ? step : -step));
},
handleWheel() {} // No idea why this works but it does
},

View File

@ -1,5 +1,5 @@
/**
* BetterDiscord Plugin Setting Radio Component
* BetterDiscord Setting Radio Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
@ -30,7 +30,7 @@
props: ['setting', 'change'],
methods: {
selectOption(option) {
this.change(this.setting.id, option.id);
this.change(option.id);
}
}
}

View File

@ -1,5 +1,5 @@
/**
* BetterDiscord Plugin Setting Component
* BetterDiscord Setting Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
@ -9,7 +9,7 @@
*/
<template>
<div class="bd-form-item" :class="{'bd-form-item-changed': changed}">
<div class="bd-form-item" :class="{'bd-form-item-changed': changed, 'bd-disabled': disabled}">
<BoolSetting v-if="setting.type === 'bool'" :setting="setting" :change="change"/>
<DropdownSetting v-if="setting.type === 'dropdown'" :setting="setting" :change="change"/>
<NumberSetting v-if="setting.type === 'number'" :setting="setting" :change="change"/>
@ -35,8 +35,7 @@
export default {
props: [
'setting',
'change',
'changed'
'change'
],
components: {
BoolSetting,
@ -47,6 +46,14 @@
MultilineTextSetting,
SliderSetting,
FileSetting
},
computed: {
changed() {
return this.setting.changed || false;
},
disabled() {
return this.setting.disabled || false;
}
}
}
</script>

View File

@ -1,5 +1,5 @@
/**
* BetterDiscord Plugin Setting Slider Component
* BetterDiscord Setting Slider Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
@ -43,7 +43,7 @@
input(e) {
let number = parseFloat(e.target.value);
if (Number.isNaN(number)) return;
this.change(this.setting.id, number);
this.change(number);
},
getPointPosition(value) {
return ((value || this.setting.value) - (this.setting.min || 0)) / ((this.setting.max || 100) - (this.setting.min || 0));

View File

@ -1,5 +1,5 @@
/**
* BetterDiscord Plugin Setting String Component
* BetterDiscord Setting String Component
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
* All rights reserved.
* https://betterdiscord.net
@ -24,7 +24,7 @@
props: ['setting', 'change'],
methods: {
input(e) {
this.change(this.setting.id, e.target.value);
this.change(e.target.value);
}
}
}

View File

@ -9,21 +9,13 @@
*/
<template>
<div class="bd-setting-switch" :class="{'bd-disabled': disabled}">
<div class="bd-setting-switch-wrap">
<div class="bd-title">
<h3>{{setting.title || setting.text}}</h3>
<label class="bd-switch-wrapper" @click="!disabled ? onClick(setting) : null">
<input type="checkbox" class="bd-switch-checkbox" />
<div class="bd-switch" :class="{'bd-checked': (setting.checked || setting.enabled || setting.value)}" />
</label>
</div>
<div class="bd-hint">{{setting.hint}}</div>
</div>
</div>
<label class="bd-switch-wrapper" @click="() => change(!checked)">
<input type="checkbox" class="bd-switch-checkbox" />
<div class="bd-switch" :class="{'bd-checked': checked}" />
</label>
</template>
<script>
export default {
props: ['setting', 'onClick', 'disabled']
props: ['checked', 'change']
}
</script>

View File

@ -21,6 +21,7 @@ const __DEV = {
clientScriptPath: `${clientScriptPath}/betterdiscord.client.js`
}
const __dataPath = path.resolve(__dirname, '..', '..', 'tests', 'data');
const __pluginPath = path.resolve(__dirname, '..', '..', 'tests', 'plugins');
const __themePath = path.resolve(__dirname, '..', '..', 'tests', 'themes');
@ -33,6 +34,7 @@ const dummyArgs = {
'version': '0.3.1',
'paths': [
{ 'id': 'base', 'path': 'basePath' },
{ 'id': 'data', 'path': __dataPath },
{ 'id': 'plugins', 'path': __pluginPath },
{ 'id': 'themes', 'path': __themePath }
]