forked from eatvio/eatvio_app
feat: Implement auto-scrolling to the first validation error in the create diet form and refine image validation logic.
This commit is contained in:
@@ -58,6 +58,39 @@ class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
final GlobalKey<MarkdownEditorState> _mdKey = GlobalKey<MarkdownEditorState>();
|
||||
bool _mdToolbarVisible = false;
|
||||
|
||||
final GlobalKey _nameKey = GlobalKey();
|
||||
final GlobalKey _durationKey = GlobalKey();
|
||||
final GlobalKey _statusKey = GlobalKey();
|
||||
final GlobalKey _typeKey = GlobalKey();
|
||||
final GlobalKey _imageKey = GlobalKey();
|
||||
final GlobalKey _planKey = GlobalKey();
|
||||
|
||||
void _scrollToFirstError(CreateDietState state) {
|
||||
GlobalKey? key;
|
||||
if (state.dietNameError != null) {
|
||||
key = _nameKey;
|
||||
} else if (state.dietDescriptionError != null) {
|
||||
key = _mdKey;
|
||||
} else if (state.dietDurationError != null) {
|
||||
key = _durationKey;
|
||||
} else if (state.dietStateError != null) {
|
||||
key = _statusKey;
|
||||
} else if (state.dietImageError != null) {
|
||||
key = _imageKey;
|
||||
} else if (state.dailyScheduleErrors.any((e) => e.isNotEmpty)) {
|
||||
key = _planKey;
|
||||
}
|
||||
|
||||
if (key != null && key.currentContext != null) {
|
||||
Scrollable.ensureVisible(
|
||||
key.currentContext!,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.easeInOut,
|
||||
alignment: 0.1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -118,6 +151,7 @@ class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
CustomTextFormField(
|
||||
key: _nameKey,
|
||||
hintText: s.enter_diet_name,
|
||||
controller: nameController,
|
||||
hasError: state.dietNameError != null,
|
||||
@@ -143,19 +177,20 @@ class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
),
|
||||
if (state.dietDescriptionError != null) ...[const SizedBox(height: 4), ValidationErrorWidget(error: state.dietDescriptionError ?? '')],
|
||||
const SizedBox(height: 12),
|
||||
const DietDurationDropDownWidget(),
|
||||
DietDurationDropDownWidget(key: _durationKey),
|
||||
const SizedBox(height: 12),
|
||||
StatusDropDownWidget(dietState: widget.diet?.state),
|
||||
StatusDropDownWidget(key: _statusKey, dietState: widget.diet?.state),
|
||||
const SizedBox(height: 16),
|
||||
const DietTypeChoiceWidget(),
|
||||
DietTypeChoiceWidget(key: _typeKey),
|
||||
const SizedBox(height: 16),
|
||||
const DietImagePickerWidget(),
|
||||
DietImagePickerWidget(key: _imageKey),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
MainBackgroundBouble(
|
||||
key: _planKey,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Center(
|
||||
@@ -185,7 +220,11 @@ class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
? () {}
|
||||
: () async {
|
||||
final diet = await context.read<CreateDietCubit>().getDietForPreview();
|
||||
if (diet == null) return;
|
||||
if (diet == null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
_scrollToFirstError(context.read<CreateDietCubit>().state);
|
||||
return;
|
||||
}
|
||||
if (!context.mounted) return;
|
||||
GoRouter.of(context).pushNamed(DietPreviewScreen.name, extra: diet);
|
||||
},
|
||||
@@ -204,7 +243,10 @@ class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
CustomOutlinedButton(
|
||||
onPressed: () async {
|
||||
final result = await context.read<CreateDietCubit>().createDiet();
|
||||
if (result == 'error') {
|
||||
if (result == 'validation') {
|
||||
// ignore: use_build_context_synchronously
|
||||
_scrollToFirstError(context.read<CreateDietCubit>().state);
|
||||
} else if (result == 'error') {
|
||||
if (!context.mounted) return;
|
||||
showErrorDialog(context, title: '${s.could_not_publish_diet} ${state.dietData.name}');
|
||||
}
|
||||
|
||||
@@ -394,11 +394,11 @@ class CreateDietCubit extends Cubit<CreateDietState> {
|
||||
result = false;
|
||||
emit(state.copyWith(dietStateError: 'Статус диеты не выбран'));
|
||||
}
|
||||
if (state.dietData.image == null) {
|
||||
if (state.dietData.image == null && state.dietData.imageUrl == null) {
|
||||
result = false;
|
||||
emit(state.copyWith(dietImageError: 'Не добавлена обложка'));
|
||||
}
|
||||
result = _isDailyScheduleValid();
|
||||
result = _isDailyScheduleValid() && result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user