summaryrefslogtreecommitdiff
path: root/frontend/src/tabs-hook.old.tsx
blob: 5b51159696c60f2dee18c0740acc24bf5579bbb8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// TabsHook for versions before the Desktop merge
import { Patch, afterPatch, sleep } from 'decky-frontend-lib';
import { memo } from 'react';

import NewTabsHook from './tabs-hook';

declare global {
  interface Array<T> {
    __filter: any;
  }
}

const isTabsArray = (tabs: any) => {
  const length = tabs.length;
  return length >= 7 && tabs[length - 1]?.tab;
};

class TabsHook extends NewTabsHook {
  // private keys = 7;
  private quickAccess: any;
  private tabRenderer: any;
  private memoizedQuickAccess: any;
  private cNode: any;

  private qAPTree: any;
  private rendererTree: any;

  private cNodePatch?: Patch;

  constructor() {
    super();

    this.log('Initialized stable TabsHook');
  }

  init() {
    const self = this;
    const tree = (document.getElementById('root') as any)._reactRootContainer._internalRoot.current;
    let scrollRoot: any;
    async function findScrollRoot(currentNode: any, iters: number): Promise<any> {
      if (iters >= 30) {
        self.error(
          'Scroll root was not found before hitting the recursion limit, a developer will need to increase the limit.',
        );
        return null;
      }
      currentNode = currentNode?.child;
      if (currentNode?.type?.prototype?.RemoveSmartScrollContainer) {
        self.log(`Scroll root was found in ${iters} recursion cycles`);
        return currentNode;
      }
      if (!currentNode) return null;
      if (currentNode.sibling) {
        let node = await findScrollRoot(currentNode.sibling, iters + 1);
        if (node !== null) return node;
      }
      return await findScrollRoot(currentNode, iters + 1);
    }
    (async () => {
      scrollRoot = await findScrollRoot(tree, 0);
      while (!scrollRoot) {
        this.log('Failed to find scroll root node, reattempting in 5 seconds');
        await sleep(5000);
        scrollRoot = await findScrollRoot(tree, 0);
      }
      let newQA: any;
      let newQATabRenderer: any;
      this.cNodePatch = 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 = (...qamArgs: any[]) => {
                  const oFilter = Array.prototype.filter;
                  Array.prototype.filter = function (...args: any[]) {
                    if (isTabsArray(this)) {
                      self.render(this, qamArgs[0].visible);
                    }
                    // @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(...qamArgs);
                  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();
      this.log('Finished initial injection');
    })();
  }

  deinit() {
    this.cNodePatch?.unpatch();
    if (this.qAPTree) this.qAPTree.type = this.quickAccess;
    if (this.rendererTree) this.rendererTree.type = this.tabRenderer;
    if (this.cNode) this.cNode.stateNode.forceUpdate();
  }
}

export default TabsHook;