Merge pull request 'main' (#43) from main into mso7nueh-feat(chat)

Reviewed-on: maxxkim/eatvio_app#43
This commit is contained in:
2024-07-03 13:55:37 +00:00
11 changed files with 2502 additions and 553 deletions

View File

@@ -0,0 +1,116 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'diary_model.freezed.dart';
part 'diary_model.g.dart';
@freezed
class DiaryModel with _$DiaryModel {
const factory DiaryModel(
{required int id,
required DateTime date,
required DateTime wakeup,
required DateTime retire,
required int closed,
required String comment,
required List<Meals> meals}) = _DiaryModel;
factory DiaryModel.fromJson(Map<String, Object?> json) => _$DiaryModelFromJson(json);
}
class Meals {
int? id;
String? time;
int? type;
int? satiety;
int? mood;
List<Portions>? portions;
List<Photos>? photos;
Meals({this.id, this.time, this.type, this.satiety, this.mood, this.portions, this.photos});
Meals.fromJson(Map<String, dynamic> json) {
List<Portions> portions = [];
List<Photos> photos = [];
id = json['id'];
time = json['time'];
type = json['type'];
satiety = json['satiety'];
mood = json['mood'];
if (json['portions'] != null) {
json['portions'].forEach((v) {
portions.add(new Portions.fromJson(v));
});
}
if (json['photos'] != null) {
json['photos'].forEach((v) {
photos.add(new Photos.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['time'] = this.time;
data['type'] = this.type;
data['satiety'] = this.satiety;
data['mood'] = this.mood;
if (this.portions != null) {
data['portions'] = this.portions?.map((v) => v.toJson()).toList();
}
if (this.photos != null) {
data['photos'] = this.photos?.map((v) => v.toJson()).toList();
}
return data;
}
}
class Portions {
int? id;
String? productName;
int? quantity;
String? portion;
Portions({this.id, this.productName, this.quantity, this.portion});
Portions.fromJson(Map<String, dynamic> json) {
id = json['id'];
productName = json['product_name'];
quantity = json['quantity'];
portion = json['portion'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['product_name'] = this.productName;
data['quantity'] = this.quantity;
data['portion'] = this.portion;
return data;
}
}
class Photos {
int? id;
String? originalName;
String? path;
int? size;
Photos({this.id, this.originalName, this.path, this.size});
Photos.fromJson(Map<String, dynamic> json) {
id = json['id'];
originalName = json['original_name'];
path = json['path'];
size = json['size'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['original_name'] = this.originalName;
data['path'] = this.path;
data['size'] = this.size;
return data;
}
}

View File

@@ -0,0 +1,282 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'diary_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
DiaryModel _$DiaryModelFromJson(Map<String, dynamic> json) {
return _DiaryModel.fromJson(json);
}
/// @nodoc
mixin _$DiaryModel {
int get id => throw _privateConstructorUsedError;
DateTime get date => throw _privateConstructorUsedError;
DateTime get wakeup => throw _privateConstructorUsedError;
DateTime get retire => throw _privateConstructorUsedError;
int get closed => throw _privateConstructorUsedError;
String get comment => throw _privateConstructorUsedError;
List<Meals> get meals => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$DiaryModelCopyWith<DiaryModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $DiaryModelCopyWith<$Res> {
factory $DiaryModelCopyWith(
DiaryModel value, $Res Function(DiaryModel) then) =
_$DiaryModelCopyWithImpl<$Res, DiaryModel>;
@useResult
$Res call(
{int id,
DateTime date,
DateTime wakeup,
DateTime retire,
int closed,
String comment,
List<Meals> meals});
}
/// @nodoc
class _$DiaryModelCopyWithImpl<$Res, $Val extends DiaryModel>
implements $DiaryModelCopyWith<$Res> {
_$DiaryModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? date = null,
Object? wakeup = null,
Object? retire = null,
Object? closed = null,
Object? comment = null,
Object? meals = null,
}) {
return _then(_value.copyWith(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
date: null == date
? _value.date
: date // ignore: cast_nullable_to_non_nullable
as DateTime,
wakeup: null == wakeup
? _value.wakeup
: wakeup // ignore: cast_nullable_to_non_nullable
as DateTime,
retire: null == retire
? _value.retire
: retire // ignore: cast_nullable_to_non_nullable
as DateTime,
closed: null == closed
? _value.closed
: closed // ignore: cast_nullable_to_non_nullable
as int,
comment: null == comment
? _value.comment
: comment // ignore: cast_nullable_to_non_nullable
as String,
meals: null == meals
? _value.meals
: meals // ignore: cast_nullable_to_non_nullable
as List<Meals>,
) as $Val);
}
}
/// @nodoc
abstract class _$$DiaryModelImplCopyWith<$Res>
implements $DiaryModelCopyWith<$Res> {
factory _$$DiaryModelImplCopyWith(
_$DiaryModelImpl value, $Res Function(_$DiaryModelImpl) then) =
__$$DiaryModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{int id,
DateTime date,
DateTime wakeup,
DateTime retire,
int closed,
String comment,
List<Meals> meals});
}
/// @nodoc
class __$$DiaryModelImplCopyWithImpl<$Res>
extends _$DiaryModelCopyWithImpl<$Res, _$DiaryModelImpl>
implements _$$DiaryModelImplCopyWith<$Res> {
__$$DiaryModelImplCopyWithImpl(
_$DiaryModelImpl _value, $Res Function(_$DiaryModelImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? date = null,
Object? wakeup = null,
Object? retire = null,
Object? closed = null,
Object? comment = null,
Object? meals = null,
}) {
return _then(_$DiaryModelImpl(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
date: null == date
? _value.date
: date // ignore: cast_nullable_to_non_nullable
as DateTime,
wakeup: null == wakeup
? _value.wakeup
: wakeup // ignore: cast_nullable_to_non_nullable
as DateTime,
retire: null == retire
? _value.retire
: retire // ignore: cast_nullable_to_non_nullable
as DateTime,
closed: null == closed
? _value.closed
: closed // ignore: cast_nullable_to_non_nullable
as int,
comment: null == comment
? _value.comment
: comment // ignore: cast_nullable_to_non_nullable
as String,
meals: null == meals
? _value._meals
: meals // ignore: cast_nullable_to_non_nullable
as List<Meals>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$DiaryModelImpl implements _DiaryModel {
const _$DiaryModelImpl(
{required this.id,
required this.date,
required this.wakeup,
required this.retire,
required this.closed,
required this.comment,
required final List<Meals> meals})
: _meals = meals;
factory _$DiaryModelImpl.fromJson(Map<String, dynamic> json) =>
_$$DiaryModelImplFromJson(json);
@override
final int id;
@override
final DateTime date;
@override
final DateTime wakeup;
@override
final DateTime retire;
@override
final int closed;
@override
final String comment;
final List<Meals> _meals;
@override
List<Meals> get meals {
if (_meals is EqualUnmodifiableListView) return _meals;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_meals);
}
@override
String toString() {
return 'DiaryModel(id: $id, date: $date, wakeup: $wakeup, retire: $retire, closed: $closed, comment: $comment, meals: $meals)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$DiaryModelImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.date, date) || other.date == date) &&
(identical(other.wakeup, wakeup) || other.wakeup == wakeup) &&
(identical(other.retire, retire) || other.retire == retire) &&
(identical(other.closed, closed) || other.closed == closed) &&
(identical(other.comment, comment) || other.comment == comment) &&
const DeepCollectionEquality().equals(other._meals, _meals));
}
@JsonKey(ignore: true)
@override
int get hashCode => Object.hash(runtimeType, id, date, wakeup, retire, closed,
comment, const DeepCollectionEquality().hash(_meals));
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$DiaryModelImplCopyWith<_$DiaryModelImpl> get copyWith =>
__$$DiaryModelImplCopyWithImpl<_$DiaryModelImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$DiaryModelImplToJson(
this,
);
}
}
abstract class _DiaryModel implements DiaryModel {
const factory _DiaryModel(
{required final int id,
required final DateTime date,
required final DateTime wakeup,
required final DateTime retire,
required final int closed,
required final String comment,
required final List<Meals> meals}) = _$DiaryModelImpl;
factory _DiaryModel.fromJson(Map<String, dynamic> json) =
_$DiaryModelImpl.fromJson;
@override
int get id;
@override
DateTime get date;
@override
DateTime get wakeup;
@override
DateTime get retire;
@override
int get closed;
@override
String get comment;
@override
List<Meals> get meals;
@override
@JsonKey(ignore: true)
_$$DiaryModelImplCopyWith<_$DiaryModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,31 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'diary_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$DiaryModelImpl _$$DiaryModelImplFromJson(Map<String, dynamic> json) =>
_$DiaryModelImpl(
id: (json['id'] as num).toInt(),
date: DateTime.parse(json['date'] as String),
wakeup: DateTime.parse(json['wakeup'] as String),
retire: DateTime.parse(json['retire'] as String),
closed: (json['closed'] as num).toInt(),
comment: json['comment'] as String,
meals: (json['meals'] as List<dynamic>)
.map((e) => Meals.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$DiaryModelImplToJson(_$DiaryModelImpl instance) =>
<String, dynamic>{
'id': instance.id,
'date': instance.date.toIso8601String(),
'wakeup': instance.wakeup.toIso8601String(),
'retire': instance.retire.toIso8601String(),
'closed': instance.closed,
'comment': instance.comment,
'meals': instance.meals,
};

View File

@@ -0,0 +1,22 @@
/*import 'package:eatvio_app/core/app_export.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/repositories/diary_repository.dart';
class DiaryCubit extends Cubit<DiaryState> {
final DiaryRepository blogPostRepository;
DiaryCubit({required this.blogPostRepository})
: super(const DiaryState.loading());
loadDiary(String blogPostID) async {
emit(const DiaryState.loading());
try {
final blogPost = await blogPostRepository.getDiary(blogPostID);
emit(DiaryState.loaded(blogPost: blogPost));
} catch (e) {
emit(DiaryState.error(errorMessage: e.toString()));
print(e);
}
}
}
*/

View File

@@ -0,0 +1,20 @@
/*import 'package:eatvio_app/features/diary/models/diary_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'diary_state.freezed.dart';
@freezed
abstract class DiaryState with _$DiaryState {
const factory DiaryState() = _DiaryState;
const factory DiaryState.loading() = DiaryStateLoading;
const factory DiaryState.loaded({
required DiaryModel blogPost,
}) = DiaryStateLoaded;
const factory DiaryState.error({
required String errorMessage,
}) = DiaryStateError;
}
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
/*import 'package:eatvio_app/features/diary/models/diary_model.dart';
import 'package:eatvio_app/features/diary/services/diary_service.dart';
class DiaryRepository {
final DiaryService blogPostService;
DiaryRepository({required this.blogPostService});
Future<DiaryModel> getDiary(String blogPostID) async {
try {
return await blogPostService.getDiary(blogPostID);
} catch (e) {
rethrow;
}
}
}
*/

View File

@@ -0,0 +1,14 @@
/*import 'package:dio/dio.dart';
import 'package:eatvio_app/features/diary/models/diary_model.dart';
import 'package:retrofit/retrofit.dart';
part 'diary_service.g.dart';
@RestApi()
abstract class DiaryService {
factory DiaryService(Dio dio, {String baseUrl}) = _DiaryService;
@GET('/feed/show/{id}')
Future<DiaryModel> getDiary(@Path() String id);
}
*/

View File

@@ -29,15 +29,18 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
on<AddPortionEvent>(_addPortion); //пользователь нажимает "Добавить продукт"
on<RemovePortionEvent>(_removePortion);
on<RemoveImageEvent>(
_removeImage,); // пользователь нажимает на крестик около продукта
_removeImage,
); // пользователь нажимает на крестик около продукта
on<UploadImages>(_uploadImages); //пользователь нажимает "Добавить фото"
on<AddComment>(_addComment); //пользователь нажимает "Добавить комментарий"
on<ProductInput>(
_inputProduct,); //пользователь нажимает "Добавить комментарий"
_inputProduct,
); //пользователь нажимает "Добавить комментарий"
on<FinishDay>(_finishDay); //пользователь нажимает "Добавить комментарий"
on<SendModeration>(_sendModeration);
on<RefreshEvent>(
reloadScreen,); //пользователь нажимает "Добавить комментарий"
reloadScreen,
); //пользователь нажимает "Добавить комментарий"
on<ClearInput>(_clearInput);
}
@@ -57,12 +60,14 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
final diary = await fetchDiaryData(token, diaryId);
print("Screen load success");
if (diary is Map<String, dynamic>) {
print(diary);
final String diaryDate = diary['date'] ?? DateTime.now().toString();
final chartValues = await fetchChartValues(token, diaryId, emit);
if (state is DiaryEditLoadedState) {
// Если текущее состояние уже загружено, обновляем его
var currentState = state as DiaryEditLoadedState;
emit((currentState).copyWith(
emit(
(currentState).copyWith(
currentMeal: currentState.currentMeal,
wakeupExpanded: currentState.wakeupExpanded,
moodExpanded: currentState.moodExpanded,
@@ -84,20 +89,24 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
selectedMood: currentState.selectedMood,
diaryDate: currentState.diaryDate,
diaryId: currentState.diaryId,
productQuantityController:
currentState.productQuantityController,
productQuantityController: currentState.productQuantityController,
recommendedChartValues: currentState.recommendedChartValues,
consumedChartValues: currentState.consumedChartValues,
autocompleteList: currentState.autocompleteList,
diaryEditModelObj: currentState.diaryEditModelObj,),);
diaryEditModelObj: currentState.diaryEditModelObj,
),
);
} else {
// Если текущее состояние - начальное, создаем новое загруженное состояние
final List<SelectionPopupModel> meals =
fillMealList(diary['meals']);
emit(DiaryEditLoadedState(
final List<SelectionPopupModel> meals = fillMealList(diary['meals']);
emit(
DiaryEditLoadedState(
currentMeal: meals[0],
portionController: SelectionPopupModel(
id: 0, title: "порций", isSelected: true,),
id: 0,
title: "порций",
isSelected: true,
),
wakeupExpanded: true,
moodExpanded: true,
moderationExpanded: false,
@@ -109,12 +118,10 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
photos: diary['meals'][0]['photos'],
wakeupController: toTime(diary['wakeup'] ?? "09:00"),
retireController: toTime(diary['retire'] ?? "23:00"),
mealTimeController:
toTime(diary['meals'][0]['time'] ?? "10:00"),
mealTimeController: toTime(diary['meals'][0]['time'] ?? "10:00"),
selectedSatiety: diary['meals'][0]['satiety'],
selectedMood: diary['meals'][0]['mood'],
commentController:
TextEditingController(text: diary['comment']),
commentController: TextEditingController(text: diary['comment']),
productNameController: TextEditingController(),
productQuantityController: TextEditingController(),
caloriesController: TextEditingController(),
@@ -124,8 +131,9 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
diaryId: diaryId,
diaryDate: diaryDate,
autocompleteList: [],
diaryEditModelObj: state.diaryEditModelObj
?.copyWith(mealList: meals, portionList: fillPortions()),),);
diaryEditModelObj: state.diaryEditModelObj?.copyWith(mealList: meals, portionList: fillPortions()),
),
);
}
}
} catch (e) {
@@ -177,31 +185,33 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
fetchChartValues(
String token, int diaryID, Emitter<DiaryEditState> emit,) async {
String token,
int diaryID,
Emitter<DiaryEditState> emit,
) async {
final responseChart = await http.get(
Uri.parse(
dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/dailyNutritionData/',),
dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/dailyNutritionData/',
),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
);
if (responseChart.statusCode == 200) {
final recommendedChartValues =
jsonDecode(responseChart.body)['dailyNutritionRecommendation']
.values
.map<double>((value) => value as double)
.toList();
final consumedChartValues =
jsonDecode(responseChart.body)['dailyNutritionIntake']
.values
.map<double>((value) => value as double)
.toList();
final responseBody = jsonDecode(responseChart.body);
final recommendedChartValues = responseBody['dailyNutritionRecommendation'].values.map<int>((value) => convertToInt(value)).toList();
final consumedChartValues = responseBody['dailyNutritionIntake'].values.map<int>((value) => convertToInt(value)).toList();
print([recommendedChartValues, consumedChartValues]);
return [recommendedChartValues, consumedChartValues];
} else {
emit(DiaryEditErrorState('Ошибка при декодировании данных КБЖУ'));
print('fail');
return -1;
return [[], []]; // Return empty lists instead of -1
}
}
@@ -249,8 +259,9 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
if (diary is Map<String, dynamic>) {
final String diaryDate = diary['date'] ?? DateTime.now().toString();
final responseChart = await http.get(
Uri.parse(dotenv.env['SERVER_ROOT']! +
'/diary/$diaryId/dailyNutritionData/',),
Uri.parse(
dotenv.env['SERVER_ROOT']! + '/diary/$diaryId/dailyNutritionData/',
),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
@@ -258,39 +269,38 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
);
if (responseChart.statusCode == 200) {
final recommendedChartValues = jsonDecode(
responseChart.body,)['dailyNutritionRecommendation'];
final consumedChartValues =
jsonDecode(responseChart.body)['dailyNutritionIntake'];
final List<SelectionPopupModel> meals =
fillMealList(diary['meals']);
responseChart.body,
)['dailyNutritionRecommendation'];
final consumedChartValues = jsonDecode(responseChart.body)['dailyNutritionIntake'];
final List<SelectionPopupModel> meals = fillMealList(diary['meals']);
try {
await Future(() => emit(DiaryEditLoadedState(
await Future(
() => emit(
DiaryEditLoadedState(
diaryEditModelObj: state.diaryEditModelObj?.copyWith(
mealList: meals, portionList: fillPortions(),),
mealList: meals,
portionList: fillPortions(),
),
currentMeal: meals[0],
portionController: SelectionPopupModel(
id: 0, title: "порций", isSelected: true,),
id: 0,
title: "порций",
isSelected: true,
),
wakeupExpanded: true,
moodExpanded: true,
moderationExpanded: false,
token: token,
recommendedChartValues: recommendedChartValues.values
.map<double>((value) => value as double)
.toList(),
consumedChartValues: consumedChartValues.values
.map<double>((value) => value as double)
.toList(),
meals: diary['meals'],
recommendedChartValues: recommendedChartValues.values.map<int>((value) => convertToInt(value)).toList(),
consumedChartValues: consumedChartValues.values.map<int>((value) => convertToInt(value)).toList(),
portions: diary['meals'][0]['portions'],
photos: diary['meals'][0]['photos'],
wakeupController: toTime(diary['wakeup'] ?? "09:00"),
retireController: toTime(diary['retire'] ?? "23:00"),
mealTimeController:
toTime(diary['meals'][0]['time'] ?? "10:00"),
mealTimeController: toTime(diary['meals'][0]['time'] ?? "10:00"),
selectedSatiety: diary['meals'][0]['satiety'],
selectedMood: diary['meals'][0]['mood'],
commentController:
TextEditingController(text: diary['comment']),
commentController: TextEditingController(text: diary['comment']),
productNameController: TextEditingController(),
productQuantityController: TextEditingController(),
caloriesController: TextEditingController(),
@@ -301,7 +311,9 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
diaryDate: diaryDate,
isLoading: false,
autocompleteList: [],
),),);
),
),
);
print("Updated");
} catch (e) {
@@ -311,12 +323,16 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
emit(DiaryEditErrorState('Ошибка при декодировании данных КБЖУ'));
}
} else {
emit(DiaryEditErrorState(
'Ошибка при декодировании данных дневника',),);
emit(
DiaryEditErrorState(
'Ошибка при декодировании данных дневника',
),
);
}
} else {
emit(
DiaryEditErrorState('Некоторые необходимые данные отсутствуют.'),);
DiaryEditErrorState('Некоторые необходимые данные отсутствуют.'),
);
}
} else {
emit(DiaryEditErrorState('Ошибка сервера: ${response.statusCode}'));
@@ -327,18 +343,20 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
Future<void> _changeSatiety(
ChangeSatiety event, Emitter<DiaryEditState> emit,) async {
ChangeSatiety event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var updatedState =
currentState.copyWith(selectedSatiety: event.selectedElement);
var updatedState = currentState.copyWith(selectedSatiety: event.selectedElement);
// Отправляем данные по HTTP маршруту и ждем ответ
var response = await sendSatietyData(
currentState.token,
event.selectedElement,
currentState.currentMeal?.id,
currentState.diaryId,);
currentState.token,
event.selectedElement,
currentState.currentMeal?.id,
currentState.diaryId,
);
if (response.statusCode == 200) {
updatedState.selectedSatiety = event.selectedElement;
@@ -353,38 +371,42 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
int? mealID,
int diaryID,
) async {
String url = dotenv.env['SERVER_ROOT']! +
'/diary/$diaryID/meal/$mealID/satiety/fill';
String url = dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/meal/$mealID/satiety/fill';
final Map<String, dynamic> credentials = {
'satiety': selectedSatiety,
};
var response = await http.post(Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,);
var response = await http.post(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,
);
return response;
}
Future<void> _changeMood(
ChangeMood event, Emitter<DiaryEditState> emit,) async {
ChangeMood event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var updatedState =
currentState.copyWith(selectedMood: event.selectedElement);
var updatedState = currentState.copyWith(selectedMood: event.selectedElement);
// Отправляем данные по HTTP маршруту и ждем ответ
var response = await sendMoodData(
currentState.token,
event.selectedElement,
currentState.currentMeal?.id,
currentState.diaryId,);
currentState.token,
event.selectedElement,
currentState.currentMeal?.id,
currentState.diaryId,
);
if (response.statusCode == 200) {
print(
'Mood change success! meal_id: ${currentState.currentMeal?.id}, mood: ${event.selectedElement}',);
'Mood change success! meal_id: ${currentState.currentMeal?.id}, mood: ${event.selectedElement}',
);
updatedState.selectedMood = event.selectedElement;
emit(updatedState); // Передаем обновленное состояние в emit
}
@@ -397,33 +419,38 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
int? mealID,
int diaryID,
) async {
String url =
dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/meal/$mealID/mood/fill';
String url = dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/meal/$mealID/mood/fill';
final Map<String, dynamic> credentials = {
'mood': selectedMood,
};
var response = await http.post(Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,);
var response = await http.post(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,
);
return response;
}
FutureOr<void> _changeWakeup(
WakeupEvent event, Emitter<DiaryEditState> emit,) async {
WakeupEvent event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var response = await sendWakeupData(
currentState.token, event.selectedTime, currentState.diaryId,);
currentState.token,
event.selectedTime,
currentState.diaryId,
);
if (response.statusCode == 200) {
await reloadScreen(event, emit);
var updatedState =
currentState.copyWith(wakeupController: event.selectedTime);
var updatedState = currentState.copyWith(wakeupController: event.selectedTime);
print("Wakeup time changed to ${event.selectedTime}");
emit(updatedState); // Передаем обновленное состояние в emit
} else
@@ -432,15 +459,19 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
FutureOr<void> _changeRetire(
RetireEvent event, Emitter<DiaryEditState> emit,) async {
RetireEvent event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var response = await sendRetireData(
currentState.token, event.selectedTime, currentState.diaryId,);
currentState.token,
event.selectedTime,
currentState.diaryId,
);
if (response.statusCode == 200) {
await reloadScreen(event, emit);
var updatedState =
currentState.copyWith(retireController: event.selectedTime);
var updatedState = currentState.copyWith(retireController: event.selectedTime);
print("Retire time changed to ${event.selectedTime}");
emit(updatedState); // Передаем обновленное состояние в emit
} else
@@ -455,46 +486,53 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
) async {
String url = dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/wakeUp/fill';
final formatter = DateFormat('HH:mm');
final wakeupString =
formatter.format(DateTime(2022, 1, 1, wakeup.hour, wakeup.minute));
final wakeupString = formatter.format(DateTime(2022, 1, 1, wakeup.hour, wakeup.minute));
final Map<String, dynamic> credentials = {
'wakeUp': wakeupString,
};
var response = await http.post(Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,);
var response = await http.post(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,
);
return response;
}
Future<http.Response> sendRetireData(
String? token, TimeOfDay retire, int diaryID,) async {
String? token,
TimeOfDay retire,
int diaryID,
) async {
String url = dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/retire/fill';
final formatter = DateFormat('HH:mm');
final retireString =
formatter.format(DateTime(2022, 1, 1, retire.hour, retire.minute));
final retireString = formatter.format(DateTime(2022, 1, 1, retire.hour, retire.minute));
final Map<String, dynamic> credentials = {
'retire': retireString,
};
var response = await http.post(Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,);
var response = await http.post(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,
);
return response;
}
FutureOr<void> _changeMealTime(
ChangeMealTime event, Emitter<DiaryEditState> emit,) async {
ChangeMealTime event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var updatedState = currentState.copyWith(mealTimeController: event.time);
@@ -516,51 +554,58 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
'diary_id': diaryID,
};
var response = await http.post(Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,);
var response = await http.post(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,
);
return response;
}
FutureOr<void> _changeMeal(
ChangeMeal event, Emitter<DiaryEditState> emit,) async {
ChangeMeal event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
final meal = currentState.meals?.firstWhere(
(meal) => meal['id'] == event.value.id,
orElse: () => null,);
(meal) => meal['id'] == event.value.id,
orElse: () => null,
);
int? id = event.value.id;
print(meal['photos']);
DiaryEditLoadedState updatedState = currentState.copyWith(
currentMeal: event.value,
portions: meal['portions'],
photos: meal['photos'],
mealTimeController: toTime(meal['time'] ?? "1$id:00"),
selectedMood: meal['mood'],
selectedSatiety: meal['satiety'],);
currentMeal: event.value,
portions: meal['portions'],
photos: meal['photos'],
mealTimeController: toTime(meal['time'] ?? "1$id:00"),
selectedMood: meal['mood'],
selectedSatiety: meal['satiety'],
);
print(updatedState.photos);
emit(updatedState);
}
}
FutureOr<void> _clearInput(
ClearInput event, Emitter<DiaryEditState> emit,) {
ClearInput event,
Emitter<DiaryEditState> emit,
) {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
DiaryEditLoadedState updatedState = currentState.copyWith(
);
DiaryEditLoadedState updatedState = currentState.copyWith();
emit(updatedState);
}
}
FutureOr<void> _changePortion(
ChangePortion event, Emitter<DiaryEditState> emit,) {
ChangePortion event,
Emitter<DiaryEditState> emit,
) {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
DiaryEditLoadedState updatedState = currentState.copyWith(
@@ -571,7 +616,9 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
FutureOr<void> _toggleMood(
ToggleMoodExpandedEvent event, Emitter<DiaryEditState> emit,) {
ToggleMoodExpandedEvent event,
Emitter<DiaryEditState> emit,
) {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
@@ -581,7 +628,9 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
FutureOr<void> _toggleWakeup(
ToggleWakeupExpandedEvent event, Emitter<DiaryEditState> emit,) {
ToggleWakeupExpandedEvent event,
Emitter<DiaryEditState> emit,
) {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
@@ -591,7 +640,9 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
FutureOr<void> _addPortion(
AddPortionEvent event, Emitter<DiaryEditState> emit,) async {
AddPortionEvent event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
@@ -609,15 +660,21 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
await reloadScreen(event, emit);
} else {
print(
'Failed to add portion. Status Code: ${response.statusCode} ${response.body}',);
'Failed to add portion. Status Code: ${response.statusCode} ${response.body}',
);
}
}
}
FutureOr<http.Response> sendPortionData(String? token, String? name,
String portion, int? quantity, int? mealID, int diaryID,) async {
String url =
'${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealID/portions/create';
FutureOr<http.Response> sendPortionData(
String? token,
String? name,
String portion,
int? quantity,
int? mealID,
int diaryID,
) async {
String url = '${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealID/portions/create';
final Map<String, dynamic> credentials = {
'product_name': name,
@@ -639,14 +696,17 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
Future<void> _inputProduct(
ProductInput event, Emitter<DiaryEditState> emit,) async {
ProductInput event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
String? token = currentState.token;
final Map<String, dynamic> credentials = {'name': event.input};
final uri = Uri.parse(
'${dotenv.env['SERVER_ROOT']!}/diary/product_nutritional_values/filter?${Uri(queryParameters: credentials).query}',);
'${dotenv.env['SERVER_ROOT']!}/diary/product_nutritional_values/filter?${Uri(queryParameters: credentials).query}',
);
final response = await http.get(
uri,
@@ -656,16 +716,13 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
},
);
final productNutritionalValues =
jsonDecode(response.body)['product_nutritional_value'];
final productNutritionalValues = jsonDecode(response.body)['product_nutritional_value'];
if (productNutritionalValues is List<dynamic>) {
// Create a new controller with the input text and update the autocomplete list
var updatedState = currentState.copyWith(
productNameController: TextEditingController(text: event.input),
autocompleteList: productNutritionalValues
.map((product) => product['name'])
.toList(),
autocompleteList: productNutritionalValues.map((product) => product['name']).toList(),
);
if (event.input.length > 3) {
updatedState = updatedState.copyWith(moderationExpanded: true);
@@ -679,12 +736,13 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
Future<void> _removePortion(
RemovePortionEvent event, Emitter<DiaryEditState> emit,) async {
RemovePortionEvent event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
int? mealId =
currentState.currentMeal?.id; // Rename id to mealId for clarity
int? mealId = currentState.currentMeal?.id; // Rename id to mealId for clarity
var response = await sendRemovePortion(
currentState.token,
@@ -697,15 +755,19 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
await reloadScreen(event, emit);
} else {
print(
'Failed to add portion. Status Code: ${response.statusCode} ${response.body}',);
'Failed to add portion. Status Code: ${response.statusCode} ${response.body}',
);
}
}
}
Future<http.Response> sendRemovePortion(
String? token, int? portionID, int? mealID, int diaryID,) async {
String url =
'${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealID/portions/$portionID/delete';
String? token,
int? portionID,
int? mealID,
int diaryID,
) async {
String url = '${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealID/portions/$portionID/delete';
var response = await http.delete(
Uri.parse(url),
@@ -720,7 +782,9 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
FutureOr<void> _removeImage(
RemoveImageEvent event, Emitter<DiaryEditState> emit,) async {
RemoveImageEvent event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
@@ -736,15 +800,20 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
await reloadScreen(event, emit);
} else {
print(
'Failed to remove photo. Status Code: ${response.statusCode} ${response.body}',);
'Failed to remove photo. Status Code: ${response.statusCode} ${response.body}',
);
}
}
}
Future<http.Response> sendRemovePhoto(String? token, String? path,
String? photoID, int? mealID, int diaryID,) async {
String url =
'${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealID/photo/delete';
Future<http.Response> sendRemovePhoto(
String? token,
String? path,
String? photoID,
int? mealID,
int diaryID,
) async {
String url = '${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealID/photo/delete';
final Map<String, dynamic> credentials = {
'id': photoID,
'path': path,
@@ -780,13 +849,16 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
}
Future<http.Response> sendFinishDay(String? token, int diaryID,
TimeOfDay? wakeup, TimeOfDay? retire, String? comment,) async {
Future<http.Response> sendFinishDay(
String? token,
int diaryID,
TimeOfDay? wakeup,
TimeOfDay? retire,
String? comment,
) async {
final formatter = DateFormat('HH:mm');
final wakeupString =
formatter.format(DateTime(2022, 1, 1, wakeup!.hour, wakeup.minute));
final retireString =
formatter.format(DateTime(2022, 1, 1, retire!.hour, retire.minute));
final wakeupString = formatter.format(DateTime(2022, 1, 1, wakeup!.hour, wakeup.minute));
final retireString = formatter.format(DateTime(2022, 1, 1, retire!.hour, retire.minute));
final Map<String, dynamic> credentials = {
'wakeup': wakeupString,
@@ -810,21 +882,30 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
Future<void> _uploadImages(
UploadImages event, Emitter<DiaryEditState> emit,) async {
UploadImages event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
emit(currentState.copyWith(isLoading: true));
await uploadImageToServer(event.image.path, currentState.diaryId,
currentState.currentMeal!.id!, currentState.token,);
await uploadImageToServer(
event.image.path,
currentState.diaryId,
currentState.currentMeal!.id!,
currentState.token,
);
await reloadScreen(event, emit);
}
}
Future<String> uploadImageToServer(
String imagePath, int diaryID, int mealId, String? token,) async {
String url =
'${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealId/photo/upload';
String imagePath,
int diaryID,
int mealId,
String? token,
) async {
String url = '${dotenv.env['SERVER_ROOT']!}/diary/$diaryID/meal/$mealId/photo/upload';
var request = http.MultipartRequest('POST', Uri.parse(url));
request.headers['Authorization'] = 'Bearer $token';
@@ -841,12 +922,15 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
return imageUrl;
} else {
throw Exception(
'Failed to upload image. Status code: ${streamedResponse.statusCode}}',);
'Failed to upload image. Status code: ${streamedResponse.statusCode}}',
);
}
}
FutureOr<void> _sendModeration(
SendModeration event, Emitter<DiaryEditState> emit,) async {
SendModeration event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
final response = await _sendModerationData(
@@ -866,14 +950,16 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
Future<http.Response> _sendModerationData(
String name,
String energy_on_100gr,
String proteins_on_100gr,
String fats_on_100gr,
String carbohydrates_on_100gr,
String? token,) async {
String name,
String energy_on_100gr,
String proteins_on_100gr,
String fats_on_100gr,
String carbohydrates_on_100gr,
String? token,
) async {
final Uri url = Uri.parse(
'${dotenv.env['SERVER_ROOT']!}/diary/product_nutritional_values/sendToModeration',);
'${dotenv.env['SERVER_ROOT']!}/diary/product_nutritional_values/sendToModeration',
);
final Uri serverURL = Uri.parse('${dotenv.env['SERVER_ROOT']!}');
String host = serverURL.host;
final Map<String, String> credentials = {
@@ -901,12 +987,15 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
return response;
} else {
throw Exception(
'Failed to send a product for moderation ${response.statusCode}',);
'Failed to send a product for moderation ${response.statusCode}',
);
}
}
FutureOr<void> _addComment(
AddComment event, Emitter<DiaryEditState> emit,) async {
AddComment event,
Emitter<DiaryEditState> emit,
) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var updatedState = currentState.copyWith(
@@ -915,7 +1004,10 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
// Отправляем данные по HTTP маршруту и ждем ответ
var response = await sendCommentData(
currentState.token, event.comment, currentState.diaryId,);
currentState.token,
event.comment,
currentState.diaryId,
);
if (response.statusCode == 200) {
emit(updatedState); // Передаем обновленное состояние в emit
@@ -924,19 +1016,24 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
}
Future<http.Response> sendCommentData(
String? token, String comment, int diaryID,) async {
String? token,
String comment,
int diaryID,
) async {
String url = dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/retire/fill';
final Map<String, dynamic> credentials = {
'comment': comment,
};
var response = await http.post(Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,);
var response = await http.post(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8,
);
return response;
}
@@ -969,3 +1066,13 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
];
}
}
int convertToInt(dynamic value) {
if (value is int) {
return value;
} else if (value is double) {
return value.toInt();
} else {
throw FormatException('Unexpected value type: ${value.runtimeType}');
}
}

View File

@@ -12,43 +12,42 @@ class DiaryEditState extends Equatable {
}
class DiaryEditInitialState extends DiaryEditState {
DiaryEditInitialState({required DiaryEditModel diaryEditModelObj})
: super(diaryEditModelObj: diaryEditModelObj);
DiaryEditInitialState({required DiaryEditModel diaryEditModelObj}) : super(diaryEditModelObj: diaryEditModelObj);
}
/// Represents the state of DiaryEdit in the application.
class DiaryEditLoadedState extends DiaryEditState {
DiaryEditLoadedState(
{this.diaryEditModelObj,
this.diaryDate,
this.token,
this.meals,
this.portions,
this.photos,
this.autocompleteList,
this.wakeupController,
this.retireController,
this.commentController,
this.mealTimeController,
this.portionController,
this.productNameController,
this.productQuantityController,
this.selectedMood,
this.currentMeal,
this.caloriesController,
this.fatsController,
this.proteinsController,
this.carbsController,
this.isLoading = false,
this.isAdded = false,
required this.recommendedChartValues,
required this.consumedChartValues,
required this.diaryId,
required this.selectedSatiety,
required this.moderationExpanded,
required this.wakeupExpanded,
required this.moodExpanded,})
: super(diaryEditModelObj: null);
DiaryEditLoadedState({
this.diaryEditModelObj,
this.diaryDate,
this.token,
this.meals,
this.portions,
this.photos,
this.autocompleteList,
this.wakeupController,
this.retireController,
this.commentController,
this.mealTimeController,
this.portionController,
this.productNameController,
this.productQuantityController,
this.selectedMood,
this.currentMeal,
this.caloriesController,
this.fatsController,
this.proteinsController,
this.carbsController,
this.isLoading = false,
this.isAdded = false,
required this.recommendedChartValues,
required this.consumedChartValues,
required this.diaryId,
required this.selectedSatiety,
required this.moderationExpanded,
required this.wakeupExpanded,
required this.moodExpanded,
}) : super(diaryEditModelObj: null);
DiaryEditModel? diaryEditModelObj;
String? diaryDate;
@@ -57,8 +56,8 @@ class DiaryEditLoadedState extends DiaryEditState {
List<dynamic>? portions;
List<dynamic>? photos;
List<dynamic>? autocompleteList;
List<double> recommendedChartValues;
List<double> consumedChartValues;
List<int> recommendedChartValues;
List<int> consumedChartValues;
SelectionPopupModel? currentMeal;
SelectionPopupModel? portionController;
TimeOfDay? wakeupController;
@@ -117,8 +116,8 @@ class DiaryEditLoadedState extends DiaryEditState {
SelectionPopupModel? portionController,
String? diaryDate,
String? token,
List<double>? recommendedChartValues,
List<double>? consumedChartValues,
List<int>? recommendedChartValues,
List<int>? consumedChartValues,
List<dynamic>? meals,
List<dynamic>? portions,
List<dynamic>? photos,
@@ -143,38 +142,36 @@ class DiaryEditLoadedState extends DiaryEditState {
bool? isAdded,
}) {
return DiaryEditLoadedState(
diaryEditModelObj: diaryEditModelObj ?? this.diaryEditModelObj,
diaryDate: diaryDate ?? this.diaryDate,
token: token ?? this.token,
meals: meals ?? this.meals,
photos: photos ?? this.photos,
autocompleteList: autocompleteList ?? this.autocompleteList,
portions: portions ?? this.portions,
recommendedChartValues:
recommendedChartValues ?? this.recommendedChartValues,
consumedChartValues: consumedChartValues ?? this.consumedChartValues,
wakeupController: wakeupController ?? this.wakeupController,
retireController: retireController ?? this.retireController,
mealTimeController: mealTimeController ?? this.mealTimeController,
commentController: commentController ?? this.commentController,
portionController: portionController ?? this.portionController,
productNameController:
productNameController ?? this.productNameController,
productQuantityController:
productQuantityController ?? this.productQuantityController,
selectedMood: selectedMood ?? this.selectedMood,
selectedSatiety: selectedSatiety ?? this.selectedSatiety,
diaryId: diaryId ?? this.diaryId,
currentMeal: currentMeal ?? this.currentMeal,
caloriesController: caloriesController ?? this.caloriesController,
fatsController: fatsController ?? this.fatsController,
proteinsController: proteinsController ?? this.proteinsController,
carbsController: carbsController ?? this.carbsController,
wakeupExpanded: wakeupExpanded ?? this.wakeupExpanded,
moderationExpanded: moderationExpanded ?? this.moderationExpanded,
moodExpanded: moodExpanded ?? this.moodExpanded,
isAdded: isAdded ?? this.isAdded,
isLoading: isLoading ?? this.isLoading,);
diaryEditModelObj: diaryEditModelObj ?? this.diaryEditModelObj,
diaryDate: diaryDate ?? this.diaryDate,
token: token ?? this.token,
meals: meals ?? this.meals,
photos: photos ?? this.photos,
autocompleteList: autocompleteList ?? this.autocompleteList,
portions: portions ?? this.portions,
recommendedChartValues: recommendedChartValues ?? this.recommendedChartValues,
consumedChartValues: consumedChartValues ?? this.consumedChartValues,
wakeupController: wakeupController ?? this.wakeupController,
retireController: retireController ?? this.retireController,
mealTimeController: mealTimeController ?? this.mealTimeController,
commentController: commentController ?? this.commentController,
portionController: portionController ?? this.portionController,
productNameController: productNameController ?? this.productNameController,
productQuantityController: productQuantityController ?? this.productQuantityController,
selectedMood: selectedMood ?? this.selectedMood,
selectedSatiety: selectedSatiety ?? this.selectedSatiety,
diaryId: diaryId ?? this.diaryId,
currentMeal: currentMeal ?? this.currentMeal,
caloriesController: caloriesController ?? this.caloriesController,
fatsController: fatsController ?? this.fatsController,
proteinsController: proteinsController ?? this.proteinsController,
carbsController: carbsController ?? this.carbsController,
wakeupExpanded: wakeupExpanded ?? this.wakeupExpanded,
moderationExpanded: moderationExpanded ?? this.moderationExpanded,
moodExpanded: moodExpanded ?? this.moodExpanded,
isAdded: isAdded ?? this.isAdded,
isLoading: isLoading ?? this.isLoading,
);
}
}

View File

@@ -21,7 +21,9 @@ class DiaryEditScreen extends StatelessWidget {
static Widget builder(BuildContext context) {
return BlocProvider<DiaryEditBloc>(
create: (context) => DiaryEditBloc(DiaryEditState(diaryEditModelObj: DiaryEditModel()))..add(DiaryEditInitialEvent()), child: DiaryEditScreen(),);
create: (context) => DiaryEditBloc(DiaryEditState(diaryEditModelObj: DiaryEditModel()))..add(DiaryEditInitialEvent()),
child: DiaryEditScreen(),
);
}
Widget build(BuildContext context) {
@@ -264,237 +266,241 @@ class DiaryEditScreen extends StatelessWidget {
//print(_options);
FocusNode focusNodeName = FocusNode();
return Container(
margin: EdgeInsets.symmetric(horizontal: 16.h),
padding: EdgeInsets.symmetric(
horizontal: 24.h,
vertical: 12.v,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(12)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Время приема пищи",
style: CustomTextStyles.bodyMediumBlack900,
),
Expanded(
// Adding Expanded widget
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width - 260,
),
child: GestureDetector(
onTap: () => _selectMealTime(context, state),
child: AbsorbPointer(
child: CustomTextFormField(
hintText: state.mealTimeController?.format(context).toString(),
autofocus: false,
),
margin: EdgeInsets.symmetric(horizontal: 16.h),
padding: EdgeInsets.symmetric(
horizontal: 24.h,
vertical: 12.v,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(12)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Время приема пищи",
style: CustomTextStyles.bodyMediumBlack900,
),
Expanded(
// Adding Expanded widget
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width - 260,
),
child: GestureDetector(
onTap: () => _selectMealTime(context, state),
child: AbsorbPointer(
child: CustomTextFormField(
hintText: state.mealTimeController?.format(context).toString(),
autofocus: false,
),
),
),
),
),
),
],
),
),
SizedBox(height: 20.v),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: BlocSelector<DiaryEditBloc, DiaryEditState, DiaryEditModel?>(
selector: (state) => state.diaryEditModelObj,
builder: (context, diaryEditModelObj) {
return CustomDropDown(
hintText: "Прием пищи",
items: diaryEditModelObj?.mealList,
contentPadding: EdgeInsets.symmetric(
horizontal: 10.h,
vertical: 9.v,
),
defaultValue: diaryEditModelObj?.mealList[0],
onChanged: changeMeal(context, state),
);
},
),
),
SizedBox(height: 20.v),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: RawAutocomplete<String>(
optionsBuilder: buildOptions(_options),
fieldViewBuilder: (
BuildContext context,
TextEditingController productEditingController,
FocusNode focusNodeName,
VoidCallback onFieldSubmitted,
) {
if (state.isAdded) {
print("Clear");
}
return CustomTextFormField(
hintText: "Введите название продукта",
controller: productEditingController,
focusNode: focusNodeName,
onChanged: getAutocomplete(context, focusNodeName),
);
},
optionsViewBuilder: (
BuildContext context,
AutocompleteOnSelected<String> onSelected,
Iterable<String> options,
) {
return Align(
alignment: Alignment.topLeft,
child: Material(
elevation: 4.0,
child: SizedBox(
height: 200.0,
child: ListView.builder(
padding: const EdgeInsets.all(8.0),
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final String option = options.elementAt(index);
return GestureDetector(
onTap: selectProduct(onSelected, option, state),
child: ListTile(
title: Text(option),
),
);
},
),
),
),
);
},
),
),
SizedBox(height: 20.v),
if (state.moderationExpanded)
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: GestureDetector(
onTap: () => openCaloriesDialog(context, state),
child: Text("Отправить на модерацию"),
),
),
SizedBox(height: 20.v),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomTextFormField(
width: 150.h,
hintText: "Кол-во",
textInputAction: TextInputAction.done,
// focusNode: focusNodeQuantity,
controller: state.productQuantityController,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly],
),
Padding(
padding: EdgeInsets.only(left: 30.h),
child: BlocSelector<DiaryEditBloc, DiaryEditState, DiaryEditModel?>(
selector: (state) => state.diaryEditModelObj,
builder: (context, diaryEditModelObj) {
return CustomDropDown(
items: diaryEditModelObj?.portionList,
defaultValue: diaryEditModelObj?.portionList?[0],
onChanged: changePortion(context, state),
);
},
),
),
],
),
),
SizedBox(height: 20.v),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: BlocSelector<DiaryEditBloc, DiaryEditState, DiaryEditModel?>(
selector: (state) => state.diaryEditModelObj,
builder: (context, diaryEditModelObj) {
return CustomDropDown(
hintText: "Прием пищи",
items: diaryEditModelObj?.mealList,
contentPadding: EdgeInsets.symmetric(
horizontal: 10.h,
vertical: 9.v,
),
defaultValue: diaryEditModelObj?.mealList[0],
onChanged: changeMeal(context, state),
);
},),),
SizedBox(height: 20.v),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: RawAutocomplete<String>(
optionsBuilder: buildOptions(_options),
fieldViewBuilder: (
BuildContext context,
TextEditingController productEditingController,
FocusNode focusNodeName,
VoidCallback onFieldSubmitted,
) {
if (state.isAdded) {
print("Clear");
}
return CustomTextFormField(
hintText: "Введите название продукта",
controller: productEditingController,
focusNode: focusNodeName,
onChanged: getAutocomplete(context, focusNodeName),
);
},
optionsViewBuilder: (
BuildContext context,
AutocompleteOnSelected<String> onSelected,
Iterable<String> options,
) {
return Align(
alignment: Alignment.topLeft,
child: Material(
elevation: 4.0,
child: SizedBox(
height: 200.0,
child: ListView.builder(
padding: const EdgeInsets.all(8.0),
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final String option = options.elementAt(index);
return GestureDetector(
onTap: selectProduct(onSelected, option, state),
child: ListTile(
title: Text(option),
),
);
},
),
),
),
);
},),
),
SizedBox(height: 20.v),
if (state.moderationExpanded)
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: GestureDetector(
onTap: () => openCaloriesDialog(context, state),
child: Text("Отправить на модерацию"),
),
),
SizedBox(height: 20.v),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.h),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomTextFormField(
width: 150.h,
hintText: "Кол-во",
textInputAction: TextInputAction.done,
// focusNode: focusNodeQuantity,
controller: state.productQuantityController,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[digitsOnly],
),
Padding(
padding: EdgeInsets.only(left: 30.h),
child: BlocSelector<DiaryEditBloc, DiaryEditState, DiaryEditModel?>(
selector: (state) => state.diaryEditModelObj,
builder: (context, diaryEditModelObj) {
return CustomDropDown(
items: diaryEditModelObj?.portionList,
defaultValue: diaryEditModelObj?.portionList?[0],
onChanged: changePortion(context, state),
);
},
),
),
],
),
),
),
SizedBox(height: 30.v),
_buildAddProduct(context, state),
SizedBox(height: 30.v),
...state.portions!.map((portion) => _buildProduct(context, portion)).toList(),
SizedBox(height: 30.v),
/*...state.photos != null
),
SizedBox(height: 30.v),
_buildAddProduct(context, state),
SizedBox(height: 30.v),
...state.portions!.map((portion) => _buildProduct(context, portion)).toList(),
SizedBox(height: 30.v),
/*...state.photos != null
? state.photos!.isEmpty
? [Text('Фото пока нет')]
: state.photos!
.map((photo) => _buildPhoto(context, photo))
.toList()
: [Text('Фото нет')],*/
_buildCarousel(context, state),
SizedBox(height: 20.v),
_buildAddPhoto(context, state),
SizedBox(height: 30.v),
Text(
"Ваша сытость после приёма пищи",
style: CustomTextStyles.bodyMediumBlack900,
),
SizedBox(height: 15.v),
BlocBuilder<DiaryEditBloc, DiaryEditState>(
builder: (context, state) {
if (state is DiaryEditLoadedState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("😭"),
ScaleElement(
color: Colors.red,
isSelected: state.selectedSatiety == 0,
onTap: changeSatiety(context, 0),
),
ScaleElement(
color: Colors.orange,
isSelected: state.selectedSatiety == 1,
onTap: changeSatiety(context, 1),
),
ScaleElement(
color: Colors.yellow,
isSelected: state.selectedSatiety == 2,
onTap: changeSatiety(context, 2),
),
ScaleElement(
color: Colors.lime,
isSelected: state.selectedSatiety == 3,
onTap: changeSatiety(context, 3),
),
ScaleElement(
color: Colors.lightGreen,
isSelected: state.selectedSatiety == 4,
onTap: changeSatiety(context, 4),
),
ScaleElement(
color: Colors.green,
isSelected: state.selectedSatiety == 5,
onTap: changeSatiety(context, 5),
),
Text("😊"),
// Остальные элементы шкалы
],
);
} else {
return Container(); // Возвращаем пустой контейнер, если состояние не является DiaryEditLoadedState
}
},
),
],
),);
_buildCarousel(context, state),
SizedBox(height: 20.v),
_buildAddPhoto(context, state),
SizedBox(height: 30.v),
Text(
"Ваша сытость после приёма пищи",
style: CustomTextStyles.bodyMediumBlack900,
),
SizedBox(height: 15.v),
BlocBuilder<DiaryEditBloc, DiaryEditState>(
builder: (context, state) {
if (state is DiaryEditLoadedState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("😭"),
ScaleElement(
color: Colors.red,
isSelected: state.selectedSatiety == 0,
onTap: changeSatiety(context, 0),
),
ScaleElement(
color: Colors.orange,
isSelected: state.selectedSatiety == 1,
onTap: changeSatiety(context, 1),
),
ScaleElement(
color: Colors.yellow,
isSelected: state.selectedSatiety == 2,
onTap: changeSatiety(context, 2),
),
ScaleElement(
color: Colors.lime,
isSelected: state.selectedSatiety == 3,
onTap: changeSatiety(context, 3),
),
ScaleElement(
color: Colors.lightGreen,
isSelected: state.selectedSatiety == 4,
onTap: changeSatiety(context, 4),
),
ScaleElement(
color: Colors.green,
isSelected: state.selectedSatiety == 5,
onTap: changeSatiety(context, 5),
),
Text("😊"),
// Остальные элементы шкалы
],
);
} else {
return Container(); // Возвращаем пустой контейнер, если состояние не является DiaryEditLoadedState
}
},
),
],
),
);
}
openCaloriesDialog(BuildContext context, DiaryEditLoadedState state) {
@@ -542,8 +548,15 @@ class DiaryEditScreen extends StatelessWidget {
child: Text('Отмена'),
),
TextButton(
onPressed: triggerModeration(context, state.productNameController!.text, state.caloriesController!.text, state.proteinsController!.text,
state.fatsController!.text, state.carbsController!.text, dialogContext,),
onPressed: triggerModeration(
context,
state.productNameController!.text,
state.caloriesController!.text,
state.proteinsController!.text,
state.fatsController!.text,
state.carbsController!.text,
dialogContext,
),
child: Text('Отправить'),
),
],
@@ -552,12 +565,26 @@ class DiaryEditScreen extends StatelessWidget {
);
}
triggerModeration(BuildContext context, String name, String energyOn100gr, String proteinsOn100gr, String fatsOn100gr, String carbohydratesOn100gr,
BuildContext dialogContext,) {
triggerModeration(
BuildContext context,
String name,
String energyOn100gr,
String proteinsOn100gr,
String fatsOn100gr,
String carbohydratesOn100gr,
BuildContext dialogContext,
) {
return () {
// Call function to send moderation with the entered values
context.read<DiaryEditBloc>().add(SendModeration(
name: name, energyOn100gr: energyOn100gr, proteinsOn100gr: proteinsOn100gr, fatsOn100gr: fatsOn100gr, carbohydratesOn100gr: carbohydratesOn100gr,),);
context.read<DiaryEditBloc>().add(
SendModeration(
name: name,
energyOn100gr: energyOn100gr,
proteinsOn100gr: proteinsOn100gr,
fatsOn100gr: fatsOn100gr,
carbohydratesOn100gr: carbohydratesOn100gr,
),
);
Navigator.of(dialogContext).pop(); // Dismiss the dialog
};
}
@@ -640,14 +667,15 @@ class DiaryEditScreen extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.only(
left: 7.h,
top: 5.v,
),
child: Text(
portion['product_name'].length > 8 ? portion['product_name'].substring(0, 8) : portion['product_name'],
style: CustomTextStyles.titleMedium16,
),),
padding: EdgeInsets.only(
left: 7.h,
top: 5.v,
),
child: Text(
portion['product_name'].length > 8 ? portion['product_name'].substring(0, 8) : portion['product_name'],
style: CustomTextStyles.titleMedium16,
),
),
Padding(
padding: EdgeInsets.only(
left: 20.h,
@@ -660,14 +688,15 @@ class DiaryEditScreen extends StatelessWidget {
),
Spacer(),
GestureDetector(
onTap: removePortion(context, portion),
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: Icon(
Icons.close,
color: appTheme.blueGray300,
),
),),
onTap: removePortion(context, portion),
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: Icon(
Icons.close,
color: appTheme.blueGray300,
),
),
),
],
),
);
@@ -720,8 +749,8 @@ class DiaryEditScreen extends StatelessWidget {
}
_buildNutritionChart(BuildContext context, DiaryEditLoadedState state) {
final List<double> recommendedValues = state.recommendedChartValues; // Рекомендуемые значения: калории, жиры, белки, углеводы
final List<double> consumedValues = state.consumedChartValues; //
final List<int> recommendedValues = state.recommendedChartValues; // Рекомендуемые значения: калории, жиры, белки, углеводы
final List<int> consumedValues = state.consumedChartValues; //
return Container(
margin: EdgeInsets.symmetric(horizontal: 16.h),
padding: EdgeInsets.symmetric(
@@ -779,30 +808,42 @@ class DiaryEditScreen extends StatelessWidget {
),
borderData: FlBorderData(show: false),
barGroups: [
BarChartGroupData(x: 0, barRods: [
BarChartRodData(
toY: consumedValues[0] / recommendedValues[0] * 100,
color: checkConsumedValues([recommendedValues[0]], [consumedValues[1]]) ? Colors.red : Colors.blue,
),
],),
BarChartGroupData(x: 1, barRods: [
BarChartRodData(
toY: consumedValues[1] / recommendedValues[1] * 100,
color: checkConsumedValues([recommendedValues[1]], [consumedValues[1]]) ? Colors.red : Colors.blue,
),
],),
BarChartGroupData(x: 2, barRods: [
BarChartRodData(
toY: consumedValues[2] / recommendedValues[2] * 100,
color: checkConsumedValues([recommendedValues[2]], [consumedValues[2]]) ? Colors.red : Colors.blue,
),
],),
BarChartGroupData(x: 3, barRods: [
BarChartRodData(
toY: consumedValues[3] / recommendedValues[3] * 100,
color: checkConsumedValues([recommendedValues[3]], [consumedValues[3]]) ? Colors.red : Colors.blue,
),
],),
BarChartGroupData(
x: 0,
barRods: [
BarChartRodData(
toY: consumedValues[0] / recommendedValues[0] * 100,
color: checkConsumedValues([recommendedValues[0]], [consumedValues[1]]) ? Colors.red : Colors.blue,
),
],
),
BarChartGroupData(
x: 1,
barRods: [
BarChartRodData(
toY: consumedValues[1] / recommendedValues[1] * 100,
color: checkConsumedValues([recommendedValues[1]], [consumedValues[1]]) ? Colors.red : Colors.blue,
),
],
),
BarChartGroupData(
x: 2,
barRods: [
BarChartRodData(
toY: consumedValues[2] / recommendedValues[2] * 100,
color: checkConsumedValues([recommendedValues[2]], [consumedValues[2]]) ? Colors.red : Colors.blue,
),
],
),
BarChartGroupData(
x: 3,
barRods: [
BarChartRodData(
toY: consumedValues[3] / recommendedValues[3] * 100,
color: checkConsumedValues([recommendedValues[3]], [consumedValues[3]]) ? Colors.red : Colors.blue,
),
],
),
],
),
),
@@ -1077,24 +1118,25 @@ class DiaryEditScreen extends StatelessWidget {
_buildMood(BuildContext context, DiaryEditLoadedState state) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 16.h),
padding: EdgeInsets.symmetric(
horizontal: 24.h,
vertical: 12.v,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(12)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Column(children: [
margin: EdgeInsets.symmetric(horizontal: 16.h),
padding: EdgeInsets.symmetric(
horizontal: 24.h,
vertical: 12.v,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(12)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Column(
children: [
GestureDetector(
onTap: toggleMood(context),
child: Row(
@@ -1147,7 +1189,9 @@ class DiaryEditScreen extends StatelessWidget {
// Остальные элементы шкалы
],
),
],),);
],
),
);
}
changeMood(BuildContext context, int satiety) {
@@ -1196,7 +1240,7 @@ class DiaryEditScreen extends StatelessWidget {
}
}
bool checkConsumedValues(List<double> recommendedValues, List<double> consumedValues) {
bool checkConsumedValues(List<int> recommendedValues, List<int> consumedValues) {
for (int i = 0; i < recommendedValues.length; i++) {
if (consumedValues[i] > recommendedValues[i]) {
// Если хотя бы одно потребленное значение превышает рекомендованное