cid_app/lib/comp_15.dart

210 lines
8.1 KiB
Dart
Raw Permalink Normal View History

2026-02-27 23:26:13 +01:00
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'global_data.dart';
import 'comp_16.dart';
class Comp15Screen extends StatefulWidget {
const Comp15Screen({super.key});
@override
State<Comp15Screen> createState() => _Comp15ScreenState();
}
class _Comp15ScreenState extends State<Comp15Screen> {
late List<Offset?> _puntiFirma;
late bool isB;
bool _isNavigating = false;
@override
void initState() {
super.initState();
isB = GlobalData.latoCorrente == 'B';
_puntiFirma = isB
? List<Offset?>.from(GlobalData.puntiFirmaB)
: List<Offset?>.from(GlobalData.puntiFirmaA);
// Appena entro, ruoto in orizzontale
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
}
// --- PUNTO CHIAVE: LA PULIZIA AUTOMATICA ---
@override
void dispose() {
// Quando questa pagina viene distrutta (in qualsiasi modo),
// FORZO immediatamente il ritorno al verticale.
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
super.dispose();
}
Future<void> _tornaIndietro() async {
_salvaInMemoria();
if (mounted) Navigator.pop(context);
}
void _salvaInMemoria() {
if (isB) {
GlobalData.puntiFirmaB = List.from(_puntiFirma);
} else {
GlobalData.puntiFirmaA = List.from(_puntiFirma);
}
}
Future<void> _confermaEProsegui() async {
_salvaInMemoria();
if (_puntiFirma.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("La firma è obbligatoria!"), backgroundColor: Colors.red),
);
return;
}
setState(() => _isNavigating = true);
if (mounted) {
// Prima di andare alla 16, forzo GIA' il verticale qui.
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
// Piccola pausa per dare tempo all'animazione di rotazione
await Future.delayed(const Duration(milliseconds: 100));
if (!mounted) return;
// Navigo verso la 16. Uso pushReplacement per distruggere la 15 (e chiamare dispose)
// oppure push normale, ma avendo già forzato il portrait sopra siamo sicuri.
await Navigator.push(
context,
MaterialPageRoute(builder: (c) => const Comp16Screen())
);
// --- AGGIUNTA FONDAMENTALE ---
// Aspettiamo un attimo. Se stiamo facendo "Cancella tutto",
// in questo lasso di tempo la pagina verrà smontata (mounted diventerà false)
// e il codice sotto NON verrà eseguito, evitando la trottola.
await Future.delayed(const Duration(milliseconds: 300));
// -----------------------------
if (mounted && ModalRoute.of(context)?.isCurrent == true) {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
setState(() => _isNavigating = false);
}
// ---------------------------
}
}
@override
Widget build(BuildContext context) {
// Ribadisco orizzontale nel build per sicurezza
// SystemChrome.setPreferredOrientations([
// DeviceOrientation.landscapeLeft,
// DeviceOrientation.landscapeRight,
// ]);
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) async {
if (!didPop) await _tornaIndietro();
},
child: Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomInset: false,
body: OrientationBuilder(
builder: (context, orientation) {
double shortestSide = MediaQuery.of(context).size.shortestSide;
bool isTablet = shortestSide > 600;
// Fix per iPad che potrebbe rimanere verticale
if (orientation == Orientation.portrait) {
return Center(
child: RotatedBox(
quarterTurns: 1,
child: SizedBox(
width: MediaQuery.of(context).size.height,
height: MediaQuery.of(context).size.width,
child: SafeArea(child: _buildBody(context, isTablet)),
),
),
);
}
return SafeArea(child: _buildBody(context, isTablet));
},
),
),
);
}
Widget _buildBody(BuildContext context, bool isTablet) {
Color mainCol = isB ? Colors.amber.shade700 : Colors.blue.shade900;
double shortestSide = MediaQuery.of(context).size.shortestSide;
double spessoreFirma = (shortestSide * 0.01).clamp(3.0, 8.0);
double verticalPadding = isTablet ? MediaQuery.of(context).size.height * 0.12 : 2.0;
double horizontalPadding = isTablet ? 80.0 : 5.0;
return _isNavigating
? const Center(child: CircularProgressIndicator())
: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 50, color: mainCol, padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(children: [
IconButton(icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: _tornaIndietro),
Expanded(child: Text("15. Firma (${GlobalData.latoCorrente})", textAlign: TextAlign.center, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18))),
const SizedBox(width: 48),
]),
),
Expanded(
child: Padding(
padding: EdgeInsets.symmetric(vertical: verticalPadding, horizontal: horizontalPadding),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (isTablet) ...[const Text("Firma nello spazio sottostante:", style: TextStyle(fontSize: 16)), const SizedBox(height: 8)],
Expanded(
child: Container(
width: double.infinity,
decoration: BoxDecoration(border: Border.all(color: Colors.grey, width: 2), borderRadius: BorderRadius.circular(10), color: Colors.grey.shade50),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: GestureDetector(
onPanUpdate: (d) => setState(() => _puntiFirma.add(d.localPosition)),
onPanEnd: (d) => setState(() => _puntiFirma.add(null)),
child: RepaintBoundary(child: CustomPaint(painter: FirmaPainter(_puntiFirma, spessoreFirma), size: Size.infinite)),
),
),
),
),
],
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 5, 20, isTablet ? 15 : 5),
child: Row(children: [
Expanded(flex: 1, child: SizedBox(height: 45, child: OutlinedButton.icon(onPressed: () => setState(() => _puntiFirma.clear()), icon: const Icon(Icons.delete, color: Colors.red), label: const Text("CANCELLA", style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold)), style: OutlinedButton.styleFrom(side: const BorderSide(color: Colors.red))))),
const SizedBox(width: 20),
Expanded(flex: 2, child: SizedBox(height: 45, child: ElevatedButton.icon(onPressed: _confermaEProsegui, style: ElevatedButton.styleFrom(backgroundColor: Colors.green[700], foregroundColor: Colors.white, elevation: 5), icon: const Icon(Icons.check_circle_outline), label: const Text("CONFERMA FIRMA", style: TextStyle(fontWeight: FontWeight.bold))))),
]),
),
],
);
}
}
class FirmaPainter extends CustomPainter {
final List<Offset?> punti;
final double spessore;
FirmaPainter(this.punti, this.spessore);
@override
void paint(Canvas canvas, Size size) {
Paint p = Paint()..color = Colors.black..strokeWidth = spessore..strokeCap = StrokeCap.round..strokeJoin = StrokeJoin.round..style = PaintingStyle.stroke..isAntiAlias = true;
for (int i = 0; i < punti.length - 1; i++) { if (punti[i] != null && punti[i + 1] != null) canvas.drawLine(punti[i]!, punti[i + 1]!, p); }
}
@override
bool shouldRepaint(FirmaPainter old) => true;
}