summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxXJSONDeruloXx <danielhimebauch@gmail.com>2026-09-11 09:38:35 -0400
committerxXJSONDeruloXx <danielhimebauch@gmail.com>2026-09-11 09:38:35 -0400
commita8388009b2ba141caafe7f2e35f7029d93e7811f (patch)
tree2f939dba1042a1d1d9c03e4aa3470ad6332864e2 /src
parent9138886fd5315eb0e8c6a4a549a9d44f93ba3cde (diff)
downloaddecky-lsfg-vk-a8388009b2ba141caafe7f2e35f7029d93e7811f.tar.gz
decky-lsfg-vk-a8388009b2ba141caafe7f2e35f7029d93e7811f.zip
handle edge cases on flatpaks and ordering
Diffstat (limited to 'src')
-rw-r--r--src/components/CollapsibleItemGroup.tsx20
-rw-r--r--src/components/Content.tsx2
-rw-r--r--src/components/FlatpakTab.tsx24
-rw-r--r--src/components/GameConfigurationSelector.tsx22
-rw-r--r--src/hooks/useFlatpakConfiguration.ts4
-rw-r--r--src/utils/nowPlaying.ts31
6 files changed, 45 insertions, 58 deletions
diff --git a/src/components/CollapsibleItemGroup.tsx b/src/components/CollapsibleItemGroup.tsx
index a66a8ba..037b34f 100644
--- a/src/components/CollapsibleItemGroup.tsx
+++ b/src/components/CollapsibleItemGroup.tsx
@@ -1,5 +1,5 @@
import { ButtonItem, Field, PanelSectionRow } from "@decky/ui";
-import { type RefObject } from "react";
+import { useEffect, useState, type RefObject } from "react";
import { RiArrowDownSFill, RiArrowUpSFill } from "react-icons/ri";
export interface CollapsibleItem {
@@ -25,6 +25,24 @@ export const collapsibleItemGroupStyles = `
}
`;
+export 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;
+}
+
interface Props {
title: string;
items: CollapsibleItem[];
diff --git a/src/components/Content.tsx b/src/components/Content.tsx
index dc8c54f..422eec8 100644
--- a/src/components/Content.tsx
+++ b/src/components/Content.tsx
@@ -86,7 +86,7 @@ export function Content() {
const hasNowPlaying = Boolean(nowPlayingTarget);
const runningWorkload = nowPlayingTarget
? nowPlayingTarget.kind === "flatpak"
- ? `flatpak:${nowPlayingTarget.app.app_id}`
+ ? `flatpak:${nowPlayingTarget.app.app_id}:${nowPlayingTarget.launcher?.appid ?? ""}`
: `steam:${nowPlayingTarget.game.appid}`
: null;
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<HTMLDivElement>(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}
/>
<CollapsibleItemGroup
title="Available"
diff --git a/src/components/GameConfigurationSelector.tsx b/src/components/GameConfigurationSelector.tsx
index ee87423..2c683ae 100644
--- a/src/components/GameConfigurationSelector.tsx
+++ b/src/components/GameConfigurationSelector.tsx
@@ -1,7 +1,7 @@
import { ButtonItem, ConfirmModal, Field, PanelSectionRow, showModal } from "@decky/ui";
-import { useEffect, useRef, useState } from "react";
+import { useEffect, useRef } from "react";
import { GameTarget } from "../hooks/useGameConfiguration";
-import { CollapsibleItemGroup, collapsibleItemGroupStyles } from "./CollapsibleItemGroup";
+import { CollapsibleItemGroup, collapsibleItemGroupStyles, usePersistentCollapsed } from "./CollapsibleItemGroup";
interface Props {
targets: GameTarget[];
@@ -16,24 +16,6 @@ interface Props {
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 {}
- }, [collapsed, key]);
-
- return [collapsed, () => setCollapsed((value) => !value)] as const;
-}
-
function targetDescription(game: GameTarget): string {
return game.nonSteam ? "Non-Steam" : "Steam";
}
diff --git a/src/hooks/useFlatpakConfiguration.ts b/src/hooks/useFlatpakConfiguration.ts
index ce881f0..6ff7a79 100644
--- a/src/hooks/useFlatpakConfiguration.ts
+++ b/src/hooks/useFlatpakConfiguration.ts
@@ -120,9 +120,7 @@ export function useFlatpakConfiguration(enabled: boolean) {
[operate],
);
- const runningApp = useMemo(() => {
- return selectMostRecentRunningFlatpak(apps, runningApps);
- }, [apps, runningApps]);
+ const runningApp = useMemo(() => selectMostRecentRunningFlatpak(apps, runningApps), [apps, runningApps]);
return {
apps,
diff --git a/src/utils/nowPlaying.ts b/src/utils/nowPlaying.ts
index a207321..2e0a876 100644
--- a/src/utils/nowPlaying.ts
+++ b/src/utils/nowPlaying.ts
@@ -29,25 +29,34 @@ export function selectMostRecentRunningFlatpak(
running,
app: apps.find((app) => app.app_id === running.app_id) || null,
}))
- .filter((candidate): candidate is { running: RunningFlatpakApp; app: FlatpakApp } => candidate.app !== null)
- .sort((a, b) => {
- if (a.running.active !== b.running.active) return a.running.active ? -1 : 1;
- const startDifference = numericValue(b.running.start_time) - numericValue(a.running.start_time);
- if (startDifference !== 0) return startDifference;
- const pidDifference = numericPid(b.running.pid) - numericPid(a.running.pid);
- if (pidDifference !== 0) return pidDifference;
- return a.running.app_id.localeCompare(b.running.app_id);
- });
+ .filter((candidate): candidate is { running: RunningFlatpakApp; app: FlatpakApp } => candidate.app !== null);
+ const activeCandidates = candidates.filter(({ running }) => running.active);
+ const eligibleCandidates = activeCandidates.length > 0
+ ? activeCandidates
+ : candidates.length === 1
+ ? candidates
+ : [];
- return candidates[0]?.app || null;
+ eligibleCandidates.sort((a, b) => {
+ const startDifference = numericValue(b.running.start_time) - numericValue(a.running.start_time);
+ if (startDifference !== 0) return startDifference;
+ const pidDifference = numericPid(b.running.pid) - numericPid(a.running.pid);
+ if (pidDifference !== 0) return pidDifference;
+ return a.running.app_id.localeCompare(b.running.app_id);
+ });
+
+ return eligibleCandidates[0]?.app || null;
}
export function resolveNowPlayingTarget(
runningGame: GameTarget | null,
runningFlatpak: FlatpakApp | null,
): NowPlayingTarget | null {
+ if (runningGame && !runningGame.nonSteam) {
+ return runningGame.configured ? { kind: "steam", game: runningGame } : null;
+ }
if (runningFlatpak) {
- return { kind: "flatpak", app: runningFlatpak, launcher: runningGame };
+ return { kind: "flatpak", app: runningFlatpak, launcher: runningGame?.nonSteam ? runningGame : null };
}
if (runningGame?.configured) return { kind: "steam", game: runningGame };
return null;