import { useState, useEffect } from 'react'; import { AppShell, Loader, Center, Stack, Text } from '@mantine/core'; import { DownloadScreen } from '@/components/screens/Download'; import { LaunchScreen } from '@/components/screens/Launch'; import { InterfaceScreen } from '@/components/screens/Interface'; import { UpdateDialog } from '@/components/UpdateDialog'; import { SettingsModal } from '@/components/settings/SettingsModal'; import { ScreenTransition } from '@/components/ScreenTransition'; import { AppHeader } from '@/components/AppHeader'; import { UI } from '@/constants'; import type { UpdateInfo } from '@/types'; type Screen = 'download' | 'launch' | 'interface'; export const App = () => { const [currentScreen, setCurrentScreen] = useState(null); const [updateInfo, setUpdateInfo] = useState(null); const [showUpdateDialog, setShowUpdateDialog] = useState(false); const [settingsOpened, setSettingsOpened] = useState(false); const [hasInitialized, setHasInitialized] = useState(false); const [activeInterfaceTab, setActiveInterfaceTab] = useState( 'terminal' ); const [isImageGenerationMode, setIsImageGenerationMode] = useState(false); useEffect(() => { const checkInstallation = async () => { try { const [versions, currentBinaryPath] = await Promise.all([ window.electronAPI.kobold.getInstalledVersions(), window.electronAPI.config.get( 'currentKoboldBinary' ) as Promise, ]); if (versions.length > 0) { let current = null; if (currentBinaryPath) { current = versions.find((v) => v.path === currentBinaryPath); } if (!current) { current = versions[0]; if (current) { await window.electronAPI.config.set( 'currentKoboldBinary', current.path ); } } setCurrentScreen('launch'); } else { setCurrentScreen('download'); } setHasInitialized(true); } catch (error) { window.electronAPI.logs.logError( 'Error checking installation:', error as Error ); setHasInitialized(true); } }; checkInstallation(); window.electronAPI.kobold.onUpdateAvailable((info) => { setUpdateInfo(info); setShowUpdateDialog(true); }); const cleanupInstallDirListener = window.electronAPI.kobold.onInstallDirChanged(() => { checkInstallation(); }); const cleanupVersionsListener = window.electronAPI.kobold.onVersionsUpdated( () => { checkInstallation(); } ); return () => { window.electronAPI.kobold.removeAllListeners('update-available'); cleanupInstallDirListener(); cleanupVersionsListener(); }; }, []); const handleDownloadComplete = async () => { try { const [versions, currentBinaryPath] = await Promise.all([ window.electronAPI.kobold.getInstalledVersions(), window.electronAPI.config.get('currentKoboldBinary') as Promise, ]); if (versions.length > 0) { let current = null; if (currentBinaryPath) { current = versions.find((v) => v.path === currentBinaryPath); } if (!current) { current = versions[0]; if (current) { await window.electronAPI.config.set( 'currentKoboldBinary', current.path ); } } } } catch (error) { window.electronAPI.logs.logError( 'Error refreshing versions after download:', error as Error ); } setTimeout(() => { setCurrentScreen('launch'); }, 100); }; const handleLaunch = () => { setActiveInterfaceTab('terminal'); setCurrentScreen('interface'); }; const handleBackToLaunch = () => { setCurrentScreen('launch'); }; const handleEject = async () => { try { const confirmed = await window.electronAPI.kobold.confirmEject(); if (!confirmed) { return; } } catch (error) { window.electronAPI.logs.logError( 'Error showing confirmation dialog:', error as Error ); return; } try { await window.electronAPI.kobold.stopKoboldCpp(); } catch (error) { window.electronAPI.logs.logError( 'Error stopping KoboldCpp:', error as Error ); } handleBackToLaunch(); }; const handleUpdateIgnore = () => { setShowUpdateDialog(false); }; const handleUpdateAccept = () => { setShowUpdateDialog(false); setCurrentScreen('download'); }; return ( <> setSettingsOpened(true)} /> {currentScreen === null ? (
Loading...
) : ( <> )} {showUpdateDialog && updateInfo && ( )}
setSettingsOpened(false)} currentScreen={currentScreen || undefined} />
); };