From 19e5aefa2f41ebd4389bf27136adacf3e75d3502 Mon Sep 17 00:00:00 2001
From: xXJSONDeruloXx <danielhimebauch@gmail.com>
Date: Tue, 19 May 2026 14:26:39 -0400
Subject: feat: add fsr4 runtime manifests

---
 src/components/OptiScalerControls.tsx | 106 +++++++++++++++++++++++++++++++---
 1 file changed, 97 insertions(+), 9 deletions(-)

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

diff --git a/src/components/OptiScalerControls.tsx b/src/components/OptiScalerControls.tsx
index f88e8f9..2167fcd 100644
--- a/src/components/OptiScalerControls.tsx
+++ b/src/components/OptiScalerControls.tsx
@@ -1,9 +1,9 @@
 import { useState, useEffect } from "react";
-import { DropdownItem, PanelSection, PanelSectionRow } from "@decky/ui";
-import { runInstallFGMod, runUninstallFGMod } from "../api";
+import { DropdownItem, Field, PanelSection, PanelSectionRow, ToggleField } from "@decky/ui";
+import { runInstallFGMod, runUninstallFGMod, setDefaultFsr4Variant } from "../api";
 import { OperationResult } from "./ResultDisplay";
 import { createAutoCleanupTimer } from "../utils";
-import { TIMEOUTS, PROXY_DLL_OPTIONS, DEFAULT_PROXY_DLL } from "../utils/constants";
+import { TIMEOUTS, PROXY_DLL_OPTIONS, DEFAULT_PROXY_DLL, FSR4_VARIANT_OPTIONS, DEFAULT_FSR4_VARIANT } from "../utils/constants";
 import { InstallationStatus } from "./InstallationStatus";
 import { OptiScalerHeader } from "./OptiScalerHeader";
 import { ClipboardCommands } from "./ClipboardCommands";
@@ -13,18 +13,31 @@ import { UninstallButton } from "./UninstallButton";
 import { ManualPatchControls } from "./CustomPathOverride";
 import { SteamGamePatcher } from "./SteamGamePatcher";
 
+interface FgmodInfo {
+  exists: boolean;
+  version?: string | null;
+  selected_fsr4_variant?: string | null;
+  selected_fsr4_variant_label?: string | null;
+  install_manifest_present?: boolean;
+}
+
 interface OptiScalerControlsProps {
   pathExists: boolean | null;
   setPathExists: (exists: boolean | null) => void;
+  fgmodInfo?: FgmodInfo | null;
 }
 
-export function OptiScalerControls({ pathExists, setPathExists }: OptiScalerControlsProps) {
+export function OptiScalerControls({ pathExists, setPathExists, fgmodInfo }: OptiScalerControlsProps) {
   const [installing, setInstalling] = useState(false);
   const [uninstalling, setUninstalling] = useState(false);
   const [installResult, setInstallResult] = useState<OperationResult | null>(null);
   const [uninstallResult, setUninstallResult] = useState<OperationResult | null>(null);
-  const [manualModeEnabled, setManualModeEnabled] = useState(false);
+  const [advancedModeEnabled, setAdvancedModeEnabled] = useState(false);
+  const [manualClipboardModeEnabled, setManualClipboardModeEnabled] = useState(false);
   const [dllName, setDllName] = useState<string>(DEFAULT_PROXY_DLL);
+  const [fsr4Variant, setFsr4Variant] = useState<string>(DEFAULT_FSR4_VARIANT);
+  const [fsr4VariantTouched, setFsr4VariantTouched] = useState(false);
+  const [switchingVariant, setSwitchingVariant] = useState(false);
   useEffect(() => {
     if (installResult) {
       return createAutoCleanupTimer(() => setInstallResult(null), TIMEOUTS.resultDisplay);
@@ -39,10 +52,17 @@ export function OptiScalerControls({ pathExists, setPathExists }: OptiScalerCont
     return () => {}; // Ensure a cleanup function is always returned
   }, [uninstallResult]);
 
+  useEffect(() => {
+    const installedVariant = fgmodInfo?.selected_fsr4_variant;
+    if (!fsr4VariantTouched && installedVariant && FSR4_VARIANT_OPTIONS.some((option) => option.value === installedVariant)) {
+      setFsr4Variant(installedVariant);
+    }
+  }, [fgmodInfo?.selected_fsr4_variant, fsr4VariantTouched]);
+
   const handleInstallClick = async () => {
     try {
       setInstalling(true);
-      const result = await runInstallFGMod();
+      const result = await runInstallFGMod(fsr4Variant);
       setInstallResult(result);
       if (result.status === "success") {
         setPathExists(true);
@@ -69,6 +89,31 @@ export function OptiScalerControls({ pathExists, setPathExists }: OptiScalerCont
     }
   };
 
+  const handleFsr4VariantChange = async (nextVariant: string) => {
+    const previousVariant = fsr4Variant;
+    setFsr4Variant(nextVariant);
+    setFsr4VariantTouched(true);
+
+    if (pathExists !== true) return;
+
+    try {
+      setSwitchingVariant(true);
+      const result = await setDefaultFsr4Variant(nextVariant);
+      if (result.status !== "success") {
+        throw new Error(result.message || result.output || "Failed to switch default FSR4 runtime.");
+      }
+      setFsr4Variant(result.selected_default_variant || nextVariant);
+      setFsr4VariantTouched(false);
+    } catch (error) {
+      console.error(error);
+      setFsr4Variant(previousVariant);
+    } finally {
+      setSwitchingVariant(false);
+    }
+  };
+
+  const installedVariantLabel = fgmodInfo?.selected_fsr4_variant_label || FSR4_VARIANT_OPTIONS.find((option) => option.value === fsr4Variant)?.label;
+
   return (
     <PanelSection>
       <InstallationStatus 
@@ -79,6 +124,28 @@ export function OptiScalerControls({ pathExists, setPathExists }: OptiScalerCont
       
       <OptiScalerHeader pathExists={pathExists} />
 
+      <PanelSectionRow>
+        <DropdownItem
+          label="Default FSR4 runtime"
+          description={FSR4_VARIANT_OPTIONS.find((option) => option.value === fsr4Variant)?.hint}
+          menuLabel="Default FSR4 runtime"
+          selectedOption={fsr4Variant}
+          rgOptions={FSR4_VARIANT_OPTIONS.map((option) => ({ data: option.value, label: option.label }))}
+          disabled={installing || uninstalling || switchingVariant}
+          onChange={(option) => {
+            void handleFsr4VariantChange(String(option.data));
+          }}
+        />
+      </PanelSectionRow>
+
+      {pathExists === true && fgmodInfo?.version && installedVariantLabel && (
+        <PanelSectionRow>
+          <Field label="Installed bundle" description={`OptiScaler ${fgmodInfo.version}`}>
+            {installedVariantLabel}
+          </Field>
+        </PanelSectionRow>
+      )}
+
       {pathExists === true && (
         <PanelSectionRow>
           <DropdownItem
@@ -93,18 +160,39 @@ export function OptiScalerControls({ pathExists, setPathExists }: OptiScalerCont
       )}
 
       {pathExists === true && (
-        <SteamGamePatcher dllName={dllName} />
+        <SteamGamePatcher dllName={dllName} fsr4Variant={fsr4Variant} />
       )}
 
       <ClipboardCommands pathExists={pathExists} dllName={dllName} />
 
+      {pathExists === true && (
+        <PanelSectionRow>
+          <ToggleField
+            label="Manual Mode"
+            description="Show wrapper command clipboard buttons for patching and unpatching through ~/fgmod scripts."
+            checked={manualClipboardModeEnabled}
+            onChange={setManualClipboardModeEnabled}
+          />
+        </PanelSectionRow>
+      )}
+
+      {pathExists === true && manualClipboardModeEnabled ? (
+        <ClipboardCommands
+          pathExists={pathExists}
+          dllName={dllName}
+          manualModeEnabled
+          showLaunchOptions={false}
+        />
+      ) : null}
+
       <ManualPatchControls
         isAvailable={pathExists === true}
-        onManualModeChange={setManualModeEnabled}
+        onManualModeChange={setAdvancedModeEnabled}
         dllName={dllName}
+        fsr4Variant={fsr4Variant}
       />
 
-      {!manualModeEnabled && (
+      {!advancedModeEnabled && (
         <InstructionCard pathExists={pathExists} />
       )}
       <OptiScalerWiki pathExists={pathExists} />
-- 
cgit v1.2.3

