Fix betterfolders nestedFolders navigation bug (#1014)
* Fix betterfolders nestedFolders navigation bug * Fix BetterFolders nested navigation * tidy up patches * setting --------- Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
This commit is contained in:
parent
393eff5a17
commit
7b6934fde7
2 changed files with 142 additions and 30 deletions
|
|
@ -21,19 +21,35 @@ import { findComponentByCodeLazy } from "@webpack";
|
|||
import { Animations, ChannelRTCStore, useStateFromStores } from "@webpack/common";
|
||||
import type { CSSProperties } from "react";
|
||||
|
||||
import { ExpandedGuildFolderStore, settings, SortedGuildStore } from ".";
|
||||
import { ExpandedGuildFolderStore, getExpandedFolderIdSet, getParentFolderId, settings, SortedGuildStore } from ".";
|
||||
|
||||
const GuildsBar = findComponentByCodeLazy('("guildsnav")');
|
||||
|
||||
type GuildTreeNode = {
|
||||
id?: string | number;
|
||||
type?: string;
|
||||
children?: GuildTreeNode[];
|
||||
};
|
||||
|
||||
function getExpandedFolderIds() {
|
||||
const expandedFolders = ExpandedGuildFolderStore.getExpandedFolders();
|
||||
const folders = SortedGuildStore.getGuildFolders();
|
||||
const expandedFolders = getExpandedFolderIdSet();
|
||||
const tree = SortedGuildStore.getGuildsTree();
|
||||
const expandedFolderIds = new Set<number>();
|
||||
const stack = [...(tree?.root?.children ?? [])];
|
||||
|
||||
const expandedFolderIds = new Set<string>();
|
||||
while (stack.length) {
|
||||
const node = stack.pop();
|
||||
if (!node) continue;
|
||||
|
||||
for (const folder of folders) {
|
||||
if (expandedFolders.has(folder.folderId) && folder.guildIds?.length) {
|
||||
expandedFolderIds.add(folder.folderId);
|
||||
if (node.type === "folder") {
|
||||
const folderId = node.id;
|
||||
if (folderId != null && expandedFolders.has(Number(folderId))) {
|
||||
expandedFolderIds.add(Number(folderId));
|
||||
}
|
||||
}
|
||||
|
||||
if (node.children?.length) {
|
||||
stack.push(...node.children);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +68,11 @@ export default ErrorBoundary.wrap(guildsBarProps => {
|
|||
/>
|
||||
);
|
||||
|
||||
const visible = !!expandedFolderIds.size;
|
||||
const visible = SortedGuildStore.getGuildFolders().some(folder =>
|
||||
folder.guildIds?.length &&
|
||||
expandedFolderIds.has(Number(folder.folderId)) &&
|
||||
getParentFolderId(folder.folderId) == null
|
||||
);
|
||||
const guilds = document.querySelector(guildsBarProps.className.split(" ").map(c => `.${c}`).join(""));
|
||||
|
||||
// We need to display none if we are in fullscreen. Yes this seems horrible doing with css, but it's literally how Discord does it.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
import "./style.css";
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { Devs, EquicordDevs } from "@utils/constants";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import type { GuildFolder } from "@vencord/discord-types";
|
||||
|
|
@ -64,32 +64,86 @@ type FolderMentionProps = {
|
|||
export const ExpandedGuildFolderStore = findStoreLazy("ExpandedGuildFolderStore");
|
||||
export const SortedGuildStore = findStoreLazy("SortedGuildStore");
|
||||
const FolderUtils = findByPropsLazy("move", "toggleGuildFolderExpand");
|
||||
const FolderItem = findComponentByCodeLazy("FolderItem", "onExpandCollapse", "folderButtonSize");
|
||||
const FolderItem = findComponentByCodeLazy("folderButtonContent", "onHoverChange", "treeItemProps");
|
||||
|
||||
const MAX_TREE_FILTER_DEPTH = 1000;
|
||||
let dispatchingFoldersClose = false;
|
||||
let pendingNavigationGuildId: string | null | undefined;
|
||||
let pendingNavigationCloseServerFolder = false;
|
||||
let navigationExpandTimeout: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
function getGuildFolder(id: string) {
|
||||
return SortedGuildStore.getGuildFolders().find((folder: GuildFolder) => folder.guildIds.includes(id));
|
||||
}
|
||||
|
||||
function expandGuildNavigationPath(guildId: string | null | undefined) {
|
||||
if (!guildId || guildId === "@me") return;
|
||||
function getGuildNavigationPathTargets(guildId: string | null | undefined): string[] {
|
||||
if (!guildId || guildId === "@me") return [];
|
||||
|
||||
for (const folderId of getGuildNavigationExpandTargets(
|
||||
return getGuildNavigationExpandTargets(
|
||||
getNestedFolderMap(),
|
||||
SortedGuildStore.getGuildFolders(),
|
||||
guildId,
|
||||
ExpandedGuildFolderStore.getExpandedFolders()
|
||||
)) {
|
||||
if (!ExpandedGuildFolderStore.isFolderExpanded(folderId)) {
|
||||
FolderUtils.toggleGuildFolderExpand(folderId);
|
||||
);
|
||||
}
|
||||
|
||||
export function getExpandedFolderIdSet() {
|
||||
return new Set(Array.from(ExpandedGuildFolderStore.getExpandedFolders(), id => Number(id)));
|
||||
}
|
||||
|
||||
function isFolderExpanded(folderId: string | number) {
|
||||
return getExpandedFolderIdSet().has(Number(folderId));
|
||||
}
|
||||
|
||||
function expandGuildNavigationPathNow(guildId: string | null | undefined) {
|
||||
for (const folderId of getGuildNavigationPathTargets(guildId)) {
|
||||
const numericFolderId = Number(folderId);
|
||||
if (!isFolderExpanded(numericFolderId)) {
|
||||
FolderUtils.toggleGuildFolderExpand(numericFolderId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function flushGuildNavigationPath() {
|
||||
navigationExpandTimeout = undefined;
|
||||
|
||||
const guildId = pendingNavigationGuildId;
|
||||
const shouldCloseServerFolder = pendingNavigationCloseServerFolder;
|
||||
pendingNavigationGuildId = undefined;
|
||||
pendingNavigationCloseServerFolder = false;
|
||||
|
||||
if (!guildId || guildId === "@me") return;
|
||||
|
||||
const folderIds = getGuildNavigationPathTargets(guildId);
|
||||
const guildFolder = getGuildFolder(guildId);
|
||||
const folderId = guildFolder?.folderId;
|
||||
const shouldCloseTargetFolder = shouldCloseServerFolder
|
||||
&& folderId != null
|
||||
&& folderIds.length === 0
|
||||
&& isFolderExpanded(folderId);
|
||||
|
||||
expandGuildNavigationPathNow(guildId);
|
||||
|
||||
if (shouldCloseTargetFolder) {
|
||||
FolderUtils.toggleGuildFolderExpand(folderId);
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleGuildNavigationPath(guildId: string | null | undefined, closeServerFolder = false) {
|
||||
const isSamePendingGuild = pendingNavigationGuildId === guildId;
|
||||
|
||||
pendingNavigationGuildId = guildId;
|
||||
pendingNavigationCloseServerFolder = isSamePendingGuild
|
||||
? pendingNavigationCloseServerFolder || closeServerFolder
|
||||
: closeServerFolder;
|
||||
|
||||
if (navigationExpandTimeout != null) return;
|
||||
|
||||
navigationExpandTimeout = setTimeout(flushGuildNavigationPath, 0);
|
||||
}
|
||||
|
||||
function closeFolders() {
|
||||
for (const id of ExpandedGuildFolderStore.getExpandedFolders())
|
||||
for (const id of getExpandedFolderIdSet())
|
||||
FolderUtils.toggleGuildFolderExpand(id);
|
||||
}
|
||||
|
||||
|
|
@ -131,6 +185,8 @@ function filterTreeWithTargetNode(children: any, predicate: (node: any) => boole
|
|||
}
|
||||
|
||||
function getNestedFolderMap(): Record<string, string> {
|
||||
if (!settings.store.enableNestedFolders) return {};
|
||||
|
||||
const nestedFolders = settings.store.nestedFolders ?? {};
|
||||
const validFolderIds = new Set<string>(
|
||||
SortedGuildStore.getGuildFolders()
|
||||
|
|
@ -227,6 +283,11 @@ export const settings = definePluginSettings({
|
|||
description: "Force a folder to open when switching to a server of that folder",
|
||||
default: false
|
||||
},
|
||||
enableNestedFolders: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Allow nesting folders inside other folders by dragging.",
|
||||
default: true
|
||||
},
|
||||
keepIcons: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Keep showing guild icons in the primary guild bar folder when it's open in the BetterFolders sidebar",
|
||||
|
|
@ -255,12 +316,20 @@ export default definePlugin({
|
|||
name: "BetterFolders",
|
||||
description: "Shows server folders on dedicated sidebar and adds folder related improvements",
|
||||
tags: ["Organisation", "Servers", "Appearance"],
|
||||
authors: [Devs.juby, Devs.AutumnVN, Devs.Nuckyz],
|
||||
authors: [Devs.juby, Devs.AutumnVN, Devs.Nuckyz, EquicordDevs.justjxke],
|
||||
isModified: true,
|
||||
settings,
|
||||
start() {
|
||||
settings.store.nestedFolders = getNestedFolderMap();
|
||||
},
|
||||
stop() {
|
||||
if (navigationExpandTimeout != null) {
|
||||
clearTimeout(navigationExpandTimeout);
|
||||
navigationExpandTimeout = undefined;
|
||||
}
|
||||
pendingNavigationGuildId = undefined;
|
||||
pendingNavigationCloseServerFolder = false;
|
||||
},
|
||||
|
||||
patches: [
|
||||
{
|
||||
|
|
@ -446,26 +515,35 @@ export default definePlugin({
|
|||
match: /return \i\.type!==\i\.\i\.GUILD/,
|
||||
replace: "return $self.renderFolderChild(arguments[0],arguments[1],arguments[2])"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "`transitionToGuild - Transitioning to",
|
||||
replacement: {
|
||||
match: /(`transitionToGuild - Transitioning to .{0,80}?guildId:\i,channelId:\i,messageId:\i.{0,40}?`\),)/,
|
||||
replace: "$&$self.handleGuildNavigation(arguments[0]),"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "`transitionTo - Transitioning to",
|
||||
replacement: {
|
||||
match: /`transitionTo - Transitioning to \$\{\i\}`\);/,
|
||||
replace: "$&$self.handleRouteNavigation(arguments[0]);"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
flux: {
|
||||
GUILD_SELECT({ guildId }: { guildId: string | null; }) {
|
||||
if (guildId == null) return;
|
||||
expandGuildNavigationPath(guildId);
|
||||
scheduleGuildNavigationPath(guildId);
|
||||
},
|
||||
|
||||
CHANNEL_SELECT(data) {
|
||||
const guildFolder = getGuildFolder(data.guildId);
|
||||
|
||||
if (guildFolder?.folderId) {
|
||||
expandGuildNavigationPath(data.guildId);
|
||||
|
||||
if (settings.store.forceOpen && !ExpandedGuildFolderStore.isFolderExpanded(guildFolder.folderId)) {
|
||||
FolderUtils.toggleGuildFolderExpand(guildFolder.folderId);
|
||||
}
|
||||
if (settings.store.closeServerFolder && ExpandedGuildFolderStore.isFolderExpanded(guildFolder.folderId)) {
|
||||
FolderUtils.toggleGuildFolderExpand(guildFolder.folderId);
|
||||
if (settings.store.forceOpen || settings.store.closeServerFolder) {
|
||||
scheduleGuildNavigationPath(data.guildId, settings.store.closeServerFolder);
|
||||
}
|
||||
} else if (settings.store.closeAllFolders) {
|
||||
closeFolders();
|
||||
|
|
@ -500,6 +578,19 @@ export default definePlugin({
|
|||
|
||||
FolderSideBar,
|
||||
closeFolders,
|
||||
handleGuildNavigation(guildId: string | null | undefined) {
|
||||
expandGuildNavigationPathNow(guildId);
|
||||
},
|
||||
handleRouteNavigation(route: unknown) {
|
||||
if (typeof route !== "string") return;
|
||||
|
||||
const guildId = route.match(/^\/channels\/([^/]+)/)?.[1];
|
||||
if (!guildId) return;
|
||||
|
||||
if (!settings.store.forceOpen && !settings.store.closeServerFolder) return;
|
||||
|
||||
expandGuildNavigationPathNow(guildId);
|
||||
},
|
||||
getGuildMentionCount(guildId: string): number {
|
||||
const mentionChannelIds = ReadStateStore.getMentionChannelIds() ?? [];
|
||||
let count = 0;
|
||||
|
|
@ -619,8 +710,6 @@ export default definePlugin({
|
|||
props: FolderRenderProps | undefined,
|
||||
baseClassName: string
|
||||
): string {
|
||||
if (props?.isBetterFolders) return baseClassName;
|
||||
|
||||
const folderNode = props?.folderNode;
|
||||
if (folderNode == null) return baseClassName;
|
||||
|
||||
|
|
@ -651,6 +740,7 @@ export default definePlugin({
|
|||
|
||||
handleFolderDrop(dragItem: FolderDragItem, targetNode: GuildTreeNode, _moveToBelow: boolean, isCombine: boolean): boolean {
|
||||
if (dragItem.type !== "folder") return false;
|
||||
if (!settings.store.enableNestedFolders) return false;
|
||||
|
||||
if (targetNode.type === "folder") {
|
||||
const childId = dragItem.nodeId?.toString();
|
||||
|
|
@ -678,13 +768,14 @@ export default definePlugin({
|
|||
|
||||
shouldShowCombineTarget(noCombine: boolean, targetNode: GuildTreeNode): boolean {
|
||||
if (noCombine) return false;
|
||||
if (!settings.store.enableNestedFolders) return targetNode.parentId == null;
|
||||
return targetNode.parentId == null || targetNode.type === "folder";
|
||||
},
|
||||
|
||||
getFolderAcceptTypes(targetNode: GuildTreeNode): string[] {
|
||||
const GUILD = "guild";
|
||||
const FOLDER = "folder";
|
||||
if (targetNode?.type === FOLDER) return [GUILD, FOLDER];
|
||||
if (settings.store.enableNestedFolders && targetNode?.type === FOLDER) return [GUILD, FOLDER];
|
||||
return [GUILD];
|
||||
},
|
||||
|
||||
|
|
@ -692,6 +783,7 @@ export default definePlugin({
|
|||
if (dragItem.nodeId === targetNode.id) return false;
|
||||
|
||||
if (dragItem.type === "folder" && targetNode.type === "folder") {
|
||||
if (!settings.store.enableNestedFolders) return false;
|
||||
return !hasParentInChain(targetNode.id?.toString(), dragItem.nodeId?.toString());
|
||||
}
|
||||
|
||||
|
|
@ -715,7 +807,7 @@ export default definePlugin({
|
|||
|
||||
if (
|
||||
!isBetterFolders ||
|
||||
node.type === "folder" && expandedFolderIds?.has(node.id) ||
|
||||
node.type === "folder" && (node.isBetterFoldersNested === true || expandedFolderIds?.has(node.id)) ||
|
||||
node.type === "guild" && node.parentId != null && expandedFolderIds?.has(node.parentId)
|
||||
) {
|
||||
return originalComponent();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue