import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/bean.dart'; import '../providers/app_state.dart'; class BeanDialog extends StatefulWidget { final Bean? bean; // null for add, non-null for edit const BeanDialog({super.key, this.bean}); @override State createState() => _BeanDialogState(); } class _BeanDialogState extends State { final _formKey = GlobalKey(); late final TextEditingController _nameController; late final TextEditingController _varietalController; late final TextEditingController _processingMethodController; late final TextEditingController _originCountryController; late final TextEditingController _roasterNameController; late final TextEditingController _roasterLocationController; late RoastLevel _selectedRoastLevel; late DateTime _roastedDate; late bool _isPreferred; late List _selectedTastingNotes; @override void initState() { super.initState(); // Initialize controllers and values final bean = widget.bean; _nameController = TextEditingController(text: bean?.name ?? ''); _varietalController = TextEditingController(text: bean?.varietal ?? ''); _processingMethodController = TextEditingController(text: bean?.processingMethod ?? ''); _originCountryController = TextEditingController(text: bean?.origin ?? ''); _roasterNameController = TextEditingController(text: bean?.roaster ?? ''); _roasterLocationController = TextEditingController(text: bean?.farm ?? ''); _selectedRoastLevel = bean?.roastLevel ?? RoastLevel.medium; _roastedDate = bean?.roastDate ?? DateTime.now(); _isPreferred = bean?.isOwned ?? false; _selectedTastingNotes = List.from(bean?.flavorNotes ?? []); } @override void dispose() { _nameController.dispose(); _varietalController.dispose(); _processingMethodController.dispose(); _originCountryController.dispose(); _roasterNameController.dispose(); _roasterLocationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Dialog( child: Container( width: MediaQuery.of(context).size.width > 600 ? 600 : double.infinity, height: MediaQuery.of(context).size.height * 0.9, padding: const EdgeInsets.all(24), child: Column( children: [ // Header Row( children: [ Icon( Icons.coffee, color: Theme.of(context).colorScheme.primary, size: 28, ), const SizedBox(width: 12), Expanded( child: Text( widget.bean == null ? 'Add New Bean' : 'Edit Bean', style: Theme.of(context).textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.w600, ), ), ), IconButton( icon: const Icon(Icons.close), onPressed: () => Navigator.of(context).pop(), ), ], ), const Divider(), // Form Expanded( child: Form( key: _formKey, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildBasicInfoSection(), const SizedBox(height: 24), _buildRoastInfoSection(), const SizedBox(height: 24), _buildOriginSection(), const SizedBox(height: 24), _buildRoasterSection(), const SizedBox(height: 24), _buildTastingNotesSection(), const SizedBox(height: 24), _buildPreferencesSection(), ], ), ), ), ), // Actions const Divider(), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), ), const SizedBox(width: 12), ElevatedButton( onPressed: _saveBean, child: Text(widget.bean == null ? 'Add Bean' : 'Update Bean'), ), ], ), ], ), ), ); } Widget _buildBasicInfoSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Basic Information', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: 16), TextFormField( controller: _nameController, decoration: const InputDecoration( labelText: 'Bean Name *', hintText: 'e.g., Ethiopian Yirgacheffe', border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.trim().isEmpty) { return 'Bean name is required'; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: _varietalController, decoration: const InputDecoration( labelText: 'Varietal *', hintText: 'e.g., Arabica, Bourbon, Typica', border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.trim().isEmpty) { return 'Varietal is required'; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: _processingMethodController, decoration: const InputDecoration( labelText: 'Processing Method *', hintText: 'e.g., Washed, Natural, Honey', border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.trim().isEmpty) { return 'Processing method is required'; } return null; }, ), ], ); } Widget _buildRoastInfoSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Roast Information', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: 16), DropdownButtonFormField( value: _selectedRoastLevel, decoration: const InputDecoration( labelText: 'Roast Level', border: OutlineInputBorder(), ), items: RoastLevel.values.map((level) { return DropdownMenuItem( value: level, child: Text(_formatRoastLevel(level)), ); }).toList(), onChanged: (value) { if (value != null) { setState(() { _selectedRoastLevel = value; }); } }, ), const SizedBox(height: 16), InkWell( onTap: _selectRoastedDate, child: InputDecorator( decoration: const InputDecoration( labelText: 'Roasted Date', border: OutlineInputBorder(), suffixIcon: Icon(Icons.calendar_today), ), child: Text(_formatDate(_roastedDate)), ), ), ], ); } Widget _buildOriginSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Origin Information', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: 16), TextFormField( controller: _originCountryController, decoration: const InputDecoration( labelText: 'Origin Country/Region', hintText: 'e.g., Ethiopia, Colombia, Guatemala', border: OutlineInputBorder(), ), ), ], ); } Widget _buildRoasterSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Roaster Information', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: 16), TextFormField( controller: _roasterNameController, decoration: const InputDecoration( labelText: 'Roaster Name', hintText: 'e.g., Blue Bottle, Intelligentsia', border: OutlineInputBorder(), ), ), const SizedBox(height: 16), TextFormField( controller: _roasterLocationController, decoration: const InputDecoration( labelText: 'Roaster Location', hintText: 'e.g., San Francisco, CA', border: OutlineInputBorder(), ), ), ], ); } Widget _buildTastingNotesSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Tasting Notes', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: 16), Wrap( spacing: 8, runSpacing: 8, children: TastingNotes.values.map((note) { final isSelected = _selectedTastingNotes.contains(note); return FilterChip( label: Text(_formatTastingNote(note)), selected: isSelected, onSelected: (selected) { setState(() { if (selected) { _selectedTastingNotes.add(note); } else { _selectedTastingNotes.remove(note); } }); }, selectedColor: Theme.of(context).colorScheme.primary.withAlpha(51), checkmarkColor: Theme.of(context).colorScheme.primary, ); }).toList(), ), ], ); } Widget _buildPreferencesSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Preferences', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: 16), SwitchListTile( title: const Text('Mark as Preferred'), subtitle: const Text('Add this bean to your favorites'), value: _isPreferred, onChanged: (value) { setState(() { _isPreferred = value; }); }, ), ], ); } String _formatRoastLevel(RoastLevel level) { switch (level) { case RoastLevel.light: return 'Light Roast'; case RoastLevel.medium: return 'Medium Roast'; case RoastLevel.mediumLight: return 'Medium-Light Roast'; case RoastLevel.mediumDark: return 'Medium-Dark Roast'; case RoastLevel.dark: return 'Dark Roast'; } } String _formatTastingNote(TastingNotes note) { switch (note) { case TastingNotes.stoneFruit: return 'Stone Fruit'; case TastingNotes.tropical: return 'Tropical Fruit'; case TastingNotes.driedFruit: return 'Dried Fruit'; case TastingNotes.brownSugar: return 'Brown Sugar'; default: return note.name.substring(0, 1).toUpperCase() + note.name.substring(1); } } String _formatDate(DateTime date) { return '${date.day}/${date.month}/${date.year}'; } Future _selectRoastedDate() async { final picked = await showDatePicker( context: context, initialDate: _roastedDate, firstDate: DateTime.now().subtract(const Duration(days: 365)), lastDate: DateTime.now(), ); if (picked != null) { setState(() { _roastedDate = picked; }); } } void _saveBean() async { if (!_formKey.currentState!.validate()) { return; } try { final bean = Bean( id: widget.bean?.id ?? DateTime.now().millisecondsSinceEpoch.toString(), name: _nameController.text.trim(), origin: _originCountryController.text.trim().isEmpty ? 'Unknown' : _originCountryController.text.trim(), farm: _roasterLocationController.text.trim().isEmpty ? 'Unknown Farm' : _roasterLocationController.text.trim(), producer: 'Unknown Producer', varietal: _varietalController.text.trim().isEmpty ? 'Unknown' : _varietalController.text.trim(), altitude: 1500, processingMethod: _processingMethodController.text.trim().isEmpty ? 'Unknown' : _processingMethodController.text.trim(), harvestSeason: 'Unknown', flavorNotes: _selectedTastingNotes, acidity: Acidity.medium, body: Body.medium, sweetness: 5, roastLevel: _selectedRoastLevel, cupScore: 85.0, price: 15.0, availability: Availability.available, certifications: [], roaster: _roasterNameController.text.trim().isEmpty ? 'Unknown Roaster' : _roasterNameController.text.trim(), roastDate: _roastedDate, bestByDate: _roastedDate.add(Duration(days: 365)), brewingMethods: ['Drip', 'Espresso'], isOwned: _isPreferred, quantity: 250.0, notes: 'User created bean', ); final appState = Provider.of(context, listen: false); if (widget.bean == null) { await appState.addBean(bean); } else { await appState.updateBean(bean); } if (mounted) { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(widget.bean == null ? 'Bean added successfully!' : 'Bean updated successfully!'), backgroundColor: Theme.of(context).colorScheme.primary, ), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Error saving bean: $e'), backgroundColor: Colors.red, ), ); } } } }