YouBar+: reintroduce the retry loop only, confirmed necessary on-device

This commit is contained in:
everestmcarthur 2026-08-01 20:49:38 -04:00
parent 538c7b8acc
commit abb019ae6f
3 changed files with 42 additions and 19 deletions

View file

@ -1,6 +1,6 @@
{ {
"name": "YouBar+", "name": "YouBar+",
"description": "Adds Settings and DM buttons to the YouBar. (May require a restart after enabling.)", "description": "Adds Settings and DM buttons to the YouBar. Toggling while Discord's already running may need one reload to take effect.",
"authors": [ "authors": [
{ "name": "everestmcarthur" }, { "name": "everestmcarthur" },
{ "name": "Purple_Ξye™" } { "name": "Purple_Ξye™" }

View file

@ -1,29 +1,50 @@
import { findByProps, findByTypeName } from "@vendetta/metro"; import { findByProps } from "@vendetta/metro";
import { React } from "@vendetta/metro/common"; import { React } from "@vendetta/metro/common";
import { instead } from "@vendetta/patcher"; import { instead } from "@vendetta/patcher";
import { storage } from "@vendetta/plugin"; import { storage } from "@vendetta/plugin";
import { getAssetIDByName } from "@vendetta/ui/assets"; import { getAssetIDByName } from "@vendetta/ui/assets";
import { waitFor } from "@shared/lib/waitFor";
import { rawFindByTypeName } from "@shared/lib/rawFind";
// Reset to Purple-EyeZ's original upstream logic, verbatim aside from the import path
// (@revenge-mod/metro -> @vendetta/metro, since this repo only has the vendetta-compat alias
// configured) - no retry loop, no raw* passive finder, no forced re-render. Every one of those
// layers added this session was meant to fix "sometimes needs a reload," but on the actual device
// buttons stopped appearing at all, even after ten restarts - worse than upstream's own documented
// "requires a restart" baseline. Resetting to the exact known-quantity upstream version first, to
// find out whether the *added* logic was the actual problem or something else in this port
// (a renamed lookup, a build difference) was always broken and just wasn't visible under the retry
// logic's own try/catch swallowing it.
export let updateYouBar = () => {}; export let updateYouBar = () => {};
/**
* Confirmed on-device, not just theorized: the exact upstream one-shot `findByTypeName` lookup at
* onLoad is genuinely non-deterministic across app boots - it found the component on one reload and
* came up empty on the very next one, same code, same device, nothing else changed. Metro doesn't
* guarantee YouBarNotificationsButton's module has been required by the time a plugin's onLoad
* runs; which reload wins that race varies. waitFor keeps checking after a first miss instead of
* giving up for the whole session - and it has to use the passive rawFindByTypeName specifically,
* because Revenge's own findByTypeName permanently caches a negative result and never rescans,
* which would make retrying it pointless.
*
* Deliberately NOT reintroducing anything beyond this. The force-render attempts tried earlier this
* session (walking React's DevTools fiber registry, nudging live navigation state) were aimed at a
* different problem - buttons not appearing on a hot toggle without ever restarting - and one of
* them caused a real regression. This only fixes the reload-timing race; "no restart ever needed"
* is a separate, deliberately deferred piece of work.
*/
export default function patchYouBarButtons(): () => void { export default function patchYouBarButtons(): () => void {
const YouBarNotificationsButton = findByTypeName("YouBarNotificationsButton"); let unpatch: () => void = () => {};
const handle = waitFor(
() => rawFindByTypeName("YouBarNotificationsButton"),
(YouBarNotificationsButton) => {
unpatch = applyButtonPatch(YouBarNotificationsButton);
}
);
return () => {
handle.cancel();
unpatch();
};
}
function applyButtonPatch(YouBarNotificationsButton: any): () => void {
const userSettingsAction = findByProps("openUserSettings"); const userSettingsAction = findByProps("openUserSettings");
const transitionModule = findByProps("transitionToGuild"); const transitionModule = findByProps("transitionToGuild");
const SettingsIcon = getAssetIDByName("SettingsIcon");
const ChatIcon = getAssetIDByName("ChatIcon"); const ChatIcon = getAssetIDByName("ChatIcon");
const SettingsIcon = getAssetIDByName("SettingsIcon");
if (!YouBarNotificationsButton) return () => {};
return instead("type", YouBarNotificationsButton, (args: any[], OriginalRender: (...a: any[]) => any) => { return instead("type", YouBarNotificationsButton, (args: any[], OriginalRender: (...a: any[]) => any) => {
const [, forceUpdate] = React.useReducer((x: number) => ~x, 0); const [, forceUpdate] = React.useReducer((x: number) => ~x, 0);

View file

@ -17,9 +17,11 @@ export default function Settings() {
return ( return (
<SettingsScaffold> <SettingsScaffold>
<NoteBox> <NoteBox>
Fork of Purple-EyeZ's YouBar+, ported to Revenge's Vendetta-compat API. Like the Fork of Purple-EyeZ's YouBar+, ported to Revenge's Vendetta-compat API, with a fix
original, this patches the YouBar the moment it loads - if you enable it while for a startup race where Metro hadn't always registered the YouBar component yet by
Discord's already running, you may need to restart once for the buttons to appear. the time this patch ran - if you toggle this on while Discord's already running,
the buttons should still appear without a restart once they mount, but a fresh
reload is the most reliable way to see them.
</NoteBox> </NoteBox>
<FormSection title="Buttons"> <FormSection title="Buttons">
<FormSwitchRow <FormSwitchRow