import 'package:flutter/material.dart'; import 'package:flutter_common/widget/dialog_widget.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:food_hub_app/models/recipe.dart'; import 'package:food_hub_app/provider/food_provider.dart'; import 'package:food_hub_app/widgets/common/form.dart'; import 'package:food_hub_app/widgets/common/index.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:flutter_common/utils/toast_util.dart'; import 'package:flutter_common/widget/loading_widget.dart'; import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; import 'package:liquid_glass_widgets/widgets/containers/glass_card.dart'; import 'package:provider/provider.dart'; class RecipeForm extends StatefulWidget { const RecipeForm({super.key}); @override State createState() => _RecipeFormState(); } class _RecipeFormState extends State { final _formKey = GlobalKey(); int _currentStep = 0; // 表单字段名称常量 static const String _nameField = 'name'; static const String _categoryField = 'category'; static const String _recommendRateField = 'recommendRate'; static const String _remarkField = 'remark'; static const String _isShareField = 'isShare'; // 分类选项 final List _categoryOptions = [ '家常菜', '川菜', '粤菜', '湘菜', '西餐', '甜品', '汤羹', '其他', ]; @override void initState() { super.initState(); } // 构建步骤内容 Widget _buildStepContent(FoodProvider provider) { switch (_currentStep) { case 0: return _buildInfo(provider); case 1: return _buildMaterials(provider); case 2: return _buildSteps(provider); default: return _buildInfo(provider); } } // 第一步:基本信息 Widget _buildInfo(FoodProvider provider) { return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ buildFormLabel(context: context, text: '菜谱名称', isRequired: true), const SizedBox(height: 8), FormBuilderTextField( name: _nameField, initialValue: provider.recipeFormItem.name, decoration: buildInputDecoration( context: context, hintText: '请输入菜谱名称', prefixIcon: Icons.restaurant_menu, ), onChanged: (value) { provider.updateRecipeFormItem(name: value ?? ''); }, validator: FormBuilderValidators.compose([ FormBuilderValidators.required(errorText: '菜谱名称不能为空'), FormBuilderValidators.maxLength(50, errorText: '名称不能超过50个字符'), ]), ), const SizedBox(height: 16), buildFormLabel(context: context, text: '分类', isRequired: true), const SizedBox(height: 8), FormBuilderDropdown( name: _categoryField, initialValue: provider.recipeFormItem.category, decoration: buildInputDecoration( context: context, hintText: '请选择分类', prefixIcon: Icons.widgets, ), items: _categoryOptions .map( (category) => DropdownMenuItem( value: category, child: Text(category), ), ) .toList(), onChanged: (value) { provider.updateRecipeFormItem(category: value ?? ''); }, validator: FormBuilderValidators.required(errorText: '请选择分类'), ), const SizedBox(height: 16), buildFormLabel(context: context, text: '推荐评分', isRequired: false), const SizedBox(height: 8), FormBuilderSlider( name: _recommendRateField, initialValue: provider.recipeFormItem.recommendRate, min: 1, max: 5, divisions: 4, activeColor: Theme.of(context).colorScheme.primary, decoration: const InputDecoration(border: InputBorder.none), onChanged: (value) { provider.updateRecipeFormItem(recommendRate: value ?? 0); }, ), const SizedBox(height: 16), buildFormLabel(context: context, text: '备注', isRequired: false), const SizedBox(height: 8), FormBuilderTextField( name: _remarkField, initialValue: provider.recipeFormItem.remark, maxLines: 3, decoration: buildInputDecoration( context: context, hintText: '请输入菜谱的特别说明或小贴士', ), onChanged: (value) { provider.updateRecipeFormItem(remark: value ?? ''); }, ), const SizedBox(height: 16), FormBuilderCheckbox( name: _isShareField, initialValue: provider.recipeFormItem.isShare, title: const Text('公开分享此菜谱'), onChanged: (value) { provider.updateRecipeFormItem(isShare: value ?? false); }, ), ], ), ); } // 第二步:食材清单 Widget _buildMaterials(FoodProvider provider) { final materials = provider.recipeFormItem.materialList; return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text('食材清单', style: Theme.of(context).textTheme.titleMedium), const Spacer(), IconButton( icon: Icon( Icons.add, color: Theme.of(context).colorScheme.primary, ), onPressed: () => provider.addRecipeMaterial(), tooltip: '添加食材', ), ], ), if (materials.isEmpty) Container( color: Theme.of(context).colorScheme.surface, margin: EdgeInsets.only(bottom: 10), padding: const EdgeInsets.all(10), child: Column( children: [ Icon(Icons.inventory_2, size: 48, color: Colors.grey[400]), const SizedBox(height: 16), Text( '暂无食材,请点击添加按钮添加食材', style: TextStyle(color: Colors.grey[600]), ), ], ), ) else Column( children: materials.asMap().entries.map((entry) { final index = entry.key; final material = entry.value; return Column( children: [ _buildMaterialItem(index, material, provider), const SizedBox(height: 8), ], ); }).toList(), ), ], ), ); } Widget _buildMaterialItem( int index, RecipeMaterial material, FoodProvider provider, ) { return Column( key: ValueKey(material.id), children: [ Row( children: [ Expanded( child: TextFormField( initialValue: material.name, decoration: buildInputDecoration( context: context, hintText: '请输入名称', prefixIcon: Icons.content_paste, ), onChanged: (value) { provider.updateRecipeMaterial(index, name: value); }, ), ), const SizedBox(width: 12), Expanded( child: TextFormField( initialValue: material.amount, decoration: buildInputDecoration( context: context, hintText: '请输入用量', prefixIcon: Icons.scale, ), onChanged: (value) { provider.updateRecipeMaterial(index, amount: value); }, ), ), IconButton( icon: const Icon(Icons.delete, color: Colors.red, size: 20), onPressed: () => provider.removeRecipeMaterial(index), ), ], ), ], ); } // 第三步:制作步骤 Widget _buildSteps(FoodProvider provider) { final steps = provider.recipeFormItem.stepList; return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text('制作步骤', style: Theme.of(context).textTheme.titleMedium), const Spacer(), IconButton( icon: Icon( Icons.add, color: Theme.of(context).colorScheme.primary, ), onPressed: () => provider.addRecipeStep(), tooltip: '添加步骤', ), ], ), if (steps.isEmpty) Container( color: Theme.of(context).colorScheme.surface, margin: EdgeInsets.only(bottom: 10), padding: const EdgeInsets.all(10), child: Column( children: [ Icon(Icons.list_alt, size: 48, color: Colors.grey[400]), const SizedBox(height: 16), Text( '暂无步骤,请点击添加按钮添加制作步骤', style: TextStyle(color: Colors.grey[600]), ), ], ), ) else Column( children: steps.asMap().entries.map((entry) { final index = entry.key; final step = entry.value; return Column( children: [ _buildStepItem(index, step, provider), const SizedBox(height: 8), ], ); }).toList(), ), ], ), ); } Widget _buildStepItem(int index, RecipeStep step, FoodProvider provider) { return Row( key: ValueKey(step.id), crossAxisAlignment: CrossAxisAlignment.center, children: [ // 步骤编号 Container( width: 28, height: 28, alignment: Alignment.center, decoration: BoxDecoration( color: Theme.of(context).colorScheme.primary, shape: BoxShape.circle, ), child: Text( '${index + 1}', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14, ), ), ), const SizedBox(width: 12), // 步骤内容 Expanded( child: TextFormField( initialValue: step.content, decoration: buildInputDecoration( context: context, hintText: '请输入内容', prefixIcon: Icons.content_paste, ), onChanged: (value) { provider.updateRecipeStep(index, content: value); }, ), ), // 删除按钮 IconButton( icon: const Icon(Icons.delete, color: Colors.red), onPressed: () => provider.removeRecipeStep(index), ), ], ); } // 步骤指示器 Widget _buildStepIndicator() { return Container( padding: const EdgeInsets.symmetric(vertical: 16), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ _buildStepCircle(0), SizedBox(width: 10), _buildStepConnector(0), SizedBox(width: 10), _buildStepCircle(1), SizedBox(width: 10), _buildStepConnector(1), SizedBox(width: 10), _buildStepCircle(2), ], ), Container( margin: const EdgeInsets.only(top: 8), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ _buildStepTitle(0, '基本信息'), SizedBox(width: 40), _buildStepTitle(1, '食材清单'), SizedBox(width: 40), _buildStepTitle(2, '制作步骤'), ], ), ), ], ), ); } // 只构建圆圈,不包含标题文字 Widget _buildStepCircle(int stepIndex) { final isActive = _currentStep == stepIndex; final isCompleted = _currentStep > stepIndex; final boxColor = isActive || isCompleted ? Theme.of(context).colorScheme.primary : Colors.grey; return Container( width: 32, height: 32, decoration: BoxDecoration(color: boxColor, shape: BoxShape.circle), child: Center( child: isCompleted ? const Icon(Icons.check, color: Colors.white, size: 16) : Text( '${stepIndex + 1}', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), ), ); } // 箭头连接器 Widget _buildStepConnector(int stepIndex) { final isActive = _currentStep > stepIndex; return SizedBox( width: 40, child: Icon( Icons.arrow_forward, size: 20, color: isActive ? Theme.of(context).colorScheme.primary : Colors.grey, ), ); } Widget _buildStepTitle(int stepIndex, String title) { final isActive = _currentStep == stepIndex; final isCompleted = _currentStep > stepIndex; final textColor = isActive || isCompleted ? Theme.of(context).colorScheme.primary : Colors.grey; return Text( title, textAlign: TextAlign.center, style: TextStyle( fontWeight: isActive ? FontWeight.bold : FontWeight.normal, color: textColor, fontSize: 12, ), ); } // 导航按钮 Widget _buildNavigationButtons(FoodProvider provider) { final isLastStep = _currentStep == 2; final isFirstStep = _currentStep == 0; return Row( children: [ if (!isFirstStep) Expanded( child: buildInfoButton( context: context, text: '上一步', onPressed: _previousStep, ), ), if (!isFirstStep) const SizedBox(width: 12), Expanded( child: buildPrimaryButton( context: context, text: isLastStep ? '提交' : '下一步', onPressed: () => _nextStep(provider), ), ), ], ); } void _nextStep(FoodProvider provider) { if (_currentStep < 2) { if (_formKey.currentState?.saveAndValidate() ?? false) { setState(() { _currentStep++; }); } } else { _submitForm(provider); } } void _previousStep() { if (_currentStep > 0) { setState(() { _currentStep--; }); } } void _submitForm(FoodProvider provider) async { if (_formKey.currentState?.saveAndValidate() ?? false) { LoadingDialog.show(context, message: '提交中'); final result = await provider.handleRecipe(); if (result == true) { LoadingDialog.hide(context); if (provider.isEditing) { showSuccessTip(context, '更新菜谱成功'); } else { showSuccessTip(context, '新增菜谱成功'); } Future.delayed(Duration(milliseconds: 1500), () { if (mounted) { Navigator.pop(context); } }); } else { LoadingDialog.hide(context); if (provider.isEditing) { showErrorTip(context, '更新菜谱失败'); } else { showErrorTip(context, '新增菜谱失败'); } } } else { ToastUtil.error('请检查表单填写是否正确'); } } @override Widget build(BuildContext context) { final provider = context.watch(); return SingleChildScrollView( child: Padding( padding: EdgeInsets.all(10), child: GlassCard( useOwnLayer: true, settings: LiquidGlassSettings( glassColor: Theme.of(context).scaffoldBackgroundColor, ), child: Column( children: [ _buildStepIndicator(), FormBuilder(key: _formKey, child: _buildStepContent(provider)), _buildNavigationButtons(provider), ], ), ), ), ); } }