Add guild selection setting and developer mode option

This commit is contained in:
Samuel Elliott 2018-03-16 00:54:50 +00:00
parent d3a5be365e
commit 086b6253bc
12 changed files with 353 additions and 42 deletions

View File

@ -47,10 +47,9 @@
{
"id": "developer-mode",
"type": "bool",
"text": "Developer Mode",
"hint": "BetterDiscord developer mode",
"value": false,
"disabled": true
"text": "Developer mode",
"hint": "Adds some of BetterDiscord's internal modules to `global._bd`.",
"value": false
},
{
"id": "ignore-content-manager-errors",

View File

@ -19,33 +19,37 @@ const DEV = true;
class BetterDiscord {
constructor() {
window.BDDEVMODE = function () {
if (!DEV) return null;
return window._bd = {
DOM,
BdUI,
Modals,
Reflection,
Patcher,
Vendor,
Events,
CssEditor,
Globals,
ExtModuleManager,
PluginManager,
ThemeManager,
ModuleManager,
WebpackModules,
Settings,
Database,
ReactComponents,
DiscordApi,
Logger,
ClientIPC,
Utils,
EmoteModule
}
}
this._bd = {
DOM,
BdUI,
Modals,
Reflection,
Patcher,
Vendor,
Events,
CssEditor,
Globals,
ExtModuleManager,
PluginManager,
ThemeManager,
ModuleManager,
WebpackModules,
Settings,
Database,
ReactComponents,
DiscordApi,
Logger,
ClientIPC,
Utils,
EmoteModule
};
const developermode = Settings.getSetting('core', 'advanced', 'developer-mode');
if (developermode.value) window._bd = this._bd;
developermode.on('setting-updated', event => {
if (event.value) window._bd = this._bd;
else if (window._bd) delete window._bd;
});
DOM.injectStyle(BdCss, 'bdmain');
this.globalReady = this.globalReady.bind(this);
@ -79,16 +83,13 @@ class BetterDiscord {
this.vueInstance = BdUI.injectUi();
this.init();
}
}
if (window.BetterDiscord) {
Logger.log('main', 'Attempting to inject again?');
} else {
let instance = null;
// eslint-disable-next-line no-inner-declarations
function init() {
instance = new BetterDiscord();
}
Events.on('autopatcher', init);
Events.on('autopatcher', () => instance = new BetterDiscord());
ReactAutoPatcher.autoPatch().then(() => Events.emit('autopatcher'));
}

View File

@ -19,6 +19,7 @@ import SliderSetting from './types/slider';
import ColourSetting from './types/colour';
import KeybindSetting from './types/keybind';
import FileSetting from './types/file';
import GuildSetting from './types/guild';
import ArraySetting from './types/array';
import CustomSetting from './types/custom';
@ -38,6 +39,7 @@ export default class Setting {
else if (args.type === 'colour') return new ColourSetting(args, ...merge);
else if (args.type === 'keybind') return new KeybindSetting(args, ...merge);
else if (args.type === 'file') return new FileSetting(args, ...merge);
else if (args.type === 'guild') return new GuildSetting(args, ...merge);
else if (args.type === 'array') return new ArraySetting(args, ...merge);
else if (args.type === 'custom') return new CustomSetting(args, ...merge);
else throw {message: `Setting type ${args.type} unknown`};

View File

@ -215,11 +215,6 @@ export default class ArraySetting extends Setting {
if (error) throw error;
}
// emit(...args) {
// console.log('Emitting event', args[0], 'with data', args[1]);
// return this.emitter.emit(...args);
// }
/**
* Updates the value of this array setting.
* This only exists for use by array settings.

View File

@ -0,0 +1,151 @@
/**
* BetterDiscord Guild Setting Struct
* 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.
*/
import { DiscordApi } from 'modules';
import { Utils, ClientLogger as Logger } from 'common';
import Setting from './basesetting';
export default class GuildSetting extends Setting {
constructor(args, ...merge) {
super(args, ...merge);
this.args.guilds = this.value ? this.value.map(guild_id => DiscordApi.guilds.get({ id: guild_id })) : [];
}
/**
* The value to use when the setting doesn't have a value.
*/
get defaultValue() {
return [];
}
/**
* An array of currently selected guilds.
*/
get guilds() {
return this.args.guilds;
}
/**
* The minimum amount of guilds the user may select.
* This only restricts removing guilds when there is less or equal guilds than this, and does not ensure that this number of guilds actually exists.
*/
get min() {
return this.args.min || 0;
}
/**
* The maximum amount of guilds the user may select.
*/
get max() {
return this.args.max || null;
}
/**
* Adds a guild to the list of selected guilds.
* @param {Number} guild_id The ID of the guild to add
* @return {Promise}
*/
addGuild(guild_id) {
return this.setValue(this.value.concat([guild_id]));
// if (this.guilds.find(g => g && g.id === guild_id)) return;
// const guild = DiscordApi.guilds.get({ id: guild_id });
// this.guilds.push(guild);
// await this.emit('guild-added', guild);
// return await this.setValue(this.value.concat([guild_id]));
}
/**
* Removes a guild from the list of selected guilds.
* @param {Number} guild_id The ID of the guild to remove
* @return {Promise}
*/
removeGuild(guild_id) {
return this.setValue(this.value.filter(g => g !== guild_id));
// const guild = this.guilds.find(g => g && g.id === guild_id);
// const value = Utils.removeFromArray(this.value.slice(0), guild_id);
// if (guild) {
// Utils.filterArray(this.guilds, g => !g || g.id !== guild_id);
// await this.emit('guild-removed', guild);
// }
// return await this.setValue(value);
}
/**
* Function to be called after the value changes.
* This can be overridden by other settings types.
* This function is used when the value needs to be updated synchronously (basically just in the constructor - so there won't be any events to emit anyway).
* @param {SettingUpdatedEvent} updatedSetting
*/
setValueHookSync(updatedSetting) {
this.args.guilds = updatedSetting.value ? updatedSetting.value.map(guild_id => DiscordApi.guilds.get({ id: guild_id })) : [];
}
/**
* Function to be called after the value changes.
* This can be overridden by other settings types.
* @param {SettingUpdatedEvent} updatedSetting
*/
async setValueHook(updatedSetting) {
const newGuilds = [];
let error;
for (let newGuild of updatedSetting.value) {
try {
const guild = updatedSetting.old_value.find(g => g === newGuild);
if (guild) {
// Guild was already selected
newGuilds.push(guild);
} else {
// Add a new guild
Logger.log('GuildSetting', ['Adding guild', newGuild, 'to', this]);
newGuilds.push(newGuild);
await this.emit('guild-added', { id: newGuild });
}
} catch (e) { error = e; }
}
for (let guild_id of updatedSetting.old_value) {
if (newGuilds.find(g => g === guild_id)) continue;
try {
// Guild removed
Logger.log('GuildSetting', ['Removing guild', guild_id, 'from', this]);
await this.emit('guild-removed', { id: guild_id });
} catch (e) { error = e; }
}
this.args.guilds = newGuilds.map(id => DiscordApi.guilds.get({ id }));
// We can't throw anything before the guilds array is updated, otherwise the guild setting would be in an inconsistent state where the values in this.guilds wouldn't match the values in this.value
if (error) throw error;
}
/**
* Returns a representation of this setting's value in SCSS.
* @return {String|Promise}
*/
async toSCSS() {
if (!this.value || !this.value.length) return '()';
const guilds = [];
for (let guild_id of this.value) {
if (guild_id)
guilds.push(guild_id);
}
return guilds.length ? guilds.join(', ') : '()';
}
}

View File

@ -0,0 +1,51 @@
.bd-form-guildinput {
}
.bd-guilds {
// margin: 15px 0;
.bd-guild {
$size: 36px;
display: inline-block;
width: $size;
height: $size;
background-color: rgb(47, 49, 54);
background-size: cover;
margin: 10px 10px 0 0;
border-radius: 50%;
cursor: pointer;
transition: border-radius .4s cubic-bezier(0.5, 0, 0.27, 1.55), background-color .4s cubic-bezier(0.5, 0, 0.27, 1.55), box-shadow .4s cubic-bezier(0.5, 0, 0.27, 1.55);
.bd-guild-text {
float: left;
display: block;
width: $size;
height: $size;
text-align: center;
vertical-align: middle;
line-height: $size;
font-size: 15px;
}
&:hover {
border-radius: 30%;
background-color: $colbdblue;
&.bd-guild-has-icon {
background-color: rgb(47, 49, 54);
// box-shadow: 0 0 1px #000000;
}
}
&.bd-active {
background-color: $colbdblue;
&.bd-guild-has-icon {
background-color: rgb(47, 49, 54);
box-shadow: 0 0 7px $colbdblue;
}
}
}
}

View File

@ -1,10 +1,11 @@
@import './main.scss';
@import './switches.scss';
@import './text.scss';
@import './files.scss';
@import './dropdowns.scss';
@import './radios.scss';
@import './sliders.scss';
@import './colourpickers.scss';
@import './keybinds.scss';
@import './files.scss';
@import './guilds.scss';
@import './arrays.scss';

View File

@ -8,6 +8,7 @@
.bd-form-colourpicker,
.bd-form-keybind,
.bd-form-fileinput,
.bd-form-guildinput,
.bd-form-settingsarray {
.bd-title {
display: flex;

View File

@ -0,0 +1,85 @@
/**
* BetterDiscord Setting Guild 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 class="bd-form-guildinput">
<div class="bd-title">
<h3>{{ setting.text }}</h3>
</div>
<div class="bd-hint">{{ setting.hint }}</div>
<div class="bd-guilds">
<div class="bd-guild" :class="{'bd-active': isGuildSelected(guild), 'bd-guild-has-icon': guild.icon}" :style="{backgroundImage: `url('${getGuildIconURL(guild)}')`}" @click="() => isGuildSelected(guild) ? unselectGuild(guild) : selectGuild(guild)" v-for="guild in guilds" v-if="guild" v-tooltip="guild.name">
<div class="bd-guild-text" v-if="!guild.icon">{{ getGuildIconText(guild) }}</div>
</div>
</div>
</div>
</template>
<script>
import { DiscordApi } from 'modules';
export default {
props: ['setting'],
data() {
return {
user_guilds: []
};
},
computed: {
guilds() {
const guilds = ([]).concat(this.user_guilds);
for (let guild of this.setting.guilds) {
if (!guilds.find(g => g && guild && g.id === guild.id))
guilds.push(guild);
}
return guilds.sort(function(a, b) {
var nameA = a.name.toUpperCase(); // ignore upper and lowercase
var nameB = b.name.toUpperCase(); // ignore upper and lowercase
if (nameA < nameB) return -1;
if (nameA > nameB) return 1;
// names must be equal
return 0;
});
}
},
methods: {
isGuildSelected(guild) {
return this.setting.guilds.find(g => g && g.id === guild.id);
},
getGuildIconURL(guild) {
return `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.webp`;
},
getGuildIconText(guild) {
const words = guild.name.split(' ');
if (!words.length) return '';
const first = words[0].substr(0, 1);
if (words.length <= 1) return first;
const last = words[words.length - 1].substr(0, 1);
return `${first}${last}`;
},
async selectGuild(guild) {
if (this.setting.max && this.setting.guilds.length >= this.setting.max) return;
await this.setting.addGuild(guild.id);
},
async unselectGuild(guild) {
if (this.setting.min && this.setting.guilds.length <= this.setting.min) return;
await this.setting.removeGuild(guild.id);
},
refreshGuilds() {
this.user_guilds = DiscordApi.guilds;
}
},
created() {
this.refreshGuilds();
}
}
</script>

View File

@ -20,6 +20,7 @@
<ColourSetting v-if="setting.type === 'colour'" :setting="setting" :change="change" />
<KeybindSetting v-if="setting.type === 'keybind'" :setting="setting" />
<FileSetting v-if="setting.type === 'file'" :setting="setting" :change="change" />
<GuildSetting v-if="setting.type === 'guild'" :setting="setting" />
<ArraySetting v-if="setting.type === 'array'" :setting="setting" :change="change" />
<CustomSetting v-if="setting.type === 'custom'" :setting="setting" :change="change" />
<div class="bd-form-divider"></div>
@ -37,6 +38,7 @@
import ColourSetting from './Colour.vue';
import KeybindSetting from './Keybind.vue';
import FileSetting from './File.vue';
import GuildSetting from './Guild.vue';
import ArraySetting from './Array.vue';
import CustomSetting from './Custom.vue';
@ -55,6 +57,7 @@
ColourSetting,
KeybindSetting,
FileSetting,
GuildSetting,
ArraySetting,
CustomSetting
},

View File

@ -162,6 +162,19 @@ export class Utils {
return object;
}
static filterArray(array, filter) {
const indexes = [];
for (let index in array) {
if (!filter(array[index], index))
indexes.push(index);
}
for (let i in indexes)
array.splice(indexes[i] - i, 1);
return array;
}
static removeFromArray(array, item) {
let index;
while ((index = array.indexOf(item)) > -1)

View File

@ -84,6 +84,15 @@
"value": "mod+.",
"text": "Test Keybind Setting 1",
"hint": "Test Keybind Setting Hint 1"
},
{
"id": "guild-1",
"type": "guild",
"value": [
"280806472928198656"
],
"text": "Test guild setting",
"hint": "Test guild setting hint"
}
]
}