import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../data/variety_repository.dart'; import '../i18n/strings.g.dart'; import '../state/quick_add_cubit.dart'; import 'photo_pick.dart'; import 'quantity_picker.dart'; Future showQuickAddSheet( BuildContext context, { required VarietyRepository repository, }) { return showModalBottomSheet( context: context, isScrollControlled: true, builder: (_) => BlocProvider( create: (_) => QuickAddCubit(repository), child: const QuickAddSheet(), ), ); } class QuickAddSheet extends StatelessWidget { const QuickAddSheet({super.key}); @override Widget build(BuildContext context) { final t = context.t; return BlocConsumer( listenWhen: (prev, curr) => !prev.submitted && curr.submitted, listener: (context, state) => Navigator.of(context).pop(), builder: (context, state) { final cubit = context.read(); return Padding( padding: EdgeInsets.only( left: 16, right: 16, top: 16, bottom: MediaQuery.of(context).viewInsets.bottom + 16, ), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( t.quickAdd.title, style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 12), const _LabelField(), const SizedBox(height: 16), LotTypeSelector( value: state.lotType, onChanged: (type) { cubit ..setLotType(type) ..setQuantity(null); }, ), const SizedBox(height: 12), Text( t.quickAdd.quantity, style: Theme.of(context).textTheme.labelLarge, ), const SizedBox(height: 8), QuantityPicker( type: state.lotType, value: state.quantity, onChanged: cubit.setQuantity, ), const SizedBox(height: 8), Align( alignment: AlignmentDirectional.centerStart, child: TextButton.icon( onPressed: cubit.toggleExpanded, icon: Icon( state.expanded ? Icons.expand_less : Icons.expand_more, ), label: Text(t.quickAdd.more), ), ), if (state.expanded) const _MoreSection(), const SizedBox(height: 8), Row( children: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: Text(t.quickAdd.cancel), ), if (state.addedCount > 0) ...[ const SizedBox(width: 8), Text( t.quickAdd.addedCount(n: state.addedCount), style: Theme.of(context).textTheme.bodySmall, ), ], const Spacer(), TextButton( key: const Key('quickAdd.saveAndAddAnother'), onPressed: state.submitting ? null : cubit.submitAndAddAnother, child: Text(t.quickAdd.saveAndAddAnother), ), const SizedBox(width: 8), FilledButton( key: const Key('quickAdd.save'), onPressed: state.submitting ? null : cubit.submit, child: Text(t.quickAdd.save), ), ], ), ], ), ), ); }, ); } } /// The name field, with its own controller so "save & add another" can clear /// it and refocus without tearing down the sheet. class _LabelField extends StatefulWidget { const _LabelField(); @override State<_LabelField> createState() => _LabelFieldState(); } class _LabelFieldState extends State<_LabelField> { final _controller = TextEditingController(); final _focusNode = FocusNode(); @override void dispose() { _controller.dispose(); _focusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final t = context.t; final cubit = context.read(); return BlocListener( listenWhen: (prev, curr) => prev.addedCount != curr.addedCount, listener: (context, _) { _controller.clear(); _focusNode.requestFocus(); }, child: BlocBuilder( buildWhen: (prev, curr) => prev.showLabelError != curr.showLabelError, builder: (context, state) => TextField( key: const Key('quickAdd.labelField'), controller: _controller, focusNode: _focusNode, autofocus: true, textInputAction: TextInputAction.done, textCapitalization: TextCapitalization.sentences, decoration: InputDecoration( labelText: t.quickAdd.labelField, errorText: state.showLabelError ? t.quickAdd.labelRequired : null, border: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(8)), ), ), onChanged: cubit.labelChanged, onSubmitted: (_) => cubit.submit(), ), ), ); } } class _MoreSection extends StatelessWidget { const _MoreSection(); @override Widget build(BuildContext context) { final t = context.t; final state = context.watch().state; final cubit = context.read(); return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 8), if (state.photoBytes != null) ClipRRect( borderRadius: BorderRadius.circular(8), child: Image.memory( state.photoBytes!, height: 120, fit: BoxFit.cover, ), ), Align( alignment: AlignmentDirectional.centerStart, child: OutlinedButton.icon( onPressed: () async { final bytes = await pickPhoto(context); if (bytes != null) cubit.photoPicked(bytes); }, icon: const Icon(Icons.photo_camera_outlined), label: Text(t.quickAdd.addPhoto), ), ), ], ); } }