diff options
| author | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2025-07-13 00:04:54 -0400 |
|---|---|---|
| committer | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2025-07-13 00:04:54 -0400 |
| commit | 77494457e2a4f5c80c3a2f7acb054b12d918d8ad (patch) | |
| tree | fad4c4dd2ce69a850b56078444427866dedce9fa /src/components | |
| parent | 6cfcaa6c169cb8c898775eee276ff2497ab8f45c (diff) | |
| download | decky-lsfg-vk-77494457e2a4f5c80c3a2f7acb054b12d918d8ad.tar.gz decky-lsfg-vk-77494457e2a4f5c80c3a2f7acb054b12d918d8ad.zip | |
restructure for maintainability
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/ConfigurationSection.tsx | 115 | ||||
| -rw-r--r-- | src/components/Content.tsx | 108 | ||||
| -rw-r--r-- | src/components/InstallationButton.tsx | 64 | ||||
| -rw-r--r-- | src/components/StatusDisplay.tsx | 38 | ||||
| -rw-r--r-- | src/components/UsageInstructions.tsx | 68 | ||||
| -rw-r--r-- | src/components/index.ts | 5 |
6 files changed, 398 insertions, 0 deletions
diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx new file mode 100644 index 0000000..707ad2a --- /dev/null +++ b/src/components/ConfigurationSection.tsx @@ -0,0 +1,115 @@ +import { PanelSectionRow, ToggleField, SliderField } from "@decky/ui"; + +interface LsfgConfig { + enableLsfg: boolean; + multiplier: number; + flowScale: number; + hdr: boolean; + perfMode: boolean; + immediateMode: boolean; +} + +interface ConfigurationSectionProps { + config: LsfgConfig; + onEnableLsfgChange: (value: boolean) => Promise<void>; + onMultiplierChange: (value: number) => Promise<void>; + onFlowScaleChange: (value: number) => Promise<void>; + onHdrChange: (value: boolean) => Promise<void>; + onPerfModeChange: (value: boolean) => Promise<void>; + onImmediateModeChange: (value: boolean) => Promise<void>; +} + +export function ConfigurationSection({ + config, + onEnableLsfgChange, + onMultiplierChange, + onFlowScaleChange, + onHdrChange, + onPerfModeChange, + onImmediateModeChange +}: ConfigurationSectionProps) { + return ( + <> + <PanelSectionRow> + <div + style={{ + fontSize: "14px", + fontWeight: "bold", + marginTop: "16px", + marginBottom: "8px", + borderBottom: "1px solid rgba(255, 255, 255, 0.2)", + paddingBottom: "4px" + }} + > + LSFG Configuration + </div> + </PanelSectionRow> + + <PanelSectionRow> + <ToggleField + label="Enable LSFG" + description="Enables the frame generation layer" + checked={config.enableLsfg} + onChange={onEnableLsfgChange} + /> + </PanelSectionRow> + + <PanelSectionRow> + <SliderField + label="FPS Multiplier" + description="Traditional FPS multiplier value" + value={config.multiplier} + min={2} + max={4} + step={1} + notchCount={3} + notchLabels={[ + { notchIndex: 0, label: "2X" }, + { notchIndex: 1, label: "3X" }, + { notchIndex: 2, label: "4X" } + ]} + onChange={onMultiplierChange} + /> + </PanelSectionRow> + + <PanelSectionRow> + <SliderField + label={`Flow Scale ${Math.round(config.flowScale * 100)}%`} + description="Lowers the generated frame's resolution" + value={config.flowScale} + min={0.25} + max={1.0} + step={0.01} + onChange={onFlowScaleChange} + /> + </PanelSectionRow> + + <PanelSectionRow> + <ToggleField + label="HDR Mode" + description="Enable HDR mode (only if Game supports HDR)" + checked={config.hdr} + onChange={onHdrChange} + /> + </PanelSectionRow> + + <PanelSectionRow> + <ToggleField + label="Performance Mode" + description="Use lighter model for FG (experimental)" + checked={config.perfMode} + onChange={onPerfModeChange} + /> + </PanelSectionRow> + + <PanelSectionRow> + <ToggleField + label="Immediate Mode" + description="Disable vsync for reduced input lag" + checked={config.immediateMode} + onChange={onImmediateModeChange} + /> + </PanelSectionRow> + </> + ); +} diff --git a/src/components/Content.tsx b/src/components/Content.tsx new file mode 100644 index 0000000..cecb142 --- /dev/null +++ b/src/components/Content.tsx @@ -0,0 +1,108 @@ +import { useEffect } from "react"; +import { PanelSection } from "@decky/ui"; +import { useInstallationStatus, useDllDetection, useLsfgConfig } from "../hooks/useLsfgHooks"; +import { useInstallationActions } from "../hooks/useInstallationActions"; +import { StatusDisplay } from "./StatusDisplay"; +import { InstallationButton } from "./InstallationButton"; +import { ConfigurationSection } from "./ConfigurationSection"; +import { UsageInstructions } from "./UsageInstructions"; + +export function Content() { + const { + isInstalled, + installationStatus, + setIsInstalled, + setInstallationStatus + } = useInstallationStatus(); + + const { dllDetected, dllDetectionStatus } = useDllDetection(); + + const { + config, + setters, + loadLsfgConfig, + updateConfig + } = useLsfgConfig(); + + const { isInstalling, isUninstalling, handleInstall, handleUninstall } = useInstallationActions(); + + // Reload config when installation status changes + useEffect(() => { + if (isInstalled) { + loadLsfgConfig(); + } + }, [isInstalled, loadLsfgConfig]); + + // Configuration change handlers + const handleEnableLsfgChange = async (value: boolean) => { + setters.setEnableLsfg(value); + await updateConfig(value, config.multiplier, config.flowScale, config.hdr, config.perfMode, config.immediateMode); + }; + + const handleMultiplierChange = async (value: number) => { + setters.setMultiplier(value); + await updateConfig(config.enableLsfg, value, config.flowScale, config.hdr, config.perfMode, config.immediateMode); + }; + + const handleFlowScaleChange = async (value: number) => { + setters.setFlowScale(value); + await updateConfig(config.enableLsfg, config.multiplier, value, config.hdr, config.perfMode, config.immediateMode); + }; + + const handleHdrChange = async (value: boolean) => { + setters.setHdr(value); + await updateConfig(config.enableLsfg, config.multiplier, config.flowScale, value, config.perfMode, config.immediateMode); + }; + + const handlePerfModeChange = async (value: boolean) => { + setters.setPerfMode(value); + await updateConfig(config.enableLsfg, config.multiplier, config.flowScale, config.hdr, value, config.immediateMode); + }; + + const handleImmediateModeChange = async (value: boolean) => { + setters.setImmediateMode(value); + await updateConfig(config.enableLsfg, config.multiplier, config.flowScale, config.hdr, config.perfMode, value); + }; + + const onInstall = () => { + handleInstall(setIsInstalled, setInstallationStatus, loadLsfgConfig); + }; + + const onUninstall = () => { + handleUninstall(setIsInstalled, setInstallationStatus); + }; + + return ( + <PanelSection> + <StatusDisplay + dllDetected={dllDetected} + dllDetectionStatus={dllDetectionStatus} + isInstalled={isInstalled} + installationStatus={installationStatus} + /> + + <InstallationButton + isInstalled={isInstalled} + isInstalling={isInstalling} + isUninstalling={isUninstalling} + onInstall={onInstall} + onUninstall={onUninstall} + /> + + {/* Configuration Section - only show if installed */} + {isInstalled && ( + <ConfigurationSection + config={config} + onEnableLsfgChange={handleEnableLsfgChange} + onMultiplierChange={handleMultiplierChange} + onFlowScaleChange={handleFlowScaleChange} + onHdrChange={handleHdrChange} + onPerfModeChange={handlePerfModeChange} + onImmediateModeChange={handleImmediateModeChange} + /> + )} + + <UsageInstructions multiplier={config.multiplier} /> + </PanelSection> + ); +} diff --git a/src/components/InstallationButton.tsx b/src/components/InstallationButton.tsx new file mode 100644 index 0000000..7892678 --- /dev/null +++ b/src/components/InstallationButton.tsx @@ -0,0 +1,64 @@ +import { ButtonItem, PanelSectionRow } from "@decky/ui"; +import { FaDownload, FaTrash } from "react-icons/fa"; + +interface InstallationButtonProps { + isInstalled: boolean; + isInstalling: boolean; + isUninstalling: boolean; + onInstall: () => void; + onUninstall: () => void; +} + +export function InstallationButton({ + isInstalled, + isInstalling, + isUninstalling, + onInstall, + onUninstall +}: InstallationButtonProps) { + const renderButtonContent = () => { + if (isInstalling) { + return ( + <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> + <div>Installing...</div> + </div> + ); + } + + if (isUninstalling) { + return ( + <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> + <div>Uninstalling...</div> + </div> + ); + } + + if (isInstalled) { + return ( + <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> + <FaTrash /> + <div>Uninstall lsfg-vk</div> + </div> + ); + } + + return ( + <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> + <FaDownload /> + <div>Install lsfg-vk</div> + </div> + ); + }; + + return ( + <PanelSectionRow> + <ButtonItem + layout="below" + onClick={isInstalled ? onUninstall : onInstall} + disabled={isInstalling || isUninstalling} + > + {renderButtonContent()} + </ButtonItem> + </PanelSectionRow> + ); +} diff --git a/src/components/StatusDisplay.tsx b/src/components/StatusDisplay.tsx new file mode 100644 index 0000000..8eecd42 --- /dev/null +++ b/src/components/StatusDisplay.tsx @@ -0,0 +1,38 @@ +import { PanelSectionRow } from "@decky/ui"; + +interface StatusDisplayProps { + dllDetected: boolean; + dllDetectionStatus: string; + isInstalled: boolean; + installationStatus: string; +} + +export function StatusDisplay({ + dllDetected, + dllDetectionStatus, + isInstalled, + installationStatus +}: StatusDisplayProps) { + return ( + <PanelSectionRow> + <div style={{ marginBottom: "8px", fontSize: "14px" }}> + <div + style={{ + color: dllDetected ? "#4CAF50" : "#F44336", + fontWeight: "bold", + marginBottom: "4px" + }} + > + {dllDetectionStatus} + </div> + <div + style={{ + color: isInstalled ? "#4CAF50" : "#FF9800" + }} + > + Status: {installationStatus} + </div> + </div> + </PanelSectionRow> + ); +} diff --git a/src/components/UsageInstructions.tsx b/src/components/UsageInstructions.tsx new file mode 100644 index 0000000..712d4c1 --- /dev/null +++ b/src/components/UsageInstructions.tsx @@ -0,0 +1,68 @@ +import { PanelSectionRow } from "@decky/ui"; + +interface UsageInstructionsProps { + multiplier: number; +} + +export function UsageInstructions({ multiplier }: UsageInstructionsProps) { + return ( + <PanelSectionRow> + <div + style={{ + fontSize: "13px", + marginTop: "12px", + padding: "8px", + backgroundColor: "rgba(255, 255, 255, 0.05)", + borderRadius: "4px" + }} + > + <div style={{ fontWeight: "bold", marginBottom: "6px" }}> + Usage Instructions: + </div> + <div style={{ marginBottom: "4px" }}> + Option 1: Use the lsfg script (recommended): + </div> + <div + style={{ + fontFamily: "monospace", + backgroundColor: "rgba(0, 0, 0, 0.3)", + padding: "4px", + borderRadius: "2px", + fontSize: "12px", + marginBottom: "6px" + }} + > + ~/lsfg %COMMAND% + </div> + <div style={{ marginBottom: "4px" }}> + Option 2: Manual environment variables: + </div> + <div + style={{ + fontFamily: "monospace", + backgroundColor: "rgba(0, 0, 0, 0.3)", + padding: "4px", + borderRadius: "2px", + fontSize: "12px", + marginBottom: "6px" + }} + > + ENABLE_LSFG=1 LSFG_MULTIPLIER={multiplier} %COMMAND% + </div> + <div style={{ fontSize: "11px", opacity: 0.8 }}> + The lsfg script uses your current configuration settings. + <br /> + • ENABLE_LSFG=1 - Enables frame generation + <br /> + • LSFG_MULTIPLIER=2-4 - FPS multiplier (start with 2) + <br /> + • LSFG_FLOW_SCALE=0.25-1.0 - Flow scale (for performance) + <br /> + • LSFG_HDR=1 - HDR mode (only if using HDR) + <br /> + • MESA_VK_WSI_PRESENT_MODE=immediate - Disable vsync + </div> + </div> + </PanelSectionRow> + ); +} diff --git a/src/components/index.ts b/src/components/index.ts new file mode 100644 index 0000000..77f11d4 --- /dev/null +++ b/src/components/index.ts @@ -0,0 +1,5 @@ +export { Content } from "./Content"; +export { StatusDisplay } from "./StatusDisplay"; +export { InstallationButton } from "./InstallationButton"; +export { ConfigurationSection } from "./ConfigurationSection"; +export { UsageInstructions } from "./UsageInstructions"; |
