diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1a5b017..78348e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,7 +16,8 @@ Alle Änderungen am Projekt. Format: [Keep a Changelog](https://keepachangelog.c
- **Ansichts-Umschalter im Header** („⧉ Kompakt" / „⧉ Cockpit"): Die App startet in **Kompakt** — der klassische Vollbild-Chat, **exakt wie vor dem Umbau** (Default, Mama-tauglich). Ein Tap auf den Button oben rechts schaltet auf **Cockpit** — den zoom-/verschiebbaren Kachel-Desktop. Persistiert über Neustart (`aria_view_mode`).
- **Warum:** Nach dem 0.2.1.8-Deploy sah die App „unverändert" aus — korrekt, denn im normalen Chat gibt es nur eine Kachel (= Vollbild-Chat). Der Umschalter macht den Cockpit-Modus jetzt **explizit sichtbar/steuerbar**, statt nur bei Code-Projekten aufzutauchen.
-- Im Cockpit ist die **Übersicht jetzt immer erreichbar** (auch im Hauptchat mit nur einer Kachel): „⤢ Übersicht"-Button (unten rechts, weg von den Chat-Kopf-Icons), 2-Finger-Pinch/Pan, Hardware-Back.
+- Im Cockpit ist die **Übersicht jetzt immer erreichbar** (auch im Hauptchat): „⤢ Übersicht" sitzt **im Header links** (kollidiert nicht mehr mit dem Abbrechen-Button der „ARIA denkt"-Leiste), dazu 2-Finger-Pinch/Pan und Hardware-Back.
+- Im Cockpit werden **immer alle vier Kacheln** gezeigt (Chat/Editor/Desktop/Vorschau) — Editor/Desktop/Vorschau als Platzhalter mit Status-Untertitel („kein Code-Projekt" / „kein Desktop"), bis ARIA ein Code-Projekt startet bzw. eine VM läuft. Vorher wirkten sie „verschwunden", weil sie erst bei Code-Projekten auftauchten.
---
diff --git a/android/App.tsx b/android/App.tsx
index 2baf3f8..99dddd7 100644
--- a/android/App.tsx
+++ b/android/App.tsx
@@ -15,6 +15,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import WorkspaceScreen from './src/workspace/WorkspaceScreen';
import SettingsScreen from './src/screens/SettingsScreen';
import ViewModeToggle from './src/components/ViewModeToggle';
+import CockpitOverviewButton from './src/components/CockpitOverviewButton';
import rvs from './src/services/rvs';
import { initLogger, installGlobalCrashReporter } from './src/services/logger';
import { acquireBackgroundAudio } from './src/services/backgroundAudio';
@@ -171,6 +172,7 @@ const App: React.FC = () => {
options={{
title: 'ARIA Chat',
headerTitle: 'ARIA Cockpit',
+ headerLeft: () => ,
headerRight: () => ,
}}
/>
diff --git a/android/src/components/CockpitOverviewButton.tsx b/android/src/components/CockpitOverviewButton.tsx
new file mode 100644
index 0000000..38e5ba0
--- /dev/null
+++ b/android/src/components/CockpitOverviewButton.tsx
@@ -0,0 +1,48 @@
+/**
+ * CockpitOverviewButton — Header-Button (links) für „⤢ Übersicht".
+ *
+ * Nur sichtbar im Cockpit-Modus, wenn gerade eine Kachel fokussiert ist. Sitzt
+ * im Navigations-Header, kollidiert also mit nichts im Chat (früher hing er über
+ * dem Abbrechen-Button der „ARIA denkt"-Leiste).
+ */
+
+import React, { useEffect, useState } from 'react';
+import { StyleSheet, Text, TouchableOpacity } from 'react-native';
+import cockpitNav from '../services/cockpitNav';
+import viewMode, { ViewModeValue } from '../services/viewMode';
+
+const CockpitOverviewButton: React.FC = () => {
+ const [mode, setMode] = useState(viewMode.get());
+ const [focused, setFocused] = useState(cockpitNav.isFocused());
+
+ useEffect(() => viewMode.subscribe(setMode), []);
+ useEffect(() => cockpitNav.subscribe(setFocused), []);
+
+ if (mode !== 'cockpit' || !focused) return null;
+
+ return (
+ cockpitNav.requestOverview()}
+ style={styles.pill}
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
+ activeOpacity={0.75}
+ >
+ ⤢ Übersicht
+
+ );
+};
+
+const styles = StyleSheet.create({
+ pill: {
+ marginLeft: 12,
+ paddingHorizontal: 12,
+ paddingVertical: 6,
+ borderRadius: 16,
+ borderWidth: 1,
+ borderColor: '#0096FF',
+ backgroundColor: '#0A1F33',
+ },
+ text: { color: '#0096FF', fontSize: 13, fontWeight: '700' },
+});
+
+export default CockpitOverviewButton;
diff --git a/android/src/services/cockpitNav.ts b/android/src/services/cockpitNav.ts
new file mode 100644
index 0000000..315cafe
--- /dev/null
+++ b/android/src/services/cockpitNav.ts
@@ -0,0 +1,43 @@
+/**
+ * cockpitNav — kleine Brücke zwischen WorkspaceCanvas (Fokus-Zustand) und dem
+ * Navigations-Header, damit der „⤢ Übersicht"-Button im Header sitzen kann
+ * (kollidiert dort mit nichts im Chat) statt im überfüllten Chat-Inhalt.
+ *
+ * Der Canvas meldet, ob gerade eine Kachel fokussiert ist, und registriert eine
+ * Aktion zum Zurück-zur-Übersicht. Der Header abonniert den Zustand und ruft die
+ * Aktion. Muster wie services/rvs.ts (Singleton).
+ */
+
+type Sub = (focused: boolean) => void;
+
+class CockpitNav {
+ private focused = false;
+ private overviewHandler: (() => void) | null = null;
+ private subs: Sub[] = [];
+
+ isFocused(): boolean { return this.focused; }
+
+ setFocused(f: boolean): void {
+ if (this.focused === f) return;
+ this.focused = f;
+ this.subs.forEach((cb) => cb(f));
+ }
+
+ /** Canvas registriert seine „zur Übersicht"-Aktion (null beim Unmount). */
+ registerOverview(fn: (() => void) | null): void {
+ this.overviewHandler = fn;
+ }
+
+ requestOverview(): void {
+ this.overviewHandler?.();
+ }
+
+ subscribe(cb: Sub): () => void {
+ this.subs.push(cb);
+ cb(this.focused);
+ return () => { this.subs = this.subs.filter((s) => s !== cb); };
+ }
+}
+
+const cockpitNav = new CockpitNav();
+export default cockpitNav;
diff --git a/android/src/workspace/WorkspaceCanvas.tsx b/android/src/workspace/WorkspaceCanvas.tsx
index 04394f0..54db78d 100644
--- a/android/src/workspace/WorkspaceCanvas.tsx
+++ b/android/src/workspace/WorkspaceCanvas.tsx
@@ -17,13 +17,14 @@
*/
import React, { useEffect, useMemo, useState } from 'react';
-import { BackHandler, StyleSheet, Text, TouchableOpacity, useWindowDimensions, View } from 'react-native';
+import { BackHandler, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import {
boundsOf, Camera, focusCamera, overviewCamera, TileId, TILE_RECTS, toLocal,
} from './layout';
+import cockpitNav from '../services/cockpitNav';
import Tile from './Tile';
import { useWorkspaceLayout } from './useWorkspaceLayout';
import ChatTile from './tiles/ChatTile';
@@ -96,6 +97,14 @@ const WorkspaceCanvas: React.FC = ({ projectId, visibleTiles, subtitles }
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [focusedTileId, visibleKey, vw, vh]);
+ // Fokus-Zustand + „zur Uebersicht"-Aktion an den Header (cockpitNav) melden,
+ // damit der Uebersicht-Button dort sitzt (kollidiert nicht mit dem Chat).
+ useEffect(() => {
+ cockpitNav.setFocused(focusedTileId != null);
+ cockpitNav.registerOverview(() => setFocusedTileId(null));
+ return () => { cockpitNav.registerOverview(null); cockpitNav.setFocused(false); };
+ }, [focusedTileId]);
+
// Hardware-Back: im Fokus → zurueck zur Uebersicht.
useEffect(() => {
const onBack = () => {
@@ -188,12 +197,8 @@ const WorkspaceCanvas: React.FC = ({ projectId, visibleTiles, subtitles }
))}
- {/* Steuerung */}
- {focusedTileId && (
- setFocusedTileId(null)} activeOpacity={0.8}>
- ⤢ Übersicht
-
- )}
+ {/* Steuerung — der „⤢ Übersicht"-Button sitzt im Header (cockpitNav),
+ nicht hier im Chat-Inhalt. */}
{!focusedTileId && (
Kachel antippen zum Öffnen · 2 Finger: zoomen & schieben
@@ -206,20 +211,6 @@ const WorkspaceCanvas: React.FC = ({ projectId, visibleTiles, subtitles }
const styles = StyleSheet.create({
root: { flex: 1, backgroundColor: '#0D0D1A' },
world: { position: 'absolute', left: 0, top: 0 },
- // Unten rechts (ueber der Chat-Eingabezeile) — weg von ChatScreens Kopf-Icons.
- overviewBtn: {
- position: 'absolute',
- bottom: 88,
- right: 14,
- backgroundColor: 'rgba(18,18,42,0.92)',
- borderColor: '#0096FF',
- borderWidth: 1,
- borderRadius: 18,
- paddingHorizontal: 14,
- paddingVertical: 8,
- elevation: 4,
- },
- overviewBtnText: { color: '#0096FF', fontSize: 14, fontWeight: '700' },
hintBar: {
position: 'absolute',
bottom: 16,
diff --git a/android/src/workspace/WorkspaceScreen.tsx b/android/src/workspace/WorkspaceScreen.tsx
index dae99dc..72e5974 100644
--- a/android/src/workspace/WorkspaceScreen.tsx
+++ b/android/src/workspace/WorkspaceScreen.tsx
@@ -16,7 +16,7 @@ import codeFile from '../services/codeFile';
import desktop from '../services/desktop';
import viewMode, { ViewModeValue } from '../services/viewMode';
import ChatScreen from '../screens/ChatScreen';
-import { TileId, visibleTilesFor } from './layout';
+import { TileId, TILE_ORDER } from './layout';
import WorkspaceCanvas from './WorkspaceCanvas';
const WorkspaceScreen: React.FC = () => {
@@ -47,15 +47,21 @@ const WorkspaceScreen: React.FC = () => {
return unsub;
}, [pid, kind]);
- const visibleTiles: TileId[] = useMemo(
- () => visibleTilesFor({ kind, hasCode, hasDesktop }),
- [kind, hasCode, hasDesktop],
- );
+ // Im Cockpit immer alle Kacheln zeigen (Editor/Desktop/Vorschau als
+ // Platzhalter, bis ein Code-Projekt/VM aktiv ist) — sonst „fehlen" sie
+ // gefuehlt. isCode blendet nur die Untertitel-Info um.
+ const visibleTiles: TileId[] = TILE_ORDER;
+ const isCode = kind === 'code' || hasCode || hasDesktop;
- const subtitles = useMemo(
- () => ({ chat: pid ? projectFocus.getProjectName(pid) : 'Hauptchat' } as Partial>),
- [pid, focus.projectNameById],
- );
+ const subtitles = useMemo(() => {
+ const fileCount = codeFile.getFiles(pid).length;
+ return {
+ chat: pid ? projectFocus.getProjectName(pid) : 'Hauptchat',
+ editor: isCode ? `${fileCount} Datei${fileCount === 1 ? '' : 'en'}` : 'kein Code-Projekt',
+ vnc: hasDesktop ? 'verbunden' : 'kein Desktop',
+ preview: undefined,
+ } as Partial>;
+ }, [pid, focus.projectNameById, isCode, hasCode, hasDesktop]);
// Kompakt-Ansicht: klassischer Vollbild-Chat, exakt wie vor dem Umbau.
if (mode === 'compact') {