summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com>2025-08-18 12:55:03 -0400
committerGitHub <noreply@github.com>2025-08-18 12:55:03 -0400
commitab89907bc2ac11fc9760297a0ae0720b7cb3469a (patch)
tree91c2f9498c94411891f24bb1b934de0b1984be0d /src
parent3d75e193791c18b1a0bcde5c8e80bdc24492c031 (diff)
parent687d017c02d5a7dc37fde941c583ff74d8dd6363 (diff)
downloaddecky-lsfg-vk-ab89907bc2ac11fc9760297a0ae0720b7cb3469a.tar.gz
decky-lsfg-vk-ab89907bc2ac11fc9760297a0ae0720b7cb3469a.zip
Merge pull request #145 from xXJSONDeruloXx/feat/detect-running-gamev0.10.4
lock profile selection if game is running
Diffstat (limited to 'src')
-rw-r--r--src/components/ConfigurationSection.tsx16
-rw-r--r--src/components/Content.tsx57
-rw-r--r--src/components/ProfileManagement.tsx175
3 files changed, 180 insertions, 68 deletions
diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx
index 92d1867..c14a2fd 100644
--- a/src/components/ConfigurationSection.tsx
+++ b/src/components/ConfigurationSection.tsx
@@ -52,22 +52,6 @@ export function ConfigurationSection({
`}
</style>
- <PanelSectionRow>
- <div
- style={{
- fontSize: "14px",
- fontWeight: "bold",
- marginTop: "16px",
- marginBottom: "16px",
- borderBottom: "1px solid rgba(255, 255, 255, 0.2)",
- paddingBottom: "4px",
- color: "white"
- }}
- >
- LSFG Configuration
- </div>
- </PanelSectionRow>
-
{/* FPS Multiplier */}
<FpsMultiplierControl config={config} onConfigChange={onConfigChange} />
diff --git a/src/components/Content.tsx b/src/components/Content.tsx
index 7815951..e0adf3f 100644
--- a/src/components/Content.tsx
+++ b/src/components/Content.tsx
@@ -76,20 +76,25 @@ export function Content() {
return (
<PanelSection>
- <InstallationButton
- isInstalled={isInstalled}
- isInstalling={isInstalling}
- isUninstalling={isUninstalling}
- onInstall={onInstall}
- onUninstall={onUninstall}
- />
-
- <StatusDisplay
- dllDetected={dllDetected}
- dllDetectionStatus={dllDetectionStatus}
- isInstalled={isInstalled}
- installationStatus={installationStatus}
- />
+ {/* Show installation components at top when not fully installed */}
+ {!isInstalled && (
+ <>
+ <InstallationButton
+ isInstalled={isInstalled}
+ isInstalling={isInstalling}
+ isUninstalling={isUninstalling}
+ onInstall={onInstall}
+ onUninstall={onUninstall}
+ />
+
+ <StatusDisplay
+ dllDetected={dllDetected}
+ dllDetectionStatus={dllDetectionStatus}
+ isInstalled={isInstalled}
+ installationStatus={installationStatus}
+ />
+ </>
+ )}
<SmartClipboardButton />
@@ -118,7 +123,29 @@ export function Content() {
<ClipboardButton />
{/* Plugin Update Checker */}
- <PluginUpdateChecker /> {/* Nerd Stuff Button */}
+ <PluginUpdateChecker />
+
+ {/* Show installation components at bottom when fully installed */}
+ {isInstalled && (
+ <>
+ <InstallationButton
+ isInstalled={isInstalled}
+ isInstalling={isInstalling}
+ isUninstalling={isUninstalling}
+ onInstall={onInstall}
+ onUninstall={onUninstall}
+ />
+
+ <StatusDisplay
+ dllDetected={dllDetected}
+ dllDetectionStatus={dllDetectionStatus}
+ isInstalled={isInstalled}
+ installationStatus={installationStatus}
+ />
+ </>
+ )}
+
+ {/* Nerd Stuff Button */}
<PanelSectionRow>
<ButtonItem
layout="below"
diff --git a/src/components/ProfileManagement.tsx b/src/components/ProfileManagement.tsx
index 67f0645..6e2a8f8 100644
--- a/src/components/ProfileManagement.tsx
+++ b/src/components/ProfileManagement.tsx
@@ -1,6 +1,5 @@
import { useState, useEffect } from "react";
import {
- PanelSection,
PanelSectionRow,
Dropdown,
DropdownOption,
@@ -11,8 +10,11 @@ import {
ButtonItem,
ModalRoot,
TextField,
- Focusable
+ Focusable,
+ AppOverview,
+ Router
} from "@decky/ui";
+import { RiArrowDownSFill, RiArrowUpSFill } from "react-icons/ri";
import {
getProfiles,
createProfile,
@@ -24,10 +26,7 @@ import {
} from "../api/lsfgApi";
import { showSuccessToast, showErrorToast } from "../utils/toastUtils";
-interface ProfileManagementProps {
- currentProfile?: string;
- onProfileChange?: (profileName: string) => void;
-}
+const PROFILES_COLLAPSED_KEY = 'lsfg-profiles-collapsed';
interface TextInputModalProps {
title: string;
@@ -110,6 +109,26 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa
const [profiles, setProfiles] = useState<string[]>([]);
const [selectedProfile, setSelectedProfile] = useState<string>(currentProfile || "decky-lsfg-vk");
const [isLoading, setIsLoading] = useState(false);
+ const [mainRunningApp, setMainRunningApp] = useState<AppOverview | undefined>(undefined);
+
+ // Initialize with localStorage value, fallback to false (expanded) if not found
+ const [profilesCollapsed, setProfilesCollapsed] = useState(() => {
+ try {
+ const saved = localStorage.getItem(PROFILES_COLLAPSED_KEY);
+ return saved !== null ? JSON.parse(saved) : false;
+ } catch {
+ return false;
+ }
+ });
+
+ // Persist profiles collapse state to localStorage
+ useEffect(() => {
+ try {
+ localStorage.setItem(PROFILES_COLLAPSED_KEY, JSON.stringify(profilesCollapsed));
+ } catch (error) {
+ console.warn('Failed to save profiles collapse state:', error);
+ }
+ }, [profilesCollapsed]);
// Load profiles on component mount
useEffect(() => {
@@ -123,6 +142,22 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa
}
}, [currentProfile]);
+ // Poll for running app every 2 seconds
+ useEffect(() => {
+ const checkRunningApp = () => {
+ setMainRunningApp(Router.MainRunningApp);
+ };
+
+ // Check immediately
+ checkRunningApp();
+
+ // Set up polling interval
+ const interval = setInterval(checkRunningApp, 2000);
+
+ // Cleanup interval on unmount
+ return () => clearInterval(interval);
+ }, []);
+
const loadProfiles = async () => {
try {
const result: ProfilesResult = await getProfiles();
@@ -300,41 +335,107 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa
];
return (
- <PanelSection title="Select Profile">
- <PanelSectionRow>
- <Field
- label=""
- childrenLayout="below"
- childrenContainerWidth="max"
- >
- <Dropdown
- rgOptions={profileOptions}
- selectedOption={selectedProfile}
- onChange={handleDropdownChange}
- disabled={isLoading}
- />
- </Field>
- </PanelSectionRow>
-
+ <>
+ <style>
+ {`
+ .LSFG_ProfilesCollapseButton_Container > div > div > div > button {
+ height: 10px !important;
+ }
+ .LSFG_ProfilesCollapseButton_Container > div > div > div > div > button {
+ height: 10px !important;
+ }
+ `}
+ </style>
+
+ {/* Display currently running game info - always visible */}
+ {mainRunningApp && (
+ <PanelSectionRow>
+ <div style={{
+ padding: "8px 12px",
+ backgroundColor: "rgba(0, 255, 0, 0.1)",
+ borderRadius: "4px",
+ border: "1px solid rgba(0, 255, 0, 0.3)",
+ fontSize: "13px"
+ }}>
+ <strong>{mainRunningApp.display_name}</strong> running. Close game to change profile.
+ </div>
+ </PanelSectionRow>
+ )}
+
<PanelSectionRow>
- <ButtonItem
- layout="below"
- onClick={handleRenameProfile}
- disabled={isLoading || selectedProfile === "decky-lsfg-vk"}
+ <div
+ style={{
+ fontSize: "14px",
+ fontWeight: "bold",
+ marginTop: "16px",
+ marginBottom: "8px",
+ borderBottom: "1px solid rgba(255, 255, 255, 0.2)",
+ paddingBottom: "4px",
+ color: "white"
+ }}
>
- Rename
- </ButtonItem>
+ Profile: {selectedProfile === "decky-lsfg-vk" ? "Default" : selectedProfile}
+ </div>
</PanelSectionRow>
-
+
<PanelSectionRow>
- <ButtonItem
- layout="below"
- onClick={handleDeleteProfile}
- disabled={isLoading || selectedProfile === "decky-lsfg-vk"}
- >
- Delete
- </ButtonItem>
+ <div className="LSFG_ProfilesCollapseButton_Container">
+ <ButtonItem
+ layout="below"
+ bottomSeparator={profilesCollapsed ? "standard" : "none"}
+ onClick={() => setProfilesCollapsed(!profilesCollapsed)}
+ >
+ {profilesCollapsed ? (
+ <RiArrowDownSFill
+ style={{ transform: "translate(0, -13px)", fontSize: "1.5em" }}
+ />
+ ) : (
+ <RiArrowUpSFill
+ style={{ transform: "translate(0, -12px)", fontSize: "1.5em" }}
+ />
+ )}
+ </ButtonItem>
+ </div>
</PanelSectionRow>
- </PanelSection>
+
+ {!profilesCollapsed && (
+ <>
+ <PanelSectionRow>
+ <Field
+ label=""
+ childrenLayout="below"
+ childrenContainerWidth="max"
+ >
+ <Dropdown
+ rgOptions={profileOptions}
+ selectedOption={selectedProfile}
+ onChange={handleDropdownChange}
+ disabled={isLoading || !!mainRunningApp}
+ />
+ </Field>
+ </PanelSectionRow>
+
+ <PanelSectionRow>
+ <ButtonItem
+ layout="below"
+ onClick={handleRenameProfile}
+ disabled={isLoading || selectedProfile === "decky-lsfg-vk" || !!mainRunningApp}
+ >
+ Rename
+ </ButtonItem>
+ </PanelSectionRow>
+
+ <PanelSectionRow>
+ <ButtonItem
+ layout="below"
+ onClick={handleDeleteProfile}
+ disabled={isLoading || selectedProfile === "decky-lsfg-vk" || !!mainRunningApp}
+ >
+ Delete
+ </ButtonItem>
+ </PanelSectionRow>
+ </>
+ )}
+ </>
);
}