Greenlens/app/profile/preferences.tsx

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',
},
});