forked from eatvio/eatvio_app
fix(diary): some fixes offline-diary
This commit is contained in:
@@ -170,10 +170,19 @@ class _AddProductModalState extends State<AddProductModal> {
|
||||
if (widget.portion != null) const SizedBox(width: 8),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
// BUG-4 fix: валидация полей перед отправкой
|
||||
final productName = productNameController.text.trim();
|
||||
if (productName.isEmpty) return;
|
||||
|
||||
final isGrams = selectedGlossary == null || selectedGlossary!.grInPortion == 0;
|
||||
final portionType = isGrams ? 'gr' : 'pcs';
|
||||
// BUG-4 fix: безопасный парсинг количества с дефолтом
|
||||
final quantity = int.tryParse(quantityController.text) ?? (isGrams ? 100 : 1);
|
||||
|
||||
// Автоматически выбираем первый элемент, если текст точно совпадает
|
||||
if (selectedGlossary == null &&
|
||||
glossariesList.isNotEmpty &&
|
||||
productNameController.text.trim().toLowerCase() == glossariesList[0].name.toLowerCase()) {
|
||||
productName.toLowerCase() == glossariesList[0].name.toLowerCase()) {
|
||||
selectedGlossary = glossariesList[0];
|
||||
}
|
||||
|
||||
@@ -181,13 +190,9 @@ class _AddProductModalState extends State<AddProductModal> {
|
||||
widget.diaryCubit.addProductToMeal(
|
||||
diaryId: widget.state.diary.id,
|
||||
mealId: widget.state.selectedMeal,
|
||||
productName: productNameController.text,
|
||||
portion: selectedGlossary == null
|
||||
? 'gr'
|
||||
: selectedGlossary!.grInPortion == 0
|
||||
? 'gr'
|
||||
: 'pcs',
|
||||
quantity: int.parse(quantityController.text),
|
||||
productName: productName,
|
||||
portion: portionType,
|
||||
quantity: quantity,
|
||||
productNutritionalValueId: selectedGlossary?.id,
|
||||
);
|
||||
} else {
|
||||
@@ -195,26 +200,22 @@ class _AddProductModalState extends State<AddProductModal> {
|
||||
diaryId: widget.state.diary.id,
|
||||
mealId: widget.state.selectedMeal,
|
||||
portionId: widget.portion!.id,
|
||||
productName: productNameController.text,
|
||||
portion: selectedGlossary == null
|
||||
? 'gr'
|
||||
: selectedGlossary!.grInPortion == 0
|
||||
? 'gr'
|
||||
: 'pcs',
|
||||
quantity: int.parse(quantityController.text),
|
||||
productName: productName,
|
||||
portion: portionType,
|
||||
quantity: quantity,
|
||||
productNutritionalValueId: selectedGlossary?.id,
|
||||
portionState: widget.portion!.portionState,
|
||||
);
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
if (selectedGlossary == null && _previousProductName != productNameController.text) {
|
||||
if (selectedGlossary == null && _previousProductName != productName) {
|
||||
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: widget.diaryCubit),
|
||||
child: GlossaryModerationRequestModalWidget(productName: productName, diaryCubit: widget.diaryCubit),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -116,7 +116,13 @@ class _PhotoGalleryWidgetState extends State<PhotoGalleryWidget> {
|
||||
builder: (context, state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
int mealIndex = state.selectedMeal - 1;
|
||||
if (state.diary.meals[mealIndex].photos.isEmpty && !state.isConsultantView && !state.isDiaryFinished && !state.isDiaryCommented) {
|
||||
final photos = state.diary.meals[mealIndex].photos;
|
||||
// BUG-5 fix: сбросить индекс, если он вышел за пределы
|
||||
// (например, после переключения на meal с меньшим числом фото)
|
||||
if (currentSelectedPhotoIndex >= photos.length) {
|
||||
currentSelectedPhotoIndex = 0;
|
||||
}
|
||||
if (photos.isEmpty && !state.isConsultantView && !state.isDiaryFinished && !state.isDiaryCommented) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
showImagePicker(state.diary);
|
||||
|
||||
@@ -25,6 +25,7 @@ class ProductWidget extends StatefulWidget {
|
||||
class _ProductWidgetState extends State<ProductWidget> {
|
||||
late final DiaryCubit diaryCubit;
|
||||
late String portionName;
|
||||
// BUG-8 fix: инициализируем из актуального state порции
|
||||
late bool isEaten;
|
||||
bool showCommentWidget = false;
|
||||
@override
|
||||
@@ -32,7 +33,7 @@ class _ProductWidgetState extends State<ProductWidget> {
|
||||
super.initState();
|
||||
diaryCubit = context.read<DiaryCubit>();
|
||||
portionName = widget.portion.portion == 'gr' ? 'гр' : 'шт';
|
||||
isEaten = widget.portion.portionState == PortionState.eatenFromDiet ? true : false;
|
||||
isEaten = widget.portion.portionState == PortionState.eatenFromDiet;
|
||||
}
|
||||
|
||||
Widget _buildNutritionalInfo() {
|
||||
@@ -93,7 +94,8 @@ class _ProductWidgetState extends State<ProductWidget> {
|
||||
void didUpdateWidget(ProductWidget oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
portionName = widget.portion.portion == 'gr' ? 'гр' : 'шт';
|
||||
isEaten = widget.portion.portionState == PortionState.eatenFromDiet ? true : false;
|
||||
// BUG-8 fix: синхронизируем isEaten с актуальным state порции
|
||||
isEaten = widget.portion.portionState == PortionState.eatenFromDiet;
|
||||
}
|
||||
|
||||
Future updateProductInMeal(DiaryStateLoaded state, PortionModel portion) {
|
||||
|
||||
@@ -23,6 +23,12 @@ class _TimeOfMealPickerWidgetState extends State<TimeOfMealPickerWidget> {
|
||||
diaryCubit = context.read<DiaryCubit>();
|
||||
}
|
||||
|
||||
/// Безопасное форматирование времени (HH:MM:SS → HH:MM, пустое → '--:--')
|
||||
String _formatTime(String time) {
|
||||
if (time.isEmpty || time.length < 5) return '--:--';
|
||||
return time.substring(0, 5);
|
||||
}
|
||||
|
||||
void showTimePicker(int diaryId) {
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
@@ -110,7 +116,7 @@ class _TimeOfMealPickerWidgetState extends State<TimeOfMealPickerWidget> {
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
state.diary.meals[state.selectedMeal - 1].time.substring(0, state.diary.meals[state.selectedMeal - 1].time.length - 3),
|
||||
_formatTime(state.diary.meals[state.selectedMeal - 1].time),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
fontSize: 17,
|
||||
|
||||
@@ -26,6 +26,12 @@ class _WakeupAndRetireWidgetState extends State<WakeupAndRetireWidget> {
|
||||
diaryCubit = context.read<DiaryCubit>();
|
||||
}
|
||||
|
||||
/// BUG-3 fix: безопасное форматирование времени (HH:MM:SS → HH:MM, null → '--:--')
|
||||
String _formatTime(String? time) {
|
||||
if (time == null || time.length < 5) return '--:--';
|
||||
return time.substring(0, 5);
|
||||
}
|
||||
|
||||
void showTimePicker(int diaryId, bool isWakeup) {
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
@@ -142,10 +148,7 @@ class _WakeupAndRetireWidgetState extends State<WakeupAndRetireWidget> {
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
state.diary.wakeup.toString().substring(
|
||||
0,
|
||||
state.diary.wakeup.toString().length - 3,
|
||||
),
|
||||
_formatTime(state.diary.wakeup),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
fontSize: 17,
|
||||
@@ -201,10 +204,7 @@ class _WakeupAndRetireWidgetState extends State<WakeupAndRetireWidget> {
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
state.diary.retire.toString().substring(
|
||||
0,
|
||||
state.diary.retire.toString().length - 3,
|
||||
),
|
||||
_formatTime(state.diary.retire),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
fontSize: 17,
|
||||
|
||||
Reference in New Issue
Block a user