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), backgroundColor: Colors.deepPurple[100], leading: IconButton(icon: const Icon(Icons.arrow_back), onPressed: () => Navigator.of(context).pop())), body: Column(children: [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))), ], ), ); } }