diff options
| author | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2025-09-22 09:38:20 -0400 |
|---|---|---|
| committer | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2025-09-22 09:38:20 -0400 |
| commit | 0da3682755e551a7d3c23fa979686d8dbcdd4f7b (patch) | |
| tree | f07d360ebaeefba28fe5b5be730c807ce337bddc /src | |
| parent | 84de5901cd1fb7d89031e4e7b3b47ed805e324c8 (diff) | |
| download | decky-lsfg-vk-0da3682755e551a7d3c23fa979686d8dbcdd4f7b.tar.gz decky-lsfg-vk-0da3682755e551a7d3c23fa979686d8dbcdd4f7b.zip | |
bring forward old flatpak modal attempt
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/lsfgApi.ts | 40 | ||||
| -rw-r--r-- | src/components/Content.tsx | 15 | ||||
| -rw-r--r-- | src/components/FlatpaksModal.tsx | 291 | ||||
| -rw-r--r-- | src/components/index.ts | 1 |
4 files changed, 347 insertions, 0 deletions
diff --git a/src/api/lsfgApi.ts b/src/api/lsfgApi.ts index 8db0c82..d08cd42 100644 --- a/src/api/lsfgApi.ts +++ b/src/api/lsfgApi.ts @@ -96,6 +96,38 @@ export interface FgmodCheckResult { error?: string; } +// Flatpak management interfaces +export interface FlatpakExtensionStatus { + success: boolean; + message: string; + error?: string; + installed_23_08: boolean; + installed_24_08: boolean; +} + +export interface FlatpakApp { + app_id: string; + app_name: string; + has_filesystem_override: boolean; + has_env_override: boolean; +} + +export interface FlatpakAppInfo { + success: boolean; + message: string; + error?: string; + apps: FlatpakApp[]; + total_apps: number; +} + +export interface FlatpakOperationResult { + success: boolean; + message: string; + error?: string; + app_id?: string; + operation?: string; +} + // Profile management interfaces export interface ProfilesResult { success: boolean; @@ -125,6 +157,14 @@ export const getConfigFileContent = callable<[], FileContentResult>("get_config_ export const getLaunchScriptContent = callable<[], FileContentResult>("get_launch_script_content"); export const checkFgmodDirectory = callable<[], FgmodCheckResult>("check_fgmod_directory"); +// Flatpak management API functions +export const checkFlatpakExtensionStatus = callable<[], FlatpakExtensionStatus>("check_flatpak_extension_status"); +export const installFlatpakExtension = callable<[string], FlatpakOperationResult>("install_flatpak_extension"); +export const uninstallFlatpakExtension = callable<[string], FlatpakOperationResult>("uninstall_flatpak_extension"); +export const getFlatpakApps = callable<[], FlatpakAppInfo>("get_flatpak_apps"); +export const setFlatpakAppOverride = callable<[string], FlatpakOperationResult>("set_flatpak_app_override"); +export const removeFlatpakAppOverride = callable<[string], FlatpakOperationResult>("remove_flatpak_app_override"); + // Updated config function using object-based configuration (single source of truth) export const updateLsfgConfig = callable< [ConfigurationData], diff --git a/src/components/Content.tsx b/src/components/Content.tsx index a00a595..b76ff59 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -15,6 +15,7 @@ import { FgmodClipboardButton } from "./FgmodClipboardButton"; // import { ClipboardDisplay } from "./ClipboardDisplay"; import { PluginUpdateChecker } from "./PluginUpdateChecker"; import { NerdStuffModal } from "./NerdStuffModal"; +import { FlatpaksModal } from "./index"; import { ConfigurationData } from "../config/configSchema"; export function Content() { @@ -76,6 +77,10 @@ export function Content() { showModal(<NerdStuffModal />); }; + const handleShowFlatpaks = () => { + showModal(<FlatpaksModal />); + }; + return ( <PanelSection> {/* Show installation components at top when not fully installed */} @@ -165,6 +170,16 @@ export function Content() { Nerd Stuff </ButtonItem> </PanelSectionRow> + + {/* Flatpaks Button */} + <PanelSectionRow> + <ButtonItem + layout="below" + onClick={handleShowFlatpaks} + > + Flatpaks + </ButtonItem> + </PanelSectionRow> </PanelSection> ); } diff --git a/src/components/FlatpaksModal.tsx b/src/components/FlatpaksModal.tsx index e69de29..a57c683 100644 --- a/src/components/FlatpaksModal.tsx +++ b/src/components/FlatpaksModal.tsx @@ -0,0 +1,291 @@ +import { FC, useState, useEffect } from 'react'; +import { + ModalRoot, + DialogBody, + DialogHeader, + DialogControlsSection, + DialogControlsSectionHeader, + ButtonItem, + PanelSectionRow, + Field, + Toggle, + Spinner, + Focusable, + showModal, + ConfirmModal +} from '@decky/ui'; +import { FaCheck, FaTimes, FaDownload, FaTrash, FaCog } from 'react-icons/fa'; +import { + checkFlatpakExtensionStatus, + installFlatpakExtension, + uninstallFlatpakExtension, + getFlatpakApps, + setFlatpakAppOverride, + removeFlatpakAppOverride, + FlatpakExtensionStatus, + FlatpakApp, + FlatpakAppInfo +} from '../api/lsfgApi'; + +interface FlatpaksModalProps { + closeModal?: () => void; +} + +const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { + const [extensionStatus, setExtensionStatus] = useState<FlatpakExtensionStatus | null>(null); + const [flatpakApps, setFlatpakApps] = useState<FlatpakAppInfo | null>(null); + const [loading, setLoading] = useState(true); + const [operationInProgress, setOperationInProgress] = useState<string | null>(null); + + const loadData = async () => { + setLoading(true); + try { + const [statusResult, appsResult] = await Promise.all([ + checkFlatpakExtensionStatus(), + getFlatpakApps() + ]); + + setExtensionStatus(statusResult); + setFlatpakApps(appsResult); + } catch (error) { + console.error('Error loading Flatpak data:', error); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + loadData(); + }, []); + + const handleExtensionOperation = async (operation: 'install' | 'uninstall', version: string) => { + const operationId = `${operation}-${version}`; + setOperationInProgress(operationId); + + try { + const result = operation === 'install' + ? await installFlatpakExtension(version) + : await uninstallFlatpakExtension(version); + + if (result.success) { + // Reload status after operation + const newStatus = await checkFlatpakExtensionStatus(); + setExtensionStatus(newStatus); + } + } catch (error) { + console.error(`Error ${operation}ing extension:`, error); + } finally { + setOperationInProgress(null); + } + }; + + const handleAppOverrideToggle = async (app: FlatpakApp) => { + const hasOverrides = app.has_filesystem_override && app.has_env_override; + const operationId = `app-${app.app_id}`; + setOperationInProgress(operationId); + + try { + const result = hasOverrides + ? await removeFlatpakAppOverride(app.app_id) + : await setFlatpakAppOverride(app.app_id); + + if (result.success) { + // Reload apps data after operation + const newApps = await getFlatpakApps(); + setFlatpakApps(newApps); + } + } catch (error) { + console.error('Error toggling app override:', error); + } finally { + setOperationInProgress(null); + } + }; + + const confirmOperation = (operation: () => void, title: string, description: string) => { + showModal( + <ConfirmModal + strTitle={title} + strDescription={description} + onOK={operation} + onCancel={() => {}} + /> + ); + }; + + if (loading) { + return ( + <ModalRoot closeModal={closeModal}> + <DialogHeader>Flatpak Extensions</DialogHeader> + <DialogBody> + <div style={{ display: 'flex', justifyContent: 'center', padding: '20px' }}> + <Spinner /> + </div> + </DialogBody> + </ModalRoot> + ); + } + + return ( + <ModalRoot closeModal={closeModal}> + <DialogHeader>Flatpak Extensions</DialogHeader> + <DialogBody> + <Focusable> + {/* Extension Status Section */} + <DialogControlsSection> + <DialogControlsSectionHeader>Runtime Extensions</DialogControlsSectionHeader> + + {extensionStatus && extensionStatus.success ? ( + <> + {/* 23.08 Runtime */} + <PanelSectionRow> + <Field + label="Runtime 23.08" + description={extensionStatus.installed_23_08 ? "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, + 'Uninstall Runtime Extension', + 'Are you sure you want to uninstall the 23.08 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 /> Uninstall + </> + ) : ( + <> + <FaDownload /> Install + </> + )} + </ButtonItem> + </Field> + </PanelSectionRow> + + {/* 24.08 Runtime */} + <PanelSectionRow> + <Field + label="Runtime 24.08" + description={extensionStatus.installed_24_08 ? "Installed" : "Not installed"} + icon={extensionStatus.installed_24_08 ? <FaCheck style={{color: 'green'}} /> : <FaTimes style={{color: 'red'}} />} + > + <ButtonItem + layout="below" + onClick={() => { + const operation = extensionStatus.installed_24_08 ? 'uninstall' : 'install'; + const action = () => handleExtensionOperation(operation, '24.08'); + + if (operation === 'uninstall') { + confirmOperation( + action, + 'Uninstall Runtime Extension', + 'Are you sure you want to uninstall the 24.08 runtime extension?' + ); + } else { + action(); + } + }} + disabled={operationInProgress === 'install-24.08' || operationInProgress === 'uninstall-24.08'} + > + {operationInProgress === 'install-24.08' || operationInProgress === 'uninstall-24.08' ? ( + <Spinner /> + ) : extensionStatus.installed_24_08 ? ( + <> + <FaTrash /> Uninstall + </> + ) : ( + <> + <FaDownload /> Install + </> + )} + </ButtonItem> + </Field> + </PanelSectionRow> + </> + ) : ( + <PanelSectionRow> + <Field + label="Error" + description={extensionStatus?.error || 'Failed to check extension status'} + icon={<FaTimes style={{color: 'red'}} />} + /> + </PanelSectionRow> + )} + </DialogControlsSection> + + {/* Flatpak Apps Section */} + <DialogControlsSection> + <DialogControlsSectionHeader>Flatpak Applications</DialogControlsSectionHeader> + + {flatpakApps && flatpakApps.success ? ( + flatpakApps.apps.length > 0 ? ( + flatpakApps.apps.map((app) => { + const hasOverrides = app.has_filesystem_override && app.has_env_override; + const partialOverrides = app.has_filesystem_override || app.has_env_override; + + let statusColor = 'red'; + let statusText = 'No overrides'; + + if (hasOverrides) { + statusColor = 'green'; + statusText = 'Configured'; + } else if (partialOverrides) { + statusColor = 'orange'; + statusText = 'Partial'; + } + + return ( + <PanelSectionRow key={app.app_id}> + <Field + label={app.app_name || app.app_id} + description={`${app.app_id} - ${statusText}`} + icon={<FaCog style={{color: statusColor}} />} + > + <Toggle + value={hasOverrides} + onChange={() => handleAppOverrideToggle(app)} + disabled={operationInProgress === `app-${app.app_id}`} + /> + </Field> + </PanelSectionRow> + ); + }) + ) : ( + <PanelSectionRow> + <Field + label="No Flatpak Apps Found" + description="No Flatpak applications are currently installed" + /> + </PanelSectionRow> + ) + ) : ( + <PanelSectionRow> + <Field + label="Error" + description={flatpakApps?.error || 'Failed to load Flatpak applications'} + icon={<FaTimes style={{color: 'red'}} />} + /> + </PanelSectionRow> + )} + </DialogControlsSection> + </Focusable> + </DialogBody> + </ModalRoot> + ); +}; + +export default FlatpaksModal; diff --git a/src/components/index.ts b/src/components/index.ts index 802cd3c..50480be 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -10,4 +10,5 @@ export { FgmodClipboardButton } from "./FgmodClipboardButton"; // export { ClipboardDisplay } from "./ClipboardDisplay"; export { PluginUpdateChecker } from "./PluginUpdateChecker"; export { NerdStuffModal } from "./NerdStuffModal"; +export { default as FlatpaksModal } from "./FlatpaksModal"; export { ProfileManagement } from "./ProfileManagement"; |
