summaryrefslogtreecommitdiff
path: root/frontend/src/toaster.tsx
diff options
context:
space:
mode:
authorAAGaming <aa@mail.catvibers.me>2022-10-24 19:14:56 -0400
committerGitHub <noreply@github.com>2022-10-24 16:14:56 -0700
commit84c3b039c385ad872bb0f22eba7a3d2cd4a5ea10 (patch)
tree20b13066c6256cc6ca1beac085094c7964226a37 /frontend/src/toaster.tsx
parent2e6b3834da357c7e81821ce60bad36f54dd9fa6e (diff)
downloaddecky-loader-84c3b039c385ad872bb0f22eba7a3d2cd4a5ea10.tar.gz
decky-loader-84c3b039c385ad872bb0f22eba7a3d2cd4a5ea10.zip
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
Diffstat (limited to 'frontend/src/toaster.tsx')
-rw-r--r--frontend/src/toaster.tsx211
1 files changed, 132 insertions, 79 deletions
diff --git a/frontend/src/toaster.tsx b/frontend/src/toaster.tsx
index d7c0584f..94b08d70 100644
--- a/frontend/src/toaster.tsx
+++ b/frontend/src/toaster.tsx
@@ -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');
}
}