diff options
| author | AAGaming <aa@mail.catvibers.me> | 2022-08-09 21:52:03 -0400 |
|---|---|---|
| committer | AAGaming <aa@mail.catvibers.me> | 2022-08-09 21:52:03 -0400 |
| commit | 67426af3ef73e788d99b6d2e0c730c270daea273 (patch) | |
| tree | 30c1f4b33e63d38d8d5cc26f26af655f1b5a44ba /frontend/src/toaster.tsx | |
| parent | 0dbdb4a143f6e4f2b08c5a38a597d5a1c49a109c (diff) | |
| download | decky-loader-67426af3ef73e788d99b6d2e0c730c270daea273.tar.gz decky-loader-67426af3ef73e788d99b6d2e0c730c270daea273.zip | |
Add api for showing toast notificationsv2.0.4-67426af-pre
Diffstat (limited to 'frontend/src/toaster.tsx')
| -rw-r--r-- | frontend/src/toaster.tsx | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/frontend/src/toaster.tsx b/frontend/src/toaster.tsx new file mode 100644 index 00000000..b6901ed2 --- /dev/null +++ b/frontend/src/toaster.tsx @@ -0,0 +1,93 @@ +import { ToastData, afterPatch, findInReactTree, findModuleChild, sleep, unpatch } from 'decky-frontend-lib'; + +import Toast from './components/Toast'; +import Logger from './logger'; + +declare global { + interface Window { + __TOASTER_INSTANCE: any; + NotificationStore: any; + } +} + +class Toaster extends Logger { + private instanceRet: any; + private node: any; + private settingsModule: any; + + constructor() { + super('Toaster'); + + window.__TOASTER_INSTANCE?.deinit?.(); + window.__TOASTER_INSTANCE = this; + this.init(); + } + + async init() { + this.settingsModule = findModuleChild((m) => { + if (typeof m !== 'object') return undefined; + for (let prop in m) { + if (typeof m[prop]?.settings?.bDisableToastsInGame !== 'undefined') return m[prop]; + } + }); + + 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; + this.node.stateNode.render = (...args: any[]) => { + const ret = this.node.stateNode.__proto__.render.call(this.node.stateNode, ...args); + if (ret) { + this.instanceRet = ret; + afterPatch(ret, 'type', (_: any, ret: any) => { + if (ret?.props?.children[1]?.children?.props?.notification?.decky) { + const toast = ret.props.children[1].children.props.notification; + ret.props.children[1].children.type = () => <Toast toast={toast} />; + } + return ret; + }); + } + return ret; + }; + this.node.stateNode.forceUpdate(); + this.log('Initialized'); + } + + toast(toast: ToastData) { + 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(); + window.NotificationStore.m_rgNotificationToasts.pop(); + } + + deinit() { + unpatch(this.instanceRet, 'type'); + delete this.node.stateNode.render; + this.node.stateNode.forceUpdate(); + } +} + +export default Toaster; |
