2020-03-12 20:00:31 +01:00
//META{"name":"UnreadBadgesRedux","source":"https://github.com/1Lighty/BetterDiscordPlugins/blob/master/Plugins/UnreadBadgesRedux/","website":"https://1lighty.github.io/BetterDiscordStuff/?plugin=UnreadBadgesRedux","authorId":"239513071272329217","invite":"NYvWdN5","donate":"https://paypal.me/lighty13"}*//
2019-12-27 21:26:03 +01:00
/ * @ c c _ o n
@ if ( @ _jscript )
// Offer to self-install for clueless users that try to run this directly.
var shell = WScript . CreateObject ( 'WScript.Shell' ) ;
var fs = new ActiveXObject ( 'Scripting.FileSystemObject' ) ;
var pathPlugins = shell . ExpandEnvironmentStrings ( '%APPDATA%\\BetterDiscord\\plugins' ) ;
var pathSelf = WScript . ScriptFullName ;
// Put the user at ease by addressing them in the first person
shell . Popup ( 'It looks like you\'ve mistakenly tried to run me directly. \n(Don\'t do that!)' , 0 , 'I\'m a plugin for BetterDiscord' , 0x30 ) ;
if ( fs . GetParentFolderName ( pathSelf ) === fs . GetAbsolutePathName ( pathPlugins ) ) {
2020-03-31 21:18:12 +02:00
shell . Popup ( 'I\'m in the correct folder already.\nJust go to settings, plugins and enable me.' , 0 , 'I\'m already installed' , 0x40 ) ;
2019-12-27 21:26:03 +01:00
} else if ( ! fs . FolderExists ( pathPlugins ) ) {
shell . Popup ( 'I can\'t find the BetterDiscord plugins folder.\nAre you sure it\'s even installed?' , 0 , 'Can\'t install myself' , 0x10 ) ;
} else if ( shell . Popup ( 'Should I copy myself to BetterDiscord\'s plugins folder for you?' , 0 , 'Do you need some help?' , 0x34 ) === 6 ) {
fs . CopyFile ( pathSelf , fs . BuildPath ( pathPlugins , fs . GetFileName ( pathSelf ) ) , true ) ;
// Show the user where to put plugins in the future
shell . Exec ( 'explorer ' + pathPlugins ) ;
2020-03-31 21:18:12 +02:00
shell . Popup ( 'I\'m installed!\nJust go to settings, plugins and enable me!' , 0 , 'Successfully installed' , 0x40 ) ;
2019-12-27 21:26:03 +01:00
}
WScript . Quit ( ) ;
@ else @ * /
/ *
* Copyright © 2019 - 2020 , _Lighty _
* All rights reserved .
* Code may not be redistributed , modified or otherwise taken without explicit permission .
* /
2020-07-26 13:39:27 +02:00
module . exports = ( ( ) => {
2019-12-27 21:26:03 +01:00
/* Setup */
const config = {
main : 'index.js' ,
info : {
name : 'UnreadBadgesRedux' ,
authors : [
{
name : 'Lighty' ,
discord _id : '239513071272329217' ,
github _username : 'LightyPon' ,
twitter _username : ''
}
] ,
2020-09-23 15:26:10 +02:00
version : '1.0.8' ,
2019-12-27 21:26:03 +01:00
description : 'Adds a number badge to server icons and channels.' ,
github : 'https://github.com/1Lighty' ,
github _raw : 'https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/UnreadBadgesRedux/UnreadBadgesRedux.plugin.js'
} ,
changelog : [
{
2020-03-31 21:18:12 +02:00
title : 'fixed' ,
2020-02-02 22:53:23 +01:00
type : 'fixed' ,
2020-09-23 15:26:10 +02:00
items : [ 'Fixed not working on channels.' ]
2019-12-27 21:26:03 +01:00
}
] ,
defaultConfig : [
{
type : 'category' ,
id : 'misc' ,
name : 'Display settings' ,
collapsible : true ,
shown : true ,
settings : [
{
name : 'Display badge on folders' ,
id : 'folders' ,
type : 'switch' ,
value : true
} ,
{
name : 'Ignore muted servers in folders unread badge count' ,
id : 'noMutedGuildsInFolderCount' ,
type : 'switch' ,
value : true
} ,
{
name : 'Ignore muted channels in servers in folders unread badge count' ,
id : 'noMutedChannelsInGuildsInFolderCount' ,
type : 'switch' ,
value : true
} ,
{
name : "Don't display badge on expanded folders" ,
id : 'expandedFolders' ,
type : 'switch' ,
value : true
} ,
{
name : 'Display badge on servers' ,
id : 'guilds' ,
type : 'switch' ,
value : true
} ,
{
name : 'Display badge on muted servers' ,
id : 'mutedGuilds' ,
type : 'switch' ,
value : true
} ,
{
name : 'Ignore muted channels in server unread badge count' ,
id : 'noMutedInGuildCount' ,
type : 'switch' ,
value : true
} ,
{
name : 'Display badge on channels' ,
id : 'channels' ,
type : 'switch' ,
value : true
} ,
{
name : 'Display badge on muted channels' ,
id : 'mutedChannels' ,
type : 'switch' ,
value : true
} ,
{
name : 'Display badge on left side on channels' ,
note : "In case you want the settings button to stay where it always is. This however doesn't move it before the NSFW tag if you use the BetterNsfwTag plugin" ,
id : 'channelsDisplayOnLeft' ,
type : 'switch' ,
value : false
} ,
{
name : 'Background color' ,
id : 'backgroundColor' ,
type : 'color' ,
value : '#7289da' ,
options : {
defaultColor : '#7289da'
}
} ,
{
name : 'Text color' ,
id : 'textColor' ,
type : 'color' ,
value : '#ffffff' ,
options : {
defaultColor : '#ffffff'
}
} ,
{
name : 'Muted channel badge darkness' ,
id : 'mutedChannelBadgeDarkness' ,
type : 'slider' ,
value : 0.25 ,
min : 0 ,
max : 1 ,
equidistant : true ,
options : {
equidistant : true
}
}
]
}
]
} ;
/* Build */
const buildPlugin = ( [ Plugin , Api ] ) => {
2020-03-31 21:18:12 +02:00
const { Settings , Utilities , WebpackModules , DiscordModules , ColorConverter , ReactComponents , Patcher , PluginUtilities , Logger , ReactTools , ModalStack } = Api ;
2019-12-27 21:26:03 +01:00
const { React , ChannelStore } = DiscordModules ;
const ReactSpring = WebpackModules . getByProps ( 'useTransition' ) ;
const BadgesModule = WebpackModules . getByProps ( 'NumberBadge' ) ;
const StoresModule = WebpackModules . getByProps ( 'useStateFromStores' ) ;
/* discord won't let me access it, so I remade it :( */
class BadgeContainer extends React . PureComponent {
componentDidMount ( ) {
this . forceUpdate ( ) ;
}
componentWillAppear ( e ) {
e ( ) ;
}
componentWillEnter ( e ) {
e ( ) ;
}
componentWillLeave ( e ) {
this . timeoutId = setTimeout ( e , 300 ) ;
}
componentWillUnmount ( ) {
clearTimeout ( this . timeoutId ) ;
}
render ( ) {
return React . createElement (
ReactSpring . animated . div ,
{
className : this . props . className ,
style : this . props . animatedStyle
} ,
this . props . children
) ;
}
}
const UnreadStore = WebpackModules . getByProps ( 'getUnreadCount' ) ;
const MuteModule = WebpackModules . getByProps ( 'isMuted' ) ;
2020-03-05 17:25:37 +01:00
const AltChannelStore = WebpackModules . find ( m => m . getChannels && m . getChannels . length === 1 ) ;
2019-12-27 21:26:03 +01:00
const getUnreadCount = ( guildId , includeMuted ) => {
2020-03-05 17:25:37 +01:00
const channels = AltChannelStore . getChannels ( guildId ) ;
2019-12-27 21:26:03 +01:00
let count = 0 ;
2020-03-05 17:25:37 +01:00
for ( const { channel } of channels . SELECTABLE ) {
2020-03-31 21:18:12 +02:00
/* isChannelMuted is SLOW! */
2020-03-05 17:25:37 +01:00
if ( includeMuted || ( ! MuteModule . isChannelMuted ( channel . guild _id , channel . id ) && ( ! channel . parent _id || ! MuteModule . isChannelMuted ( channel . guild _id , channel . parent _id ) ) ) ) count += UnreadStore . getUnreadCount ( channel . id ) ;
2019-12-27 21:26:03 +01:00
}
return count ;
} ;
class Slider extends Settings . SettingField {
/ * r i p p e d o u t o f Z e r e s P l u g i n L i b r a r y , b e c a u s e i t d o e s t h i n g s i n a w a y I D I S L I K E !
but otherwise full credits to Zerebos
https : //github.com/rauenzi/BDPluginLibrary/blob/master/src/ui/settings/types/slider.js
* /
constructor ( name , note , min , max , value , onChange , options = { } ) {
const props = {
onChange : _ => _ ,
defaultValue : value ,
disabled : options . disabled ? true : false ,
minValue : min ,
maxValue : max ,
handleSize : 10 ,
initialValue : value /* added this */
} ;
if ( options . fillStyles ) props . fillStyles = options . fillStyles ;
if ( options . markers ) props . markers = options . markers ;
if ( options . stickToMarkers ) props . stickToMarkers = options . stickToMarkers ;
if ( typeof options . equidistant != 'undefined' ) props . equidistant = options . equidistant ;
super ( name , note , onChange , DiscordModules . Slider , Object . assign ( props , { onValueChange : v => this . onChange ( v ) } ) ) ;
}
}
return class UnreadBadgesRedux extends Plugin {
constructor ( ) {
super ( ) ;
XenoLib . changeName ( _ _filename , 'UnreadBadgesRedux' ) ;
2020-03-31 21:18:12 +02:00
const oOnStart = this . onStart . bind ( this ) ;
this . onStart = ( ) => {
try {
oOnStart ( ) ;
} catch ( e ) {
Logger . stacktrace ( 'Failed to start!' , e ) ;
PluginUpdater . checkForUpdate ( this . name , this . version , this . _config . info . github _raw ) ;
XenoLib . Notifications . error ( ` [** ${ this . name } **] Failed to start! Please update it, press CTRL + R, or ${ GuildStore . getGuild ( XenoLib . supportServerId ) ? 'go to <#639665366380838924>' : '[join my support server](https://discord.gg/NYvWdN5)' } for further assistance. ` , { timeout : 0 } ) ;
try {
this . onStop ( ) ;
} catch ( e ) { }
}
} ;
2020-03-12 20:00:31 +01:00
try {
ModalStack . popWithKey ( ` ${ this . name } _DEP_MODAL ` ) ;
} catch ( e ) { }
2019-12-27 21:26:03 +01:00
}
onStart ( ) {
this . promises = { state : { cancelled : false } } ;
this . patchedModules = [ ] ;
this . patchAll ( ) ;
PluginUtilities . addStyle (
this . short + '-CSS' ,
`
. unread - badge {
right : unset ;
}
`
) ;
}
onStop ( ) {
this . promises . state . cancelled = true ;
Patcher . unpatchAll ( ) ;
PluginUtilities . removeStyle ( this . short + '-CSS' ) ;
this . forceUpdateAll ( ) ;
}
buildSetting ( data ) {
if ( data . type === 'color' ) {
const setting = new XenoLib . Settings . ColorPicker ( data . name , data . note , data . value , data . onChange , data . options ) ;
if ( data . id ) setting . id = data . id ;
return setting ;
} else if ( data . type === 'slider' ) {
const options = { } ;
const { name , note , value , onChange , min , max } = data ;
if ( typeof data . markers !== 'undefined' ) options . markers = data . markers ;
if ( typeof data . stickToMarkers !== 'undefined' ) options . stickToMarkers = data . stickToMarkers ;
const setting = new Slider ( name , note , min , max , value , onChange , options ) ;
if ( data . id ) setting . id = data . id ;
return setting ;
}
return super . buildSetting ( data ) ;
}
saveSettings ( _ , setting , value ) {
super . saveSettings ( _ , setting , value ) ;
this . forceUpdateAll ( ) ;
}
forceUpdateAll ( ) {
this . patchedModules . forEach ( e => e ( ) ) ;
}
/* PATCHES */
patchAll ( ) {
Utilities . suppressErrors ( this . patchBlobMask . bind ( this ) , 'BlobMask patch' ) ( this . promises . state ) ;
Utilities . suppressErrors ( this . patchGuildIcon . bind ( this ) , 'GuildIcon patch' ) ( this . promises . state ) ;
Utilities . suppressErrors ( this . patchChannelItem . bind ( this ) , 'ChannelItem patch' ) ( this . promises . state ) ;
Utilities . suppressErrors ( this . patchConnectedGuild . bind ( this ) , 'ConnectedGuild patch' ) ( this . promises . state ) ;
Utilities . suppressErrors ( this . patchGuildFolder . bind ( this ) , 'GuildFolder patch' ) ( this . promises . state ) ;
}
async patchChannelItem ( promiseState ) {
2020-03-12 20:00:31 +01:00
const selector = ` . ${ XenoLib . getSingleClass ( 'modeUnread wrapper' , true ) } ` ;
const ChannelItem = await ReactComponents . getComponentByName ( 'ChannelItem' , selector ) ;
if ( ! ChannelItem . selector ) ChannelItem . selector = selector ;
2019-12-27 21:26:03 +01:00
if ( promiseState . cancelled ) return ;
const settings = this . settings ;
const MentionsBadgeClassname = XenoLib . getClass ( 'iconVisibility mentionsBadge' ) ;
const IconsChildren = XenoLib . getClass ( 'modeMuted children' ) ;
function UnreadBadge ( e ) {
2020-03-05 17:25:37 +01:00
const unreadCount = StoresModule . useStateFromStores ( [ UnreadStore ] , ( ) => {
if ( ( e . muted && ! settings . misc . mutedChannels ) || ! settings . misc . channels ) return 0 ;
const count = UnreadStore . getUnreadCount ( e . channelId ) ;
if ( count > 1000 ) return Math . floor ( count / 1000 ) * 1000 ; /* only trigger rerender if it changes in thousands */
return count ;
} ) ;
2019-12-27 21:26:03 +01:00
if ( ! unreadCount ) return null ;
return React . createElement (
'div' ,
{
className : MentionsBadgeClassname
} ,
BadgesModule . NumberBadge ( { count : unreadCount , color : e . muted ? ColorConverter . darkenColor ( settings . misc . backgroundColor , settings . misc . mutedChannelBadgeDarkness * 100 ) : settings . misc . backgroundColor , style : { color : e . muted ? ColorConverter . darkenColor ( settings . misc . textColor , settings . misc . mutedChannelBadgeDarkness * 100 ) : settings . misc . textColor } } )
) ;
}
Patcher . after ( ChannelItem . component . prototype , 'renderIcons' , ( _this , args , ret ) => {
const badge = React . createElement ( UnreadBadge , { channelId : _this . props . channel . id , muted : _this . props . muted && ! _this . props . selected } ) ;
if ( ! ret ) {
return React . createElement (
'div' ,
{
onClick : e => e . stopPropagation ( ) ,
className : IconsChildren
} ,
badge
) ;
}
/ * c h i l d r e n i s a r e f e r n c e t o t h e c h i l d r e n p r o p w i t h i n t h e c o m p o n e n t , w h i c h i s b a d
so appending it without slicing first would append it to the components props
children array
* /
2020-09-23 15:26:10 +02:00
const props = Utilities . findInReactTree ( ret , e => Array . isArray ( e . children ) && e . children . find ( e => e && e . type && e . type . displayName === 'ConnectedEditButton' ) ) ;
if ( ! props ) return ;
const buttons = props . children . slice ( 0 ) ;
2019-12-27 21:26:03 +01:00
if ( ! buttons ) return ;
buttons . splice ( this . settings . misc . channelsDisplayOnLeft ? 0 : 2 , 0 , badge ) ;
2020-09-23 15:26:10 +02:00
props . children = buttons ;
2019-12-27 21:26:03 +01:00
} ) ;
ChannelItem . forceUpdateAll ( ) ;
}
async patchGuildFolder ( promiseState ) {
const settings = this . settings ;
2020-03-31 21:18:12 +02:00
const FolderStore = WebpackModules . getByProps ( 'isFolderExpanded' ) ;
2019-12-27 21:26:03 +01:00
function BlobMaskWrapper ( e ) {
e . _ _UBR _unread _count = StoresModule . useStateFromStores ( [ UnreadStore , MuteModule ] , ( ) => {
if ( ( e . _ _UBR _folder _expanded && settings . misc . expandedFolders ) || ! settings . misc . folders ) return 0 ;
let count = 0 ;
for ( let i = 0 ; i < e . _ _UBR _guildIds . length ; i ++ ) {
const guildId = e . _ _UBR _guildIds [ i ] ;
if ( ! settings . misc . noMutedGuildsInFolderCount || ( settings . misc . noMutedGuildsInFolderCount && ! MuteModule . isMuted ( guildId ) ) ) count += getUnreadCount ( guildId , ! settings . misc . noMutedChannelsInGuildsInFolderCount ) ;
}
2020-03-05 17:25:37 +01:00
if ( count > 1000 ) return Math . floor ( count / 1000 ) * 1000 ; /* only trigger rerender if it changes in thousands */
2019-12-27 21:26:03 +01:00
return count ;
} ) ;
return React . createElement ( e . _ _UBR _old _type , e ) ;
}
BlobMaskWrapper . displayName = 'BlobMask' ;
2020-07-01 19:16:33 +02:00
const GuildFolderMemo = WebpackModules . find ( m => m . type && m . type . toString ( ) . indexOf ( '.Messages.SERVER_FOLDER_PLACEHOLDER' ) !== - 1 ) ;
2020-03-31 21:18:12 +02:00
if ( GuildFolderMemo ) {
Patcher . after ( GuildFolderMemo , 'type' , ( _ , [ props ] , ret ) => {
const mask = Utilities . findInReactTree ( ret , e => e && e . type && e . type . displayName === 'BlobMask' ) ;
if ( ! mask ) return ;
mask . props . _ _UBR _old _type = mask . type ;
mask . props . _ _UBR _guildIds = props . guildIds ;
mask . props . _ _UBR _folder _expanded = FolderStore . isFolderExpanded ( props . folderId ) ;
mask . type = BlobMaskWrapper ;
} ) ;
const instance = ReactTools . getOwnerInstance ( document . querySelector ( '.wrapper-21YSNc' ) ) ;
if ( ! instance ) return ;
const unpatch = Patcher . after ( instance , 'render' , ( _ , _ _ , ret ) => {
unpatch ( ) ;
if ( ! ret ) return ;
ret . key = ` GETGOOD ${ Math . random ( ) } ` ;
const oRef = ret . props . setFolderRef ;
ret . props . setFolderRef = ( e , n ) => {
_ . forceUpdate ( ) ;
return oRef ( e , n ) ;
} ;
} ) ;
instance . forceUpdate ( ) ;
return ;
}
const selector = ` . ${ XenoLib . getSingleClass ( 'folder wrapper' , true ) } ` ;
const GuildFolder = await ReactComponents . getComponentByName ( 'GuildFolder' , selector ) ;
if ( ! GuildFolder . selector ) GuildFolder . selector = selector ;
if ( promiseState . cancelled ) return ;
2020-03-05 17:25:37 +01:00
Patcher . after ( GuildFolder . component . prototype , 'render' , ( _this , _ , ret ) => {
const mask = Utilities . findInTree ( ret , e => e && e . type && e . type . displayName === 'BlobMask' , { walkable : [ 'props' , 'children' ] } ) ;
2019-12-27 21:26:03 +01:00
if ( ! mask ) return ;
mask . props . _ _UBR _old _type = mask . type ;
mask . props . _ _UBR _guildIds = _this . props . guildIds ;
mask . props . _ _UBR _folder _expanded = _this . props . expanded ;
mask . type = BlobMaskWrapper ;
} ) ;
GuildFolder . forceUpdateAll ( ) ;
this . patchedModules . push ( GuildFolder . forceUpdateAll . bind ( GuildFolder ) ) ;
}
async patchConnectedGuild ( promiseState ) {
2020-03-12 20:00:31 +01:00
const selector = ` . ${ XenoLib . getSingleClass ( 'listItem' , true ) } ` ;
const ConnectedGuild = await ReactComponents . getComponentByName ( 'DragSource(ConnectedGuild)' , selector ) ;
if ( ! ConnectedGuild . selector ) ConnectedGuild . selector = selector ;
2019-12-27 21:26:03 +01:00
if ( promiseState . cancelled ) return ;
const settings = this . settings ;
function PatchedConnectedGuild ( e ) {
/* get on my level scrublords */
e . _ _UBR _unread _count = StoresModule . useStateFromStores ( [ UnreadStore , MuteModule ] , ( ) => ( ! settings . misc . guilds || ( ! settings . misc . mutedGuilds && MuteModule . isMuted ( e . guildId ) ) ? 0 : getUnreadCount ( e . guildId , ! settings . misc . noMutedInGuildCount ) ) ) ;
return e . _ _UBR _old _type ( e ) ;
}
PatchedConnectedGuild . displayName = 'ConnectedGuild' ;
2020-03-05 17:25:37 +01:00
Patcher . after ( ConnectedGuild . component . prototype , 'render' , ( _this , _ , ret ) => {
2019-12-27 21:26:03 +01:00
const old = ret . props . children ;
ret . props . children = e => {
const ret2 = old ( e ) ;
ret2 . props . _ _UBR _old _type = ret2 . type ;
ret2 . type = PatchedConnectedGuild ;
return ret2 ;
} ;
} ) ;
ConnectedGuild . forceUpdateAll ( ) ;
this . patchedModules . push ( ConnectedGuild . forceUpdateAll . bind ( ConnectedGuild ) ) ;
}
async patchGuildIcon ( promiseState ) {
2020-03-12 20:00:31 +01:00
const selector = ` . ${ XenoLib . getSingleClass ( 'listItem' , true ) } ` ;
const Guild = await ReactComponents . getComponentByName ( 'Guild' , selector ) ;
if ( ! Guild . selector ) Guild . selector = selector ;
2019-12-27 21:26:03 +01:00
if ( promiseState . cancelled ) return ;
2020-03-05 17:25:37 +01:00
Patcher . after ( Guild . component . prototype , 'render' , ( _this , _ , ret ) => {
const mask = Utilities . findInTree ( ret , e => e && e . type && e . type . displayName === 'BlobMask' , { walkable : [ 'props' , 'children' ] } ) ;
if ( ! mask ) return ;
mask . props . _ _UBR _unread _count = _this . props . _ _UBR _unread _count ;
mask . props . guildId = _this . props . guildId ;
2019-12-27 21:26:03 +01:00
} ) ;
Guild . forceUpdateAll ( ) ;
}
async patchBlobMask ( promiseState ) {
2020-03-12 20:00:31 +01:00
const selector = ` . ${ XenoLib . getSingleClass ( 'lowerBadge wrapper' ) } ` ;
const BlobMask = await ReactComponents . getComponentByName ( 'BlobMask' , selector ) ;
if ( ! BlobMask . selector ) BlobMask . selector = selector ;
2019-12-27 21:26:03 +01:00
if ( promiseState . cancelled ) return ;
const ensureUnreadBadgeMask = _this => {
if ( _this . state . unreadBadgeMask ) return ;
_this . state . unreadBadgeMask = new ReactSpring . Controller ( {
spring : 0
} ) ;
} ;
2020-03-05 17:25:37 +01:00
Patcher . after ( BlobMask . component . prototype , 'componentDidMount' , _this => {
2019-12-27 21:26:03 +01:00
if ( typeof _this . props . _ _UBR _unread _count !== 'number' ) return ;
ensureUnreadBadgeMask ( _this ) ;
_this . state . unreadBadgeMask
. update ( {
spring : ! ! _this . props . _ _UBR _unread _count ,
immediate : true
} )
. start ( ) ;
} ) ;
2020-03-05 17:25:37 +01:00
Patcher . after ( BlobMask . component . prototype , 'componentWillUnmount' , _this => {
2019-12-27 21:26:03 +01:00
if ( typeof _this . props . _ _UBR _unread _count !== 'number' ) return ;
if ( ! _this . state . unreadBadgeMask ) return ;
2020-08-31 13:49:27 +02:00
if ( typeof _this . state . unreadBadgeMask . destroy === 'function' ) _this . state . unreadBadgeMask . destroy ( ) ;
else _this . state . unreadBadgeMask . dispose ( ) ;
2020-03-31 21:18:12 +02:00
_this . state . unreadBadgeMask = null ;
2019-12-27 21:26:03 +01:00
} ) ;
2020-03-05 17:25:37 +01:00
Patcher . after ( BlobMask . component . prototype , 'componentDidUpdate' , ( _this , [ { _ _UBR _unread _count } ] ) => {
if ( typeof _this . props . _ _UBR _unread _count !== 'number' || _this . props . _ _UBR _unread _count === _ _UBR _unread _count ) return ;
2019-12-27 21:26:03 +01:00
ensureUnreadBadgeMask ( _this ) ;
_this . state . unreadBadgeMask
. update ( {
spring : ! ! _this . props . _ _UBR _unread _count ,
immediate : ! document . hasFocus ( ) ,
config : {
friction : 40 ,
tension : 900 ,
mass : 1
}
} )
. start ( ) ;
} ) ;
const LowerBadgeClassname = XenoLib . joinClassNames ( XenoLib . getClass ( 'wrapper lowerBadge' ) , 'unread-badge' ) ;
2020-03-05 17:25:37 +01:00
Patcher . after ( BlobMask . component . prototype , 'render' , ( _this , _ , ret ) => {
2019-12-27 21:26:03 +01:00
if ( typeof _this . props . _ _UBR _unread _count !== 'number' ) return ;
2020-03-05 17:25:37 +01:00
const badges = Utilities . findInTree ( ret , e => e && e . type && e . type . displayName === 'TransitionGroup' , { walkable : [ 'props' , 'children' ] } ) ;
const masks = Utilities . findInTree ( ret , e => e && e . type === 'mask' , { walkable : [ 'props' , 'children' ] } ) ;
2019-12-27 21:26:03 +01:00
if ( ! badges || ! masks ) return ;
ensureUnreadBadgeMask ( _this ) ;
/ * i f c o u n t i s 0 , w e ' r e a n i m a t i n g o u t , a n d a s s u c h , i t ' s b e t t e r t o a t l e a s t s t i l l d i s p l a y t h e o l d
count while animating out
* /
const counter = _this . props . _ _UBR _unread _count || _this . state . _ _UBR _old _unread _count ;
if ( _this . props . _ _UBR _unread _count ) _this . state . _ _UBR _old _unread _count = _this . props . _ _UBR _unread _count ;
const width = BadgesModule . getBadgeWidthForValue ( counter ) ;
2020-08-31 13:49:27 +02:00
const unreadCountMaskSpring = ( _this . state . unreadBadgeMask . animated || _this . state . unreadBadgeMask . springs ) . spring ;
2020-03-05 17:25:37 +01:00
masks . props . children . push (
2019-12-27 21:26:03 +01:00
React . createElement ( ReactSpring . animated . rect , {
x : - 4 ,
y : 28 ,
width : width + 8 ,
height : 24 ,
rx : 12 ,
ry : 12 ,
2020-03-31 21:18:12 +02:00
opacity : unreadCountMaskSpring . to ( [ 0 , 0.5 , 1 ] , [ 0 , 0 , 1 ] ) ,
transform : unreadCountMaskSpring . to ( [ 0 , 1 ] , [ - 16 , 0 ] ) . to ( e => ` translate( ${ e } ${ - e } ) ` ) ,
2019-12-27 21:26:03 +01:00
fill : 'black'
} )
) ;
2020-03-05 17:25:37 +01:00
badges . props . children . unshift (
2019-12-27 21:26:03 +01:00
React . createElement (
BadgeContainer ,
{
className : LowerBadgeClassname ,
animatedStyle : {
opacity : unreadCountMaskSpring . to ( [ 0 , 0.5 , 1 ] , [ 0 , 0 , 1 ] ) ,
2020-03-31 21:18:12 +02:00
transform : unreadCountMaskSpring . to ( e => ` translate( ${ - 20 + 20 * e } ${ - 1 * ( 16 - 16 * e ) } ) ` )
2019-12-27 21:26:03 +01:00
}
} ,
2020-03-31 21:18:12 +02:00
React . createElement ( BadgesModule . NumberBadge , { count : counter , color : this . settings . misc . backgroundColor , style : { color : this . settings . misc . textColor } } )
2019-12-27 21:26:03 +01:00
)
) ;
} ) ;
BlobMask . forceUpdateAll ( ) ;
}
/* PATCHES */
2020-03-05 17:25:37 +01:00
showChangelog ( footer ) {
XenoLib . showChangelog ( ` ${ this . name } has been updated! ` , this . version , this . _config . changelog ) ;
}
2019-12-27 21:26:03 +01:00
getSettingsPanel ( ) {
return this . buildSettingsPanel ( ) . getElement ( ) ;
}
get [ Symbol . toStringTag ] ( ) {
return 'Plugin' ;
}
get css ( ) {
return this . _css ;
}
get name ( ) {
return config . info . name ;
}
get short ( ) {
let string = '' ;
for ( let i = 0 , len = config . info . name . length ; i < len ; i ++ ) {
const char = config . info . name [ i ] ;
if ( char === char . toUpperCase ( ) ) string += char ;
}
return string ;
}
get author ( ) {
return config . info . authors . map ( author => author . name ) . join ( ', ' ) ;
}
get version ( ) {
return config . info . version ;
}
get description ( ) {
return config . info . description ;
}
} ;
} ;
/* Finalize */
2020-03-05 17:25:37 +01:00
let ZeresPluginLibraryOutdated = false ;
let XenoLibOutdated = false ;
try {
if ( global . BdApi && 'function' == typeof BdApi . getPlugin ) {
const i = ( i , n ) => ( ( i = i . split ( '.' ) . map ( i => parseInt ( i ) ) ) , ( n = n . split ( '.' ) . map ( i => parseInt ( i ) ) ) , ! ! ( n [ 0 ] > i [ 0 ] ) || ! ! ( n [ 0 ] == i [ 0 ] && n [ 1 ] > i [ 1 ] ) || ! ! ( n [ 0 ] == i [ 0 ] && n [ 1 ] == i [ 1 ] && n [ 2 ] > i [ 2 ] ) ) ,
n = ( n , e ) => n && n . _config && n . _config . info && n . _config . info . version && i ( n . _config . info . version , e ) ,
e = BdApi . getPlugin ( 'ZeresPluginLibrary' ) ,
2020-03-12 20:00:31 +01:00
o = BdApi . getPlugin ( 'XenoLib' ) ;
2020-04-12 17:19:05 +02:00
n ( e , '1.2.14' ) && ( ZeresPluginLibraryOutdated = ! 0 ) , n ( o , '1.3.17' ) && ( XenoLibOutdated = ! 0 ) ;
2020-03-05 17:25:37 +01:00
}
} catch ( i ) {
console . error ( 'Error checking if libraries are out of date' , i ) ;
}
return ! global . ZeresPluginLibrary || ! global . XenoLib || ZeresPluginLibraryOutdated || XenoLibOutdated
2019-12-27 21:26:03 +01:00
? class {
2020-03-12 20:00:31 +01:00
constructor ( ) {
this . _XL _PLUGIN = true ;
2020-03-31 21:18:12 +02:00
this . start = this . load = this . handleMissingLib ;
2020-03-12 20:00:31 +01:00
}
2019-12-27 21:26:03 +01:00
getName ( ) {
return this . name . replace ( /\s+/g , '' ) ;
}
getAuthor ( ) {
return this . author ;
}
getVersion ( ) {
return this . version ;
}
getDescription ( ) {
2020-03-31 21:18:12 +02:00
return this . description + ' You are missing libraries for this plugin, please enable the plugin and click Download Now.' ;
2019-12-27 21:26:03 +01:00
}
stop ( ) { }
2020-03-31 21:18:12 +02:00
handleMissingLib ( ) {
2020-07-17 15:39:31 +02:00
const a = BdApi . findModuleByProps ( 'openModal' , 'hasModalOpen' ) ;
if ( a && a . hasModalOpen ( ` ${ this . name } _DEP_MODAL ` ) ) return ;
2020-03-12 20:00:31 +01:00
const b = ! global . XenoLib ,
c = ! global . ZeresPluginLibrary ,
d = ( b && c ) || ( ( b || c ) && ( XenoLibOutdated || ZeresPluginLibraryOutdated ) ) ,
2020-03-05 17:25:37 +01:00
e = ( ( ) => {
2020-03-12 20:00:31 +01:00
let a = '' ;
return b || c ? ( a += ` Missing ${ XenoLibOutdated || ZeresPluginLibraryOutdated ? ' and outdated' : '' } ` ) : ( XenoLibOutdated || ZeresPluginLibraryOutdated ) && ( a += ` Outdated ` ) , ( a += ` ${ d ? 'Libraries' : 'Library' } ` ) , a ;
2020-03-05 17:25:37 +01:00
} ) ( ) ,
2020-03-12 20:00:31 +01:00
f = ( ( ) => {
let a = ` The ${ d ? 'libraries' : 'library' } ` ;
return b || XenoLibOutdated ? ( ( a += 'XenoLib ' ) , ( c || ZeresPluginLibraryOutdated ) && ( a += 'and ZeresPluginLibrary ' ) ) : ( c || ZeresPluginLibraryOutdated ) && ( a += 'ZeresPluginLibrary ' ) , ( a += ` required for ${ this . name } ${ d ? 'are' : 'is' } ${ b || c ? 'missing' : '' } ${ XenoLibOutdated || ZeresPluginLibraryOutdated ? ( b || c ? ' and/or outdated' : 'outdated' ) : '' } . ` ) , a ;
} ) ( ) ,
2020-07-17 15:39:31 +02:00
g = BdApi . findModuleByDisplayName ( 'Text' ) ,
h = BdApi . findModuleByDisplayName ( 'ConfirmModal' ) ,
i = ( ) => BdApi . alert ( e , BdApi . React . createElement ( 'span' , { } , BdApi . React . createElement ( 'div' , { } , f ) , ` Due to a slight mishap however, you'll have to download the libraries yourself. This is not intentional, something went wrong, errors are in console. ` , c || ZeresPluginLibraryOutdated ? BdApi . React . createElement ( 'div' , { } , BdApi . React . createElement ( 'a' , { href : 'https://betterdiscord.net/ghdl?id=2252' , target : '_blank' } , 'Click here to download ZeresPluginLibrary' ) ) : null , b || XenoLibOutdated ? BdApi . React . createElement ( 'div' , { } , BdApi . React . createElement ( 'a' , { href : 'https://betterdiscord.net/ghdl?id=3169' , target : '_blank' } , 'Click here to download XenoLib' ) ) : null ) ) ;
if ( ! a || ! h || ! g ) return console . error ( ` Missing components: ${ ( a ? '' : ' ModalStack' ) + ( h ? '' : ' ConfirmationModalComponent' ) + ( g ? '' : 'TextElement' ) } ` ) , i ( ) ;
class j extends BdApi . React . PureComponent {
2020-03-05 17:25:37 +01:00
constructor ( a ) {
2020-07-17 15:39:31 +02:00
super ( a ) , ( this . state = { hasError : ! 1 } ) , ( this . componentDidCatch = a => ( console . error ( ` Error in ${ this . props . label } , screenshot or copy paste the error above to Lighty for help. ` ) , this . setState ( { hasError : ! 0 } ) , 'function' == typeof this . props . onError && this . props . onError ( a ) ) ) , ( this . render = ( ) => ( this . state . hasError ? null : this . props . children ) ) ;
2020-03-12 20:00:31 +01:00
}
}
2020-07-17 15:39:31 +02:00
let k = ! 1 ,
l = ! 1 ;
const m = a . openModal (
b => {
if ( l ) return null ;
try {
return BdApi . React . createElement (
j ,
{ label : 'missing dependency modal' , onError : ( ) => ( a . closeModal ( m ) , i ( ) ) } ,
BdApi . React . createElement (
h ,
Object . assign (
{
header : e ,
children : BdApi . React . createElement ( g , { size : g . Sizes . SIZE _16 , children : [ ` ${ f } Please click Download Now to download ${ d ? 'them' : 'it' } . ` ] } ) ,
red : ! 1 ,
confirmText : 'Download Now' ,
cancelText : 'Cancel' ,
onCancel : b . onClose ,
onConfirm : ( ) => {
if ( k ) return ;
k = ! 0 ;
const b = require ( 'request' ) ,
c = require ( 'fs' ) ,
d = require ( 'path' ) ,
e = BdApi . Plugins && BdApi . Plugins . folder ? BdApi . Plugins . folder : window . ContentManager . pluginsFolder ,
f = ( ) => {
( global . XenoLib && ! XenoLibOutdated ) ||
b ( 'https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/1XenoLib.plugin.js' , ( b , f , g ) => {
try {
if ( b || 200 !== f . statusCode ) return a . closeModal ( m ) , i ( ) ;
c . writeFile ( d . join ( e , '1XenoLib.plugin.js' ) , g , ( ) => { } ) ;
} catch ( b ) {
console . error ( 'Fatal error downloading XenoLib' , b ) , a . closeModal ( m ) , i ( ) ;
}
} ) ;
} ;
! global . ZeresPluginLibrary || ZeresPluginLibraryOutdated
? b ( 'https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js' , ( b , g , h ) => {
try {
if ( b || 200 !== g . statusCode ) return a . closeModal ( m ) , i ( ) ;
c . writeFile ( d . join ( e , '0PluginLibrary.plugin.js' ) , h , ( ) => { } ) , f ( ) ;
} catch ( b ) {
console . error ( 'Fatal error downloading ZeresPluginLibrary' , b ) , a . closeModal ( m ) , i ( ) ;
}
} )
: f ( ) ;
}
} ,
b ,
{ onClose : ( ) => { } }
)
2020-03-12 20:00:31 +01:00
)
2020-07-17 15:39:31 +02:00
) ;
} catch ( b ) {
return console . error ( 'There has been an error constructing the modal' , b ) , ( l = ! 0 ) , a . closeModal ( m ) , i ( ) , null ;
}
} ,
{ modalKey : ` ${ this . name } _DEP_MODAL ` }
2020-03-05 17:25:37 +01:00
) ;
2019-12-27 21:26:03 +01:00
}
get [ Symbol . toStringTag ] ( ) {
return 'Plugin' ;
}
get name ( ) {
return config . info . name ;
}
get short ( ) {
let string = '' ;
for ( let i = 0 , len = config . info . name . length ; i < len ; i ++ ) {
const char = config . info . name [ i ] ;
if ( char === char . toUpperCase ( ) ) string += char ;
}
return string ;
}
get author ( ) {
return config . info . authors . map ( author => author . name ) . join ( ', ' ) ;
}
get version ( ) {
return config . info . version ;
}
get description ( ) {
return config . info . description ;
}
}
: buildPlugin ( global . ZeresPluginLibrary . buildPlugin ( config ) ) ;
} ) ( ) ;
/*@end@*/