feat: implement recipe creation feature including state management, ingredient/step management, image handling, and validation.

This commit is contained in:
mso7nueh
2026-01-22 00:42:30 +03:00
parent de8f879f59
commit e76c1aed20
4 changed files with 37 additions and 2 deletions

View File

@@ -237,7 +237,16 @@ class CreateRecipeCubit extends Cubit<CreateRecipeState> {
final isActiveCookTimeValid = validateActiveCookTime();
final isEnergyPerServingsValid = validateEnergyPerServing();
return isTitleValid && isDescValid && isImageValid && areServingsValid && isCookTimeValid && isActiveCookTimeValid && isEnergyPerServingsValid;
final isStepsValid = validateSteps();
return isTitleValid &&
isDescValid &&
isImageValid &&
areServingsValid &&
isCookTimeValid &&
isActiveCookTimeValid &&
isEnergyPerServingsValid &&
isStepsValid;
}
bool validateTitle() {
@@ -328,4 +337,20 @@ class CreateRecipeCubit extends Cubit<CreateRecipeState> {
Future<List<GlossaryModel>> getGlossaryListByQuery(String query) async {
return await glossaryRepository.getGlossaryListByQuery(query);
}
bool validateSteps() {
bool isValid = true;
for (var step in state.entity.steps) {
if (step.description == null || step.description!.trim().isEmpty) {
isValid = false;
break;
}
}
if (!isValid) {
emit(state.copyWith(stepsValidationError: 'Заполните описание для всех шагов'));
} else {
emit(state.copyWith(stepsValidationError: null));
}
return isValid;
}
}

View File

@@ -15,6 +15,7 @@ abstract class CreateRecipeState with _$CreateRecipeState {
String? servingsValidationError,
String? energyPerServingValidationError,
String? imageValidationError,
String? stepsValidationError,
}) = _CreateRecipeState;
}

View File

@@ -55,6 +55,13 @@ class _StepsWidgetState extends State<StepsWidget> {
),
),
),
if (state.stepsValidationError != null) ...[
const SizedBox(height: 8),
Text(
state.stepsValidationError!,
style: const TextStyle(color: Colors.red, fontSize: 12),
),
],
const SizedBox(height: 12),
ListView.separated(
shrinkWrap: true,

View File

@@ -228,7 +228,9 @@ class _FeedScreenContentState extends State<FeedScreenContent> {
),
const SizedBox(width: 12),
switch (_selectedChipIndex) {
1 => AddItemButton(onTap: () => GoRouter.of(context).pushNamed(RecipeCreateScreen.name)),
1 => AddItemButton(
onTap: state.profile?.roles.contains('consultant') ?? false ? () => GoRouter.of(context).pushNamed(RecipeCreateScreen.name) : null,
),
2 => AddItemButton(
onTap: state.profile?.roles.contains('consultant') ?? false
? () async {