import React, { useEffect } from 'react'; import { View, Text, StyleSheet, Pressable } from 'react-native'; import { Check } from '../icons'; import { SettingsSection, SettingItem, RadioGroup } from './settings-section'; import { spacing, radius, typography, type ThemePalette } from '../../theme/tokens'; import { useColors } from '../../theme/colors'; import { useLocaleStore } from '../../stores/locale-store'; import { useSettingsStore, type DateFormat, type TimeFormat } from '../../stores/settings-store'; import { formatListDate } from '../../lib/date-format'; import { SUPPORTED_LOCALES, detectDeviceLocale, type LocaleCode } from '../../i18n'; export function LanguageSettings() { const c = useColors(); const styles = React.useMemo(() => makeStyles(c), [c]); const override = useLocaleStore((s) => s.override); const setOverride = useLocaleStore((s) => s.setOverride); const locale = useLocaleStore((s) => s.locale); const hydrated = useLocaleStore((s) => s.hydrated); const hydrate = useLocaleStore((s) => s.hydrate); const t = useLocaleStore((s) => s.t); const settingsHydrated = useSettingsStore((s) => s.hydrated); const hydrateSettings = useSettingsStore((s) => s.hydrate); const dateFormat = useSettingsStore((s) => s.dateFormat); const timeFormat = useSettingsStore((s) => s.timeFormat); const update = useSettingsStore((s) => s.updateSetting); useEffect(() => { if (!hydrated) void hydrate(); }, [hydrated, hydrate]); useEffect(() => { if (!settingsHydrated) void hydrateSettings(); }, [settingsHydrated, hydrateSettings]); const deviceCode = detectDeviceLocale(); const selected: LocaleCode | 'system' = override ?? 'system'; // Build live preview samples so the user sees what each format looks like. const now = new Date(); const fmtOpts = { dateFormat, timeFormat, locale }; const previewToday = formatListDate(now, fmtOpts); const previewWeek = formatListDate(new Date(now.getTime() - 3 * 86400000), fmtOpts); const previewOlder = formatListDate(new Date(now.getTime() - 40 * 86400000), fmtOpts); const renderRow = (code: LocaleCode | 'system', label: string, sublabel?: string) => { const active = selected === code; return ( setOverride(code === 'system' ? null : (code as LocaleCode))} style={({ pressed }) => [styles.row, pressed && styles.rowPressed]} > {label} {sublabel ? {sublabel} : null} {active ? : null} ); }; const deviceLabel = SUPPORTED_LOCALES.find((l) => l.code === deviceCode)?.label ?? 'English'; const directionChangePending = useLocaleStore((s) => s.directionChangePending); return ( {renderRow( 'system', `${t('settings.appearance.language.system_default', 'System default')} (${deviceLabel})`, )} {SUPPORTED_LOCALES.map((l) => renderRow(l.code, l.label))} {directionChangePending && ( {t( 'settings.appearance.language.restart_for_direction', 'Restart the app to apply the new text direction.', )} )} update('dateFormat', v as DateFormat)} options={[ { value: 'smart', label: t('settings.language_region.date_format.smart', 'Smart (locale-aware)') }, { value: 'relative', label: t('settings.language_region.date_format.relative', 'Relative (1h ago, 2d ago)') }, { value: 'full', label: t('settings.language_region.date_format.full', 'Always full date') }, ]} /> {t('settings.language_region.date_format.preview_today', 'Today:')} {previewToday} {t('settings.language_region.date_format.preview_this_week', 'This week:')} {previewWeek} {t('settings.language_region.date_format.preview_older', 'Older:')} {previewOlder} update('timeFormat', v as TimeFormat)} options={[ { value: '24h', label: t('settings.language_region.time_format.24h', '24-hour') }, { value: '12h', label: t('settings.language_region.time_format.12h', '12-hour') }, ]} /> ); } function makeStyles(c: ThemePalette) { return StyleSheet.create({ list: { borderRadius: radius.md, overflow: 'hidden', backgroundColor: c.background }, row: { flexDirection: 'row', alignItems: 'center', paddingVertical: 12, paddingHorizontal: spacing.md, gap: spacing.sm, }, rowPressed: { backgroundColor: c.muted }, divider: { height: 1, backgroundColor: c.border, marginHorizontal: spacing.md }, label: { ...typography.body, color: c.text }, sublabel: { ...typography.caption, color: c.textMuted, marginTop: 2 }, hint: { ...typography.caption, color: c.warning, marginTop: spacing.sm }, previewBox: { marginTop: spacing.md, padding: spacing.md, borderRadius: radius.md, backgroundColor: c.muted, gap: 4, }, previewRow: { flexDirection: 'row', justifyContent: 'space-between', gap: spacing.md }, previewLabel: { ...typography.caption, color: c.mutedForeground }, previewValue: { ...typography.captionMedium, color: c.text }, }); }