/** * I riquadri della pagina Impostazioni (e della schermata di scelta Tema/ * Lingua): una superficie arrotondata che raccoglie righe imparentate, come * Impostazioni di iPhone e le WhatsApp. * * `Riquadro` è solo lo sfondo e gli angoli, con `overflow: 'hidden'` perché il * colore di sfondo del tocco sulle righe non deve uscire dagli angoli tondi. * `RigaRiquadro` è la riga: un segno a sinistra (assente nelle righe di * scelta, dove non serve), il testo, il valore tenue se c'è, e in fondo la * freccia — normale, obliqua per chi apre il browser, o la spunta di una * scelta attiva. Ogni riga disegna da sé il separatore sotto di sé (tranne * l'ultima del riquadro): un `View` a parte, rientrato dopo il segno, non un * bordo sulla riga — un bordo sulla `Pressable` intera non si può rientrare * senza tagliare anche l'area toccabile. * * Quali segni, quale freccia e quale ruolo di accessibilità per ogni riga * sono decisioni prese in logica-impostazioni.ts (segnoRiga, segnoFineRiga, * ruoloRigaImpostazioni): qui si mostra quello che arriva, senza deciderlo. */ import type { ReactNode } from 'react'; import { useMemo } from 'react'; import { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native'; import type { ChiaveSegno } from '../segni.ts'; import type { Colori } from '../tema.ts'; import { RAGGIO, SPAZIO, TESTO, useColori } from '../tema.ts'; import Segno from './Segno.tsx'; /** La larghezza riservata al segno a sinistra: allinea il testo di tutte le righe, con o senza segno. */ const LARGO_SEGNO = 24; export function Riquadro({ children }: { children: ReactNode }) { const colori = useColori(); const stili = useMemo(() => creaStiliRiquadro(colori), [colori]); return {children}; } export type VarianteRiga = 'normale' | 'pericolo' | 'spento'; export type FineRiga = 'freccia' | 'esterno' | 'spunta' | 'nessuno'; export interface PropsRigaRiquadro { /** Il segno a sinistra. Assente nelle righe di scelta (Scelta.tsx), dove il testo comincia al bordo. */ segno?: ChiaveSegno; titolo: string; /** Il valore tenue a destra, prima del segno di fondo: «Come il telefono», «Italiano». */ valore?: string; /** 'freccia' di default: le altre varianti le sceglie chi chiama con segnoFineRiga/ 'spunta' per le righe di scelta. */ fine?: FineRiga; variante?: VarianteRiga; onPress?: () => void; /** Sostituisce il segno di fondo con lo spinner: l'operazione DI QUESTA riga è in corso. */ inCorso?: boolean; /** Spenta perché un'altra riga sta scrivendo: niente spinner qui, solo il tocco che non fa niente. */ disabled?: boolean; /** L'ultima riga del riquadro non ha il separatore sotto. */ ultima?: boolean; accessibilityRole?: 'button' | 'link'; accessibilityLabel?: string; accessibilityState?: { selected?: boolean; disabled?: boolean }; } export function RigaRiquadro({ segno, titolo, valore, fine = 'freccia', variante = 'normale', onPress, inCorso = false, disabled = false, ultima = false, accessibilityRole = 'button', accessibilityLabel, accessibilityState, }: PropsRigaRiquadro) { const colori = useColori(); const stili = useMemo(() => creaStiliRiga(colori), [colori]); const spento = variante === 'spento'; const disabilitata = spento || onPress === undefined || inCorso || disabled; const coloreEnfasi = variante === 'pericolo' ? colori.errore : spento ? colori.testoTenue : colori.testo; const coloreSegno = variante === 'pericolo' ? colori.errore : spento ? colori.testoTenue : colori.accento; return ( <> [stili.riga, pressed && !disabilitata ? stili.premuta : null]} > {segno !== undefined ? ( ) : null} {titolo} {valore !== undefined ? ( {valore} ) : null} {inCorso ? ( ) : fine === 'nessuno' ? null : fine === 'spunta' ? ( accessibilityState?.selected ? : ( // Riserva lo spazio della spunta anche quando manca: senza, // il testo delle scelte non attive traballerebbe a sinistra // di un pixel rispetto a quella scelta. ) ) : ( )} {!ultima ? ( ) : null} ); } const creaStiliRiquadro = (colori: Colori) => StyleSheet.create({ riquadro: { backgroundColor: colori.superficie, borderRadius: RAGGIO.riga, overflow: 'hidden', }, }); const creaStiliRiga = (colori: Colori) => StyleSheet.create({ riga: { flexDirection: 'row', alignItems: 'center', minHeight: 44, paddingVertical: SPAZIO.s, paddingHorizontal: SPAZIO.l, gap: SPAZIO.m, }, premuta: { backgroundColor: colori.bordo }, segno: { width: LARGO_SEGNO, alignItems: 'center' }, titolo: { ...TESTO.corpo, flex: 1 }, valore: { ...TESTO.corpo, color: colori.testoTenue }, separatore: { height: StyleSheet.hairlineWidth, backgroundColor: colori.bordo }, });