import { ButtonItem, ConfirmModal, Field, PanelSectionRow, showModal } from "@decky/ui"; import { useEffect, useRef, useState, type RefObject } from "react"; import { RiArrowDownSFill, RiArrowUpSFill } from "react-icons/ri"; import { GameTarget } from "../hooks/useGameConfiguration"; interface Props { targets: GameTarget[]; runningGame: GameTarget | null; onSelect: (appid: string) => void; onEnableAll: () => Promise; onResetAll: () => Promise; focusConfiguredToggle?: boolean; onConfiguredToggleFocused?: () => void; } const ENABLED_COLLAPSED_KEY = "lsfg-enabled-games-collapsed-v4"; const AVAILABLE_COLLAPSED_KEY = "lsfg-available-games-collapsed-v3"; function usePersistentCollapsed(key: string) { const [collapsed, setCollapsed] = useState(() => { try { return localStorage.getItem(key) !== "false"; } catch { return true; } }); useEffect(() => { try { localStorage.setItem(key, String(collapsed)); } catch { // Persisting the view preference is optional. } }, [collapsed, key]); return [collapsed, () => setCollapsed((value) => !value)] as const; } function targetDescription(game: GameTarget): string { return game.nonSteam ? "Non-Steam" : "Steam"; } function GameGroup({ title, games, collapsed, onToggle, onSelect, toggleRef, }: { title: string; games: GameTarget[]; collapsed: boolean; onToggle: () => void; onSelect: (appid: string) => void; toggleRef?: RefObject; }) { if (games.length === 0) return null; return ( <>
{collapsed ? : }
{!collapsed && games.map((game) => ( onSelect(game.appid)} highlightOnFocus /> ))} ); } export function GameConfigurationSelector({ targets, runningGame, onSelect, onEnableAll, onResetAll, focusConfiguredToggle = false, onConfiguredToggleFocused, }: Props) { const sortGames = (games: GameTarget[]) => [...games].sort((a, b) => { if (a.appid === runningGame?.appid) return -1; if (b.appid === runningGame?.appid) return 1; return a.name.localeCompare(b.name); }); const enabledGames = sortGames(targets.filter((game) => game.configured)); const availableGames = sortGames(targets.filter((game) => !game.configured)); const [enabledCollapsed, toggleEnabled] = usePersistentCollapsed(ENABLED_COLLAPSED_KEY); const [availableCollapsed, toggleAvailable] = usePersistentCollapsed(AVAILABLE_COLLAPSED_KEY); const enabledToggleRef = useRef(null); useEffect(() => { if (!focusConfiguredToggle) return; const frame = requestAnimationFrame(() => { enabledToggleRef.current?.querySelector('[role="button"], button')?.focus(); onConfiguredToggleFocused?.(); }); return () => cancelAnimationFrame(frame); }, [enabledGames.length, focusConfiguredToggle, onConfiguredToggleFocused]); const confirmResetAll = () => { showModal( void onResetAll()} onCancel={() => {}} />, ); }; const confirmEnableAll = () => { showModal( void onEnableAll()} onCancel={() => {}} />, ); }; return ( <> {targets.length === 0 && ( )} {availableGames.length > 0 && ( Enable all available games )} target.configured)} > Remove all profiles ); }