From 7960019cd93d64f6554fbf660f7277c7bf3fe020 Mon Sep 17 00:00:00 2001 From: Novattz Date: Tue, 23 Dec 2025 02:42:19 +0100 Subject: [PATCH] update creamlinux config #64 --- src/App.tsx | 5 ++ src/components/dialogs/DlcSelectionDialog.tsx | 40 +++++++++++-- src/contexts/AppContext.tsx | 15 +---- src/contexts/AppProvider.tsx | 2 + src/hooks/useDlcManager.ts | 58 ++++++++++++++++++- .../components/dialogs/_dlc_dialog.scss | 22 +++++++ 6 files changed, 124 insertions(+), 18 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 42838c1..f2c3df6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -40,6 +40,7 @@ function App() { handleGameAction, handleDlcConfirm, handleGameEdit, + handleUpdateDlcs, settingsDialog, handleSettingsOpen, handleSettingsClose, @@ -107,13 +108,17 @@ function App() { {/* Settings Dialog */} diff --git a/src/components/dialogs/DlcSelectionDialog.tsx b/src/components/dialogs/DlcSelectionDialog.tsx index 8276b77..57e2bc8 100644 --- a/src/components/dialogs/DlcSelectionDialog.tsx +++ b/src/components/dialogs/DlcSelectionDialog.tsx @@ -6,17 +6,22 @@ import DialogFooter from './DialogFooter' import DialogActions from './DialogActions' import { Button, AnimatedCheckbox } from '@/components/buttons' import { DlcInfo } from '@/types' +import { Icon, check } from '@/components/icons' export interface DlcSelectionDialogProps { visible: boolean gameTitle: string + gameId: string dlcs: DlcInfo[] onClose: () => void onConfirm: (selectedDlcs: DlcInfo[]) => void + onUpdate?: (gameId: string) => void isLoading: boolean isEditMode?: boolean + isUpdating?: boolean loadingProgress?: number estimatedTimeLeft?: string + newDlcsCount?: number } /** @@ -27,13 +32,17 @@ export interface DlcSelectionDialogProps { const DlcSelectionDialog = ({ visible, gameTitle, + gameId, dlcs, onClose, onConfirm, + onUpdate, isLoading, isEditMode = false, + isUpdating = false, loadingProgress = 0, estimatedTimeLeft = '', + newDlcsCount = 0, }: DlcSelectionDialogProps) => { // State for DLC management const [selectedDlcs, setSelectedDlcs] = useState([]) @@ -169,13 +178,13 @@ const DlcSelectionDialog = ({ - {isLoading && loadingProgress > 0 && ( + {(isLoading || isUpdating) && loadingProgress > 0 && (
- Loading DLCs: {loadingProgress}% + {isUpdating ? 'Updating DLC list' : 'Loading DLCs'}: {loadingProgress}% {estimatedTimeLeft && ( Est. time left: {estimatedTimeLeft} )} @@ -211,15 +220,36 @@ const DlcSelectionDialog = ({ + {/* Show update results if we found new DLCs */} + {newDlcsCount > 0 && !isUpdating && ( +
+ + Found {newDlcsCount} new DLC{newDlcsCount > 1 ? 's' : ''}! + +
+ )} + - + )} + + @@ -228,4 +258,4 @@ const DlcSelectionDialog = ({ ) } -export default DlcSelectionDialog +export default DlcSelectionDialog \ No newline at end of file diff --git a/src/contexts/AppContext.tsx b/src/contexts/AppContext.tsx index 9f4232e..10b0f0f 100644 --- a/src/contexts/AppContext.tsx +++ b/src/contexts/AppContext.tsx @@ -1,6 +1,7 @@ import { createContext } from 'react' import { Game, DlcInfo } from '@/types' import { ActionType } from '@/components/buttons/ActionButton' +import { DlcDialogState } from '@/hooks/useDlcManager' // Types for context sub-components export interface InstallationInstructions { @@ -10,17 +11,6 @@ export interface InstallationInstructions { dlc_count?: number } -export interface DlcDialogState { - visible: boolean - gameId: string - gameTitle: string - dlcs: DlcInfo[] - isLoading: boolean - isEditMode: boolean - progress: number - timeLeft?: string -} - export interface ProgressDialogState { visible: boolean title: string @@ -49,6 +39,7 @@ export interface AppContextType { dlcDialog: DlcDialogState handleGameEdit: (gameId: string) => void handleDlcDialogClose: () => void + handleUpdateDlcs: (gameId: string) => Promise // Game actions progressDialog: ProgressDialogState @@ -74,4 +65,4 @@ export interface AppContextType { } // Create the context with a default value -export const AppContext = createContext(undefined) +export const AppContext = createContext(undefined) \ No newline at end of file diff --git a/src/contexts/AppProvider.tsx b/src/contexts/AppProvider.tsx index df09bd5..12e1e4f 100644 --- a/src/contexts/AppProvider.tsx +++ b/src/contexts/AppProvider.tsx @@ -25,6 +25,7 @@ export const AppProvider = ({ children }: AppProviderProps) => { handleDlcDialogClose: closeDlcDialog, streamGameDlcs, handleGameEdit, + handleUpdateDlcs, } = useDlcManager() const { @@ -220,6 +221,7 @@ export const AppProvider = ({ children }: AppProviderProps) => { handleGameEdit(gameId, games) }, handleDlcDialogClose: closeDlcDialog, + handleUpdateDlcs: (gameId: string) => handleUpdateDlcs(gameId), // Game actions progressDialog, diff --git a/src/hooks/useDlcManager.ts b/src/hooks/useDlcManager.ts index f403bac..4be1468 100644 --- a/src/hooks/useDlcManager.ts +++ b/src/hooks/useDlcManager.ts @@ -11,10 +11,12 @@ export interface DlcDialogState { enabledDlcs: string[] isLoading: boolean isEditMode: boolean + isUpdating: boolean progress: number progressMessage: string timeLeft: string error: string | null + newDlcsCount: number } /** @@ -36,10 +38,12 @@ export function useDlcManager() { enabledDlcs: [], isLoading: false, isEditMode: false, + isUpdating: false, progress: 0, progressMessage: '', timeLeft: '', error: null, + newDlcsCount: 0, }) // Set up event listeners for DLC streaming @@ -80,6 +84,7 @@ export function useDlcManager() { setDlcDialog((prev) => ({ ...prev, isLoading: false, + isUpdating: false, })) // Reset fetch state @@ -177,10 +182,12 @@ export function useDlcManager() { enabledDlcs: [], isLoading: true, isEditMode: true, + isUpdating: false, progress: 0, progressMessage: 'Reading DLC configuration...', timeLeft: '', error: null, + newDlcsCount: 0, }) // Always get a fresh copy from the config file @@ -302,6 +309,54 @@ export function useDlcManager() { } }, [dlcDialog.dlcs, dlcDialog.enabledDlcs]) + // Function to update DLC list (refetch from Steam API) + const handleUpdateDlcs = async (gameId: string) => { + try { + // Store current app IDs to identify new DLCs later + const currentAppIds = new Set(dlcDialog.dlcs.map((dlc) => dlc.appid)) + + // Set updating state and clear DLCs + setDlcDialog((prev) => ({ + ...prev, + isUpdating: true, + isLoading: true, + progress: 0, + progressMessage: 'Checking for new DLCs...', + newDlcsCount: 0, + dlcs: [], // Clear current DLCs to start fresh + })) + + // Mark that we're fetching DLCs for this game + setIsFetchingDlcs(true) + activeDlcFetchId.current = gameId + + // Start streaming DLCs + await streamGameDlcs(gameId) + + // After streaming, calculate new DLCs + // This will be done when progress reaches 100% in the listener + setTimeout(() => { + setDlcDialog((prev) => { + const actualNewCount = prev.dlcs.filter(dlc => !currentAppIds.has(dlc.appid)).length + + return { + ...prev, + newDlcsCount: actualNewCount > 0 ? actualNewCount : 0, + } + }) + }, 1000) + + } catch (error) { + console.error('Error updating DLCs:', error) + setDlcDialog((prev) => ({ + ...prev, + error: `Failed to update DLCs: ${error}`, + isLoading: false, + isUpdating: false, + })) + } + } + return { dlcDialog, setDlcDialog, @@ -309,6 +364,7 @@ export function useDlcManager() { streamGameDlcs, handleGameEdit, handleDlcDialogClose, + handleUpdateDlcs, forceReload, } -} +} \ No newline at end of file diff --git a/src/styles/components/dialogs/_dlc_dialog.scss b/src/styles/components/dialogs/_dlc_dialog.scss index 62c8123..36449c6 100644 --- a/src/styles/components/dialogs/_dlc_dialog.scss +++ b/src/styles/components/dialogs/_dlc_dialog.scss @@ -154,6 +154,28 @@ color: var(--text-secondary); } +// Update results message +.dlc-update-results { + padding: 0.75rem 1.5rem; + background-color: var(--elevated-bg); + border: 1px solid var(--border-soft); + border-radius: var(--radius-sm); + margin-bottom: 0.75rem; + + .update-success-message { + color: var(--text-primary); + font-weight: 600; + font-size: 0.9rem; + display: flex; + align-items: center; + gap: 0.5rem; + + .dlc-update-icon { + color: var(--success); + } + } +} + // Game information in DLC dialog .dlc-game-info { display: flex;