fix(app): Cockpit — alle Kacheln sichtbar + Uebersicht-Button in den Header
Zwei Nachbesserungen am Cockpit-Modus (noch Teil von 0.2.1.9): - Im Cockpit werden IMMER alle vier Kacheln gezeigt (Chat/Editor/Desktop/ Vorschau) statt erst bei Code-Projekten — Editor/Desktop/Vorschau als Platzhalter mit Status-Untertitel. Vorher wirkten sie "verschwunden". - Der "⤢ Uebersicht"-Button hing im Chat genau ueber dem Abbrechen-Button der "ARIA denkt"-Leiste. Jetzt sitzt er im Navigations-Header links (nur sichtbar im Cockpit + Fokus), via neuem cockpitNav-Signal-Singleton. In-Content-Button entfernt. tsc clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+2
-1
@@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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: () => <CockpitOverviewButton />,
|
||||
headerRight: () => <ViewModeToggle />,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -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<ViewModeValue>(viewMode.get());
|
||||
const [focused, setFocused] = useState<boolean>(cockpitNav.isFocused());
|
||||
|
||||
useEffect(() => viewMode.subscribe(setMode), []);
|
||||
useEffect(() => cockpitNav.subscribe(setFocused), []);
|
||||
|
||||
if (mode !== 'cockpit' || !focused) return null;
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => cockpitNav.requestOverview()}
|
||||
style={styles.pill}
|
||||
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
||||
activeOpacity={0.75}
|
||||
>
|
||||
<Text style={styles.text}>⤢ Übersicht</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -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;
|
||||
@@ -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<Props> = ({ 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<Props> = ({ projectId, visibleTiles, subtitles }
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* Steuerung */}
|
||||
{focusedTileId && (
|
||||
<TouchableOpacity style={styles.overviewBtn} onPress={() => setFocusedTileId(null)} activeOpacity={0.8}>
|
||||
<Text style={styles.overviewBtnText}>⤢ Übersicht</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{/* Steuerung — der „⤢ Übersicht"-Button sitzt im Header (cockpitNav),
|
||||
nicht hier im Chat-Inhalt. */}
|
||||
{!focusedTileId && (
|
||||
<View style={styles.hintBar} pointerEvents="none">
|
||||
<Text style={styles.hintText}>Kachel antippen zum Öffnen · 2 Finger: zoomen & schieben</Text>
|
||||
@@ -206,20 +211,6 @@ const WorkspaceCanvas: React.FC<Props> = ({ 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,
|
||||
|
||||
@@ -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<Record<TileId, string>>),
|
||||
[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<Record<TileId, string>>;
|
||||
}, [pid, focus.projectNameById, isCode, hasCode, hasDesktop]);
|
||||
|
||||
// Kompakt-Ansicht: klassischer Vollbild-Chat, exakt wie vor dem Umbau.
|
||||
if (mode === 'compact') {
|
||||
|
||||
Reference in New Issue
Block a user