400 lines
14 KiB
Dart
400 lines
14 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:flutter/foundation.dart'; // <-- AGGIUNTA LIBRERIA PER IL DEBUG
|
||
|
|
import 'global_data.dart';
|
||
|
|
import 'comp_1-5.dart';
|
||
|
|
import 'comp_6-7.dart';
|
||
|
|
|
||
|
|
class SceltaLatoScreen extends StatefulWidget {
|
||
|
|
const SceltaLatoScreen({super.key});
|
||
|
|
|
||
|
|
@override
|
||
|
|
State<SceltaLatoScreen> createState() => _SceltaLatoScreenState();
|
||
|
|
}
|
||
|
|
|
||
|
|
class _SceltaLatoScreenState extends State<SceltaLatoScreen> {
|
||
|
|
|
||
|
|
@override
|
||
|
|
void initState() {
|
||
|
|
super.initState();
|
||
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
|
|
_mostraGuidaSicurezza(context);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
void _mostraGuidaSicurezza(BuildContext context) {
|
||
|
|
showDialog(
|
||
|
|
context: context,
|
||
|
|
builder: (ctx) => AlertDialog(
|
||
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||
|
|
title: Row(
|
||
|
|
children: [
|
||
|
|
Container(
|
||
|
|
padding: const EdgeInsets.all(8),
|
||
|
|
decoration: BoxDecoration(color: Colors.red.shade50, borderRadius: BorderRadius.circular(10)),
|
||
|
|
child: const Icon(Icons.health_and_safety, color: Colors.red),
|
||
|
|
),
|
||
|
|
const SizedBox(width: 10),
|
||
|
|
const Text("GUIDA RAPIDA", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
content: SingleChildScrollView(
|
||
|
|
child: Column(
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||
|
|
mainAxisSize: MainAxisSize.min,
|
||
|
|
children: const [
|
||
|
|
_StepGuida(icon: Icons.back_hand, text: "FERMATI in sicurezza e non intralciare il traffico."),
|
||
|
|
Divider(),
|
||
|
|
_StepGuida(icon: Icons.engineering, text: "Se sei fuori dal centro abitato indossa il GILET arancione e posiziona il TRIANGOLO."),
|
||
|
|
Divider(),
|
||
|
|
_StepGuida(icon: Icons.local_hospital, text: "Ci sono feriti? NON muoverli e chiama il 118."),
|
||
|
|
Divider(),
|
||
|
|
_StepGuida(icon: Icons.file_copy, text: "Prepara la patente e i dati della polizza, ti serviranno per compilare il modulo."),
|
||
|
|
Divider(),
|
||
|
|
_StepGuida(
|
||
|
|
icon: Icons.camera_alt,
|
||
|
|
text: "FAI LE FOTO ORA! 📸\n1. Targhe veicoli.\n2. Danni da vicino e lontano.\n3. Posizione auto sulla strada.\n\nLe allegherai alla fine nella mail!",
|
||
|
|
isBold: true
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
actions: [
|
||
|
|
SizedBox(
|
||
|
|
width: double.infinity,
|
||
|
|
child: ElevatedButton(
|
||
|
|
style: ElevatedButton.styleFrom(
|
||
|
|
backgroundColor: Colors.blue.shade800,
|
||
|
|
foregroundColor: Colors.white,
|
||
|
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))
|
||
|
|
),
|
||
|
|
onPressed: () => Navigator.pop(ctx),
|
||
|
|
child: const Text("HO CAPITO, INIZIAMO", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
return Scaffold(
|
||
|
|
appBar: AppBar(
|
||
|
|
title: const Text("Compilazione CAI", style: TextStyle(fontWeight: FontWeight.bold)),
|
||
|
|
backgroundColor: Colors.blue.shade900,
|
||
|
|
foregroundColor: Colors.white,
|
||
|
|
elevation: 0,
|
||
|
|
actions: [
|
||
|
|
|
||
|
|
if (kDebugMode) // <-- AGGIUNTO: NASCONDE IL TASTO NEGLI STORE
|
||
|
|
IconButton(
|
||
|
|
icon: const Icon(Icons.flash_on, color: Colors.orangeAccent),
|
||
|
|
tooltip: "POPOLA DATI TEST",
|
||
|
|
onPressed: () {
|
||
|
|
GlobalData.popolaDatiDiTest();
|
||
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
||
|
|
const SnackBar(
|
||
|
|
content: Text("⚡ Dati di test caricati! Vai a generare il PDF."),
|
||
|
|
backgroundColor: Colors.green,
|
||
|
|
duration: Duration(seconds: 2),
|
||
|
|
)
|
||
|
|
);
|
||
|
|
},
|
||
|
|
),
|
||
|
|
|
||
|
|
IconButton(
|
||
|
|
icon: const Icon(Icons.help_outline, color: Colors.yellowAccent, size: 28),
|
||
|
|
onPressed: () => _mostraGuidaSicurezza(context),
|
||
|
|
tooltip: "Guida Rapida Sicurezza",
|
||
|
|
)
|
||
|
|
],
|
||
|
|
),
|
||
|
|
body: Stack(
|
||
|
|
children: [
|
||
|
|
// 1. BASE CROMATICA DIVISA (Blu/Giallo)
|
||
|
|
Row(
|
||
|
|
children: [
|
||
|
|
Expanded(child: Container(color: const Color(0xFFE3F2FD))), // Blu chiaro
|
||
|
|
Expanded(child: Container(color: const Color(0xFFFFFDE7))), // Giallo chiaro
|
||
|
|
],
|
||
|
|
),
|
||
|
|
|
||
|
|
// 2. FILIGRANA STILIZZATA (Sfondo CID)
|
||
|
|
Positioned.fill(
|
||
|
|
child: Opacity(
|
||
|
|
opacity: 0.12,
|
||
|
|
child: Image.asset(
|
||
|
|
'assets/sfondo_cid.jpg',
|
||
|
|
width: double.infinity,
|
||
|
|
height: double.infinity,
|
||
|
|
fit: BoxFit.cover,
|
||
|
|
errorBuilder: (c, e, s) => const SizedBox(),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
|
||
|
|
// 3. CONTENUTO ATTIVO (SEMPLIFICATO E OTTIMIZZATO)
|
||
|
|
SafeArea(
|
||
|
|
child: SingleChildScrollView(
|
||
|
|
// Aggiungiamo un po' di padding per non attaccare il tutto ai bordi dello schermo
|
||
|
|
padding: const EdgeInsets.all(16.0),
|
||
|
|
child: Column(
|
||
|
|
children: [
|
||
|
|
// Il box informativo ora è diretto figlio della colonna
|
||
|
|
_buildInfoBox(context),
|
||
|
|
|
||
|
|
const SizedBox(height: 20), // Spazio ridotto tra box e bottoni
|
||
|
|
|
||
|
|
// PULSANTI AFFIANCATI (Responsive)
|
||
|
|
IntrinsicHeight(
|
||
|
|
child: Row(
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
|
|
children: [
|
||
|
|
// LATO A (BLU)
|
||
|
|
Expanded(
|
||
|
|
child: _buildBtnConRilievo(
|
||
|
|
context,
|
||
|
|
"VEICOLO A",
|
||
|
|
"LATO BLU",
|
||
|
|
Colors.blue.shade800,
|
||
|
|
'A',
|
||
|
|
Icons.directions_car_rounded,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
const SizedBox(width: 20),
|
||
|
|
// LATO B (GIALLO)
|
||
|
|
Expanded(
|
||
|
|
child: _buildBtnConRilievo(
|
||
|
|
context,
|
||
|
|
"VEICOLO B",
|
||
|
|
"LATO GIALLO",
|
||
|
|
Colors.amber.shade600,
|
||
|
|
'B',
|
||
|
|
Icons.directions_car_filled_rounded,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
const SizedBox(height: 20), // Un po' di spazio extra in fondo
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// FUNZIONE AGGIORNATA PER EFFETTO 3D POTENZIATO
|
||
|
|
Widget _buildBtnConRilievo(BuildContext context, String titolo, String sottotitolo, Color color, String lato, IconData icon) {
|
||
|
|
bool isB = lato == 'B';
|
||
|
|
|
||
|
|
// Definiamo i colori per il gradiente (luce in alto a sx, ombra in basso a dx)
|
||
|
|
Color colorLight, colorDark;
|
||
|
|
if (isB) {
|
||
|
|
// Per il giallo
|
||
|
|
colorLight = Colors.amber.shade400; // Luce
|
||
|
|
colorDark = Colors.amber.shade700; // Ombra
|
||
|
|
} else {
|
||
|
|
// Per il blu
|
||
|
|
colorLight = Colors.blue.shade600; // Luce
|
||
|
|
colorDark = Colors.blue.shade900; // Ombra
|
||
|
|
}
|
||
|
|
|
||
|
|
return Container(
|
||
|
|
// Decorazione complessa del Container per l'effetto 3D
|
||
|
|
decoration: BoxDecoration(
|
||
|
|
borderRadius: BorderRadius.circular(24), // Arrotondamento leggermente aumentato
|
||
|
|
|
||
|
|
// 1. GRADIENTE DI SUPERFICIE (Simula la luce che colpisce un oggetto curvo)
|
||
|
|
gradient: LinearGradient(
|
||
|
|
begin: Alignment.topLeft,
|
||
|
|
end: Alignment.bottomRight,
|
||
|
|
colors: [colorLight, colorDark],
|
||
|
|
stops: const [0.1, 0.9], // Regola i punti di luce e ombra
|
||
|
|
),
|
||
|
|
|
||
|
|
// 2. OMBRE STRATIFICATE (Doppia ombra per profondità realistica)
|
||
|
|
boxShadow: [
|
||
|
|
// Ombra 1: "Spessore" (scura, nitida, vicina)
|
||
|
|
BoxShadow(
|
||
|
|
color: colorDark.withOpacity(0.6),
|
||
|
|
blurRadius: 8,
|
||
|
|
offset: const Offset(0, 8),
|
||
|
|
spreadRadius: 1, // Espande leggermente l'ombra scura
|
||
|
|
),
|
||
|
|
// Ombra 2: "Sollevamento" (morbida, ampia, lontana)
|
||
|
|
BoxShadow(
|
||
|
|
color: colorDark.withOpacity(0.3),
|
||
|
|
blurRadius: 25,
|
||
|
|
offset: const Offset(0, 18),
|
||
|
|
spreadRadius: -5, // Contrae l'ombra diffusa per non sporcare troppo
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
child: Material(
|
||
|
|
color: Colors.transparent, // Necessario per far vedere il gradiente sottostante
|
||
|
|
child: InkWell(
|
||
|
|
// L'InkWell gestisce il tocco e l'effetto "splash"
|
||
|
|
borderRadius: BorderRadius.circular(24),
|
||
|
|
onTap: () {
|
||
|
|
GlobalData.latoCorrente = lato;
|
||
|
|
if (lato == 'B') {
|
||
|
|
Navigator.push(context, MaterialPageRoute(builder: (c) => const Comp6_7Screen()));
|
||
|
|
} else {
|
||
|
|
Navigator.push(context, MaterialPageRoute(builder: (c) => const Comp1_5Screen()));
|
||
|
|
}
|
||
|
|
},
|
||
|
|
child: Padding(
|
||
|
|
padding: const EdgeInsets.symmetric(vertical: 30),
|
||
|
|
child: Column(
|
||
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
|
children: [
|
||
|
|
// Aggiunto un leggero effetto ombra anche all'icona per farla "uscire"
|
||
|
|
Icon(
|
||
|
|
icon,
|
||
|
|
size: 48,
|
||
|
|
color: isB ? Colors.black87 : Colors.white,
|
||
|
|
shadows: [
|
||
|
|
Shadow(
|
||
|
|
color: Colors.black.withOpacity(0.3),
|
||
|
|
offset: const Offset(2, 2),
|
||
|
|
blurRadius: 4,
|
||
|
|
)
|
||
|
|
],
|
||
|
|
),
|
||
|
|
const SizedBox(height: 15),
|
||
|
|
Text(
|
||
|
|
titolo,
|
||
|
|
style: TextStyle(
|
||
|
|
fontSize: 20, // Leggermente più grande
|
||
|
|
fontWeight: FontWeight.w800, // Più grassetto
|
||
|
|
color: isB ? Colors.black87 : Colors.white,
|
||
|
|
// Leggera ombra sul testo per contrasto
|
||
|
|
shadows: [
|
||
|
|
Shadow(color: Colors.black.withOpacity(0.2), offset: const Offset(1, 1), blurRadius: 2)
|
||
|
|
]
|
||
|
|
)
|
||
|
|
),
|
||
|
|
const SizedBox(height: 5),
|
||
|
|
Text(
|
||
|
|
sottotitolo,
|
||
|
|
style: TextStyle(
|
||
|
|
fontSize: 13,
|
||
|
|
fontWeight: FontWeight.w600,
|
||
|
|
color: isB ? Colors.black54 : Colors.white70
|
||
|
|
)
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Widget _buildInfoBox(BuildContext context) {
|
||
|
|
return Container(
|
||
|
|
padding: const EdgeInsets.all(16),
|
||
|
|
// Rimosso il margine verticale che creava spazio extra inutile
|
||
|
|
decoration: BoxDecoration(
|
||
|
|
color: Colors.blue.shade50,
|
||
|
|
borderRadius: BorderRadius.circular(15),
|
||
|
|
border: Border.all(color: Colors.blue.shade200, width: 1.5),
|
||
|
|
// Aggiunta una leggera ombra per staccarlo dallo sfondo
|
||
|
|
boxShadow: [
|
||
|
|
BoxShadow(color: Colors.blue.shade100.withOpacity(0.5), blurRadius: 8, offset: const Offset(0, 4))
|
||
|
|
],
|
||
|
|
),
|
||
|
|
child: Column(
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||
|
|
children: [
|
||
|
|
Row(
|
||
|
|
children: [
|
||
|
|
Icon(Icons.lightbulb_outline, color: Colors.blue.shade800),
|
||
|
|
const SizedBox(width: 10),
|
||
|
|
Expanded(
|
||
|
|
child: Text(
|
||
|
|
"Come funziona la scelta del lato?",
|
||
|
|
style: TextStyle(
|
||
|
|
fontSize: 16,
|
||
|
|
fontWeight: FontWeight.bold,
|
||
|
|
color: Colors.blue.shade900
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
const SizedBox(height: 12),
|
||
|
|
const Text(
|
||
|
|
"Nel modulo CAI, i veicoli vengono chiamati A e B. La lettera non indica chi ha ragione o torto, serve solo per distinguere le due auto.",
|
||
|
|
style: TextStyle(fontSize: 14, height: 1.4),
|
||
|
|
),
|
||
|
|
const SizedBox(height: 16),
|
||
|
|
_buildInfoRow("🤝", "1. Accordati", "Scegli con l'altro conducente chi sarà il Veicolo A e chi il B."),
|
||
|
|
const SizedBox(height: 12),
|
||
|
|
_buildInfoRow("✍️", "2. Compila", "Seleziona il tuo lato e inserisci i dati con attenzione per non dover ricominciare."),
|
||
|
|
const SizedBox(height: 12),
|
||
|
|
_buildInfoRow("📱", "3. Scambia e Genera", "Firma e scambia i dati con la controparte per ottenere il PDF per l'assicurazione."),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Widget _buildInfoRow(String emoji, String title, String desc) {
|
||
|
|
return Row(
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||
|
|
children: [
|
||
|
|
Text(emoji, style: const TextStyle(fontSize: 18)),
|
||
|
|
const SizedBox(width: 10),
|
||
|
|
Expanded(
|
||
|
|
child: RichText(
|
||
|
|
text: TextSpan(
|
||
|
|
style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4),
|
||
|
|
children: [
|
||
|
|
TextSpan(text: "$title\n", style: const TextStyle(fontWeight: FontWeight.bold)),
|
||
|
|
TextSpan(text: desc),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Widget Helper interno
|
||
|
|
class _StepGuida extends StatelessWidget {
|
||
|
|
final IconData icon;
|
||
|
|
final String text;
|
||
|
|
final bool isBold;
|
||
|
|
|
||
|
|
const _StepGuida({required this.icon, required this.text, this.isBold = false});
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
return Padding(
|
||
|
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||
|
|
child: Row(
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||
|
|
children: [
|
||
|
|
Icon(icon, color: isBold ? Colors.red : Colors.blueGrey, size: 24),
|
||
|
|
const SizedBox(width: 15),
|
||
|
|
Expanded(
|
||
|
|
child: Text(
|
||
|
|
text,
|
||
|
|
style: TextStyle(
|
||
|
|
fontSize: 15,
|
||
|
|
height: 1.4,
|
||
|
|
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
|
||
|
|
color: isBold ? Colors.red.shade900 : Colors.black87,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|