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
This commit is contained in:
parent
360fd5a705
commit
b9d1d750b6
2 changed files with 53 additions and 1 deletions
|
|
@ -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<bool> Function(String hwId)? onDetected;
|
||||
final List<Collection> collections;
|
||||
final String? activeCollectionId;
|
||||
final ValueChanged<String>? onCollectionChanged;
|
||||
|
||||
const ScannerScreen({super.key, this.onDetected});
|
||||
const ScannerScreen({
|
||||
super.key,
|
||||
this.onDetected,
|
||||
this.collections = const [],
|
||||
this.activeCollectionId,
|
||||
this.onCollectionChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ScannerScreen> createState() => _ScannerScreenState();
|
||||
|
|
@ -26,6 +36,7 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
|||
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<ScannerScreen> {
|
|||
@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<void> _initCamera() async {
|
||||
final cameras = await availableCameras();
|
||||
if (cameras.isEmpty) {
|
||||
|
|
@ -188,6 +206,37 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
|||
),
|
||||
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<String>(
|
||||
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<String>(
|
||||
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),
|
||||
|
|
|
|||
|
|
@ -239,6 +239,9 @@ class ScanTabState extends State<ScanTab> {
|
|||
await navigatorKey.currentState!.push<void>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => ScannerScreen(
|
||||
collections: _collections,
|
||||
activeCollectionId: _selectedCollection?.id,
|
||||
onCollectionChanged: _setActiveCollection,
|
||||
onDetected: (hwId) => _processHwId(hwId),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in a new issue