diff options
Diffstat (limited to 'src/index.tsx')
| -rw-r--r--[-rwxr-xr-x] | src/index.tsx | 303 |
1 files changed, 3 insertions, 300 deletions
diff --git a/src/index.tsx b/src/index.tsx index 64dabdb..12150d2 100755..100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,304 +1,7 @@ -import { useState, useEffect } from "react"; -import { - PanelSection, - PanelSectionRow, - ButtonItem, - DropdownItem, - ConfirmModal, - showModal -} from "@decky/ui"; -import { definePlugin, callable } from "@decky/api"; +import { definePlugin } from "@decky/api"; import { RiAiGenerate } from "react-icons/ri"; - -const runInstallFGMod = callable< - [], - { status: string; message?: string; output?: string } ->("run_install_fgmod"); - -const runUninstallFGMod = callable< - [], - { status: string; message?: string; output?: string } ->("run_uninstall_fgmod"); - -const checkFGModPath = callable< - [], - { exists: boolean } ->("check_fgmod_path"); - -const listInstalledGames = callable< - [], - { status: string; games: { appid: string; name: string }[] } ->("list_installed_games"); - -const logError = callable<[string], void>("log_error"); - -function FGModInstallerSection() { - const [installing, setInstalling] = useState(false); - const [uninstalling, setUninstalling] = useState(false); - const [installResult, setInstallResult] = useState<{ - status: string; - output?: string; - message?: string; - } | null>(null); - const [uninstallResult, setUninstallResult] = useState<{ - status: string; - output?: string; - message?: string; - } | null>(null); - const [pathExists, setPathExists] = useState<boolean | null>(null); - - useEffect(() => { - const checkPath = async () => { - try { - const result = await checkFGModPath(); - setPathExists(result.exists); - } catch (e) { - logError('useEffect -> checkPath' + String(e)); - console.error(e); - } - }; - checkPath(); // Initial check - const intervalId = setInterval(checkPath, 3000); // Check every 3 seconds - return () => clearInterval(intervalId); // Cleanup interval on component unmount - }, []); - - useEffect(() => { - if (installResult) { - const timer = setTimeout(() => { - setInstallResult(null); - }, 5000); - return () => clearTimeout(timer); - } - return () => {}; // Ensure a cleanup function is always returned - }, [installResult]); - - useEffect(() => { - if (uninstallResult) { - const timer = setTimeout(() => { - setUninstallResult(null); - }, 5000); - return () => clearTimeout(timer); - } - return () => {}; - }, [uninstallResult]); - - const handleInstallClick = async () => { - try { - setInstalling(true); - const result = await runInstallFGMod(); - setInstalling(false); - setInstallResult(result); - } catch (e) { - logError('handleInstallClick: ' + String(e)); - console.error(e) - } - }; - - const handleUninstallClick = async () => { - try { - setUninstalling(true); - const result = await runUninstallFGMod(); - setUninstalling(false); - setUninstallResult(result); - } catch (e) { - logError('handleUninstallClick' + String(e)); - console.error(e) - } - }; - - return ( - <PanelSection> - {pathExists !== null ? ( - <PanelSectionRow> - <div style={{ color: pathExists ? "green" : "red" }}> - {pathExists ? "OptiScaler Mod Is Installed" : "OptiScaler Mod Not Installed"} - </div> - </PanelSectionRow> - ) : null} - {pathExists === false ? ( - <PanelSectionRow> - <ButtonItem layout="below" onClick={handleInstallClick} disabled={installing}> - {installing ? "Installing..." : "Install OptiScaler FG Mod"} - </ButtonItem> - </PanelSectionRow> - ) : null} - {pathExists === true ? ( - <PanelSectionRow> - <ButtonItem layout="below" onClick={handleUninstallClick} disabled={uninstalling}> - {uninstalling ? "Uninstalling..." : "Uninstall OptiScaler FG Mod"} - </ButtonItem> - </PanelSectionRow> - ) : null} - {installResult ? ( - <PanelSectionRow> - <div> - <strong>Status:</strong>{" "} - {installResult.status === "success" ? "Success" : "Error"} - <br /> - {installResult.output ? ( - <> - <strong>Output:</strong> - <pre style={{ whiteSpace: "pre-wrap" }}>{installResult.output}</pre> - </> - ) : null} - {installResult.message ? ( - <> - <strong>Error:</strong> {installResult.message} - </> - ) : null} - </div> - </PanelSectionRow> - ) : null} - {uninstallResult ? ( - <PanelSectionRow> - <div> - <strong>Status:</strong>{" "} - {uninstallResult.status === "success" ? "Success" : "Error"} - <br /> - {uninstallResult.output ? ( - <> - <strong>Output:</strong> - <pre style={{ whiteSpace: "pre-wrap" }}>{uninstallResult.output}</pre> - </> - ) : null} - {uninstallResult.message ? ( - <> - <strong>Error:</strong> {uninstallResult.message} - </> - ) : null} - </div> - </PanelSectionRow> - ) : null} - <PanelSectionRow> - <div> - Install the OptiScaler-based mod above, then select and patch a game below to enable DLSS replacement with FSR Frame Generation. Map a button to "insert" key to bring up the OptiScaler menu in-game. - </div> - </PanelSectionRow> - </PanelSection> - ); -} - -function InstalledGamesSection() { - const [games, setGames] = useState<{ appid: number; name: string }[]>([]); - const [selectedGame, setSelectedGame] = useState<{ appid: number; name: string } | null>(null); - const [result, setResult] = useState<string>(''); - - useEffect(() => { - const fetchGames = async () => { - try { - const response = await listInstalledGames(); - if (response.status === "success") { - const sortedGames = [...response.games] - .map(game => ({ - ...game, - appid: parseInt(game.appid, 10), - })) - .sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())); - setGames(sortedGames); - } else { - logError('fetchGames: ' + JSON.stringify(response)); - console.error('fetchGames: ' + JSON.stringify(response)); - } - } catch (error) { - logError("Error fetching games:" + String(error)); - console.error("Error fetching games:", String(error)); - } - }; - fetchGames(); - }, []); - - const handlePatchClick = async () => { - if (!selectedGame) return; - - // Show confirmation modal - showModal( - <ConfirmModal - strTitle={`Patch ${selectedGame.name}?`} - strDescription={ - "WARNING: Decky Framegen does not unpatch games when uninstalled. Be sure to unpatch the game or verify the integrity of your game files if you choose to uninstall the plugin or the game has issues." - } - strOKButtonText="Yeah man, I wanna do it" - strCancelButtonText="Cancel" - onOK={async () => { - try { - await SteamClient.Apps.SetAppLaunchOptions(selectedGame.appid, '~/fgmod/fgmod %COMMAND%'); - setResult(`Launch options set for ${selectedGame.name}. You can now select DLSS in the game's menu, and access OptiScaler with Insert key.`); - } catch (error) { - logError('handlePatchClick: ' + String(error)); - setResult(error instanceof Error ? `Error setting launch options: ${error.message}` : 'Error setting launch options'); - } - }} - /> - ); - }; - - const handleUnpatchClick = async () => { - if (!selectedGame) return; - - try { - await SteamClient.Apps.SetAppLaunchOptions(selectedGame.appid, '~/fgmod/fgmod-uninstaller.sh %COMMAND%'); - setResult(`OptiScaler will uninstall on next launch of ${selectedGame.name}.`); - } catch (error) { - logError('handleUnpatchClick: ' + String(error)); - setResult(error instanceof Error ? `Error clearing launch options: ${error.message}` : 'Error clearing launch options'); - } - }; - - return ( - <PanelSection title="Select a game to patch:"> - <PanelSectionRow> - <DropdownItem - rgOptions={games.map(game => ({ - data: game.appid, - label: game.name - }))} - selectedOption={selectedGame?.appid} - onChange={(option) => { - const game = games.find(g => g.appid === option.data); - setSelectedGame(game || null); - setResult(''); - }} - strDefaultLabel="Select a game..." - menuLabel="Installed Games" - /> - </PanelSectionRow> - - {result ? ( - <PanelSectionRow> - <div style={{ - padding: '12px', - marginTop: '16px', - backgroundColor: 'var(--decky-selected-ui-bg)', - borderRadius: '4px' - }}> - {result} - </div> - </PanelSectionRow> - ) : null} - - {selectedGame ? ( - <> - <PanelSectionRow> - <ButtonItem - layout="below" - onClick={handlePatchClick} - > - Patch - </ButtonItem> - </PanelSectionRow> - <PanelSectionRow> - <ButtonItem - layout="below" - onClick={handleUnpatchClick} - > - Unpatch - </ButtonItem> - </PanelSectionRow> - </> - ) : null} - </PanelSection> - ); -} +import { FGModInstallerSection } from "./components/FGModInstallerSection"; +import { InstalledGamesSection } from "./components/InstalledGamesSection"; export default definePlugin(() => ({ name: "Framegen Plugin", |
