diff --git a/Plugins/ThemeRepo/ThemeRepo.plugin.js b/Plugins/ThemeRepo/ThemeRepo.plugin.js index 93bd8cf47c..eb11d60704 100644 --- a/Plugins/ThemeRepo/ThemeRepo.plugin.js +++ b/Plugins/ThemeRepo/ThemeRepo.plugin.js @@ -1,1183 +1,1149 @@ //META{"name":"ThemeRepo","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/ThemeRepo","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/ThemeRepo/ThemeRepo.plugin.js"}*// -var ThemeRepo = (_ => { - var _this; - var loading, cachedThemes, grabbedThemes, foundThemes, loadedThemes, generatorThemes, updateInterval; - var list, header, preview, searchTimeout, updateGeneratorTimeout, forceRerenderGenerator, nativeCSS, nativeCSSvars, forcedSort, forcedOrder, showOnlyOutdated; - var settings = {}, modalSettings = {}, favorites = [], customList = []; - - const themeStates = { - UPDATED: 0, - OUTDATED: 1, - DOWNLOADABLE: 2 - }; - const buttonData = { - UPDATED: { - colorClass: "GREEN", - backgroundColor: "STATUS_GREEN", - text: "Updated" - }, - OUTDATED: { - colorClass: "RED", - backgroundColor: "STATUS_RED", - text: "Outdated" - }, - DOWNLOADABLE: { - colorClass: "BRAND", - backgroundColor: "BRAND", - text: "Download" +module.exports = (_ => { + const config = { + "info": { + "name": "ThemeRepo", + "author": "DevilBro", + "version": "2.0.7", + "description": "Allows you to preview all themes from the theme repo and download them on the fly. Repo button is in the theme settings." } }; - const favStates = { - FAVORIZED: 0, - NOT_FAVORIZED: 1 - }; - const newStates = { - NEW: 0, - NOT_NEW: 1 - }; - const sortKeys = { - NAME: "Name", - AUTHOR: "Author", - VERSION: "Version", - DESCRIPTION: "Description", - STATE: "Update State", - FAV: "Favorites", - NEW: "New Themes" - }; - const orderKeys = { - ASC: "ascending", - DESC: "descending" - }; - - const themeRepoIcon = ``; - - const RepoListComponent = class ThemeList extends BdApi.React.Component { - componentDidMount() { - list = this; - BDFDB.TimeUtils.timeout(_ => { - forcedSort = null; - forcedOrder = null; - showOnlyOutdated = false; - }, 5000); - } - componentWillUnmount() { - if (preview) { - BDFDB.WindowUtils.close(preview); - preview = null; + return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return config.info.description;} + + load() { + if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue:[]}); + if (!window.BDFDB_Global.downloadModal) { + window.BDFDB_Global.downloadModal = true; + BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, + onConfirm: _ => {delete window.BDFDB_Global.downloadModal;require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (error, response, body) => {require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), body, _ => {});});} + }); } - } - filterThemes() { - let themes = Object.keys(loadedThemes).map(url => { - let theme = loadedThemes[url]; - let instTheme = BDFDB.BDUtils.getTheme(theme.name); - if (instTheme && instTheme.author.toUpperCase() == theme.author.toUpperCase()) theme.state = instTheme.version != theme.version ? themeStates.OUTDATED : themeStates.UPDATED; - else theme.state = themeStates.DOWNLOADABLE; - return { - url: theme.url, - requestUrl: theme.requestUrl, - search: (theme.name + " " + theme.version + " " + theme.author + " " + theme.description).toUpperCase(), - name: theme.name, - version: theme.version, - author: theme.author, - description: theme.description || "No Description found.", - fav: favorites.includes(url) ? favStates.FAVORIZED : favStates.NOT_FAVORIZED, - new: !cachedThemes.includes(url) ? newStates.NEW : newStates.NOT_NEW, - state: theme.state, - css: theme.css, - fullCSS: theme.fullCSS - }; - }); - if (!this.props.updated) themes = themes.filter(theme => theme.state != themeStates.UPDATED); - if (!this.props.outdated) themes = themes.filter(theme => theme.state != themeStates.OUTDATED); - if (!this.props.downloadable) themes = themes.filter(theme => theme.state != themeStates.DOWNLOADABLE); - if (this.props.searchString) { - let searchString = this.props.searchString.toUpperCase(); - themes = themes.filter(theme => theme.search.indexOf(searchString) > -1).map(theme => Object.assign({}, theme, { - name: BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(BDFDB.StringUtils.highlight(theme.name, searchString))) || theme.name, - version: BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(BDFDB.StringUtils.highlight(theme.version, searchString))) || theme.version, - author: BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(BDFDB.StringUtils.highlight(theme.author, searchString))) || theme.author, - description: BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(BDFDB.StringUtils.highlight(theme.description, searchString))) || theme.description - })); + if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + } + start() {} + stop() {} + } : (([Plugin, BDFDB]) => { + var _this; + var loading, cachedThemes, grabbedThemes, foundThemes, loadedThemes, generatorThemes, updateInterval; + var list, header, preview, searchTimeout, updateGeneratorTimeout, forceRerenderGenerator, nativeCSS, nativeCSSvars, forcedSort, forcedOrder, showOnlyOutdated; + var settings = {}, modalSettings = {}, favorites = [], customList = []; + + const themeStates = { + UPDATED: 0, + OUTDATED: 1, + DOWNLOADABLE: 2 + }; + const buttonData = { + UPDATED: { + colorClass: "GREEN", + backgroundColor: "STATUS_GREEN", + text: "Updated" + }, + OUTDATED: { + colorClass: "RED", + backgroundColor: "STATUS_RED", + text: "Outdated" + }, + DOWNLOADABLE: { + colorClass: "BRAND", + backgroundColor: "BRAND", + text: "Download" } - - BDFDB.ArrayUtils.keySort(themes, (!this.props.sortKey || this.props.sortKey == "NEW" && !themes.some(theme => theme.new == newStates.NEW) ? Object.keys(sortKeys)[0] : this.props.sortKey).toLowerCase()); - if (this.props.orderKey == "DESC") themes.reverse(); - return themes; - } - openPreview() { - preview = BDFDB.WindowUtils.open(this, "https://mwittrien.github.io/BetterDiscordAddons/Plugins/_res/DiscordPreview.html", { - alwaysOnTop: settings.keepOnTop, - showOnReady: true, - frame: false, - onLoad: _ => { - let titleBar = document.querySelector(BDFDB.dotCN.titlebar); - preview.executeJavaScriptSafe(`window.onmessage({ - location: document.location.origin, - origin: "ThemeRepo", - reason: "OnLoad", - username: ${JSON.stringify(BDFDB.UserUtils.me.username || "")}, - id: ${JSON.stringify(BDFDB.UserUtils.me.id || "")}, - discriminator: ${JSON.stringify(BDFDB.UserUtils.me.discriminator || "")}, - avatar: ${JSON.stringify(BDFDB.UserUtils.getAvatar() || "")}, - classes: ${JSON.stringify(JSON.stringify(BDFDB.DiscordClasses))}, - classModules: ${JSON.stringify(JSON.stringify(BDFDB.DiscordClassModules))}, - nativeCSS: ${JSON.stringify(nativeCSS || "")}, - htmlClassName: ${JSON.stringify(document.documentElement.className || "")}, - titleBar: ${JSON.stringify(titleBar && titleBar.outerHTML || "")} - })`); - if (this.props.currentTheme) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "NewTheme", - checked: true, - css: ${JSON.stringify(this.props.currentTheme.css || "")} - })`); - if (this.props.currentGenerator) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "NewTheme", - checked: true, - css: ${JSON.stringify((loadedThemes[this.props.currentGenerator] || {}).fullCSS || "")} - })`); - if (this.props.useLightMode) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "DarkLight", - checked: true - })`); - if (this.props.useNormalizer) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "Normalize", - checked: true - })`); - if (this.props.useCustomCSS) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "CustomCSS", - checked: true - })`); - if (this.props.useThemeFixer) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "ThemeFixer", - checked: true - })`); - }, - onClose: _ => { + }; + const favStates = { + FAVORIZED: 0, + NOT_FAVORIZED: 1 + }; + const newStates = { + NEW: 0, + NOT_NEW: 1 + }; + const sortKeys = { + NAME: "Name", + AUTHOR: "Author", + VERSION: "Version", + DESCRIPTION: "Description", + STATE: "Update State", + FAV: "Favorites", + NEW: "New Themes" + }; + const orderKeys = { + ASC: "ascending", + DESC: "descending" + }; + + const themeRepoIcon = ``; + + const RepoListComponent = class ThemeList extends BdApi.React.Component { + componentDidMount() { + list = this; + BDFDB.TimeUtils.timeout(_ => { + forcedSort = null; + forcedOrder = null; + showOnlyOutdated = false; + }, 5000); + } + componentWillUnmount() { + if (preview) { + BDFDB.WindowUtils.close(preview); preview = null; } - }); - } - render() { - let automaticLoading = BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds.automaticLoading); - if (!this.props.tab) this.props.tab = "Themes"; - this.props.entries = (!loading.is && !BDFDB.ObjectUtils.isEmpty(loadedThemes) ? this.filterThemes() : []).map(theme => BDFDB.ReactUtils.createElement(RepoCardComponent, { - theme: theme - })).filter(n => n); - - BDFDB.TimeUtils.timeout(_ => { - if (!loading.is && header && this.props.entries.length != header.props.amount) { - header.props.amount = this.props.entries.length; - BDFDB.ReactUtils.forceUpdate(header); + } + filterThemes() { + let themes = Object.keys(loadedThemes).map(url => { + let theme = loadedThemes[url]; + let instTheme = BDFDB.BDUtils.getTheme(theme.name); + if (instTheme && instTheme.author.toUpperCase() == theme.author.toUpperCase()) theme.state = instTheme.version != theme.version ? themeStates.OUTDATED : themeStates.UPDATED; + else theme.state = themeStates.DOWNLOADABLE; + return { + url: theme.url, + requestUrl: theme.requestUrl, + search: (theme.name + " " + theme.version + " " + theme.author + " " + theme.description).toUpperCase(), + name: theme.name, + version: theme.version, + author: theme.author, + description: theme.description || "No Description found.", + fav: favorites.includes(url) ? favStates.FAVORIZED : favStates.NOT_FAVORIZED, + new: theme.state == themeStates.DOWNLOADABLE && !cachedThemes.includes(url) ? newStates.NEW : newStates.NOT_NEW, + state: theme.state, + css: theme.css, + fullCSS: theme.fullCSS + }; + }); + if (!this.props.updated) themes = themes.filter(theme => theme.state != themeStates.UPDATED); + if (!this.props.outdated) themes = themes.filter(theme => theme.state != themeStates.OUTDATED); + if (!this.props.downloadable) themes = themes.filter(theme => theme.state != themeStates.DOWNLOADABLE); + if (this.props.searchString) { + let searchString = this.props.searchString.toUpperCase(); + themes = themes.filter(theme => theme.search.indexOf(searchString) > -1).map(theme => Object.assign({}, theme, { + name: BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(BDFDB.StringUtils.highlight(theme.name, searchString))) || theme.name, + version: BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(BDFDB.StringUtils.highlight(theme.version, searchString))) || theme.version, + author: BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(BDFDB.StringUtils.highlight(theme.author, searchString))) || theme.author, + description: BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(BDFDB.StringUtils.highlight(theme.description, searchString))) || theme.description + })); } - }); - - if (forceRerenderGenerator && this.props.tab == "Generator") BDFDB.TimeUtils.timeout(_ => { - forceRerenderGenerator = false; - BDFDB.ReactUtils.forceUpdate(this); - }); - - return [ - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { - tab: "Themes", - open: this.props.tab == "Themes", - render: false, - children: loading.is ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { - direction: BDFDB.LibraryComponents.Flex.Direction.VERTICAL, - justify: BDFDB.LibraryComponents.Flex.Justify.CENTER, - style: {marginTop: "50%"}, - children: [ - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Spinner, { - type: BDFDB.LibraryComponents.Spinner.Type.WANDERING_CUBES - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextElement, { - className: BDFDB.disCN.margintop20, - style: {textAlign: "center"}, - children: "Themes are still being fetched. Please wait a moment." - }) - ] - }) : BDFDB.ReactUtils.forceStyle(BDFDB.ReactUtils.createElement("div", { - className: BDFDB.disCN._repolist, - style: { - display: "flex", - flexDirection: "column", - margin: "unset", - width: "unset" - }, - children: this.props.entries - }), ["display", "flex-direction", "margin", "width"]) - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { - tab: "Generator", - open: this.props.tab == "Generator", - render: false, - children: [ - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - className: BDFDB.disCN.marginbottom20, - type: "Select", - label: "Choose a Generator Theme", - basis: "60%", - value: this.props.currentGenerator && this.props.currentGenerator.value || "-----", - options: [{value:"-----", label:"-----"}, nativeCSSvars && {value:"nativediscord", label:"Discord", native:true}].concat((generatorThemes).map(url => ({value:url, label:(loadedThemes[url] || {}).name || "-----"})).sort((x, y) => (x.label < y.label ? -1 : x.label > y.label ? 1 : 0))).filter(n => n), - searchable: true, - onChange: (value, instance) => { - if (loadedThemes[value.value] || value.native) { - if (this.props.currentGenerator) forceRerenderGenerator = true; - this.props.currentGenerator = value; - this.props.generatorValues = {}; - } - else { - delete this.props.currentGenerator; - delete this.props.generatorValues; - } - delete this.props.currentTheme; - if (preview) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "NewTheme", - checked: true, - css: ${JSON.stringify((loadedThemes[value.value] || {}).fullCSS || "")} - })`); - else this.openPreview(); - BDFDB.ReactUtils.forceUpdate(this); - } - }), - !this.props.currentGenerator ? null : (forceRerenderGenerator ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + + BDFDB.ArrayUtils.keySort(themes, (!this.props.sortKey || this.props.sortKey == "NEW" && !themes.some(theme => theme.new == newStates.NEW) ? Object.keys(sortKeys)[0] : this.props.sortKey).toLowerCase()); + if (this.props.orderKey == "DESC") themes.reverse(); + return themes; + } + openPreview() { + preview = BDFDB.WindowUtils.open(this, "https://mwittrien.github.io/BetterDiscordAddons/Plugins/_res/DiscordPreview.html", { + alwaysOnTop: settings.keepOnTop, + showOnReady: true, + frame: false, + onLoad: _ => { + let titleBar = document.querySelector(BDFDB.dotCN.titlebar); + preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "OnLoad", + username: ${JSON.stringify(BDFDB.UserUtils.me.username || "")}, + id: ${JSON.stringify(BDFDB.UserUtils.me.id || "")}, + discriminator: ${JSON.stringify(BDFDB.UserUtils.me.discriminator || "")}, + avatar: ${JSON.stringify(BDFDB.UserUtils.getAvatar() || "")}, + classes: ${JSON.stringify(JSON.stringify(BDFDB.DiscordClasses))}, + classModules: ${JSON.stringify(JSON.stringify(BDFDB.DiscordClassModules))}, + nativeCSS: ${JSON.stringify((nativeCSS || "").replace(/\/assets\//g, document.location.origin + "/assets/").replace(/[\t\r\n]/g, ""))}, + htmlClassName: ${JSON.stringify(document.documentElement.className || "")}, + titleBar: ${JSON.stringify(titleBar && titleBar.outerHTML || "")} + })`); + if (this.props.currentTheme) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "NewTheme", + checked: true, + css: ${JSON.stringify(this.props.currentTheme.css || "")} + })`); + if (this.props.currentGenerator) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "NewTheme", + checked: true, + css: ${JSON.stringify((loadedThemes[this.props.currentGenerator] || {}).fullCSS || "")} + })`); + if (this.props.useLightMode) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "DarkLight", + checked: true + })`); + if (this.props.useNormalizer) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "Normalize", + checked: true + })`); + if (this.props.useCustomCSS) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "CustomCSS", + checked: true + })`); + if (this.props.useThemeFixer) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "ThemeFixer", + checked: true + })`); + }, + onClose: _ => { + preview = null; + } + }); + } + render() { + let automaticLoading = BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds.automaticLoading); + if (!this.props.tab) this.props.tab = "Themes"; + this.props.entries = (!loading.is && !BDFDB.ObjectUtils.isEmpty(loadedThemes) ? this.filterThemes() : []).map(theme => BDFDB.ReactUtils.createElement(RepoCardComponent, { + theme: theme + })).filter(n => n); + + BDFDB.TimeUtils.timeout(_ => { + if (!loading.is && header && this.props.entries.length != header.props.amount) { + header.props.amount = this.props.entries.length; + BDFDB.ReactUtils.forceUpdate(header); + } + }); + + if (forceRerenderGenerator && this.props.tab == "Generator") BDFDB.TimeUtils.timeout(_ => { + forceRerenderGenerator = false; + BDFDB.ReactUtils.forceUpdate(this); + }); + + return [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: "Themes", + open: this.props.tab == "Themes", + render: false, + children: loading.is ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { direction: BDFDB.LibraryComponents.Flex.Direction.VERTICAL, justify: BDFDB.LibraryComponents.Flex.Justify.CENTER, style: {marginTop: "50%"}, - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Spinner, { - type: BDFDB.LibraryComponents.Spinner.Type.WANDERING_CUBES - }) - }) : [ + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Spinner, { + type: BDFDB.LibraryComponents.Spinner.Type.WANDERING_CUBES + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextElement, { + className: BDFDB.disCN.margintop20, + style: {textAlign: "center"}, + children: "Themes are still being fetched. Please wait a moment." + }) + ] + }) : BDFDB.ReactUtils.forceStyle(BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._repolist, + style: { + display: "flex", + flexDirection: "column", + margin: "unset", + width: "unset" + }, + children: this.props.entries + }), ["display", "flex-direction", "margin", "width"]) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: "Generator", + open: this.props.tab == "Generator", + render: false, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: BDFDB.disCN.marginbottom20, + type: "Select", + label: "Choose a Generator Theme", + basis: "60%", + value: this.props.currentGenerator && this.props.currentGenerator.value || "-----", + options: [{value:"-----", label:"-----"}, nativeCSSvars && {value:"nativediscord", label:"Discord", native:true}].concat((generatorThemes).map(url => ({value:url, label:(loadedThemes[url] || {}).name || "-----"})).sort((x, y) => (x.label < y.label ? -1 : x.label > y.label ? 1 : 0))).filter(n => n), + searchable: true, + onChange: (value, instance) => { + if (loadedThemes[value.value] || value.native) { + if (this.props.currentGenerator) forceRerenderGenerator = true; + this.props.currentGenerator = value; + this.props.generatorValues = {}; + } + else { + delete this.props.currentGenerator; + delete this.props.generatorValues; + } + delete this.props.currentTheme; + if (preview) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "NewTheme", + checked: true, + css: ${JSON.stringify((loadedThemes[value.value] || {}).fullCSS || "")} + })`); + else this.openPreview(); + BDFDB.ReactUtils.forceUpdate(this); + } + }), + !this.props.currentGenerator ? null : (forceRerenderGenerator ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + direction: BDFDB.LibraryComponents.Flex.Direction.VERTICAL, + justify: BDFDB.LibraryComponents.Flex.Justify.CENTER, + style: {marginTop: "50%"}, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Spinner, { + type: BDFDB.LibraryComponents.Spinner.Type.WANDERING_CUBES + }) + }) : [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: BDFDB.disCN.marginbottom20, + type: "Button", + label: "Download generated Theme", + children: "Download", + onClick: _ => { + if (this.props.currentGenerator.native) { + _this.createThemeFile("Discord.theme.css", `//META{"name":"Discord","description":"Allows you to easily customize discords native look","author":"DevilBro","version":"1.0.0","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien"}*//\n\n` + _this.generateTheme(nativeCSSvars, this.props.generatorValues)); + } + else if (loadedThemes[this.props.currentGenerator.value]) { + _this.createThemeFile(loadedThemes[this.props.currentGenerator.value].name + ".theme.css", _this.generateTheme(loadedThemes[this.props.currentGenerator.value].fullCSS, this.props.generatorValues)); + } + } + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, { + className: BDFDB.disCN.marginbottom20 + }), + (_ => { + let vars = this.props.currentGenerator.native ? nativeCSSvars.split(".theme-dark, .theme-light") : loadedThemes[this.props.currentGenerator.value].fullCSS.split(":root"); + if (vars.length < 2) return null; + vars = vars[1].replace(/\t\(/g, " (").replace(/\r|\t| {2,}/g, "").replace(/\/\*\n*((?!\/\*|\*\/).|\n)*\n+((?!\/\*|\*\/).|\n)*\n*\*\//g, "").replace(/\n\/\*.*?\*\//g, "").replace(/\n/g, ""); + vars = vars.split("{"); + vars.shift(); + vars = vars.join("{").replace(/\s*(:|;|--|\*)\s*/g, "$1"); + vars = vars.split("}")[0]; + vars = vars.slice(2).split(/;--|\*\/--/); + let inputRefs = []; + for (let varStr of vars) { + varStr = varStr.split(":"); + let varName = varStr.shift().trim(); + varStr = varStr.join(":").split(/;[^A-z0-9]|\/\*/); + let oldValue = varStr.shift().trim(); + if (oldValue) { + let childType = "text", childMode = ""; + let isColor = BDFDB.ColorUtils.getType(oldValue); + let isComp = !isColor && /^[0-9 ]+,[0-9 ]+,[0-9 ]+$/g.test(oldValue); + if (isColor || isComp) { + childType = "color"; + childMode = isComp && "comp"; + } + else { + let isUrlFile = /url\(.+\)/gi.test(oldValue); + let isFile = !isUrlFile && /(http(s)?):\/\/[(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.test(oldValue); + if (isFile || isUrlFile) { + childType = "file"; + childMode = isUrlFile && "url"; + } + } + let varDescription = varStr.join("").replace(/\*\/|\/\*/g, "").replace(/:/g, ": ").replace(/: \//g, ":/").replace(/--/g, " --").replace(/\( --/g, "(--").trim(); + this.props.generatorValues[varName] = {value:oldValue, oldValue}; + inputRefs.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: BDFDB.disCN.marginbottom20, + dividerbottom: vars[vars.length-1] != varStr, + type: "TextInput", + childProps: { + type: childType, + mode: childMode, + filter: childType == "file" && "image" + }, + label: varName[0].toUpperCase() + varName.slice(1), + note: varDescription && varDescription.indexOf("*") == 0 ? varDescription.slice(1) : varDescription, + basis: "70%", + value: oldValue, + placeholder: oldValue, + onChange: value => { + BDFDB.TimeUtils.clear(updateGeneratorTimeout); + updateGeneratorTimeout = BDFDB.TimeUtils.timeout(_ => { + this.props.generatorValues[varName] = {value, oldValue}; + if (preview) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "NewTheme", + checked: true, + css: ${JSON.stringify(_this.generateTheme(this.props.currentGenerator.native ? nativeCSSvars : loadedThemes[this.props.currentGenerator.value].fullCSS, this.props.generatorValues) || "")} + })`); + }, 1000); + } + })); + } + } + return inputRefs; + })() + ]) + ].flat(10).filter(n => n) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: BDFDB.LanguageUtils.LanguageStrings.SETTINGS, + open: this.props.tab == BDFDB.LanguageUtils.LanguageStrings.SETTINGS, + render: false, + children: [ + !automaticLoading && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCNS.titledefault + BDFDB.disCN.cursordefault, + children: "To experience ThemeRepo in the best way. I would recommend you to enable BD intern reload function, that way all downloaded files are loaded into Discord without the need to reload." + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: BDFDB.disCN.marginbottom20, + type: "Switch", + label: "Preview in light mode", + value: this.props.useLightMode, + onChange: (value, instance) => { + this.props.useLightMode = value; + if (preview) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "DarkLight", + checked: ${this.props.useLightMode} + })`); + } + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: BDFDB.disCN.marginbottom20, + type: "Switch", + label: "Preview with useNormalizer classes", + value: this.props.useNormalizer, + onChange: (value, instance) => { + this.props.useNormalizer = value; + if (preview) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "Normalize", + checked: ${this.props.useNormalizer} + })`); + } + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: BDFDB.disCN.marginbottom20, + type: "Switch", + label: "Include Custom CSS in Preview", + value: this.props.useCustomCSS, + onChange: (value, instance) => { + this.props.useCustomCSS = value; + let customCSS = document.querySelector("style#customcss"); + if (preview && customCSS && customCSS.innerText.length > 0) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "CustomCSS", + checked: ${this.props.useCustomCSS}, + css: ${JSON.stringify(customCSS.innerText || "")} + })`); + } + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: BDFDB.disCN.marginbottom20, + type: "Switch", + label: "Include ThemeFixer CSS in Preview", + value: this.props.useThemeFixer, + onChange: (value, instance) => { + this.props.useThemeFixer = value; + BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeFixer.css", (error, response, body) => { + if (preview) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "ThemeFixer", + checked: ${this.props.useThemeFixer}, + css: ${JSON.stringify(_this.createFixerCSS(body) || "")} + })`); + }); + } + }), BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { className: BDFDB.disCN.marginbottom20, type: "Button", - label: "Download generated Theme", + label: "Download ThemeFixer", children: "Download", onClick: _ => { - if (this.props.currentGenerator.native) { - _this.createThemeFile("Discord.theme.css", `//META{"name":"Discord","description":"Allows you to easily customize discords native look","author":"DevilBro","version":"1.0.0","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien"}*//\n\n` + _this.generateTheme(nativeCSSvars, this.props.generatorValues)); - } - else if (loadedThemes[this.props.currentGenerator.value]) { - _this.createThemeFile(loadedThemes[this.props.currentGenerator.value].name + ".theme.css", _this.generateTheme(loadedThemes[this.props.currentGenerator.value].fullCSS, this.props.generatorValues)); - } + BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeFixer.css", (error, response, body) => { + _this.createThemeFile("ThemeFixer.theme.css", `//META{"name":"ThemeFixer","description":"ThemeFixerCSS for transparent themes","author":"DevilBro","version":"1.0.3","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien"}*//\n\n` + _this.createFixerCSS(body)); + }); } }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, { - className: BDFDB.disCN.marginbottom20 - }), - (_ => { - let vars = this.props.currentGenerator.native ? nativeCSSvars.split(".theme-dark, .theme-light") : loadedThemes[this.props.currentGenerator.value].fullCSS.split(":root"); - if (vars.length < 2) return null; - vars = vars[1].replace(/\t\(/g, " (").replace(/\r|\t| {2,}/g, "").replace(/\/\*\n*((?!\/\*|\*\/).|\n)*\n+((?!\/\*|\*\/).|\n)*\n*\*\//g, "").replace(/\n\/\*.*?\*\//g, "").replace(/\n/g, ""); - vars = vars.split("{"); - vars.shift(); - vars = vars.join("{").replace(/\s*(:|;|--|\*)\s*/g, "$1"); - vars = vars.split("}")[0]; - vars = vars.slice(2).split(/;--|\*\/--/); - let inputRefs = []; - for (let varStr of vars) { - varStr = varStr.split(":"); - let varName = varStr.shift().trim(); - varStr = varStr.join(":").split(/;[^A-z0-9]|\/\*/); - let oldValue = varStr.shift().trim(); - if (oldValue) { - let childType = "text", childMode = ""; - let isColor = BDFDB.ColorUtils.getType(oldValue); - let isComp = !isColor && /^[0-9 ]+,[0-9 ]+,[0-9 ]+$/g.test(oldValue); - if (isColor || isComp) { - childType = "color"; - childMode = isComp && "comp"; - } - else { - let isUrlFile = /url\(.+\)/gi.test(oldValue); - let isFile = !isUrlFile && /(http(s)?):\/\/[(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.test(oldValue); - if (isFile || isUrlFile) { - childType = "file"; - childMode = isUrlFile && "url"; - } - } - let varDescription = varStr.join("").replace(/\*\/|\/\*/g, "").replace(/:/g, ": ").replace(/: \//g, ":/").replace(/--/g, " --").replace(/\( --/g, "(--").trim(); - this.props.generatorValues[varName] = {value:oldValue, oldValue}; - inputRefs.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - className: BDFDB.disCN.marginbottom20, - dividerbottom: vars[vars.length-1] != varStr, - type: "TextInput", - childProps: { - type: childType, - mode: childMode, - filter: childType == "file" && "image" - }, - label: varName[0].toUpperCase() + varName.slice(1), - note: varDescription && varDescription.indexOf("*") == 0 ? varDescription.slice(1) : varDescription, - basis: "70%", - value: oldValue, - placeholder: oldValue, - onChange: value => { - BDFDB.TimeUtils.clear(updateGeneratorTimeout); - updateGeneratorTimeout = BDFDB.TimeUtils.timeout(_ => { - this.props.generatorValues[varName] = {value, oldValue}; - if (preview) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "NewTheme", - checked: true, - css: ${JSON.stringify(_this.generateTheme(this.props.currentGenerator.native ? nativeCSSvars : loadedThemes[this.props.currentGenerator.value].fullCSS, this.props.generatorValues) || "")} - })`); - }, 1000); - } - })); - } - } - return inputRefs; - })() - ]) - ].flat(10).filter(n => n) - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { - tab: BDFDB.LanguageUtils.LanguageStrings.SETTINGS, - open: this.props.tab == BDFDB.LanguageUtils.LanguageStrings.SETTINGS, - render: false, - children: [ - !automaticLoading && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { - className: BDFDB.disCN.marginbottom20, - children: BDFDB.ReactUtils.createElement("div", { - className: BDFDB.disCNS.titledefault + BDFDB.disCN.cursordefault, - children: "To experience ThemeRepo in the best way. I would recommend you to enable BD intern reload function, that way all downloaded files are loaded into Discord without the need to reload." - }) - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - className: BDFDB.disCN.marginbottom20, - type: "Switch", - label: "Preview in light mode", - value: this.props.useLightMode, - onChange: (value, instance) => { - this.props.useLightMode = value; - if (preview) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "DarkLight", - checked: ${this.props.useLightMode} - })`); - } - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - className: BDFDB.disCN.marginbottom20, - type: "Switch", - label: "Preview with useNormalizer classes", - value: this.props.useNormalizer, - onChange: (value, instance) => { - this.props.useNormalizer = value; - if (preview) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "Normalize", - checked: ${this.props.useNormalizer} - })`); - } - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - className: BDFDB.disCN.marginbottom20, - type: "Switch", - label: "Include Custom CSS in Preview", - value: this.props.useCustomCSS, - onChange: (value, instance) => { - this.props.useCustomCSS = value; - let customCSS = document.querySelector("style#customcss"); - if (preview && customCSS && customCSS.innerText.length > 0) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "CustomCSS", - checked: ${this.props.useCustomCSS}, - css: ${JSON.stringify(customCSS.innerText || "")} - })`); - } - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - className: BDFDB.disCN.marginbottom20, - type: "Switch", - label: "Include ThemeFixer CSS in Preview", - value: this.props.useThemeFixer, - onChange: (value, instance) => { - this.props.useThemeFixer = value; - BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeFixer.css", (error, response, body) => { - if (preview) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "ThemeFixer", - checked: ${this.props.useThemeFixer}, - css: ${JSON.stringify(_this.createFixerCSS(body) || "")} - })`); - }); - } - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - className: BDFDB.disCN.marginbottom20, - type: "Button", - label: "Download ThemeFixer", - children: "Download", - onClick: _ => { - BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeFixer.css", (error, response, body) => { - _this.createThemeFile("ThemeFixer.theme.css", `//META{"name":"ThemeFixer","description":"ThemeFixerCSS for transparent themes","author":"DevilBro","version":"1.0.3","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien"}*//\n\n` + _this.createFixerCSS(body)); - }); - } - }), - Object.keys(modalSettings).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { - className: BDFDB.disCN.marginbottom20, - type: "Switch", - plugin: _this, - keys: ["modalSettings", key], - label: _this.defaults.modalSettings[key].description, - note: key == "rnmStart" && !automaticLoading && "Automatic Loading has to be enabled", - disabled: key == "rnmStart" && !automaticLoading, - value: this.props[key], - onChange: (value, instance) => { - this.props[key] = value; - BDFDB.ReactUtils.forceUpdate(this); - } - })) - ].flat(10).filter(n => n) - }) - ]; - } - }; - - const RepoCardComponent = class ThemeCard extends BdApi.React.Component { - render() { - let buttonConfig = buttonData[(Object.entries(themeStates).find(n => n[1] == this.props.theme.state) || [])[0]]; - return buttonConfig && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.AddonCard, { - data: this.props.theme, - controls: [ - this.props.theme.new == newStates.NEW && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.TextBadge, { - style: { - borderRadius: 3, - textTransform: "uppercase", - background: BDFDB.DiscordConstants.Colors.STATUS_YELLOW - }, - text: BDFDB.LanguageUtils.LanguageStrings.NEW - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FavButton, { - className: BDFDB.disCN._repocontrolsbutton, - isFavorite: this.props.theme.fav == favStates.FAVORIZED, - onClick: value => { - this.props.theme.fav = value ? favStates.FAVORIZED : favStates.NOT_FAVORIZED; - if (value) favorites.push(this.props.theme.url); - else BDFDB.ArrayUtils.remove(favorites, this.props.theme.url, true); - BDFDB.DataUtils.save(favorites, _this, "favorites"); - } - }), - BDFDB.ReactUtils.createElement("div", { - className: BDFDB.disCN._repocontrolsbutton, - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { - text: "Go to Source", - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { - name: BDFDB.LibraryComponents.SvgIcon.Names.GITHUB, - className: BDFDB.disCN._repoicon, - onClick: _ => { - let gitUrl = null; - if (this.props.theme.url.indexOf("https://raw.githubusercontent.com") == 0) { - let temp = this.props.theme.url.replace("//raw.githubusercontent", "//github").split("/"); - temp.splice(5, 0, "blob"); - gitUrl = temp.join("/"); - } - else if (this.props.theme.url.indexOf("https://gist.githubusercontent.com/") == 0) { - gitUrl = this.props.theme.url.replace("//gist.githubusercontent", "//gist.github").split("/raw/")[0]; - } - if (gitUrl) BDFDB.DiscordUtils.openLink(gitUrl, settings.useChromium); - } - }) - }) - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Switch, { - value: list && list.props.currentTheme && list.props.currentTheme.url == this.props.theme.url, - onChange: (value, instance) => { - if (!list) return; - if (value) list.props.currentTheme = this.props.theme; - else delete list.props.currentTheme; - delete list.props.currentGenerator; - delete list.props.generatorValues; - if (preview) preview.executeJavaScriptSafe(`window.onmessage({ - origin: "ThemeRepo", - reason: "NewTheme", - checked: ${value}, - css: ${JSON.stringify(this.props.theme.css || "")} - })`); - else list.openPreview(); - BDFDB.ReactUtils.forceUpdate(this); - } - }) - ], - buttons: [ - this.props.theme.state != themeStates.DOWNLOADABLE && BDFDB.ReactUtils.createElement("div", { - className: BDFDB.disCN._repocontrolsbutton, - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { - text: "Delete Themefile", - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { - name: BDFDB.LibraryComponents.SvgIcon.Names.NOVA_TRASH, - className: BDFDB.disCN._repoicon, - onClick: (e, instance) => { - _this.removeTheme(this.props.theme); - _this.deleteThemeFile(this.props.theme); - this.props.theme.state = themeStates.DOWNLOADABLE; + Object.keys(modalSettings).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + className: BDFDB.disCN.marginbottom20, + type: "Switch", + plugin: _this, + keys: ["modalSettings", key], + label: _this.defaults.modalSettings[key].description, + note: key == "rnmStart" && !automaticLoading && "Automatic Loading has to be enabled", + disabled: key == "rnmStart" && !automaticLoading, + value: this.props[key], + onChange: (value, instance) => { + this.props[key] = value; BDFDB.ReactUtils.forceUpdate(this); } + })) + ].flat(10).filter(n => n) + }) + ]; + } + }; + + const RepoCardComponent = class ThemeCard extends BdApi.React.Component { + render() { + let buttonConfig = buttonData[(Object.entries(themeStates).find(n => n[1] == this.props.theme.state) || [])[0]]; + return buttonConfig && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.AddonCard, { + data: this.props.theme, + controls: [ + this.props.theme.new == newStates.NEW && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.TextBadge, { + style: { + borderRadius: 3, + textTransform: "uppercase", + background: BDFDB.DiscordConstants.Colors.STATUS_YELLOW + }, + text: BDFDB.LanguageUtils.LanguageStrings.NEW + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FavButton, { + className: BDFDB.disCN._repocontrolsbutton, + isFavorite: this.props.theme.fav == favStates.FAVORIZED, + onClick: value => { + this.props.theme.fav = value ? favStates.FAVORIZED : favStates.NOT_FAVORIZED; + if (value) favorites.push(this.props.theme.url); + else BDFDB.ArrayUtils.remove(favorites, this.props.theme.url, true); + BDFDB.DataUtils.save(favorites, _this, "favorites"); + } + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._repocontrolsbutton, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: "Go to Source", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + name: BDFDB.LibraryComponents.SvgIcon.Names.GITHUB, + className: BDFDB.disCN._repoicon, + onClick: _ => { + let gitUrl = null; + if (this.props.theme.url.indexOf("https://raw.githubusercontent.com") == 0) { + let temp = this.props.theme.url.replace("//raw.githubusercontent", "//github").split("/"); + temp.splice(5, 0, "blob"); + gitUrl = temp.join("/"); + } + else if (this.props.theme.url.indexOf("https://gist.githubusercontent.com/") == 0) { + gitUrl = this.props.theme.url.replace("//gist.githubusercontent", "//gist.github").split("/raw/")[0]; + } + if (gitUrl) BDFDB.DiscordUtils.openLink(gitUrl, settings.useChromium); + } + }) }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Switch, { + value: list && list.props.currentTheme && list.props.currentTheme.url == this.props.theme.url, + onChange: (value, instance) => { + if (!list) return; + if (value) list.props.currentTheme = this.props.theme; + else delete list.props.currentTheme; + delete list.props.currentGenerator; + delete list.props.generatorValues; + if (preview) preview.executeJavaScriptSafe(`window.onmessage({ + origin: "ThemeRepo", + reason: "NewTheme", + checked: ${value}, + css: ${JSON.stringify(this.props.theme.css || "")} + })`); + else list.openPreview(); + BDFDB.ReactUtils.forceUpdate(this); + } }) - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { - size: BDFDB.LibraryComponents.Button.Sizes.MIN, - color: BDFDB.LibraryComponents.Button.Colors[buttonConfig.colorClass], - style: {backgroundColor: BDFDB.DiscordConstants.Colors[buttonConfig.backgroundColor]}, - children: buttonConfig.text, - onClick: (e, instance) => { - _this.downloadTheme(this.props.theme); - if (list && list.props.rnmStart) BDFDB.TimeUtils.timeout(_ => { - if (this.props.theme.state == themeStates.UPDATED) _this.applyTheme(this.props.theme); - }, 3000); - this.props.theme.state = themeStates.UPDATED; - BDFDB.ReactUtils.forceUpdate(this); - } - }) - ] - }); - } - }; - - const RepoListHeaderComponent = class ThemeListHeader extends BdApi.React.Component { - componentDidMount() { - header = this; - } - render() { - if (!this.props.tab) this.props.tab = "Themes"; - return BDFDB.ReactUtils.createElement("div", { - className: BDFDB.disCN._repolistheader, - children: [ - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { - className: BDFDB.disCN.marginbottom4, - align: BDFDB.LibraryComponents.Flex.Align.CENTER, - children: [ - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormTitle, { - tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H2, - className: BDFDB.disCN.marginreset, - children: `Theme Repo — ${loading.is ? 0 : this.props.amount || 0}/${loading.is ? 0 : Object.keys(loadedThemes).length}` - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SearchBar, { - autoFocus: true, - query: this.props.searchString, - onChange: (value, instance) => { - BDFDB.TimeUtils.clear(searchTimeout); - searchTimeout = BDFDB.TimeUtils.timeout(_ => { - this.props.searchString = list.props.searchString = value.replace(/[<|>]/g, ""); + ], + buttons: [ + this.props.theme.state != themeStates.DOWNLOADABLE && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._repocontrolsbutton, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: "Delete Themefile", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + name: BDFDB.LibraryComponents.SvgIcon.Names.NOVA_TRASH, + className: BDFDB.disCN._repoicon, + onClick: (e, instance) => { + _this.removeTheme(this.props.theme); + _this.deleteThemeFile(this.props.theme); + this.props.theme.state = themeStates.DOWNLOADABLE; + BDFDB.ReactUtils.forceUpdate(this); + } + }) + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { + size: BDFDB.LibraryComponents.Button.Sizes.MIN, + color: BDFDB.LibraryComponents.Button.Colors[buttonConfig.colorClass], + style: {backgroundColor: BDFDB.DiscordConstants.Colors[buttonConfig.backgroundColor]}, + children: buttonConfig.text, + onClick: (e, instance) => { + _this.downloadTheme(this.props.theme); + if (list && list.props.rnmStart) BDFDB.TimeUtils.timeout(_ => { + if (this.props.theme.state == themeStates.UPDATED) _this.applyTheme(this.props.theme); + }, 3000); + this.props.theme.state = themeStates.UPDATED; + BDFDB.ReactUtils.forceUpdate(this); + } + }) + ] + }); + } + }; + + const RepoListHeaderComponent = class ThemeListHeader extends BdApi.React.Component { + componentDidMount() { + header = this; + } + render() { + if (!this.props.tab) this.props.tab = "Themes"; + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._repolistheader, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom4, + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormTitle, { + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H2, + className: BDFDB.disCN.marginreset, + children: `Theme Repo — ${loading.is ? 0 : this.props.amount || 0}/${loading.is ? 0 : Object.keys(loadedThemes).length}` + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SearchBar, { + autoFocus: true, + query: this.props.searchString, + onChange: (value, instance) => { + BDFDB.TimeUtils.clear(searchTimeout); + searchTimeout = BDFDB.TimeUtils.timeout(_ => { + this.props.searchString = list.props.searchString = value.replace(/[<|>]/g, ""); + BDFDB.ReactUtils.forceUpdate(this, list); + }, 1000); + }, + onClear: instance => { + this.props.searchString = list.props.searchString = ""; BDFDB.ReactUtils.forceUpdate(this, list); - }, 1000); - }, - onClear: instance => { - this.props.searchString = list.props.searchString = ""; - BDFDB.ReactUtils.forceUpdate(this, list); - } + } + }) }) - }) - ] - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { - className: BDFDB.disCNS.tabbarcontainer + BDFDB.disCN.tabbarcontainerbottom, - align: BDFDB.LibraryComponents.Flex.Align.CENTER, - children: [ - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TabBar, { - className: BDFDB.disCN.tabbar, - itemClassName: BDFDB.disCN.tabbaritem, - type: BDFDB.LibraryComponents.TabBar.Types.TOP, - selectedItem: this.props.tab, - items: [{value:"Themes"}, {value:"Generator"}, {value:BDFDB.LanguageUtils.LanguageStrings.SETTINGS}], - onItemSelect: (value, instance) => { - this.props.tab = list.props.tab = value; - BDFDB.ReactUtils.forceUpdate(list); - } - }) - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.QuickSelect, { - label: BDFDB.LanguageUtils.LibraryStrings.sort_by + ":", - value: { - label: sortKeys[this.props.sortKey], - value: this.props.sortKey - }, - options: Object.keys(sortKeys).filter(n => n != "NEW" || Object.keys(loadedThemes).some(p => !cachedThemes.includes(p))).map(key => ({ - label: sortKeys[key], - value: key - })), - onChange: (key, instance) => { - this.props.sortKey = list.props.sortKey = key; - BDFDB.ReactUtils.forceUpdate(this, list); - } - }) - }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.QuickSelect, { - label: BDFDB.LanguageUtils.LibraryStrings.order + ":", - value: { - label: BDFDB.LanguageUtils.LibraryStrings[orderKeys[this.props.orderKey]], - value: this.props.orderKey - }, - options: Object.keys(orderKeys).map(key => ({ - label: BDFDB.LanguageUtils.LibraryStrings[orderKeys[key]], - value: key - })), - onChange: (key, instance) => { - this.props.orderKey = list.props.orderKey = key; - BDFDB.ReactUtils.forceUpdate(this, list); - } - }) - }) - ] - }) - ] - }); - } - }; - - return class ThemeRepo { - getName () {return "ThemeRepo";} - - getVersion () {return "2.0.7";} - - getAuthor () {return "DevilBro";} - - getDescription () {return "Allows you to preview all themes from the theme repo and download them on the fly. Repo button is in the theme settings.";} - - constructor () { - this.patchedModules = { - before: { - SettingsView: "render" - }, - after: { - StandardSidebarView: "render" - } - }; - } - - initConstructor () { - _this = this; - - loading = {is:false, timeout:null, amount:0}; - - cachedThemes = []; - grabbedThemes = []; - foundThemes = []; - loadedThemes = {}; - generatorThemes = []; - - this.defaults = { - settings: { - useChromium: {value:false, description:"Use an inbuilt browser window instead of opening your default browser"}, - keepOnTop: {value:false, description:"Keep the preview window always on top"}, - notifyOutdated: {value:true, description:"Notifies you when one of your Themes is outdated"}, - notifyNewentries: {value:true, description:"Notifies you when there are new entries in the Repo"} - }, - modalSettings: { - updated: {value:true, modify:true, description:"Show updated Themes",}, - outdated: {value:true, modify:true, description:"Show outdated Themes"}, - downloadable: {value:true, modify:true, description:"Show downloadable Themes"}, - rnmStart: {value:true, modify:false, description:"Apply Theme after Download"} - } - }; - - this.css = ` - .${this.name}-modal.repo-modal { - max-width: 800px; - min-height: 90vh; - max-height: 90vh; - } - `; - } - - getSettingsPanel (collapseStates = {}) { - if (!window.BDFDB || typeof BDFDB != "object" || !BDFDB.loaded || !this.started) return; - let customUrl = ""; - let settingsPanel, settingsItems = []; - - settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { - title: "Settings", - collapseStates: collapseStates, - children: Object.keys(settings).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { - className: BDFDB.disCN.marginbottom8, - type: "Switch", - plugin: this, - keys: ["settings", key], - label: this.defaults.settings[key].description, - value: settings[key] - })) - })); - settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { - title: "Custom Themes", - collapseStates: collapseStates, - children: [ - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { - title: "Add Theme:", - tag: BDFDB.LibraryComponents.FormComponents.FormTitleTags.H3, - className: BDFDB.disCNS.margintop4 + BDFDB.disCN.marginbottom8, - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCNS.tabbarcontainer + BDFDB.disCN.tabbarcontainerbottom, align: BDFDB.LibraryComponents.Flex.Align.CENTER, children: [ BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { - placeholder: "Insert Raw Github Link of Theme (https://raw.githubusercontent.com/...)", - onChange: value => {customUrl = value.trim();} + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TabBar, { + className: BDFDB.disCN.tabbar, + itemClassName: BDFDB.disCN.tabbaritem, + type: BDFDB.LibraryComponents.TabBar.Types.TOP, + selectedItem: this.props.tab, + items: [{value:"Themes"}, {value:"Generator"}, {value:BDFDB.LanguageUtils.LanguageStrings.SETTINGS}], + onItemSelect: (value, instance) => { + this.props.tab = list.props.tab = value; + BDFDB.ReactUtils.forceUpdate(list); + } }) }), - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { - onClick: _ => { - if (customUrl) { - customList.push(customUrl); - BDFDB.DataUtils.save(BDFDB.ArrayUtils.removeCopies(customList), this, "custom"); - BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates); + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.QuickSelect, { + label: BDFDB.LanguageUtils.LibraryStrings.sort_by + ":", + value: { + label: sortKeys[this.props.sortKey], + value: this.props.sortKey + }, + options: Object.keys(sortKeys).filter(n => n != "NEW" || Object.keys(loadedThemes).some(p => !cachedThemes.includes(p))).map(key => ({ + label: sortKeys[key], + value: key + })), + onChange: (key, instance) => { + this.props.sortKey = list.props.sortKey = key; + BDFDB.ReactUtils.forceUpdate(this, list); } - }, - children: BDFDB.LanguageUtils.LanguageStrings.ADD + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.QuickSelect, { + label: BDFDB.LanguageUtils.LibraryStrings.order + ":", + value: { + label: BDFDB.LanguageUtils.LibraryStrings[orderKeys[this.props.orderKey]], + value: this.props.orderKey + }, + options: Object.keys(orderKeys).map(key => ({ + label: BDFDB.LanguageUtils.LibraryStrings[orderKeys[key]], + value: key + })), + onChange: (key, instance) => { + this.props.orderKey = list.props.orderKey = key; + BDFDB.ReactUtils.forceUpdate(this, list); + } + }) }) ] }) - }), - customList.length ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelInner, { - title: "Custom Theme List:", - className: BDFDB.disCNS.margintop8 + BDFDB.disCN.marginbottom20, - first: true, - last: true, - children: customList.map(url => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Card, { - children: url, - onRemove: _ => { - BDFDB.ArrayUtils.remove(customList, url, true); - BDFDB.DataUtils.save(customList, this, "custom"); - BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates); - } - })) - }) : null, - BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - type: "Button", - color: BDFDB.LibraryComponents.Button.Colors.RED, - label: "Remove all custom added Themes", - onClick: _ => { - BDFDB.ModalUtils.confirm(this, "Are you sure you want to remove all added Themes from your own list", _ => { - BDFDB.DataUtils.save([], this, "custom"); - BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates); - }); - }, - children: BDFDB.LanguageUtils.LanguageStrings.REMOVE - }) - ].flat(10).filter(n => n) - })); - settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { - title: "Refetch All", - collapseStates: collapseStates, - children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - type: "Button", - label: "Force all Themes to be fetched again", - onClick: _ => { - loading = {is:false, timeout:null, amount:0}; - this.loadThemes(); - }, - children: BDFDB.LanguageUtils.LanguageStrings.ERRORS_RELOAD - }) - })); - - return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, settingsItems); - } - - // Legacy - load () { - if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) BDFDB.PluginUtils.load(this); - } - - start () { - if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; - if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; - let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); - if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { - if (libraryScript) libraryScript.remove(); - libraryScript = document.createElement("script"); - libraryScript.setAttribute("id", "BDFDBLibraryScript"); - libraryScript.setAttribute("type", "text/javascript"); - libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); - libraryScript.setAttribute("date", performance.now()); - libraryScript.addEventListener("load", _ => {this.initialize();}); - document.head.appendChild(libraryScript); + ] + }); } - else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); - this.startTimeout = setTimeout(_ => { - try {return this.initialize();} - catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} - }, 30000); - } - - initialize () { - if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { - if (this.started) return; - BDFDB.PluginUtils.init(this); + }; + return class ThemeRepo extends Plugin { + onLoad() { + _this = this; + + loading = {is:false, timeout:null, amount:0}; + + cachedThemes = []; + grabbedThemes = []; + foundThemes = []; + loadedThemes = {}; + generatorThemes = []; + this.defaults = { + settings: { + useChromium: {value:false, description:"Use an inbuilt browser window instead of opening your default browser"}, + keepOnTop: {value:false, description:"Keep the preview window always on top"}, + notifyOutdated: {value:true, description:"Notifies you when one of your Themes is outdated"}, + notifyNewentries: {value:true, description:"Notifies you when there are new entries in the Repo"} + }, + modalSettings: { + updated: {value:true, modify:true, description:"Show updated Themes",}, + outdated: {value:true, modify:true, description:"Show outdated Themes"}, + downloadable: {value:true, modify:true, description:"Show downloadable Themes"}, + rnmStart: {value:true, modify:false, description:"Apply Theme after Download"} + } + }; + + this.patchedModules = { + before: { + SettingsView: "render" + }, + after: { + StandardSidebarView: "render" + } + }; + } + + onStart() { this.forceUpdateAll(); this.loadThemes(); updateInterval = BDFDB.TimeUtils.interval(_ => {this.checkForNewThemes();}, 1000*60*30); } - else console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not load BD functions!"); - } - - - stop () { - if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { - this.stopping = true; - + + onStop() { BDFDB.TimeUtils.clear(updateInterval); BDFDB.TimeUtils.clear(loading.timeout); this.forceUpdateAll(); BDFDB.DOMUtils.remove(".bd-themerepobutton", ".themerepo-notice", ".themerepo-loadingicon"); - - BDFDB.PluginUtils.clear(this); } - } - - // Begin of own functions - - forceUpdateAll () { - settings = BDFDB.DataUtils.get(this, "settings"); - modalSettings = BDFDB.DataUtils.get(this, "modalSettings"); - favorites = BDFDB.DataUtils.load(this, "favorites"); - favorites = BDFDB.ArrayUtils.is(favorites) ? favorites : []; - customList = BDFDB.DataUtils.load(this, "custom"); - customList = BDFDB.ArrayUtils.is(customList) ? customList : []; - - BDFDB.PatchUtils.forceAllUpdates(this); - } - - onSettingsClosed () { - if (this.SettingsUpdated) { - delete this.SettingsUpdated; - this.forceUpdateAll(); - } - } - - onUserSettingsCogContextMenu (e) { - BDFDB.TimeUtils.timeout(_ => { - let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["label", "BandagedBD"]]}); - if (index > -1 && BDFDB.ArrayUtils.is(children[index].props.children)) children[index].props.children.push(BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { - label: "Theme Repo", - id: BDFDB.ContextMenuUtils.createItemId(this.name, "repo"), - action: _ => { - BDFDB.LibraryModules.UserSettingsUtils.open("themerepo"); - } + getSettingsPanel (collapseStates = {}) { + let customUrl = ""; + let settingsPanel, settingsItems = []; + + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { + title: "Settings", + collapseStates: collapseStates, + children: Object.keys(settings).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + className: BDFDB.disCN.marginbottom8, + type: "Switch", + plugin: this, + keys: ["settings", key], + label: this.defaults.settings[key].description, + value: settings[key] + })) })); - }); - } - - processSettingsView (e) { - if (BDFDB.ArrayUtils.is(e.instance.props.sections) && e.instance.props.sections[0] && e.instance.props.sections[0].label == BDFDB.LanguageUtils.LanguageStrings.USER_SETTINGS && !e.instance.props.sections.find(n => n.section == "themerepo")) { - let oldSettings = !e.instance.props.sections.find(n => n.section == "themes"); - let isPRinjected = oldSettings && e.instance.props.sections.find(n => n.section == "pluginrepo"); - let search = oldSettings ? (isPRinjected ? n => n.section == "pluginrepo" : n => n.section == BDFDB.DiscordConstants.UserSettingsSections.DEVELOPER_OPTIONS) : n => n.section == BDFDB.DiscordConstants.UserSettingsSections.CHANGE_LOG || n.section == "changelog" - let index = e.instance.props.sections.indexOf(e.instance.props.sections.find(search)); - if (index > -1) { - e.instance.props.sections.splice(oldSettings ? index + 1 : index - 1, 0, { + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { + title: "Custom Themes", + collapseStates: collapseStates, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: "Add Theme:", + tag: BDFDB.LibraryComponents.FormComponents.FormTitleTags.H3, + className: BDFDB.disCNS.margintop4 + BDFDB.disCN.marginbottom8, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + placeholder: "Insert Raw Github Link of Theme (https://raw.githubusercontent.com/...)", + onChange: value => {customUrl = value.trim();} + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { + onClick: _ => { + if (customUrl) { + customList.push(customUrl); + BDFDB.DataUtils.save(BDFDB.ArrayUtils.removeCopies(customList), this, "custom"); + BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates); + } + }, + children: BDFDB.LanguageUtils.LanguageStrings.ADD + }) + ] + }) + }), + customList.length ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelInner, { + title: "Custom Theme List:", + className: BDFDB.disCNS.margintop8 + BDFDB.disCN.marginbottom20, + first: true, + last: true, + children: customList.map(url => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Card, { + children: url, + onRemove: _ => { + BDFDB.ArrayUtils.remove(customList, url, true); + BDFDB.DataUtils.save(customList, this, "custom"); + BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates); + } + })) + }) : null, + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Button", + color: BDFDB.LibraryComponents.Button.Colors.RED, + label: "Remove all custom added Themes", + onClick: _ => { + BDFDB.ModalUtils.confirm(this, "Are you sure you want to remove all added Themes from your own list", _ => { + BDFDB.DataUtils.save([], this, "custom"); + BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates); + }); + }, + children: BDFDB.LanguageUtils.LanguageStrings.REMOVE + }) + ].flat(10).filter(n => n) + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { + title: "Refetch All", + collapseStates: collapseStates, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Button", + label: "Force all Themes to be fetched again", + onClick: _ => { + loading = {is:false, timeout:null, amount:0}; + this.loadThemes(); + }, + children: BDFDB.LanguageUtils.LanguageStrings.ERRORS_RELOAD + }) + })); + + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, settingsItems); + } + + onSettingsClosed () { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + this.forceUpdateAll(); + } + } + + forceUpdateAll () { + settings = BDFDB.DataUtils.get(this, "settings"); + modalSettings = BDFDB.DataUtils.get(this, "modalSettings"); + favorites = BDFDB.DataUtils.load(this, "favorites"); + favorites = BDFDB.ArrayUtils.is(favorites) ? favorites : []; + customList = BDFDB.DataUtils.load(this, "custom"); + customList = BDFDB.ArrayUtils.is(customList) ? customList : []; + + BDFDB.PatchUtils.forceAllUpdates(this); + } + + onUserSettingsCogContextMenu (e) { + BDFDB.TimeUtils.timeout(_ => { + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["label", "BandagedBD"]]}); + if (index > -1 && BDFDB.ArrayUtils.is(children[index].props.children)) children[index].props.children.push(BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { label: "Theme Repo", - section: "themerepo", - element: _ => { - let options = Object.assign({}, modalSettings); - options.updated = options.updated && !showOnlyOutdated; - options.outdated = options.outdated || showOnlyOutdated; - options.downloadable = options.downloadable && !showOnlyOutdated; - options.searchString = ""; - options.sortKey = forcedSort || Object.keys(sortKeys)[0]; - options.orderKey = forcedOrder || Object.keys(orderKeys)[0]; - options.useLightMode = BDFDB.DiscordUtils.getTheme() == BDFDB.disCN.themelight; - options.useNormalizer = BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds.normalizedClasses); - options.useThemeFixer = false; - options.useCustomCSS = false; - - return BDFDB.ReactUtils.createElement(RepoListComponent, options); + id: BDFDB.ContextMenuUtils.createItemId(this.name, "repo"), + action: _ => { + BDFDB.LibraryModules.UserSettingsUtils.open("themerepo"); } - }); - if (oldSettings && !isPRinjected) e.instance.props.sections.splice(index + 1, 0, {section: "DIVIDER"}); - } - } - } - - processStandardSidebarView (e) { - if (BDFDB.ObjectUtils.get(e, "instance.props.content.props.section") == "themerepo") { - let content = BDFDB.ReactUtils.findChild(e.returnvalue, {props: [["className", BDFDB.disCN.settingswindowcontentregion]]}); - if (content) content.props.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._repolistwrapper, content.props.className); - let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["className", BDFDB.disCN.settingswindowcontentregionscroller]]}); - if (index > -1) { - let options = {}; - options.searchString = ""; - options.sortKey = forcedSort || Object.keys(sortKeys)[0]; - options.orderKey = forcedOrder || Object.keys(orderKeys)[0]; - children[index] = [ - BDFDB.ReactUtils.createElement(RepoListHeaderComponent, options), - children[index] - ]; - } - } - } - - createFixerCSS (body) { - let oldcss = body.replace(/\n/g, "\\n").replace(/\t/g, "\\t").replace(/\r/g, "\\r").split("REPLACE_CLASS_"); - let newcss = oldcss.shift(); - for (let str of oldcss) { - let reg = /([A-z0-9_]+)(.*)/.exec(str); - newcss += BDFDB.dotCN[reg[1]] + reg[2]; - } - return newcss.replace(/\\n/g, "\n").replace(/\\t/g, "\t").replace(/\\r/g, "\r"); - } - - createGeneratorInputs (theme, generatorValues) { - if (!BDFDB.ObjectUtils.is(theme) || !BDFDB.ObjectUtils.is(generatorValues) || !theme.fullCSS) return null; - return inputRefs; - } - - generateTheme (fullCSS, generatorValues) { - if (!fullCSS || !BDFDB.ObjectUtils.is(generatorValues)) return ""; - for (let inputId in generatorValues) if (generatorValues[inputId].value && generatorValues[inputId].value.trim() && generatorValues[inputId].value != generatorValues[inputId].oldValue) fullCSS = fullCSS.replace(new RegExp(`--${BDFDB.StringUtils.regEscape(inputId)}(\\s*):(\\s*)${BDFDB.StringUtils.regEscape(generatorValues[inputId].oldValue)}`,"g"),`--${inputId}$1:$2${generatorValues[inputId].value}`); - return fullCSS; - } - - loadThemes () { - BDFDB.DOMUtils.remove(".themerepo-loadingicon"); - let getThemeInfo, outdated = 0, newEntries = 0, i = 0, NFLDreplace = null; - let tags = ["name","description","author","version"]; - let newEntriesData = BDFDB.DataUtils.load(this, "newentriesdata"); - cachedThemes = (newEntriesData.urlbase64 ? atob(newEntriesData.urlbase64).split("\n") : []).concat(customList); - BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeList.txt", (error, response, body) => { - if (!error && body) { - body = body.replace(/[\r\t]/g, ""); - BDFDB.DataUtils.save(btoa(body), this, "newentriesdata", "urlbase64"); - loadedThemes = {}; - grabbedThemes = body.split("\n").filter(n => n); - BDFDB.LibraryRequires.request("https://github.com/NFLD99/Better-Discord", (error2, response2, body2) => { - if (!error2 && body2) { - NFLDreplace = /\/NFLD99\/Better-Discord\/tree\/master\/Themes_[^"]+">([^<]+)/i.exec(body2); - NFLDreplace = NFLDreplace && NFLDreplace.length > 1 ? NFLDreplace[1] : null; - } - foundThemes = grabbedThemes.concat(customList); - - loading = {is:true, timeout:BDFDB.TimeUtils.timeout(_ => { - BDFDB.TimeUtils.clear(loading.timeout); - if (this.started) { - if (loading.is && loading.amount < 4) BDFDB.TimeUtils.timeout(_ => {this.loadThemes();}, 10000); - loading = {is: false, timeout:null, amount:loading.amount}; - } - },1200000), amount:loading.amount+1}; - - let loadingicon = BDFDB.DOMUtils.create(themeRepoIcon); - BDFDB.DOMUtils.addClass(loadingicon, "themerepo-loadingicon"); - loadingicon.addEventListener("mouseenter", _ => { - BDFDB.TooltipUtils.create(loadingicon, this.getLoadingTooltipText(), { - type: "left", - delay: 500, - style: "max-width: unset;", - selector: "themerepo-loading-tooltip" - }); - }); - BDFDB.PluginUtils.addLoadingIcon(loadingicon); - - getThemeInfo(_ => { - if (!this.started) { - BDFDB.TimeUtils.clear(loading.timeout); - return; - } - BDFDB.TimeUtils.clear(loading.timeout); - BDFDB.DOMUtils.remove(loadingicon, ".themerepo-loadingicon"); - loading = {is:false, timeout:null, amount:loading.amount}; - - BDFDB.LogUtils.log("Finished fetching Themes.", this.name); - if (list) BDFDB.ReactUtils.forceUpdate(list); - - if ((settings.notifyOutdated || settings.notifyOutdated == undefined) && outdated > 0) { - let oldBarButton = document.querySelector(".themerepo-outdate-notice " + BDFDB.dotCN.noticedismiss); - if (oldBarButton) oldBarButton.click(); - let bar = BDFDB.NotificationUtils.notice(`${outdated} of your Themes ${outdated == 1 ? "is" : "are"} outdated. Check:`, { - type: "danger", - btn: "ThemeRepo", - selector: "themerepo-notice themerepo-outdate-notice", - customicon: themeRepoIcon.replace(/#7289da/gi, "#FFF").replace(/#7f8186/gi, "#B9BBBE") - }); - bar.querySelector(BDFDB.dotCN.noticebutton).addEventListener("click", _ => { - showOnlyOutdated = true; - BDFDB.LibraryModules.UserSettingsUtils.open("themerepo"); - bar.querySelector(BDFDB.dotCN.noticedismiss).click(); - }); - } - - if (settings.notifyNewEntries && newEntries > 0) { - let oldBarButton = document.querySelector(".themerepo-newentries-notice " + BDFDB.dotCN.noticedismiss); - if (oldBarButton) oldBarButton.click(); - let single = newEntries == 1; - let bar = BDFDB.NotificationUtils.notice(`There ${single ? "is" : "are"} ${newEntries} new Theme${single ? "" : "s"} in the Repo. Check:`, { - type: "success", - btn: "ThemeRepo", - selector: "themerepo-notice themerepo-newentries-notice", - customicon: themeRepoIcon.replace(/#7289da/gi, "#FFF").replace(/#7f8186/gi, "#B9BBBE") - }); - bar.querySelector(BDFDB.dotCN.noticebutton).addEventListener("click", _ => { - forcedSort = "NEW"; - forcedOrder = "ASC"; - BDFDB.LibraryModules.UserSettingsUtils.open("themerepo"); - bar.querySelector(BDFDB.dotCN.noticedismiss).click(); - }); - } - - if (BDFDB.UserUtils.me.id == "278543574059057154") { - let wrongUrls = []; - for (let url of foundThemes) if (url && !loadedThemes[url] && !wrongUrls.includes(url)) wrongUrls.push(url); - if (wrongUrls.length) { - let bar = BDFDB.NotificationUtils.notice(`ThemeRepo: ${wrongUrls.length} Theme${wrongUrls.length > 1 ? "s" : ""} could not be loaded.`, { - type: "danger", - btn: "List", - selector: "themerepo-notice themerepo-fail-notice", - customicon: themeRepoIcon.replace(/#7289da/gi, "#FFF").replace(/#7f8186/gi, "#B9BBBE") - }); - bar.querySelector(BDFDB.dotCN.noticebutton).addEventListener("click", e => { - let toast = BDFDB.NotificationUtils.toast(wrongUrls.join("\n"), {type: "error"}); - toast.style.setProperty("overflow", "hidden"); - for (let url of wrongUrls) console.log(url); - }); - } - } - - BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/GeneratorList.txt", (error3, response3, body3) => { - if (!error3 && body3) for (let url of body3.replace(/[\r\t]/g, "").split("\n").filter(n => n)) if (loadedThemes[url]) generatorThemes.push(url); - }); - - BDFDB.LibraryRequires.request(document.querySelector("head link[rel='stylesheet'][integrity]").href, (error3, response3, body3) => { - if (!error3 && body3) { - nativeCSS = body3; - let theme = BDFDB.DiscordUtils.getTheme(); - let vars = (nativeCSS.split(`.${theme}{`)[1] || "").split("}")[0]; - nativeCSSvars = vars ? `.theme-dark, .theme-light {${vars}}` : ""; - } - else nativeCSS = nativeCSSvars = ""; - }); - }); - }); - } - }); - - getThemeInfo = (callback) => { - if (i >= foundThemes.length || !this.started || !loading.is) { - callback(); - return; - } - let url = foundThemes[i]; - let requestUrl = NFLDreplace && url.includes("NFLD99/Better-Discord/master/Themes") ? url.replace("master/Themes", "master/" + NFLDreplace) : url; - BDFDB.LibraryRequires.request(requestUrl, (error, response, body) => { - if (!response) { - if (url && BDFDB.ArrayUtils.getAllIndexes(foundThemes, url).length < 2) foundThemes.push(url); - } - else if (body && body.indexOf("404: Not Found") != 0 && response.statusCode == 200) { - let theme = {}, text = body; - if ((text.split("*//").length > 1 || text.indexOf("/**") == 0) && text.split("\n").length > 1) { - let hasMETAline = text.replace(/\s/g, "").indexOf("//META{"); - if (hasMETAline < 20 && hasMETAline > -1) { - let searchtext = text.replace(/\s*:\s*/g, ":").replace(/\s*}\s*/g, "}"); - for (let tag of tags) { - let result = searchtext.split('"' + tag + '":"'); - result = result.length > 1 ? result[1].split('",')[0].split('"}')[0] : null; - result = result && tag != "version" ? result.charAt(0).toUpperCase() + result.slice(1) : result; - theme[tag] = result ? result.trim() : result; - } - } - else { - let searchtext = text.replace(/[\r\t| ]*\*\s*/g, "*"); - for (let tag of tags) { - let result = searchtext.split('@' + tag + ' '); - result = result.length > 1 ? result[1].split('\n')[0] : null; - result = result && tag != "version" ? result.charAt(0).toUpperCase() + result.slice(1) : result; - theme[tag] = result ? result.trim() : result; - } - } - - let valid = true; - for (let tag of tags) if (theme[tag] === null) valid = false; - if (valid) { - theme.fullCSS = text; - theme.css = hasMETAline < 20 && hasMETAline > -1 ? text.split("\n").slice(1).join("\n").replace(/[\r|\n|\t]/g, "") : text.replace(/[\r|\n|\t]/g, ""); - theme.url = url; - theme.requestUrl = requestUrl; - loadedThemes[url] = theme; - let instTheme = BDFDB.BDUtils.getTheme(theme.name); - if (instTheme && instTheme.author.toUpperCase() == theme.author.toUpperCase() && instTheme.version != theme.version) outdated++; - if (!cachedThemes.includes(url)) newEntries++; - } - } - } - i++; - - let loadingTooltip = document.querySelector(".themerepo-loading-tooltip"); - if (loadingTooltip) loadingTooltip.update(this.getLoadingTooltipText()); - - getThemeInfo(callback); + })); }); } - } - - getLoadingTooltipText () { - return `Loading ThemeRepo - [${Object.keys(loadedThemes).length}/${Object.keys(grabbedThemes).length}]`; - } - - checkForNewThemes () { - BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeList.txt", (error, response, result) => { - if (response && !BDFDB.equals(result.replace(/\t|\r/g, "").split("\n").filter(n => n), grabbedThemes)) { - loading = {is:false, timeout:null, amount:0}; - this.loadThemes(); + + processSettingsView (e) { + if (BDFDB.ArrayUtils.is(e.instance.props.sections) && e.instance.props.sections[0] && e.instance.props.sections[0].label == BDFDB.LanguageUtils.LanguageStrings.USER_SETTINGS && !e.instance.props.sections.find(n => n.section == "themerepo")) { + let oldSettings = !e.instance.props.sections.find(n => n.section == "themes"); + let isPRinjected = oldSettings && e.instance.props.sections.find(n => n.section == "pluginrepo"); + let search = oldSettings ? (isPRinjected ? n => n.section == "pluginrepo" : n => n.section == BDFDB.DiscordConstants.UserSettingsSections.DEVELOPER_OPTIONS) : n => n.section == BDFDB.DiscordConstants.UserSettingsSections.CHANGE_LOG || n.section == "changelog" + let index = e.instance.props.sections.indexOf(e.instance.props.sections.find(search)); + if (index > -1) { + e.instance.props.sections.splice(oldSettings ? index + 1 : index - 1, 0, { + label: "Theme Repo", + section: "themerepo", + element: _ => { + let options = Object.assign({}, modalSettings); + options.updated = options.updated && !showOnlyOutdated; + options.outdated = options.outdated || showOnlyOutdated; + options.downloadable = options.downloadable && !showOnlyOutdated; + options.searchString = ""; + options.sortKey = forcedSort || Object.keys(sortKeys)[0]; + options.orderKey = forcedOrder || Object.keys(orderKeys)[0]; + options.useLightMode = BDFDB.DiscordUtils.getTheme() == BDFDB.disCN.themelight; + options.useNormalizer = BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds.normalizedClasses); + options.useThemeFixer = false; + options.useCustomCSS = false; + + return BDFDB.ReactUtils.createElement(RepoListComponent, options); + } + }); + if (oldSettings && !isPRinjected) e.instance.props.sections.splice(index + 1, 0, {section: "DIVIDER"}); + } } - }); - } - - downloadTheme (data) { - BDFDB.LibraryRequires.request(data.requestUrl, (error, response, body) => { - if (error) BDFDB.NotificationUtils.toast(`Unable to download Theme "${data.name}".`, {type:"danger"}); - else this.createThemeFile(data.requestUrl.split("/").pop(), body); - }); - } - - createThemeFile (filename, content) { - BDFDB.LibraryRequires.fs.writeFile(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getThemesFolder(), filename), content, (error) => { - if (error) BDFDB.NotificationUtils.toast(`Unable to save Theme "${filename}".`, {type:"danger"}); - else BDFDB.NotificationUtils.toast(`Successfully saved Theme "${filename}".`, {type:"success"}); - }); - } - - applyTheme (data) { - if (data.name && BDFDB.BDUtils.isThemeEnabled(data.name) == false) { - let id = data.name.replace(/^[^a-z]+|[^\w-]+/gi, "-"); - BDFDB.DOMUtils.remove(`style#${id}`); - BDFDB.BDUtils.enableTheme(data.name, false); - BDFDB.LogUtils.log(`Applied Theme ${data.name}.`, this.name); } - } - - deleteThemeFile (data) { - let filename = data.requestUrl.split("/").pop(); - BDFDB.LibraryRequires.fs.unlink(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getThemesFolder(), filename), (error) => { - if (error) BDFDB.NotificationUtils.toast(`Unable to delete Theme "${filename}".`, {type:"danger"}); - else BDFDB.NotificationUtils.toast(`Successfully deleted Theme "${filename}".`); - }); - } - - removeTheme (data) { - if (data.name && BDFDB.BDUtils.isThemeEnabled(data.name) == true) { - let id = data.name.replace(/^[^a-z]+|[^\w-]+/gi, "-"); - BDFDB.DOMUtils.remove(`style#${id}`); - BDFDB.BDUtils.disableTheme(data.name, false); - BDFDB.LogUtils.log(`Removed Theme ${data.name}.`, this.name); + + processStandardSidebarView (e) { + if (BDFDB.ObjectUtils.get(e, "instance.props.content.props.section") == "themerepo") { + let content = BDFDB.ReactUtils.findChild(e.returnvalue, {props: [["className", BDFDB.disCN.settingswindowcontentregion]]}); + if (content) content.props.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._repolistwrapper, content.props.className); + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["className", BDFDB.disCN.settingswindowcontentregionscroller]]}); + if (index > -1) { + let options = {}; + options.searchString = ""; + options.sortKey = forcedSort || Object.keys(sortKeys)[0]; + options.orderKey = forcedOrder || Object.keys(orderKeys)[0]; + children[index] = [ + BDFDB.ReactUtils.createElement(RepoListHeaderComponent, options), + children[index] + ]; + } + } + } + + createFixerCSS (body) { + let oldcss = body.replace(/\n/g, "\\n").replace(/\t/g, "\\t").replace(/\r/g, "\\r").split("REPLACE_CLASS_"); + let newcss = oldcss.shift(); + for (let str of oldcss) { + let reg = /([A-z0-9_]+)(.*)/.exec(str); + newcss += BDFDB.dotCN[reg[1]] + reg[2]; + } + return newcss.replace(/\\n/g, "\n").replace(/\\t/g, "\t").replace(/\\r/g, "\r"); + } + + createGeneratorInputs (theme, generatorValues) { + if (!BDFDB.ObjectUtils.is(theme) || !BDFDB.ObjectUtils.is(generatorValues) || !theme.fullCSS) return null; + return inputRefs; + } + + generateTheme (fullCSS, generatorValues) { + if (!fullCSS || !BDFDB.ObjectUtils.is(generatorValues)) return ""; + for (let inputId in generatorValues) if (generatorValues[inputId].value && generatorValues[inputId].value.trim() && generatorValues[inputId].value != generatorValues[inputId].oldValue) fullCSS = fullCSS.replace(new RegExp(`--${BDFDB.StringUtils.regEscape(inputId)}(\\s*):(\\s*)${BDFDB.StringUtils.regEscape(generatorValues[inputId].oldValue)}`,"g"),`--${inputId}$1:$2${generatorValues[inputId].value}`); + return fullCSS; } - } - } -})(); -module.exports = ThemeRepo; + loadThemes () { + BDFDB.DOMUtils.remove(".themerepo-loadingicon"); + let getThemeInfo, outdated = 0, newEntries = 0, i = 0, NFLDreplace = null; + let tags = ["name","description","author","version"]; + let newEntriesData = BDFDB.DataUtils.load(this, "newentriesdata"); + cachedThemes = (newEntriesData.urlbase64 ? atob(newEntriesData.urlbase64).split("\n") : []).concat(customList); + BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeList.txt", (error, response, body) => { + if (!error && body) { + body = body.replace(/[\r\t]/g, ""); + BDFDB.DataUtils.save(btoa(body), this, "newentriesdata", "urlbase64"); + loadedThemes = {}; + grabbedThemes = body.split("\n").filter(n => n); + BDFDB.LibraryRequires.request("https://github.com/NFLD99/Better-Discord", (error2, response2, body2) => { + if (!error2 && body2) { + NFLDreplace = /\/NFLD99\/Better-Discord\/tree\/master\/Themes_[^"]+">([^<]+)/i.exec(body2); + NFLDreplace = NFLDreplace && NFLDreplace.length > 1 ? NFLDreplace[1] : null; + } + foundThemes = grabbedThemes.concat(customList); + + loading = {is:true, timeout:BDFDB.TimeUtils.timeout(_ => { + BDFDB.TimeUtils.clear(loading.timeout); + if (this.started) { + if (loading.is && loading.amount < 4) BDFDB.TimeUtils.timeout(_ => {this.loadThemes();}, 10000); + loading = {is: false, timeout:null, amount:loading.amount}; + } + },1200000), amount:loading.amount+1}; + + let loadingicon = BDFDB.DOMUtils.create(themeRepoIcon); + BDFDB.DOMUtils.addClass(loadingicon, "themerepo-loadingicon"); + loadingicon.addEventListener("mouseenter", _ => { + BDFDB.TooltipUtils.create(loadingicon, this.getLoadingTooltipText(), { + type: "left", + delay: 500, + style: "max-width: unset;", + selector: "themerepo-loading-tooltip" + }); + }); + BDFDB.PluginUtils.addLoadingIcon(loadingicon); + + getThemeInfo(_ => { + if (!this.started) { + BDFDB.TimeUtils.clear(loading.timeout); + return; + } + BDFDB.TimeUtils.clear(loading.timeout); + BDFDB.DOMUtils.remove(loadingicon, ".themerepo-loadingicon"); + loading = {is:false, timeout:null, amount:loading.amount}; + + BDFDB.LogUtils.log("Finished fetching Themes.", this.name); + if (list) BDFDB.ReactUtils.forceUpdate(list); + + if ((settings.notifyOutdated || settings.notifyOutdated == undefined) && outdated > 0) { + let oldBarButton = document.querySelector(".themerepo-outdate-notice " + BDFDB.dotCN.noticedismiss); + if (oldBarButton) oldBarButton.click(); + let bar = BDFDB.NotificationUtils.notice(`${outdated} of your Themes ${outdated == 1 ? "is" : "are"} outdated. Check:`, { + type: "danger", + btn: "ThemeRepo", + selector: "themerepo-notice themerepo-outdate-notice", + customicon: themeRepoIcon.replace(/#7289da/gi, "#FFF").replace(/#7f8186/gi, "#B9BBBE") + }); + bar.querySelector(BDFDB.dotCN.noticebutton).addEventListener("click", _ => { + showOnlyOutdated = true; + BDFDB.LibraryModules.UserSettingsUtils.open("themerepo"); + bar.querySelector(BDFDB.dotCN.noticedismiss).click(); + }); + } + + if (settings.notifyNewEntries && newEntries > 0) { + let oldBarButton = document.querySelector(".themerepo-newentries-notice " + BDFDB.dotCN.noticedismiss); + if (oldBarButton) oldBarButton.click(); + let single = newEntries == 1; + let bar = BDFDB.NotificationUtils.notice(`There ${single ? "is" : "are"} ${newEntries} new Theme${single ? "" : "s"} in the Repo. Check:`, { + type: "success", + btn: "ThemeRepo", + selector: "themerepo-notice themerepo-newentries-notice", + customicon: themeRepoIcon.replace(/#7289da/gi, "#FFF").replace(/#7f8186/gi, "#B9BBBE") + }); + bar.querySelector(BDFDB.dotCN.noticebutton).addEventListener("click", _ => { + forcedSort = "NEW"; + forcedOrder = "ASC"; + BDFDB.LibraryModules.UserSettingsUtils.open("themerepo"); + bar.querySelector(BDFDB.dotCN.noticedismiss).click(); + }); + } + + if (BDFDB.UserUtils.me.id == "278543574059057154") { + let wrongUrls = []; + for (let url of foundThemes) if (url && !loadedThemes[url] && !wrongUrls.includes(url)) wrongUrls.push(url); + if (wrongUrls.length) { + let bar = BDFDB.NotificationUtils.notice(`ThemeRepo: ${wrongUrls.length} Theme${wrongUrls.length > 1 ? "s" : ""} could not be loaded.`, { + type: "danger", + btn: "List", + selector: "themerepo-notice themerepo-fail-notice", + customicon: themeRepoIcon.replace(/#7289da/gi, "#FFF").replace(/#7f8186/gi, "#B9BBBE") + }); + bar.querySelector(BDFDB.dotCN.noticebutton).addEventListener("click", e => { + let toast = BDFDB.NotificationUtils.toast(wrongUrls.join("\n"), {type: "error"}); + toast.style.setProperty("overflow", "hidden"); + for (let url of wrongUrls) console.log(url); + }); + } + } + + BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/GeneratorList.txt", (error3, response3, body3) => { + if (!error3 && body3) for (let url of body3.replace(/[\r\t]/g, "").split("\n").filter(n => n)) if (loadedThemes[url]) generatorThemes.push(url); + }); + + BDFDB.LibraryRequires.request(document.querySelector("head link[rel='stylesheet'][integrity]").href, (error3, response3, body3) => { + if (!error3 && body3) { + nativeCSS = body3; + let theme = BDFDB.DiscordUtils.getTheme(); + let vars = (nativeCSS.split(`.${theme}{`)[1] || "").split("}")[0]; + nativeCSSvars = vars ? `.theme-dark, .theme-light {${vars}}` : ""; + } + else nativeCSS = nativeCSSvars = ""; + }); + }); + }); + } + }); + + getThemeInfo = (callback) => { + if (i >= foundThemes.length || !this.started || !loading.is) { + callback(); + return; + } + let url = foundThemes[i]; + let requestUrl = NFLDreplace && url.includes("NFLD99/Better-Discord/master/Themes") ? url.replace("master/Themes", "master/" + NFLDreplace) : url; + BDFDB.LibraryRequires.request(requestUrl, (error, response, body) => { + if (!response) { + if (url && BDFDB.ArrayUtils.getAllIndexes(foundThemes, url).length < 2) foundThemes.push(url); + } + else if (body && body.indexOf("404: Not Found") != 0 && response.statusCode == 200) { + let theme = {}, text = body; + if ((text.split("*//").length > 1 || text.indexOf("/**") == 0) && text.split("\n").length > 1) { + let hasMETAline = text.replace(/\s/g, "").indexOf("//META{"); + if (hasMETAline < 20 && hasMETAline > -1) { + let searchtext = text.replace(/\s*:\s*/g, ":").replace(/\s*}\s*/g, "}"); + for (let tag of tags) { + let result = searchtext.split('"' + tag + '":"'); + result = result.length > 1 ? result[1].split('",')[0].split('"}')[0] : null; + result = result && tag != "version" ? result.charAt(0).toUpperCase() + result.slice(1) : result; + theme[tag] = result ? result.trim() : result; + } + } + else { + let searchtext = text.replace(/[\r\t| ]*\*\s*/g, "*"); + for (let tag of tags) { + let result = searchtext.split('@' + tag + ' '); + result = result.length > 1 ? result[1].split('\n')[0] : null; + result = result && tag != "version" ? result.charAt(0).toUpperCase() + result.slice(1) : result; + theme[tag] = result ? result.trim() : result; + } + } + + let valid = true; + for (let tag of tags) if (theme[tag] === null) valid = false; + if (valid) { + theme.fullCSS = text; + theme.css = hasMETAline < 20 && hasMETAline > -1 ? text.split("\n").slice(1).join("\n").replace(/[\r|\n|\t]/g, "") : text.replace(/[\r|\n|\t]/g, ""); + theme.url = url; + theme.requestUrl = requestUrl; + loadedThemes[url] = theme; + let instTheme = BDFDB.BDUtils.getTheme(theme.name); + if (instTheme && instTheme.author.toUpperCase() == theme.author.toUpperCase() && instTheme.version != theme.version) outdated++; + if (!cachedThemes.includes(url)) newEntries++; + } + } + } + i++; + + let loadingTooltip = document.querySelector(".themerepo-loading-tooltip"); + if (loadingTooltip) loadingTooltip.update(this.getLoadingTooltipText()); + + getThemeInfo(callback); + }); + } + } + + getLoadingTooltipText () { + return `Loading ThemeRepo - [${Object.keys(loadedThemes).length}/${Object.keys(grabbedThemes).length}]`; + } + + checkForNewThemes () { + BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeList.txt", (error, response, result) => { + if (response && !BDFDB.equals(result.replace(/\t|\r/g, "").split("\n").filter(n => n), grabbedThemes)) { + loading = {is:false, timeout:null, amount:0}; + this.loadThemes(); + } + }); + } + + downloadTheme (data) { + BDFDB.LibraryRequires.request(data.requestUrl, (error, response, body) => { + if (error) BDFDB.NotificationUtils.toast(`Unable to download Theme "${data.name}".`, {type:"danger"}); + else this.createThemeFile(data.requestUrl.split("/").pop(), body); + }); + } + + createThemeFile (filename, content) { + BDFDB.LibraryRequires.fs.writeFile(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getThemesFolder(), filename), content, (error) => { + if (error) BDFDB.NotificationUtils.toast(`Unable to save Theme "${filename}".`, {type:"danger"}); + else BDFDB.NotificationUtils.toast(`Successfully saved Theme "${filename}".`, {type:"success"}); + }); + } + + applyTheme (data) { + if (data.name && BDFDB.BDUtils.isThemeEnabled(data.name) == false) { + let id = data.name.replace(/^[^a-z]+|[^\w-]+/gi, "-"); + BDFDB.DOMUtils.remove(`style#${id}`); + BDFDB.BDUtils.enableTheme(data.name, false); + BDFDB.LogUtils.log(`Applied Theme ${data.name}.`, this.name); + } + } + + deleteThemeFile (data) { + let filename = data.requestUrl.split("/").pop(); + BDFDB.LibraryRequires.fs.unlink(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getThemesFolder(), filename), (error) => { + if (error) BDFDB.NotificationUtils.toast(`Unable to delete Theme "${filename}".`, {type:"danger"}); + else BDFDB.NotificationUtils.toast(`Successfully deleted Theme "${filename}".`); + }); + } + + removeTheme (data) { + if (data.name && BDFDB.BDUtils.isThemeEnabled(data.name) == true) { + let id = data.name.replace(/^[^a-z]+|[^\w-]+/gi, "-"); + BDFDB.DOMUtils.remove(`style#${id}`); + BDFDB.BDUtils.disableTheme(data.name, false); + BDFDB.LogUtils.log(`Removed Theme ${data.name}.`, this.name); + } + } + }; + })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); +})(); \ No newline at end of file