/**
|
|
* @name PlatformIndicators
|
|
* @displayName PlatformIndicators
|
|
* @authorId 415849376598982656
|
|
* @invite gvA2ree
|
|
*/
|
|
/*@cc_on
|
|
@if (@_jscript)
|
|
|
|
// Offer to self-install for clueless users that try to run this directly.
|
|
var shell = WScript.CreateObject("WScript.Shell");
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject");
|
|
var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\BetterDiscord\plugins");
|
|
var pathSelf = WScript.ScriptFullName;
|
|
// Put the user at ease by addressing them in the first person
|
|
shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30);
|
|
if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
|
|
shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40);
|
|
} else if (!fs.FolderExists(pathPlugins)) {
|
|
shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10);
|
|
} else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) {
|
|
fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
|
|
// Show the user where to put plugins in the future
|
|
shell.Exec("explorer " + pathPlugins);
|
|
shell.Popup("I'm installed!", 0, "Successfully installed", 0x40);
|
|
}
|
|
WScript.Quit();
|
|
|
|
@else@*/
|
|
module.exports = (() => {
|
|
const config = {
|
|
info: {
|
|
name: "PlatformIndicators",
|
|
authors: [
|
|
{
|
|
name: "Strencher",
|
|
discord_id: "415849376598982656",
|
|
github_username: "Strencher",
|
|
twitter_username: "Strencher3"
|
|
}
|
|
],
|
|
version: "0.0.5",
|
|
description: "Adds indicators for every platform that the user is using. Source code availble on the repo in the 'src' folder.",
|
|
github: "https://github.com/Strencher/BetterDiscordStuff/blob/master/PlatformIndicators/APlatformIndicators.plugin.js",
|
|
github_raw: "https://raw.githubusercontent.com/Strencher/BetterDiscordStuff/master/PlatformIndicators/APlatformIndicators.plugin.js"
|
|
},
|
|
changelog: [
|
|
{
|
|
title: "v0.0.5",
|
|
type: "fixed",
|
|
items: [
|
|
"Thanks to @qwert#1441 for fixing the padding issue in chat messages!",
|
|
"I still need ideas where to show all of them at one position that is not next to the username... join my Support server => https://discord.gg/gvA2ree to send me ideas!"
|
|
]
|
|
},
|
|
{
|
|
title: "v0.0.4",
|
|
type: "added",
|
|
items: [
|
|
"2 Attempt to fix conflicts with BetterRoleColors.",
|
|
"It'll probably require you to update 2 times because the filename has changed.",
|
|
"Bug fixes... styling fixes..."
|
|
]
|
|
}
|
|
],
|
|
defaultConfig: [
|
|
{
|
|
type: "switch",
|
|
name: "Show in MemberList",
|
|
note: "Shows the platform indicators in the memberlist",
|
|
id: "showInMemberList",
|
|
value: true
|
|
},
|
|
{
|
|
type: "switch",
|
|
name: "Show next to username",
|
|
note: "Shows the platform indicators next the username in messages.",
|
|
id: "showOnMessages",
|
|
value: true
|
|
},
|
|
{
|
|
type: "switch",
|
|
name: "Show in Dmd List",
|
|
note: "Shows the platform indicators in the dm list.",
|
|
id: "showInDmsList",
|
|
value: true
|
|
},
|
|
{
|
|
type: "switch",
|
|
name: "Show next to discord tags",
|
|
note: "Shows the platform indicators right next to the discord tag.",
|
|
id: "showOnTags",
|
|
value: true
|
|
},
|
|
{
|
|
type: "switch",
|
|
name: "Ignore Bots",
|
|
note: "Ignores the status of bots which is always web anyways.",
|
|
id: "ignoreBots",
|
|
value: true
|
|
},
|
|
{
|
|
type: "category",
|
|
name: "icons",
|
|
id: "icons",
|
|
settings: [
|
|
{
|
|
type: "switch",
|
|
name: "Web Icon",
|
|
note: "Show the Web icon.",
|
|
id: "web",
|
|
value: true
|
|
},
|
|
{
|
|
type: "switch",
|
|
name: "Desktop Icon",
|
|
note: "Show the Desktop icon.",
|
|
id: "desktop",
|
|
value: true
|
|
},
|
|
{
|
|
type: "switch",
|
|
name: "Mobile Icon",
|
|
note: "Show the Mobile icon.",
|
|
id: "mobile",
|
|
value: true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
};
|
|
//@ts-ignore
|
|
const BdApi = window.BdApi;
|
|
// @ts-ignore
|
|
return !global.ZeresPluginLibrary ? class {
|
|
constructor() {
|
|
this._config = config;
|
|
}
|
|
getName() { return config.info.name; }
|
|
getAuthor() { return config.info.authors.map(a => a.name).join(", "); }
|
|
getDescription() { return config.info.description; }
|
|
getVersion() { return config.info.version; }
|
|
load() {
|
|
BdApi.showConfirmationModal("Library plugin is needed", [`The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`], {
|
|
confirmText: "Download",
|
|
cancelText: "Cancel",
|
|
onConfirm: () => {
|
|
require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => {
|
|
if (error)
|
|
return require("electron").shell.openExternal("https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js");
|
|
await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r));
|
|
});
|
|
}
|
|
});
|
|
}
|
|
start() { }
|
|
stop() { }
|
|
} : (([Plugin, Api]) => {
|
|
const plugin = (Plugin, Api) => {
|
|
const { Utilities, WebpackModules, PluginUtilities, ReactTools, Patcher, Logger, DiscordModules: { React, UserStatusStore, Dispatcher, DiscordConstants: { ActionTypes } } } = Api;
|
|
const Utils = Object.assign(Utilities, {
|
|
joinClassNames: (...classNames) => classNames.filter(Boolean).join(" "),
|
|
capFirst(text) {
|
|
return text[0].toUpperCase() + text.slice(1);
|
|
}
|
|
});
|
|
const DesktopIcon = React.memo(props => (React.createElement("svg", Object.assign({ className: "PI-icon_desktop", width: "24", height: "24" }, props, { viewBox: "0 0 24 24" }),
|
|
React.createElement("path", { fill: "currentColor", d: "M4 2.5C2.897 2.5 2 3.397 2 4.5V15.5C2 16.604 2.897 17.5 4 17.5H11V19.5H7V21.5H17V19.5H13V17.5H20C21.103 17.5 22 16.604 22 15.5V4.5C22 3.397 21.103 2.5 20 2.5H4ZM20 4.5V13.5H4V4.5H20Z" }))));
|
|
const WebIcon = React.memo(props => (React.createElement("svg", Object.assign({ className: "PI-icon_web", width: "24", height: "24" }, props, { viewBox: "0 0 24 24" }),
|
|
React.createElement("path", { fill: "currentColor", d: "M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM11 19.93C7.05 19.44 4 16.08 4 12C4 11.38 4.08 10.79 4.21 10.21L9 15V16C9 17.1 9.9 18 11 18V19.93ZM17.9 17.39C17.64 16.58 16.9 16 16 16H15V13C15 12.45 14.55 12 14 12H8V10H10C10.55 10 11 9.55 11 9V7H13C14.1 7 15 6.1 15 5V4.59C17.93 5.78 20 8.65 20 12C20 14.08 19.2 15.97 17.9 17.39Z" }))));
|
|
const MobileIcon = React.memo(props => (React.createElement("svg", Object.assign({ className: "PI-icon_mobile", width: "24", height: "24" }, props, { viewBox: "0 0 24 24" }),
|
|
React.createElement("g", { fill: "none" },
|
|
React.createElement("path", { fill: "currentColor", d: "M15.5 1h-8C6.12 1 5 2.12 5 3.5v17C5 21.88 6.12 23 7.5 23h8c1.38 0 2.5-1.12 2.5-2.5v-17C18 2.12 16.88 1 15.5 1zm-4 21c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm4.5-4H7V4h9v14z" })))));
|
|
const Icons = {
|
|
mobile: MobileIcon,
|
|
web: WebIcon,
|
|
desktop: DesktopIcon
|
|
};
|
|
const getClass = (props = [], items = props, exclude = [], selector = false) => {
|
|
const module = WebpackModules.getModule(m => m && props.every(prop => m[prop] !== undefined) && exclude.every(e => m[e] == undefined));
|
|
if (!module)
|
|
return '';
|
|
return (selector ? '.' : '') + items.map(item => module[item]).join(selector ? '.' : ' ');
|
|
};
|
|
const { TooltipContainer: Tooltip } = WebpackModules.getByProps("TooltipContainer");
|
|
const StatusModule = WebpackModules.getByProps("Status", "getStatusMask");
|
|
const Flux = WebpackModules.getByProps("connectStores");
|
|
const MessageTimestamp = WebpackModules.getByProps("MessageTimestamp");
|
|
const { Messages } = WebpackModules.getByProps("Messages", "setLocale");
|
|
const AuthStore = WebpackModules.getByProps("getId", "getEmail");
|
|
let plugin, currentClientStatus;
|
|
const StatusIndicators = function StatusIndicators(props) {
|
|
if (!props)
|
|
return null;
|
|
return (React.createElement("div", { className: Utils.joinClassNames("PI-indicatorContainer", "PI-type_" + props.type) }, Object.keys(props).filter(e => plugin.settings.icons[e]).map(e => {
|
|
const color = StatusModule.getStatusColor(props[e]);
|
|
const Icon = Icons[e];
|
|
return React.createElement(Tooltip, { text: Utils.capFirst(e) + ": " + Messages[`STATUS_${(props[e] == "mobile" ? "mobile_online" : props[e]).toUpperCase()}`], position: "top" },
|
|
React.createElement(Icon, { style: { color }, width: "18", height: "18" }));
|
|
})));
|
|
};
|
|
return class PlatformIndicators extends Plugin {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.css = `
|
|
.PI-indicatorContainer {
|
|
display: inline-flex;
|
|
}
|
|
|
|
.PI-indicatorContainer svg {
|
|
margin-left: 2px;
|
|
}
|
|
|
|
.header-23xsNx {
|
|
display: flex !important;
|
|
flex-direction: row !important;
|
|
}
|
|
|
|
.PI-container {
|
|
display: flex;
|
|
}
|
|
`;
|
|
this.getSettingsPanel = () => {
|
|
return this.buildSettingsPanel().getElement();
|
|
};
|
|
this.ON_PRESENCE_UPDATE = ({ user, clientStatus }) => {
|
|
if (user.id != AuthStore.getId())
|
|
return;
|
|
currentClientStatus = clientStatus;
|
|
UserStatusStore.emitChange();
|
|
};
|
|
}
|
|
getClients(userId) {
|
|
const isSelf = userId == AuthStore.getId();
|
|
const status = isSelf ? currentClientStatus : UserStatusStore.getState().clientStatuses[userId];
|
|
return status !== null && status !== void 0 ? status : {};
|
|
}
|
|
onStart() {
|
|
plugin = this;
|
|
PluginUtilities.addStyle(config.info.name, this.css);
|
|
Utils.suppressErrors(this.patchMessageHeader.bind(this))();
|
|
Utils.suppressErrors(this.patchMemberListItem.bind(this))();
|
|
Utils.suppressErrors(this.patchDmList.bind(this))();
|
|
Utils.suppressErrors(this.patchDiscordTag.bind(this))();
|
|
Dispatcher.subscribe(ActionTypes.PRESENCE_UPDATE, this.ON_PRESENCE_UPDATE);
|
|
}
|
|
async patchMemberListItem() {
|
|
const MemberListItem = WebpackModules.getByDisplayName("MemberListItem");
|
|
Patcher.after(MemberListItem.prototype, "renderDecorators", ({ props }, _, returnValue) => {
|
|
var _a;
|
|
if (!this.settings.showInMemberList)
|
|
return;
|
|
try {
|
|
const tree = (_a = returnValue === null || returnValue === void 0 ? void 0 : returnValue.props) === null || _a === void 0 ? void 0 : _a.children;
|
|
if (!Array.isArray(tree) || (this.settings.ignoreBots && props.user.bot))
|
|
return;
|
|
const FluxWrapper = Flux.connectStores([UserStatusStore], () => this.getClients(props.user.id))(clients => React.createElement(StatusIndicators, Object.assign({}, clients, { type: "memberList" })));
|
|
tree.unshift(React.createElement(FluxWrapper, null));
|
|
}
|
|
catch (error) {
|
|
Logger.error("Error while patching MemberListItem:", error);
|
|
}
|
|
});
|
|
this.forceUpdate(getClass(["member"], ["member"], [], true));
|
|
}
|
|
patchMessageHeader() {
|
|
Patcher.after(MessageTimestamp, "default", (_, [props], returnValue) => {
|
|
if (!this.settings.showOnMessages)
|
|
return;
|
|
try {
|
|
const tree = Utils.getNestedProp(returnValue, "props.children.1.props.children");
|
|
if (!Array.isArray(tree) || (this.settings.ignoreBots && props.message.author.bot))
|
|
return;
|
|
const FluxWrapper = Flux.connectStores([UserStatusStore], () => this.getClients(props.message.author.id))(clients => React.createElement(StatusIndicators, Object.assign({}, clients, { type: "chat" })));
|
|
tree.splice(2, 0, React.createElement(FluxWrapper, null));
|
|
}
|
|
catch (error) {
|
|
Logger.error("Error while patching MessageTimestammp:", error);
|
|
}
|
|
});
|
|
}
|
|
patchDmList() {
|
|
var _a;
|
|
const { default: PrivateChannel } = (_a = WebpackModules.getModule(m => { var _a; return ((_a = m === null || m === void 0 ? void 0 : m.default) === null || _a === void 0 ? void 0 : _a.displayName) === "PrivateChannel"; })) !== null && _a !== void 0 ? _a : {};
|
|
Patcher.after(PrivateChannel.prototype, "render", (_this, _, ret) => {
|
|
const unpatch = Patcher.after(ret.type, "render", (_, __, ret) => {
|
|
var _a, _b;
|
|
unpatch();
|
|
if (!this.settings.showInDmsList)
|
|
return;
|
|
const tree = Utils.findInReactTree(ret, m => { var _a; return ((_a = m === null || m === void 0 ? void 0 : m.className) === null || _a === void 0 ? void 0 : _a.indexOf("nameAndDecorators")) > -1; });
|
|
if (!tree)
|
|
return;
|
|
if (!Array.isArray(tree === null || tree === void 0 ? void 0 : tree.children) || (this.settings.ignoreBots && ((_b = (_a = _this.props) === null || _a === void 0 ? void 0 : _a.user) === null || _b === void 0 ? void 0 : _b.bot)))
|
|
return;
|
|
const FluxWrapper = Flux.connectStores([UserStatusStore], () => { var _a, _b; return this.getClients((_b = (_a = _this.props) === null || _a === void 0 ? void 0 : _a.user) === null || _b === void 0 ? void 0 : _b.id); })(clients => React.createElement(StatusIndicators, Object.assign({}, clients, { type: "dmList" })));
|
|
tree.children = [
|
|
tree.children,
|
|
React.createElement(FluxWrapper, null)
|
|
];
|
|
});
|
|
});
|
|
this.forceUpdate(getClass(["privateChannels"], ["privateChannels"], [], true));
|
|
}
|
|
forceUpdate(selector) {
|
|
const nodes = document.querySelectorAll(selector);
|
|
if (!nodes.length)
|
|
return;
|
|
for (const node of nodes) {
|
|
const instance = ReactTools.getOwnerInstance(node);
|
|
if (!instance)
|
|
return;
|
|
instance.forceUpdate();
|
|
}
|
|
}
|
|
patchDiscordTag() {
|
|
const DiscordTag = WebpackModules.getModule(m => { var _a; return ((_a = m === null || m === void 0 ? void 0 : m.default) === null || _a === void 0 ? void 0 : _a.displayName) === "DiscordTag"; });
|
|
const NameTag = WebpackModules.getModule(m => { var _a; return ((_a = m === null || m === void 0 ? void 0 : m.default) === null || _a === void 0 ? void 0 : _a.displayName) === "NameTag"; });
|
|
Patcher.after(DiscordTag, "default", (_, [{ user }], ret) => {
|
|
ret.props.user = user;
|
|
});
|
|
Patcher.after(NameTag, "default", (_, [args], ret) => {
|
|
if (!this.settings.showOnTags)
|
|
return;
|
|
const tree = ret === null || ret === void 0 ? void 0 : ret.props;
|
|
var { user } = args;
|
|
if (!Array.isArray(tree === null || tree === void 0 ? void 0 : tree.children) || (this.settings.ignoreBots && (user === null || user === void 0 ? void 0 : user.bot)))
|
|
return;
|
|
const FluxWrapper = Flux.connectStores([UserStatusStore], () => this.getClients(user === null || user === void 0 ? void 0 : user.id))(clients => React.createElement(StatusIndicators, Object.assign({}, clients, { type: "discordTag" })));
|
|
try {
|
|
tree.children.push(React.createElement(FluxWrapper, null));
|
|
}
|
|
catch (error) {
|
|
Logger.error("Failed to inject into NameTag:\n", error);
|
|
}
|
|
return ret;
|
|
});
|
|
}
|
|
onStop() {
|
|
Patcher.unpatchAll();
|
|
PluginUtilities.removeStyle(config.info.name);
|
|
Dispatcher.unsubscribe(ActionTypes.PRESENCE_UPDATE, this.ON_PRESENCE_UPDATE);
|
|
}
|
|
};
|
|
};
|
|
return plugin(Plugin, Api);
|
|
//@ts-ignore
|
|
})(global.ZeresPluginLibrary.buildPlugin(config));
|
|
})();
|
|
/*@end@*/
|