diff options
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/Content.tsx | 21 | ||||
| -rw-r--r-- | src/components/FlatpaksModal.tsx | 67 | ||||
| -rw-r--r-- | src/components/NerdStuffModal.tsx | 55 | ||||
| -rw-r--r-- | src/components/StatusDisplay.tsx | 21 |
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", |
