From d2bfdafa92f3d31cc5392bf8a5a1f1df5c2358ce Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 11 Sep 2026 09:05:14 -0400 Subject: flatpak correctness, ui alignment, tests --- src/components/FlatpakTab.tsx | 79 +++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 22 deletions(-) (limited to 'src/components/FlatpakTab.tsx') diff --git a/src/components/FlatpakTab.tsx b/src/components/FlatpakTab.tsx index c5e27f5..31bfc2d 100644 --- a/src/components/FlatpakTab.tsx +++ b/src/components/FlatpakTab.tsx @@ -1,7 +1,8 @@ import { ButtonItem, DialogButton, Field, Focusable, PanelSection, PanelSectionRow, gamepadDialogClasses } from "@decky/ui"; -import { useCallback, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { FaArrowLeft } from "react-icons/fa"; import type { FlatpakApp, LsfgConfig, WorkaroundState } from "../api/lsfgApi"; +import { CollapsibleItemGroup, collapsibleItemGroupStyles } from "./CollapsibleItemGroup"; import { ConfigurationSection } from "./ConfigurationSection"; import { FlatpakWorkaroundsSection } from "./FlatpakWorkaroundsSection"; import { FpsMultiplierControl } from "./FpsMultiplierControl"; @@ -19,6 +20,24 @@ interface Props { onWorkaroundChange: (appId: string, state: WorkaroundState) => Promise; } +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 {} + }, [collapsed, key]); + + return [collapsed, () => setCollapsed((value) => !value)] as const; +} + export function FlatpakTab({ apps, runningApp, @@ -36,31 +55,47 @@ export function FlatpakTab({ [apps, selectedAppId], ); const close = useCallback(() => setSelectedAppId(null), []); + const [enabledCollapsed, toggleEnabled] = usePersistentCollapsed("lsfg-flatpak-enabled-collapsed-v1"); + const [availableCollapsed, toggleAvailable] = usePersistentCollapsed("lsfg-flatpak-available-collapsed-v1"); + const enabledToggleRef = useRef(null); + + const enabledApps = useMemo( + () => apps.filter((app) => app.enabled).sort((a, b) => a.app_name.localeCompare(b.app_name)), + [apps], + ); + const availableApps = useMemo( + () => apps.filter((app) => !app.enabled).sort((a, b) => a.app_name.localeCompare(b.app_name)), + [apps], + ); + const itemFor = (app: FlatpakApp) => ({ + id: app.app_id, + label: app.app_name, + description: `${app.app_id} · ${app.prepared && !app.owned ? "Prepared externally" : "Available"}`, + }); if (!selectedAppId) { return ( - {/* - - */} - {apps.map((app) => { - const status = app.enabled - ? app.app_id === runningApp?.app_id ? "Enabled · Running" : "Enabled" - : app.prepared && !app.owned ? "Prepared externally" : "Available"; - return ( - - setSelectedAppId(app.app_id)} - highlightOnFocus - /> - - ); - })} + + ({ + id: app.app_id, + label: app.app_name, + description: `${app.app_id}${app.app_id === runningApp?.app_id ? " · Running" : ""}`, + }))} + collapsed={enabledCollapsed} + onToggle={toggleEnabled} + onSelect={setSelectedAppId} + toggleRef={enabledToggleRef} + /> + {apps.length === 0 && !loading && ( -- cgit v1.2.3 From 9138886fd5315eb0e8c6a4a549a9d44f93ba3cde Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 11 Sep 2026 09:30:30 -0400 Subject: consistent tab collapsed toggles on flatpak --- src/components/FlatpakTab.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/components/FlatpakTab.tsx') diff --git a/src/components/FlatpakTab.tsx b/src/components/FlatpakTab.tsx index 31bfc2d..b46eb28 100644 --- a/src/components/FlatpakTab.tsx +++ b/src/components/FlatpakTab.tsx @@ -20,6 +20,9 @@ interface Props { onWorkaroundChange: (appId: string, state: WorkaroundState) => Promise; } +const ENABLED_COLLAPSED_KEY = "lsfg-flatpak-enabled-collapsed-v2"; +const AVAILABLE_COLLAPSED_KEY = "lsfg-flatpak-available-collapsed-v2"; + function usePersistentCollapsed(key: string) { const [collapsed, setCollapsed] = useState(() => { try { @@ -55,8 +58,8 @@ export function FlatpakTab({ [apps, selectedAppId], ); const close = useCallback(() => setSelectedAppId(null), []); - const [enabledCollapsed, toggleEnabled] = usePersistentCollapsed("lsfg-flatpak-enabled-collapsed-v1"); - const [availableCollapsed, toggleAvailable] = usePersistentCollapsed("lsfg-flatpak-available-collapsed-v1"); + const [enabledCollapsed, toggleEnabled] = usePersistentCollapsed(ENABLED_COLLAPSED_KEY); + const [availableCollapsed, toggleAvailable] = usePersistentCollapsed(AVAILABLE_COLLAPSED_KEY); const enabledToggleRef = useRef(null); const enabledApps = useMemo( -- cgit v1.2.3 From a8388009b2ba141caafe7f2e35f7029d93e7811f Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 11 Sep 2026 09:38:35 -0400 Subject: handle edge cases on flatpaks and ordering --- src/components/FlatpakTab.tsx | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'src/components/FlatpakTab.tsx') diff --git a/src/components/FlatpakTab.tsx b/src/components/FlatpakTab.tsx index b46eb28..0b20da0 100644 --- a/src/components/FlatpakTab.tsx +++ b/src/components/FlatpakTab.tsx @@ -1,8 +1,8 @@ import { ButtonItem, DialogButton, Field, Focusable, PanelSection, PanelSectionRow, gamepadDialogClasses } from "@decky/ui"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { FaArrowLeft } from "react-icons/fa"; import type { FlatpakApp, LsfgConfig, WorkaroundState } from "../api/lsfgApi"; -import { CollapsibleItemGroup, collapsibleItemGroupStyles } from "./CollapsibleItemGroup"; +import { CollapsibleItemGroup, collapsibleItemGroupStyles, usePersistentCollapsed } from "./CollapsibleItemGroup"; import { ConfigurationSection } from "./ConfigurationSection"; import { FlatpakWorkaroundsSection } from "./FlatpakWorkaroundsSection"; import { FpsMultiplierControl } from "./FpsMultiplierControl"; @@ -23,24 +23,6 @@ interface Props { const ENABLED_COLLAPSED_KEY = "lsfg-flatpak-enabled-collapsed-v2"; const AVAILABLE_COLLAPSED_KEY = "lsfg-flatpak-available-collapsed-v2"; -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 {} - }, [collapsed, key]); - - return [collapsed, () => setCollapsed((value) => !value)] as const; -} - export function FlatpakTab({ apps, runningApp, @@ -60,7 +42,6 @@ export function FlatpakTab({ const close = useCallback(() => setSelectedAppId(null), []); const [enabledCollapsed, toggleEnabled] = usePersistentCollapsed(ENABLED_COLLAPSED_KEY); const [availableCollapsed, toggleAvailable] = usePersistentCollapsed(AVAILABLE_COLLAPSED_KEY); - const enabledToggleRef = useRef(null); const enabledApps = useMemo( () => apps.filter((app) => app.enabled).sort((a, b) => a.app_name.localeCompare(b.app_name)), @@ -90,7 +71,6 @@ export function FlatpakTab({ collapsed={enabledCollapsed} onToggle={toggleEnabled} onSelect={setSelectedAppId} - toggleRef={enabledToggleRef} />