/** * WorkspaceScreen — Screen-Wrapper fuer die Workbench. * * Kompakt-Modus → klassischer Vollbild-Chat (wie vor dem Umbau). * Cockpit-Modus → Workbench mit Taskleisten-Dock: Chat · Code · Desktop. * * Aktivitaets-Badges am Dock: Editor blau, wenn schon Code-Dateien da sind; * Desktop gruen NUR, wenn im aktiven Projekt eine VM laeuft. */ import React, { useEffect, useMemo, useState } from 'react'; import { View } from 'react-native'; import projectFocus, { FocusSnapshot } from '../services/projectFocus'; import codeFile from '../services/codeFile'; import brainApi from '../services/brainApi'; import viewMode, { ViewModeValue } from '../services/viewMode'; import ChatScreen from '../screens/ChatScreen'; import { TileId } from './layout'; import WorkspaceDeck from './WorkspaceDeck'; import ariaView, { AriaView } from '../services/ariaView'; import AriaViewCanvas from './AriaViewCanvas'; const COCKPIT_PANELS: TileId[] = ['chat', 'files', 'editor', 'vnc']; const WorkspaceScreen: React.FC = () => { const [mode, setMode] = useState(viewMode.get()); const [focus, setFocus] = useState(projectFocus.get()); const [hasCode, setHasCode] = useState(false); const [hasDesktop, setHasDesktop] = useState(false); const [view, setView] = useState(undefined); useEffect(() => viewMode.subscribe(setMode), []); useEffect(() => projectFocus.subscribe(setFocus), []); const pid = focus.focusedProjectId; // aria_view: ARIAs komponierte Ansicht fuers fokussierte Projekt spiegeln. useEffect(() => { setView(ariaView.getView(pid)); return ariaView.subscribe((v) => { if ((v.projectId || '') === (pid || '')) setView(v); }); }, [pid]); // Code-Signal: hat der Spiegel schon Dateien fuer dieses Projekt? useEffect(() => { setHasCode(codeFile.getFiles(pid).length > 0); return codeFile.subscribe((u) => { if ((u.projectId || '') === (pid || '')) setHasCode(true); }); }, [pid]); // Desktop-Signal: gruener Punkt NUR, wenn im AKTIVEN Projekt wirklich eine VM // laeuft (nicht generell irgendwo). Quelle ist die projektbezogene VM-Liste; // leichtes Nachfassen, damit Start/Stop sich zeitnah zeigt. useEffect(() => { if (!pid) { setHasDesktop(false); return; } let alive = true; const check = () => { brainApi.listProjectVms(pid) .then(r => { if (alive) setHasDesktop((r.vms || []).some(v => v.running)); }) .catch(() => { if (alive) setHasDesktop(false); }); }; check(); const t = setInterval(check, 6000); return () => { alive = false; clearInterval(t); }; }, [pid]); const badges = useMemo(() => ({ editor: hasCode ? '#0096FF' : undefined, vnc: hasDesktop ? '#34C759' : undefined, } as Partial>), [hasCode, hasDesktop]); // Kompakt-Ansicht: klassischer Vollbild-Chat; Cockpit: Workbench mit Dock. const content = mode === 'compact' ? ( ) : ( ); // Generative Flaeche als Overlay, sobald ARIA fuer dieses Projekt eine Ansicht // komponiert hat (present_view → aria_view). Chat/Cockpit bleiben darunter. const showView = !!view && (view.projectId || '') === (pid || ''); return ( {content} {showView && view && ( { ariaView.clear(pid); setView(undefined); }} /> )} ); }; export default WorkspaceScreen;