diff options
| author | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2026-09-07 16:02:26 -0400 |
|---|---|---|
| committer | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2026-09-07 16:02:26 -0400 |
| commit | 22db1125238e54b29538102727c36284e122e703 (patch) | |
| tree | 9fb5f2bc5a00256dc811e4dbbd1e963c5492c48c /src/hooks/useGameConfiguration.ts | |
| parent | f48ff4b541b1ef877905bda248459460a943dd6e (diff) | |
| download | decky-lsfg-vk-22db1125238e54b29538102727c36284e122e703.tar.gz decky-lsfg-vk-22db1125238e54b29538102727c36284e122e703.zip | |
feat: refine game discovery and profile UX
Diffstat (limited to 'src/hooks/useGameConfiguration.ts')
| -rw-r--r-- | src/hooks/useGameConfiguration.ts | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/src/hooks/useGameConfiguration.ts b/src/hooks/useGameConfiguration.ts index d279a8c..597edca 100644 --- a/src/hooks/useGameConfiguration.ts +++ b/src/hooks/useGameConfiguration.ts @@ -1,10 +1,36 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useQuickAccessVisible } from "@decky/api"; import { Router } from "@decky/ui"; import { getGameConfigs, getInstalledGames, updateGameConfig, resetGameConfig, resetAllGameConfigs, type GameConfigEntry, type GlobalConfig, type InstalledGame } from "../api/lsfgApi"; import { ConfigurationData, getDefaults } from "../config/configSchema"; +import { showErrorToast } from "../utils/toastUtils"; export interface GameTarget extends InstalledGame { configured: boolean; } +async function getSteamShortcuts(): Promise<InstalledGame[]> { + const apps = (globalThis as any).SteamClient?.Apps; + if (typeof apps?.GetAllShortcuts !== "function") return []; + + try { + const shortcuts = await apps.GetAllShortcuts(); + if (!Array.isArray(shortcuts)) return []; + return shortcuts.flatMap((shortcut: any) => { + const appid = Number(shortcut?.appid); + const name = shortcut?.data?.strAppName; + if (!Number.isInteger(appid) || appid === 0 || typeof name !== "string" || !name) return []; + return [{ appid: String(appid >>> 0), name, nonSteam: true }]; + }); + } catch { + return []; + } +} + +function mergeInstalledGames(backendGames: InstalledGame[], shortcutGames: InstalledGame[]) { + const games = new Map(backendGames.map((game) => [game.appid, game])); + for (const game of shortcutGames) games.set(game.appid, game); + return Array.from(games.values()); +} + export function useGameConfiguration() { const [games, setGames] = useState<GameConfigEntry[]>([]); const [globalConfig, setGlobalConfig] = useState<GlobalConfig>({ dll: "", no_fp16: false }); @@ -13,18 +39,25 @@ export function useGameConfiguration() { const [selectedAppId, setSelectedAppId] = useState(""); const [runningGame, setRunningGame] = useState<GameTarget | null>(null); const previousRunningAppId = useRef<string | null>(null); + const previousQuickAccessVisible = useRef<boolean | null>(null); + const quickAccessVisible = useQuickAccessVisible(); const load = useCallback(async () => { - const [result, installed] = await Promise.all([getGameConfigs(), getInstalledGames()]); + const [result, installed, shortcuts] = await Promise.all([getGameConfigs(), getInstalledGames(), getSteamShortcuts()]); if (result.success) { setGlobalConfig(result.global_config || { dll: "", no_fp16: false }); setGames(result.games || []); } - if (installed.success) setInstalledGames(installed.games || []); + setInstalledGames(mergeInstalledGames(installed.success ? installed.games || [] : [], shortcuts)); setConfigsLoaded(true); }, []); - useEffect(() => { load(); }, [load]); + useEffect(() => { + const initialLoad = previousQuickAccessVisible.current === null; + const becameVisible = quickAccessVisible && previousQuickAccessVisible.current === false; + previousQuickAccessVisible.current = quickAccessVisible; + if (initialLoad || becameVisible) void load(); + }, [load, quickAccessVisible]); useEffect(() => { const poll = () => { if (!configsLoaded) return; @@ -75,6 +108,18 @@ export function useGameConfiguration() { if (result.success) await load(); return result.success; }, [load, targets, template]); + const enableAll = useCallback(async (): Promise<void> => { + const available = targets.filter((target) => !target.configured && target.name); + if (available.length === 0) return; + for (const target of available) { + const result = await updateGameConfig(target.appid, target.name, template); + if (!result.success) { + showErrorToast("Could not enable all games", result.error || "A game profile could not be created"); + return; + } + } + await load(); + }, [load, targets, template]); const resetSelected = useCallback(async () => { if (selectedAppId) { @@ -95,5 +140,5 @@ export function useGameConfiguration() { } }, [load]); - return { config, games, targets, runningGame, selectedAppId, setSelectedAppId, save, enable, resetSelected, resetAll, reload: load }; + return { config, games, targets, runningGame, selectedAppId, setSelectedAppId, save, enable, enableAll, resetSelected, resetAll, reload: load }; } |
