summaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/Content.tsx21
-rw-r--r--src/components/FlatpaksModal.tsx67
-rw-r--r--src/components/NerdStuffModal.tsx55
-rw-r--r--src/components/StatusDisplay.tsx21
4 files changed, 99 insertions, 65 deletions
diff --git a/src/components/Content.tsx b/src/components/Content.tsx
index 5988e79..aab2fb8 100644
--- a/src/components/Content.tsx
+++ b/src/components/Content.tsx
@@ -1,6 +1,6 @@
import { useEffect } from "react";
import { PanelSection, showModal, ButtonItem, PanelSectionRow } from "@decky/ui";
-import { useInstallationStatus, useDllDetection, useLsfgConfig } from "../hooks/useLsfgHooks";
+import { useInstallationStatus, useLsfgConfig } from "../hooks/useLsfgHooks";
import { useProfileManagement } from "../hooks/useProfileManagement";
import { useInstallationActions } from "../hooks/useInstallationActions";
import { StatusDisplay } from "./StatusDisplay";
@@ -21,11 +21,12 @@ export function Content() {
isInstalled,
installationStatus,
setIsInstalled,
- setInstallationStatus
+ setInstallationStatus,
+ losslessScalingInstalled,
+ losslessScalingStatus,
+ checkInstallation
} = useInstallationStatus();
- const { dllDetected, dllDetectionStatus } = useDllDetection();
-
const {
config,
loadLsfgConfig,
@@ -59,11 +60,11 @@ export function Content() {
};
const onInstall = () => {
- handleInstall(setIsInstalled, setInstallationStatus, loadLsfgConfig);
+ handleInstall(setIsInstalled, setInstallationStatus, loadLsfgConfig, checkInstallation);
};
const onUninstall = () => {
- handleUninstall(setIsInstalled, setInstallationStatus);
+ handleUninstall(setIsInstalled, setInstallationStatus, checkInstallation);
};
const handleShowNerdStuff = () => {
@@ -87,10 +88,10 @@ export function Content() {
/>
<StatusDisplay
- dllDetected={dllDetected}
- dllDetectionStatus={dllDetectionStatus}
isInstalled={isInstalled}
installationStatus={installationStatus}
+ losslessScalingInstalled={losslessScalingInstalled}
+ losslessScalingStatus={losslessScalingStatus}
/>
</>
)}
@@ -167,10 +168,10 @@ export function Content() {
{isInstalled && (
<>
<StatusDisplay
- dllDetected={dllDetected}
- dllDetectionStatus={dllDetectionStatus}
isInstalled={isInstalled}
installationStatus={installationStatus}
+ losslessScalingInstalled={losslessScalingInstalled}
+ losslessScalingStatus={losslessScalingStatus}
/>
<InstallationButton
diff --git a/src/components/FlatpaksModal.tsx b/src/components/FlatpaksModal.tsx
index 479b919..8245160 100644
--- a/src/components/FlatpaksModal.tsx
+++ b/src/components/FlatpaksModal.tsx
@@ -28,6 +28,7 @@ import {
FlatpakAppInfo
} from '../api/lsfgApi';
import t from '../i18n/i18n';
+import { showErrorToast } from '../utils/toastUtils';
interface FlatpaksModalProps {
closeModal?: () => void;
@@ -38,6 +39,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
const [flatpakApps, setFlatpakApps] = useState<FlatpakAppInfo | null>(null);
const [loading, setLoading] = useState(true);
const [operationInProgress, setOperationInProgress] = useState<string | null>(null);
+ const [operationError, setOperationError] = useState<string | null>(null);
const loadData = async () => {
setLoading(true);
@@ -63,6 +65,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
const handleExtensionOperation = async (operation: 'install' | 'uninstall', version: string) => {
const operationId = `${operation}-${version}`;
setOperationInProgress(operationId);
+ setOperationError(null);
try {
const result = operation === 'install'
@@ -73,9 +76,16 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
// Reload status after operation
const newStatus = await checkFlatpakExtensionStatus();
setExtensionStatus(newStatus);
+ } else {
+ const message = result.error || result.message || 'Flatpak operation failed';
+ setOperationError(message);
+ showErrorToast('Flatpak operation failed', message);
}
} catch (error) {
console.error(`Error ${operation}ing extension:`, error);
+ const message = String(error);
+ setOperationError(message);
+ showErrorToast('Flatpak operation failed', message);
} finally {
setOperationInProgress(null);
}
@@ -85,6 +95,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
const hasOverrides = app.has_filesystem_override && app.has_env_override;
const operationId = `app-${app.app_id}`;
setOperationInProgress(operationId);
+ setOperationError(null);
try {
const result = hasOverrides
@@ -95,9 +106,16 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
// Reload apps data after operation
const newApps = await getFlatpakApps();
setFlatpakApps(newApps);
+ } else {
+ const message = result.error || result.message || 'Flatpak override failed';
+ setOperationError(message);
+ showErrorToast('Flatpak override failed', message);
}
} catch (error) {
console.error('Error toggling app override:', error);
+ const message = String(error);
+ setOperationError(message);
+ showErrorToast('Flatpak override failed', message);
} finally {
setOperationInProgress(null);
}
@@ -170,8 +188,57 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
<DialogControlsSection>
<DialogControlsSectionHeader>{t('FLATPAK_RUNTIME_INSTALLER', 'Runtime Extension Installer')}</DialogControlsSectionHeader>
+ {operationError && (
+ <PanelSectionRow>
+ <Field
+ label={t('FLATPAK_OPERATION_ERROR', 'Operation failed')}
+ description={operationError}
+ icon={<FaTimes style={{color: 'red'}} />}
+ />
+ </PanelSectionRow>
+ )}
+
{extensionStatus && extensionStatus.success ? (
<>
+ <PanelSectionRow>
+ <Field
+ label={t('FLATPAK_RUNTIME_23', 'Runtime 23.08')}
+ description={extensionStatus.installed_23_08 ? t('FLATPAK_INSTALLED', 'Installed') : t('FLATPAK_NOT_INSTALLED', 'Not installed')}
+ icon={extensionStatus.installed_23_08 ? <FaCheck style={{color: 'green'}} /> : <FaTimes style={{color: 'red'}} />}
+ >
+ <ButtonItem
+ layout="below"
+ onClick={() => {
+ const operation = extensionStatus.installed_23_08 ? 'uninstall' : 'install';
+ const action = () => handleExtensionOperation(operation, '23.08');
+
+ if (operation === 'uninstall') {
+ confirmOperation(
+ action,
+ t('FLATPAK_UNINSTALL_TITLE', 'Uninstall Runtime Extension'),
+ `${t('FLATPAK_UNINSTALL_CONFIRM_PREFIX', 'Are you sure you want to uninstall the')} 23.08 ${t('FLATPAK_UNINSTALL_CONFIRM_SUFFIX', 'runtime extension?')}`
+ );
+ } else {
+ action();
+ }
+ }}
+ disabled={operationInProgress === 'install-23.08' || operationInProgress === 'uninstall-23.08'}
+ >
+ {operationInProgress === 'install-23.08' || operationInProgress === 'uninstall-23.08' ? (
+ <Spinner />
+ ) : extensionStatus.installed_23_08 ? (
+ <>
+ <FaTrash /> {t('FLATPAK_UNINSTALL_BTN', 'Uninstall')}
+ </>
+ ) : (
+ <>
+ <FaDownload /> {t('FLATPAK_INSTALL_BTN', 'Install')}
+ </>
+ )}
+ </ButtonItem>
+ </Field>
+ </PanelSectionRow>
+
{/* 24.08 Runtime */}
<PanelSectionRow>
<Field
diff --git a/src/components/NerdStuffModal.tsx b/src/components/NerdStuffModal.tsx
index 8a79b67..f075ccb 100644
--- a/src/components/NerdStuffModal.tsx
+++ b/src/components/NerdStuffModal.tsx
@@ -7,7 +7,11 @@ import {
PanelSectionRow,
ButtonItem
} from "@decky/ui";
-import { getDllStats, DllStatsResult, getConfigFileContent, getLaunchScriptContent, FileContentResult } from "../api/lsfgApi";
+import {
+ getConfigFileContent,
+ getLaunchScriptContent,
+ FileContentResult,
+} from "../api/lsfgApi";
import t from '../i18n/i18n';
interface NerdStuffModalProps {
@@ -15,7 +19,6 @@ interface NerdStuffModalProps {
}
export function NerdStuffModal({ closeModal }: NerdStuffModalProps) {
- const [dllStats, setDllStats] = useState<DllStatsResult | null>(null);
const [configContent, setConfigContent] = useState<FileContentResult | null>(null);
const [scriptContent, setScriptContent] = useState<FileContentResult | null>(null);
const [loading, setLoading] = useState(true);
@@ -28,13 +31,11 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) {
setError(null);
// Load all data in parallel
- const [dllResult, configResult, scriptResult] = await Promise.all([
- getDllStats(),
+ const [configResult, scriptResult] = await Promise.all([
getConfigFileContent(),
- getLaunchScriptContent()
+ getLaunchScriptContent(),
]);
- setDllStats(dllResult);
setConfigContent(configResult);
setScriptContent(scriptResult);
} catch (err) {
@@ -47,11 +48,6 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) {
loadData();
}, []);
- const formatSHA256 = (hash: string) => {
- // Format SHA256 hash for better readability (add spaces every 8 characters)
- return hash.replace(/(.{8})/g, '$1 ').trim();
- };
-
const copyToClipboard = async (text: string) => {
try {
await navigator.clipboard.writeText(text);
@@ -73,41 +69,6 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) {
{!loading && !error && (
<>
- {/* DLL Stats Section */}
- {dllStats && (
- <>
- {!dllStats.success ? (
- <div>{dllStats.error || "Failed to get DLL stats"}</div>
- ) : (
- <div>
- <Field label={t('NERD_DLL_PATH', 'DLL Path')}>
- <Focusable
- onClick={() => dllStats.dll_path && copyToClipboard(dllStats.dll_path)}
- onActivate={() => dllStats.dll_path && copyToClipboard(dllStats.dll_path)}
- >
- {dllStats.dll_path || t('NERD_NOT_AVAILABLE', 'Not available')}
- </Focusable>
- </Field>
-
- <Field label={t('NERD_DLL_HASH', 'DLL SHA256 Hash')}>
- <Focusable
- onClick={() => dllStats.dll_sha256 && copyToClipboard(dllStats.dll_sha256)}
- onActivate={() => dllStats.dll_sha256 && copyToClipboard(dllStats.dll_sha256)}
- >
- {dllStats.dll_sha256 ? formatSHA256(dllStats.dll_sha256) : t('NERD_NOT_AVAILABLE', 'Not available')}
- </Focusable>
- </Field>
-
- {dllStats.dll_source && (
- <Field label={t('NERD_DETECTION_SOURCE', 'Detection Source')}>
- <div>{dllStats.dll_source}</div>
- </Field>
- )}
- </div>
- )}
- </>
- )}
-
{/* Launch Script Section */}
{scriptContent && (
<Field label={t('NERD_LAUNCH_SCRIPT', 'Launch Script')}>
@@ -168,7 +129,7 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) {
)}
</Field>
)}
-
+
{/* Close Button */}
<DialogControlsSection>
<PanelSectionRow>
diff --git a/src/components/StatusDisplay.tsx b/src/components/StatusDisplay.tsx
index 3a48a15..31584eb 100644
--- a/src/components/StatusDisplay.tsx
+++ b/src/components/StatusDisplay.tsx
@@ -1,24 +1,24 @@
import { PanelSectionRow } from "@decky/ui";
interface StatusDisplayProps {
- dllDetected: boolean;
- dllDetectionStatus: string;
isInstalled: boolean;
installationStatus: string;
+ losslessScalingInstalled: boolean;
+ losslessScalingStatus: string;
}
export function StatusDisplay({
- dllDetected,
- dllDetectionStatus,
isInstalled,
- installationStatus
+ installationStatus,
+ losslessScalingInstalled,
+ losslessScalingStatus
}: StatusDisplayProps) {
return (
<PanelSectionRow>
<div style={{ marginBottom: "8px", fontSize: "14px" }}>
<div
style={{
- color: dllDetected ? "#4CAF50" : "#F44336",
+ color: losslessScalingInstalled ? "#4CAF50" : "#F44336",
fontWeight: "600",
marginBottom: "6px",
display: "flex",
@@ -27,10 +27,15 @@ export function StatusDisplay({
}}
>
<span style={{ fontSize: "16px" }}>
- {dllDetected ? "✅" : "❌"}
+ {losslessScalingInstalled ? "✅" : "❌"}
</span>
- {dllDetectionStatus}
+ {losslessScalingInstalled ? "Lossless Scaling Installed" : "Lossless Scaling Not Installed"}
</div>
+ {!losslessScalingInstalled && losslessScalingStatus && (
+ <div style={{ color: "#B8B8B8", fontSize: "12px", margin: "0 0 6px 22px" }}>
+ {losslessScalingStatus}
+ </div>
+ )}
<div
style={{
color: isInstalled ? "#4CAF50" : "#FF9800",