/** * Configuración del pie de página en fotos. * Permite activar/desactivar el footer, cambiar el logo, activar/desactivar * cada campo (proyecto, fecha, coordenadas) y añadir campos personalizados * con etiqueta y valor estático. */ import React, { useCallback, useEffect, useState } from 'react'; import { Alert, Image, ScrollView, StyleSheet, Switch, Text, TextInput, TouchableOpacity, View, } from 'react-native'; import { newUuid } from '../sync/uuid'; import { clearLogo, FooterConfig, FooterField, loadFooterConfig, pickAndSaveLogo, saveFooterConfig, } from '../photo/footerConfig'; import { COLORS, PrimaryButton, SectionTitle } from '../ui/components'; const BUILT_IN_LABELS: Record = { project_name: 'Nombre del proyecto', date: 'Fecha y hora', coordinates: 'Coordenadas GPS', }; export function PhotoSettingsScreen() { const [config, setConfig] = useState(null); const [newLabel, setNewLabel] = useState(''); const [newValue, setNewValue] = useState(''); const [showAddForm, setShowAddForm] = useState(false); const load = useCallback(async () => { setConfig(await loadFooterConfig()); }, []); useEffect(() => { void load(); }, [load]); const save = useCallback(async (next: FooterConfig) => { setConfig(next); await saveFooterConfig(next); }, []); const toggleEnabled = useCallback((val: boolean) => { if (!config) return; void save({ ...config, enabled: val }); }, [config, save]); const toggleField = useCallback((id: string, val: boolean) => { if (!config) return; void save({ ...config, fields: config.fields.map((f) => (f.id === id ? { ...f, enabled: val } : f)), }); }, [config, save]); const editFieldLabel = useCallback((id: string, label: string) => { if (!config) return; const next = { ...config, fields: config.fields.map((f) => (f.id === id ? { ...f, label } : f)), }; void save(next); }, [config, save]); const deleteCustomField = useCallback((id: string) => { if (!config) return; void save({ ...config, fields: config.fields.filter((f) => f.id !== id) }); }, [config, save]); const addCustomField = useCallback(() => { if (!config) return; const label = newLabel.trim(); const value = newValue.trim(); if (!label) { Alert.alert('', 'La etiqueta no puede estar vacía.'); return; } const field: FooterField = { id: newUuid(), key: 'custom', label, enabled: true, customValue: value || label, }; void save({ ...config, fields: [...config.fields, field] }); setNewLabel(''); setNewValue(''); setShowAddForm(false); }, [config, newLabel, newValue, save]); const onChangeLogo = useCallback(async () => { if (!config) return; const uri = await pickAndSaveLogo(); if (uri) void save({ ...config, logoUri: uri }); }, [config, save]); const onRemoveLogo = useCallback(() => { if (!config) return; Alert.alert('Quitar logo', '¿Eliminar el logo del pie de página?', [ { text: 'Quitar', style: 'destructive', onPress: () => { void clearLogo(); void save({ ...config, logoUri: null }); }, }, { text: 'Cancelar', style: 'cancel' }, ]); }, [config, save]); if (!config) return null; return ( {/* Master toggle */} Añadir pie de página a las fotos {/* ── Logo ── */} Logo {config.logoUri ? ( ) : ( Sin logo )} void onChangeLogo()} /> {config.logoUri ? ( ) : null} Recorte cuadrado. Se recomienda logo con fondo blanco. {/* ── Campos ── */} Campos {config.fields.map((f) => { const isBuiltIn = f.key !== 'custom'; return ( toggleField(f.id, v)} trackColor={{ true: COLORS.primary }} /> {isBuiltIn ? BUILT_IN_LABELS[f.key] ?? f.label : ''} editFieldLabel(f.id, t)} placeholder="Etiqueta…" returnKeyType="done" /> {f.key === 'custom' && ( { if (!config) return; void save({ ...config, fields: config.fields.map((x) => x.id === f.id ? { ...x, customValue: t } : x, ), }); }} placeholder="Valor…" returnKeyType="done" /> )} {!isBuiltIn && ( deleteCustomField(f.id)} style={styles.deleteBtn} > )} ); })} {/* Añadir campo personalizado */} {showAddForm ? ( setShowAddForm(false)} /> ) : ( setShowAddForm(true)}> + Añadir campo personalizado )} ); } // ─── estilos ────────────────────────────────────────────────────────────── const styles = StyleSheet.create({ body: { padding: 16 }, row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 14, borderBottomWidth: StyleSheet.hairlineWidth, borderColor: COLORS.border, marginBottom: 8, }, masterLabel: { fontSize: 16, fontWeight: '600', flex: 1, marginRight: 12 }, /* Logo */ logoRow: { flexDirection: 'row', alignItems: 'center', gap: 16, marginBottom: 4 }, logoPreview: { width: 72, height: 72, borderRadius: 8, backgroundColor: COLORS.bg }, logoPlaceholder: { width: 72, height: 72, borderRadius: 8, backgroundColor: COLORS.bg, justifyContent: 'center', alignItems: 'center', borderWidth: StyleSheet.hairlineWidth, borderColor: COLORS.border, }, logoPlaceholderText: { fontSize: 11, color: COLORS.muted }, logoActions: { gap: 8 }, hint: { fontSize: 11, color: COLORS.muted, marginBottom: 8 }, /* Campos */ fieldRow: { flexDirection: 'row', alignItems: 'center', gap: 10, paddingVertical: 10, borderBottomWidth: StyleSheet.hairlineWidth, borderColor: COLORS.border, }, fieldInfo: { flex: 1 }, fieldKey: { fontSize: 11, color: COLORS.muted, marginBottom: 2 }, fieldLabel: { fontSize: 14, color: '#111', borderBottomWidth: 1, borderColor: COLORS.border, paddingVertical: 2, paddingHorizontal: 0, }, fieldValue: { marginTop: 4, color: COLORS.muted }, deleteBtn: { padding: 8 }, deleteTxt: { color: COLORS.danger, fontSize: 16 }, /* Nuevo campo */ addFieldBtn: { marginTop: 16, paddingVertical: 12, alignItems: 'center', borderWidth: 1, borderStyle: 'dashed', borderColor: COLORS.primary, borderRadius: 8, }, addFieldTxt: { color: COLORS.primary, fontWeight: '600' }, addForm: { marginTop: 12, padding: 12, backgroundColor: COLORS.bg, borderRadius: 8, gap: 10, }, addInput: { borderWidth: 1, borderColor: COLORS.border, borderRadius: 6, paddingHorizontal: 10, paddingVertical: 8, fontSize: 14, }, addFormBtns: { flexDirection: 'row', gap: 8 }, });