cid_app/lib/comp_12.dart

298 lines
10 KiB
Dart
Raw Permalink Normal View History

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",
barrierColor: Colors.black.withOpacity(0.5),
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))
)
)
),
],
);
}
}