2026-02-27 23:26:13 +01:00
// Versione: FINAL - SLIVER LAYOUT (Footer Sicuro e Testi Corretti)
import ' package:flutter/material.dart ' ;
import ' global_data.dart ' ;
import ' comp_13.dart ' ; // IMPORTA IL GRAFICO
import ' comp_15.dart ' ; // IMPORTA LE FIRME
class Comp12Screen extends StatefulWidget {
const Comp12Screen ( { super . key } ) ;
@ override
_Comp12ScreenState createState ( ) = > _Comp12ScreenState ( ) ;
}
class _Comp12ScreenState extends State < Comp12Screen > {
final List < String > _testiCircostanze = [
" 1. In fermata / in sosta " ,
" 2. Ripartiva dopo una sosta / apriva una portiera " ,
" 3. Stava parcheggiando " ,
" 4. Usciva da un parcheggio / luogo privato " ,
" 5. Entrava in un parcheggio / luogo privato " ,
" 6. Si immetteva in una piazza a senso rotatorio " ,
" 7. Circolava su una piazza a senso rotatorio " ,
" 8. Tamponava procedendo nello stesso senso " ,
" 9. Procedeva nello stesso senso ma in fila diversa " ,
" 10. Cambiava fila " ,
" 11. Sorpassava " ,
" 12. Girava a destra " ,
" 13. Girava a sinistra " ,
" 14. Retrocedeva " ,
" 15. Invadeva la sede stradale riservata " ,
" 16. Proveniva da destra " ,
" 17. Non osservava il segnale di precedenza/semaforo "
] ;
bool _isReady = false ;
@ override
void initState ( ) {
super . initState ( ) ;
_inizializzaPagina ( ) ;
}
Future < void > _inizializzaPagina ( ) async {
await Future . delayed ( const Duration ( milliseconds: 200 ) ) ;
if ( mounted ) {
setState ( ( ) = > _isReady = true ) ;
// MOSTRA IL POPUP ANIMATO ALL'AVVIO
WidgetsBinding . instance . addPostFrameCallback ( ( _ ) = > _mostraInfoPopup ( context ) ) ;
}
}
// --- POPUP INFORMATIVO ANIMATO ---
void _mostraInfoPopup ( BuildContext context ) {
bool isB = GlobalData . latoCorrente = = ' B ' ;
Color activeColor = isB ? Colors . amber . shade700 : Colors . blue . shade900 ;
showGeneralDialog (
context: context ,
barrierDismissible: false ,
barrierLabel: " Popup " ,
2026-04-24 23:00:16 +02:00
barrierColor: Colors . black . withValues ( alpha: 0.5 ) ,
2026-02-27 23:26:13 +01:00
transitionDuration: const Duration ( milliseconds: 400 ) ,
pageBuilder: ( context , animation , secondaryAnimation ) {
return AlertDialog (
shape: RoundedRectangleBorder ( borderRadius: BorderRadius . circular ( 20 ) ) ,
title: Row (
children: [
Icon ( Icons . fact_check , color: activeColor , size: 28 ) ,
const SizedBox ( width: 10 ) ,
const Expanded ( child: Text ( " Circostanze Incidente " , style: TextStyle ( fontWeight: FontWeight . bold , fontSize: 18 ) ) ) ,
] ,
) ,
content: SingleChildScrollView (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
mainAxisSize: MainAxisSize . min ,
children: [
Text ( " Indica l'esatta dinamica del Veicolo ${ GlobalData . latoCorrente } al momento dell'urto. " , style: const TextStyle ( fontSize: 15 ) ) ,
const SizedBox ( height: 16 ) ,
_buildPopupRow ( Icons . check_box_outlined , " Selezione Multipla " , " Puoi spuntare anche più di una circostanza, ma assicurati che descrivano correttamente l'accaduto. " ) ,
const SizedBox ( height: 12 ) ,
_buildPopupRow ( Icons . warning_amber_rounded , " Attenzione " , " Le circostanze selezionate in questa pagina sono fondamentali per stabilire la responsabilità del sinistro! " ) ,
] ,
) ,
) ,
actions: [
SizedBox (
width: double . infinity ,
child: ElevatedButton (
style: ElevatedButton . styleFrom (
backgroundColor: activeColor ,
foregroundColor: isB ? Colors . black87 : Colors . white ,
shape: RoundedRectangleBorder ( borderRadius: BorderRadius . circular ( 12 ) ) ,
padding: const EdgeInsets . symmetric ( vertical: 14 ) ,
) ,
onPressed: ( ) = > Navigator . pop ( context ) ,
child: const Text ( " HO CAPITO " , style: TextStyle ( fontSize: 16 , fontWeight: FontWeight . bold ) ) ,
) ,
) ,
] ,
) ;
} ,
transitionBuilder: ( context , animation , secondaryAnimation , child ) {
var curvePosizione = CurvedAnimation (
parent: animation ,
curve: Curves . easeOutBack ,
reverseCurve: Curves . easeInBack ,
) ;
var curveOpacita = CurvedAnimation (
parent: animation ,
curve: Curves . easeOut ,
reverseCurve: Curves . easeIn ,
) ;
return SlideTransition (
position: Tween < Offset > (
begin: const Offset ( 0.0 , 0.4 ) ,
end: Offset . zero ,
) . animate ( curvePosizione ) ,
child: FadeTransition (
opacity: curveOpacita ,
child: child ,
) ,
) ;
} ,
) ;
}
Widget _buildPopupRow ( IconData icon , String title , String desc ) {
return Row (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Icon ( icon , size: 24 , color: Colors . blueGrey ) ,
const SizedBox ( width: 12 ) ,
Expanded (
child: RichText (
text: TextSpan (
style: const TextStyle ( fontSize: 14 , color: Colors . black87 , height: 1.4 ) ,
children: [
TextSpan ( text: " $ title : " , style: const TextStyle ( fontWeight: FontWeight . bold ) ) ,
TextSpan ( text: desc ) ,
] ,
) ,
) ,
) ,
] ,
) ;
}
void _prosegui ( ) {
bool isB = GlobalData . latoCorrente = = ' B ' ;
if ( isB ) {
// IL LATO B SALTA IL GRAFICO E VA DIRETTAMENTE ALLE FIRME (15)
Navigator . push (
context ,
MaterialPageRoute ( builder: ( context ) = > const Comp15Screen ( ) ) ,
) ;
} else {
// IL LATO A VA AL GRAFICO (13)
Navigator . push (
context ,
MaterialPageRoute ( builder: ( context ) = > const Comp13Screen ( ) ) ,
) ;
}
}
@ override
Widget build ( BuildContext context ) {
bool isB = GlobalData . latoCorrente = = ' B ' ;
Color mainCol = isB ? Colors . amber . shade700 : Colors . blue . shade900 ;
Color bgCol = isB ? const Color ( 0xFFFFF9C4 ) : const Color ( 0xFFF5F7FA ) ;
if ( ! _isReady ) {
return Scaffold ( backgroundColor: bgCol , body: Container ( ) ) ;
}
return Scaffold (
backgroundColor: bgCol ,
appBar: AppBar (
title: Text ( " 12. Circostanze ( ${ GlobalData . latoCorrente } ) " ) ,
backgroundColor: mainCol ,
foregroundColor: isB ? Colors . black : Colors . white ,
) ,
// --- SLIVER LAYOUT ---
body: SafeArea (
child: CustomScrollView (
physics: const BouncingScrollPhysics ( ) ,
slivers: [
// 1. Header (Testo Istruzioni)
SliverToBoxAdapter (
child: Container (
padding: const EdgeInsets . all ( 15 ) ,
color: Colors . white ,
margin: const EdgeInsets . only ( bottom: 1 ) ,
child: Text (
" Seleziona le circostanze per il veicolo ${ GlobalData . latoCorrente } . " ,
style: TextStyle ( fontSize: 16 , fontWeight: FontWeight . bold , color: mainCol ) ,
) ,
) ,
) ,
// 2. Lista Scrollabile (Le 17 Checkbox)
SliverList (
delegate: SliverChildBuilderDelegate (
( context , index ) {
int circIndex = index + 1 ;
bool isChecked = isB
? ( GlobalData . circostanzeB [ circIndex ] ? ? false )
: ( GlobalData . circostanzeA [ circIndex ] ? ? false ) ;
return Column (
children: [
Container (
color: Colors . white ,
child: CheckboxListTile (
activeColor: mainCol ,
contentPadding: const EdgeInsets . symmetric ( horizontal: 16 , vertical: 4 ) ,
title: Text ( " ${ circIndex } . ${ _testiCircostanze [ index ] } " , style: const TextStyle ( fontSize: 14 ) ) ,
value: isChecked ,
onChanged: ( bool ? val ) {
setState ( ( ) {
if ( isB ) {
GlobalData . circostanzeB [ circIndex ] = val ? ? false ;
} else {
GlobalData . circostanzeA [ circIndex ] = val ? ? false ;
}
} ) ;
} ,
) ,
) ,
const Divider ( height: 1 , thickness: 1 , indent: 16 , endIndent: 16 ) ,
] ,
) ;
} ,
childCount: _testiCircostanze . length ,
) ,
) ,
// 3. Piè di pagina elastico (Bottoni)
SliverFillRemaining (
hasScrollBody: false ,
child: Align (
alignment: Alignment . bottomCenter ,
child: Container (
padding: const EdgeInsets . all ( 20 ) ,
child: _navButtons ( context , mainCol , isB ) ,
) ,
) ,
) ,
] ,
) ,
) ,
) ;
}
Widget _navButtons ( BuildContext context , Color color , bool isB ) {
return Row (
children: [
// Tasto INDIETRO (Expanded flex 1)
Expanded (
flex: 4 , // Proporzione 4/10
child: OutlinedButton (
onPressed: ( ) = > Navigator . pop ( context ) ,
style: OutlinedButton . styleFrom (
minimumSize: const Size ( 0 , 55 ) ,
padding: const EdgeInsets . symmetric ( horizontal: 5 ) , // Padding ridotto
) ,
// FittedBox evita che il testo vada a capo se lo spazio è poco
child: const FittedBox (
child: Text ( " INDIETRO " , style: TextStyle ( fontWeight: FontWeight . bold ) )
)
)
) ,
const SizedBox ( width: 15 ) ,
// Tasto SALVA E PROCEDI (Expanded flex 2)
Expanded (
flex: 6 , // Proporzione 6/10 (più largo)
child: ElevatedButton (
style: ElevatedButton . styleFrom (
backgroundColor: color ,
foregroundColor: isB ? Colors . black : Colors . white ,
minimumSize: const Size ( 0 , 55 )
) ,
onPressed: _prosegui ,
child: const FittedBox (
child: Text ( " SALVA E PROCEDI " , style: TextStyle ( fontWeight: FontWeight . bold ) )
)
)
) ,
] ,
) ;
}
}