230 lines
9.3 KiB
TypeScript
230 lines
9.3 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { View, Text, TouchableOpacity, ScrollView, StyleSheet } from 'react-native';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { useRouter } from 'expo-router';
|
|
import { useApp } from '../../context/AppContext';
|
|
import { useColors } from '../../constants/Colors';
|
|
import { ThemeBackdrop } from '../../components/ThemeBackdrop';
|
|
import { AppearanceMode, ColorPalette, Language } from '../../types';
|
|
|
|
const PALETTE_SWATCHES: Record<ColorPalette, string[]> = {
|
|
forest: ['#5fa779', '#3d7f57'],
|
|
ocean: ['#5a90be', '#3d6f99'],
|
|
sunset: ['#c98965', '#a36442'],
|
|
mono: ['#7b8796', '#5b6574'],
|
|
};
|
|
|
|
const getPreferencesCopy = (language: Language) => {
|
|
if (language === 'de') {
|
|
return {
|
|
title: 'Einstellungen',
|
|
appearanceMode: 'Modell',
|
|
colorPalette: 'Farbpalette',
|
|
languageLabel: 'Sprache',
|
|
themeSystem: 'System',
|
|
themeLight: 'Hell',
|
|
themeDark: 'Dunkel',
|
|
paletteForest: 'Forest',
|
|
paletteOcean: 'Ocean',
|
|
paletteSunset: 'Sunset',
|
|
paletteMono: 'Mono',
|
|
};
|
|
} else if (language === 'es') {
|
|
return {
|
|
title: 'Ajustes',
|
|
appearanceMode: 'Modo',
|
|
colorPalette: 'Paleta',
|
|
languageLabel: 'Idioma',
|
|
themeSystem: 'Sistema',
|
|
themeLight: 'Claro',
|
|
themeDark: 'Oscuro',
|
|
paletteForest: 'Forest',
|
|
paletteOcean: 'Ocean',
|
|
paletteSunset: 'Sunset',
|
|
paletteMono: 'Mono',
|
|
};
|
|
}
|
|
return {
|
|
title: 'Preferences',
|
|
appearanceMode: 'Appearance Mode',
|
|
colorPalette: 'Color Palette',
|
|
languageLabel: 'Language',
|
|
themeSystem: 'System',
|
|
themeLight: 'Light',
|
|
themeDark: 'Dark',
|
|
paletteForest: 'Forest',
|
|
paletteOcean: 'Ocean',
|
|
paletteSunset: 'Sunset',
|
|
paletteMono: 'Mono',
|
|
};
|
|
};
|
|
|
|
export default function PreferencesScreen() {
|
|
const router = useRouter();
|
|
const { isDarkMode, appearanceMode, colorPalette, language, setAppearanceMode, setColorPalette, changeLanguage } = useApp();
|
|
const colors = useColors(isDarkMode, colorPalette);
|
|
const copy = getPreferencesCopy(language);
|
|
|
|
return (
|
|
<View style={{ flex: 1, backgroundColor: colors.background }}>
|
|
<ThemeBackdrop colors={colors} />
|
|
<SafeAreaView style={styles.safeArea} edges={['top']}>
|
|
<View style={styles.header}>
|
|
<TouchableOpacity onPress={() => router.back()} style={styles.backButton}>
|
|
<Ionicons name="arrow-back" size={24} color={colors.text} />
|
|
</TouchableOpacity>
|
|
<Text style={[styles.title, { color: colors.text }]}>{copy.title}</Text>
|
|
<View style={{ width: 40 }} />
|
|
</View>
|
|
<ScrollView contentContainerStyle={styles.scrollContent}>
|
|
|
|
<View style={[styles.card, { backgroundColor: colors.cardBg, borderColor: colors.border }]}>
|
|
<Text style={[styles.sectionTitle, { color: colors.text }]}>{copy.appearanceMode}</Text>
|
|
<View style={styles.segmentedControl}>
|
|
{(['system', 'light', 'dark'] as AppearanceMode[]).map((mode) => {
|
|
const isActive = appearanceMode === mode;
|
|
const label = mode === 'system' ? copy.themeSystem : mode === 'light' ? copy.themeLight : copy.themeDark;
|
|
return (
|
|
<TouchableOpacity
|
|
key={mode}
|
|
style={[
|
|
styles.segmentBtn,
|
|
isActive && { backgroundColor: colors.primary },
|
|
]}
|
|
onPress={() => setAppearanceMode(mode)}
|
|
>
|
|
<Text style={[
|
|
styles.segmentText,
|
|
{ color: isActive ? '#fff' : colors.text }
|
|
]}>
|
|
{label}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
);
|
|
})}
|
|
</View>
|
|
</View>
|
|
|
|
<View style={[styles.card, { backgroundColor: colors.cardBg, borderColor: colors.border }]}>
|
|
<Text style={[styles.sectionTitle, { color: colors.text }]}>{copy.colorPalette}</Text>
|
|
<View style={styles.swatchContainer}>
|
|
{(['forest', 'ocean', 'sunset', 'mono'] as ColorPalette[]).map((p) => {
|
|
const isActive = colorPalette === p;
|
|
const swatch = PALETTE_SWATCHES[p] || ['#ccc', '#999'];
|
|
const label = p === 'forest' ? copy.paletteForest : p === 'ocean' ? copy.paletteOcean : p === 'sunset' ? copy.paletteSunset : copy.paletteMono;
|
|
return (
|
|
<TouchableOpacity
|
|
key={p}
|
|
style={[
|
|
styles.swatchWrap,
|
|
isActive && { borderColor: colors.primary, borderWidth: 2 }
|
|
]}
|
|
onPress={() => setColorPalette(p)}
|
|
>
|
|
<View style={[styles.swatch, { backgroundColor: swatch[0] }]} />
|
|
<Text style={[styles.swatchLabel, { color: colors.text }]}>{label}</Text>
|
|
</TouchableOpacity>
|
|
);
|
|
})}
|
|
</View>
|
|
</View>
|
|
|
|
<View style={[styles.card, { backgroundColor: colors.cardBg, borderColor: colors.border }]}>
|
|
<Text style={[styles.sectionTitle, { color: colors.text }]}>{copy.languageLabel}</Text>
|
|
<View style={styles.langRow}>
|
|
{(['en', 'de', 'es'] as Language[]).map(lang => {
|
|
const isActive = language === lang;
|
|
const label = lang === 'en' ? 'English' : lang === 'de' ? 'Deutsch' : 'Español';
|
|
return (
|
|
<TouchableOpacity
|
|
key={lang}
|
|
style={[
|
|
styles.langBtn,
|
|
isActive && { backgroundColor: colors.primary }
|
|
]}
|
|
onPress={() => changeLanguage(lang)}
|
|
>
|
|
<Text style={isActive ? { color: '#fff', fontWeight: '600' } : { color: colors.text }}>
|
|
{label}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
);
|
|
})}
|
|
</View>
|
|
</View>
|
|
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
safeArea: { flex: 1 },
|
|
header: { flexDirection: 'row', alignItems: 'center', padding: 16 },
|
|
backButton: { width: 40, height: 40, justifyContent: 'center' },
|
|
title: { flex: 1, fontSize: 20, fontWeight: '700', textAlign: 'center' },
|
|
scrollContent: { padding: 16, gap: 16 },
|
|
card: {
|
|
padding: 16,
|
|
borderRadius: 16,
|
|
borderWidth: StyleSheet.hairlineWidth,
|
|
},
|
|
sectionTitle: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
textTransform: 'uppercase',
|
|
letterSpacing: 0.5,
|
|
marginBottom: 16,
|
|
},
|
|
segmentedControl: {
|
|
flexDirection: 'row',
|
|
backgroundColor: '#00000010',
|
|
borderRadius: 12,
|
|
padding: 4,
|
|
},
|
|
segmentBtn: {
|
|
flex: 1,
|
|
paddingVertical: 10,
|
|
alignItems: 'center',
|
|
borderRadius: 8,
|
|
},
|
|
segmentText: {
|
|
fontSize: 14,
|
|
fontWeight: '500',
|
|
},
|
|
swatchContainer: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
},
|
|
swatchWrap: {
|
|
alignItems: 'center',
|
|
padding: 4,
|
|
borderRadius: 12,
|
|
borderWidth: 2,
|
|
borderColor: 'transparent',
|
|
gap: 6,
|
|
},
|
|
swatch: {
|
|
width: 48,
|
|
height: 48,
|
|
borderRadius: 24,
|
|
},
|
|
swatchLabel: {
|
|
fontSize: 12,
|
|
fontWeight: '500',
|
|
},
|
|
langRow: {
|
|
flexDirection: 'row',
|
|
flexWrap: 'wrap',
|
|
gap: 12,
|
|
},
|
|
langBtn: {
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 10,
|
|
borderRadius: 12,
|
|
backgroundColor: '#00000010',
|
|
},
|
|
});
|