feat(app): Workspace-Umbau Schritt 4 — zoombarer Canvas + Fokus/Uebersicht
Der Chat-Tab hostet ab jetzt den Workspace-Canvas (eine ChatScreen-Instanz,
kein Doppel-Mount). Zwei Ebenen:
- Welt-Ebene (reanimated scale/translate): leichte Thumbnail-Kacheln, 2-Finger
Pinch-Zoom + 2-Finger-Pan nur in der Uebersicht (gesture-handler).
- Identity-Content-Ebene (Scale 1): schwere Inhalte (ChatScreen + kommende
WebViews) immer gemountet, nur die fokussierte per display sichtbar → Touch/
Keyboard bleiben korrekt, nichts remountet beim Fokuswechsel.
Tap auf Kachel = Fokus (voll interaktiv), "⤢ Uebersicht"/Hardware-Back = zurueck
zur Landkarte. Bei nur einer Kachel (reiner Chat) ist diese dauerhaft fokussiert
→ verhaelt sich exakt wie der bisherige Vollbild-Chat.
Neue Dateien unter android/src/workspace/: layout.ts (Kamera-Mathe, Center-
Origin fuer RN 0.73), WorkspaceCanvas.tsx, WorkspaceScreen.tsx, Tile.tsx,
tiles/{ChatTile,CodeEditorTile,VncTile,PreviewTile}.tsx. Editor/VNC sind noch
Platzhalter (Commit 5/7). tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* WorkspaceScreen — Screen-Wrapper fuer den Workspace-Canvas.
|
||||
*
|
||||
* Buendelt die Signale, die entscheiden welche Kacheln sichtbar sind:
|
||||
* - projectFocus: aktives Projekt + dessen kind ('code'|'chat')
|
||||
* - codeFile: kam schon eine Code-Datei rein? (Live-Reveal des Editors)
|
||||
* - desktop: ist ein QEMU-Desktop verfuegbar? (Live-Reveal der VNC-Kachel)
|
||||
*
|
||||
* Ersetzt den bisherigen Chat-Tab: die ChatScreen lebt als Kachel im Canvas,
|
||||
* bleibt aber genau eine Instanz.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import projectFocus, { FocusSnapshot } from '../services/projectFocus';
|
||||
import codeFile from '../services/codeFile';
|
||||
import desktop from '../services/desktop';
|
||||
import { TileId, visibleTilesFor } from './layout';
|
||||
import WorkspaceCanvas from './WorkspaceCanvas';
|
||||
|
||||
const WorkspaceScreen: React.FC = () => {
|
||||
const [focus, setFocus] = useState<FocusSnapshot>(projectFocus.get());
|
||||
const [hasCode, setHasCode] = useState(false);
|
||||
const [hasDesktop, setHasDesktop] = useState(false);
|
||||
|
||||
useEffect(() => projectFocus.subscribe(setFocus), []);
|
||||
|
||||
const pid = focus.focusedProjectId;
|
||||
const kind = projectFocus.getProjectKind(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 + einmaliger Check beim Betreten eines Code-Projekts.
|
||||
useEffect(() => {
|
||||
setHasDesktop(desktop.getStatus().available);
|
||||
const unsub = desktop.subscribeStatus((s) => setHasDesktop(s.available));
|
||||
if (kind === 'code') desktop.requestCheck(pid);
|
||||
return unsub;
|
||||
}, [pid, kind]);
|
||||
|
||||
const visibleTiles: TileId[] = useMemo(
|
||||
() => visibleTilesFor({ kind, hasCode, hasDesktop }),
|
||||
[kind, hasCode, hasDesktop],
|
||||
);
|
||||
|
||||
const subtitles = useMemo(
|
||||
() => ({ chat: pid ? projectFocus.getProjectName(pid) : 'Hauptchat' } as Partial<Record<TileId, string>>),
|
||||
[pid, focus.projectNameById],
|
||||
);
|
||||
|
||||
return <WorkspaceCanvas projectId={pid} visibleTiles={visibleTiles} subtitles={subtitles} />;
|
||||
};
|
||||
|
||||
export default WorkspaceScreen;
|
||||
Reference in New Issue
Block a user