feat(app): service_status Banner oben in ChatScreen
App-Pendant zum Diagnostic-Banner. Wenn die Gamebox-Bridges (F5-TTS / Whisper) ihren Lade-Status broadcasten, zeigt die App oben unter der Verbindungs-Statusleiste ein farbiges Banner: Gelb = irgendwas laedt (NICHT wegtippbar) Gruen = alles bereit (tippbar zum Schliessen) Rot = Fehler Banner aggregiert beide Services in einer Kachel. Dismiss-State wird zurueckgesetzt sobald irgendein Service wieder in 'loading' geht (z.B. Modell-Wechsel via Diagnostic). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -108,6 +108,9 @@ const ChatScreen: React.FC = () => {
|
|||||||
const [searchVisible, setSearchVisible] = useState(false);
|
const [searchVisible, setSearchVisible] = useState(false);
|
||||||
const [pendingAttachments, setPendingAttachments] = useState<{file: any, isPhoto: boolean}[]>([]);
|
const [pendingAttachments, setPendingAttachments] = useState<{file: any, isPhoto: boolean}[]>([]);
|
||||||
const [agentActivity, setAgentActivity] = useState<{activity: string, tool: string}>({activity: 'idle', tool: ''});
|
const [agentActivity, setAgentActivity] = useState<{activity: string, tool: string}>({activity: 'idle', tool: ''});
|
||||||
|
// Service-Status (Gamebox: F5-TTS / Whisper Lade-Status) + Banner-Sichtbarkeit
|
||||||
|
const [serviceStatus, setServiceStatus] = useState<Record<string, {state: string, model?: string, loadSeconds?: number, error?: string}>>({});
|
||||||
|
const [serviceBannerDismissed, setServiceBannerDismissed] = useState(false);
|
||||||
// Gerätelokale TTS-Config: globaler Toggle (aus Settings) + temporäres Muten (Mund-Button)
|
// Gerätelokale TTS-Config: globaler Toggle (aus Settings) + temporäres Muten (Mund-Button)
|
||||||
const [ttsDeviceEnabled, setTtsDeviceEnabled] = useState(true);
|
const [ttsDeviceEnabled, setTtsDeviceEnabled] = useState(true);
|
||||||
const [ttsMuted, setTtsMuted] = useState(false);
|
const [ttsMuted, setTtsMuted] = useState(false);
|
||||||
@@ -351,6 +354,24 @@ const ChatScreen: React.FC = () => {
|
|||||||
ToastAndroid.show(`Stimme "${v || 'Standard'}" bereit`, ToastAndroid.SHORT);
|
ToastAndroid.show(`Stimme "${v || 'Standard'}" bereit`, ToastAndroid.SHORT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gamebox-Bridges (f5tts/whisper) melden Lade-Status — Banner oben
|
||||||
|
if (message.type === ('service_status' as any)) {
|
||||||
|
const p = message.payload as any;
|
||||||
|
const svc = (p?.service as string) || '';
|
||||||
|
if (!svc) return;
|
||||||
|
setServiceStatus(prev => ({
|
||||||
|
...prev,
|
||||||
|
[svc]: {
|
||||||
|
state: (p?.state as string) || 'unknown',
|
||||||
|
model: p?.model as string | undefined,
|
||||||
|
loadSeconds: p?.loadSeconds as number | undefined,
|
||||||
|
error: p?.error as string | undefined,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
// Bei neuer Loading-Phase Banner wieder aktivieren
|
||||||
|
if (p?.state === 'loading') setServiceBannerDismissed(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const unsubState = rvs.onStateChange((state) => {
|
const unsubState = rvs.onStateChange((state) => {
|
||||||
@@ -764,6 +785,49 @@ const ChatScreen: React.FC = () => {
|
|||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{/* Service-Status Banner (Gamebox: F5-TTS / Whisper Lade-Status) */}
|
||||||
|
{(() => {
|
||||||
|
const entries = Object.entries(serviceStatus);
|
||||||
|
if (entries.length === 0 || serviceBannerDismissed) return null;
|
||||||
|
const anyLoading = entries.some(([, v]) => v.state === 'loading');
|
||||||
|
const anyError = entries.some(([, v]) => v.state === 'error');
|
||||||
|
const allReady = !anyLoading && !anyError && entries.every(([, v]) => v.state === 'ready');
|
||||||
|
const bg = anyError ? '#3A1F1F' : anyLoading ? '#3A331F' : '#1F3A2A';
|
||||||
|
const border = anyError ? '#FF3B30' : anyLoading ? '#FFD60A' : '#34C759';
|
||||||
|
const labels: Record<string, string> = { f5tts: 'F5-TTS', whisper: 'Whisper STT' };
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
activeOpacity={allReady ? 0.6 : 1.0}
|
||||||
|
onPress={() => { if (allReady) setServiceBannerDismissed(true); }}
|
||||||
|
style={[styles.serviceBanner, { backgroundColor: bg, borderColor: border }]}
|
||||||
|
>
|
||||||
|
{entries.map(([svc, info]) => {
|
||||||
|
let icon = '\u23F3', text = '';
|
||||||
|
if (info.state === 'loading') {
|
||||||
|
text = `${labels[svc] || svc}: laedt${info.model ? ' ' + info.model : ''}...`;
|
||||||
|
} else if (info.state === 'ready') {
|
||||||
|
icon = '\u2705';
|
||||||
|
const sec = info.loadSeconds ? ` (${info.loadSeconds.toFixed(1)}s)` : '';
|
||||||
|
text = `${labels[svc] || svc}: bereit${info.model ? ' ' + info.model : ''}${sec}`;
|
||||||
|
} else if (info.state === 'error') {
|
||||||
|
icon = '\u274C';
|
||||||
|
text = `${labels[svc] || svc}: Fehler ${info.error || ''}`;
|
||||||
|
} else {
|
||||||
|
text = `${labels[svc] || svc}: ${info.state}`;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Text key={svc} style={styles.serviceBannerLine}>
|
||||||
|
{icon} {text}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Text style={styles.serviceBannerHint}>
|
||||||
|
{allReady ? 'Tippen zum Schliessen' : 'Bitte warten...'}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
|
||||||
{/* Suchleiste */}
|
{/* Suchleiste */}
|
||||||
{searchVisible && (
|
{searchVisible && (
|
||||||
<View style={styles.searchBar}>
|
<View style={styles.searchBar}>
|
||||||
@@ -978,6 +1042,25 @@ const styles = StyleSheet.create({
|
|||||||
color: '#8888AA',
|
color: '#8888AA',
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
},
|
},
|
||||||
|
serviceBanner: {
|
||||||
|
paddingVertical: 8,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
borderTopWidth: 0,
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderLeftWidth: 0,
|
||||||
|
borderRightWidth: 0,
|
||||||
|
},
|
||||||
|
serviceBannerLine: {
|
||||||
|
color: '#FFFFFF',
|
||||||
|
fontSize: 12,
|
||||||
|
lineHeight: 18,
|
||||||
|
},
|
||||||
|
serviceBannerHint: {
|
||||||
|
color: '#AAAACC',
|
||||||
|
fontSize: 10,
|
||||||
|
marginTop: 2,
|
||||||
|
fontStyle: 'italic',
|
||||||
|
},
|
||||||
messageList: {
|
messageList: {
|
||||||
padding: 12,
|
padding: 12,
|
||||||
paddingBottom: 8,
|
paddingBottom: 8,
|
||||||
|
|||||||
Reference in New Issue
Block a user