import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_dimens.dart'; import '../../../core/utils/validators.dart'; import '../providers/cart_controller.dart'; import '../providers/catalog_providers.dart'; /// Doubles as the barcode input. /// /// If the submitted text looks like a barcode we bill it immediately and clear /// the field; otherwise it stays as a live search term. class PosSearchField extends ConsumerStatefulWidget { const PosSearchField({super.key, this.focusNode}); final FocusNode? focusNode; @override ConsumerState createState() => _PosSearchFieldState(); } class _PosSearchFieldState extends ConsumerState { final _controller = TextEditingController(); @override void dispose() { _controller.dispose(); super.dispose(); } void _submit(String value) { final text = value.trim(); if (text.isEmpty) return; if (Validators.isLikelyBarcode(text)) { ref.read(cartControllerProvider.notifier).scanBarcode(text); _controller.clear(); ref.read(searchQueryProvider.notifier).state = ''; } } @override Widget build(BuildContext context) { final query = ref.watch(searchQueryProvider); // A scan clears the query from outside this widget. Mirror that into the // controller so any stray character the scanner leaked into the field goes // with it. ref.listen(searchQueryProvider, (_, next) { if (next.isEmpty && _controller.text.isNotEmpty) _controller.clear(); }); return TextField( controller: _controller, focusNode: widget.focusNode, autofocus: true, textInputAction: TextInputAction.search, style: const TextStyle(fontSize: 16), onChanged: (v) => ref.read(searchQueryProvider.notifier).state = v, onSubmitted: _submit, decoration: InputDecoration( hintText: 'Search product, scan barcode or enter SKU…', prefixIcon: const Padding( padding: EdgeInsets.only(left: AppSpacing.md, right: AppSpacing.sm), child: Icon(Icons.search_rounded, color: AppColors.textTertiary), ), prefixIconConstraints: const BoxConstraints(minWidth: 0), contentPadding: const EdgeInsets.symmetric( horizontal: AppSpacing.lg, vertical: AppSpacing.lg + 2, ), suffixIcon: Row(mainAxisSize: MainAxisSize.min, children: [ if (query.isNotEmpty) IconButton( tooltip: 'Clear', icon: const Icon(Icons.close_rounded, size: 20), color: AppColors.textTertiary, onPressed: () { _controller.clear(); ref.read(searchQueryProvider.notifier).state = ''; }, ), Container( margin: const EdgeInsets.only(right: AppSpacing.sm), padding: const EdgeInsets.symmetric( horizontal: AppSpacing.md, vertical: AppSpacing.sm, ), decoration: const BoxDecoration( color: AppColors.primarySurface, borderRadius: AppRadius.brSm, ), child: const Row(mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.qr_code_scanner_rounded, size: 18, color: AppColors.primary,), SizedBox(width: AppSpacing.xs + 2), Text('Scanner ready', style: TextStyle( color: AppColors.primary, fontSize: 12, fontWeight: FontWeight.w600, ),), ],), ), ],), ), ); } }