forked from eatvio/eatvio_app
create diet screen updated
This commit is contained in:
@@ -2,13 +2,16 @@ import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart';
|
||||
import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
|
||||
import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||
|
||||
class CreateDietCubit extends Cubit<CreateDietState> {
|
||||
final CreateDietRepository createDietRepository;
|
||||
final GlossaryRepository glossaryRepository;
|
||||
static const _dietStateValues = ['active', 'draft', 'personal'];
|
||||
CreateDietCubit({required this.createDietRepository}) : super(CreateDietState.initial());
|
||||
CreateDietCubit({required this.createDietRepository, required this.glossaryRepository}) : super(CreateDietState.initial());
|
||||
|
||||
void setDetails(String text) {
|
||||
emit(state.copyWith(dietData: state.dietData.copyWith(details: text)));
|
||||
@@ -29,6 +32,10 @@ class CreateDietCubit extends Cubit<CreateDietState> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<GlossaryModel>> getGlossaryListByQuery(String query) async {
|
||||
return await glossaryRepository.getGlossaryListByQuery(query);
|
||||
}
|
||||
|
||||
void setImage(XFile? image) {
|
||||
emit(state.copyWith(dietData: state.dietData.copyWith(image: image)));
|
||||
}
|
||||
@@ -44,4 +51,16 @@ class CreateDietCubit extends Cubit<CreateDietState> {
|
||||
void setDietType(List<bool> type) {
|
||||
emit(state.copyWith(dietData: state.dietData.copyWith(type: type)));
|
||||
}
|
||||
|
||||
void addPortion({required int dayIndex,required int mealIndex, required DailySchedule portion}) {
|
||||
final currentSchedule = state.dietData.dailySchedule;
|
||||
if (currentSchedule != null) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void removePortion({required int day,required int meal,required int portionIndex, }) {}
|
||||
|
||||
void updatePortion({required int day,required int meal,required int portionIndex, required DailySchedule portion}) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
|
||||
class AddMealWidget extends StatefulWidget {
|
||||
const AddMealWidget({
|
||||
super.key,
|
||||
required this.createDietCubit,
|
||||
this.portionIndex,
|
||||
this.productNameControllerText,
|
||||
this.quantityControllerText,
|
||||
required this.dayIndex,
|
||||
required this.mealIndex,
|
||||
});
|
||||
final CreateDietCubit createDietCubit;
|
||||
final String? productNameControllerText;
|
||||
final String? quantityControllerText;
|
||||
final int? portionIndex;
|
||||
final int dayIndex;
|
||||
final int mealIndex;
|
||||
@override
|
||||
State<AddMealWidget> createState() => _AddMealWidgetState();
|
||||
}
|
||||
|
||||
class _AddMealWidgetState extends State<AddMealWidget> {
|
||||
GlossaryModel? selectedGlossary;
|
||||
final productNameController = TextEditingController();
|
||||
final quantityController = TextEditingController();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16) +
|
||||
EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Добавление блюда',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF323F4B),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.8 - 32,
|
||||
child: TypeAheadField<GlossaryModel>(
|
||||
controller: productNameController,
|
||||
itemBuilder: (context, glossary) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
glossary.name,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
itemSeparatorBuilder: (context, index) => _divider(context),
|
||||
onSelected: (newSelectedGlossary) async {
|
||||
setState(() {
|
||||
selectedGlossary = newSelectedGlossary;
|
||||
productNameController.text = selectedGlossary!.name;
|
||||
});
|
||||
},
|
||||
suggestionsCallback: (query) async {
|
||||
if (query.length < 1) return [];
|
||||
final suggestionsList = await widget.createDietCubit.getGlossaryListByQuery(query);
|
||||
return suggestionsList;
|
||||
},
|
||||
builder: (context, controller, focusNode) {
|
||||
return CustomTextFormField(
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
focusNode: focusNode,
|
||||
hintText: 'Введите название продукта/блюда',
|
||||
);
|
||||
},
|
||||
emptyBuilder: (context) {
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
errorBuilder: (context, object) => Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text('Нет подходящих вариантов'),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.2 - 4,
|
||||
child: CustomTextFormField(
|
||||
controller: quantityController,
|
||||
keyboardType: TextInputType.number,
|
||||
hintText: selectedGlossary == null
|
||||
? '100'
|
||||
: selectedGlossary!.grInPortion == 0
|
||||
? '100'
|
||||
: '1',
|
||||
suffixText: selectedGlossary == null
|
||||
? 'гр'
|
||||
: selectedGlossary?.grInPortion == 0
|
||||
? 'гр'
|
||||
: 'шт',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
if (widget.portionIndex != null)
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
width: 52,
|
||||
height: 52,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Color(0xFFF6F6F6),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.delete_outline_rounded,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.portionIndex != null) const SizedBox(width: 8),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if (widget.portionIndex == null) {
|
||||
// final glossary = selectedGlossary;
|
||||
// if (glossary != null) {
|
||||
// final measurementUnits = glossary.grInPortion != 0 ? Portion.PCS : Portion.GRAMS ;
|
||||
// final portion = DailySchedule(
|
||||
// quantity: int.parse(quantityController.text),
|
||||
// name: glossary.name,
|
||||
// uniq: glossary.id.toString(),
|
||||
// portion: measurementUnits,
|
||||
// );
|
||||
// widget.createDietCubit.addPortion(
|
||||
// dayIndex: widget.dayIndex,
|
||||
// mealIndex: widget.mealIndex,
|
||||
// portion: portion,
|
||||
// );
|
||||
// }
|
||||
} else {
|
||||
// final portion = DailySchedule(
|
||||
// quantity: int.parse(quantityController.text),
|
||||
// name: glossary.name,
|
||||
// uniq: glossary.id.toString(),
|
||||
// portion: measurementUnits,
|
||||
// );
|
||||
// widget.createDietCubit.updatePortion(
|
||||
// day: widget.dayIndex,
|
||||
// meal: widget.mealIndex,
|
||||
// portionIndex: widget.portionIndex!,
|
||||
// portion: portion,
|
||||
// );
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
if (selectedGlossary == null) {
|
||||
showModalBottomSheet(
|
||||
isScrollControlled: true,
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (context) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: GlossaryModerationRequestModalWidget(
|
||||
productName: productNameController.text,
|
||||
diaryCubit: sl<DiaryCubit>(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - (widget.portionIndex == null ? 32 : 92),
|
||||
height: 52,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
widget.portionIndex == null ? 'Добавить' : 'Сохранить',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_divider(BuildContext context) {
|
||||
return Container(
|
||||
height: 0.4,
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black26,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,19 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/add_meal_widget.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
|
||||
class DayWidget extends StatefulWidget {
|
||||
const DayWidget({
|
||||
@@ -22,7 +26,7 @@ class DayWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _DayWidgetState extends State<DayWidget> {
|
||||
int _selectedDayIndex = 0;
|
||||
int _selectedMealIndex = 0;
|
||||
final chipsLabelList = ['1', '2', '3', '4', '5'];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -74,10 +78,10 @@ class _DayWidgetState extends State<DayWidget> {
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 0,
|
||||
selectedChipIndex: _selectedDayIndex,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedDayIndex = 0;
|
||||
_selectedMealIndex = 0;
|
||||
});
|
||||
},
|
||||
),
|
||||
@@ -88,10 +92,10 @@ class _DayWidgetState extends State<DayWidget> {
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 1,
|
||||
selectedChipIndex: _selectedDayIndex,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedDayIndex = 1;
|
||||
_selectedMealIndex = 1;
|
||||
});
|
||||
},
|
||||
),
|
||||
@@ -102,10 +106,10 @@ class _DayWidgetState extends State<DayWidget> {
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 2,
|
||||
selectedChipIndex: _selectedDayIndex,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedDayIndex = 2;
|
||||
_selectedMealIndex = 2;
|
||||
});
|
||||
},
|
||||
),
|
||||
@@ -116,10 +120,10 @@ class _DayWidgetState extends State<DayWidget> {
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 3,
|
||||
selectedChipIndex: _selectedDayIndex,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedDayIndex = 3;
|
||||
_selectedMealIndex = 3;
|
||||
});
|
||||
},
|
||||
),
|
||||
@@ -130,15 +134,37 @@ class _DayWidgetState extends State<DayWidget> {
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 4,
|
||||
selectedChipIndex: _selectedDayIndex,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedDayIndex = 4;
|
||||
_selectedMealIndex = 4;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
ListView.builder(
|
||||
itemBuilder: (context, index) {
|
||||
final product = state.dietData.dailySchedule?[widget.index][_selectedMealIndex][index];
|
||||
if (product != null) {
|
||||
return _product(
|
||||
index,
|
||||
product.name,
|
||||
product.quantity,
|
||||
getLocalizedMeasurementUnits(
|
||||
s,
|
||||
product.portion,
|
||||
),
|
||||
widget.index,
|
||||
_selectedMealIndex,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
itemCount: state.dietData.dailySchedule?[widget.index][_selectedMealIndex].length ?? 0,
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
@@ -154,6 +180,13 @@ class _DayWidgetState extends State<DayWidget> {
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
_modalBottomSheet(
|
||||
dayIndex: widget.index,
|
||||
mealIndex: _selectedMealIndex,
|
||||
createDietCubit: context.read<CreateDietCubit>(),
|
||||
);
|
||||
},
|
||||
text: s.add,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(
|
||||
@@ -175,4 +208,54 @@ class _DayWidgetState extends State<DayWidget> {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_product(int index, String product, int quantity, String portion, int dayIndex, int mealIndex) {
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
_modalBottomSheet(
|
||||
mealIndex: mealIndex,
|
||||
dayIndex: dayIndex,
|
||||
createDietCubit: context.read<CreateDietCubit>(),
|
||||
portionIndex: index,
|
||||
productNameControllerText: product,
|
||||
quantityControllerText: quantity.toString(),
|
||||
);
|
||||
},
|
||||
trailing: Icon(Icons.more_vert_rounded),
|
||||
title: Text(product),
|
||||
subtitle: Text('$quantity $portion'),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
tileColor: Color(0xFFF6FAFF),
|
||||
);
|
||||
}
|
||||
|
||||
_modalBottomSheet({
|
||||
required CreateDietCubit createDietCubit,
|
||||
required int dayIndex,
|
||||
required int mealIndex,
|
||||
int? portionIndex,
|
||||
String? productNameControllerText,
|
||||
String? quantityControllerText,
|
||||
}) {
|
||||
return showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
|
||||
),
|
||||
isScrollControlled: true,
|
||||
builder: (context) {
|
||||
return AddMealWidget(
|
||||
dayIndex: dayIndex,
|
||||
createDietCubit: createDietCubit,
|
||||
portionIndex: portionIndex,
|
||||
productNameControllerText: productNameControllerText,
|
||||
quantityControllerText: quantityControllerText,
|
||||
mealIndex: mealIndex,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user