From b9d1d750b6b07a838d1fa6b83a3961ca7206209e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20M=C3=BCllner?= Date: Wed, 4 Mar 2026 11:05:38 +0100 Subject: [PATCH] feat(scanner): add in-scanner active collection switcher - Add collection dropdown at top of scanner screen - Wire scanner selection changes back to scan tab active collection state - Reuse persisted active collection behavior while scanning - Keep continuous scan loop intact with collection changes applied immediately --- lib/scanner_screen.dart | 51 ++++++++++++++++++++++++++++++++++++++- lib/screens/scan_tab.dart | 3 +++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/scanner_screen.dart b/lib/scanner_screen.dart index 29b1b7c..fad1298 100644 --- a/lib/scanner_screen.dart +++ b/lib/scanner_screen.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:camera/camera.dart'; import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart'; +import 'services/collection_service.dart'; import 'theme/app_colors.dart'; /// Screen that uses the camera to scan text (OCR) from a Hot Wheels package @@ -11,8 +12,17 @@ import 'theme/app_colors.dart'; /// The detected ID is returned via Navigator.pop(context, hwId). class ScannerScreen extends StatefulWidget { final Future Function(String hwId)? onDetected; + final List collections; + final String? activeCollectionId; + final ValueChanged? onCollectionChanged; - const ScannerScreen({super.key, this.onDetected}); + const ScannerScreen({ + super.key, + this.onDetected, + this.collections = const [], + this.activeCollectionId, + this.onCollectionChanged, + }); @override State createState() => _ScannerScreenState(); @@ -26,6 +36,7 @@ class _ScannerScreenState extends State { String? _lastDetected; bool _scanAccepted = false; String _statusText = 'Ready to scan'; + String? _activeCollectionId; // Matches typical Hot Wheels model IDs: 2–5 uppercase letters followed by // 2–4 digits, e.g. JKF21, HCV73, GRX33, FYD83. @@ -34,10 +45,17 @@ class _ScannerScreenState extends State { @override void initState() { super.initState(); + _activeCollectionId = widget.activeCollectionId; _textRecognizer = TextRecognizer(); _initCamera(); } + void _handleCollectionChanged(String? value) { + if (value == null) return; + setState(() => _activeCollectionId = value); + widget.onCollectionChanged?.call(value); + } + Future _initCamera() async { final cameras = await availableCameras(); if (cameras.isEmpty) { @@ -188,6 +206,37 @@ class _ScannerScreenState extends State { ), body: Column( children: [ + if (widget.collections.isNotEmpty) + Container( + width: double.infinity, + padding: const EdgeInsets.fromLTRB(12, 10, 12, 8), + color: Colors.black.withValues(alpha: 0.55), + child: DropdownButtonHideUnderline( + child: DropdownButton( + isExpanded: true, + value: _activeCollectionId, + dropdownColor: AppColors.navy, + iconEnabledColor: Colors.white, + style: const TextStyle(color: Colors.white), + hint: const Text( + 'Select collection', + style: TextStyle(color: Colors.white70), + ), + items: widget.collections + .map( + (c) => DropdownMenuItem( + value: c.id, + child: Text( + c.name, + overflow: TextOverflow.ellipsis, + ), + ), + ) + .toList(), + onChanged: _isBusy ? null : _handleCollectionChanged, + ), + ), + ), Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), diff --git a/lib/screens/scan_tab.dart b/lib/screens/scan_tab.dart index 96017ad..a675d9f 100644 --- a/lib/screens/scan_tab.dart +++ b/lib/screens/scan_tab.dart @@ -239,6 +239,9 @@ class ScanTabState extends State { await navigatorKey.currentState!.push( MaterialPageRoute( builder: (_) => ScannerScreen( + collections: _collections, + activeCollectionId: _selectedCollection?.id, + onCollectionChanged: _setActiveCollection, onDetected: (hwId) => _processHwId(hwId), ), ),