From 84c3b039c385ad872bb0f22eba7a3d2cd4a5ea10 Mon Sep 17 00:00:00 2001
From: AAGaming <aa@mail.catvibers.me>
Date: Mon, 24 Oct 2022 19:14:56 -0400
Subject: 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
---
 frontend/src/tabs-hook.tsx | 143 ++++++++++++++++++---------------------------
 1 file changed, 57 insertions(+), 86 deletions(-)

(limited to 'frontend/src/tabs-hook.tsx')

diff --git a/frontend/src/tabs-hook.tsx b/frontend/src/tabs-hook.tsx
index c5072e27..5929b8a0 100644
--- a/frontend/src/tabs-hook.tsx
+++ b/frontend/src/tabs-hook.tsx
@@ -1,5 +1,4 @@
-import { Patch, QuickAccessTab, afterPatch, sleep } from 'decky-frontend-lib';
-import { memo } from 'react';
+import { QuickAccessTab, quickAccessMenuClasses, sleep } from 'decky-frontend-lib';
 
 import { QuickAccessVisibleStateProvider } from './components/QuickAccessVisibleState';
 import Logger from './logger';
@@ -28,15 +27,7 @@ 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;
-
-  private cNodePatch?: Patch;
+  private oFilter: (...args: any[]) => any;
 
   constructor() {
     super('TabsHook');
@@ -46,84 +37,63 @@ class TabsHook extends Logger {
     window.__TABS_HOOK_INSTANCE = this;
 
     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);
+    const oFilter = (this.oFilter = Array.prototype.filter);
+    Array.prototype.filter = function patchedFilter(...args: any[]) {
+      if (isTabsArray(this)) {
+        self.render(this);
       }
-      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;
+      // @ts-ignore
+      return oFilter.call(this, ...args);
+    };
+
+    if (document.title != 'SP')
+      try {
+        const tree = (document.getElementById('root') as any)._reactRootContainer._internalRoot.current;
+        let qAMRoot: any;
+        async function findQAMRoot(currentNode: any, iters: number): Promise<any> {
+          if (iters >= 60) {
+            // currently 44
+            return null;
+          }
+          currentNode = currentNode?.child;
+          if (
+            currentNode?.memoizedProps?.className &&
+            currentNode?.memoizedProps?.className.startsWith(quickAccessMenuClasses.ViewPlaceholder)
+          ) {
+            self.log(`QAM root was found in ${iters} recursion cycles`);
+            return currentNode;
+          }
+          if (!currentNode) return null;
+          if (currentNode.sibling) {
+            let node = await findQAMRoot(currentNode.sibling, iters + 1);
+            if (node !== null) return node;
+          }
+          return await findQAMRoot(currentNode, iters + 1);
         }
-        return ret;
-      });
-      this.cNode = scrollRoot;
-      this.cNode.stateNode.forceUpdate();
-      this.log('Finished initial injection');
-    })();
+        (async () => {
+          qAMRoot = await findQAMRoot(tree, 0);
+          while (!qAMRoot) {
+            this.error(
+              'Failed to find QAM root node, reattempting in 5 seconds. A developer may need to increase the recursion limit.',
+            );
+            await sleep(5000);
+            qAMRoot = await findQAMRoot(tree, 0);
+          }
+
+          while (!qAMRoot?.stateNode?.forceUpdate) {
+            qAMRoot = qAMRoot.return;
+          }
+          qAMRoot.stateNode.shouldComponentUpdate = () => true;
+          qAMRoot.stateNode.forceUpdate();
+          delete qAMRoot.stateNode.shouldComponentUpdate;
+        })();
+      } catch (e) {
+        this.log('Failed to rerender QAM', e);
+      }
   }
 
   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();
+    Array.prototype.filter = this.oFilter;
   }
 
   add(tab: Tab) {
@@ -136,13 +106,14 @@ class TabsHook extends Logger {
     this.tabs = this.tabs.filter((tab) => tab.id !== id);
   }
 
-  render(existingTabs: any[], visible: boolean) {
+  render(existingTabs: any[]) {
     for (const { title, icon, content, id } of this.tabs) {
       existingTabs.push({
         key: id,
         title,
         tab: icon,
-        panel: <QuickAccessVisibleStateProvider visible={visible}>{content}</QuickAccessVisibleStateProvider>,
+        decky: true,
+        panel: <QuickAccessVisibleStateProvider>{content}</QuickAccessVisibleStateProvider>,
       });
     }
   }
-- 
cgit v1.2.3

