update creamlinux config #64

This commit is contained in:
Novattz
2025-12-23 02:42:19 +01:00
parent a00cc92b70
commit 7960019cd9
6 changed files with 124 additions and 18 deletions

View File

@@ -40,6 +40,7 @@ function App() {
handleGameAction, handleGameAction,
handleDlcConfirm, handleDlcConfirm,
handleGameEdit, handleGameEdit,
handleUpdateDlcs,
settingsDialog, settingsDialog,
handleSettingsOpen, handleSettingsOpen,
handleSettingsClose, handleSettingsClose,
@@ -107,13 +108,17 @@ function App() {
<DlcSelectionDialog <DlcSelectionDialog
visible={dlcDialog.visible} visible={dlcDialog.visible}
gameTitle={dlcDialog.gameTitle} gameTitle={dlcDialog.gameTitle}
gameId={dlcDialog.gameId}
dlcs={dlcDialog.dlcs} dlcs={dlcDialog.dlcs}
isLoading={dlcDialog.isLoading} isLoading={dlcDialog.isLoading}
isEditMode={dlcDialog.isEditMode} isEditMode={dlcDialog.isEditMode}
isUpdating={dlcDialog.isUpdating}
loadingProgress={dlcDialog.progress} loadingProgress={dlcDialog.progress}
estimatedTimeLeft={dlcDialog.timeLeft} estimatedTimeLeft={dlcDialog.timeLeft}
newDlcsCount={dlcDialog.newDlcsCount}
onClose={handleDlcDialogClose} onClose={handleDlcDialogClose}
onConfirm={handleDlcConfirm} onConfirm={handleDlcConfirm}
onUpdate={handleUpdateDlcs}
/> />
{/* Settings Dialog */} {/* Settings Dialog */}

View File

@@ -6,17 +6,22 @@ import DialogFooter from './DialogFooter'
import DialogActions from './DialogActions' import DialogActions from './DialogActions'
import { Button, AnimatedCheckbox } from '@/components/buttons' import { Button, AnimatedCheckbox } from '@/components/buttons'
import { DlcInfo } from '@/types' import { DlcInfo } from '@/types'
import { Icon, check } from '@/components/icons'
export interface DlcSelectionDialogProps { export interface DlcSelectionDialogProps {
visible: boolean visible: boolean
gameTitle: string gameTitle: string
gameId: string
dlcs: DlcInfo[] dlcs: DlcInfo[]
onClose: () => void onClose: () => void
onConfirm: (selectedDlcs: DlcInfo[]) => void onConfirm: (selectedDlcs: DlcInfo[]) => void
onUpdate?: (gameId: string) => void
isLoading: boolean isLoading: boolean
isEditMode?: boolean isEditMode?: boolean
isUpdating?: boolean
loadingProgress?: number loadingProgress?: number
estimatedTimeLeft?: string estimatedTimeLeft?: string
newDlcsCount?: number
} }
/** /**
@@ -27,13 +32,17 @@ export interface DlcSelectionDialogProps {
const DlcSelectionDialog = ({ const DlcSelectionDialog = ({
visible, visible,
gameTitle, gameTitle,
gameId,
dlcs, dlcs,
onClose, onClose,
onConfirm, onConfirm,
onUpdate,
isLoading, isLoading,
isEditMode = false, isEditMode = false,
isUpdating = false,
loadingProgress = 0, loadingProgress = 0,
estimatedTimeLeft = '', estimatedTimeLeft = '',
newDlcsCount = 0,
}: DlcSelectionDialogProps) => { }: DlcSelectionDialogProps) => {
// State for DLC management // State for DLC management
const [selectedDlcs, setSelectedDlcs] = useState<DlcInfo[]>([]) const [selectedDlcs, setSelectedDlcs] = useState<DlcInfo[]>([])
@@ -169,13 +178,13 @@ const DlcSelectionDialog = ({
</div> </div>
</div> </div>
{isLoading && loadingProgress > 0 && ( {(isLoading || isUpdating) && loadingProgress > 0 && (
<div className="dlc-loading-progress"> <div className="dlc-loading-progress">
<div className="progress-bar-container"> <div className="progress-bar-container">
<div className="progress-bar" style={{ width: `${loadingProgress}%` }} /> <div className="progress-bar" style={{ width: `${loadingProgress}%` }} />
</div> </div>
<div className="loading-details"> <div className="loading-details">
<span>Loading DLCs: {loadingProgress}%</span> <span>{isUpdating ? 'Updating DLC list' : 'Loading DLCs'}: {loadingProgress}%</span>
{estimatedTimeLeft && ( {estimatedTimeLeft && (
<span className="time-left">Est. time left: {estimatedTimeLeft}</span> <span className="time-left">Est. time left: {estimatedTimeLeft}</span>
)} )}
@@ -211,15 +220,36 @@ const DlcSelectionDialog = ({
</DialogBody> </DialogBody>
<DialogFooter> <DialogFooter>
{/* Show update results if we found new DLCs */}
{newDlcsCount > 0 && !isUpdating && (
<div className="dlc-update-results">
<span className="update-success-message">
<Icon name={check} size="sm" variant="solid" className="dlc-update-icon" /> Found {newDlcsCount} new DLC{newDlcsCount > 1 ? 's' : ''}!
</span>
</div>
)}
<DialogActions> <DialogActions>
<Button <Button
variant="secondary" variant="secondary"
onClick={onClose} onClick={onClose}
disabled={isLoading && loadingProgress < 10} disabled={(isLoading || isUpdating) && loadingProgress < 10}
> >
Cancel Cancel
</Button> </Button>
<Button variant="primary" onClick={handleConfirm} disabled={isLoading}>
{/* Update button - only show in edit mode */}
{isEditMode && onUpdate && (
<Button
variant="warning"
onClick={() => onUpdate(gameId)}
disabled={isLoading || isUpdating}
>
{isUpdating ? 'Updating...' : 'Update DLC List'}
</Button>
)}
<Button variant="primary" onClick={handleConfirm} disabled={isLoading || isUpdating}>
{actionButtonText} {actionButtonText}
</Button> </Button>
</DialogActions> </DialogActions>

View File

@@ -1,6 +1,7 @@
import { createContext } from 'react' import { createContext } from 'react'
import { Game, DlcInfo } from '@/types' import { Game, DlcInfo } from '@/types'
import { ActionType } from '@/components/buttons/ActionButton' import { ActionType } from '@/components/buttons/ActionButton'
import { DlcDialogState } from '@/hooks/useDlcManager'
// Types for context sub-components // Types for context sub-components
export interface InstallationInstructions { export interface InstallationInstructions {
@@ -10,17 +11,6 @@ export interface InstallationInstructions {
dlc_count?: number 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 { export interface ProgressDialogState {
visible: boolean visible: boolean
title: string title: string
@@ -49,6 +39,7 @@ export interface AppContextType {
dlcDialog: DlcDialogState dlcDialog: DlcDialogState
handleGameEdit: (gameId: string) => void handleGameEdit: (gameId: string) => void
handleDlcDialogClose: () => void handleDlcDialogClose: () => void
handleUpdateDlcs: (gameId: string) => Promise<void>
// Game actions // Game actions
progressDialog: ProgressDialogState progressDialog: ProgressDialogState

View File

@@ -25,6 +25,7 @@ export const AppProvider = ({ children }: AppProviderProps) => {
handleDlcDialogClose: closeDlcDialog, handleDlcDialogClose: closeDlcDialog,
streamGameDlcs, streamGameDlcs,
handleGameEdit, handleGameEdit,
handleUpdateDlcs,
} = useDlcManager() } = useDlcManager()
const { const {
@@ -220,6 +221,7 @@ export const AppProvider = ({ children }: AppProviderProps) => {
handleGameEdit(gameId, games) handleGameEdit(gameId, games)
}, },
handleDlcDialogClose: closeDlcDialog, handleDlcDialogClose: closeDlcDialog,
handleUpdateDlcs: (gameId: string) => handleUpdateDlcs(gameId),
// Game actions // Game actions
progressDialog, progressDialog,

View File

@@ -11,10 +11,12 @@ export interface DlcDialogState {
enabledDlcs: string[] enabledDlcs: string[]
isLoading: boolean isLoading: boolean
isEditMode: boolean isEditMode: boolean
isUpdating: boolean
progress: number progress: number
progressMessage: string progressMessage: string
timeLeft: string timeLeft: string
error: string | null error: string | null
newDlcsCount: number
} }
/** /**
@@ -36,10 +38,12 @@ export function useDlcManager() {
enabledDlcs: [], enabledDlcs: [],
isLoading: false, isLoading: false,
isEditMode: false, isEditMode: false,
isUpdating: false,
progress: 0, progress: 0,
progressMessage: '', progressMessage: '',
timeLeft: '', timeLeft: '',
error: null, error: null,
newDlcsCount: 0,
}) })
// Set up event listeners for DLC streaming // Set up event listeners for DLC streaming
@@ -80,6 +84,7 @@ export function useDlcManager() {
setDlcDialog((prev) => ({ setDlcDialog((prev) => ({
...prev, ...prev,
isLoading: false, isLoading: false,
isUpdating: false,
})) }))
// Reset fetch state // Reset fetch state
@@ -177,10 +182,12 @@ export function useDlcManager() {
enabledDlcs: [], enabledDlcs: [],
isLoading: true, isLoading: true,
isEditMode: true, isEditMode: true,
isUpdating: false,
progress: 0, progress: 0,
progressMessage: 'Reading DLC configuration...', progressMessage: 'Reading DLC configuration...',
timeLeft: '', timeLeft: '',
error: null, error: null,
newDlcsCount: 0,
}) })
// Always get a fresh copy from the config file // Always get a fresh copy from the config file
@@ -302,6 +309,54 @@ export function useDlcManager() {
} }
}, [dlcDialog.dlcs, dlcDialog.enabledDlcs]) }, [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 { return {
dlcDialog, dlcDialog,
setDlcDialog, setDlcDialog,
@@ -309,6 +364,7 @@ export function useDlcManager() {
streamGameDlcs, streamGameDlcs,
handleGameEdit, handleGameEdit,
handleDlcDialogClose, handleDlcDialogClose,
handleUpdateDlcs,
forceReload, forceReload,
} }
} }

View File

@@ -154,6 +154,28 @@
color: var(--text-secondary); 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 // Game information in DLC dialog
.dlc-game-info { .dlc-game-info {
display: flex; display: flex;