/** * I pezzi dell'aspetto della 1.5: foto di sfondo scura, pulsanti con sfumatura * blu e bordo chiaro, riquadri grigi chiari. */ import { useCallback, type ReactNode } from 'react'; import { BackHandler, ImageBackground, Pressable, StyleSheet, Text, View, type StyleProp, type ViewStyle, } from 'react-native'; import { LinearGradient } from 'expo-linear-gradient'; import * as Haptics from 'expo-haptics'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useFocusEffect } from '@react-navigation/native'; import { STILI, type Stile } from '../gioco.ts'; import { SFONDI } from '../immagini.ts'; import { suona, type Suono } from '../suoni.ts'; import { useStato } from './stato.tsx'; export const FONT = 'BarlowCondensed_700Bold'; export const FONT_TESTO = 'BarlowCondensed_500Medium'; export const COLORI = { bluScuro: '#232933', blu: '#22435E', grigio: '#DCE2EB', bordo: '#B1B5BC', spento: '#8A9099', arancio: '#FFA500', }; /** Sul tablet il contenuto resta una colonna centrata, come sul telefono. */ const LARGHEZZA_MAX = 520; const NOMI_STILI: Record = { a: 'Hollywood', b: 'Dallas', c: 'Gothic' }; export function vibra(): void { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(() => {}); } export function Sfondo({ children }: { children: ReactNode }) { const { imp } = useStato(); return ( {children} ); } export function Pulsante({ titolo, onPress, suono = 'click', disattivo = false, style, }: { titolo: string; onPress: () => void; suono?: Suono | null; disattivo?: boolean; style?: StyleProp; }) { return ( { vibra(); if (suono) suona(suono); onPress(); }} style={({ pressed }) => [st.pulsante, style, pressed && st.premuto]} > {titolo} ); } export function Riquadro({ children, style }: { children: ReactNode; style?: StyleProp }) { return ( {children} ); } function Tondo({ segno, onPress, etichetta }: { segno: string; onPress: () => void; etichetta: string }) { return ( { vibra(); onPress(); }} style={({ pressed }) => [st.tondo, pressed && st.premuto]} > {segno} ); } export function Contatore({ valore, meno, piu }: { valore: number; meno: () => void; piu: () => void }) { return ( {valore} ); } /** Hollywood, Dallas, Gothic: cambia foto e sfondi di tutta l'app. */ export function SceltaStile() { const { imp, setImp } = useStato(); return ( {STILI.map((s) => ( { vibra(); setImp({ ...imp, stile: s }); }} > {NOMI_STILI[s]} ))} ); } /** Durante il giro del telefono e il timer il tasto indietro di Android non fa niente. */ export function useBloccaIndietro(): void { useFocusEffect( useCallback(() => { const sub = BackHandler.addEventListener('hardwareBackPress', () => true); return () => sub.remove(); }, []), ); } export const testi = StyleSheet.create({ desc: { fontFamily: FONT_TESTO, fontSize: 20, lineHeight: 26, color: COLORI.bluScuro, textAlign: 'center' }, etichetta: { fontFamily: FONT, fontSize: 16, color: COLORI.spento, textAlign: 'center' }, grande: { fontFamily: FONT, fontSize: 30, color: COLORI.bluScuro, textAlign: 'center' }, }); const st = StyleSheet.create({ pieno: { flex: 1 }, colonna: { flex: 1, width: '100%', maxWidth: LARGHEZZA_MAX, alignSelf: 'center', padding: 16, gap: 12 }, pulsante: { borderRadius: 5, borderWidth: 2, borderColor: COLORI.grigio, overflow: 'hidden' }, pulsanteFondo: { minHeight: 56, paddingHorizontal: 12, paddingVertical: 8, alignItems: 'center', justifyContent: 'center' }, pulsanteTesto: { fontFamily: FONT, fontSize: 28, color: '#FFFFFF', textAlign: 'center' }, premuto: { opacity: 0.75 }, riquadro: { borderRadius: 5, borderWidth: 2, borderColor: COLORI.bordo, padding: 14 }, contatore: { flexDirection: 'row', alignItems: 'center', gap: 14 }, numero: { minWidth: 44 }, tondo: { width: 40, height: 40, borderRadius: 20, backgroundColor: COLORI.blu, alignItems: 'center', justifyContent: 'center', }, tondoTesto: { fontFamily: FONT, fontSize: 26, color: '#FFFFFF', marginTop: -2 }, stili: { flexDirection: 'row', justifyContent: 'center', gap: 18 }, stile: { fontFamily: FONT, fontSize: 20 }, });