Fix BetterFolders
This commit is contained in:
		
							parent
							
								
									7845af0802
								
							
						
					
					
						commit
						9ce923d4d7
					
				
					 4 changed files with 251 additions and 236 deletions
				
			
		| 
						 | 
					@ -16,56 +16,34 @@
 | 
				
			||||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
					 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Settings } from "@api/Settings";
 | 
					 | 
				
			||||||
import { classNameFactory } from "@api/Styles";
 | 
					 | 
				
			||||||
import ErrorBoundary from "@components/ErrorBoundary";
 | 
					import ErrorBoundary from "@components/ErrorBoundary";
 | 
				
			||||||
import { findByPropsLazy, findStoreLazy } from "@webpack";
 | 
					import { LazyComponent } from "@utils/react";
 | 
				
			||||||
import { i18n, React, useStateFromStores } from "@webpack/common";
 | 
					import { find, findByPropsLazy } from "@webpack";
 | 
				
			||||||
 | 
					import { React, useStateFromStores } from "@webpack/common";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const cl = classNameFactory("vc-bf-");
 | 
					import { ExpandedGuildFolderStore, settings } from ".";
 | 
				
			||||||
const classes = findByPropsLazy("sidebar", "guilds");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Animations = findByPropsLazy("a", "animated", "useTransition");
 | 
					const Animations = findByPropsLazy("a", "animated", "useTransition");
 | 
				
			||||||
const ChannelRTCStore = findStoreLazy("ChannelRTCStore");
 | 
					const GuildsBar = LazyComponent(() => find(m => m.type?.toString().includes('("guildsnav")')));
 | 
				
			||||||
const ExpandedGuildFolderStore = findStoreLazy("ExpandedGuildFolderStore");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Guilds(props: {
 | 
					export default ErrorBoundary.wrap(guildsBarProps => {
 | 
				
			||||||
    className: string;
 | 
					 | 
				
			||||||
    bfGuildFolders: any[];
 | 
					 | 
				
			||||||
}) {
 | 
					 | 
				
			||||||
    // @ts-expect-error
 | 
					 | 
				
			||||||
    const res = Vencord.Plugins.plugins.BetterFolders.Guilds(props);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // TODO: Make this better
 | 
					 | 
				
			||||||
    const scrollerProps = res.props.children?.props?.children?.props?.children?.[1]?.props;
 | 
					 | 
				
			||||||
    if (scrollerProps?.children) {
 | 
					 | 
				
			||||||
        const servers = scrollerProps.children.find(c => c?.props?.["aria-label"] === i18n.Messages.SERVERS);
 | 
					 | 
				
			||||||
        if (servers) scrollerProps.children = servers;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default ErrorBoundary.wrap(() => {
 | 
					 | 
				
			||||||
    const expandedFolders = useStateFromStores([ExpandedGuildFolderStore], () => ExpandedGuildFolderStore.getExpandedFolders());
 | 
					    const expandedFolders = useStateFromStores([ExpandedGuildFolderStore], () => ExpandedGuildFolderStore.getExpandedFolders());
 | 
				
			||||||
    const fullscreen = useStateFromStores([ChannelRTCStore], () => ChannelRTCStore.isFullscreenInContext());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const guilds = document.querySelector(`.${classes.guilds}`);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const visible = !!expandedFolders.size;
 | 
					 | 
				
			||||||
    const className = cl("folder-sidebar", { fullscreen });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const Sidebar = (
 | 
					    const Sidebar = (
 | 
				
			||||||
        <Guilds
 | 
					        <GuildsBar
 | 
				
			||||||
            className={classes.guilds}
 | 
					            {...guildsBarProps}
 | 
				
			||||||
            bfGuildFolders={Array.from(expandedFolders)}
 | 
					            isBetterFolders={true}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!guilds || !Settings.plugins.BetterFolders.sidebarAnim)
 | 
					    const visible = !!expandedFolders.size;
 | 
				
			||||||
 | 
					    const guilds = document.querySelector(guildsBarProps.className.split(" ").map(c => `.${c}`).join(""));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!guilds || !settings.store.sidebarAnim) {
 | 
				
			||||||
        return visible
 | 
					        return visible
 | 
				
			||||||
            ? <div className={className}>{Sidebar}</div>
 | 
					            ? <div style={{ display: "flex " }}>{Sidebar}</div>
 | 
				
			||||||
            : null;
 | 
					            : null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Animations.Transition
 | 
					        <Animations.Transition
 | 
				
			||||||
| 
						 | 
					@ -75,11 +53,13 @@ export default ErrorBoundary.wrap(() => {
 | 
				
			||||||
            leave={{ width: 0 }}
 | 
					            leave={{ width: 0 }}
 | 
				
			||||||
            config={{ duration: 200 }}
 | 
					            config={{ duration: 200 }}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            {(style, show) => show && (
 | 
					            {(style, show) =>
 | 
				
			||||||
                <Animations.animated.div style={style} className={className}>
 | 
					                show && (
 | 
				
			||||||
 | 
					                    <Animations.animated.div style={{ ...style, display: "flex" }}>
 | 
				
			||||||
                        {Sidebar}
 | 
					                        {Sidebar}
 | 
				
			||||||
                    </Animations.animated.div>
 | 
					                    </Animations.animated.div>
 | 
				
			||||||
            )}
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        </Animations.Transition>
 | 
					        </Animations.Transition>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}, { noop: true });
 | 
					}, { noop: true });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
.vc-bf-folder-sidebar [class*="wrapper-"] > [class*="listItem-"]:first-of-type,
 | 
					 | 
				
			||||||
.vc-bf-folder-sidebar [class*="unreadMentionsIndicator"] {
 | 
					 | 
				
			||||||
    display: none;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.vc-bf-folder-sidebar [class*="expandedFolderBackground-"] {
 | 
					 | 
				
			||||||
    background-color: transparent;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.vc-bf-folder-sidebar {
 | 
					 | 
				
			||||||
    display: flex;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.vc-bf-fullscreen {
 | 
					 | 
				
			||||||
    width: 0 !important;
 | 
					 | 
				
			||||||
    visibility: hidden;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,177 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Vencord, a modification for Discord's desktop app
 | 
					 | 
				
			||||||
 * Copyright (c) 2023 Vendicated and contributors
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 * it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
					 | 
				
			||||||
 * (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 * GNU General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "./betterFolders.css";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { definePluginSettings } from "@api/Settings";
 | 
					 | 
				
			||||||
import { Devs } from "@utils/constants";
 | 
					 | 
				
			||||||
import definePlugin, { OptionType } from "@utils/types";
 | 
					 | 
				
			||||||
import { findByPropsLazy, findLazy, findStoreLazy } from "@webpack";
 | 
					 | 
				
			||||||
import { FluxDispatcher } from "@webpack/common";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import FolderSideBar from "./FolderSideBar";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const GuildsTree = findLazy(m => m.prototype?.convertToFolder);
 | 
					 | 
				
			||||||
const GuildFolderStore = findStoreLazy("SortedGuildStore");
 | 
					 | 
				
			||||||
const ExpandedFolderStore = findStoreLazy("ExpandedGuildFolderStore");
 | 
					 | 
				
			||||||
const FolderUtils = findByPropsLazy("move", "toggleGuildFolderExpand");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const settings = definePluginSettings({
 | 
					 | 
				
			||||||
    sidebar: {
 | 
					 | 
				
			||||||
        type: OptionType.BOOLEAN,
 | 
					 | 
				
			||||||
        description: "Display servers from folder on dedicated sidebar",
 | 
					 | 
				
			||||||
        default: true,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    sidebarAnim: {
 | 
					 | 
				
			||||||
        type: OptionType.BOOLEAN,
 | 
					 | 
				
			||||||
        description: "Animate opening the folder sidebar",
 | 
					 | 
				
			||||||
        default: true,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    closeAllFolders: {
 | 
					 | 
				
			||||||
        type: OptionType.BOOLEAN,
 | 
					 | 
				
			||||||
        description: "Close all folders when selecting a server not in a folder",
 | 
					 | 
				
			||||||
        default: false,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    closeAllHomeButton: {
 | 
					 | 
				
			||||||
        type: OptionType.BOOLEAN,
 | 
					 | 
				
			||||||
        description: "Close all folders when clicking on the home button",
 | 
					 | 
				
			||||||
        default: false,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    closeOthers: {
 | 
					 | 
				
			||||||
        type: OptionType.BOOLEAN,
 | 
					 | 
				
			||||||
        description: "Close other folders when opening a folder",
 | 
					 | 
				
			||||||
        default: false,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    forceOpen: {
 | 
					 | 
				
			||||||
        type: OptionType.BOOLEAN,
 | 
					 | 
				
			||||||
        description: "Force a folder to open when switching to a server of that folder",
 | 
					 | 
				
			||||||
        default: false,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default definePlugin({
 | 
					 | 
				
			||||||
    name: "BetterFolders",
 | 
					 | 
				
			||||||
    description: "Shows server folders on dedicated sidebar and adds folder related improvements",
 | 
					 | 
				
			||||||
    authors: [Devs.juby, Devs.AutumnVN],
 | 
					 | 
				
			||||||
    patches: [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            find: '("guildsnav")',
 | 
					 | 
				
			||||||
            predicate: () => settings.store.sidebar,
 | 
					 | 
				
			||||||
            replacement: [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    match: /(\i)\(\){return \i\(\(0,\i\.jsx\)\("div",{className:\i\(\)\.guildSeparator}\)\)}/,
 | 
					 | 
				
			||||||
                    replace: "$&$self.Separator=$1;"
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Folder component patch
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    match: /\i\(\(function\(\i,\i,\i\){var \i=\i\.key;return.+\(\i\)},\i\)}\)\)/,
 | 
					 | 
				
			||||||
                    replace: "arguments[0].bfHideServers?null:$&"
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // BEGIN Guilds component patch
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    match: /(\i)\.themeOverride,(.{15,25}\(function\(\){var \i=)(\i\.\i\.getGuildsTree\(\))/,
 | 
					 | 
				
			||||||
                    replace: "$1.themeOverride,bfPatch=$1.bfGuildFolders,$2bfPatch?$self.getGuildsTree(bfPatch,$3):$3"
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    match: /return(\(0,\i\.jsx\))(\(\i,{)(folderNode:\i,setNodeRef:\i\.setNodeRef,draggable:!0,.+},\i\.id\));case/,
 | 
					 | 
				
			||||||
                    replace: "var bfHideServers=typeof bfPatch==='undefined',folder=$1$2bfHideServers,$3;return !bfHideServers&&arguments[1]?[$1($self.Separator,{}),folder]:folder;case"
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                // END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    match: /\("guildsnav"\);return\(0,\i\.jsx\)\(.{1,6},{navigator:\i,children:\(0,\i\.jsx\)\(/,
 | 
					 | 
				
			||||||
                    replace: "$&$self.Guilds="
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            find: "APPLICATION_LIBRARY,render",
 | 
					 | 
				
			||||||
            predicate: () => settings.store.sidebar,
 | 
					 | 
				
			||||||
            replacement: {
 | 
					 | 
				
			||||||
                match: /(\(0,\i\.jsx\))\(\i\..,{className:\i\(\)\.guilds,themeOverride:\i}\)/,
 | 
					 | 
				
			||||||
                replace: "$&,$1($self.FolderSideBar,{})"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            find: '("guildsnav")',
 | 
					 | 
				
			||||||
            predicate: () => settings.store.closeAllHomeButton,
 | 
					 | 
				
			||||||
            replacement: {
 | 
					 | 
				
			||||||
                match: ",onClick:function(){if(!__OVERLAY__){",
 | 
					 | 
				
			||||||
                replace: "$&$self.closeFolders();"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    settings,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    start() {
 | 
					 | 
				
			||||||
        const getGuildFolder = (id: string) => GuildFolderStore.getGuildFolders().find(f => f.guildIds.includes(id));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        FluxDispatcher.subscribe("CHANNEL_SELECT", this.onSwitch = data => {
 | 
					 | 
				
			||||||
            if (!settings.store.closeAllFolders && !settings.store.forceOpen)
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (this.lastGuildId !== data.guildId) {
 | 
					 | 
				
			||||||
                this.lastGuildId = data.guildId;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const guildFolder = getGuildFolder(data.guildId);
 | 
					 | 
				
			||||||
                if (guildFolder?.folderId) {
 | 
					 | 
				
			||||||
                    if (settings.store.forceOpen && !ExpandedFolderStore.isFolderExpanded(guildFolder.folderId))
 | 
					 | 
				
			||||||
                        FolderUtils.toggleGuildFolderExpand(guildFolder.folderId);
 | 
					 | 
				
			||||||
                } else if (settings.store.closeAllFolders)
 | 
					 | 
				
			||||||
                    this.closeFolders();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        FluxDispatcher.subscribe("TOGGLE_GUILD_FOLDER_EXPAND", this.onToggleFolder = e => {
 | 
					 | 
				
			||||||
            if (settings.store.closeOthers && !this.dispatching)
 | 
					 | 
				
			||||||
                FluxDispatcher.wait(() => {
 | 
					 | 
				
			||||||
                    const expandedFolders = ExpandedFolderStore.getExpandedFolders();
 | 
					 | 
				
			||||||
                    if (expandedFolders.size > 1) {
 | 
					 | 
				
			||||||
                        this.dispatching = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        for (const id of expandedFolders) if (id !== e.folderId)
 | 
					 | 
				
			||||||
                            FolderUtils.toggleGuildFolderExpand(id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        this.dispatching = false;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    stop() {
 | 
					 | 
				
			||||||
        FluxDispatcher.unsubscribe("CHANNEL_SELECT", this.onSwitch);
 | 
					 | 
				
			||||||
        FluxDispatcher.unsubscribe("TOGGLE_GUILD_FOLDER_EXPAND", this.onToggleFolder);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    FolderSideBar,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    getGuildsTree(folders, oldTree) {
 | 
					 | 
				
			||||||
        const tree = new GuildsTree();
 | 
					 | 
				
			||||||
        tree.root.children = oldTree.root.children.filter(e => folders.includes(e.id));
 | 
					 | 
				
			||||||
        tree.nodes = folders.map(id => oldTree.nodes[id]);
 | 
					 | 
				
			||||||
        return tree;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    closeFolders() {
 | 
					 | 
				
			||||||
        for (const id of ExpandedFolderStore.getExpandedFolders())
 | 
					 | 
				
			||||||
            FolderUtils.toggleGuildFolderExpand(id);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
							
								
								
									
										229
									
								
								src/plugins/betterFolders/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								src/plugins/betterFolders/index.tsx
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,229 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Vencord, a modification for Discord's desktop app
 | 
				
			||||||
 | 
					 * Copyright (c) 2023 Vendicated and contributors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { definePluginSettings } from "@api/Settings";
 | 
				
			||||||
 | 
					import { Devs } from "@utils/constants";
 | 
				
			||||||
 | 
					import definePlugin, { OptionType } from "@utils/types";
 | 
				
			||||||
 | 
					import { findByPropsLazy, findStoreLazy } from "@webpack";
 | 
				
			||||||
 | 
					import { FluxDispatcher, i18n } from "@webpack/common";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import FolderSideBar from "./FolderSideBar";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const GuildFolderStore = findStoreLazy("SortedGuildStore");
 | 
				
			||||||
 | 
					export const ExpandedGuildFolderStore = findStoreLazy("ExpandedGuildFolderStore");
 | 
				
			||||||
 | 
					const FolderUtils = findByPropsLazy("move", "toggleGuildFolderExpand");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let lastGuildId = null as string | null;
 | 
				
			||||||
 | 
					let dispatchingFoldersClose = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getGuildFolder(id: string) {
 | 
				
			||||||
 | 
					    return GuildFolderStore.getGuildFolders().find(folder => folder.guildIds.includes(id));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function closeFolders() {
 | 
				
			||||||
 | 
					    for (const id of ExpandedGuildFolderStore.getExpandedFolders())
 | 
				
			||||||
 | 
					        FolderUtils.toggleGuildFolderExpand(id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const settings = definePluginSettings({
 | 
				
			||||||
 | 
					    sidebar: {
 | 
				
			||||||
 | 
					        type: OptionType.BOOLEAN,
 | 
				
			||||||
 | 
					        description: "Display servers from folder on dedicated sidebar",
 | 
				
			||||||
 | 
					        restartNeeded: true,
 | 
				
			||||||
 | 
					        default: true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    sidebarAnim: {
 | 
				
			||||||
 | 
					        type: OptionType.BOOLEAN,
 | 
				
			||||||
 | 
					        description: "Animate opening the folder sidebar",
 | 
				
			||||||
 | 
					        restartNeeded: true,
 | 
				
			||||||
 | 
					        default: true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    closeAllFolders: {
 | 
				
			||||||
 | 
					        type: OptionType.BOOLEAN,
 | 
				
			||||||
 | 
					        description: "Close all folders when selecting a server not in a folder",
 | 
				
			||||||
 | 
					        default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    closeAllHomeButton: {
 | 
				
			||||||
 | 
					        type: OptionType.BOOLEAN,
 | 
				
			||||||
 | 
					        description: "Close all folders when clicking on the home button",
 | 
				
			||||||
 | 
					        restartNeeded: true,
 | 
				
			||||||
 | 
					        default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    closeOthers: {
 | 
				
			||||||
 | 
					        type: OptionType.BOOLEAN,
 | 
				
			||||||
 | 
					        description: "Close other folders when opening a folder",
 | 
				
			||||||
 | 
					        default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    forceOpen: {
 | 
				
			||||||
 | 
					        type: OptionType.BOOLEAN,
 | 
				
			||||||
 | 
					        description: "Force a folder to open when switching to a server of that folder",
 | 
				
			||||||
 | 
					        default: false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default definePlugin({
 | 
				
			||||||
 | 
					    name: "BetterFolders",
 | 
				
			||||||
 | 
					    description: "Shows server folders on dedicated sidebar and adds folder related improvements",
 | 
				
			||||||
 | 
					    authors: [Devs.juby, Devs.AutumnVN, Devs.Nuckyz],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    settings,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    patches: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            find: '("guildsnav")',
 | 
				
			||||||
 | 
					            predicate: () => settings.store.sidebar,
 | 
				
			||||||
 | 
					            replacement: [
 | 
				
			||||||
 | 
					                // Create the isBetterFolders variable in the GuildsBar component
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /(?<=let{disableAppDownload:\i=\i\.isPlatformEmbedded,isOverlay:.+?)(?=}=\i,)/,
 | 
				
			||||||
 | 
					                    replace: ",isBetterFolders"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // If we are rendering the Better Folders sidebar, we filter out everything but the servers and folders from the GuildsBar Guild List children
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /lastTargetNode:\i\[\i\.length-1\].+?Fragment.+?\]}\)\]/,
 | 
				
			||||||
 | 
					                    replace: '$&.filter($self.makeGuildsBarGuildListFilter(typeof isBetterFolders!=="undefined"?isBetterFolders:false))'
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // If we are rendering the Better Folders sidebar, we filter out everything but the scroller for the guild list from the GuildsBar Tree children
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /unreadMentionsIndicatorBottom,barClassName.+?}\)\]/,
 | 
				
			||||||
 | 
					                    replace: '$&.filter($self.makeGuildsBarTreeFilter(typeof isBetterFolders!=="undefined"?isBetterFolders:false))'
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // Export the isBetterFolders variable to the folders component
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /(?<=\.Messages\.SERVERS.+?switch\((\i)\.type\){case \i\.\i\.FOLDER:.+?folderNode:\i,)/,
 | 
				
			||||||
 | 
					                    replace: 'isBetterFolders:typeof isBetterFolders!=="undefined"?isBetterFolders:false,'
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // Avoid rendering servers that are not in folders in the Better Folders sidebar
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /(?<=\.Messages\.SERVERS.+?switch\((\i)\.type\){case \i\.\i\.FOLDER:.+?GUILD:)/,
 | 
				
			||||||
 | 
					                    replace: 'if((typeof isBetterFolders!=="undefined"?isBetterFolders:false)&&$1.parentId==null)return null;'
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            find: ".FOLDER_ITEM_GUILD_ICON_MARGIN);",
 | 
				
			||||||
 | 
					            replacement: [
 | 
				
			||||||
 | 
					                // Create the isBetterFolders variable in the nested folders component (the parent exports all the props so we don't have to patch it)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /(?<=let{folderNode:\i,setNodeRef:\i,)/,
 | 
				
			||||||
 | 
					                    replace: "isBetterFolders,"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // If we are rendering the normal GuildsBar sidebar, we make Discord think the folder is always collapsed to show better icons (the mini guild icons) and avoid transitions
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /(?<=let{folderNode:\i,setNodeRef:\i,.+?expanded:(\i).+?;)(?=let)/,
 | 
				
			||||||
 | 
					                    replace: '$1=(typeof isBetterFolders!=="undefined"?isBetterFolders:false)?$1:false;'
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // If we are rendering the Better Folders sidebar, we filter out folders that are not expanded
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /(?=return\(0,\i.\i\)\("div")(?<=selected:\i,expanded:(\i),.+?)/,
 | 
				
			||||||
 | 
					                    replace: (_, expanded) => `if((typeof isBetterFolders!=="undefined"?isBetterFolders:false)&&!${expanded})return null;`
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // This code is required for the plugin to work, but we don't need it right now because we are making Discord think the folder is always collapsed
 | 
				
			||||||
 | 
					                // If we no longer want to make Discord think the folder is always collapsed, we can use this code for the plugin to work
 | 
				
			||||||
 | 
					                // One reason to no longer want that is to make better icons (the mini guild icons) no longer show
 | 
				
			||||||
 | 
					                /* // Disable expanding and collapsing folders transition in the normal GuildsBar sidebar
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /(?<=\.Messages\.SERVER_FOLDER_PLACEHOLDER.+?useTransition\)\()/,
 | 
				
			||||||
 | 
					                    replace: '(typeof isBetterFolders!=="undefined"?isBetterFolders:false)&&'
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // If we are rendering the normal GuildsBar sidebar, we avoid rendering guilds from folders that are expanded
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    match: /expandedFolderBackground,.+?,(?=\i\(\(\i,\i,\i\)=>{let{key.{0,45}ul)(?<=selected:\i,expanded:(\i),.+?)/,
 | 
				
			||||||
 | 
					                    replace: (m, expanded) => `${m}((typeof isBetterFolders!=="undefined"?isBetterFolders:false)||!${expanded})&&`
 | 
				
			||||||
 | 
					                } */
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            find: "APPLICATION_LIBRARY,render",
 | 
				
			||||||
 | 
					            predicate: () => settings.store.sidebar,
 | 
				
			||||||
 | 
					            replacement: {
 | 
				
			||||||
 | 
					                // Render the Better Folders sidebar
 | 
				
			||||||
 | 
					                match: /(?<=({className:\i\.guilds,themeOverride:\i})\))/,
 | 
				
			||||||
 | 
					                replace: ",$self.FolderSideBar($1)"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            find: ".Messages.DISCODO_DISABLED",
 | 
				
			||||||
 | 
					            predicate: () => settings.store.closeAllHomeButton,
 | 
				
			||||||
 | 
					            replacement: {
 | 
				
			||||||
 | 
					                // Close all folders when clicking the home button
 | 
				
			||||||
 | 
					                match: /(?<=onClick:\(\)=>{)(?=.{0,200}"discodo")/,
 | 
				
			||||||
 | 
					                replace: "$self.closeFolders();"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flux: {
 | 
				
			||||||
 | 
					        CHANNEL_SELECT(data) {
 | 
				
			||||||
 | 
					            if (!settings.store.closeAllFolders && !settings.store.forceOpen)
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (lastGuildId !== data.guildId) {
 | 
				
			||||||
 | 
					                lastGuildId = data.guildId;
 | 
				
			||||||
 | 
					                const guildFolder = getGuildFolder(data.guildId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (guildFolder?.folderId) {
 | 
				
			||||||
 | 
					                    if (settings.store.forceOpen && !ExpandedGuildFolderStore.isFolderExpanded(guildFolder.folderId)) {
 | 
				
			||||||
 | 
					                        FolderUtils.toggleGuildFolderExpand(guildFolder.folderId);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else if (settings.store.closeAllFolders) {
 | 
				
			||||||
 | 
					                    closeFolders();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TOGGLE_GUILD_FOLDER_EXPAND(data) {
 | 
				
			||||||
 | 
					            if (settings.store.closeOthers && !dispatchingFoldersClose) {
 | 
				
			||||||
 | 
					                dispatchingFoldersClose = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                FluxDispatcher.wait(() => {
 | 
				
			||||||
 | 
					                    const expandedFolders = ExpandedGuildFolderStore.getExpandedFolders();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (expandedFolders.size > 1) {
 | 
				
			||||||
 | 
					                        for (const id of expandedFolders) if (id !== data.folderId)
 | 
				
			||||||
 | 
					                            FolderUtils.toggleGuildFolderExpand(id);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    dispatchingFoldersClose = false;
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    makeGuildsBarGuildListFilter(isBetterFolders: boolean) {
 | 
				
			||||||
 | 
					        return child => {
 | 
				
			||||||
 | 
					            if (isBetterFolders) {
 | 
				
			||||||
 | 
					                return child?.props?.["aria-label"] === i18n.Messages.SERVERS;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    makeGuildsBarTreeFilter(isBetterFolders: boolean) {
 | 
				
			||||||
 | 
					        return child => {
 | 
				
			||||||
 | 
					            if (isBetterFolders) {
 | 
				
			||||||
 | 
					                return "onScroll" in child.props;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FolderSideBar: guildsBarProps => <FolderSideBar {...guildsBarProps} />,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    closeFolders
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
		Reference in a new issue