mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-07-11 16:02:01 +00:00
implement new toaster hook
this also supports the notification list and probably also desktop toasts (UI wip, read location enum prop from toast component probably)
This commit is contained in:
@@ -69,13 +69,13 @@ class ErrorBoundaryHook extends Logger {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!ErrorBoundary) {
|
if (!ErrorBoundary) {
|
||||||
this.error('could not find ValveErrorBoundary');
|
this.error('@decky/ui could not find ErrorBoundary, skipping patch');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.errorBoundaryPatch = replacePatch(ErrorBoundary.prototype, 'render', function (this: any) {
|
this.errorBoundaryPatch = replacePatch(ErrorBoundary.prototype, 'render', function (this: any) {
|
||||||
if (this.state._deckyForceRerender) {
|
if (this.state._deckyForceRerender) {
|
||||||
const stateClone = {...this.state, _deckyForceRerender: null};
|
const stateClone = { ...this.state, _deckyForceRerender: null };
|
||||||
this.setState(stateClone);
|
this.setState(stateClone);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -93,9 +93,9 @@ class ErrorBoundaryHook extends Logger {
|
|||||||
return callOriginal;
|
return callOriginal;
|
||||||
});
|
});
|
||||||
// Small hack that gives us a lot more flexibility to force rerenders.
|
// Small hack that gives us a lot more flexibility to force rerenders.
|
||||||
ValveErrorBoundary.prototype._deckyForceRerender = function (this: any) {
|
ErrorBoundary.prototype._deckyForceRerender = function (this: any) {
|
||||||
this.setState({...this.state, _deckyForceRerender: true});
|
this.setState({ ...this.state, _deckyForceRerender: true });
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public temporarilyDisableReporting() {
|
public temporarilyDisableReporting() {
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import Toaster from './toaster';
|
|||||||
import { getVersionInfo } from './updater';
|
import { getVersionInfo } from './updater';
|
||||||
import { getSetting, setSetting } from './utils/settings';
|
import { getSetting, setSetting } from './utils/settings';
|
||||||
import TranslationHelper, { TranslationClass } from './utils/TranslationHelper';
|
import TranslationHelper, { TranslationClass } from './utils/TranslationHelper';
|
||||||
import AppHook from './app-hook';
|
|
||||||
|
|
||||||
const StorePage = lazy(() => import('./components/store/Store'));
|
const StorePage = lazy(() => import('./components/store/Store'));
|
||||||
const SettingsPage = lazy(() => import('./components/settings'));
|
const SettingsPage = lazy(() => import('./components/settings'));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ErrorBoundary, Focusable, Patch, afterPatch, beforePatch, findInReactTree, findModuleByExport, findModuleExport, getReactRoot, sleep } from '@decky/ui';
|
import { ErrorBoundary, Patch, afterPatch, findInReactTree, getReactRoot, sleep } from '@decky/ui';
|
||||||
import { FC, ReactElement, ReactNode, cloneElement, createElement, memo } from 'react';
|
import { FC, ReactElement, ReactNode, cloneElement, createElement } from 'react';
|
||||||
import type { Route } from 'react-router';
|
import type { Route } from 'react-router';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -32,6 +32,7 @@ class RouterHook extends Logger {
|
|||||||
private DeckyWrapper = this.routerWrapper.bind(this);
|
private DeckyWrapper = this.routerWrapper.bind(this);
|
||||||
private DeckyGlobalComponentsWrapper = this.globalComponentsWrapper.bind(this);
|
private DeckyGlobalComponentsWrapper = this.globalComponentsWrapper.bind(this);
|
||||||
private toReplace = new Map<string, ReactNode>();
|
private toReplace = new Map<string, ReactNode>();
|
||||||
|
private routerPatch?: Patch;
|
||||||
public routes?: any[];
|
public routes?: any[];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -41,22 +42,25 @@ class RouterHook extends Logger {
|
|||||||
window.__ROUTER_HOOK_INSTANCE?.deinit?.();
|
window.__ROUTER_HOOK_INSTANCE?.deinit?.();
|
||||||
window.__ROUTER_HOOK_INSTANCE = this;
|
window.__ROUTER_HOOK_INSTANCE = this;
|
||||||
|
|
||||||
(async()=> {
|
(async () => {
|
||||||
const root = getReactRoot(document.getElementById('root') as any);
|
const root = getReactRoot(document.getElementById('root') as any);
|
||||||
// TODO be more specific, this is horrible and very very slow
|
// TODO be more specific, this is horrible and very very slow
|
||||||
const findRouterNode = () =>findInReactTree(root, node => typeof node?.pendingProps?.loggedIn == "undefined" && node?.type?.toString().includes("Settings.Root()"));
|
const findRouterNode = () =>
|
||||||
|
findInReactTree(
|
||||||
|
root,
|
||||||
|
(node) =>
|
||||||
|
typeof node?.pendingProps?.loggedIn == 'undefined' && node?.type?.toString().includes('Settings.Root()'),
|
||||||
|
);
|
||||||
let routerNode = findRouterNode();
|
let routerNode = findRouterNode();
|
||||||
while (!routerNode) {
|
while (!routerNode) {
|
||||||
this.warn(
|
this.warn('Failed to find Router node, reattempting in 5 seconds.');
|
||||||
'Failed to find Router node, reattempting in 5 seconds.',
|
|
||||||
);
|
|
||||||
await sleep(5000);
|
await sleep(5000);
|
||||||
routerNode = findRouterNode();
|
routerNode = findRouterNode();
|
||||||
}
|
}
|
||||||
if (routerNode) {
|
if (routerNode) {
|
||||||
this.debug("routerNode", routerNode);
|
this.debug('routerNode', routerNode);
|
||||||
// Patch the component globally
|
// Patch the component globally
|
||||||
afterPatch(routerNode.elementType, "type", this.handleRouterRender.bind(this));
|
this.routerPatch = afterPatch(routerNode.elementType, 'type', this.handleRouterRender.bind(this));
|
||||||
// Swap out the current instance
|
// Swap out the current instance
|
||||||
routerNode.type = routerNode.elementType.type;
|
routerNode.type = routerNode.elementType.type;
|
||||||
if (routerNode?.alternate) {
|
if (routerNode?.alternate) {
|
||||||
@@ -91,14 +95,14 @@ class RouterHook extends Logger {
|
|||||||
return returnVal;
|
return returnVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private globalComponentsWrapper () {
|
private globalComponentsWrapper() {
|
||||||
const { components } = useDeckyGlobalComponentsState();
|
const { components } = useDeckyGlobalComponentsState();
|
||||||
if (this.renderedComponents.length != components.size) {
|
if (this.renderedComponents.length != components.size) {
|
||||||
this.debug('Rerendering global components');
|
this.debug('Rerendering global components');
|
||||||
this.renderedComponents = Array.from(components.values()).map((GComponent) => <GComponent />);
|
this.renderedComponents = Array.from(components.values()).map((GComponent) => <GComponent />);
|
||||||
}
|
}
|
||||||
return <>{this.renderedComponents}</>;
|
return <>{this.renderedComponents}</>;
|
||||||
};
|
}
|
||||||
|
|
||||||
private routerWrapper({ children }: { children: ReactElement }) {
|
private routerWrapper({ children }: { children: ReactElement }) {
|
||||||
// Used to store the new replicated routes we create to allow routes to be unpatched.
|
// Used to store the new replicated routes we create to allow routes to be unpatched.
|
||||||
@@ -106,7 +110,7 @@ class RouterHook extends Logger {
|
|||||||
const { routes, routePatches } = useDeckyRouterState();
|
const { routes, routePatches } = useDeckyRouterState();
|
||||||
// TODO make more redundant
|
// TODO make more redundant
|
||||||
if (!children?.props?.children?.[0]?.props?.children) {
|
if (!children?.props?.children?.[0]?.props?.children) {
|
||||||
console.log("routerWrapper wrong component?", children)
|
console.log('routerWrapper wrong component?', children);
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
const mainRouteList = children.props.children[0].props.children;
|
const mainRouteList = children.props.children[0].props.children;
|
||||||
@@ -116,7 +120,7 @@ class RouterHook extends Logger {
|
|||||||
|
|
||||||
this.debug('Rerendered routes list');
|
this.debug('Rerendered routes list');
|
||||||
return children;
|
return children;
|
||||||
};
|
}
|
||||||
|
|
||||||
private processList(
|
private processList(
|
||||||
routeList: any[],
|
routeList: any[],
|
||||||
@@ -167,7 +171,7 @@ class RouterHook extends Logger {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
addRoute(path: string, component: RouterEntry['component'], props: RouterEntry['props'] = {}) {
|
addRoute(path: string, component: RouterEntry['component'], props: RouterEntry['props'] = {}) {
|
||||||
this.routerState.addRoute(path, component, props);
|
this.routerState.addRoute(path, component, props);
|
||||||
@@ -194,8 +198,7 @@ class RouterHook extends Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit() {
|
deinit() {
|
||||||
// this.wrapperPatch.unpatch();
|
this.routerPatch?.unpatch();
|
||||||
// this.routerPatch?.unpatch();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-15
@@ -1,5 +1,14 @@
|
|||||||
// TabsHook for versions after the Desktop merge
|
// TabsHook for versions after the Desktop merge
|
||||||
import { ErrorBoundary, Patch, QuickAccessTab, afterPatch, createReactTreePatcher, findInReactTree, findModuleByExport, getReactRoot, setReactPatcherLoggingEnabled, sleep } from '@decky/ui';
|
import {
|
||||||
|
ErrorBoundary,
|
||||||
|
Patch,
|
||||||
|
QuickAccessTab,
|
||||||
|
afterPatch,
|
||||||
|
createReactTreePatcher,
|
||||||
|
findInReactTree,
|
||||||
|
findModuleByExport,
|
||||||
|
getReactRoot,
|
||||||
|
} from '@decky/ui';
|
||||||
|
|
||||||
import { QuickAccessVisibleStateProvider } from './components/QuickAccessVisibleState';
|
import { QuickAccessVisibleStateProvider } from './components/QuickAccessVisibleState';
|
||||||
import Logger from './logger';
|
import Logger from './logger';
|
||||||
@@ -20,9 +29,7 @@ interface Tab {
|
|||||||
class TabsHook extends Logger {
|
class TabsHook extends Logger {
|
||||||
// private keys = 7;
|
// private keys = 7;
|
||||||
tabs: Tab[] = [];
|
tabs: Tab[] = [];
|
||||||
private qAMRoot?: any;
|
|
||||||
private qamPatch?: Patch;
|
private qamPatch?: Patch;
|
||||||
private cachedTabs: any;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super('TabsHook');
|
super('TabsHook');
|
||||||
@@ -34,25 +41,29 @@ class TabsHook extends Logger {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
// TODO patch the "embedded" renderer in this module too (seems to be for VR? unsure)
|
// TODO patch the "embedded" renderer in this module too (seems to be for VR? unsure)
|
||||||
const qamModule = findModuleByExport(e => e?.type?.toString()?.includes("QuickAccessMenuBrowserView"));
|
const qamModule = findModuleByExport((e) => e?.type?.toString()?.includes('QuickAccessMenuBrowserView'));
|
||||||
const qamRenderer = Object.values(qamModule).find((e: any) => e?.type?.toString()?.includes("QuickAccessMenuBrowserView"))
|
const qamRenderer = Object.values(qamModule).find((e: any) =>
|
||||||
|
e?.type?.toString()?.includes('QuickAccessMenuBrowserView'),
|
||||||
|
);
|
||||||
|
|
||||||
const patchHandler = createReactTreePatcher([
|
const patchHandler = createReactTreePatcher(
|
||||||
tree => findInReactTree(tree, node => node?.props?.onFocusNavDeactivated)
|
[(tree) => findInReactTree(tree, (node) => node?.props?.onFocusNavDeactivated)],
|
||||||
], (args, ret) => {
|
(args, ret) => {
|
||||||
this.log("qam render", args, ret);
|
this.log('qam render', args, ret);
|
||||||
const tabs = findInReactTree(ret, (x) => x?.props?.tabs);
|
const tabs = findInReactTree(ret, (x) => x?.props?.tabs);
|
||||||
this.render(tabs.props.tabs, args[0].visible);
|
this.render(tabs.props.tabs, args[0].visible);
|
||||||
return ret;
|
return ret;
|
||||||
}, "TabsHook");
|
},
|
||||||
|
'TabsHook',
|
||||||
|
);
|
||||||
|
|
||||||
this.qamPatch = afterPatch(qamRenderer, "type", patchHandler);
|
this.qamPatch = afterPatch(qamRenderer, 'type', patchHandler);
|
||||||
|
|
||||||
// Patch already rendered qam
|
// Patch already rendered qam
|
||||||
const root = getReactRoot(document.getElementById('root') as any);
|
const root = getReactRoot(document.getElementById('root') as any);
|
||||||
const qamNode = root && findInReactTree(root, (n: any) => n.elementType == qamRenderer); // need elementType, because type is actually mobx wrapper
|
const qamNode = root && findInReactTree(root, (n: any) => n.elementType == qamRenderer); // need elementType, because type is actually mobx wrapper
|
||||||
if (qamNode) {
|
if (qamNode) {
|
||||||
this.debug("qamNode", qamNode);
|
this.debug('qamNode', qamNode);
|
||||||
// Only affects this fiber node so we don't need to unpatch here
|
// Only affects this fiber node so we don't need to unpatch here
|
||||||
qamNode.type = qamNode.elementType.type;
|
qamNode.type = qamNode.elementType.type;
|
||||||
if (qamNode?.alternate) {
|
if (qamNode?.alternate) {
|
||||||
|
|||||||
+36
-136
@@ -1,19 +1,16 @@
|
|||||||
import type { ToastData } from '@decky/api';
|
import type { ToastData } from '@decky/api';
|
||||||
import {
|
import { Patch, callOriginal, findModuleExport, injectFCTrampoline, replacePatch } from '@decky/ui';
|
||||||
Export,
|
|
||||||
Patch,
|
|
||||||
afterPatch,
|
|
||||||
findClassByName,
|
|
||||||
findInReactTree,
|
|
||||||
findModuleExport,
|
|
||||||
getReactRoot,
|
|
||||||
sleep,
|
|
||||||
} from '@decky/ui';
|
|
||||||
import { ReactNode } from 'react';
|
|
||||||
|
|
||||||
import Toast from './components/Toast';
|
import Toast from './components/Toast';
|
||||||
import Logger from './logger';
|
import Logger from './logger';
|
||||||
|
|
||||||
|
// TODO export
|
||||||
|
enum ToastType {
|
||||||
|
New,
|
||||||
|
Update,
|
||||||
|
Remove,
|
||||||
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
__TOASTER_INSTANCE: any;
|
__TOASTER_INSTANCE: any;
|
||||||
@@ -23,18 +20,12 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Toaster extends Logger {
|
class Toaster extends Logger {
|
||||||
// private routerHook: RouterHook;
|
|
||||||
// private toasterState: DeckyToasterState = new DeckyToasterState();
|
|
||||||
private node: any;
|
|
||||||
private rNode: any;
|
|
||||||
private audioModule: any;
|
|
||||||
private finishStartup?: () => void;
|
private finishStartup?: () => void;
|
||||||
private ready: Promise<void> = new Promise((res) => (this.finishStartup = res));
|
private ready: Promise<void> = new Promise((res) => (this.finishStartup = res));
|
||||||
private toasterPatch?: Patch;
|
private toastPatch?: Patch;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super('Toaster');
|
super('Toaster');
|
||||||
// this.routerHook = routerHook;
|
|
||||||
|
|
||||||
window.__TOASTER_INSTANCE?.deinit?.();
|
window.__TOASTER_INSTANCE?.deinit?.();
|
||||||
window.__TOASTER_INSTANCE = this;
|
window.__TOASTER_INSTANCE = this;
|
||||||
@@ -42,115 +33,18 @@ class Toaster extends Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
// this.routerHook.addGlobalComponent('DeckyToaster', () => (
|
const ToastRenderer = findModuleExport((e) => e?.toString()?.includes(`controller:"notification",method:`));
|
||||||
// <DeckyToasterStateContextProvider deckyToasterState={this.toasterState}>
|
this.debug('toastrenderer', ToastRenderer);
|
||||||
// <DeckyToaster />
|
// TODO find a way to undo this if possible?
|
||||||
// </DeckyToasterStateContextProvider>
|
const patchedRenderer = injectFCTrampoline(ToastRenderer);
|
||||||
// ));
|
this.toastPatch = replacePatch(patchedRenderer, 'component', (args: any[]) => {
|
||||||
let instance: any;
|
this.debug('render toast', args);
|
||||||
const tree = getReactRoot(document.getElementById('root') as any);
|
if (args?.[0]?.group?.decky || args?.[0]?.group?.notifications?.[0]?.decky) {
|
||||||
const toasterClass1 = findClassByName('GamepadToastPlaceholder');
|
this.debug('rendering decky toast');
|
||||||
const toasterClass2 = findClassByName('ToastPlaceholder');
|
return args[0].group.notifications.map((notification: any) => <Toast toast={notification.data} />);
|
||||||
const toasterClass3 = findClassByName('ToastPopup');
|
|
||||||
const toasterClass4 = findClassByName('GamepadToastPopup');
|
|
||||||
const findToasterRoot = (currentNode: any, iters: number): any => {
|
|
||||||
if (iters >= 80) {
|
|
||||||
// currently 66
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
if (
|
return callOriginal;
|
||||||
currentNode?.memoizedProps?.className?.startsWith?.(toasterClass1) ||
|
});
|
||||||
currentNode?.memoizedProps?.className?.startsWith?.(toasterClass2) ||
|
|
||||||
currentNode?.memoizedProps?.className?.startsWith?.(toasterClass3) ||
|
|
||||||
currentNode?.memoizedProps?.className?.startsWith?.(toasterClass4)
|
|
||||||
) {
|
|
||||||
this.log(`Toaster root was found in ${iters} recursion cycles`);
|
|
||||||
return currentNode;
|
|
||||||
}
|
|
||||||
if (currentNode.sibling) {
|
|
||||||
let node = findToasterRoot(currentNode.sibling, iters + 1);
|
|
||||||
if (node !== null) return node;
|
|
||||||
}
|
|
||||||
if (currentNode.child) {
|
|
||||||
let node = findToasterRoot(currentNode.child, iters + 1);
|
|
||||||
if (node !== null) return node;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
instance = findToasterRoot(tree, 0);
|
|
||||||
while (!instance) {
|
|
||||||
this.warn(
|
|
||||||
'Failed to find Toaster root node, reattempting in 5 seconds. A developer may need to increase the recursion limit.',
|
|
||||||
);
|
|
||||||
await sleep(5000);
|
|
||||||
instance = findToasterRoot(tree, 0);
|
|
||||||
}
|
|
||||||
this.node = instance.return;
|
|
||||||
this.rNode = findInReactTree(
|
|
||||||
this.node.return.return,
|
|
||||||
(node) => node?.stateNode && node.type?.InstallErrorReportingStore,
|
|
||||||
);
|
|
||||||
let toast: any;
|
|
||||||
let renderedToast: ReactNode = null;
|
|
||||||
let innerPatched: any;
|
|
||||||
const repatch = () => {
|
|
||||||
if (this.node && !this.node.type.decky) {
|
|
||||||
this.toasterPatch = afterPatch(this.node, 'type', (_: any, ret: any) => {
|
|
||||||
const inner = findInReactTree(ret.props.children, (x) => x?.props?.onDismiss);
|
|
||||||
if (innerPatched) {
|
|
||||||
inner.type = innerPatched;
|
|
||||||
} else {
|
|
||||||
afterPatch(inner, 'type', (innerArgs: any, ret: any) => {
|
|
||||||
const currentToast = innerArgs[0]?.notification;
|
|
||||||
if (currentToast?.decky) {
|
|
||||||
if (currentToast == toast) {
|
|
||||||
ret.props.children = renderedToast;
|
|
||||||
} else {
|
|
||||||
toast = currentToast;
|
|
||||||
renderedToast = <Toast toast={toast.data} />;
|
|
||||||
ret.props.children = renderedToast;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
toast = null;
|
|
||||||
renderedToast = null;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
innerPatched = inner.type;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
this.node.type.decky = true;
|
|
||||||
this.node.alternate.type = this.node.type;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const oRender = Object.getPrototypeOf(this.rNode.stateNode).render;
|
|
||||||
let int: number | undefined;
|
|
||||||
this.rNode.stateNode.render = (...args: any[]) => {
|
|
||||||
const ret = oRender.call(this.rNode.stateNode, ...args);
|
|
||||||
if (ret && !this?.node?.return?.return) {
|
|
||||||
int && clearInterval(int);
|
|
||||||
int = setInterval(() => {
|
|
||||||
const n = findToasterRoot(tree, 0);
|
|
||||||
if (n?.return) {
|
|
||||||
clearInterval(int);
|
|
||||||
this.node = n.return;
|
|
||||||
this.rNode = this.node.return;
|
|
||||||
repatch();
|
|
||||||
} else {
|
|
||||||
this.error('Failed to re-grab Toaster node, trying again...');
|
|
||||||
}
|
|
||||||
}, 1200);
|
|
||||||
}
|
|
||||||
repatch();
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.rNode.stateNode.shouldComponentUpdate = () => true;
|
|
||||||
this.rNode.stateNode.forceUpdate();
|
|
||||||
delete this.rNode.stateNode.shouldComponentUpdate;
|
|
||||||
|
|
||||||
this.audioModule = findModuleExport((e: Export) => e.PlayNavSound && e.RegisterCallbackOnPlaySound);
|
|
||||||
|
|
||||||
this.log('Initialized');
|
this.log('Initialized');
|
||||||
this.finishStartup?.();
|
this.finishStartup?.();
|
||||||
@@ -168,8 +62,6 @@ class Toaster extends Logger {
|
|||||||
data: toast,
|
data: toast,
|
||||||
decky: true,
|
decky: true,
|
||||||
};
|
};
|
||||||
// @ts-ignore
|
|
||||||
toastData.data.appid = () => 0;
|
|
||||||
if (toast.sound === undefined) toast.sound = 6;
|
if (toast.sound === undefined) toast.sound = 6;
|
||||||
if (toast.playSound === undefined) toast.playSound = true;
|
if (toast.playSound === undefined) toast.playSound = true;
|
||||||
if (toast.showToast === undefined) toast.showToast = true;
|
if (toast.showToast === undefined) toast.showToast = true;
|
||||||
@@ -180,19 +72,27 @@ class Toaster extends Logger {
|
|||||||
window.NotificationStore.BIsUserInGame())
|
window.NotificationStore.BIsUserInGame())
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
if (toast.playSound) this.audioModule?.PlayNavSound(toast.sound);
|
|
||||||
if (toast.showToast) {
|
if (toast.showToast) {
|
||||||
window.NotificationStore.m_rgNotificationToasts.push(toastData);
|
function fnTray(toast: any, tray: any) {
|
||||||
window.NotificationStore.DispatchNextToast();
|
let group = {
|
||||||
|
eType: toast.eType,
|
||||||
|
notifications: [toast],
|
||||||
|
};
|
||||||
|
tray.unshift(group);
|
||||||
|
}
|
||||||
|
const info = {
|
||||||
|
showToast: toast.showToast,
|
||||||
|
sound: toast.sound,
|
||||||
|
eFeature: 0,
|
||||||
|
toastDurationMS: toastData.nToastDurationMS,
|
||||||
|
fnTray,
|
||||||
|
};
|
||||||
|
window.NotificationStore.ProcessNotification(info, toastData, ToastType.New);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit() {
|
deinit() {
|
||||||
this.toasterPatch?.unpatch();
|
this.toastPatch?.unpatch();
|
||||||
this.node.alternate.type = this.node.type;
|
|
||||||
delete this.rNode.stateNode.render;
|
|
||||||
this.ready = new Promise((res) => (this.finishStartup = res));
|
|
||||||
// this.routerHook.removeGlobalComponent('DeckyToaster');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user