import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import '../l10n/app_localizations.dart'; import '../models/tasks/barcode_task.dart'; import '../widgets/offline_banner.dart'; class BarcodeCaptureScreen extends StatefulWidget { final BarcodeTask task; final Function(List) onBarcodesCompleted; const BarcodeCaptureScreen({ super.key, required this.task, required this.onBarcodesCompleted, }); @override State createState() => _BarcodeCaptureScreenState(); } class _BarcodeCaptureScreenState extends State { final List _scannedBarcodes = []; final List _textControllers = []; MobileScannerController? _scannerController; bool _isMobilePlatform = false; bool _isScannerInitialized = false; @override void initState() { super.initState(); _detectPlatformAndInit(); } @override void dispose() { _scannerController?.dispose(); for (final controller in _textControllers) { controller.dispose(); } super.dispose(); } void _detectPlatformAndInit() { // Determine if we're on a mobile platform if (kIsWeb) { _isMobilePlatform = false; _initializeDesktopMode(); } else { switch (defaultTargetPlatform) { case TargetPlatform.android: case TargetPlatform.iOS: _isMobilePlatform = true; _initializeMobileScanner(); break; case TargetPlatform.macOS: case TargetPlatform.windows: case TargetPlatform.linux: _isMobilePlatform = false; _initializeDesktopMode(); break; default: _isMobilePlatform = false; _initializeDesktopMode(); } } } void _initializeMobileScanner() { try { _scannerController = MobileScannerController(); setState(() { _isScannerInitialized = true; }); } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('${AppLocalizations.of(context).cameraError}: $e'), ), ); } } } void _initializeDesktopMode() { // Create text controllers for desktop input fields for (int i = 0; i < widget.task.maxBarcodeCount; i++) { _textControllers.add(TextEditingController()); } setState(() { _isScannerInitialized = true; }); } void _onBarcodeDetected(BarcodeCapture capture) { final List barcodes = capture.barcodes; for (final barcode in barcodes) { final String? code = barcode.rawValue; if (code != null && code.isNotEmpty && !_scannedBarcodes.contains(code)) { if (_scannedBarcodes.length < widget.task.maxBarcodeCount) { setState(() { _scannedBarcodes.add(code); }); } } } } void _removeBarcode(int index) { setState(() { _scannedBarcodes.removeAt(index); }); } void _finishTask() { final List barcodes; if (_isMobilePlatform) { barcodes = _scannedBarcodes; } else { // Collect barcodes from text fields barcodes = []; for (final controller in _textControllers) { if (controller.text.trim().isNotEmpty) { barcodes.add(controller.text.trim()); } } } // Navigate back to task view first Navigator.of(context).pop(); // Then call the completion callback widget.onBarcodesCompleted(barcodes); } bool _canFinish() { if (_isMobilePlatform) { return _scannedBarcodes.length >= widget.task.minBarcodeCount; } else { int filledFields = 0; for (final controller in _textControllers) { if (controller.text.trim().isNotEmpty) { filledFields++; } } return filledFields >= widget.task.minBarcodeCount; } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context).barcodeScan), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => Navigator.of(context).pop(), ), ), body: Column( children: [ const OfflineBanner(), Expanded( child: _isScannerInitialized ? (_isMobilePlatform ? _buildMobileView() : _buildDesktopView()) : const Center(child: CircularProgressIndicator()), ), ], ), ); } Widget _buildMobileView() { return Column( children: [ // Scanner view Expanded( flex: 3, child: Stack( children: [ MobileScanner( controller: _scannerController, onDetect: _onBarcodeDetected, ), // Overlay with scanning frame Container( decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.5), ), child: Center( child: Container( width: 250, height: 250, decoration: BoxDecoration( border: Border.all(color: Colors.white, width: 2), borderRadius: BorderRadius.circular(12), ), child: Container( margin: const EdgeInsets.all(20), decoration: BoxDecoration( border: Border.all(color: Colors.green, width: 2), borderRadius: BorderRadius.circular(8), ), ), ), ), ), ], ), ), // Scanned barcodes list Expanded( flex: 2, child: Container( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${AppLocalizations.of(context).scannedBarcodes} (${_scannedBarcodes.length}/${widget.task.maxBarcodeCount})', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Text( '${AppLocalizations.of(context).minBarcodes} ${widget.task.minBarcodeCount} ${AppLocalizations.of(context).barcodesRequired}', style: TextStyle(fontSize: 14, color: Colors.grey[600]), ), const SizedBox(height: 16), Expanded( child: ListView.builder( itemCount: _scannedBarcodes.length, itemBuilder: (context, index) { return Card( child: ListTile( leading: const Icon(Icons.qr_code), title: Text(_scannedBarcodes[index]), trailing: IconButton( icon: const Icon(Icons.delete, color: Colors.red), onPressed: () => _removeBarcode(index), ), ), ); }, ), ), const SizedBox(height: 16), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _canFinish() ? _finishTask : null, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), ), child: Text(AppLocalizations.of(context).finish), ), ), ], ), ), ), ], ); } Widget _buildDesktopView() { return Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( AppLocalizations.of(context).enterBarcode, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Text( '${AppLocalizations.of(context).barcodeEnterDescription} (${widget.task.minBarcodeCount}-${widget.task.maxBarcodeCount})', style: TextStyle(fontSize: 16, color: Colors.grey[600]), ), const SizedBox(height: 24), Expanded( child: ListView.builder( itemCount: widget.task.maxBarcodeCount, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: TextField( controller: _textControllers[index], decoration: InputDecoration( labelText: index < widget.task.minBarcodeCount ? AppLocalizations.of( context, ).barcodeNumberRequired(index + 1) : AppLocalizations.of( context, ).barcodeNumberOptional(index + 1), border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.qr_code), ), onChanged: (value) { setState(() { // Trigger rebuild to update button state }); }, ), ); }, ), ), const SizedBox(height: 16), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _canFinish() ? _finishTask : null, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), ), child: Text(AppLocalizations.of(context).finish), ), ), ], ), ); } }