From ad2b182777bfd0a5ceef6e654df75ff13eb8b503 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Sun, 6 Sep 2026 15:08:45 -0400 Subject: refactor: offload configuration to lsfg-vk --- src/hooks/useGameConfiguration.ts | 68 +++++++++++++ src/hooks/useProfileManagement.ts | 194 -------------------------------------- 2 files changed, 68 insertions(+), 194 deletions(-) create mode 100644 src/hooks/useGameConfiguration.ts delete mode 100644 src/hooks/useProfileManagement.ts (limited to 'src/hooks') diff --git a/src/hooks/useGameConfiguration.ts b/src/hooks/useGameConfiguration.ts new file mode 100644 index 0000000..e0ba360 --- /dev/null +++ b/src/hooks/useGameConfiguration.ts @@ -0,0 +1,68 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { Router } from "@decky/ui"; +import { getGameConfigs, getInstalledGames, updateGameConfig, updateLsfgConfig, resetGameConfig, resetAllGameConfigs, type GameConfigEntry, type InstalledGame } from "../api/lsfgApi"; +import { ConfigurationData, getDefaults } from "../config/configSchema"; + +export interface GameTarget { appid: string; name: string; configured: boolean; } + +export function useGameConfiguration() { + const [defaultConfig, setDefaultConfig] = useState(getDefaults()); + const [games, setGames] = useState([]); + const [installedGames, setInstalledGames] = useState([]); + const [selectedAppId, setSelectedAppId] = useState(""); + const [runningGame, setRunningGame] = useState(null); + const autoSelected = useRef(false); + + const load = useCallback(async () => { + const [result, installed] = await Promise.all([getGameConfigs(), getInstalledGames()]); + if (result.success) { + setDefaultConfig(result.default || getDefaults()); + setGames(result.games || []); + } + if (installed.success) setInstalledGames(installed.games || []); + }, []); + + useEffect(() => { load(); }, [load]); + useEffect(() => { + const poll = () => { + const app = Router.MainRunningApp as any; + if (app?.appid) setRunningGame({ appid: String(app.appid), name: app.display_name || `App ${app.appid}`, configured: games.some((game) => game.appid === String(app.appid)) }); + else setRunningGame(null); + }; + poll(); + const interval = window.setInterval(poll, 2000); + return () => window.clearInterval(interval); + }, [games]); + useEffect(() => { + if (!autoSelected.current && runningGame) { + autoSelected.current = true; + setSelectedAppId(runningGame.appid); + } + }, [runningGame]); + + const targets = useMemo(() => { + const configured = installedGames.map((game) => ({ appid: game.appid, name: game.name, configured: games.some((item) => item.appid === game.appid) })); + for (const game of games) if (!configured.some((item) => item.appid === game.appid)) configured.push({ appid: game.appid, name: `App ${game.appid}`, configured: true }); + if (runningGame && !configured.some((game) => game.appid === runningGame.appid)) configured.unshift(runningGame); + return configured; + }, [games, installedGames, runningGame]); + const selected = selectedAppId ? games.find((game) => game.appid === selectedAppId)?.config : defaultConfig; + const config = selected || defaultConfig; + + const save = useCallback(async (next: ConfigurationData) => { + if (!selectedAppId) { + const result = await updateLsfgConfig(next); + if (result.success) setDefaultConfig(next); + return; + } + const result = await updateGameConfig(selectedAppId, next); + if (result.success) await load(); + }, [load, selectedAppId]); + + const resetSelected = useCallback(async () => { + if (selectedAppId) { await resetGameConfig(selectedAppId); setSelectedAppId(""); await load(); } + }, [load, selectedAppId]); + const resetAll = useCallback(async () => { await resetAllGameConfigs(); setSelectedAppId(""); await load(); }, [load]); + + return { config, defaultConfig, games, targets, runningGame, selectedAppId, setSelectedAppId, save, resetSelected, resetAll, reload: load }; +} diff --git a/src/hooks/useProfileManagement.ts b/src/hooks/useProfileManagement.ts deleted file mode 100644 index a5f2a07..0000000 --- a/src/hooks/useProfileManagement.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { - getProfiles, - createProfile, - deleteProfile, - renameProfile, - setCurrentProfile, - updateProfileConfig, - type ProfilesResult, - type ProfileResult, - type ConfigUpdateResult -} from "../api/lsfgApi"; -import { ConfigurationData } from "../config/configSchema"; -import { showSuccessToast, showErrorToast } from "../utils/toastUtils"; - -export function useProfileManagement() { - const [profiles, setProfiles] = useState([]); - const [currentProfile, setCurrentProfileState] = useState("decky-lsfg-vk"); - const [isLoading, setIsLoading] = useState(false); - - // Load profiles on hook initialization - const loadProfiles = useCallback(async () => { - try { - const result: ProfilesResult = await getProfiles(); - if (result.success && result.profiles) { - setProfiles(result.profiles); - if (result.current_profile) { - setCurrentProfileState(result.current_profile); - } - return result; - } else { - console.error("Failed to load profiles:", result.error); - showErrorToast("Failed to load profiles", result.error || "Unknown error"); - return result; - } - } catch (error) { - console.error("Error loading profiles:", error); - showErrorToast("Error loading profiles", String(error)); - return { success: false, error: String(error) }; - } - }, []); - - // Create a new profile - const handleCreateProfile = useCallback(async (profileName: string, sourceProfile?: string) => { - setIsLoading(true); - try { - const result: ProfileResult = await createProfile(profileName, sourceProfile || currentProfile); - if (result.success) { - // Use the normalized name returned from backend (spaces converted to dashes) - const actualProfileName = result.profile_name || profileName; - showSuccessToast("Profile created", `Created profile: ${actualProfileName}`); - await loadProfiles(); - return result; - } else { - console.error("Failed to create profile:", result.error); - showErrorToast("Failed to create profile", result.error || "Unknown error"); - return result; - } - } catch (error) { - console.error("Error creating profile:", error); - showErrorToast("Error creating profile", String(error)); - return { success: false, error: String(error) }; - } finally { - setIsLoading(false); - } - }, [currentProfile, loadProfiles]); - - // Delete a profile - const handleDeleteProfile = useCallback(async (profileName: string) => { - if (profileName === "decky-lsfg-vk") { - showErrorToast("Cannot delete default profile", "The default profile cannot be deleted"); - return { success: false, error: "Cannot delete default profile" }; - } - - setIsLoading(true); - try { - const result: ProfileResult = await deleteProfile(profileName); - if (result.success) { - showSuccessToast("Profile deleted", `Deleted profile: ${profileName}`); - await loadProfiles(); - // If we deleted the current profile, it should have switched to default - if (currentProfile === profileName) { - setCurrentProfileState("decky-lsfg-vk"); - } - return result; - } else { - console.error("Failed to delete profile:", result.error); - showErrorToast("Failed to delete profile", result.error || "Unknown error"); - return result; - } - } catch (error) { - console.error("Error deleting profile:", error); - showErrorToast("Error deleting profile", String(error)); - return { success: false, error: String(error) }; - } finally { - setIsLoading(false); - } - }, [currentProfile, loadProfiles]); - - // Rename a profile - const handleRenameProfile = useCallback(async (oldName: string, newName: string) => { - if (oldName === "decky-lsfg-vk") { - showErrorToast("Cannot rename default profile", "The default profile cannot be renamed"); - return { success: false, error: "Cannot rename default profile" }; - } - - setIsLoading(true); - try { - const result: ProfileResult = await renameProfile(oldName, newName); - if (result.success) { - // Use the normalized name returned from backend (spaces converted to dashes) - const actualNewName = result.profile_name || newName; - showSuccessToast("Profile renamed", `Renamed profile to: ${actualNewName}`); - await loadProfiles(); - // Update current profile if it was renamed - if (currentProfile === oldName) { - setCurrentProfileState(actualNewName); - } - return result; - } else { - console.error("Failed to rename profile:", result.error); - showErrorToast("Failed to rename profile", result.error || "Unknown error"); - return result; - } - } catch (error) { - console.error("Error renaming profile:", error); - showErrorToast("Error renaming profile", String(error)); - return { success: false, error: String(error) }; - } finally { - setIsLoading(false); - } - }, [currentProfile, loadProfiles]); - - // Set the current active profile - const handleSetCurrentProfile = useCallback(async (profileName: string) => { - setIsLoading(true); - try { - const result: ProfileResult = await setCurrentProfile(profileName); - if (result.success) { - setCurrentProfileState(profileName); - showSuccessToast("Profile switched", `Switched to profile: ${profileName}`); - return result; - } else { - console.error("Failed to switch profile:", result.error); - showErrorToast("Failed to switch profile", result.error || "Unknown error"); - return result; - } - } catch (error) { - console.error("Error switching profile:", error); - showErrorToast("Error switching profile", String(error)); - return { success: false, error: String(error) }; - } finally { - setIsLoading(false); - } - }, []); - - // Update configuration for a specific profile - const handleUpdateProfileConfig = useCallback(async (profileName: string, config: ConfigurationData) => { - setIsLoading(true); - try { - const result: ConfigUpdateResult = await updateProfileConfig(profileName, config); - if (result.success) { - return result; - } else { - console.error("Failed to update profile config:", result.error); - showErrorToast("Failed to update profile config", result.error || "Unknown error"); - return result; - } - } catch (error) { - console.error("Error updating profile config:", error); - showErrorToast("Error updating profile config", String(error)); - return { success: false, error: String(error) }; - } finally { - setIsLoading(false); - } - }, [currentProfile]); - - // Initialize profiles on mount - useEffect(() => { - loadProfiles(); - }, [loadProfiles]); - - return { - profiles, - currentProfile, - isLoading, - loadProfiles, - createProfile: handleCreateProfile, - deleteProfile: handleDeleteProfile, - renameProfile: handleRenameProfile, - setCurrentProfile: handleSetCurrentProfile, - updateProfileConfig: handleUpdateProfileConfig - }; -} -- cgit v1.2.3