Merge pull request #2 from samuelthomas2774/discord-api-2
Discord api 2
This commit is contained in:
commit
83b212c252
|
@ -1,335 +0,0 @@
|
||||||
/**
|
|
||||||
* BetterDiscord Discord API
|
|
||||||
* 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 { List } from 'structs';
|
|
||||||
import { User, Channel, Guild, Message } from 'discordstructs';
|
|
||||||
import Reflection from './reflection/index';
|
|
||||||
|
|
||||||
export const Modules = {
|
|
||||||
_getModule(name) {
|
|
||||||
const foundModule = Reflection.module.byName(name);
|
|
||||||
if (!foundModule) return null;
|
|
||||||
delete this[name];
|
|
||||||
return this[name] = foundModule;
|
|
||||||
},
|
|
||||||
|
|
||||||
get ChannelSelector() { return this._getModule('ChannelSelector'); },
|
|
||||||
get MessageActions() { return this._getModule('MessageActions'); },
|
|
||||||
get MessageParser() { return this._getModule('MessageParser'); },
|
|
||||||
get MessageStore() { return this._getModule('MessageStore'); },
|
|
||||||
get EmojiUtils() { return this._getModule('EmojiUtils'); },
|
|
||||||
get PermissionUtils() { return this._getModule('Permissions'); },
|
|
||||||
get SortedGuildStore() { return this._getModule('SortedGuildStore'); },
|
|
||||||
get PrivateChannelActions() { return this._getModule('PrivateChannelActions'); },
|
|
||||||
get GuildMemberStore() { return this._getModule('GuildMemberStore'); },
|
|
||||||
get GuildChannelsStore() { return this._getModule('GuildChannelsStore'); },
|
|
||||||
get MemberCountStore() { return this._getModule('MemberCountStore'); },
|
|
||||||
get GuildActions() { return this._getModule('GuildActions'); },
|
|
||||||
get NavigationUtils() { return this._getModule('NavigationUtils'); },
|
|
||||||
get GuildPermissions() { return this._getModule('GuildPermissions'); },
|
|
||||||
get DiscordConstants() { return this._getModule('DiscordConstants'); },
|
|
||||||
get ChannelStore() { return this._getModule('ChannelStore'); },
|
|
||||||
get GuildStore() { return this._getModule('GuildStore'); },
|
|
||||||
get SelectedGuildStore() { return this._getModule('SelectedGuildStore'); },
|
|
||||||
get SelectedChannelStore() { return this._getModule('SelectedChannelStore'); },
|
|
||||||
get UserStore() { return this._getModule('UserStore'); },
|
|
||||||
get RelationshipStore() { return this._getModule('RelationshipStore'); },
|
|
||||||
get RelationshipManager() { return this._getModule('RelationshipManager'); },
|
|
||||||
get ChangeNicknameModal() { return this._getModule('ChangeNicknameModal'); },
|
|
||||||
get UserSettingsStore() { return this._getModule('UserSettingsStore'); },
|
|
||||||
get UserSettingsWindow() { return this._getModule('UserSettingsWindow'); },
|
|
||||||
get UserStatusStore() { return this._getModule('UserStatusStore'); },
|
|
||||||
get ChannelSettingsWindow() { return this._getModule('ChannelSettingsWindow'); },
|
|
||||||
get GuildSettingsWindow() { return this._getModule('GuildSettingsWindow'); },
|
|
||||||
get CreateChannelModal() { return this._getModule('CreateChannelModal'); },
|
|
||||||
get PruneMembersModal() { return this._getModule('PruneMembersModal'); },
|
|
||||||
get NotificationSettingsModal() { return this._getModule('NotificationSettingsModal'); },
|
|
||||||
get PrivacySettingsModal() { return this._getModule('PrivacySettingsModal'); },
|
|
||||||
get UserProfileModal() { return this._getModule('UserProfileModal'); },
|
|
||||||
get APIModule() { return this._getModule('APIModule'); },
|
|
||||||
get UserNoteStore() { return this._getModule('UserNoteStore'); },
|
|
||||||
|
|
||||||
get DiscordPermissions() { return this.DiscordConstants.Permissions; }
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class DiscordApi {
|
|
||||||
|
|
||||||
static get modules() { return Modules }
|
|
||||||
static get User() { return User }
|
|
||||||
static get Channel() { return Channel }
|
|
||||||
static get Guild() { return Guild }
|
|
||||||
static get Message() { return Message }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of loaded guilds.
|
|
||||||
* @type {List<Guild>}
|
|
||||||
*/
|
|
||||||
static get guilds() {
|
|
||||||
const guilds = Modules.GuildStore.getGuilds();
|
|
||||||
return List.from(Object.entries(guilds), ([i, g]) => Guild.from(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of loaded channels.
|
|
||||||
* @type {List<Channel>}
|
|
||||||
*/
|
|
||||||
static get channels() {
|
|
||||||
const channels = Modules.ChannelStore.getChannels();
|
|
||||||
return List.from(Object.entries(channels), ([i, c]) => Channel.from(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of loaded users.
|
|
||||||
* @type {List<User>}
|
|
||||||
*/
|
|
||||||
static get users() {
|
|
||||||
const users = Modules.UserStore.getUsers();
|
|
||||||
return List.from(Object.entries(users), ([i, u]) => User.from(u));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An object mapping guild IDs to their member counts.
|
|
||||||
* @type {Object}
|
|
||||||
*/
|
|
||||||
static get memberCounts() {
|
|
||||||
return Modules.MemberCountStore.getMemberCounts();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of guilds in the order they appear in the server list.
|
|
||||||
* @type {List<Guild>}
|
|
||||||
*/
|
|
||||||
static get sortedGuilds() {
|
|
||||||
const guilds = Modules.SortedGuildStore.getSortedGuilds();
|
|
||||||
return List.from(guilds, g => Guild.from(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array of guild IDs in the order they appear in the server list.
|
|
||||||
* @type {Number[]}
|
|
||||||
*/
|
|
||||||
static get guildPositions() {
|
|
||||||
return Modules.SortedGuildStore.guildPositions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The currently selected guild.
|
|
||||||
* @type {Guild}
|
|
||||||
*/
|
|
||||||
static get currentGuild() {
|
|
||||||
const guild = Modules.GuildStore.getGuild(Modules.SelectedGuildStore.getGuildId());
|
|
||||||
if (guild) return Guild.from(guild);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The currently selected channel.
|
|
||||||
* @type {Channel}
|
|
||||||
*/
|
|
||||||
static get currentChannel() {
|
|
||||||
const channel = Modules.ChannelStore.getChannel(Modules.SelectedChannelStore.getChannelId());
|
|
||||||
if (channel) return Channel.from(channel);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current user.
|
|
||||||
* @type {User}
|
|
||||||
*/
|
|
||||||
static get currentUser() {
|
|
||||||
const user = Modules.UserStore.getCurrentUser();
|
|
||||||
if (user) return User.from(user);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of the current user's friends.
|
|
||||||
* @type {List<User>}
|
|
||||||
*/
|
|
||||||
static get friends() {
|
|
||||||
const friends = Modules.RelationshipStore.getFriendIDs();
|
|
||||||
return List.from(friends, id => User.fromId(id));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* User settings
|
|
||||||
*/
|
|
||||||
static get UserSettings() {
|
|
||||||
return UserSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UserSettings {
|
|
||||||
/**
|
|
||||||
* Opens Discord's settings UI.
|
|
||||||
*/
|
|
||||||
static open(section = 'ACCOUNT') {
|
|
||||||
Modules.UserSettingsWindow.setSection(section);
|
|
||||||
Modules.UserSettingsWindow.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The user's current status. Either "online", "idle", "dnd" or "invisible".
|
|
||||||
* @type {String}
|
|
||||||
*/
|
|
||||||
static get status() { return Modules.UserSettingsStore.status }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The user's selected explicit content filter level.
|
|
||||||
* 0 == off, 1 == everyone except friends, 2 == everyone
|
|
||||||
* Configurable in the privacy and safety panel.
|
|
||||||
* @type {Number}
|
|
||||||
*/
|
|
||||||
static get explicitContentFilter() { return Modules.UserSettingsStore.explicitContentFilter }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to disallow direct messages from server members by default.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get defaultGuildsRestricted() { return Modules.UserSettingsStore.defaultGuildsRestricted }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array of guilds to disallow direct messages from their members.
|
|
||||||
* This is bypassed if the member is has another mutual guild with this disabled, or the member is friends with the current user.
|
|
||||||
* Configurable in each server's privacy settings.
|
|
||||||
* @type {Guild[]}
|
|
||||||
*/
|
|
||||||
static get restrictedGuildIds() { return Modules.UserSettingsStore.restrictedGuilds }
|
|
||||||
|
|
||||||
static get restrictedGuilds() {
|
|
||||||
return List.from(this.restrictedGuildIds, id => Guild.fromId(id) || id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array of flags specifying who should be allowed to add the current user as a friend.
|
|
||||||
* If everyone is checked, this will only have one item, "all". Otherwise it has either "mutual_friends", "mutual_guilds", both or neither.
|
|
||||||
* Configurable in the privacy and safety panel.
|
|
||||||
* @type {Array}
|
|
||||||
*/
|
|
||||||
static get friendSourceFlags() { return Object.keys(Modules.UserSettingsStore.friendSourceFlags) }
|
|
||||||
static get friendSourceEveryone() { return this.friendSourceFlags.include('all') }
|
|
||||||
static get friendSourceMutual_friends() { return this.friendSourceFlags.include('all') || this.friendSourceFlags.include('mutual_friends') }
|
|
||||||
static get friendSourceMutual_guilds() { return this.friendSourceFlags.include('all') || this.friendSourceFlags.include('mutual_guilds') }
|
|
||||||
static get friendSourceAnyone() { return this.friendSourceFlags.length > 0 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to automatically add accounts from other platforms running on the user's computer.
|
|
||||||
* Configurable in the connections panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get detectPlatformAccounts() { return Modules.UserSettingsStore.detectPlatformAccounts }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of seconds Discord will wait for activity before sending mobile push notifications.
|
|
||||||
* Configurable in the notifications panel.
|
|
||||||
* @type {Number}
|
|
||||||
*/
|
|
||||||
static get afkTimeout() { return Modules.UserSettingsStore.afkTimeout }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to display the currently running game as a status message.
|
|
||||||
* Configurable in the games panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get showCurrentGame() { return Modules.UserSettingsStore.showCurrentGame }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to show images uploaded directly to Discord.
|
|
||||||
* Configurable in the text and images panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get inlineAttachmentMedia() { return Modules.UserSettingsStore.inlineAttachmentMedia }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to show images linked in Discord.
|
|
||||||
* Configurable in the text and images panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get inlineEmbedMedia() { return Modules.UserSettingsStore.inlineEmbedMedia }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to automatically play GIFs when the Discord window is active without having to hover the mouse over the image.
|
|
||||||
* Configurable in the text and images panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get autoplayGifs() { return Modules.UserSettingsStore.gifAutoPlay }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to show content from HTTP[s] links as embeds.
|
|
||||||
* Configurable in the text and images panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get showEmbeds() { return Modules.UserSettingsStore.renderEmbeds }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to show a message's reactions.
|
|
||||||
* Configurable in the text and images panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get showReactions() { return Modules.UserSettingsStore.renderReactions }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to play animated emoji.
|
|
||||||
* Configurable in the text and images panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get animateEmoji() { return Modules.UserSettingsStore.animateEmoji }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to convert ASCII emoticons to emoji.
|
|
||||||
* Configurable in the text and images panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get convertEmoticons() { return Modules.UserSettingsStore.convertEmoticons }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to allow playing text-to-speech messages.
|
|
||||||
* Configurable in the text and images panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get allowTts() { return Modules.UserSettingsStore.enableTTSCommand }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The user's selected theme. Either "dark" or "light".
|
|
||||||
* Configurable in the appearance panel.
|
|
||||||
* @type {String}
|
|
||||||
*/
|
|
||||||
static get theme() { return Modules.UserSettingsStore.theme }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the user has enabled compact mode.
|
|
||||||
* `true` if compact mode is enabled, `false` if cozy mode is enabled.
|
|
||||||
* Configurable in the appearance panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get displayCompact() { return Modules.UserSettingsStore.messageDisplayCompact }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the user has enabled developer mode.
|
|
||||||
* Currently only adds a "Copy ID" option to the context menu on users, guilds and channels.
|
|
||||||
* Configurable in the appearance panel.
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
static get developerMode() { return Modules.UserSettingsStore.developerMode }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The user's selected language code.
|
|
||||||
* Configurable in the language panel.
|
|
||||||
* @type {String}
|
|
||||||
*/
|
|
||||||
static get locale() { return Modules.UserSettingsStore.locale }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The user's timezone offset in hours.
|
|
||||||
* This is not configurable.
|
|
||||||
* @type {Number}
|
|
||||||
*/
|
|
||||||
static get timezoneOffset() { return Modules.UserSettingsStore.timezoneOffset }
|
|
||||||
}
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Discord API
|
||||||
|
* 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 { List } from 'structs';
|
||||||
|
import { User, Channel, Guild, Message } from 'discordstructs';
|
||||||
|
import Reflection from '../reflection';
|
||||||
|
import UserSettings from './usersettings';
|
||||||
|
|
||||||
|
export { UserSettings };
|
||||||
|
|
||||||
|
export const Modules = {
|
||||||
|
_getModule(name) {
|
||||||
|
const foundModule = Reflection.module.byName(name);
|
||||||
|
if (!foundModule) return null;
|
||||||
|
delete this[name];
|
||||||
|
return this[name] = foundModule;
|
||||||
|
},
|
||||||
|
|
||||||
|
get ChannelSelector() { return this._getModule('ChannelSelector'); },
|
||||||
|
get MessageActions() { return this._getModule('MessageActions'); },
|
||||||
|
get MessageParser() { return this._getModule('MessageParser'); },
|
||||||
|
get MessageStore() { return this._getModule('MessageStore'); },
|
||||||
|
get EmojiUtils() { return this._getModule('EmojiUtils'); },
|
||||||
|
get PermissionUtils() { return this._getModule('Permissions'); },
|
||||||
|
get SortedGuildStore() { return this._getModule('SortedGuildStore'); },
|
||||||
|
get PrivateChannelActions() { return this._getModule('PrivateChannelActions'); },
|
||||||
|
get GuildMemberStore() { return this._getModule('GuildMemberStore'); },
|
||||||
|
get GuildChannelsStore() { return this._getModule('GuildChannelsStore'); },
|
||||||
|
get MemberCountStore() { return this._getModule('MemberCountStore'); },
|
||||||
|
get GuildActions() { return this._getModule('GuildActions'); },
|
||||||
|
get NavigationUtils() { return this._getModule('NavigationUtils'); },
|
||||||
|
get GuildPermissions() { return this._getModule('GuildPermissions'); },
|
||||||
|
get DiscordConstants() { return this._getModule('DiscordConstants'); },
|
||||||
|
get ChannelStore() { return this._getModule('ChannelStore'); },
|
||||||
|
get GuildStore() { return this._getModule('GuildStore'); },
|
||||||
|
get SelectedGuildStore() { return this._getModule('SelectedGuildStore'); },
|
||||||
|
get SelectedChannelStore() { return this._getModule('SelectedChannelStore'); },
|
||||||
|
get UserStore() { return this._getModule('UserStore'); },
|
||||||
|
get RelationshipStore() { return this._getModule('RelationshipStore'); },
|
||||||
|
get RelationshipManager() { return this._getModule('RelationshipManager'); },
|
||||||
|
get ChangeNicknameModal() { return this._getModule('ChangeNicknameModal'); },
|
||||||
|
get UserInfoStore() { return this._getModule('UserInfoStore'); },
|
||||||
|
get UserSettingsStore() { return this._getModule('UserSettingsStore'); },
|
||||||
|
get UserSettingsUpdater() { return this._getModule('UserSettingsUpdater'); },
|
||||||
|
get AccessibilityStore() { return this._getModule('AccessibilityStore'); },
|
||||||
|
get AccessibilitySettingsUpdater() { return this._getModule('AccessibilitySettingsUpdater'); },
|
||||||
|
get UserSettingsWindow() { return this._getModule('UserSettingsWindow'); },
|
||||||
|
get UserStatusStore() { return this._getModule('UserStatusStore'); },
|
||||||
|
get ChannelSettingsWindow() { return this._getModule('ChannelSettingsWindow'); },
|
||||||
|
get GuildSettingsWindow() { return this._getModule('GuildSettingsWindow'); },
|
||||||
|
get CreateChannelModal() { return this._getModule('CreateChannelModal'); },
|
||||||
|
get PruneMembersModal() { return this._getModule('PruneMembersModal'); },
|
||||||
|
get NotificationSettingsModal() { return this._getModule('NotificationSettingsModal'); },
|
||||||
|
get PrivacySettingsModal() { return this._getModule('PrivacySettingsModal'); },
|
||||||
|
get UserProfileModal() { return this._getModule('UserProfileModal'); },
|
||||||
|
get APIModule() { return this._getModule('APIModule'); },
|
||||||
|
get UserNoteStore() { return this._getModule('UserNoteStore'); },
|
||||||
|
get KeyboardCombosModal() { return this._getModule('KeyboardCombosModal'); },
|
||||||
|
|
||||||
|
get DiscordPermissions() { return this.DiscordConstants.Permissions; }
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DiscordApi {
|
||||||
|
|
||||||
|
static get modules() { return Modules }
|
||||||
|
static get User() { return User }
|
||||||
|
static get Channel() { return Channel }
|
||||||
|
static get Guild() { return Guild }
|
||||||
|
static get Message() { return Message }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of loaded guilds.
|
||||||
|
* @type {List<Guild>}
|
||||||
|
*/
|
||||||
|
static get guilds() {
|
||||||
|
const guilds = Modules.GuildStore.getGuilds();
|
||||||
|
return List.from(Object.values(guilds), g => Guild.from(g));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of loaded channels.
|
||||||
|
* @type {List<Channel>}
|
||||||
|
*/
|
||||||
|
static get channels() {
|
||||||
|
const channels = Modules.ChannelStore.getChannels();
|
||||||
|
return List.from(Object.values(channels), c => Channel.from(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of loaded users.
|
||||||
|
* @type {List<User>}
|
||||||
|
*/
|
||||||
|
static get users() {
|
||||||
|
const users = Modules.UserStore.getUsers();
|
||||||
|
return List.from(Object.values(users), u => User.from(u));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object mapping guild IDs to their member counts.
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
static get memberCounts() {
|
||||||
|
return Modules.MemberCountStore.getMemberCounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of guilds in the order they appear in the server list.
|
||||||
|
* @type {List<Guild>}
|
||||||
|
*/
|
||||||
|
static get sortedGuilds() {
|
||||||
|
const guilds = Modules.SortedGuildStore.getSortedGuilds();
|
||||||
|
return List.from(guilds, g => Guild.from(g));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of guild IDs in the order they appear in the server list.
|
||||||
|
* @type {Number[]}
|
||||||
|
*/
|
||||||
|
static get guildPositions() {
|
||||||
|
return Modules.SortedGuildStore.guildPositions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently selected guild.
|
||||||
|
* @type {Guild}
|
||||||
|
*/
|
||||||
|
static get currentGuild() {
|
||||||
|
const guild = Modules.GuildStore.getGuild(Modules.SelectedGuildStore.getGuildId());
|
||||||
|
return guild ? Guild.from(guild) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently selected channel.
|
||||||
|
* @type {Channel}
|
||||||
|
*/
|
||||||
|
static get currentChannel() {
|
||||||
|
const channel = Modules.ChannelStore.getChannel(Modules.SelectedChannelStore.getChannelId());
|
||||||
|
return channel ? Channel.from(channel) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current user.
|
||||||
|
* @type {User}
|
||||||
|
*/
|
||||||
|
static get currentUser() {
|
||||||
|
const user = Modules.UserStore.getCurrentUser();
|
||||||
|
return user ? User.from(user) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the current user's friends.
|
||||||
|
* @type {List<User>}
|
||||||
|
*/
|
||||||
|
static get friends() {
|
||||||
|
const friends = Modules.RelationshipStore.getFriendIDs();
|
||||||
|
return List.from(friends, id => User.fromId(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a user is logged in.
|
||||||
|
*/
|
||||||
|
static get authenticated() {
|
||||||
|
return !Modules.UserInfoStore.isGuest();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User settings.
|
||||||
|
*/
|
||||||
|
static get UserSettings() {
|
||||||
|
return UserSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
static showKeyboardCombosModal() {
|
||||||
|
Modules.KeyboardCombosModal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,629 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Discord API
|
||||||
|
* 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, { Modules } from '.';
|
||||||
|
import EventEmitter from 'events';
|
||||||
|
import { Utils } from 'common';
|
||||||
|
import { List } from 'structs';
|
||||||
|
import { User, Channel, Guild, Message } from 'discordstructs';
|
||||||
|
import Events from '../events';
|
||||||
|
|
||||||
|
const remoteSettingsKeys = {
|
||||||
|
showCurrentGame: 'show_current_game',
|
||||||
|
inlineAttachmentMedia: 'inline_attachment_media',
|
||||||
|
inlineEmbedMedia: 'inline_embed_media',
|
||||||
|
gifAutoPlay: 'gif_auto_play',
|
||||||
|
renderEmbeds: 'render_embeds',
|
||||||
|
renderReactions: 'render_reactions',
|
||||||
|
renderSpoilers: 'render_spoilers',
|
||||||
|
showInAppNotifications: 'show_in_app_notifications',
|
||||||
|
animateEmoji: 'animate_emoji',
|
||||||
|
sync: 'sync',
|
||||||
|
theme: 'theme',
|
||||||
|
enableTTSCommand: 'enable_tts_command',
|
||||||
|
messageDisplayCompact: 'message_display_compact',
|
||||||
|
locale: 'locale',
|
||||||
|
convertEmoticons: 'convert_emoticons',
|
||||||
|
restrictedGuilds: 'restricted_guilds',
|
||||||
|
friendSourceFlags: 'friend_source_flags',
|
||||||
|
developerMode: 'developer_mode',
|
||||||
|
guildPositions: 'guild_positions',
|
||||||
|
detectPlatformAccounts: 'detect_platform_accounts',
|
||||||
|
status: 'status',
|
||||||
|
explicitContentFilter: 'explicit_content_filter',
|
||||||
|
disableGamesTab: 'disable_games_tab',
|
||||||
|
defaultGuildsRestricted: 'default_guilds_restricted',
|
||||||
|
afkTimeout: 'afk_timeout',
|
||||||
|
timezoneOffset: 'timezone_offset'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default new class UserSettings extends EventEmitter {
|
||||||
|
|
||||||
|
init() {
|
||||||
|
for (const [key, discordKey] of Object.entries({
|
||||||
|
'status': 'status',
|
||||||
|
'explicitContentFilter': 'explicitContentFilter',
|
||||||
|
'defaultGuildsRestricted': 'defaultGuildsRestricted',
|
||||||
|
'restrictedGuildIds': 'restrictedGuilds',
|
||||||
|
// 'friendSourceFlags',
|
||||||
|
'detectPlatformAccounts': 'detectPlatformAccounts',
|
||||||
|
'afkTimeout': 'afkTimeout',
|
||||||
|
'showCurrentGame': 'showCurrentGame',
|
||||||
|
'inlineAttachmentMedia': 'inlineAttachmentMedia',
|
||||||
|
'inlineEmbedMedia': 'inlineEmbedMedia',
|
||||||
|
'autoplayGifs': 'gifAutoPlay',
|
||||||
|
'showEmbeds': 'renderEmbeds',
|
||||||
|
'showReactions': 'renderReactions',
|
||||||
|
'showSpoilers': 'renderSpoilers',
|
||||||
|
'animateEmoji': 'animateEmoji',
|
||||||
|
'convertEmoticons': 'convertEmoticons',
|
||||||
|
'allowTts': 'enableTTSCommand',
|
||||||
|
'theme': 'theme',
|
||||||
|
'displayCompact': 'messageDisplayCompact',
|
||||||
|
// 'disableGamesTab',
|
||||||
|
'developerMode': 'developerMode',
|
||||||
|
'locale': 'locale',
|
||||||
|
'timezoneOffset': 'timezoneOffset',
|
||||||
|
})) {
|
||||||
|
this['_' + discordKey] = this.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._friendSourceFlags = Modules.UserSettingsStore.friendSourceFlags;
|
||||||
|
this._disableGamesTab = !this.showActivityTab;
|
||||||
|
|
||||||
|
Events.on('discord-dispatch:USER_SETTINGS_UPDATE', event => {
|
||||||
|
for (const k of Object.keys(event.settings)) {
|
||||||
|
// No change
|
||||||
|
if (Utils.compare(event.settings[k], this['_' + k])) continue;
|
||||||
|
|
||||||
|
if (this['_update_' + k]) this['_update_' + k]();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this._colourblindMode = this.colourblindMode;
|
||||||
|
|
||||||
|
Events.on('discord-dispatch:ACCESSIBILITY_COLORBLIND_TOGGLE', () => {
|
||||||
|
if (Utils.compare(this.colourblindMode, this._colourblindMode)) return;
|
||||||
|
|
||||||
|
this.emit('colourblind-mode', this.colourblindMode, this._colourblindMode);
|
||||||
|
this._colourblindMode = this.colourblindMode;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens Discord's settings UI.
|
||||||
|
*/
|
||||||
|
open(section = 'ACCOUNT') {
|
||||||
|
Modules.UserSettingsWindow.open();
|
||||||
|
Modules.UserSettingsWindow.setSection(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates settings.
|
||||||
|
* @param {Object} data
|
||||||
|
* @param {boolean} [save=true]
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
async updateSettings(data, save = true) {
|
||||||
|
Modules.UserSettingsUpdater.updateLocalSettings(data);
|
||||||
|
|
||||||
|
if (save && DiscordApi.authenticated) {
|
||||||
|
await Modules.APIModule.patch({
|
||||||
|
url: Modules.DiscordConstants.Endpoints.SETTINGS,
|
||||||
|
body: this.toRemoteKeys(data)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toRemoteKeys(data) {
|
||||||
|
const body = {};
|
||||||
|
for (const k of Object.keys(data)) {
|
||||||
|
body[remoteSettingsKeys[k] || k] = data[k];
|
||||||
|
}
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates settings locally.
|
||||||
|
* @param {Object} data
|
||||||
|
*/
|
||||||
|
localUpdateSettings(data) {
|
||||||
|
this.updateSettings(data, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user's current status. Either "online", "idle", "dnd" or "invisible".
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
get status() {
|
||||||
|
// Reading _status tells Vue to watch it
|
||||||
|
return this._status, Modules.UserSettingsStore.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
set status(status) {
|
||||||
|
if (!['online', 'idle', 'dnd', 'invisible'].includes(status)) throw new Error('Invalid status.');
|
||||||
|
this.updateSettings({status});
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_status() {
|
||||||
|
this.emit('status', this.status, this._status);
|
||||||
|
this._status = this.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
get StatusOnline() { return 'online' }
|
||||||
|
get StatusIdle() { return 'idle' }
|
||||||
|
get StatusDND() { return 'dnd' }
|
||||||
|
get StatusInvisible() { return 'invisible' }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user's selected explicit content filter level.
|
||||||
|
* 0 == off, 1 == everyone except friends, 2 == everyone
|
||||||
|
* Configurable in the privacy and safety panel.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get explicitContentFilter() { return this._explicitContentFilter, Modules.UserSettingsStore.explicitContentFilter }
|
||||||
|
|
||||||
|
set explicitContentFilter(explicitContentFilter) {
|
||||||
|
if (![0, 1, 2].includes(explicitContentFilter)) throw new Error('Invalid explicit content filter level.');
|
||||||
|
this.updateSettings({explicitContentFilter});
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_explicitContentFilter() {
|
||||||
|
this.emit('explicit-content-filter', this.explicitContentFilter, this._explicitContentFilter);
|
||||||
|
this._explicitContentFilter = this.explicitContentFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
get ExplicitContentFilterDisabled() { return 0 }
|
||||||
|
get ExplicitContentFilterExceptFriends() { return 1 }
|
||||||
|
get ExplicitContentFilterEnabled() { return 2 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to disallow direct messages from server members by default.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get defaultGuildsRestricted() { return this._defaultGuildsRestricted, Modules.UserSettingsStore.defaultGuildsRestricted }
|
||||||
|
|
||||||
|
set defaultGuildsRestricted(defaultGuildsRestricted) {
|
||||||
|
this.updateSettings({defaultGuildsRestricted: !!defaultGuildsRestricted});
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_defaultGuildsRestricted() {
|
||||||
|
this.emit('default-guilds-restricted', this.defaultGuildsRestricted, this._defaultGuildsRestricted);
|
||||||
|
this._defaultGuildsRestricted = this.defaultGuildsRestricted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of guilds to disallow direct messages from their members.
|
||||||
|
* This is bypassed if the member is has another mutual guild with this disabled, or the member is friends with the current user.
|
||||||
|
* Configurable in each server's privacy settings.
|
||||||
|
* @type {Guild[]}
|
||||||
|
*/
|
||||||
|
get restrictedGuilds() {
|
||||||
|
return List.from(this.restrictedGuildIds, id => Guild.fromId(id) || id);
|
||||||
|
}
|
||||||
|
|
||||||
|
get restrictedGuildIds() { return this._restrictedGuilds, Modules.UserSettingsStore.restrictedGuilds }
|
||||||
|
|
||||||
|
_update_restrictedGuilds() {
|
||||||
|
this.emit('restricted-guilds', this.restrictedGuildIds, this._restrictedGuilds);
|
||||||
|
this._restrictedGuilds = this.restrictedGuildIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of flags specifying who should be allowed to add the current user as a friend.
|
||||||
|
* If everyone is checked, this will only have one item, "all". Otherwise it has either "mutual_friends", "mutual_guilds", both or neither.
|
||||||
|
* Configurable in the privacy and safety panel.
|
||||||
|
* @type {string[]}
|
||||||
|
*/
|
||||||
|
get friendSourceFlags() { return this._friendSourceFlags, Object.keys(Modules.UserSettingsStore.friendSourceFlags).filter(f => Modules.UserSettingsStore.friendSourceFlags[f]) }
|
||||||
|
get friendSourceEveryone() { return this.friendSourceFlags.includes('all') }
|
||||||
|
get friendSourceMutualFriends() { return this.friendSourceFlags.includes('all') || this.friendSourceFlags.includes('mutual_friends') }
|
||||||
|
get friendSourceMutualGuilds() { return this.friendSourceFlags.includes('all') || this.friendSourceFlags.includes('mutual_guilds') }
|
||||||
|
get friendSourceAnyone() { return this.friendSourceFlags.length > 0 }
|
||||||
|
|
||||||
|
set friendSourceFlags(friendSourceFlags) {
|
||||||
|
this.updateSettings({friendSourceFlags: {
|
||||||
|
all: friendSourceFlags.includes('all'),
|
||||||
|
mutual_friends: friendSourceFlags.includes('all') || friendSourceFlags.includes('mutual_friends'),
|
||||||
|
mutual_guilds: friendSourceFlags.includes('all') || friendSourceFlags.includes('mutual_guilds')
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
set friendSourceEveryone(friendSourceEveryone) {
|
||||||
|
if (!!friendSourceEveryone === this.friendSourceEveryone) return;
|
||||||
|
this.friendSourceFlags = friendSourceEveryone ? ['all'] : ['mutual_friends', 'mutual_guilds'];
|
||||||
|
}
|
||||||
|
|
||||||
|
set friendSourceMutualFriends(friendSourceMutualFriends) {
|
||||||
|
if (!!friendSourceMutualFriends === this.friendSourceMutualFriends) return;
|
||||||
|
this.friendSourceFlags = friendSourceMutualFriends ? this.friendSourceFlags.concat(['mutual_friends']) :
|
||||||
|
this.friendSourceFlags.includes('all') ? ['mutual_guilds'] :
|
||||||
|
this.friendSourceFlags.filter(f => f !== 'mutual_friends');
|
||||||
|
}
|
||||||
|
|
||||||
|
set friendSourceMutualGuilds(friendSourceMutualGuilds) {
|
||||||
|
if (!!friendSourceMutualGuilds === this.friendSourceMutualGuilds) return;
|
||||||
|
this.friendSourceFlags = friendSourceMutualGuilds ? this.friendSourceFlags.concat(['mutual_guilds']) :
|
||||||
|
this.friendSourceFlags.includes('all') ? ['mutual_friends'] :
|
||||||
|
this.friendSourceFlags.filter(f => f !== 'mutual_guilds');
|
||||||
|
}
|
||||||
|
|
||||||
|
set friendSourceAnyone(friendSourceAnyone) {
|
||||||
|
if (!!friendSourceAnyone === this.friendSourceAnyone) return;
|
||||||
|
this.friendSourceFlags = friendSourceAnyone ? ['mutual_friends', 'mutual_guilds'] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_friendSourceFlags() {
|
||||||
|
this.emit('friend-source-flags', this.friendSourceFlags, Object.keys(this._friendSourceFlags).filter(f => this._friendSourceFlags[f]));
|
||||||
|
this._friendSourceFlags = this.friendSourceFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to automatically add accounts from other platforms running on the user's computer.
|
||||||
|
* Configurable in the connections panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get detectPlatformAccounts() { return this._detectPlatformAccounts, Modules.UserSettingsStore.detectPlatformAccounts }
|
||||||
|
|
||||||
|
set detectPlatformAccounts(detectPlatformAccounts) {
|
||||||
|
this.updateSettings({detectPlatformAccounts: !!detectPlatformAccounts});
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_detectPlatformAccounts() {
|
||||||
|
this.emit('detect-platform-accounts', this.detectPlatformAccounts, this._detectPlatformAccounts);
|
||||||
|
this._detectPlatformAccounts = this.detectPlatformAccounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of seconds Discord will wait for activity before sending mobile push notifications.
|
||||||
|
* Configurable in the notifications panel.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get afkTimeout() { return this._afkTimeout, Modules.UserSettingsStore.afkTimeout }
|
||||||
|
|
||||||
|
set afkTimeout(afkTimeout) {
|
||||||
|
this.updateSettings({afkTimeout: parseInt(afkTimeout)});
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_afkTimeout() {
|
||||||
|
this.emit('afk-timeout', this.afkTimeout, this._afkTimeout);
|
||||||
|
this._afkTimeout = this.afkTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
get AfkTimeout1Minute() { return 60 }
|
||||||
|
get AfkTimeout2Minutes() { return 120 }
|
||||||
|
get AfkTimeout3Minutes() { return 180 }
|
||||||
|
get AfkTimeout4Minutes() { return 240 }
|
||||||
|
get AfkTimeout5Minutes() { return 300 }
|
||||||
|
get AfkTimeout6Minutes() { return 360 }
|
||||||
|
get AfkTimeout7Minutes() { return 420 }
|
||||||
|
get AfkTimeout8Minutes() { return 480 }
|
||||||
|
get AfkTimeout9Minutes() { return 540 }
|
||||||
|
get AfkTimeout10Minutes() { return 600 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to display the currently running game as a status message.
|
||||||
|
* Configurable in the games panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get showCurrentGame() { return this._showCurrentGame, Modules.UserSettingsStore.showCurrentGame }
|
||||||
|
|
||||||
|
set showCurrentGame(showCurrentGame) {
|
||||||
|
this.updateSettings({showCurrentGame: !!showCurrentGame});
|
||||||
|
}
|
||||||
|
set localShowCurrentGame(showCurrentGame) {
|
||||||
|
this.updateSettings({showCurrentGame: !!showCurrentGame}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_showCurrentGame() {
|
||||||
|
this.emit('restricted-guilds', this.showCurrentGame, this._showCurrentGame);
|
||||||
|
this._showCurrentGame = this.showCurrentGame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show images uploaded directly to Discord.
|
||||||
|
* Configurable in the text and images panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get inlineAttachmentMedia() { return this._inlineAttachmentMedia, Modules.UserSettingsStore.inlineAttachmentMedia }
|
||||||
|
|
||||||
|
set inlineAttachmentMedia(inlineAttachmentMedia) {
|
||||||
|
this.updateSettings({inlineAttachmentMedia: !!inlineAttachmentMedia});
|
||||||
|
}
|
||||||
|
set localInlineAttachmentMedia(inlineAttachmentMedia) {
|
||||||
|
this.updateSettings({inlineAttachmentMedia: !!inlineAttachmentMedia}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_inlineAttachmentMedia() {
|
||||||
|
this.emit('inline-attachment-media', this.inlineAttachmentMedia, this._inlineAttachmentMedia);
|
||||||
|
this._inlineAttachmentMedia = this.inlineAttachmentMedia;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show images linked in Discord.
|
||||||
|
* Configurable in the text and images panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get inlineEmbedMedia() { return this._inlineEmbedMedia, Modules.UserSettingsStore.inlineEmbedMedia }
|
||||||
|
|
||||||
|
set inlineEmbedMedia(inlineEmbedMedia) {
|
||||||
|
this.updateSettings({inlineEmbedMedia: !!inlineEmbedMedia});
|
||||||
|
}
|
||||||
|
set localInlineEmbedMedia(inlineEmbedMedia) {
|
||||||
|
this.updateSettings({inlineEmbedMedia: !!inlineEmbedMedia}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_inlineEmbedMedia() {
|
||||||
|
this.emit('inline-embed-media', this.inlineEmbedMedia, this._inlineEmbedMedia);
|
||||||
|
this._inlineEmbedMedia = this.inlineEmbedMedia;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to automatically play GIFs when the Discord window is active without having to hover the mouse over the image.
|
||||||
|
* Configurable in the text and images panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get autoplayGifs() { return this._gifAutoPlay, Modules.UserSettingsStore.gifAutoPlay }
|
||||||
|
|
||||||
|
set autoplayGifs(gifAutoPlay) {
|
||||||
|
this.updateSettings({gifAutoPlay: !!gifAutoPlay});
|
||||||
|
}
|
||||||
|
set localAutoplayGifs(gifAutoPlay) {
|
||||||
|
this.updateSettings({gifAutoPlay: !!gifAutoPlay}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_gifAutoPlay() {
|
||||||
|
this.emit('autoplay-gifs', this.autoplayGifs, this._gifAutoPlay);
|
||||||
|
this._gifAutoPlay = this.autoplayGifs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show content from HTTP[s] links as embeds.
|
||||||
|
* Configurable in the text and images panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get showEmbeds() { return this._renderEmbeds, Modules.UserSettingsStore.renderEmbeds }
|
||||||
|
|
||||||
|
set showEmbeds(renderEmbeds) {
|
||||||
|
this.updateSettings({renderEmbeds: !!renderEmbeds});
|
||||||
|
}
|
||||||
|
set localShowEmbeds(renderEmbeds) {
|
||||||
|
this.updateSettings({renderEmbeds: !!renderEmbeds}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_renderEmbeds() {
|
||||||
|
this.emit('show-embeds', this.showEmbeds, this._renderEmbeds);
|
||||||
|
this._renderEmbeds = this.showEmbeds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show a message's reactions.
|
||||||
|
* Configurable in the text and images panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get showReactions() { return this._renderReactions, Modules.UserSettingsStore.renderReactions }
|
||||||
|
|
||||||
|
set showReactions(renderReactions) {
|
||||||
|
this.updateSettings({renderReactions: !!renderReactions});
|
||||||
|
}
|
||||||
|
set localShowReactions(renderReactions) {
|
||||||
|
this.updateSettings({renderReactions: !!renderReactions}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_showReactions() {
|
||||||
|
this.emit('show-reactions', this.showReactions, this._showReactions);
|
||||||
|
this._showReactions = this.showReactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When to show spoilers.
|
||||||
|
* Configurable in the text and images panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get showSpoilers() { return this._renderSpoilers, Modules.UserSettingsStore.renderSpoilers }
|
||||||
|
|
||||||
|
set showSpoilers(renderSpoilers) {
|
||||||
|
if (!['ON_CLICK', 'IF_MODERATOR', 'ALWAYS'].includes(renderSpoilers)) throw new Error('Invalid show spoilers value.');
|
||||||
|
this.updateSettings({renderSpoilers: !!renderSpoilers}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_renderSpoilers() {
|
||||||
|
this.emit('show-spoilers', this.showSpoilers, this._renderSpoilers);
|
||||||
|
this._renderSpoilers = this.showSpoilers;
|
||||||
|
}
|
||||||
|
|
||||||
|
get ShowSpoilersOnClick() { return 'ON_CLICK' }
|
||||||
|
get ShowSpoilersIfModerator() { return 'IF_MODERATOR' }
|
||||||
|
get ShowSpoilersAlways() { return 'ALWAYS' }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to play animated emoji.
|
||||||
|
* Configurable in the text and images panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get animateEmoji() { return this._animateEmoji, Modules.UserSettingsStore.animateEmoji }
|
||||||
|
|
||||||
|
set animateEmoji(animateEmoji) {
|
||||||
|
this.updateSettings({animateEmoji: !!animateEmoji});
|
||||||
|
}
|
||||||
|
set localAnimateEmoji(animateEmoji) {
|
||||||
|
this.updateSettings({animateEmoji: !!animateEmoji}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_animateEmoji() {
|
||||||
|
this.emit('animate-emoji', this.animateEmoji, this._animateEmoji);
|
||||||
|
this._animateEmoji = this.animateEmoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to convert ASCII emoticons to emoji.
|
||||||
|
* Configurable in the text and images panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get convertEmoticons() { return this._convertEmoticons, Modules.UserSettingsStore.convertEmoticons }
|
||||||
|
|
||||||
|
set convertEmoticons(convertEmoticons) {
|
||||||
|
this.updateSettings({convertEmoticons: !!convertEmoticons});
|
||||||
|
}
|
||||||
|
set localConvertEmoticons(convertEmoticons) {
|
||||||
|
this.updateSettings({convertEmoticons: !!convertEmoticons}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_convertEmoticons() {
|
||||||
|
this.emit('convert-emoticons', this.convertEmoticons, this._convertEmoticons);
|
||||||
|
this._convertEmoticons = this.convertEmoticons;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to allow playing text-to-speech messages.
|
||||||
|
* Configurable in the text and images panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get allowTts() { return this._enableTTSCommand, Modules.UserSettingsStore.enableTTSCommand }
|
||||||
|
|
||||||
|
set allowTts(enableTTSCommand) {
|
||||||
|
this.updateSettings({enableTTSCommand: !!enableTTSCommand});
|
||||||
|
}
|
||||||
|
set localAllowTts(enableTTSCommand) {
|
||||||
|
this.updateSettings({enableTTSCommand: !!enableTTSCommand}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_enableTTSCommand() {
|
||||||
|
this.emit('allow-tts', this.allowTts, this._enableTTSCommand);
|
||||||
|
this._enableTTSCommand = this.allowTts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user's selected theme. Either "dark" or "light".
|
||||||
|
* Configurable in the appearance panel.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
get theme() { return this._theme, Modules.UserSettingsStore.theme }
|
||||||
|
|
||||||
|
set theme(theme) {
|
||||||
|
if (!['dark', 'light'].includes(theme)) throw new Error('Invalid theme.');
|
||||||
|
this.updateSettings({theme});
|
||||||
|
}
|
||||||
|
set localTheme(theme) {
|
||||||
|
if (!['dark', 'light'].includes(theme)) throw new Error('Invalid theme.');
|
||||||
|
this.updateSettings({theme}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_theme() {
|
||||||
|
this.emit('theme', this.theme, this._theme);
|
||||||
|
this._theme = this.theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
get ThemeDark() { return 'dark' }
|
||||||
|
get ThemeLight() { return 'light' }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user has enabled compact mode.
|
||||||
|
* `true` if compact mode is enabled, `false` if cozy mode is enabled.
|
||||||
|
* Configurable in the appearance panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get displayCompact() { return this._messageDisplayCompact, Modules.UserSettingsStore.messageDisplayCompact }
|
||||||
|
|
||||||
|
set displayCompact(messageDisplayCompact) {
|
||||||
|
this.updateSettings({messageDisplayCompact: !!messageDisplayCompact});
|
||||||
|
}
|
||||||
|
set localDisplayCompact(messageDisplayCompact) {
|
||||||
|
this.updateSettings({messageDisplayCompact: !!messageDisplayCompact}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_messageDisplayCompact() {
|
||||||
|
this.emit('inline-embed-media', this.displayCompact, this._messageDisplayCompact);
|
||||||
|
this._messageDisplayCompact = this.displayCompact;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user has enabled colourblind mode.
|
||||||
|
* Configurable in the appearance panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get colourblindMode() { return this._colourblindMode, Modules.AccessibilityStore.colorblindMode }
|
||||||
|
|
||||||
|
set colourblindMode(colourblindMode) {
|
||||||
|
if (!!colourblindMode === this.colourblindMode) return;
|
||||||
|
Modules.AccessibilitySettingsUpdater.toggleColorblindMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user has enabled the activity tab.
|
||||||
|
* Configurable in the appearance panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get showActivityTab() { return this._disableGamesTab, !Modules.UserSettingsStore.disableGamesTab }
|
||||||
|
|
||||||
|
set showActivityTab(disableGamesTab) {
|
||||||
|
this.updateSettings({disableGamesTab: !disableGamesTab});
|
||||||
|
}
|
||||||
|
set localShowActivityTab(disableGamesTab) {
|
||||||
|
this.updateSettings({disableGamesTab: !disableGamesTab}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_disableGamesTab() {
|
||||||
|
this.emit('show-activity-tab', this.showActivityTab, !this._disableGamesTab);
|
||||||
|
this._disableGamesTab = !this.showActivityTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user has enabled developer mode.
|
||||||
|
* Currently only adds a "Copy ID" option to the context menu on users, guilds and channels.
|
||||||
|
* Configurable in the appearance panel.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get developerMode() { return this._developerMode, Modules.UserSettingsStore.developerMode }
|
||||||
|
|
||||||
|
set developerMode(developerMode) {
|
||||||
|
this.updateSettings({developerMode: !!developerMode});
|
||||||
|
}
|
||||||
|
set localDeveloperMode(developerMode) {
|
||||||
|
this.updateSettings({developerMode: !!developerMode}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_developerMode() {
|
||||||
|
this.emit('developer-mode', this.developerMode, this._developerMode);
|
||||||
|
this._developerMode = this.developerMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user's selected language code.
|
||||||
|
* Configurable in the language panel.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
get locale() { return this._locale, Modules.UserSettingsStore.locale }
|
||||||
|
|
||||||
|
set locale(locale) {
|
||||||
|
this.updateSettings({locale: !!locale});
|
||||||
|
}
|
||||||
|
set localLocale(locale) {
|
||||||
|
this.updateSettings({locale: !!locale}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_locale() {
|
||||||
|
this.emit('locale', this.locale, this._locale);
|
||||||
|
this._locale = this.locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user's timezone offset in hours.
|
||||||
|
* This is not configurable.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get timezoneOffset() { return this._timezoneOffset, Modules.UserSettingsStore.timezoneOffset }
|
||||||
|
|
||||||
|
_update_timezoneOffset() {
|
||||||
|
this.emit('timezone-offset', this.timezoneOffset, this._timezoneOffset);
|
||||||
|
this._timezoneOffset = this.timezoneOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Dispatch Hook
|
||||||
|
* 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 Reflection from './reflection';
|
||||||
|
import { MonkeyPatch } from './patcher';
|
||||||
|
import Events from './events';
|
||||||
|
import EventListener from './eventlistener';
|
||||||
|
|
||||||
|
// Discord seems to like to dispatch some things multiple times
|
||||||
|
const dispatched = new WeakSet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discord event hook.
|
||||||
|
* @extends {EventListener}
|
||||||
|
*/
|
||||||
|
export default class extends EventListener {
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.hook();
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings() {
|
||||||
|
this.hook = this.hook.bind(this);
|
||||||
|
this.dispatch = this.dispatch.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
get eventBindings() {
|
||||||
|
return [
|
||||||
|
{ id: 'discord-ready', callback: this.hook }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
hook() {
|
||||||
|
const { Dispatcher } = Reflection.modules;
|
||||||
|
MonkeyPatch('BD:EVENTS', Dispatcher).after('dispatch', this.dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit callback.
|
||||||
|
*/
|
||||||
|
dispatch(Dispatcher, [event], retVal) {
|
||||||
|
if (dispatched.has(event)) return;
|
||||||
|
dispatched.add(event);
|
||||||
|
|
||||||
|
Events.emit('discord-dispatch', event);
|
||||||
|
Events.emit(`discord-dispatch:${event.type}`, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,8 +9,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ClientLogger as Logger } from 'common';
|
import { ClientLogger as Logger } from 'common';
|
||||||
import { SocketProxy, EventHook } from 'modules';
|
import { SocketProxy, EventHook, DispatchHook } from 'modules';
|
||||||
import { ProfileBadges, ClassNormaliser } from 'ui';
|
import { ProfileBadges, ClassNormaliser } from 'ui';
|
||||||
|
import { UserSettings } from './discordapi';
|
||||||
import Updater from './updater';
|
import Updater from './updater';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,6 +28,8 @@ export default class {
|
||||||
new ClassNormaliser(),
|
new ClassNormaliser(),
|
||||||
new SocketProxy(),
|
new SocketProxy(),
|
||||||
new EventHook(),
|
new EventHook(),
|
||||||
|
new DispatchHook(),
|
||||||
|
UserSettings,
|
||||||
Updater
|
Updater
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ export { default as Module } from './module';
|
||||||
export { default as EventListener } from './eventlistener';
|
export { default as EventListener } from './eventlistener';
|
||||||
export { default as SocketProxy } from './socketproxy';
|
export { default as SocketProxy } from './socketproxy';
|
||||||
export { default as EventHook } from './eventhook';
|
export { default as EventHook } from './eventhook';
|
||||||
|
export { default as DispatchHook } from './dispatchhook';
|
||||||
export { default as DiscordApi, Modules as DiscordApiModules } from './discordapi';
|
export { default as DiscordApi, Modules as DiscordApiModules } from './discordapi';
|
||||||
export { default as BdWebApi } from './bdwebapi';
|
export { default as BdWebApi } from './bdwebapi';
|
||||||
export { default as Connectivity } from './connectivity';
|
export { default as Connectivity } from './connectivity';
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Reflection Modules
|
||||||
|
* 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 { Filters } from 'common';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
React: Filters.byProperties(['createElement', 'cloneElement']),
|
||||||
|
ReactDOM: Filters.byProperties(['render', 'findDOMNode']),
|
||||||
|
|
||||||
|
Events: Filters.byPrototypeFields(['setMaxListeners', 'emit']),
|
||||||
|
|
||||||
|
/* Guild Info, Stores, and Utilities */
|
||||||
|
GuildStore: Filters.byProperties(['getGuild']),
|
||||||
|
SortedGuildStore: Filters.byProperties(['getSortedGuilds']),
|
||||||
|
SelectedGuildStore: Filters.byProperties(['getLastSelectedGuildId']),
|
||||||
|
GuildSync: Filters.byProperties(['getSyncedGuilds']),
|
||||||
|
GuildInfo: Filters.byProperties(['getAcronym']),
|
||||||
|
GuildChannelsStore: Filters.byProperties(['getChannels', 'getDefaultChannel']),
|
||||||
|
GuildMemberStore: Filters.byProperties(['getMember']),
|
||||||
|
MemberCountStore: Filters.byProperties(['getMemberCounts']),
|
||||||
|
GuildEmojiStore: Filters.byProperties(['getEmojis']),
|
||||||
|
GuildActions: Filters.byProperties(['markGuildAsRead']),
|
||||||
|
GuildPermissions: Filters.byProperties(['getGuildPermissions']),
|
||||||
|
|
||||||
|
/* Channel Store & Actions */
|
||||||
|
ChannelStore: Filters.byProperties(['getChannels', 'getDMFromUserId']),
|
||||||
|
SelectedChannelStore: Filters.byProperties(['getLastSelectedChannelId']),
|
||||||
|
ChannelActions: Filters.byProperties(['selectChannel']),
|
||||||
|
PrivateChannelActions: Filters.byProperties(['openPrivateChannel']),
|
||||||
|
ChannelSelector: Filters.byProperties(['selectGuild', 'selectChannel']),
|
||||||
|
VoiceChannelActions: Filters.byProperties(['selectVoiceChannel']),
|
||||||
|
|
||||||
|
/* Current User Info, State and Settings */
|
||||||
|
UserInfoStore: Filters.byProperties(['getToken']),
|
||||||
|
UserSettingsStore: Filters.byProperties(['guildPositions']),
|
||||||
|
AccessibilityStore: Filters.byProperties(['colorblindMode']),
|
||||||
|
AccountManager: Filters.byProperties(['register', 'login']),
|
||||||
|
UserSettingsUpdater: Filters.byProperties(['updateRemoteSettings']),
|
||||||
|
AccessibilitySettingsUpdater: Filters.byProperties(['toggleColorblindMode']),
|
||||||
|
OnlineWatcher: Filters.byProperties(['isOnline']),
|
||||||
|
CurrentUserIdle: Filters.byProperties(['getIdleTime']),
|
||||||
|
RelationshipStore: Filters.byProperties(['isBlocked', 'isFriend']),
|
||||||
|
RelationshipManager: Filters.byProperties(['addRelationship']),
|
||||||
|
MentionStore: Filters.byProperties(['getMentions']),
|
||||||
|
|
||||||
|
/* User Stores and Utils */
|
||||||
|
UserStore: Filters.byProperties(['getCurrentUser']),
|
||||||
|
UserStatusStore: Filters.byProperties(['getStatuses']),
|
||||||
|
UserTypingStore: Filters.byProperties(['isTyping']),
|
||||||
|
UserActivityStore: Filters.byProperties(['getActivity']),
|
||||||
|
UserNameResolver: Filters.byProperties(['getName']),
|
||||||
|
UserNoteStore: Filters.byProperties(['getNote']),
|
||||||
|
UserNoteActions: Filters.byProperties(['updateNote']),
|
||||||
|
DraftActions: Filters.byProperties(['changeDraft']),
|
||||||
|
|
||||||
|
/* Emoji Store and Utils */
|
||||||
|
EmojiInfo: Filters.byProperties(['isEmojiDisabled']),
|
||||||
|
EmojiUtils: Filters.byProperties(['getGuildEmoji']),
|
||||||
|
EmojiStore: Filters.byProperties(['getByCategory', 'EMOJI_NAME_RE']),
|
||||||
|
|
||||||
|
/* Invite Store and Utils */
|
||||||
|
InviteStore: Filters.byProperties(['getInvites']),
|
||||||
|
InviteResolver: Filters.byProperties(['findInvite']),
|
||||||
|
InviteActions: Filters.byProperties(['acceptInvite']),
|
||||||
|
|
||||||
|
/* Discord Objects & Utils */
|
||||||
|
DiscordConstants: Filters.byProperties(['Permissions', 'ActivityTypes', 'StatusTypes']),
|
||||||
|
Permissions: Filters.byProperties(['getHighestRole']),
|
||||||
|
ColorConverter: Filters.byProperties(['hex2int']),
|
||||||
|
ColorShader: Filters.byProperties(['darken']),
|
||||||
|
TinyColor: Filters.byPrototypeFields(['toRgb']),
|
||||||
|
ClassResolver: Filters.byProperties(['getClass']),
|
||||||
|
ButtonData: Filters.byProperties(['ButtonSizes']),
|
||||||
|
IconNames: Filters.byProperties(['IconNames']),
|
||||||
|
NavigationUtils: Filters.byProperties(['transitionTo', 'replaceWith', 'getHistory']),
|
||||||
|
|
||||||
|
/* Discord Messages */
|
||||||
|
MessageStore: Filters.byProperties(['getMessages']),
|
||||||
|
MessageActions: Filters.byProperties(['jumpToMessage', '_sendMessage']),
|
||||||
|
MessageQueue: Filters.byProperties(['enqueue']),
|
||||||
|
MessageParser: Filters.byProperties(['createMessage', 'parse', 'unparse']),
|
||||||
|
|
||||||
|
/* In-Game Overlay */
|
||||||
|
OverlayUserPopoutSettings: Filters.byProperties(['openUserPopout']),
|
||||||
|
OverlayUserPopoutInfo: Filters.byProperties(['getOpenedUserPopout']),
|
||||||
|
|
||||||
|
/* Experiments */
|
||||||
|
ExperimentStore: Filters.byProperties(['getExperimentOverrides']),
|
||||||
|
ExperimentsManager: Filters.byProperties(['isDeveloper']),
|
||||||
|
CurrentExperiment: Filters.byProperties(['getExperimentId']),
|
||||||
|
|
||||||
|
/* Images, Avatars and Utils */
|
||||||
|
ImageResolver: Filters.byProperties(['getUserAvatarURL']),
|
||||||
|
ImageUtils: Filters.byProperties(['getSizedImageSrc']),
|
||||||
|
AvatarDefaults: Filters.byProperties(['getUserAvatarURL', 'DEFAULT_AVATARS']),
|
||||||
|
|
||||||
|
/* Drag & Drop */
|
||||||
|
DNDActions: Filters.byProperties(['beginDrag']),
|
||||||
|
DNDSources: Filters.byProperties(['addTarget']),
|
||||||
|
DNDObjects: Filters.byProperties(['DragSource']),
|
||||||
|
|
||||||
|
/* Electron & Other Internals with Utils */
|
||||||
|
ElectronModule: Filters.byProperties(['_getMainWindow']),
|
||||||
|
Dispatcher: Filters.byProperties(['dirtyDispatch']),
|
||||||
|
PathUtils: Filters.byProperties(['hasBasename']),
|
||||||
|
NotificationModule: Filters.byProperties(['showNotification']),
|
||||||
|
RouterModule: Filters.byProperties(['Router']),
|
||||||
|
APIModule: Filters.byProperties(['getAPIBaseURL']),
|
||||||
|
AnalyticEvents: Filters.byProperties(['AnalyticEventConfigs']),
|
||||||
|
KeyGenerator: Filters.byCode(/"binary"/),
|
||||||
|
Buffers: Filters.byProperties(['Buffer', 'kMaxLength']),
|
||||||
|
DeviceStore: Filters.byProperties(['getDevices']),
|
||||||
|
SoftwareInfo: Filters.byProperties(['os']),
|
||||||
|
CurrentContext: Filters.byProperties(['setTagsContext']),
|
||||||
|
|
||||||
|
/* Media Stuff (Audio/Video) */
|
||||||
|
MediaDeviceInfo: Filters.byProperties(['Codecs', 'SUPPORTED_BROWSERS']),
|
||||||
|
MediaInfo: Filters.byProperties(['getOutputVolume']),
|
||||||
|
MediaEngineInfo: Filters.byProperties(['MediaEngineFeatures']),
|
||||||
|
VoiceInfo: Filters.byProperties(['EchoCancellation']),
|
||||||
|
VideoStream: Filters.byProperties(['getVideoStream']),
|
||||||
|
SoundModule: Filters.byProperties(['playSound']),
|
||||||
|
|
||||||
|
/* Window, DOM, HTML */
|
||||||
|
WindowInfo: Filters.byProperties(['isFocused', 'windowSize']),
|
||||||
|
TagInfo: Filters.byProperties(['VALID_TAG_NAMES']),
|
||||||
|
DOMInfo: Filters.byProperties(['canUseDOM']),
|
||||||
|
|
||||||
|
/* Locale/Location and Time */
|
||||||
|
LocaleManager: Filters.byProperties(['setLocale']),
|
||||||
|
Moment: Filters.byProperties(['parseZone']),
|
||||||
|
LocationManager: Filters.byProperties(['createLocation']),
|
||||||
|
Timestamps: Filters.byProperties(['fromTimestamp']),
|
||||||
|
TimeFormatter: Filters.byProperties(['dateFormat']),
|
||||||
|
|
||||||
|
/* Strings and Utils */
|
||||||
|
Strings: Filters.byProperties(['TEXT', 'TEXTAREA_PLACEHOLDER']),
|
||||||
|
StringFormats: Filters.byProperties(['a', 'z']),
|
||||||
|
StringUtils: Filters.byProperties(['toASCII']),
|
||||||
|
|
||||||
|
/* URLs and Utils */
|
||||||
|
URLParser: Filters.byProperties(['Url', 'parse']),
|
||||||
|
ExtraURLs: Filters.byProperties(['getArticleURL']),
|
||||||
|
|
||||||
|
/* Text Processing */
|
||||||
|
hljs: Filters.byProperties(['highlight', 'highlightBlock']),
|
||||||
|
SimpleMarkdown: Filters.byProperties(['parseBlock', 'parseInline', 'defaultOutput']),
|
||||||
|
|
||||||
|
/* DOM/React Components */
|
||||||
|
/* ==================== */
|
||||||
|
LayerManager: Filters.byProperties(['popLayer', 'pushLayer']),
|
||||||
|
UserSettingsWindow: Filters.byProperties(['open', 'updateAccount']),
|
||||||
|
ChannelSettingsWindow: Filters.byProperties(['open', 'updateChannel']),
|
||||||
|
GuildSettingsWindow: Filters.byProperties(['open', 'updateGuild']),
|
||||||
|
KeyboardCombosModal: Filters.byProperties(['show', 'activateRagingDemon']),
|
||||||
|
|
||||||
|
/* Modals */
|
||||||
|
ModalStack: Filters.byProperties(['push', 'update', 'pop', 'popWithKey']),
|
||||||
|
ConfirmModal: Filters.byPrototypeFields(['handleCancel', 'handleSubmit', 'handleMinorConfirm']),
|
||||||
|
UserProfileModal: Filters.byProperties(['fetchMutualFriends', 'setSection']),
|
||||||
|
ChangeNicknameModal: Filters.byProperties(['open', 'changeNickname']),
|
||||||
|
CreateChannelModal: Filters.byProperties(['open', 'createChannel']),
|
||||||
|
PruneMembersModal: Filters.byProperties(['open', 'prune']),
|
||||||
|
NotificationSettingsModal: Filters.byProperties(['open', 'updateNotificationSettings']),
|
||||||
|
PrivacySettingsModal: Filters.byCode(/PRIVACY_SETTINGS_MODAL_OPEN/, m => m.open),
|
||||||
|
CreateInviteModal: Filters.byProperties(['open', 'createInvite']),
|
||||||
|
|
||||||
|
/* Popouts */
|
||||||
|
PopoutStack: Filters.byProperties(['open', 'close', 'closeAll']),
|
||||||
|
PopoutOpener: Filters.byProperties(['openPopout']),
|
||||||
|
EmojiPicker: Filters.byPrototypeFields(['onHoverEmoji', 'selectEmoji']),
|
||||||
|
|
||||||
|
/* Context Menus */
|
||||||
|
ContextMenuActions: Filters.byCode(/CONTEXT_MENU_CLOSE/, c => c.close),
|
||||||
|
ContextMenuItemsGroup: Filters.byCode(/itemGroup/),
|
||||||
|
ContextMenuItem: Filters.byCode(/\.label\b.*\.hint\b.*\.action\b/),
|
||||||
|
|
||||||
|
/* In-Message Links */
|
||||||
|
ExternalLink: Filters.byCode(/\.trusted\b/)
|
||||||
|
|
||||||
|
}
|
|
@ -10,179 +10,7 @@
|
||||||
|
|
||||||
import { Utils, Filters } from 'common';
|
import { Utils, Filters } from 'common';
|
||||||
import Events from '../events';
|
import Events from '../events';
|
||||||
|
import KnownModules from './knownmodules';
|
||||||
const KnownModules = {
|
|
||||||
React: Filters.byProperties(['createElement', 'cloneElement']),
|
|
||||||
ReactDOM: Filters.byProperties(['render', 'findDOMNode']),
|
|
||||||
|
|
||||||
Events: Filters.byPrototypeFields(['setMaxListeners', 'emit']),
|
|
||||||
|
|
||||||
/* Guild Info, Stores, and Utilities */
|
|
||||||
GuildStore: Filters.byProperties(['getGuild']),
|
|
||||||
SortedGuildStore: Filters.byProperties(['getSortedGuilds']),
|
|
||||||
SelectedGuildStore: Filters.byProperties(['getLastSelectedGuildId']),
|
|
||||||
GuildSync: Filters.byProperties(['getSyncedGuilds']),
|
|
||||||
GuildInfo: Filters.byProperties(['getAcronym']),
|
|
||||||
GuildChannelsStore: Filters.byProperties(['getChannels', 'getDefaultChannel']),
|
|
||||||
GuildMemberStore: Filters.byProperties(['getMember']),
|
|
||||||
MemberCountStore: Filters.byProperties(['getMemberCounts']),
|
|
||||||
GuildEmojiStore: Filters.byProperties(['getEmojis']),
|
|
||||||
GuildActions: Filters.byProperties(['markGuildAsRead']),
|
|
||||||
GuildPermissions: Filters.byProperties(['getGuildPermissions']),
|
|
||||||
|
|
||||||
/* Channel Store & Actions */
|
|
||||||
ChannelStore: Filters.byProperties(['getChannels', 'getDMFromUserId']),
|
|
||||||
SelectedChannelStore: Filters.byProperties(['getLastSelectedChannelId']),
|
|
||||||
ChannelActions: Filters.byProperties(['selectChannel']),
|
|
||||||
PrivateChannelActions: Filters.byProperties(['openPrivateChannel']),
|
|
||||||
ChannelSelector: Filters.byProperties(['selectGuild', 'selectChannel']),
|
|
||||||
VoiceChannelActions: Filters.byProperties(['selectVoiceChannel']),
|
|
||||||
|
|
||||||
/* Current User Info, State and Settings */
|
|
||||||
UserInfoStore: Filters.byProperties(['getToken']),
|
|
||||||
UserSettingsStore: Filters.byProperties(['guildPositions']),
|
|
||||||
AccountManager: Filters.byProperties(['register', 'login']),
|
|
||||||
UserSettingsUpdater: Filters.byProperties(['updateRemoteSettings']),
|
|
||||||
OnlineWatcher: Filters.byProperties(['isOnline']),
|
|
||||||
CurrentUserIdle: Filters.byProperties(['getIdleTime']),
|
|
||||||
RelationshipStore: Filters.byProperties(['isBlocked', 'isFriend']),
|
|
||||||
RelationshipManager: Filters.byProperties(['addRelationship']),
|
|
||||||
MentionStore: Filters.byProperties(['getMentions']),
|
|
||||||
|
|
||||||
/* User Stores and Utils */
|
|
||||||
UserStore: Filters.byProperties(['getCurrentUser']),
|
|
||||||
UserStatusStore: Filters.byProperties(['getStatuses']),
|
|
||||||
UserTypingStore: Filters.byProperties(['isTyping']),
|
|
||||||
UserActivityStore: Filters.byProperties(['getActivity']),
|
|
||||||
UserNameResolver: Filters.byProperties(['getName']),
|
|
||||||
UserNoteStore: Filters.byProperties(['getNote']),
|
|
||||||
UserNoteActions: Filters.byProperties(['updateNote']),
|
|
||||||
DraftActions: Filters.byProperties(['changeDraft']),
|
|
||||||
|
|
||||||
/* Emoji Store and Utils */
|
|
||||||
EmojiInfo: Filters.byProperties(['isEmojiDisabled']),
|
|
||||||
EmojiUtils: Filters.byProperties(['getGuildEmoji']),
|
|
||||||
EmojiStore: Filters.byProperties(['getByCategory', 'EMOJI_NAME_RE']),
|
|
||||||
|
|
||||||
/* Invite Store and Utils */
|
|
||||||
InviteStore: Filters.byProperties(['getInvites']),
|
|
||||||
InviteResolver: Filters.byProperties(['findInvite']),
|
|
||||||
InviteActions: Filters.byProperties(['acceptInvite']),
|
|
||||||
|
|
||||||
/* Discord Objects & Utils */
|
|
||||||
DiscordConstants: Filters.byProperties(['Permissions', 'ActivityTypes', 'StatusTypes']),
|
|
||||||
Permissions: Filters.byProperties(['getHighestRole']),
|
|
||||||
ColorConverter: Filters.byProperties(['hex2int']),
|
|
||||||
ColorShader: Filters.byProperties(['darken']),
|
|
||||||
TinyColor: Filters.byPrototypeFields(['toRgb']),
|
|
||||||
ClassResolver: Filters.byProperties(['getClass']),
|
|
||||||
ButtonData: Filters.byProperties(['ButtonSizes']),
|
|
||||||
IconNames: Filters.byProperties(['IconNames']),
|
|
||||||
NavigationUtils: Filters.byProperties(['transitionTo', 'replaceWith', 'getHistory']),
|
|
||||||
|
|
||||||
/* Discord Messages */
|
|
||||||
MessageStore: Filters.byProperties(['getMessages']),
|
|
||||||
MessageActions: Filters.byProperties(['jumpToMessage', '_sendMessage']),
|
|
||||||
MessageQueue: Filters.byProperties(['enqueue']),
|
|
||||||
MessageParser: Filters.byProperties(['createMessage', 'parse', 'unparse']),
|
|
||||||
|
|
||||||
/* In-Game Overlay */
|
|
||||||
OverlayUserPopoutSettings: Filters.byProperties(['openUserPopout']),
|
|
||||||
OverlayUserPopoutInfo: Filters.byProperties(['getOpenedUserPopout']),
|
|
||||||
|
|
||||||
/* Experiments */
|
|
||||||
ExperimentStore: Filters.byProperties(['getExperimentOverrides']),
|
|
||||||
ExperimentsManager: Filters.byProperties(['isDeveloper']),
|
|
||||||
CurrentExperiment: Filters.byProperties(['getExperimentId']),
|
|
||||||
|
|
||||||
/* Images, Avatars and Utils */
|
|
||||||
ImageResolver: Filters.byProperties(['getUserAvatarURL']),
|
|
||||||
ImageUtils: Filters.byProperties(['getSizedImageSrc']),
|
|
||||||
AvatarDefaults: Filters.byProperties(['getUserAvatarURL', 'DEFAULT_AVATARS']),
|
|
||||||
|
|
||||||
/* Drag & Drop */
|
|
||||||
DNDActions: Filters.byProperties(['beginDrag']),
|
|
||||||
DNDSources: Filters.byProperties(['addTarget']),
|
|
||||||
DNDObjects: Filters.byProperties(['DragSource']),
|
|
||||||
|
|
||||||
/* Electron & Other Internals with Utils */
|
|
||||||
ElectronModule: Filters.byProperties(['_getMainWindow']),
|
|
||||||
Dispatcher: Filters.byProperties(['dirtyDispatch']),
|
|
||||||
PathUtils: Filters.byProperties(['hasBasename']),
|
|
||||||
NotificationModule: Filters.byProperties(['showNotification']),
|
|
||||||
RouterModule: Filters.byProperties(['Router']),
|
|
||||||
APIModule: Filters.byProperties(['getAPIBaseURL']),
|
|
||||||
AnalyticEvents: Filters.byProperties(['AnalyticEventConfigs']),
|
|
||||||
KeyGenerator: Filters.byCode(/"binary"/),
|
|
||||||
Buffers: Filters.byProperties(['Buffer', 'kMaxLength']),
|
|
||||||
DeviceStore: Filters.byProperties(['getDevices']),
|
|
||||||
SoftwareInfo: Filters.byProperties(['os']),
|
|
||||||
CurrentContext: Filters.byProperties(['setTagsContext']),
|
|
||||||
|
|
||||||
/* Media Stuff (Audio/Video) */
|
|
||||||
MediaDeviceInfo: Filters.byProperties(['Codecs', 'SUPPORTED_BROWSERS']),
|
|
||||||
MediaInfo: Filters.byProperties(['getOutputVolume']),
|
|
||||||
MediaEngineInfo: Filters.byProperties(['MediaEngineFeatures']),
|
|
||||||
VoiceInfo: Filters.byProperties(['EchoCancellation']),
|
|
||||||
VideoStream: Filters.byProperties(['getVideoStream']),
|
|
||||||
SoundModule: Filters.byProperties(['playSound']),
|
|
||||||
|
|
||||||
/* Window, DOM, HTML */
|
|
||||||
WindowInfo: Filters.byProperties(['isFocused', 'windowSize']),
|
|
||||||
TagInfo: Filters.byProperties(['VALID_TAG_NAMES']),
|
|
||||||
DOMInfo: Filters.byProperties(['canUseDOM']),
|
|
||||||
|
|
||||||
/* Locale/Location and Time */
|
|
||||||
LocaleManager: Filters.byProperties(['setLocale']),
|
|
||||||
Moment: Filters.byProperties(['parseZone']),
|
|
||||||
LocationManager: Filters.byProperties(['createLocation']),
|
|
||||||
Timestamps: Filters.byProperties(['fromTimestamp']),
|
|
||||||
TimeFormatter: Filters.byProperties(['dateFormat']),
|
|
||||||
|
|
||||||
/* Strings and Utils */
|
|
||||||
Strings: Filters.byProperties(['TEXT', 'TEXTAREA_PLACEHOLDER']),
|
|
||||||
StringFormats: Filters.byProperties(['a', 'z']),
|
|
||||||
StringUtils: Filters.byProperties(['toASCII']),
|
|
||||||
|
|
||||||
/* URLs and Utils */
|
|
||||||
URLParser: Filters.byProperties(['Url', 'parse']),
|
|
||||||
ExtraURLs: Filters.byProperties(['getArticleURL']),
|
|
||||||
|
|
||||||
/* Text Processing */
|
|
||||||
hljs: Filters.byProperties(['highlight', 'highlightBlock']),
|
|
||||||
SimpleMarkdown: Filters.byProperties(['parseBlock', 'parseInline', 'defaultOutput']),
|
|
||||||
|
|
||||||
/* DOM/React Components */
|
|
||||||
/* ==================== */
|
|
||||||
LayerManager: Filters.byProperties(['popLayer', 'pushLayer']),
|
|
||||||
UserSettingsWindow: Filters.byProperties(['open', 'updateAccount']),
|
|
||||||
ChannelSettingsWindow: Filters.byProperties(['open', 'updateChannel']),
|
|
||||||
GuildSettingsWindow: Filters.byProperties(['open', 'updateGuild']),
|
|
||||||
|
|
||||||
/* Modals */
|
|
||||||
ModalStack: Filters.byProperties(['push', 'update', 'pop', 'popWithKey']),
|
|
||||||
ConfirmModal: Filters.byPrototypeFields(['handleCancel', 'handleSubmit', 'handleMinorConfirm']),
|
|
||||||
UserProfileModal: Filters.byProperties(['fetchMutualFriends', 'setSection']),
|
|
||||||
ChangeNicknameModal: Filters.byProperties(['open', 'changeNickname']),
|
|
||||||
CreateChannelModal: Filters.byProperties(['open', 'createChannel']),
|
|
||||||
PruneMembersModal: Filters.byProperties(['open', 'prune']),
|
|
||||||
NotificationSettingsModal: Filters.byProperties(['open', 'updateNotificationSettings']),
|
|
||||||
PrivacySettingsModal: Filters.byCode(/PRIVACY_SETTINGS_MODAL_OPEN/, m => m.open),
|
|
||||||
CreateInviteModal: Filters.byProperties(['open', 'createInvite']),
|
|
||||||
|
|
||||||
/* Popouts */
|
|
||||||
PopoutStack: Filters.byProperties(['open', 'close', 'closeAll']),
|
|
||||||
PopoutOpener: Filters.byProperties(['openPopout']),
|
|
||||||
EmojiPicker: Filters.byPrototypeFields(['onHoverEmoji', 'selectEmoji']),
|
|
||||||
|
|
||||||
/* Context Menus */
|
|
||||||
ContextMenuActions: Filters.byCode(/CONTEXT_MENU_CLOSE/, c => c.close),
|
|
||||||
ContextMenuItemsGroup: Filters.byCode(/itemGroup/),
|
|
||||||
ContextMenuItem: Filters.byCode(/\.label\b.*\.hint\b.*\.action\b/),
|
|
||||||
|
|
||||||
/* In-Message Links */
|
|
||||||
ExternalLink: Filters.byCode(/\.trusted\b/)
|
|
||||||
};
|
|
||||||
|
|
||||||
class Module {
|
class Module {
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@ export class Channel {
|
||||||
case 2: return new GuildVoiceChannel(channel);
|
case 2: return new GuildVoiceChannel(channel);
|
||||||
case 3: return new GroupChannel(channel);
|
case 3: return new GroupChannel(channel);
|
||||||
case 4: return new ChannelCategory(channel);
|
case 4: return new ChannelCategory(channel);
|
||||||
|
case 5: return new GuildNewsChannel(channel);
|
||||||
|
case 6: return new GuildStoreChannel(channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +50,8 @@ export class Channel {
|
||||||
static get GuildTextChannel() { return GuildTextChannel }
|
static get GuildTextChannel() { return GuildTextChannel }
|
||||||
static get GuildVoiceChannel() { return GuildVoiceChannel }
|
static get GuildVoiceChannel() { return GuildVoiceChannel }
|
||||||
static get ChannelCategory() { return ChannelCategory }
|
static get ChannelCategory() { return ChannelCategory }
|
||||||
|
static get GuildNewsChannel() { return GuildNewsChannel }
|
||||||
|
static get GuildStoreChannel() { return GuildStoreChannel }
|
||||||
static get PrivateChannel() { return PrivateChannel }
|
static get PrivateChannel() { return PrivateChannel }
|
||||||
static get DirectMessageChannel() { return DirectMessageChannel }
|
static get DirectMessageChannel() { return DirectMessageChannel }
|
||||||
static get GroupChannel() { return GroupChannel }
|
static get GroupChannel() { return GroupChannel }
|
||||||
|
@ -59,9 +63,9 @@ export class Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message in this channel.
|
* Send a message in this channel.
|
||||||
* @param {String} content The new message's content
|
* @param {string} content The new message's content
|
||||||
* @param {Boolean} parse Whether to parse the message or send it as it is
|
* @param {boolean} [parse=false] Whether to parse the message or send it as it is
|
||||||
* @return {Promise => Message}
|
* @return {Promise<Message>}
|
||||||
*/
|
*/
|
||||||
async sendMessage(content, parse = false) {
|
async sendMessage(content, parse = false) {
|
||||||
if (this.assertPermissions) this.assertPermissions('SEND_MESSAGES', Modules.DiscordPermissions.VIEW_CHANNEL | Modules.DiscordPermissions.SEND_MESSAGES);
|
if (this.assertPermissions) this.assertPermissions('SEND_MESSAGES', Modules.DiscordPermissions.VIEW_CHANNEL | Modules.DiscordPermissions.SEND_MESSAGES);
|
||||||
|
@ -77,7 +81,7 @@ export class Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a bot message in this channel that only the current user can see.
|
* Send a bot message in this channel that only the current user can see.
|
||||||
* @param {String} content The new message's content
|
* @param {string} content The new message's content
|
||||||
* @return {Message}
|
* @return {Message}
|
||||||
*/
|
*/
|
||||||
sendBotMessage(content) {
|
sendBotMessage(content) {
|
||||||
|
@ -111,8 +115,8 @@ export class Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends an invite in this channel.
|
* Sends an invite in this channel.
|
||||||
* @param {String} code The invite code
|
* @param {string} code The invite code
|
||||||
* @return {Promise => Messaage}
|
* @return {Promise<Message>}
|
||||||
*/
|
*/
|
||||||
async sendInvite(code) {
|
async sendInvite(code) {
|
||||||
if (this.assertPermissions) this.assertPermissions('SEND_MESSAGES', Modules.DiscordPermissions.VIEW_CHANNEL | Modules.DiscordPermissions.SEND_MESSAGES);
|
if (this.assertPermissions) this.assertPermissions('SEND_MESSAGES', Modules.DiscordPermissions.VIEW_CHANNEL | Modules.DiscordPermissions.SEND_MESSAGES);
|
||||||
|
@ -130,7 +134,7 @@ export class Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this channel is currently selected.
|
* Whether this channel is currently selected.
|
||||||
* @type {Boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
get isSelected() {
|
get isSelected() {
|
||||||
return DiscordApi.currentChannel === this;
|
return DiscordApi.currentChannel === this;
|
||||||
|
@ -138,6 +142,7 @@ export class Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this channel.
|
* Updates this channel.
|
||||||
|
* @param {Object} body Data to send in the API request
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
async updateChannel(body) {
|
async updateChannel(body) {
|
||||||
|
@ -153,12 +158,25 @@ export class Channel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Channel.GUILD_TEXT = 0;
|
||||||
|
Channel.DM = 1;
|
||||||
|
Channel.GUILD_VOICE = 2;
|
||||||
|
Channel.GROUP_DM = 3;
|
||||||
|
Channel.GUILD_CATEGORY = 4;
|
||||||
|
Channel.GUILD_NEWS = 5;
|
||||||
|
Channel.GUILD_STORE = 6;
|
||||||
|
|
||||||
export class PermissionOverwrite {
|
export class PermissionOverwrite {
|
||||||
constructor(data, channel_id) {
|
constructor(data, channel_id) {
|
||||||
this.discordObject = data;
|
this.discordObject = data;
|
||||||
this.channelId = channel_id;
|
this.channelId = channel_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} data
|
||||||
|
* @param {number} channel_id
|
||||||
|
* @return {PermissionOverwrite}
|
||||||
|
*/
|
||||||
static from(data, channel_id) {
|
static from(data, channel_id) {
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
default: return new PermissionOverwrite(data, channel_id);
|
default: return new PermissionOverwrite(data, channel_id);
|
||||||
|
@ -174,10 +192,16 @@ export class PermissionOverwrite {
|
||||||
get allow() { return this.discordObject.allow }
|
get allow() { return this.discordObject.allow }
|
||||||
get deny() { return this.discordObject.deny }
|
get deny() { return this.discordObject.deny }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?Channel}
|
||||||
|
*/
|
||||||
get channel() {
|
get channel() {
|
||||||
return Channel.fromId(this.channelId);
|
return Channel.fromId(this.channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?Guild}
|
||||||
|
*/
|
||||||
get guild() {
|
get guild() {
|
||||||
return this.channel ? this.channel.guild : null;
|
return this.channel ? this.channel.guild : null;
|
||||||
}
|
}
|
||||||
|
@ -186,6 +210,9 @@ export class PermissionOverwrite {
|
||||||
export class RolePermissionOverwrite extends PermissionOverwrite {
|
export class RolePermissionOverwrite extends PermissionOverwrite {
|
||||||
get roleId() { return this.discordObject.id }
|
get roleId() { return this.discordObject.id }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?Role}
|
||||||
|
*/
|
||||||
get role() {
|
get role() {
|
||||||
return this.guild ? this.guild.roles.find(r => r.id === this.roleId) : null;
|
return this.guild ? this.guild.roles.find(r => r.id === this.roleId) : null;
|
||||||
}
|
}
|
||||||
|
@ -194,6 +221,9 @@ export class RolePermissionOverwrite extends PermissionOverwrite {
|
||||||
export class MemberPermissionOverwrite extends PermissionOverwrite {
|
export class MemberPermissionOverwrite extends PermissionOverwrite {
|
||||||
get memberId() { return this.discordObject.id }
|
get memberId() { return this.discordObject.id }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {GuildMember}
|
||||||
|
*/
|
||||||
get member() {
|
get member() {
|
||||||
return GuildMember.fromId(this.memberId);
|
return GuildMember.fromId(this.memberId);
|
||||||
}
|
}
|
||||||
|
@ -208,34 +238,45 @@ export class GuildChannel extends Channel {
|
||||||
get nicks() { return this.discordObject.nicks }
|
get nicks() { return this.discordObject.nicks }
|
||||||
|
|
||||||
checkPermissions(perms) {
|
checkPermissions(perms) {
|
||||||
return Modules.PermissionUtils.can(perms, DiscordApi.currentUser, this.discordObject);
|
return Modules.PermissionUtils.can(perms, DiscordApi.currentUser.discordObject, this.discordObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertPermissions(name, perms) {
|
assertPermissions(name, perms) {
|
||||||
if (!this.checkPermissions(perms)) throw new InsufficientPermissions(name);
|
if (!this.checkPermissions(perms)) throw new InsufficientPermissions(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?ChannelCategory}
|
||||||
|
*/
|
||||||
get category() {
|
get category() {
|
||||||
return Channel.fromId(this.parentId);
|
return Channel.fromId(this.parentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current user's permissions on this channel.
|
* The current user's permissions on this channel.
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
get permissions() {
|
get permissions() {
|
||||||
return Modules.GuildPermissions.getChannelPermissions(this.id);
|
return Modules.GuildPermissions.getChannelPermissions(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {List<PermissionOverwrite>}
|
||||||
|
*/
|
||||||
get permissionOverwrites() {
|
get permissionOverwrites() {
|
||||||
return List.from(Object.entries(this.discordObject.permissionOverwrites), ([i, p]) => PermissionOverwrite.from(p, this.id));
|
return List.from(Object.values(this.discordObject.permissionOverwrites), p => PermissionOverwrite.from(p, this.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Guild}
|
||||||
|
*/
|
||||||
get guild() {
|
get guild() {
|
||||||
return Guild.fromId(this.guildId);
|
return Guild.fromId(this.guildId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this channel is the guild's default channel.
|
* Whether this channel is the guild's default channel.
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
get isDefaultChannel() {
|
get isDefaultChannel() {
|
||||||
return Modules.GuildChannelsStore.getDefaultChannel(this.guildId).id === this.id;
|
return Modules.GuildChannelsStore.getDefaultChannel(this.guildId).id === this.id;
|
||||||
|
@ -243,16 +284,16 @@ export class GuildChannel extends Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens this channel's settings window.
|
* Opens this channel's settings window.
|
||||||
* @param {String} section The section to open (see DiscordConstants.ChannelSettingsSections)
|
* @param {string} section The section to open (see DiscordConstants.ChannelSettingsSections)
|
||||||
*/
|
*/
|
||||||
openSettings(section = 'OVERVIEW') {
|
openSettings(section = 'OVERVIEW') {
|
||||||
Modules.ChannelSettingsWindow.setSection(section);
|
|
||||||
Modules.ChannelSettingsWindow.open(this.id);
|
Modules.ChannelSettingsWindow.open(this.id);
|
||||||
|
Modules.ChannelSettingsWindow.setSection(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this channel's name.
|
* Updates this channel's name.
|
||||||
* @param {String} name The channel's new name
|
* @param {string} name The channel's new name
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
updateName(name) {
|
updateName(name) {
|
||||||
|
@ -261,7 +302,7 @@ export class GuildChannel extends Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the channel's position.
|
* Changes the channel's position.
|
||||||
* @param {Number} position The channel's new position
|
* @param {(GuildChannel|number)} [position=0] The channel's new position
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
changeSortLocation(position = 0) {
|
changeSortLocation(position = 0) {
|
||||||
|
@ -271,7 +312,7 @@ export class GuildChannel extends Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this channel's permission overwrites.
|
* Updates this channel's permission overwrites.
|
||||||
* @param {Array} permissionOverwrites An array of permission overwrites
|
* @param {Object[]} permission_overwrites An array of permission overwrites
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
updatePermissionOverwrites(permission_overwrites) {
|
updatePermissionOverwrites(permission_overwrites) {
|
||||||
|
@ -280,7 +321,7 @@ export class GuildChannel extends Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this channel's category.
|
* Updates this channel's category.
|
||||||
* @param {ChannelCategory} category The new channel category
|
* @param {?(ChannelCategory|number)} category The new channel category
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
updateCategory(category) {
|
updateCategory(category) {
|
||||||
|
@ -296,7 +337,7 @@ export class GuildTextChannel extends GuildChannel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this channel's topic.
|
* Updates this channel's topic.
|
||||||
* @param {String} topc The new channel topic
|
* @param {string} topic The new channel topic
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
updateTopic(topic) {
|
updateTopic(topic) {
|
||||||
|
@ -305,13 +346,17 @@ export class GuildTextChannel extends GuildChannel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this channel's not-safe-for-work flag.
|
* Updates this channel's not-safe-for-work flag.
|
||||||
* @param {Boolean} nsfw Whether the channel should be marked as NSFW
|
* @param {boolean} [nsfw=true] Whether the channel should be marked as NSFW
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
setNsfw(nsfw = true) {
|
setNsfw(nsfw = true) {
|
||||||
return this.updateChannel({ nsfw });
|
return this.updateChannel({ nsfw });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates this channel's not-safe-for-work flag.
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
setNotNsfw() {
|
setNotNsfw() {
|
||||||
return this.setNsfw(false);
|
return this.setNsfw(false);
|
||||||
}
|
}
|
||||||
|
@ -328,11 +373,13 @@ export class GuildVoiceChannel extends GuildChannel {
|
||||||
jumpToPresent() { throw new Error('Cannot select a voice channel.'); }
|
jumpToPresent() { throw new Error('Cannot select a voice channel.'); }
|
||||||
get hasMoreAfter() { return false; }
|
get hasMoreAfter() { return false; }
|
||||||
sendInvite() { throw new Error('Cannot invite someone to a voice channel.'); }
|
sendInvite() { throw new Error('Cannot invite someone to a voice channel.'); }
|
||||||
|
|
||||||
|
// TODO: can select a voice/video channel when guild video is enabled
|
||||||
select() { throw new Error('Cannot select a voice channel.'); }
|
select() { throw new Error('Cannot select a voice channel.'); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this channel's bitrate.
|
* Updates this channel's bitrate.
|
||||||
* @param {Number} bitrate The new bitrate
|
* @param {number} bitrate The new bitrate
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
updateBitrate(bitrate) {
|
updateBitrate(bitrate) {
|
||||||
|
@ -341,7 +388,7 @@ export class GuildVoiceChannel extends GuildChannel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this channel's user limit.
|
* Updates this channel's user limit.
|
||||||
* @param {Number} userLimit The new user limit
|
* @param {number} user_limit The new user limit
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
updateUserLimit(user_limit) {
|
updateUserLimit(user_limit) {
|
||||||
|
@ -365,6 +412,7 @@ export class ChannelCategory extends GuildChannel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of channels in this category.
|
* A list of channels in this category.
|
||||||
|
* @type {List<GuildChannel>}
|
||||||
*/
|
*/
|
||||||
get channels() {
|
get channels() {
|
||||||
return List.from(this.guild.channels.filter(c => c.parentId === this.id));
|
return List.from(this.guild.channels.filter(c => c.parentId === this.id));
|
||||||
|
@ -372,23 +420,105 @@ export class ChannelCategory extends GuildChannel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the create channel modal for this guild.
|
* Opens the create channel modal for this guild.
|
||||||
* @param {Number} type The type of channel to create - either 0 (text), 2 (voice) or 4 (category)
|
* @param {number} type The type of channel to create - either 0 (text), 2 (voice/video), 5 (news) or 6 (store)
|
||||||
* @param {GuildChannel} clone A channel to clone permissions of
|
* @param {GuildChannel} clone A channel to clone permissions of
|
||||||
*/
|
*/
|
||||||
openCreateChannelModal(type, category, clone) {
|
openCreateChannelModal(type, clone) {
|
||||||
this.guild.openCreateChannelModal(type, this.id, this, clone);
|
this.guild.openCreateChannelModal(type, this.id, this, clone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the create channel modal for this guild with type 0 (text).
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions of
|
||||||
|
*/
|
||||||
|
openCreateTextChannelModal(clone) {
|
||||||
|
this.guild.openCreateChannelModal(Channel.GUILD_TEXT, this.id, this, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the create channel modal for this guild with type 2 (voice).
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions of
|
||||||
|
*/
|
||||||
|
openCreateVoiceChannelModal(clone) {
|
||||||
|
this.guild.openCreateChannelModal(Channel.GUILD_VOICE, this.id, this, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the create channel modal for this guild with type 5 (news).
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions of
|
||||||
|
*/
|
||||||
|
openCreateNewsChannelModal(clone) {
|
||||||
|
this.guild.openCreateChannelModal(Channel.GUILD_NEWS, this.id, this, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the create channel modal for this guild with type 6 (store).
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions of
|
||||||
|
*/
|
||||||
|
openCreateStoreChannelModal(clone) {
|
||||||
|
this.guild.openCreateChannelModal(Channel.GUILD_STORE, this.id, this, clone);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a channel in this category.
|
* Creates a channel in this category.
|
||||||
* @param {Number} type The type of channel to create - either 0 (text) or 2 (voice)
|
* @param {number} type The type of channel to create - either 0 (text) or 2 (voice)
|
||||||
* @param {String} name A name for the new channel
|
* @param {string} name A name for the new channel
|
||||||
* @param {Array} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
|
* @param {Object[]} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
|
||||||
* @return {Promise => GuildChannel}
|
* @return {Promise<GuildChannel>}
|
||||||
*/
|
*/
|
||||||
createChannel(type, name, permission_overwrites) {
|
createChannel(type, name, permission_overwrites) {
|
||||||
return this.guild.createChannel(type, name, this, permission_overwrites);
|
return this.guild.createChannel(type, name, this, permission_overwrites);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this category.
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {Object[]} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
|
||||||
|
* @return {Promise<GuildTextChannel>}
|
||||||
|
*/
|
||||||
|
createTextChannel(name, permission_overwrites) {
|
||||||
|
return this.guild.createChannel(Channel.GUILD_TEXT, name, this, permission_overwrites);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this category.
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {Object[]} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
|
||||||
|
* @return {Promise<GuildVoiceChannel>}
|
||||||
|
*/
|
||||||
|
createVoiceChannel(name, permission_overwrites) {
|
||||||
|
return this.guild.createChannel(Channel.GUILD_VOICE, name, this, permission_overwrites);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this category.
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {Object[]} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
|
||||||
|
* @return {Promise<GuildNewsChannel>}
|
||||||
|
*/
|
||||||
|
createNewsChannel(name, permission_overwrites) {
|
||||||
|
return this.guild.createChannel(Channel.GUILD_NEWS, name, this, permission_overwrites);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this category.
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {Object[]} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
|
||||||
|
* @return {Promise<GuildStoreChannel>}
|
||||||
|
*/
|
||||||
|
createStoreChannel(name, permission_overwrites) {
|
||||||
|
return this.guild.createChannel(Channel.GUILD_STORE, name, this, permission_overwrites);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type 5 - GUILD_NEWS
|
||||||
|
export class GuildNewsChannel extends GuildTextChannel {
|
||||||
|
get type() { return 'GUILD_NEWS' }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type 6 - GUILD_STORE
|
||||||
|
export class GuildStoreChannel extends GuildChannel {
|
||||||
|
get type() { return 'GUILD_STORE' }
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PrivateChannel extends Channel {
|
export class PrivateChannel extends Channel {
|
||||||
|
@ -403,6 +533,7 @@ export class DirectMessageChannel extends PrivateChannel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The other user of this direct message channel.
|
* The other user of this direct message channel.
|
||||||
|
* @type {User}
|
||||||
*/
|
*/
|
||||||
get recipient() {
|
get recipient() {
|
||||||
return User.fromId(this.recipientId);
|
return User.fromId(this.recipientId);
|
||||||
|
@ -418,6 +549,7 @@ export class GroupChannel extends PrivateChannel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of the other members of this group direct message channel.
|
* A list of the other members of this group direct message channel.
|
||||||
|
* @type {List<User>}
|
||||||
*/
|
*/
|
||||||
get members() {
|
get members() {
|
||||||
return List.from(this.discordObject.recipients, id => User.fromId(id));
|
return List.from(this.discordObject.recipients, id => User.fromId(id));
|
||||||
|
@ -425,6 +557,7 @@ export class GroupChannel extends PrivateChannel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The owner of this group direct message channel. This is usually the person who created it.
|
* The owner of this group direct message channel. This is usually the person who created it.
|
||||||
|
* @type {User}
|
||||||
*/
|
*/
|
||||||
get owner() {
|
get owner() {
|
||||||
return User.fromId(this.ownerId);
|
return User.fromId(this.ownerId);
|
||||||
|
@ -432,7 +565,7 @@ export class GroupChannel extends PrivateChannel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this channel's name.
|
* Updates this channel's name.
|
||||||
* @param {String} name The channel's new name
|
* @param {string} name The channel's new name
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
updateName(name) {
|
updateName(name) {
|
||||||
|
|
|
@ -39,6 +39,9 @@ export class Role {
|
||||||
get colour() { return this.discordObject.color }
|
get colour() { return this.discordObject.color }
|
||||||
get colourString() { return this.discordObject.colorString }
|
get colourString() { return this.discordObject.colorString }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Guild}
|
||||||
|
*/
|
||||||
get guild() {
|
get guild() {
|
||||||
return Guild.fromId(this.guildId);
|
return Guild.fromId(this.guildId);
|
||||||
}
|
}
|
||||||
|
@ -71,6 +74,9 @@ export class Emoji {
|
||||||
get url() { return this.discordObject.url }
|
get url() { return this.discordObject.url }
|
||||||
get roles() { return this.discordObject.roles }
|
get roles() { return this.discordObject.roles }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Guild}
|
||||||
|
*/
|
||||||
get guild() {
|
get guild() {
|
||||||
return Guild.fromId(this.guildId);
|
return Guild.fromId(this.guildId);
|
||||||
}
|
}
|
||||||
|
@ -122,15 +128,24 @@ export class Guild {
|
||||||
get splash() { return this.discordObject.splash }
|
get splash() { return this.discordObject.splash }
|
||||||
get features() { return this.discordObject.features }
|
get features() { return this.discordObject.features }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {GuildMember}
|
||||||
|
*/
|
||||||
get owner() {
|
get owner() {
|
||||||
return this.members.find(m => m.userId === this.ownerId);
|
return this.members.find(m => m.userId === this.ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {List<Role>}
|
||||||
|
*/
|
||||||
get roles() {
|
get roles() {
|
||||||
return List.from(Object.entries(this.discordObject.roles), ([i, r]) => new Role(r, this.id))
|
return List.from(Object.values(this.discordObject.roles), r => new Role(r, this.id))
|
||||||
.sort((r1, r2) => r1.position === r2.position ? 0 : r1.position > r2.position ? 1 : -1);
|
.sort((r1, r2) => r1.position === r2.position ? 0 : r1.position > r2.position ? 1 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {List<GuildChannel>}
|
||||||
|
*/
|
||||||
get channels() {
|
get channels() {
|
||||||
const channels = Modules.GuildChannelsStore.getChannels(this.id);
|
const channels = Modules.GuildChannelsStore.getChannels(this.id);
|
||||||
const returnChannels = new List();
|
const returnChannels = new List();
|
||||||
|
@ -150,6 +165,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Channels that don't have a parent. (Channel categories and any text/voice channel not in one.)
|
* Channels that don't have a parent. (Channel categories and any text/voice channel not in one.)
|
||||||
|
* @type {List<GuildChannel>}
|
||||||
*/
|
*/
|
||||||
get mainChannels() {
|
get mainChannels() {
|
||||||
return this.channels.filter(c => !c.parentId);
|
return this.channels.filter(c => !c.parentId);
|
||||||
|
@ -157,6 +173,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The guild's default channel. (Usually the first in the list.)
|
* The guild's default channel. (Usually the first in the list.)
|
||||||
|
* @type {?GuildTextChannel}
|
||||||
*/
|
*/
|
||||||
get defaultChannel() {
|
get defaultChannel() {
|
||||||
return Channel.from(Modules.GuildChannelsStore.getDefaultChannel(this.id));
|
return Channel.from(Modules.GuildChannelsStore.getDefaultChannel(this.id));
|
||||||
|
@ -164,6 +181,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The guild's AFK channel.
|
* The guild's AFK channel.
|
||||||
|
* @type {?GuildVoiceChannel}
|
||||||
*/
|
*/
|
||||||
get afkChannel() {
|
get afkChannel() {
|
||||||
return this.afkChannelId ? Channel.fromId(this.afkChannelId) : null;
|
return this.afkChannelId ? Channel.fromId(this.afkChannelId) : null;
|
||||||
|
@ -171,6 +189,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The channel system messages are sent to.
|
* The channel system messages are sent to.
|
||||||
|
* @type {?GuildTextChannel}
|
||||||
*/
|
*/
|
||||||
get systemChannel() {
|
get systemChannel() {
|
||||||
return this.systemChannelId ? Channel.fromId(this.systemChannelId) : null;
|
return this.systemChannelId ? Channel.fromId(this.systemChannelId) : null;
|
||||||
|
@ -178,6 +197,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of GuildMember objects.
|
* A list of GuildMember objects.
|
||||||
|
* @type {List<GuildMember>}
|
||||||
*/
|
*/
|
||||||
get members() {
|
get members() {
|
||||||
const members = Modules.GuildMemberStore.getMembers(this.id);
|
const members = Modules.GuildMemberStore.getMembers(this.id);
|
||||||
|
@ -186,6 +206,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current user as a GuildMember of this guild.
|
* The current user as a GuildMember of this guild.
|
||||||
|
* @type {GuildMember}
|
||||||
*/
|
*/
|
||||||
get currentUser() {
|
get currentUser() {
|
||||||
return this.members.find(m => m.user === DiscordApi.currentUser);
|
return this.members.find(m => m.user === DiscordApi.currentUser);
|
||||||
|
@ -193,6 +214,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The total number of members in the guild.
|
* The total number of members in the guild.
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
get memberCount() {
|
get memberCount() {
|
||||||
return Modules.MemberCountStore.getMemberCount(this.id);
|
return Modules.MemberCountStore.getMemberCount(this.id);
|
||||||
|
@ -200,6 +222,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of the guild's custom emojis.
|
* An array of the guild's custom emojis.
|
||||||
|
* @type {List<Emoji>}
|
||||||
*/
|
*/
|
||||||
get emojis() {
|
get emojis() {
|
||||||
return List.from(Modules.EmojiUtils.getGuildEmoji(this.id), e => new Emoji(e, this.id));
|
return List.from(Modules.EmojiUtils.getGuildEmoji(this.id), e => new Emoji(e, this.id));
|
||||||
|
@ -215,6 +238,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current user's permissions on this guild.
|
* The current user's permissions on this guild.
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
get permissions() {
|
get permissions() {
|
||||||
return Modules.GuildPermissions.getGuildPermissions(this.id);
|
return Modules.GuildPermissions.getGuildPermissions(this.id);
|
||||||
|
@ -222,8 +246,8 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the GuildMember object for a user.
|
* Returns the GuildMember object for a user.
|
||||||
* @param {User|GuildMember|Number} user A User or GuildMember object or a user ID
|
* @param {(User|GuildMember|number)} user A User or GuildMember object or a user ID
|
||||||
* @return {GuildMember}
|
* @return {?GuildMember}
|
||||||
*/
|
*/
|
||||||
getMember(user) {
|
getMember(user) {
|
||||||
const member = Modules.GuildMemberStore.getMember(this.id, user.userId || user.id || user);
|
const member = Modules.GuildMemberStore.getMember(this.id, user.userId || user.id || user);
|
||||||
|
@ -232,8 +256,8 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a user is a member of this guild.
|
* Checks if a user is a member of this guild.
|
||||||
* @param {User|GuildMember|Number} user A User or GuildMember object or a user ID
|
* @param {(User|GuildMember|number)} user A User or GuildMember object or a user ID
|
||||||
* @return {Boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
isMember(user) {
|
isMember(user) {
|
||||||
return Modules.GuildMemberStore.isMember(this.id, user.userId || user.id || user);
|
return Modules.GuildMemberStore.isMember(this.id, user.userId || user.id || user);
|
||||||
|
@ -241,6 +265,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the user has not restricted direct messages from members of this guild.
|
* Whether the user has not restricted direct messages from members of this guild.
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
get allowPrivateMessages() {
|
get allowPrivateMessages() {
|
||||||
return !DiscordApi.UserSettings.restrictedGuildIds.includes(this.id);
|
return !DiscordApi.UserSettings.restrictedGuildIds.includes(this.id);
|
||||||
|
@ -262,6 +287,7 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this guild is currently selected.
|
* Whether this guild is currently selected.
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
get isSelected() {
|
get isSelected() {
|
||||||
return DiscordApi.currentGuild === this;
|
return DiscordApi.currentGuild === this;
|
||||||
|
@ -269,16 +295,16 @@ export class Guild {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens this guild's settings window.
|
* Opens this guild's settings window.
|
||||||
* @param {String} section The section to open (see DiscordConstants.GuildSettingsSections)
|
* @param {string} section The section to open (see DiscordConstants.GuildSettingsSections)
|
||||||
*/
|
*/
|
||||||
openSettings(section = 'OVERVIEW') {
|
openSettings(section = 'OVERVIEW') {
|
||||||
Modules.GuildSettingsWindow.setSection(section);
|
|
||||||
Modules.GuildSettingsWindow.open(this.id);
|
Modules.GuildSettingsWindow.open(this.id);
|
||||||
|
Modules.GuildSettingsWindow.setSection(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kicks members who don't have any roles and haven't been seen in the number of days passed.
|
* Kicks members who don't have any roles and haven't been seen in the number of days passed.
|
||||||
* @param {Number} days
|
* @param {number} days
|
||||||
*/
|
*/
|
||||||
pruneMembers(days) {
|
pruneMembers(days) {
|
||||||
this.assertPermissions('KICK_MEMBERS', Modules.DiscordPermissions.KICK_MEMBERS);
|
this.assertPermissions('KICK_MEMBERS', Modules.DiscordPermissions.KICK_MEMBERS);
|
||||||
|
@ -302,12 +328,56 @@ export class Guild {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a channel in this guild.
|
* Opens the create channel modal for this guild.
|
||||||
* @param {Number} type The type of channel to create - either 0 (text), 2 (voice) or 4 (category)
|
|
||||||
* @param {String} name A name for the new channel
|
|
||||||
* @param {ChannelCategory} category The category to create the channel in
|
* @param {ChannelCategory} category The category to create the channel in
|
||||||
* @param {Array} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
* @return {Promise => GuildChannel}
|
*/
|
||||||
|
openCreateTextChannelModal(category, clone) {
|
||||||
|
return this.openCreateChannelModal(Channel.GUILD_TEXT, category, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the create channel modal for this guild.
|
||||||
|
* @param {ChannelCategory} category The category to create the channel in
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
|
*/
|
||||||
|
openCreateVoiceChannelModal(category, clone) {
|
||||||
|
return this.openCreateChannelModal(Channel.GUILD_VOICE, category, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the create channel modal for this guild.
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
|
*/
|
||||||
|
openCreateChannelCategoryModal(clone) {
|
||||||
|
return this.openCreateChannelModal(Channel.GUILD_CATEGORY, undefined, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the create channel modal for this guild.
|
||||||
|
* @param {ChannelCategory} category The category to create the channel in
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
|
*/
|
||||||
|
openCreateNewsChannelModal(category, clone) {
|
||||||
|
return this.openCreateChannelModal(Channel.GUILD_NEWS, category, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the create channel modal for this guild.
|
||||||
|
* @param {ChannelCategory} category The category to create the channel in
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
|
*/
|
||||||
|
openCreateStoreChannelModal(category, clone) {
|
||||||
|
return this.openCreateChannelModal(Channel.GUILD_STORE, category, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this guild.
|
||||||
|
* @param {number} type The type of channel to create - either 0 (text), 2 (voice), 4 (category), 5 (news) or 6 (store)
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {ChannelCategory} category The category to create the channel in
|
||||||
|
* @param {Object[]} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
|
||||||
|
* @return {Promise<GuildChannel>}
|
||||||
*/
|
*/
|
||||||
async createChannel(type, name, category, permission_overwrites) {
|
async createChannel(type, name, category, permission_overwrites) {
|
||||||
this.assertPermissions('MANAGE_CHANNELS', Modules.DiscordPermissions.MANAGE_CHANNELS);
|
this.assertPermissions('MANAGE_CHANNELS', Modules.DiscordPermissions.MANAGE_CHANNELS);
|
||||||
|
@ -328,6 +398,60 @@ export class Guild {
|
||||||
return Channel.fromId(response.body.id);
|
return Channel.fromId(response.body.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this guild.
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {ChannelCategory} category The category to create the channel in
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
|
* @return {Promise<GuildTextChannel>}
|
||||||
|
*/
|
||||||
|
createTextChannel(name, category, clone) {
|
||||||
|
return this.createChannel(Channel.GUILD_TEXT, name, category, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this guild.
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {ChannelCategory} category The category to create the channel in
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
|
* @return {Promise<GuildVoiceChannel>}
|
||||||
|
*/
|
||||||
|
createVoiceChannel(name, category, clone) {
|
||||||
|
return this.createChannel(Channel.GUILD_VOICE, name, category, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this guild.
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
|
* @return {Promise<GuildTextChannel>}
|
||||||
|
*/
|
||||||
|
createChannelCategory(name, clone) {
|
||||||
|
return this.createChannel(Channel.GUILD_CATEGORY, name, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this guild.
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {ChannelCategory} category The category to create the channel in
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
|
* @return {Promise<GuildNewsChannel>}
|
||||||
|
*/
|
||||||
|
createNewsChannel(name, category, clone) {
|
||||||
|
return this.createChannel(Channel.GUILD_NEWS, name, category, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel in this guild.
|
||||||
|
* @param {string} name A name for the new channel
|
||||||
|
* @param {ChannelCategory} category The category to create the channel in
|
||||||
|
* @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
|
||||||
|
* @return {Promise<GuildStoreChannel>}
|
||||||
|
*/
|
||||||
|
createStoreChannel(name, category, clone) {
|
||||||
|
return this.createChannel(Channel.GUILD_STORE, name, category, clone);
|
||||||
|
}
|
||||||
|
|
||||||
openNotificationSettingsModal() {
|
openNotificationSettingsModal() {
|
||||||
Modules.NotificationSettingsModal.open(this.id);
|
Modules.NotificationSettingsModal.open(this.id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"id": "user-settings-example",
|
||||||
|
"name": "User Settings Example",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Samuel Elliott",
|
||||||
|
"url": "https://samuelelliott.ml",
|
||||||
|
"discord_id": "284056145272766465",
|
||||||
|
"github_username": "samuelthomas2774",
|
||||||
|
"twitter_username": "_samuelelliott"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"main": "index.js",
|
||||||
|
"mainExport": "default"
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
exports.default = (Plugin, {Logger, DiscordApi, BdMenuItems, CommonComponents, Api}) => class UserSettingsTest extends Plugin {
|
||||||
|
onstart() {
|
||||||
|
DiscordApi.UserSettings.theme = DiscordApi.UserSettings.ThemeDark; // === 'dark'
|
||||||
|
|
||||||
|
this.menu_item = BdMenuItems.addVueComponent('Test', 'User Settings', {
|
||||||
|
template: `<settings-wrapper headertext="User Settings API">
|
||||||
|
<h4 style="color: #f6f6f7;">Status</h4>
|
||||||
|
<radio-group v-model="UserSettings.status" :options="statusOptions" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Explicit content filter</h4>
|
||||||
|
<radio-group v-model="UserSettings.explicitContentFilter" :options="explicitContentFilterOptions" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Default guilds restricted</h4>
|
||||||
|
<setting-switch v-model="UserSettings.defaultGuildsRestricted" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Friend source flags</h4>
|
||||||
|
<p style="color: #f6f6f7;">{{ JSON.stringify(UserSettings.friendSourceFlags)}}</p>
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Friend source everyone</h4>
|
||||||
|
<setting-switch v-model="UserSettings.friendSourceEveryone" />
|
||||||
|
<h4 style="color: #f6f6f7;">Friend source mutual friends</h4>
|
||||||
|
<setting-switch v-model="UserSettings.friendSourceMutualFriends" />
|
||||||
|
<h4 style="color: #f6f6f7;">Friend source mutual guilds</h4>
|
||||||
|
<setting-switch v-model="UserSettings.friendSourceMutualGuilds" />
|
||||||
|
<h4 style="color: #f6f6f7;">Friend source anyone</h4>
|
||||||
|
<setting-switch v-model="UserSettings.friendSourceAnyone" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Detect platform accounts</h4>
|
||||||
|
<setting-switch v-model="UserSettings.detectPlatformAccounts" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">AFK timeout</h4>
|
||||||
|
<radio-group v-model="UserSettings.afkTimeout" :options="afkTimeoutOptions" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Show current game</h4>
|
||||||
|
<setting-switch v-model="UserSettings.showCurrentGame" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Inline attachment media</h4>
|
||||||
|
<setting-switch v-model="UserSettings.inlineAttachmentMedia" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Inline embed media</h4>
|
||||||
|
<setting-switch v-model="UserSettings.inlineEmbedMedia" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Autoplay GIFs</h4>
|
||||||
|
<setting-switch v-model="UserSettings.autoplayGifs" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Show embeds</h4>
|
||||||
|
<setting-switch v-model="UserSettings.showEmbeds" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Show reactions</h4>
|
||||||
|
<setting-switch v-model="UserSettings.showReactions" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Show spoilers</h4>
|
||||||
|
<radio-group v-model="UserSettings.showSpoilers" :options="showSpoilersOptions" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Animate emoji</h4>
|
||||||
|
<setting-switch v-model="UserSettings.animateEmoji" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Convert emoticons</h4>
|
||||||
|
<setting-switch v-model="UserSettings.convertEmoticons" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Allow TTS messages</h4>
|
||||||
|
<setting-switch v-model="UserSettings.allowTts" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Theme</h4>
|
||||||
|
<radio-group v-model="UserSettings.theme" :options="themeOptions" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Compact mode</h4>
|
||||||
|
<setting-switch v-model="UserSettings.displayCompact" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Colourblind mode</h4>
|
||||||
|
<setting-switch v-model="UserSettings.colourblindMode" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Show activity tab</h4>
|
||||||
|
<setting-switch v-model="UserSettings.showActivityTab" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Developer mode</h4>
|
||||||
|
<setting-switch v-model="UserSettings.developerMode" />
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Locale</h4>
|
||||||
|
<p style="color: #f6f6f7;">{{ JSON.stringify(UserSettings.locale)}}</p>
|
||||||
|
|
||||||
|
<h4 style="color: #f6f6f7;">Timezone offset</h4>
|
||||||
|
<p style="color: #f6f6f7;">{{ JSON.stringify(UserSettings.timezoneOffset)}}</p>
|
||||||
|
</settings-wrapper>`,
|
||||||
|
components: {
|
||||||
|
SettingsWrapper: CommonComponents.SettingsWrapper,
|
||||||
|
SettingSwitch: CommonComponents.SettingSwitch,
|
||||||
|
RadioGroup: CommonComponents.RadioGroup
|
||||||
|
},
|
||||||
|
data() { return {
|
||||||
|
Api, plugin: Api.plugin, UserSettings: DiscordApi.UserSettings,
|
||||||
|
|
||||||
|
statusOptions: [
|
||||||
|
{value: DiscordApi.UserSettings.StatusOnline, text: 'Online'},
|
||||||
|
{value: DiscordApi.UserSettings.StatusIdle, text: 'Idle'},
|
||||||
|
{value: DiscordApi.UserSettings.StatusDND, text: 'Do not disturb'},
|
||||||
|
{value: DiscordApi.UserSettings.StatusInvisible, text: 'Invisible'}
|
||||||
|
],
|
||||||
|
|
||||||
|
explicitContentFilterOptions: [
|
||||||
|
{value: DiscordApi.UserSettings.ExplicitContentFilterDisabled, text: 'Disabled'},
|
||||||
|
{value: DiscordApi.UserSettings.ExplicitContentFilterExceptFriends, text: 'Except friends'},
|
||||||
|
{value: DiscordApi.UserSettings.ExplicitContentFilterEnabled, text: 'Enabled'}
|
||||||
|
],
|
||||||
|
|
||||||
|
afkTimeoutOptions: [
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout1Minute, text: '1 minute'},
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout2Minutes, text: '2 minutes'},
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout3Minutes, text: '3 minutes'},
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout4Minutes, text: '4 minutes'},
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout5Minutes, text: '5 minutes'},
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout6Minutes, text: '6 minutes'},
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout7Minutes, text: '7 minutes'},
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout8Minutes, text: '8 minutes'},
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout9Minutes, text: '9 minutes'},
|
||||||
|
{value: DiscordApi.UserSettings.AfkTimeout10Minutes, text: '10 minutes'}
|
||||||
|
],
|
||||||
|
|
||||||
|
showSpoilersOptions: [
|
||||||
|
{value: DiscordApi.UserSettings.ShowSpoilersOnClick, text: 'On click'},
|
||||||
|
{value: DiscordApi.UserSettings.ShowSpoilersIfModerator, text: 'If moderator'},
|
||||||
|
{value: DiscordApi.UserSettings.ShowSpoilersAlways, text: 'Always'}
|
||||||
|
],
|
||||||
|
|
||||||
|
themeOptions: [
|
||||||
|
{value: DiscordApi.UserSettings.ThemeDark, text: 'Dark'},
|
||||||
|
{value: DiscordApi.UserSettings.ThemeLight, text: 'Light'}
|
||||||
|
]
|
||||||
|
}; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onstop() {
|
||||||
|
BdMenuItems.removeAll();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue