cid_app/lib/screens/fea_verification_screen.dart
2026-04-28 15:00:01 +02:00

210 lines
6.6 KiB
Dart

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import '../services/otp_service.dart';
class FeaVerificationModal extends StatefulWidget {
final String phoneNumber;
final String conducenteName;
final VoidCallback onVerificationSuccess;
final VoidCallback onCancel;
const FeaVerificationModal({
super.key,
required this.phoneNumber,
required this.conducenteName,
required this.onVerificationSuccess,
required this.onCancel,
});
static Future<void> show({
required BuildContext context,
required String phoneNumber,
required String conducenteName,
required VoidCallback onVerificationSuccess,
required VoidCallback onCancel,
}) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (context) => FeaVerificationModal(
phoneNumber: phoneNumber,
conducenteName: conducenteName,
onVerificationSuccess: onVerificationSuccess,
onCancel: onCancel,
),
);
}
@override
State<FeaVerificationModal> createState() => _FeaVerificationModalState();
}
class _FeaVerificationModalState extends State<FeaVerificationModal> {
final OtpService _otpService = OtpService();
final TextEditingController _otpController = TextEditingController();
bool _isLoading = false;
bool _codeSent = false;
String? _verificationId;
String? _errorMessage;
@override
void initState() {
super.initState();
_inviaSms();
}
Future<void> _inviaSms() async {
setState(() {
_isLoading = true;
_errorMessage = null;
});
try {
await _otpService.sendOtp(
phoneNumber: widget.phoneNumber,
onCodeSent: (verId) {
if (mounted) {
setState(() {
_verificationId = verId;
_codeSent = true;
_isLoading = false;
});
}
},
onVerificationFailed: (e) {
if (mounted) {
setState(() {
_errorMessage = e.message ?? "Errore nell'invio dell'SMS. Controlla il numero.";
_isLoading = false;
});
}
},
onVerificationCompleted: (credential) async {
// Auto-resolution (su alcuni Android)
if (mounted) {
setState(() => _isLoading = true);
}
try {
await FirebaseAuth.instance.signInWithCredential(credential);
widget.onVerificationSuccess();
} catch (e) {
if (mounted) {
setState(() {
_errorMessage = "Errore auto-verifica.";
_isLoading = false;
});
}
}
},
onCodeAutoRetrievalTimeout: (verId) {
_verificationId = verId;
},
);
} catch (e) {
if (mounted) {
setState(() {
_errorMessage = "Errore generico: $e";
_isLoading = false;
});
}
}
}
Future<void> _verificaPin() async {
final code = _otpController.text.trim();
if (code.length != 6 || _verificationId == null) {
setState(() => _errorMessage = "Inserisci il codice a 6 cifre");
return;
}
setState(() {
_isLoading = true;
_errorMessage = null;
});
try {
await _otpService.verifyCode(verificationId: _verificationId!, smsCode: code);
widget.onVerificationSuccess();
} catch (e) {
if (mounted) {
setState(() {
_errorMessage = "Codice errato o scaduto. Riprova.";
_isLoading = false;
});
}
}
}
@override
Widget build(BuildContext context) {
return BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: AlertDialog(
backgroundColor: Colors.white.withValues(alpha: 0.95),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: Column(
children: [
const Icon(Icons.verified_user, color: Colors.green, size: 50),
const SizedBox(height: 10),
const Text("Firma Elettronica", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), textAlign: TextAlign.center),
const SizedBox(height: 5),
Text(widget.conducenteName, style: const TextStyle(fontSize: 14, color: Colors.black87), textAlign: TextAlign.center),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (_errorMessage != null)
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Text(_errorMessage!, style: const TextStyle(color: Colors.red, fontSize: 13), textAlign: TextAlign.center),
),
if (!_codeSent) ...[
const Text("Invio SMS in corso...", textAlign: TextAlign.center),
const SizedBox(height: 15),
if (_isLoading) const CircularProgressIndicator(),
] else ...[
Text("Abbiamo inviato un codice a:\n${widget.phoneNumber}", textAlign: TextAlign.center),
const SizedBox(height: 15),
TextField(
controller: _otpController,
keyboardType: TextInputType.number,
maxLength: 6,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 24, letterSpacing: 8, fontWeight: FontWeight.bold),
decoration: InputDecoration(
counterText: "",
hintText: "000000",
filled: true,
fillColor: Colors.grey.shade100,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none),
),
),
const SizedBox(height: 10),
if (_isLoading) const CircularProgressIndicator()
else ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade800,
foregroundColor: Colors.white,
minimumSize: const Size(double.infinity, 50),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
elevation: 2,
),
onPressed: _verificaPin,
child: const Text("VERIFICA", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
),
]
],
),
actions: [
TextButton(
onPressed: widget.onCancel,
child: const Text("ANNULLA", style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold)),
),
],
),
);
}
}