298 lines
No EOL
10 KiB
Dart
298 lines
No EOL
10 KiB
Dart
// 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))
|
|
)
|
|
)
|
|
),
|
|
],
|
|
);
|
|
}
|
|
} |