feat: diary add update

This commit is contained in:
Alex
2024-11-30 18:33:56 +03:00
parent 06e8336cd3
commit 7e0ca28ede
6 changed files with 99 additions and 49 deletions

View File

@@ -1,3 +1,4 @@
import 'package:easy_debounce/easy_debounce.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/widgets/custom_divider.dart';
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
@@ -7,7 +8,6 @@ import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart';
import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
class AddProductModal extends StatefulWidget {
final Portion? portion;
@@ -29,6 +29,7 @@ class _AddProductModalState extends State<AddProductModal> {
final productNameController = TextEditingController();
final quantityController = TextEditingController();
GlossaryModel? selectedGlossary;
List<GlossaryModel> glossariesList = [];
@override
void initState() {
@@ -36,6 +37,11 @@ class _AddProductModalState extends State<AddProductModal> {
if (widget.portion != null) {
productNameController.text = widget.portion!.productName;
quantityController.text = '${widget.portion!.quantity}';
selectedGlossary = GlossaryModel(
id: widget.portion!.id,
name: widget.portion!.productName,
grInPortion: widget.portion!.portion == 'gr' ? 0 : 1,
);
}
}
@@ -66,47 +72,20 @@ class _AddProductModalState extends State<AddProductModal> {
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.8 - 32,
child: TypeAheadField(
child: CustomTextFormField(
controller: productNameController,
itemBuilder: (context, glossary) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
glossary.name,
style: TextStyle(
height: 1,
fontSize: 16,
),
),
autofocus: true,
hintText: 'Введите название продукта/блюда',
onChanged: (query) {
EasyDebounce.debounce(
'client-typing',
Duration(milliseconds: 250),
() async {
glossariesList = await widget.diaryCubit.getGlossaryListByQuery(query);
setState(() {});
},
);
},
itemSeparatorBuilder: (context, index) => CustomDivider(),
onSelected: (newSelectedGlossary) async {
setState(() {
selectedGlossary = newSelectedGlossary;
productNameController.text = selectedGlossary!.name;
});
},
suggestionsCallback: (query) async {
if (query.length < 1) return [];
final suggestionsList = await widget.diaryCubit.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),
@@ -129,7 +108,55 @@ class _AddProductModalState extends State<AddProductModal> {
),
],
),
const SizedBox(height: 16),
glossariesList.isEmpty ? const SizedBox(height: 16) : const SizedBox.shrink(),
Container(
constraints: BoxConstraints(
maxHeight: 256,
),
child: ListView.separated(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, i) {
return ListTile(
onTap: () async {
setState(() {
selectedGlossary = glossariesList[i];
productNameController.text = selectedGlossary!.name;
});
glossariesList = await widget.diaryCubit.getGlossaryListByQuery(glossariesList[i].name);
setState(() {});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
title: Text(
glossariesList[i].name,
style: TextStyle(
height: 1,
),
),
subtitle: glossariesList[i].grInPortion == 0
? null
: Text(
'${glossariesList[i].grInPortion} г',
style: TextStyle(
height: 1,
color: Colors.grey.shade600,
),
),
trailing: Icon(
Icons.keyboard_arrow_right_rounded,
color: Colors.grey.shade400,
),
contentPadding: EdgeInsets.only(left: 12),
);
},
itemCount: glossariesList.length,
separatorBuilder: (BuildContext context, int index) {
return CustomDivider();
},
),
),
Row(
children: [
if (widget.portion != null)
@@ -170,6 +197,7 @@ class _AddProductModalState extends State<AddProductModal> {
? 'gr'
: 'pcs',
quantity: int.parse(quantityController.text),
productNutritionalValueId: selectedGlossary?.id,
);
} else {
widget.diaryCubit.updateProductInMeal(
@@ -183,6 +211,7 @@ class _AddProductModalState extends State<AddProductModal> {
? 'gr'
: 'pcs',
quantity: int.parse(quantityController.text),
productNutritionalValueId: selectedGlossary?.id,
);
}
Navigator.of(context).pop();

View File

@@ -19,11 +19,13 @@ class ProductWidget extends StatefulWidget {
class _ProductWidgetState extends State<ProductWidget> {
late final DiaryCubit diaryCubit;
late String portionName;
@override
void initState() {
super.initState();
diaryCubit = context.read<DiaryCubit>();
portionName = widget.portion == 'gr' ? 'гр' : 'шт';
}
updateProductInMeal(DiaryStateLoaded state, Portion portion) {
@@ -51,7 +53,7 @@ class _ProductWidgetState extends State<ProductWidget> {
onTap: () => updateProductInMeal(state, widget.portion),
trailing: Icon(Icons.more_vert_rounded),
title: Text(widget.portion.productName),
subtitle: Text('${widget.portion.quantity} ${widget.portion == 'gr' ? 'гр' : 'шт'}'),
subtitle: Text('${widget.portion.quantity} ${widget.portion.portion == 'gr' ? 'гр' : 'шт'}'),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),