784 lines
23 KiB
Dart
784 lines
23 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_common/widget/common_widget.dart';
|
||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||
import 'package:food_hub_app/models/recipe.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';
|
||
|
||
class RecipeFormPage extends StatefulWidget {
|
||
final RecipeDetail? initialData;
|
||
|
||
const RecipeFormPage({super.key, this.initialData});
|
||
|
||
@override
|
||
State<RecipeFormPage> createState() => _RecipeFormPageState();
|
||
}
|
||
|
||
class _RecipeFormPageState extends State<RecipeFormPage> {
|
||
final _formKey = GlobalKey<FormBuilderState>();
|
||
int _currentStep = 0;
|
||
List<RecipeMaterial> _materials = [];
|
||
List<RecipeStep> _steps = [];
|
||
|
||
// 表单字段名称常量
|
||
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<String> _categoryOptions = [
|
||
'家常菜',
|
||
'川菜',
|
||
'粤菜',
|
||
'湘菜',
|
||
'西餐',
|
||
'甜品',
|
||
'汤羹',
|
||
'其他',
|
||
];
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_initializeFormData();
|
||
}
|
||
|
||
void _initializeFormData() {
|
||
if (widget.initialData != null) {
|
||
_materials = List.from(widget.initialData!.materialList);
|
||
_steps = List.from(widget.initialData!.stepList);
|
||
}
|
||
}
|
||
|
||
// 构建步骤内容
|
||
Widget _buildStepContent() {
|
||
switch (_currentStep) {
|
||
case 0:
|
||
return _buildBasicInfoStep();
|
||
case 1:
|
||
return _buildMaterialsStep();
|
||
case 2:
|
||
return _buildStepsStep();
|
||
default:
|
||
return _buildBasicInfoStep();
|
||
}
|
||
}
|
||
|
||
// 第一步:基本信息
|
||
Widget _buildBasicInfoStep() {
|
||
return SingleChildScrollView(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
buildFormLabel(context: context, text: '菜谱名称', isRequired: true),
|
||
const SizedBox(height: 8),
|
||
FormBuilderTextField(
|
||
name: _nameField,
|
||
initialValue: widget.initialData?.name ?? '',
|
||
decoration: buildInputDecoration(
|
||
context: context,
|
||
hintText: '请输入菜谱名称',
|
||
prefixIcon: Icons.restaurant_menu,
|
||
),
|
||
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: widget.initialData?.category ?? '家常菜',
|
||
decoration: buildInputDecoration(
|
||
context: context,
|
||
hintText: '请选择分类',
|
||
prefixIcon: Icons.widgets,
|
||
),
|
||
items:
|
||
_categoryOptions
|
||
.map(
|
||
(category) => DropdownMenuItem(
|
||
value: category,
|
||
child: Text(category),
|
||
),
|
||
)
|
||
.toList(),
|
||
validator: FormBuilderValidators.required(errorText: '请选择分类'),
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
buildFormLabel(context: context, text: '推荐评分', isRequired: false),
|
||
const SizedBox(height: 8),
|
||
FormBuilderSlider(
|
||
name: _recommendRateField,
|
||
initialValue: widget.initialData?.recommendRate ?? 3.0,
|
||
min: 0,
|
||
max: 5,
|
||
divisions: 10,
|
||
activeColor: Colors.orange,
|
||
decoration: const InputDecoration(border: InputBorder.none),
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
buildFormLabel(context: context, text: '备注', isRequired: false),
|
||
const SizedBox(height: 8),
|
||
FormBuilderTextField(
|
||
name: _remarkField,
|
||
initialValue: widget.initialData?.remark ?? '',
|
||
maxLines: 3,
|
||
decoration: buildInputDecoration(
|
||
context: context,
|
||
hintText: '请输入菜谱的特别说明或小贴士'
|
||
)
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
FormBuilderCheckbox(
|
||
name: _isShareField,
|
||
initialValue: widget.initialData?.isShare ?? false,
|
||
title: const Text('公开分享此菜谱'),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
// 第二步:食材清单
|
||
Widget _buildMaterialsStep() {
|
||
return SingleChildScrollView(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Text('食材清单', style: Theme.of(context).textTheme.headlineSmall),
|
||
const Spacer(),
|
||
IconButton(
|
||
icon: const Icon(Icons.add, color: Colors.blue),
|
||
onPressed: _addMaterial,
|
||
tooltip: '添加食材',
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
if (_materials.isEmpty)
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(vertical: 40),
|
||
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
|
||
..._materials.asMap().entries.map(
|
||
(entry) => _buildMaterialItem(entry.key, entry.value),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildMaterialItem(int index, RecipeMaterial material) {
|
||
return Card(
|
||
key: ValueKey(material.id),
|
||
margin: const EdgeInsets.only(bottom: 12),
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Column(
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(
|
||
horizontal: 12,
|
||
vertical: 4,
|
||
),
|
||
decoration: BoxDecoration(
|
||
color: Colors.blue.shade50,
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
child: Text(
|
||
'食材 ${index + 1}',
|
||
style: const TextStyle(
|
||
fontWeight: FontWeight.bold,
|
||
color: Colors.blue,
|
||
),
|
||
),
|
||
),
|
||
const Spacer(),
|
||
IconButton(
|
||
icon: const Icon(Icons.delete, color: Colors.red, size: 20),
|
||
onPressed: () => _removeMaterial(index),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 12),
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: TextFormField(
|
||
initialValue: material.type,
|
||
decoration: const InputDecoration(
|
||
labelText: '类型',
|
||
border: OutlineInputBorder(),
|
||
hintText: '如:主料、辅料',
|
||
),
|
||
onChanged: (value) {
|
||
_updateMaterial(index, type: value);
|
||
},
|
||
),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
flex: 2,
|
||
child: TextFormField(
|
||
initialValue: material.name,
|
||
decoration: const InputDecoration(
|
||
labelText: '食材名称',
|
||
border: OutlineInputBorder(),
|
||
hintText: '如:鸡蛋、西红柿',
|
||
),
|
||
onChanged: (value) {
|
||
_updateMaterial(index, name: value);
|
||
},
|
||
),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
child: TextFormField(
|
||
initialValue: material.amount,
|
||
decoration: const InputDecoration(
|
||
labelText: '用量',
|
||
border: OutlineInputBorder(),
|
||
hintText: '如:2个、100g',
|
||
),
|
||
onChanged: (value) {
|
||
_updateMaterial(index, amount: value);
|
||
},
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
void _addMaterial() {
|
||
setState(() {
|
||
_materials.add(
|
||
RecipeMaterial(
|
||
id: DateTime.now().microsecondsSinceEpoch,
|
||
type: '主料',
|
||
name: '',
|
||
amount: '',
|
||
),
|
||
);
|
||
});
|
||
}
|
||
|
||
void _removeMaterial(int index) {
|
||
setState(() {
|
||
_materials.removeAt(index);
|
||
});
|
||
}
|
||
|
||
void _updateMaterial(
|
||
int index, {
|
||
String? type,
|
||
String? name,
|
||
String? amount,
|
||
}) {
|
||
setState(() {
|
||
final material = _materials[index];
|
||
_materials[index] = RecipeMaterial(
|
||
id: material.id,
|
||
type: type ?? material.type,
|
||
name: name ?? material.name,
|
||
amount: amount ?? material.amount,
|
||
);
|
||
});
|
||
}
|
||
|
||
// 第三步:制作步骤
|
||
Widget _buildStepsStep() {
|
||
return SingleChildScrollView(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Text('制作步骤', style: Theme.of(context).textTheme.headlineSmall),
|
||
const Spacer(),
|
||
IconButton(
|
||
icon: const Icon(Icons.add, color: Colors.blue),
|
||
onPressed: _addStep,
|
||
tooltip: '添加步骤',
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
if (_steps.isEmpty)
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(vertical: 40),
|
||
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
|
||
ReorderableListView.builder(
|
||
shrinkWrap: true,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
itemCount: _steps.length,
|
||
itemBuilder:
|
||
(context, index) => _buildStepItem(index, _steps[index]),
|
||
onReorder:
|
||
(oldIndex, newIndex) => _reorderStep(oldIndex, newIndex),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildStepItem(int index, RecipeStep step) {
|
||
return Card(
|
||
key: Key('step_$index'),
|
||
margin: const EdgeInsets.only(bottom: 12),
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Column(
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(
|
||
horizontal: 12,
|
||
vertical: 6,
|
||
),
|
||
decoration: BoxDecoration(
|
||
color: Colors.green.shade50,
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
child: Text(
|
||
'步骤 ${index + 1}',
|
||
style: const TextStyle(
|
||
fontWeight: FontWeight.bold,
|
||
color: Colors.green,
|
||
),
|
||
),
|
||
),
|
||
const Spacer(),
|
||
IconButton(
|
||
icon: const Icon(Icons.delete, color: Colors.red),
|
||
onPressed: () => _removeStep(index),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 12),
|
||
TextFormField(
|
||
initialValue: step.content,
|
||
maxLines: 3,
|
||
decoration: const InputDecoration(
|
||
labelText: '步骤说明',
|
||
border: OutlineInputBorder(),
|
||
hintText: '详细描述此步骤的操作方法',
|
||
),
|
||
onChanged: (value) {
|
||
_updateStep(index, content: value);
|
||
},
|
||
),
|
||
const SizedBox(height: 12),
|
||
TextFormField(
|
||
initialValue: step.imageUrl,
|
||
decoration: const InputDecoration(
|
||
labelText: '步骤图片URL(可选)',
|
||
border: OutlineInputBorder(),
|
||
hintText: '添加步骤演示图片链接',
|
||
prefixIcon: Icon(Icons.image),
|
||
),
|
||
onChanged: (value) {
|
||
_updateStep(index, imageUrl: value);
|
||
},
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
void _addStep() {
|
||
setState(() {
|
||
_steps.add(
|
||
RecipeStep(
|
||
id: DateTime.now().microsecond,
|
||
sort: _steps.length,
|
||
content: '',
|
||
imageUrl: '',
|
||
),
|
||
);
|
||
});
|
||
}
|
||
|
||
void _removeStep(int index) {
|
||
setState(() {
|
||
_steps.removeAt(index);
|
||
// 重新排序
|
||
for (int i = 0; i < _steps.length; i++) {
|
||
_steps[i] = RecipeStep(
|
||
id: DateTime.now().microsecond,
|
||
sort: i,
|
||
content: _steps[i].content,
|
||
imageUrl: _steps[i].imageUrl,
|
||
);
|
||
}
|
||
});
|
||
}
|
||
|
||
void _reorderStep(int oldIndex, int newIndex) {
|
||
setState(() {
|
||
if (oldIndex < newIndex) {
|
||
newIndex -= 1;
|
||
}
|
||
final RecipeStep item = _steps.removeAt(oldIndex);
|
||
_steps.insert(newIndex, item);
|
||
// 更新排序序号
|
||
for (int i = 0; i < _steps.length; i++) {
|
||
_steps[i] = RecipeStep(
|
||
id: DateTime.now().microsecond,
|
||
sort: i,
|
||
content: _steps[i].content,
|
||
imageUrl: _steps[i].imageUrl,
|
||
);
|
||
}
|
||
});
|
||
}
|
||
|
||
void _updateStep(int index, {String? content, String? imageUrl}) {
|
||
setState(() {
|
||
final step = _steps[index];
|
||
_steps[index] = RecipeStep(
|
||
id: DateTime.now().microsecond,
|
||
sort: step.sort,
|
||
content: content ?? step.content,
|
||
imageUrl: imageUrl ?? step.imageUrl,
|
||
);
|
||
});
|
||
}
|
||
|
||
// 步骤指示器
|
||
Widget _buildStepIndicator() {
|
||
return Container(
|
||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||
child: Column(
|
||
children: [
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
_buildStepCircle(0),
|
||
_buildStepConnector(0),
|
||
_buildStepCircle(1),
|
||
_buildStepConnector(1),
|
||
_buildStepCircle(2),
|
||
],
|
||
),
|
||
Container(
|
||
margin: const EdgeInsets.only(top: 8),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
_buildStepTitle(0, '基本信息'),
|
||
SizedBox(width: 25),
|
||
_buildStepTitle(1, '食材清单'),
|
||
SizedBox(width: 25),
|
||
_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: isActive ? Colors.white : Colors.grey.shade700,
|
||
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() {
|
||
final isLastStep = _currentStep == 2;
|
||
final isFirstStep = _currentStep == 0;
|
||
|
||
return Row(
|
||
children: [
|
||
if (!isFirstStep)
|
||
Expanded(
|
||
child: OutlinedButton(
|
||
onPressed: _previousStep,
|
||
style: OutlinedButton.styleFrom(
|
||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||
side: BorderSide(color: Theme.of(context).colorScheme.primary),
|
||
),
|
||
child: Text(
|
||
'上一步',
|
||
style: TextStyle(color: Theme.of(context).colorScheme.primary),
|
||
),
|
||
),
|
||
),
|
||
if (!isFirstStep) const SizedBox(width: 12),
|
||
Expanded(
|
||
child: buildPrimaryButton(
|
||
context: context,
|
||
text: isLastStep ? '完成创建' : '下一步',
|
||
onPressed: _nextStep,
|
||
),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
void _nextStep() {
|
||
if (_currentStep < 2) {
|
||
if (_formKey.currentState?.saveAndValidate() ?? false) {
|
||
setState(() {
|
||
_currentStep++;
|
||
});
|
||
}
|
||
} else {
|
||
_submitForm();
|
||
}
|
||
}
|
||
|
||
void _previousStep() {
|
||
if (_currentStep > 0) {
|
||
setState(() {
|
||
_currentStep--;
|
||
});
|
||
}
|
||
}
|
||
|
||
bool _validateCurrentStep() {
|
||
return true;
|
||
switch (_currentStep) {
|
||
case 0:
|
||
// 验证基本信息
|
||
final name =
|
||
_formKey.currentState?.fields[_nameField]?.value?.toString() ?? '';
|
||
final category =
|
||
_formKey.currentState?.fields[_categoryField]?.value?.toString() ??
|
||
'';
|
||
|
||
if (name.isEmpty) {
|
||
ToastUtil.error('请输入菜谱名称');
|
||
return false;
|
||
}
|
||
if (category.isEmpty) {
|
||
ToastUtil.error('请选择分类');
|
||
return false;
|
||
}
|
||
return true;
|
||
|
||
case 1:
|
||
// 验证食材清单
|
||
if (_materials.isEmpty) {
|
||
ToastUtil.error('请至少添加一个食材');
|
||
return false;
|
||
}
|
||
|
||
for (var material in _materials) {
|
||
if (material.name.isEmpty || material.amount.isEmpty) {
|
||
ToastUtil.error('请完善食材信息');
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
|
||
case 2:
|
||
// 验证制作步骤
|
||
if (_steps.isEmpty) {
|
||
ToastUtil.error('请至少添加一个制作步骤');
|
||
return false;
|
||
}
|
||
|
||
for (var step in _steps) {
|
||
if (step.content.isEmpty) {
|
||
ToastUtil.error('请完善步骤说明');
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
|
||
default:
|
||
return true;
|
||
}
|
||
}
|
||
|
||
void _submitForm() {
|
||
if (_formKey.currentState?.saveAndValidate() ?? false) {
|
||
if (_validateCurrentStep()) {
|
||
final formData = _formKey.currentState!.value;
|
||
|
||
// 构建完整的RecipeDetail对象
|
||
final recipe = RecipeDetail(
|
||
id: widget.initialData?.id ?? 0,
|
||
name: formData[_nameField],
|
||
category: formData[_categoryField],
|
||
recommendRate: formData[_recommendRateField] ?? 3.0,
|
||
remark: formData[_remarkField] ?? '',
|
||
isShare: formData[_isShareField] ?? false,
|
||
userId: widget.initialData?.userId ?? 0,
|
||
username: widget.initialData?.username ?? '',
|
||
avatar: widget.initialData?.avatar ?? '',
|
||
materialList: _materials,
|
||
stepList: _steps,
|
||
recordList: widget.initialData?.recordList ?? [],
|
||
likeList: widget.initialData?.likeList ?? [],
|
||
favouriteList: widget.initialData?.favouriteList ?? [],
|
||
commentList: widget.initialData?.commentList ?? [],
|
||
);
|
||
|
||
_saveRecipe(recipe);
|
||
}
|
||
} else {
|
||
ToastUtil.error('请检查表单填写是否正确');
|
||
}
|
||
}
|
||
|
||
void _saveRecipe(RecipeDetail recipe) {
|
||
LoadingDialog.show(context, message: '提交中');
|
||
|
||
// 模拟保存操作
|
||
Future.delayed(const Duration(seconds: 2), () {
|
||
LoadingDialog.hide(context);
|
||
|
||
if (mounted) {
|
||
ToastUtil.success(widget.initialData == null ? '菜谱创建成功!' : '菜谱更新成功!');
|
||
|
||
Future.delayed(const Duration(milliseconds: 1500), () {
|
||
if (mounted) {
|
||
Navigator.pop(context);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final colors = Theme.of(context).colorScheme;
|
||
final title = widget.initialData == null ? '创建新菜谱' : '编辑菜谱';
|
||
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
title: Text(title, style: const TextStyle(color: Colors.white)),
|
||
backgroundColor: colors.primary,
|
||
leading: IconButton(
|
||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
||
onPressed: () => Navigator.pop(context),
|
||
),
|
||
),
|
||
body: Padding(
|
||
padding: EdgeInsets.all(10),
|
||
child: CommonCard(
|
||
child: Column(
|
||
children: [
|
||
_buildStepIndicator(),
|
||
Expanded(
|
||
child: FormBuilder(
|
||
key: _formKey,
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: _buildStepContent(),
|
||
),
|
||
),
|
||
),
|
||
_buildNavigationButtons(),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|