summaryrefslogtreecommitdiff
path: root/frontend/src/tabs-hook.ts
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/tabs-hook.ts')
-rw-r--r--frontend/src/tabs-hook.ts85
1 files changed, 75 insertions, 10 deletions
diff --git a/frontend/src/tabs-hook.ts b/frontend/src/tabs-hook.ts
index dd013844..de03310e 100644
--- a/frontend/src/tabs-hook.ts
+++ b/frontend/src/tabs-hook.ts
@@ -1,3 +1,6 @@
+import { afterPatch, sleep, unpatch } from 'decky-frontend-lib';
+import { memo } from 'react';
+
import Logger from './logger';
declare global {
@@ -11,7 +14,7 @@ declare global {
const isTabsArray = (tabs: any) => {
const length = tabs.length;
- return length === 7 && tabs[length - 1]?.key === 6 && tabs[length - 1]?.tab;
+ return length >= 7 && tabs[length - 1]?.tab;
};
interface Tab {
@@ -24,24 +27,86 @@ interface Tab {
class TabsHook extends Logger {
// private keys = 7;
tabs: Tab[] = [];
+ private quickAccess: any;
+ private tabRenderer: any;
+ private memoizedQuickAccess: any;
+ private cNode: any;
+
+ private qAPTree: any;
+ private rendererTree: any;
constructor() {
super('TabsHook');
this.log('Initialized');
+ window.__TABS_HOOK_INSTANCE?.deinit?.();
window.__TABS_HOOK_INSTANCE = this;
const self = this;
-
- const filter = Array.prototype.__filter ?? Array.prototype.filter;
- Array.prototype.__filter = filter;
- Array.prototype.filter = function (...args: any[]) {
- if (isTabsArray(this)) {
- self.render(this);
+ const tree = (document.getElementById('root') as any)._reactRootContainer._internalRoot.current;
+ let scrollRoot: any;
+ let currentNode = tree;
+ (async () => {
+ let iters = 0;
+ while (!scrollRoot) {
+ iters++;
+ currentNode = currentNode?.child;
+ if (iters >= 30 || !currentNode) {
+ iters = 0;
+ currentNode = tree;
+ await sleep(5000);
+ }
+ if (currentNode?.type?.prototype?.RemoveSmartScrollContainer) scrollRoot = currentNode;
}
- // @ts-ignore
- return filter.call(this, ...args);
- };
+ let newQA: any;
+ let newQATabRenderer: any;
+ afterPatch(scrollRoot.stateNode, 'render', (_: any, ret: any) => {
+ if (!this.quickAccess && ret.props.children.props.children[4]) {
+ this.quickAccess = ret?.props?.children?.props?.children[4].type;
+ newQA = (...args: any) => {
+ const ret = this.quickAccess.type(...args);
+ if (ret) {
+ if (!newQATabRenderer) {
+ this.tabRenderer = ret.props.children[1].children.type;
+ newQATabRenderer = (...args: any) => {
+ const oFilter = Array.prototype.filter;
+ Array.prototype.filter = function (...args: any[]) {
+ if (isTabsArray(this)) {
+ self.render(this);
+ }
+ // @ts-ignore
+ return oFilter.call(this, ...args);
+ };
+ // TODO remove array hack entirely and use this instead const tabs = ret.props.children.props.children[0].props.children[1].props.children[0].props.children[0].props.tabs
+ const ret = this.tabRenderer(...args);
+ Array.prototype.filter = oFilter;
+ return ret;
+ };
+ }
+ this.rendererTree = ret.props.children[1].children;
+ ret.props.children[1].children.type = newQATabRenderer;
+ }
+ return ret;
+ };
+ this.memoizedQuickAccess = memo(newQA);
+ this.memoizedQuickAccess.isDeckyQuickAccess = true;
+ }
+ if (ret.props.children.props.children[4]) {
+ this.qAPTree = ret.props.children.props.children[4];
+ ret.props.children.props.children[4].type = this.memoizedQuickAccess;
+ }
+ return ret;
+ });
+ this.cNode = scrollRoot;
+ this.cNode.stateNode.forceUpdate();
+ })();
+ }
+
+ deinit() {
+ unpatch(this.cNode.stateNode, 'render');
+ if (this.qAPTree) this.qAPTree.type = this.quickAccess;
+ if (this.rendererTree) this.rendererTree.type = this.tabRenderer;
+ if (this.cNode) this.cNode.stateNode.forceUpdate();
}
add(tab: Tab) {