feat(app): Workspace-Umbau Schritt 8 — Live-Reveal + Layout-Persistenz

- Progressive Reveal: ChatScreen spiegelt bei project_changed den Projekt-Typ
  sofort in projectFocus (kind_changed nach set_project_kind) → Editor/Desktop-
  Kacheln erscheinen live, nicht erst beim Reconnect.
- useWorkspaceLayout: merkt pro Projekt die zuletzt fokussierte Kachel
  (AsyncStorage aria_workspace_layout) und stellt sie beim Zurueckkehren in ein
  Code-Projekt wieder her.

tsc clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 00:04:03 +02:00
co-authored by Claude Opus 4.8
parent 0b35ea9bde
commit ea3de70d05
3 changed files with 63 additions and 0 deletions
+18
View File
@@ -25,6 +25,7 @@ import {
boundsOf, Camera, focusCamera, overviewCamera, TileId, TILE_RECTS, toLocal,
} from './layout';
import Tile from './Tile';
import { useWorkspaceLayout } from './useWorkspaceLayout';
import ChatTile from './tiles/ChatTile';
import CodeEditorTile from './tiles/CodeEditorTile';
import VncTile from './tiles/VncTile';
@@ -49,6 +50,7 @@ const WorkspaceCanvas: React.FC<Props> = ({ projectId, visibleTiles, subtitles }
const worldW = bounds.w;
const worldH = bounds.h;
const single = visibleTiles.length <= 1;
const { loaded: layoutLoaded, getFocus, saveFocus } = useWorkspaceLayout(projectId);
// Kamera (shared values fuer 60fps auf dem UI-Thread).
const scale = useSharedValue(1);
@@ -69,6 +71,22 @@ const WorkspaceCanvas: React.FC<Props> = ({ projectId, visibleTiles, subtitles }
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [visibleKey]);
// Zuletzt fokussierte Kachel pro Projekt wiederherstellen (nur Mehr-Kachel-
// Projekte; laeuft NACH dem single-Effekt oben, gewinnt also fuer Code-Projekte).
useEffect(() => {
if (!layoutLoaded || single) return;
const stored = getFocus();
if (stored === undefined) return;
if (stored === null || visibleTiles.includes(stored)) setFocusedTileId(stored);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectId, layoutLoaded, visibleKey]);
// Fokus-Wahl persistieren.
useEffect(() => {
if (layoutLoaded) saveFocus(focusedTileId);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [focusedTileId, layoutLoaded]);
// Kamera auf das Ziel fahren (Fokus-Rect oder Uebersicht).
useEffect(() => {
const cam: Camera = focusedTileId