summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxXJSONDeruloXx <danielhimebauch@gmail.com>2025-01-31 22:54:15 -0500
committerxXJSONDeruloXx <danielhimebauch@gmail.com>2025-01-31 22:54:15 -0500
commit77d4d13a06cddc879d238d5cc89e47608d633921 (patch)
tree91fdbaf916ea9f403b0285e47b1315af25893acb
parentf65cee80a47f093dbdc51fc26ace8d92b99b4f07 (diff)
downloadDecky-Framegen-77d4d13a06cddc879d238d5cc89e47608d633921.tar.gz
Decky-Framegen-77d4d13a06cddc879d238d5cc89e47608d633921.zip
Feat: initial dropdown menu implementation
-rwxr-xr-xsrc/index.tsx101
1 files changed, 59 insertions, 42 deletions
diff --git a/src/index.tsx b/src/index.tsx
index 52c3128..8c48ad5 100755
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -3,7 +3,7 @@ import {
PanelSection,
PanelSectionRow,
ButtonItem,
- // Router
+ DropdownItem
} from "@decky/ui";
import { definePlugin, callable } from "@decky/api";
import { RiAiGenerate } from "react-icons/ri";
@@ -164,25 +164,21 @@ function FGModInstallerSection() {
function InstalledGamesSection() {
const [games, setGames] = useState<{ appid: number; name: string }[]>([]);
- const [clickedGame, setClickedGame] = useState<{ appid: number; name: string } | null>(null);
+ const [selectedGame, setSelectedGame] = useState<{ appid: number; name: string } | null>(null);
const [result, setResult] = useState<string>('');
useEffect(() => {
const fetchGames = async () => {
try {
const response = await listInstalledGames();
- console.log("listInstalledGames response:", response);
if (response.status === "success") {
const sortedGames = [...response.games]
.map(game => ({
...game,
- appid: parseInt(game.appid, 10), // Convert string to number
+ appid: parseInt(game.appid, 10),
}))
.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
- console.log("Fetched games successfully:", sortedGames.length);
setGames(sortedGames);
- } else {
- console.error("Failed to fetch games:", response);
}
} catch (error) {
console.error("Error fetching games:", error);
@@ -192,64 +188,85 @@ function InstalledGamesSection() {
fetchGames();
}, []);
- const handlePatchClick = async (game: { appid: number; name: string }) => {
- setClickedGame(game);
+ const handlePatchClick = async () => {
+ if (!selectedGame) return;
+
try {
- await SteamClient.Apps.SetAppLaunchOptions(game.appid, '~/fgmod/fgmod %COMMAND%');
- setResult(`Launch options set successfully for ${game.name}. You can now select DLSS in the game's menu to use FSR Upscaling and FrameGen equivalents.`);
+ await SteamClient.Apps.SetAppLaunchOptions(selectedGame.appid, '~/fgmod/fgmod %COMMAND%');
+ setResult(`Launch options set successfully for ${selectedGame.name}. You can now select DLSS in the game's menu to use FSR Upscaling and FrameGen equivalents.`);
} catch (error) {
- if (error instanceof Error) {
- setResult(`Error setting launch options: ${error.message}`);
- } else {
- setResult('Error setting launch options');
- }
+ setResult(error instanceof Error ? `Error setting launch options: ${error.message}` : 'Error setting launch options');
}
};
- const handleUnpatchClick = async (game: { appid: number; name: string }) => {
- setClickedGame(game);
+ const handleUnpatchClick = async () => {
+ if (!selectedGame) return;
+
try {
- await SteamClient.Apps.SetAppLaunchOptions(game.appid, '~/fgmod/fgmod-uninstaller.sh %COMMAND%');
- setResult(`DLSS mods will uninstall on next launch of ${game.name}. The game is now unpatched.`);
+ await SteamClient.Apps.SetAppLaunchOptions(selectedGame.appid, '~/fgmod/fgmod-uninstaller.sh %COMMAND%');
+ setResult(`DLSS mods will uninstall on next launch of ${selectedGame.name}. The game is now unpatched.`);
} catch (error) {
- if (error instanceof Error) {
- setResult(`Error clearing launch options: ${error.message}`);
- } else {
- setResult('Error clearing launch options');
- }
+ setResult(error instanceof Error ? `Error clearing launch options: ${error.message}` : 'Error clearing launch options');
}
};
return (
- <PanelSection title="Select a game below to patch or unpatch:">
- {games.map((game) => (
- <PanelSectionRow key={game.appid}>
- <div style={{ marginBottom: '16px' }}>
- {/* Game Name as Bold Subheader */}
- <div style={{ fontWeight: 'bold', marginBottom: '8px' }}>{game.name}</div>
- {/* Buttons Stacked Vertically */}
- <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
+ <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>
+
+ {selectedGame && (
+ <>
+ <PanelSectionRow>
+ <div style={{ fontWeight: 'bold', fontSize: '1.1em' }}>
+ {selectedGame.name}
+ </div>
+ </PanelSectionRow>
+ <PanelSectionRow>
+ <div style={{ display: 'flex', gap: '16px', marginTop: '12px' }}>
<ButtonItem
layout="below"
- onClick={() => handlePatchClick(game)}
+ onClick={handlePatchClick}
>
Patch
</ButtonItem>
<ButtonItem
layout="below"
- onClick={() => handleUnpatchClick(game)}
+ onClick={handleUnpatchClick}
>
Unpatch
</ButtonItem>
</div>
+ </PanelSectionRow>
+ </>
+ )}
+
+ {result && (
+ <PanelSectionRow>
+ <div style={{
+ padding: '12px',
+ marginTop: '16px',
+ backgroundColor: 'var(--decky-selected-ui-bg)',
+ borderRadius: '4px'
+ }}>
+ {result}
</div>
- {clickedGame?.appid === game.appid && (
- <div style={{ padding: '8px', marginTop: '8px' }}>
- {result}
- </div>
- )}
</PanelSectionRow>
- ))}
+ )}
</PanelSection>
);
}
@@ -257,7 +274,7 @@ function InstalledGamesSection() {
export default definePlugin(() => ({
name: "Framegen Plugin",
titleView: <div>Decky Framegen</div>,
- alwaysRender: false,
+ alwaysRender: true,
content: (
<>
<FGModInstallerSection />