import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../controllers/ar_scanner_controller.dart'; /// WiFi Scanner View /// Connect to external physical scanners over WiFi. /// Discover → Connect → Scan → Upload class WifiScannerView extends GetView { const WifiScannerView({super.key}); static const _navy = Color(0xFF0F4C81); static const _gold = Color(0xFFD4AF37); static const _green = Color(0xFF10B981); @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( appBar: AppBar( title: const Text('ماسح ضوئي WiFi', style: TextStyle(fontFamily: 'El Messiri')), centerTitle: true, backgroundColor: _navy, foregroundColor: Colors.white, actions: [ Obx(() => controller.isConnected.value ? IconButton( onPressed: controller.disconnect, icon: const Icon(Icons.link_off), tooltip: 'قطع الاتصال', ) : const SizedBox()), ], ), body: Obx(() { if (controller.selectedCompanyId.value.isEmpty) { return _buildCompanySelection(); } if (!controller.isConnected.value) { return _buildScannerDiscovery(isDark); } return _buildScannerInterface(isDark); }), ); } // ─── Step 1: Company Selection ──────────────────── Widget _buildCompanySelection() { return Obx(() { if (controller.isLoadingCompanies.value) { return const Center(child: CircularProgressIndicator()); } if (controller.companies.isEmpty) { return const Center( child: Padding( padding: EdgeInsets.all(32), child: Text('لا توجد شركات.\nأضف شركة أولاً من الإعدادات.', textAlign: TextAlign.center, style: TextStyle(fontSize: 16)), ), ); } return ListView( padding: const EdgeInsets.all(16), children: [ Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( gradient: LinearGradient(colors: [_navy, _navy.withValues(alpha: 0.8)]), borderRadius: BorderRadius.circular(16), ), child: const Column( children: [ Icon(Icons.scanner, size: 48, color: Colors.white), SizedBox(height: 12), Text('ماسح ضوئي خارجي', style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold)), SizedBox(height: 4), Text('اربط جهاز المسح الضوئي عبر WiFi واستورد الفواتير مباشرة', textAlign: TextAlign.center, style: TextStyle(color: Colors.white70, fontSize: 13)), ], ), ), const SizedBox(height: 20), const Text('اختر الشركة أولاً:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 12), ...controller.companies.map((c) => Card( elevation: 2, margin: const EdgeInsets.only(bottom: 10), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: ListTile( leading: CircleAvatar( backgroundColor: _navy.withValues(alpha: 0.1), child: const Icon(Icons.business, color: _navy), ), title: Text(c['name'] ?? '', style: const TextStyle(fontWeight: FontWeight.bold)), subtitle: Text('الرقم الضريبي: ${c['tax_identification_number'] ?? '-'}'), trailing: const Icon(Icons.arrow_forward_ios, size: 16), onTap: () => controller.selectCompany(c['id'], c['name'] ?? ''), ), )), ], ); }); } // ─── Step 2: Scanner Discovery ──────────────────── Widget _buildScannerDiscovery(bool isDark) { return ListView( padding: const EdgeInsets.all(16), children: [ // Status card Obx(() => Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: isDark ? const Color(0xFF1E1E2E) : Colors.white, borderRadius: BorderRadius.circular(14), border: Border.all(color: _navy.withValues(alpha: 0.2)), ), child: Row( children: [ Icon( controller.isScanning.value ? Icons.search : Icons.wifi_find, color: _navy, size: 32, ), const SizedBox(width: 12), Expanded( child: Text(controller.statusMessage.value, style: const TextStyle(fontSize: 14)), ), ], ), )), const SizedBox(height: 16), // Auto-discover button Obx(() => ElevatedButton.icon( onPressed: controller.isScanning.value ? null : controller.discoverScanners, icon: controller.isScanning.value ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Icon(Icons.search, color: Colors.white), label: Text( controller.isScanning.value ? 'جارٍ البحث...' : '🔍 بحث تلقائي عن ماسحات', style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white), ), style: ElevatedButton.styleFrom( backgroundColor: _navy, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), )), const SizedBox(height: 20), // Manual IP entry Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: isDark ? const Color(0xFF1E1E2E) : const Color(0xFFF8FAFC), borderRadius: BorderRadius.circular(14), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('أو أدخل IP يدوياً:', style: TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 10), Row( children: [ Expanded( child: TextField( controller: controller.manualIpController, keyboardType: TextInputType.number, decoration: InputDecoration( hintText: '192.168.1.100', hintStyle: const TextStyle(color: Colors.grey), border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)), contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), prefixIcon: const Icon(Icons.lan), ), ), ), const SizedBox(width: 10), ElevatedButton( onPressed: controller.connectManualIp, style: ElevatedButton.styleFrom( backgroundColor: _gold, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: const Text('اتصل', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)), ), ], ), ], ), ), const SizedBox(height: 20), // Discovered scanners list Obx(() => controller.discoveredScanners.isEmpty ? const SizedBox() : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('ماسحات مكتشفة:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 8), ...controller.discoveredScanners.map((s) => Card( elevation: 2, margin: const EdgeInsets.only(bottom: 8), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: _green.withValues(alpha: 0.1), shape: BoxShape.circle, ), child: const Icon(Icons.scanner, color: _green), ), title: Text(s['name'] ?? '', style: const TextStyle(fontWeight: FontWeight.bold)), subtitle: Text('${s['ip']}:${s['port']} • ${s['protocol']}'), trailing: ElevatedButton( onPressed: () => controller.connectToScanner(s), style: ElevatedButton.styleFrom(backgroundColor: _green), child: const Text('اتصل', style: TextStyle(color: Colors.white)), ), ), )), ], )), ], ); } // ─── Step 3: Connected — Scan Interface ─────────── Widget _buildScannerInterface(bool isDark) { return Column( children: [ // Connection status bar Obx(() => Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), color: _green.withValues(alpha: 0.1), child: Row( children: [ const Icon(Icons.check_circle, color: _green, size: 18), const SizedBox(width: 8), Expanded( child: Text(controller.connectionStatus.value, style: const TextStyle(color: _green, fontWeight: FontWeight.w600, fontSize: 13)), ), Text(controller.selectedCompanyName.value, style: const TextStyle(fontSize: 12, color: Colors.grey)), ], ), )), // Scan settings Padding( padding: const EdgeInsets.all(16), child: Row( children: [ // Resolution Expanded( child: Obx(() => _buildSettingChip( '${controller.scanResolution.value} DPI', Icons.high_quality, () { final current = controller.scanResolution.value; controller.scanResolution.value = current == 150 ? 300 : (current == 300 ? 600 : 150); }, )), ), const SizedBox(width: 8), // Color mode Expanded( child: Obx(() => _buildSettingChip( controller.scanColorMode.value == 'Color' ? 'ألوان' : 'رمادي', Icons.palette, () { controller.scanColorMode.value = controller.scanColorMode.value == 'Color' ? 'Grayscale' : 'Color'; }, )), ), ], ), ), // Status message Obx(() => Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text(controller.statusMessage.value, textAlign: TextAlign.center, style: TextStyle(fontSize: 13, color: isDark ? Colors.white54 : Colors.grey)), )), const SizedBox(height: 16), // Scan Button Obx(() => Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: controller.isScanningDocument.value ? null : controller.triggerScan, icon: controller.isScanningDocument.value ? const SizedBox( width: 22, height: 22, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Icon(Icons.scanner, color: Colors.white, size: 24), label: Text( controller.isScanningDocument.value ? 'جارٍ المسح...' : '📄 مسح فاتورة', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white), ), style: ElevatedButton.styleFrom( backgroundColor: _navy, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), elevation: 4, ), ), ), )), const SizedBox(height: 16), // Scanned images queue Expanded( child: Obx(() { if (controller.scannedImages.isEmpty) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.inbox, size: 64, color: Colors.grey.withValues(alpha: 0.3)), const SizedBox(height: 12), Text('لا توجد صور ممسوحة بعد', style: TextStyle(color: Colors.grey.withValues(alpha: 0.5))), const Text('اضغط "مسح فاتورة" لبدء المسح', style: TextStyle(fontSize: 12, color: Colors.grey)), ], ), ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ Text('الطابور (${controller.scannedImages.length})', style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)), const Spacer(), TextButton.icon( onPressed: controller.clearQueue, icon: const Icon(Icons.delete_sweep, size: 18, color: Colors.red), label: const Text('مسح الكل', style: TextStyle(color: Colors.red, fontSize: 12)), ), ], ), ), Expanded( child: GridView.builder( padding: const EdgeInsets.all(16), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 10, mainAxisSpacing: 10, childAspectRatio: 0.75, ), itemCount: controller.scannedImages.length, itemBuilder: (_, index) { return Stack( children: [ ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.file(controller.scannedImages[index], fit: BoxFit.cover, width: double.infinity, height: double.infinity), ), Positioned( top: 4, right: 4, child: GestureDetector( onTap: () => controller.removeImage(index), child: Container( padding: const EdgeInsets.all(4), decoration: const BoxDecoration(color: Colors.red, shape: BoxShape.circle), child: const Icon(Icons.close, size: 14, color: Colors.white), ), ), ), Positioned( bottom: 4, left: 4, child: Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: Colors.black54, borderRadius: BorderRadius.circular(8), ), child: Text('${index + 1}', style: const TextStyle(color: Colors.white, fontSize: 11)), ), ), ], ); }, ), ), ], ); }), ), // Upload Bar Obx(() => controller.scannedImages.isEmpty ? const SizedBox() : Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: isDark ? const Color(0xFF1E1E2E) : Colors.white, boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 8, offset: const Offset(0, -2))], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ if (controller.isUploading.value) Padding( padding: const EdgeInsets.only(bottom: 10), child: ClipRRect( borderRadius: BorderRadius.circular(4), child: LinearProgressIndicator( value: controller.uploadProgress.value, backgroundColor: Colors.grey.withValues(alpha: 0.2), color: _gold, minHeight: 6, ), ), ), SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: controller.isUploading.value ? null : controller.uploadQueue, icon: controller.isUploading.value ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Icon(Icons.cloud_upload_rounded, color: Colors.white), label: Text( controller.isUploading.value ? 'جارٍ الرفع... ${(controller.uploadProgress.value * 100).toInt()}%' : '☁️ رفع ${controller.scannedImages.length} فاتورة لمُصادَق', style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold, color: Colors.white), ), style: ElevatedButton.styleFrom( backgroundColor: _gold, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), ), ), ], ), )), ], ); } Widget _buildSettingChip(String label, IconData icon, VoidCallback onTap) { return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12), decoration: BoxDecoration( color: _navy.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(10), border: Border.all(color: _navy.withValues(alpha: 0.2)), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, size: 16, color: _navy), const SizedBox(width: 6), Text(label, style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600)), ], ), ), ); } }