246 lines
5.5 KiB
TypeScript
246 lines
5.5 KiB
TypeScript
/**
|
|
* ModeSelector - Modus-Auswahl fuer ARIA
|
|
*
|
|
* Zeigt den aktuellen Betriebsmodus an und ermoeglicht das Umschalten
|
|
* ueber ein Modal-Dropdown.
|
|
*/
|
|
|
|
import React, { useState } from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
TouchableOpacity,
|
|
Modal,
|
|
FlatList,
|
|
StyleSheet,
|
|
} from 'react-native';
|
|
import rvs from '../services/rvs';
|
|
|
|
// --- Typen ---
|
|
|
|
export interface Mode {
|
|
id: string;
|
|
label: string;
|
|
emoji: string;
|
|
description: string;
|
|
}
|
|
|
|
interface ModeSelectorProps {
|
|
currentModeId: string;
|
|
onModeChange: (modeId: string) => void;
|
|
}
|
|
|
|
// --- Verfuegbare Modi ---
|
|
|
|
export const MODES: Mode[] = [
|
|
{
|
|
id: 'normal',
|
|
label: 'Normal',
|
|
emoji: '\uD83D\uDFE2',
|
|
description: 'Standardmodus - ARIA reagiert auf alle Eingaben',
|
|
},
|
|
{
|
|
id: 'nicht_stoeren',
|
|
label: 'Nicht st\u00F6ren',
|
|
emoji: '\uD83D\uDD34',
|
|
description: 'Nur kritische Benachrichtigungen',
|
|
},
|
|
{
|
|
id: 'fluester',
|
|
label: 'Fl\u00FCster',
|
|
emoji: '\uD83D\uDFE1',
|
|
description: 'Leise Antworten, reduzierte Aktivit\u00E4t',
|
|
},
|
|
{
|
|
id: 'hangar',
|
|
label: 'Hangar',
|
|
emoji: '\u2708\uFE0F',
|
|
description: 'Flugmodus - minimale Kommunikation',
|
|
},
|
|
{
|
|
id: 'gaming',
|
|
label: 'Gaming',
|
|
emoji: '\uD83C\uDFAE',
|
|
description: 'Spielmodus - nur dringende Meldungen',
|
|
},
|
|
];
|
|
|
|
// --- Komponente ---
|
|
|
|
const ModeSelector: React.FC<ModeSelectorProps> = ({ currentModeId, onModeChange }) => {
|
|
const [modalVisible, setModalVisible] = useState(false);
|
|
|
|
const currentMode = MODES.find(m => m.id === currentModeId) || MODES[0];
|
|
|
|
const handleSelectMode = (mode: Mode) => {
|
|
setModalVisible(false);
|
|
onModeChange(mode.id);
|
|
|
|
// Moduswechsel an ARIA senden
|
|
rvs.send('mode', { mode: mode.id });
|
|
};
|
|
|
|
const renderModeItem = ({ item }: { item: Mode }) => {
|
|
const isActive = item.id === currentModeId;
|
|
return (
|
|
<TouchableOpacity
|
|
style={[styles.modeItem, isActive && styles.modeItemActive]}
|
|
onPress={() => handleSelectMode(item)}
|
|
activeOpacity={0.7}
|
|
>
|
|
<Text style={styles.modeEmoji}>{item.emoji}</Text>
|
|
<View style={styles.modeTextContainer}>
|
|
<Text style={[styles.modeLabel, isActive && styles.modeLabelActive]}>
|
|
{item.label}
|
|
</Text>
|
|
<Text style={styles.modeDescription}>{item.description}</Text>
|
|
</View>
|
|
{isActive && <Text style={styles.checkmark}>{'\u2713'}</Text>}
|
|
</TouchableOpacity>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<View>
|
|
{/* Aktueller Modus - Tappen zum Oeffnen */}
|
|
<TouchableOpacity
|
|
style={styles.currentMode}
|
|
onPress={() => setModalVisible(true)}
|
|
activeOpacity={0.7}
|
|
>
|
|
<Text style={styles.currentEmoji}>{currentMode.emoji}</Text>
|
|
<Text style={styles.currentLabel}>{currentMode.label}</Text>
|
|
<Text style={styles.chevron}>{'\u25BC'}</Text>
|
|
</TouchableOpacity>
|
|
|
|
{/* Modus-Auswahl Modal */}
|
|
<Modal
|
|
visible={modalVisible}
|
|
transparent
|
|
animationType="slide"
|
|
onRequestClose={() => setModalVisible(false)}
|
|
>
|
|
<TouchableOpacity
|
|
style={styles.modalOverlay}
|
|
activeOpacity={1}
|
|
onPress={() => setModalVisible(false)}
|
|
>
|
|
<View style={styles.modalContent}>
|
|
<Text style={styles.modalTitle}>Modus w\u00E4hlen</Text>
|
|
<FlatList
|
|
data={MODES}
|
|
keyExtractor={item => item.id}
|
|
renderItem={renderModeItem}
|
|
scrollEnabled={false}
|
|
/>
|
|
<TouchableOpacity
|
|
style={styles.cancelButton}
|
|
onPress={() => setModalVisible(false)}
|
|
>
|
|
<Text style={styles.cancelText}>Abbrechen</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</TouchableOpacity>
|
|
</Modal>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
// --- Styles ---
|
|
|
|
const styles = StyleSheet.create({
|
|
currentMode: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
backgroundColor: '#1E1E2E',
|
|
borderRadius: 12,
|
|
padding: 14,
|
|
borderWidth: 1,
|
|
borderColor: '#2A2A3E',
|
|
},
|
|
currentEmoji: {
|
|
fontSize: 22,
|
|
marginRight: 10,
|
|
},
|
|
currentLabel: {
|
|
color: '#FFFFFF',
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
flex: 1,
|
|
},
|
|
chevron: {
|
|
color: '#8888AA',
|
|
fontSize: 12,
|
|
},
|
|
modalOverlay: {
|
|
flex: 1,
|
|
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
justifyContent: 'flex-end',
|
|
},
|
|
modalContent: {
|
|
backgroundColor: '#1A1A2E',
|
|
borderTopLeftRadius: 20,
|
|
borderTopRightRadius: 20,
|
|
padding: 20,
|
|
paddingBottom: 40,
|
|
},
|
|
modalTitle: {
|
|
color: '#FFFFFF',
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
textAlign: 'center',
|
|
marginBottom: 16,
|
|
},
|
|
modeItem: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
padding: 14,
|
|
borderRadius: 10,
|
|
marginBottom: 6,
|
|
},
|
|
modeItemActive: {
|
|
backgroundColor: 'rgba(0, 150, 255, 0.15)',
|
|
},
|
|
modeEmoji: {
|
|
fontSize: 26,
|
|
marginRight: 14,
|
|
},
|
|
modeTextContainer: {
|
|
flex: 1,
|
|
},
|
|
modeLabel: {
|
|
color: '#CCCCDD',
|
|
fontSize: 16,
|
|
fontWeight: '500',
|
|
},
|
|
modeLabelActive: {
|
|
color: '#0096FF',
|
|
fontWeight: '700',
|
|
},
|
|
modeDescription: {
|
|
color: '#666680',
|
|
fontSize: 12,
|
|
marginTop: 2,
|
|
},
|
|
checkmark: {
|
|
color: '#0096FF',
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
marginLeft: 8,
|
|
},
|
|
cancelButton: {
|
|
marginTop: 12,
|
|
padding: 14,
|
|
borderRadius: 10,
|
|
backgroundColor: '#2A2A3E',
|
|
alignItems: 'center',
|
|
},
|
|
cancelText: {
|
|
color: '#8888AA',
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
},
|
|
});
|
|
|
|
export default ModeSelector;
|