From 0b5e71fe916e92ef9ecf7de91ca43371c4bd6d25 Mon Sep 17 00:00:00 2001
From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com>
Date: Tue, 29 Jul 2025 07:53:45 -0700
Subject: wording and layout tweaks (#125)

* wording and layout tweaks

* red in remove button

* reorganize frontend components

* fix ld preload permissions issue for decky 3.1.10

* bump ver
---
 src/components/OptiScalerControls.tsx | 92 +++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 src/components/OptiScalerControls.tsx

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

diff --git a/src/components/OptiScalerControls.tsx b/src/components/OptiScalerControls.tsx
new file mode 100644
index 0000000..7b2db0e
--- /dev/null
+++ b/src/components/OptiScalerControls.tsx
@@ -0,0 +1,92 @@
+import { useState, useEffect } from "react";
+import { PanelSection } from "@decky/ui";
+import { runInstallFGMod, runUninstallFGMod } from "../api";
+import { OperationResult } from "./ResultDisplay";
+import { createAutoCleanupTimer } from "../utils";
+import { TIMEOUTS } from "../utils/constants";
+import { InstallationStatus } from "./InstallationStatus";
+import { OptiScalerHeader } from "./OptiScalerHeader";
+import { ClipboardCommands } from "./ClipboardCommands";
+import { InstructionCard } from "./InstructionCard";
+import { OptiScalerWiki } from "./OptiScalerWiki";
+import { UninstallButton } from "./UninstallButton";
+
+interface OptiScalerControlsProps {
+  pathExists: boolean | null;
+  setPathExists: (exists: boolean | null) => void;
+}
+
+export function OptiScalerControls({ pathExists, setPathExists }: 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);
+
+  useEffect(() => {
+    if (installResult) {
+      return createAutoCleanupTimer(() => setInstallResult(null), TIMEOUTS.resultDisplay);
+    }
+    return () => {}; // Ensure a cleanup function is always returned
+  }, [installResult]);
+
+  useEffect(() => {
+    if (uninstallResult) {
+      return createAutoCleanupTimer(() => setUninstallResult(null), TIMEOUTS.resultDisplay);
+    }
+    return () => {}; // Ensure a cleanup function is always returned
+  }, [uninstallResult]);
+
+  const handleInstallClick = async () => {
+    try {
+      setInstalling(true);
+      const result = await runInstallFGMod();
+      setInstallResult(result);
+      if (result.status === "success") {
+        setPathExists(true);
+      }
+    } catch (e) {
+      console.error(e);
+    } finally {
+      setInstalling(false);
+    }
+  };
+
+  const handleUninstallClick = async () => {
+    try {
+      setUninstalling(true);
+      const result = await runUninstallFGMod();
+      setUninstallResult(result);
+      if (result.status === "success") {
+        setPathExists(false);
+      }
+    } catch (e) {
+      console.error(e);
+    } finally {
+      setUninstalling(false);
+    }
+  };
+
+  return (
+    <PanelSection>
+      <InstallationStatus 
+        pathExists={pathExists}
+        installing={installing}
+        onInstallClick={handleInstallClick}
+      />
+      
+      <OptiScalerHeader pathExists={pathExists} />
+      
+      <ClipboardCommands pathExists={pathExists} />
+      
+      <InstructionCard pathExists={pathExists} />
+      
+      <OptiScalerWiki pathExists={pathExists} />
+      
+      <UninstallButton 
+        pathExists={pathExists}
+        uninstalling={uninstalling}
+        onUninstallClick={handleUninstallClick}
+      />
+    </PanelSection>
+  );
+}
-- 
cgit v1.2.3

