import { useCallback, useMemo, useState } from 'react'; import { open } from '@tauri-apps/plugin-dialog'; import { TopBar } from '../components/topbar/TopBar'; import { KebabItem } from '../components/topbar/KebabMenu'; import { ResultsBar } from '../components/grid/ResultsBar'; import { GameGrid } from '../components/grid/GameGrid'; import { GameDetailModal } from '../components/modals/GameDetailModal'; import { ConfirmRemoveDownloadModal } from '../components/modals/ConfirmRemoveDownloadModal'; import { SettingsDialog } from '../components/modals/SettingsDialog'; import { NoDirectoryState } from '../components/empty/NoDirectoryState'; import { EmptyResultsState } from '../components/empty/EmptyResultsState'; import { useGameDirectory } from '../hooks/useGameDirectory'; import { useGames } from '../hooks/useGames'; import { useGameActions } from '../hooks/useGameActions'; import { useThumbnails } from '../hooks/useThumbnails'; import { useSettings } from '../hooks/useSettings'; import { Game } from '../lib/types'; import { applyFilterAndSort, countByFilter, needsUpdate } from '../lib/gameState'; const openLogsWindow = async () => { const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow'); try { const existing = await WebviewWindow.getByLabel('unpack-logs'); if (existing) { await existing.setFocus(); return; } const win = new WebviewWindow('unpack-logs', { url: '/?view=unpack-logs', title: 'Unpack Logs', width: 900, height: 700, resizable: true, }); await win.once('tauri://error', (event) => { console.error('Error opening unpack logs window:', event.payload); }); } catch (err) { console.error('Error opening unpack logs window:', err); } }; export const MainWindow = () => { const { settings, set: setSetting } = useSettings(); const { gameDir, setGameDir, rescan } = useGameDirectory(); const games = useGames(rescan); const actions = useGameActions(games); const thumbnails = useThumbnails(); const [openGameId, setOpenGameId] = useState(null); const [removeGameId, setRemoveGameId] = useState(null); const [settingsOpen, setSettingsOpen] = useState(false); const counts = useMemo(() => countByFilter(games.games), [games.games]); // Query is local UI state (no need to persist). const [query, setQuery] = useState(''); const filteredGames = useMemo( () => applyFilterAndSort(games.games, settings.filter, settings.sort, query), [games.games, settings.filter, settings.sort, query], ); const openGame = useMemo( () => openGameId ? games.games.find(g => g.id === openGameId) ?? null : null, [openGameId, games.games], ); const removeGame = useMemo( () => removeGameId ? games.games.find(g => g.id === removeGameId) ?? null : null, [removeGameId, games.games], ); const pickDirectory = useCallback(async () => { const picked = await open({ multiple: false, directory: true }); if (typeof picked === 'string' && picked) setGameDir(picked); }, [setGameDir]); const handlePrimary = useCallback((game: Game) => { if (game.installed) { if (needsUpdate(game)) actions.update(game.id); else actions.play(game.id); } else { actions.install(game.id); } }, [actions]); const handleUninstall = useCallback((game: Game) => { actions.uninstall(game.id); }, [actions]); const handleRemoveDownload = useCallback((game: Game) => { setRemoveGameId(game.id); }, []); const confirmRemoveDownload = useCallback((game: Game) => { actions.removeDownload(game.id); setRemoveGameId(null); setOpenGameId(current => current === game.id ? null : current); }, [actions]); const kebabItems: ReadonlyArray = useMemo(() => [ { kind: 'item', label: 'Settings', onClick: () => setSettingsOpen(true) }, { kind: 'item', label: 'Refresh library', onClick: () => rescan() }, { kind: 'separator' }, { kind: 'item', label: 'Unpack logs', onClick: () => void openLogsWindow() }, ], [rescan]); const rootStyle = { '--accent': settings.accent } as React.CSSProperties; const className = [ 'launcher', `bg-${settings.bg}`, `density-${settings.density}`, ].join(' '); return (
{gameDir ? ( <> setSetting('filter', v)} counts={counts} query={query} setQuery={setQuery} sort={settings.sort} setSort={(v) => setSetting('sort', v)} gameDir={gameDir} onPickDirectory={() => void pickDirectory()} kebabItems={kebabItems} />
{filteredGames.length === 0 ? ( games.games.length === 0 ? ( ) : ( ) ) : ( setOpenGameId(g.id)} onPrimary={handlePrimary} /> )}
) : (
void pickDirectory()} />
)} {openGame && ( setOpenGameId(null)} onPrimary={handlePrimary} onUninstall={handleUninstall} onRemoveDownload={handleRemoveDownload} /> )} {removeGame && ( setRemoveGameId(null)} onConfirm={confirmRemoveDownload} /> )} {settingsOpen && ( setSettingsOpen(false)} /> )}
); };