import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; class VerificaRcaScreen extends StatefulWidget { final String targa; const VerificaRcaScreen({super.key, required this.targa}); @override _VerificaRcaScreenState createState() => _VerificaRcaScreenState(); } class _VerificaRcaScreenState extends State { InAppWebViewController? webViewController; bool isLoading = true; String? dataScadenzaTrovata; bool ricercaFallita = false; final String urlPortale = "https://www.ilportaledellautomobilista.it/web/portale-automobilista/verifica-copertura-rc"; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Verifica Copertura RCA"), backgroundColor: Colors.blue[900], foregroundColor: Colors.white, ), body: Stack( children: [ // 1. WEBVIEW (Il motore nascosto/mascherato) InAppWebView( initialUrlRequest: URLRequest(url: WebUri(urlPortale)), initialSettings: InAppWebViewSettings( javaScriptEnabled: true, supportZoom: false, ), onWebViewCreated: (controller) { webViewController = controller; }, onLoadStop: (controller, url) async { setState(() { isLoading = false; }); // Appena caricata, nascondiamo la grafica del sito await _preparaPagina(); }, onProgressChanged: (controller, progress) { // Ogni volta che la pagina cambia (es. dopo il click su Cerca), controlliamo se c'è il risultato if (progress == 100) { _cercaRisultato(); } }, ), // 2. LOADER / SCHERMATA SUCCESSO (Copre la WebView quando serve) if (isLoading || dataScadenzaTrovata != null || ricercaFallita) Container( color: Colors.white, width: double.infinity, height: double.infinity, child: Center( child: _buildOverlayContent(), ), ), ], ), ); } Widget _buildOverlayContent() { if (ricercaFallita) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline, color: Colors.red, size: 60), const SizedBox(height: 20), const Text("Veicolo non assicurato\no targa errata", textAlign: TextAlign.center, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 30), ElevatedButton( onPressed: () { setState(() { ricercaFallita = false; isLoading = false; // Rimostra la webview per riprovare webViewController?.reload(); }); }, child: const Text("Riprova"), ) ], ); } if (dataScadenzaTrovata != null) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.check_circle, color: Colors.green, size: 80), const SizedBox(height: 20), const Text("Scadenza Trovata!", style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)), const SizedBox(height: 10), Text(dataScadenzaTrovata!, style: TextStyle(fontSize: 30, color: Colors.blue[900], fontWeight: FontWeight.bold)), const SizedBox(height: 40), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.blue[900], foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15), ), onPressed: () { Navigator.pop(context, dataScadenzaTrovata); }, child: const Text("USA QUESTA DATA", style: TextStyle(fontSize: 18)), ) ], ); } return const CircularProgressIndicator(); } // --- FUNZIONI DI SCRAPING --- Future _preparaPagina() async { if (webViewController == null) return; // 1. INIEZIONE CSS: Stile "App Mobile" await webViewController!.evaluateJavascript(source: """ // Nascondi tutto il contorno inutile var elementsToHide = document.querySelectorAll('header, footer, .navbar, .breadcrumb, #cookie-bar, .portlet-title, .lfr-meta-actions'); elementsToHide.forEach(el => el.style.display = 'none'); var mainForm = document.querySelector('form'); if(mainForm) { document.body.innerHTML = ''; document.body.appendChild(mainForm); document.body.style.backgroundColor = '#ffffff'; document.body.style.padding = '20px'; document.body.style.fontFamily = 'sans-serif'; } """); // 2. INIEZIONE JS: Compilazione e UX await webViewController!.evaluateJavascript(source: """ // A. Compila Targa var campoTarga = document.getElementById('targa'); if (campoTarga) { campoTarga.value = '${widget.targa}'; campoTarga.style.fontSize = '24px'; campoTarga.style.fontWeight = 'bold'; campoTarga.style.textAlign = 'center'; campoTarga.style.border = '2px solid #1565C0'; campoTarga.readOnly = true; } // B. Seleziona "Autoveicolo" var selectVeicolo = document.querySelector('select'); if (selectVeicolo) { for (var i = 0; i < selectVeicolo.options.length; i++) { if (selectVeicolo.options[i].text.toLowerCase().includes('auto')) { selectVeicolo.selectedIndex = i; break; } } // Nascondi la select e la sua label selectVeicolo.style.display = 'none'; if(selectVeicolo.previousElementSibling) selectVeicolo.previousElementSibling.style.display = 'none'; } // C. Restyling Bottone Ricerca var btn = document.querySelector("input[name='ricercaCoperturaVeicolo']"); if (btn) { btn.style.cssText = ''; btn.style.width = '100%'; btn.style.height = '60px'; btn.style.backgroundColor = '#1565C0'; btn.style.color = 'white'; btn.style.border = 'none'; btn.style.borderRadius = '12px'; btn.style.fontSize = '20px'; btn.style.marginTop = '30px'; btn.value = 'CERCA SCADENZA'; } // D. Focus sul Captcha var campoCaptcha = document.querySelector("input[name*='captcha']"); if(campoCaptcha) { campoCaptcha.placeholder = 'Inserisci i caratteri qui'; campoCaptcha.style.height = '50px'; campoCaptcha.style.fontSize = '20px'; campoCaptcha.style.textAlign = 'center'; campoCaptcha.style.marginTop = '10px'; campoCaptcha.scrollIntoView(); } """); } Future _cercaRisultato() async { if (webViewController == null) return; // Leggiamo tutto l'HTML della pagina String? html = await webViewController!.getHtml(); if (html == null) return; // CASO 1: SUCCESSO if (html.contains("Scadenza copertura")) { // Eseguiamo JS per estrarre la data precisa var dataEstratta = await webViewController!.evaluateJavascript(source: """ (function() { // Cerca tutti i 'td' (celle di tabella) var cells = document.querySelectorAll('td'); for (var i = 0; i < cells.length; i++) { // Se la cella contiene la label... if (cells[i].innerText.includes('Scadenza copertura')) { // ...prendi il testo della cella successiva (dove c'è la data) var nextCell = cells[i].nextElementSibling; return nextCell ? nextCell.innerText : null; } } return null; })(); """); if (dataEstratta != null && dataEstratta.toString().trim().isNotEmpty) { setState(() { dataScadenzaTrovata = dataEstratta.toString().trim(); }); } } // CASO 2: FALLIMENTO (Non assicurata o targa errata) else if (html.contains("dal controllo non risulta coperto") || html.contains("Targa non trovata")) { setState(() { ricercaFallita = true; }); } // CASO 3: ANCORA NEL FORM (Es. captcha errato) else { // Riapplichiamo lo stile grafico perché il reload della pagina potrebbe averlo resettato _preparaPagina(); } } }