diff --git a/plugins/server-drawer/src/patches/hideGuildsBar.tsx b/plugins/server-drawer/src/patches/hideGuildsBar.tsx index 2b5babc..17e57af 100644 --- a/plugins/server-drawer/src/patches/hideGuildsBar.tsx +++ b/plugins/server-drawer/src/patches/hideGuildsBar.tsx @@ -1,94 +1,78 @@ import React from "react"; -import { Pressable, Image, View } from "react-native"; -import { find, findByName, findByProps } from "@vendetta/metro"; -import { getAssetIDByName } from "@vendetta/ui/assets"; -import { registerIntercept } from "./createElementIntercept"; +import { View } from "react-native"; +import { registerPropsTransform, registerTypeDetector, registerIntercept } from "./createElementIntercept"; const TAG = "[ServerDrawer]"; +const SD_NOTHING_TEST_ID = "ServerDrawerNothing"; -const ChatIcon = getAssetIDByName("ChatIcon"); -const Haptic = findByProps("triggerHapticFeedback", "HapticFeedbackTypes"); -const ChannelActions = findByProps("selectPrivateChannel"); -const SelectedChannelStore = findByName("SelectedChannelStore"); -const FluxStores = findByProps("useStateFromStores"); -const useStateFromStores = FluxStores?.useStateFromStores; -const GuildStore = findByProps("getGuildId"); -const colors = findByProps("colors", "unsafe_rawColors")?.colors; -const Routes = findByProps("ME"); -const ME = Routes?.ME ?? "/channels/@me"; +function Nothing() { + return React.createElement(View, { + style: { + display: "none", + width: 0, + minWidth: 0, + maxWidth: 0, + flexGrow: 0, + flexShrink: 0, + flexBasis: 0, + margin: 0, + padding: 0, + borderWidth: 0, + overflow: "hidden", + }, + }); +} -function openDms() { - Haptic?.triggerHapticFeedback(Haptic.HapticFeedbackTypes.SOFT); - if (ChannelActions?.selectPrivateChannel) { - const lastChannelId = SelectedChannelStore?.getLastSelectedChannelId?.(); - ChannelActions.selectPrivateChannel(lastChannelId); +// The parent creates GuildsBar via its outer React.memo wrapper object, which has no own +// .name/.displayName at all - those only exist on the memo's inner function, at +// type.type.name/type.type.displayName. +function isGuildsBar(type: any): boolean { + return type?.name === "GuildsBar" || type?.displayName === "GuildsBar" || + type?.type?.name === "GuildsBar" || type?.type?.displayName === "GuildsBar"; +} + +function hasChildWithTestID(children: any, rest: any[], testID: string): boolean { + const inspect = (child: any) => child != null && typeof child === "object" && child.props?.testID === testID; + if (children != null) { + if (Array.isArray(children)) { if (children.some(inspect)) return true; } + else if (inspect(children)) return true; } -} - -function useIsInDms(): boolean { - try { - return GuildStore ? useStateFromStores([GuildStore], () => { - const guildId = GuildStore?.getGuildId?.(); - return guildId == null || guildId === ME; - }) : false; - } catch { return false; } -} - -function DmsGuildIcon() { - const selected = useIsInDms(); - - const iconColor = selected - ? (colors?.WHITE ?? "#fff") - : (colors?.INTERACTIVE_NORMAL ?? "#80848e"); - - return ( - - {selected ? ( - - ) : null} - - - ); -} - -function findGuildsBar(): any { - const byName = findByName("GuildsBar"); - if (byName) return { default: byName }; - - let mod = find((m) => { - try { return m?.default?.type?.name === "GuildsBar"; } catch { return false; } - }); - if (mod?.default) return mod; - - mod = find((m) => { - try { return m?.default?.displayName === "GuildsBar"; } catch { return false; } - }); - if (mod?.default) return mod; - - return null; + for (const child of rest) if (inspect(child)) return true; + return false; } export function patchHideGuildsBar(cleanups: (() => void)[]): boolean { - const mod = findGuildsBar(); - if (!mod?.default) { - console.log(TAG, "WARN: GuildsBar not found"); - return false; - } - const orig = mod.default; + // Rendering GuildsBar as nothing alone still leaves its space reserved - the immediate parent + // carries an explicit width in its own style, so display: none on the child doesn't reclaim + // it. This zeroes the parent wrapper too once it spots the hidden marker as a child. + registerPropsTransform( + (props: any, _type: any, rest: any[]) => + hasChildWithTestID(props?.children, rest, SD_NOTHING_TEST_ID), + (props: any) => ({ + ...props, + style: [ + props?.style, + { + display: "none", + width: 0, + minWidth: 0, + maxWidth: 0, + flexGrow: 0, + flexShrink: 0, + flexBasis: 0, + margin: 0, + padding: 0, + borderWidth: 0, + overflow: "hidden", + }, + ], + }), + ); - registerIntercept(orig, DmsGuildIcon); - - mod.default = function DmsGuildsBar() { - return React.createElement(DmsGuildIcon); - }; - mod.default.displayName = "GuildsBar"; - cleanups.push(() => { mod.default = orig; }); + registerTypeDetector("ServerDrawer.HideGuildsBar", isGuildsBar, (realGuildsBar) => { + registerIntercept(realGuildsBar, Nothing, { testID: SD_NOTHING_TEST_ID }, { collapseAncestors: 6 }); + console.log(TAG, "PATCH: found a real GuildsBar reference, now rendering nothing"); + }, { persistent: true }); + console.log(TAG, "PATCH: watching for the real GuildsBar to appear"); return true; }