From 7d2322e637faae5ccfab58c54f7a13e6a5f7ea88 Mon Sep 17 00:00:00 2001
From: xXJSONDeruloXx <danielhimebauch@gmail.com>
Date: Fri, 26 Sep 2025 12:16:22 -0400
Subject: feat: first arg steam path start, second mirror first

---
 src/components/CustomPathOverride.tsx | 146 +++++++++++++++++++++++++++++-----
 1 file changed, 126 insertions(+), 20 deletions(-)

(limited to 'src/components/CustomPathOverride.tsx')

diff --git a/src/components/CustomPathOverride.tsx b/src/components/CustomPathOverride.tsx
index 9e7d34b..9915efc 100644
--- a/src/components/CustomPathOverride.tsx
+++ b/src/components/CustomPathOverride.tsx
@@ -1,6 +1,7 @@
 import { useCallback, useEffect, useMemo, useState } from "react";
 import { ButtonItem, Field, PanelSectionRow, ToggleField } from "@decky/ui";
 import { FileSelectionType, openFilePicker } from "@decky/api";
+import { getPathDefaults } from "../api";
 import type { CustomOverrideConfig } from "../types/index";
 
 interface CustomPathOverrideProps {
@@ -8,9 +9,23 @@ interface CustomPathOverrideProps {
 }
 
 const DEFAULT_START_PATH = "/home";
+const DEFAULT_STEAM_LIBRARY_PATH = "/home/deck/.local/share/Steam/steamapps/common";
+
+interface PathDefaults {
+  home: string;
+  steamCommon: string;
+}
+
+const INITIAL_PATH_DEFAULTS: PathDefaults = {
+  home: DEFAULT_START_PATH,
+  steamCommon: DEFAULT_STEAM_LIBRARY_PATH,
+};
 
 const normalizePath = (path: string) => path.replace(/\\/g, "/");
 
+const stripTrailingSlash = (value: string) =>
+  value.endsWith("/") ? value.slice(0, -1) : value;
+
 const escapeForDoubleQuotes = (value: string) =>
   value.replace(/[`"\\$]/g, (match) => `\\${match}`);
 
@@ -31,6 +46,14 @@ const escapeForReplacement = (value: string) =>
 
 const quoteForShell = (value: string) => `'${value.replace(/'/g, "'\\''")}'`;
 
+const dirname = (path: string) => {
+  const normalized = normalizePath(path);
+  const parts = normalized.split("/");
+  parts.pop();
+  const dir = parts.join("/");
+  return dir.length > 0 ? dir : "/";
+};
+
 const longestCommonPrefix = (left: string[], right: string[]) => {
   const length = Math.min(left.length, right.length);
   let idx = 0;
@@ -129,6 +152,40 @@ export const CustomPathOverride = ({ onOverrideChange }: CustomPathOverrideProps
   const [launcherPath, setLauncherPath] = useState<string | null>(null);
   const [overridePath, setOverridePath] = useState<string | null>(null);
   const [isEnabled, setEnabled] = useState(false);
+  const [pathDefaults, setPathDefaults] = useState<PathDefaults>(INITIAL_PATH_DEFAULTS);
+
+  useEffect(() => {
+    let cancelled = false;
+
+    const fetchDefaults = async () => {
+      try {
+        const result = await getPathDefaults();
+        if (!result) {
+          return;
+        }
+
+        const home = result.home ? normalizePath(result.home) : INITIAL_PATH_DEFAULTS.home;
+        const steamCommonSource = result.steam_common
+          ? normalizePath(result.steam_common)
+          : normalizePath(`${stripTrailingSlash(home)}/.local/share/Steam/steamapps/common`);
+
+        if (!cancelled) {
+          setPathDefaults({
+            home,
+            steamCommon: steamCommonSource || INITIAL_PATH_DEFAULTS.steamCommon,
+          });
+        }
+      } catch (err) {
+        console.error("CustomPathOverride -> getPathDefaults", err);
+      }
+    };
+
+    fetchDefaults();
+
+    return () => {
+      cancelled = true;
+    };
+  }, []);
 
   const { config, error } = useMemo(
     () => buildOverride(launcherPath, overridePath),
@@ -143,27 +200,58 @@ export const CustomPathOverride = ({ onOverrideChange }: CustomPathOverrideProps
     }
   }, [config, isEnabled, onOverrideChange]);
 
+  interface PickerArgs {
+    existing: string | null;
+    setter: (value: string) => void;
+    fallbackStart?: string | null;
+  }
+
   const openPicker = useCallback(
-    async (existing: string | null, setter: (value: string) => void) => {
-      try {
-        const startPath = existing ? normalizePath(existing) : DEFAULT_START_PATH;
-        const result = await openFilePicker(
-          FileSelectionType.FILE,
-          startPath,
-          true,
-          false,
-          undefined,
-          undefined,
-          true
-        );
-        if (result?.path) {
-          setter(normalizePath(result.path));
+    async ({ existing, setter, fallbackStart }: PickerArgs) => {
+      const candidates = new Set<string>();
+
+      if (existing) {
+        candidates.add(normalizePath(existing));
+      } else {
+        if (fallbackStart) {
+          candidates.add(normalizePath(fallbackStart));
         }
-      } catch (err) {
-        console.error("CustomPathOverride -> openPicker", err);
+        candidates.add(pathDefaults.steamCommon);
+        candidates.add(pathDefaults.home);
+      }
+
+      let lastError: unknown = null;
+
+      for (const candidate of candidates) {
+        if (!candidate) {
+          continue;
+        }
+
+        try {
+          const result = await openFilePicker(
+            FileSelectionType.FILE,
+            candidate,
+            true,
+            true,
+            undefined,
+            undefined,
+            true
+          );
+
+          if (result?.path) {
+            setter(normalizePath(result.path));
+            return;
+          }
+        } catch (err) {
+          lastError = err;
+        }
+      }
+
+      if (lastError) {
+        console.error("CustomPathOverride -> openPicker", lastError);
       }
     },
-    []
+    [pathDefaults]
   );
 
   const handleToggle = (value: boolean) => {
@@ -193,7 +281,13 @@ export const CustomPathOverride = ({ onOverrideChange }: CustomPathOverrideProps
           <PanelSectionRow>
             <ButtonItem
               layout="below"
-              onClick={() => openPicker(launcherPath, setLauncherPath)}
+              onClick={() =>
+                openPicker({
+                  existing: launcherPath,
+                  setter: setLauncherPath,
+                  fallbackStart: pathDefaults.steamCommon,
+                })
+              }
               description={launcherPath || "Pick the EXE Steam currently uses."}
             >
               Select Steam-provided EXE
@@ -203,8 +297,20 @@ export const CustomPathOverride = ({ onOverrideChange }: CustomPathOverrideProps
           <PanelSectionRow>
             <ButtonItem
               layout="below"
-              onClick={() => openPicker(overridePath, setOverridePath)}
-              description={overridePath || "Pick the executable that should run instead."}
+              disabled={!launcherPath}
+              onClick={() =>
+                launcherPath &&
+                openPicker({
+                  existing: overridePath,
+                  setter: setOverridePath,
+                  fallbackStart: launcherPath ? dirname(launcherPath) : pathDefaults.steamCommon,
+                })
+              }
+              description={
+                launcherPath
+                  ? overridePath || "Pick the executable that should run instead."
+                  : "Select the Steam-provided executable first."
+              }
             >
               Select Override EXE
             </ButtonItem>
-- 
cgit v1.2.3

