preview 10/21/2022 fixes (#234)

* initial fixes: everything working except toasts and patch notes

* tabshook changes, disable toaster for now

* prettier

* oops

* implement custom toaster because I am tired of Valve's shit

also fix QAM not injecting sometimes

* remove extra logging

* add findSP, fix patch notes, fix vscode screwup

* fix patch notes

* show error when plugin frontends fail to load

* add get_tab_lambda

* add css and has_element helpers to Tab

* small modals fixup

* Don't forceUpdate QuickAccess on stable

* add routes prop used to get tabs component

* add more dev utils to DFL global
This commit is contained in:
AAGaming
2022-10-24 19:14:56 -04:00
committed by GitHub
parent 2e6b3834da
commit 84c3b039c3
21 changed files with 695 additions and 278 deletions
+132 -79
View File
@@ -1,8 +1,10 @@
import { Patch, ToastData, afterPatch, findInReactTree, findModuleChild, sleep } from 'decky-frontend-lib';
import { ReactNode } from 'react';
import { Patch, ToastData, sleep } from 'decky-frontend-lib';
import DeckyToaster from './components/DeckyToaster';
import { DeckyToasterState, DeckyToasterStateContextProvider } from './components/DeckyToasterState';
import Toast from './components/Toast';
import Logger from './logger';
import RouterHook from './router-hook';
declare global {
interface Window {
@@ -13,12 +15,15 @@ declare global {
class Toaster extends Logger {
private instanceRetPatch?: Patch;
private routerHook: RouterHook;
private toasterState: DeckyToasterState = new DeckyToasterState();
private node: any;
private settingsModule: any;
private ready: boolean = false;
constructor() {
constructor(routerHook: RouterHook) {
super('Toaster');
this.routerHook = routerHook;
window.__TOASTER_INSTANCE?.deinit?.();
window.__TOASTER_INSTANCE = this;
@@ -26,87 +31,135 @@ class Toaster extends Logger {
}
async init() {
let instance: any;
while (true) {
instance = findInReactTree(
(document.getElementById('root') as any)._reactRootContainer._internalRoot.current,
(x) => x?.memoizedProps?.className?.startsWith?.('toastmanager_ToastPlaceholder'),
);
if (instance) break;
this.debug('finding instance');
await sleep(2000);
}
this.node = instance.return.return;
let toast: any;
let renderedToast: ReactNode = null;
this.node.stateNode.render = (...args: any[]) => {
const ret = this.node.stateNode.__proto__.render.call(this.node.stateNode, ...args);
if (ret) {
this.instanceRetPatch = afterPatch(ret, 'type', (_: any, ret: any) => {
if (ret?.props?.children[1]?.children?.props) {
const currentToast = ret.props.children[1].children.props.notification;
if (currentToast?.decky) {
if (currentToast == toast) {
ret.props.children[1].children = renderedToast;
} else {
toast = currentToast;
renderedToast = <Toast toast={toast} />;
ret.props.children[1].children = renderedToast;
}
} else {
toast = null;
renderedToast = null;
}
}
return ret;
});
this.node.stateNode.shouldComponentUpdate = () => {
return false;
};
delete this.node.stateNode.render;
}
return ret;
};
this.settingsModule = findModuleChild((m) => {
if (typeof m !== 'object') return undefined;
for (let prop in m) {
if (typeof m[prop]?.settings && m[prop]?.communityPreferences) return m[prop];
}
});
this.log('Initialized');
this.ready = true;
this.routerHook.addGlobalComponent('DeckyToaster', () => (
<DeckyToasterStateContextProvider deckyToasterState={this.toasterState}>
<DeckyToaster />
</DeckyToasterStateContextProvider>
));
// let instance: any;
// while (true) {
// instance = findInReactTree(
// (document.getElementById('root') as any)._reactRootContainer._internalRoot.current,
// (x) => x?.memoizedProps?.className?.startsWith?.('toastmanager_ToastPlaceholder'),
// );
// if (instance) break;
// this.debug('finding instance');
// await sleep(2000);
// }
// // const windowManager = findModuleChild((m) => {
// // if (typeof m !== 'object') return false;
// // for (let prop in m) {
// // if (m[prop]?.prototype?.GetRenderElement) return m[prop];
// // }
// // return false;
// // });
// this.node = instance.return.return;
// let toast: any;
// let renderedToast: ReactNode = null;
// console.log(instance, this.node);
// // replacePatch(window.SteamClient.BrowserView, "Destroy", (args: any[]) => {
// // console.debug("destroy", args)
// // return callOriginal;
// // })
// // let node = this.node.child.updateQueue.lastEffect;
// // while (node.next && !node.deckyPatched) {
// // node = node.next;
// // if (node.deps[1] == "notificationtoasts") {
// // console.log("Deleting destroy");
// // node.deckyPatched = true;
// // node.create = () => {console.debug("VVVVVVVVVVV")};
// // node.destroy = () => {console.debug("AAAAAAAAAAAAAAAAaaaaaaaaaaaaaaa")};
// // }
// // }
// this.node.stateNode.render = (...args: any[]) => {
// const ret = this.node.stateNode.__proto__.render.call(this.node.stateNode, ...args);
// console.log('toast', ret);
// if (ret) {
// console.log(ret)
// // this.instanceRetPatch = replacePatch(ret, 'type', (innerArgs: any) => {
// // console.log("inner toast", innerArgs)
// // // @ts-ignore
// // const oldEffect = window.SP_REACT.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher.current.useEffect;
// // // @ts-ignore
// // window.SP_REACT.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher.current.useEffect = (effect, deps) => {
// // console.log(effect, deps)
// // if (deps?.[1] == "notificationtoasts") {
// // console.log("run")
// // effect();
// // }
// // return oldEffect(effect, deps);
// // }
// // const ret = this.instanceRetPatch?.original(...args);
// // console.log("inner ret", ret)
// // // @ts-ignore
// // window.SP_REACT.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher.current.useEffect = oldEffect;
// // return ret
// // });
// }
// // console.log("toast ret", ret)
// // if (ret?.props?.children[1]?.children?.props) {
// // const currentToast = ret.props.children[1].children.props.notification;
// // if (currentToast?.decky) {
// // if (currentToast == toast) {
// // ret.props.children[1].children = renderedToast;
// // } else {
// // toast = currentToast;
// // renderedToast = <Toast toast={toast} />;
// // ret.props.children[1].children = renderedToast;
// // }
// // } else {
// // toast = null;
// // renderedToast = null;
// // }
// // }
// // return ret;
// // });
// // }
// return ret;
// };
// this.settingsModule = findModuleChild((m) => {
// if (typeof m !== 'object') return undefined;
// for (let prop in m) {
// if (typeof m[prop]?.settings && m[prop]?.communityPreferences) return m[prop];
// }
// });
// // const idx = FocusNavController.m_ActiveContext.m_rgGamepadNavigationTrees.findIndex((x: any) => x.m_ID == "ToastContainer");
// // if (idx > -1) {
// // FocusNavController.m_ActiveContext.m_rgGamepadNavigationTrees.splice(idx, 1)
// // }
// this.node.stateNode.forceUpdate();
// this.node.stateNode.shouldComponentUpdate = () => {
// return false;
// };
// this.log('Initialized');
// this.ready = true;
}
async toast(toast: ToastData) {
while (!this.ready) {
await sleep(100);
}
const settings = this.settingsModule?.settings;
let toastData = {
nNotificationID: window.NotificationStore.m_nNextTestNotificationID++,
rtCreated: Date.now(),
eType: 15,
nToastDurationMS: toast.duration || 5e3,
data: toast,
decky: true,
};
// @ts-ignore
toastData.data.appid = () => 0;
if (
(settings?.bDisableAllToasts && !toast.critical) ||
(settings?.bDisableToastsInGame && !toast.critical && window.NotificationStore.BIsUserInGame())
)
return;
window.NotificationStore.m_rgNotificationToasts.push(toastData);
window.NotificationStore.DispatchNextToast();
toast(toast: ToastData) {
toast.duration = toast.duration || 5e3;
this.toasterState.addToast(toast);
// const settings = this.settingsModule?.settings;
// let toastData = {
// nNotificationID: window.NotificationStore.m_nNextTestNotificationID++,
// rtCreated: Date.now(),
// eType: 15,
// nToastDurationMS: toast.duration || 5e3,
// data: toast,
// decky: true,
// };
// // @ts-ignore
// toastData.data.appid = () => 0;
// if (
// (settings?.bDisableAllToasts && !toast.critical) ||
// (settings?.bDisableToastsInGame && !toast.critical && window.NotificationStore.BIsUserInGame())
// )
// return;
// window.NotificationStore.m_rgNotificationToasts.push(toastData);
// window.NotificationStore.DispatchNextToast();
}
deinit() {
this.instanceRetPatch?.unpatch();
this.node && delete this.node.stateNode.shouldComponentUpdate;
this.node && this.node.stateNode.forceUpdate();
this.routerHook.removeGlobalComponent('DeckyToaster');
}
}