diff --git a/plugins/you-bar-plus/src/patches/youBarButtons.tsx b/plugins/you-bar-plus/src/patches/youBarButtons.tsx index 3df059a..ddcdc3c 100644 --- a/plugins/you-bar-plus/src/patches/youBarButtons.tsx +++ b/plugins/you-bar-plus/src/patches/youBarButtons.tsx @@ -1,21 +1,18 @@ -import { findByProps, findByName } from "@vendetta/metro"; +import { findByProps, findByTypeName, findByName } from "@vendetta/metro"; import { React } from "@vendetta/metro/common"; +import { instead } from "@vendetta/patcher"; import { storage } from "@vendetta/plugin"; import { getAssetIDByName } from "@vendetta/ui/assets"; -import { registerTypeDetector, registerIntercept, registerPropsTransform, patchCreateElement } from "@shared/lib/createElementIntercept"; +import { registerPropsTransform, patchCreateElement } from "@shared/lib/createElementIntercept"; import NotificationCenter from "../ui/NotificationCenter"; // Retry logic lives one level up in index.ts, calling this repeatedly until it succeeds - keep // this function itself simple. export let updateYouBar = () => {}; -// findByTypeName + instead("type", ...) used to patch this, but that mutates whatever object -// Metro's search hands back - which isn't reliably the same reference Discord's own render call -// site reads from in this bundle (confirmed live: the property write didn't stick, and a fresh -// findByTypeName call moments later returned undefined). registerTypeDetector instead captures -// the exact type value at the actual createElement/jsx call site, so there's no reference -// mismatch to go stale. -export default function patchYouBarButtons(): () => void { +/** Returns null (not undefined) when YouBarNotificationsButton isn't registered in Metro yet, so a caller can tell "not ready" apart from "patched, here's the unpatch fn". */ +export default function patchYouBarButtons(): (() => void) | null { + const YouBarNotificationsButton = findByTypeName("YouBarNotificationsButton"); const userSettingsAction = findByProps("openUserSettings"); const transitionModule = findByProps("transitionToGuild"); @@ -28,6 +25,8 @@ export default function patchYouBarButtons(): () => void { const SettingsIcon = getAssetIDByName("SettingsIcon"); const ChatIcon = getAssetIDByName("ChatIcon"); + if (!YouBarNotificationsButton) return null; + const openInbox = () => { if (!Navigator || !Navigation?.push) { console.error("[YouBar+] Inbox: Navigator not available"); @@ -48,65 +47,59 @@ export default function patchYouBarButtons(): () => void { )); }; - const cleanups: (() => void)[] = []; - patchCreateElement(cleanups); - // The native bell is one of four sibling buttons YouBarNotificationsButton renders - the // other three are unrelated icon buttons with raw numeric asset ids. accessibilityLabel is // the only reliable way to pick the real bell out (confirmed live via the fiber tree). + const elementCleanups: (() => void)[] = []; + patchCreateElement(elementCleanups); registerPropsTransform( (props) => !!storage.showInboxButton && props?.accessibilityLabel === "Notifications", (props) => ({ ...props, onPress: openInbox }), ); - registerTypeDetector( - "you-bar-plus-notifications-button", - (type) => typeof type === "function" && type.name === "YouBarNotificationsButton", - (YouBarNotificationsButton: any) => { - const PatchedYouBarNotificationsButton = (props: any) => { - const [, forceUpdate] = React.useReducer((x: number) => ~x, 0); - updateYouBar = () => forceUpdate(); + const unpatchType = instead("type", YouBarNotificationsButton, (args: any[], OriginalRender: (...a: any[]) => any) => { + const [, forceUpdate] = React.useReducer((x: number) => ~x, 0); - const res = YouBarNotificationsButton(props); + updateYouBar = () => forceUpdate(); - if (!res?.props?.children) return res; + const res = OriginalRender(...args); - const IconButton = res.props.children.type; - const originalProps = res.props.children.props; + if (!res?.props?.children) return res; - return ( - - {storage.showDMButton && ( - { - transitionModule?.transitionToGuild?.("@me"); - }} - /> - )} + const IconButton = res.props.children.type; + const originalProps = res.props.children.props; - {storage.showSettingsButton && ( - { - userSettingsAction?.openUserSettings?.(); - }} - /> - )} + return ( + + {storage.showDMButton && ( + { + transitionModule?.transitionToGuild?.("@me"); + }} + /> + )} - {res} - - ); - }; + {storage.showSettingsButton && ( + { + userSettingsAction?.openUserSettings?.(); + }} + /> + )} - registerIntercept(YouBarNotificationsButton, PatchedYouBarNotificationsButton); - }, - { persistent: true }, - ); + {res} + + ); + }); - return () => cleanups.forEach((fn) => fn()); + return () => { + unpatchType(); + elementCleanups.forEach((fn) => fn()); + }; }