forked from eatvio/eatvio_app
feat(diary): wakeup, retire, mood, comment
This commit is contained in:
@@ -4,12 +4,9 @@ part 'finish_diary_day_model.freezed.dart';
|
||||
|
||||
part 'finish_diary_day_model.g.dart';
|
||||
|
||||
@freezed
|
||||
@Freezed()
|
||||
class FinishDiaryDayModel with _$FinishDiaryDayModel {
|
||||
const factory FinishDiaryDayModel({
|
||||
required String wakeUp,
|
||||
required String retire,
|
||||
}) = _FinishDiaryDayModel;
|
||||
const factory FinishDiaryDayModel({required String wakeUp, required String retire, @JsonKey(includeIfNull: false) String? comment}) = _FinishDiaryDayModel;
|
||||
|
||||
factory FinishDiaryDayModel.fromJson(Map<String, Object?> json) => _$FinishDiaryDayModelFromJson(json);
|
||||
factory FinishDiaryDayModel.fromJson(Map<String, dynamic> json) => _$FinishDiaryDayModelFromJson(json);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ FinishDiaryDayModel _$FinishDiaryDayModelFromJson(Map<String, dynamic> json) {
|
||||
mixin _$FinishDiaryDayModel {
|
||||
String get wakeUp => throw _privateConstructorUsedError;
|
||||
String get retire => throw _privateConstructorUsedError;
|
||||
@JsonKey(includeIfNull: false)
|
||||
String? get comment => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this FinishDiaryDayModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@@ -41,7 +43,11 @@ abstract class $FinishDiaryDayModelCopyWith<$Res> {
|
||||
$Res Function(FinishDiaryDayModel) then,
|
||||
) = _$FinishDiaryDayModelCopyWithImpl<$Res, FinishDiaryDayModel>;
|
||||
@useResult
|
||||
$Res call({String wakeUp, String retire});
|
||||
$Res call({
|
||||
String wakeUp,
|
||||
String retire,
|
||||
@JsonKey(includeIfNull: false) String? comment,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -58,7 +64,11 @@ class _$FinishDiaryDayModelCopyWithImpl<$Res, $Val extends FinishDiaryDayModel>
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? wakeUp = null, Object? retire = null}) {
|
||||
$Res call({
|
||||
Object? wakeUp = null,
|
||||
Object? retire = null,
|
||||
Object? comment = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
wakeUp:
|
||||
@@ -71,6 +81,11 @@ class _$FinishDiaryDayModelCopyWithImpl<$Res, $Val extends FinishDiaryDayModel>
|
||||
? _value.retire
|
||||
: retire // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
comment:
|
||||
freezed == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
@@ -86,7 +101,11 @@ abstract class _$$FinishDiaryDayModelImplCopyWith<$Res>
|
||||
) = __$$FinishDiaryDayModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String wakeUp, String retire});
|
||||
$Res call({
|
||||
String wakeUp,
|
||||
String retire,
|
||||
@JsonKey(includeIfNull: false) String? comment,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -102,7 +121,11 @@ class __$$FinishDiaryDayModelImplCopyWithImpl<$Res>
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? wakeUp = null, Object? retire = null}) {
|
||||
$Res call({
|
||||
Object? wakeUp = null,
|
||||
Object? retire = null,
|
||||
Object? comment = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$FinishDiaryDayModelImpl(
|
||||
wakeUp:
|
||||
@@ -115,6 +138,11 @@ class __$$FinishDiaryDayModelImplCopyWithImpl<$Res>
|
||||
? _value.retire
|
||||
: retire // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
comment:
|
||||
freezed == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -123,7 +151,11 @@ class __$$FinishDiaryDayModelImplCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$FinishDiaryDayModelImpl implements _FinishDiaryDayModel {
|
||||
const _$FinishDiaryDayModelImpl({required this.wakeUp, required this.retire});
|
||||
const _$FinishDiaryDayModelImpl({
|
||||
required this.wakeUp,
|
||||
required this.retire,
|
||||
@JsonKey(includeIfNull: false) this.comment,
|
||||
});
|
||||
|
||||
factory _$FinishDiaryDayModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$FinishDiaryDayModelImplFromJson(json);
|
||||
@@ -132,10 +164,13 @@ class _$FinishDiaryDayModelImpl implements _FinishDiaryDayModel {
|
||||
final String wakeUp;
|
||||
@override
|
||||
final String retire;
|
||||
@override
|
||||
@JsonKey(includeIfNull: false)
|
||||
final String? comment;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FinishDiaryDayModel(wakeUp: $wakeUp, retire: $retire)';
|
||||
return 'FinishDiaryDayModel(wakeUp: $wakeUp, retire: $retire, comment: $comment)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -144,12 +179,13 @@ class _$FinishDiaryDayModelImpl implements _FinishDiaryDayModel {
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$FinishDiaryDayModelImpl &&
|
||||
(identical(other.wakeUp, wakeUp) || other.wakeUp == wakeUp) &&
|
||||
(identical(other.retire, retire) || other.retire == retire));
|
||||
(identical(other.retire, retire) || other.retire == retire) &&
|
||||
(identical(other.comment, comment) || other.comment == comment));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, wakeUp, retire);
|
||||
int get hashCode => Object.hash(runtimeType, wakeUp, retire, comment);
|
||||
|
||||
/// Create a copy of FinishDiaryDayModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -172,6 +208,7 @@ abstract class _FinishDiaryDayModel implements FinishDiaryDayModel {
|
||||
const factory _FinishDiaryDayModel({
|
||||
required final String wakeUp,
|
||||
required final String retire,
|
||||
@JsonKey(includeIfNull: false) final String? comment,
|
||||
}) = _$FinishDiaryDayModelImpl;
|
||||
|
||||
factory _FinishDiaryDayModel.fromJson(Map<String, dynamic> json) =
|
||||
@@ -181,6 +218,9 @@ abstract class _FinishDiaryDayModel implements FinishDiaryDayModel {
|
||||
String get wakeUp;
|
||||
@override
|
||||
String get retire;
|
||||
@override
|
||||
@JsonKey(includeIfNull: false)
|
||||
String? get comment;
|
||||
|
||||
/// Create a copy of FinishDiaryDayModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@@ -11,8 +11,13 @@ _$FinishDiaryDayModelImpl _$$FinishDiaryDayModelImplFromJson(
|
||||
) => _$FinishDiaryDayModelImpl(
|
||||
wakeUp: json['wakeUp'] as String,
|
||||
retire: json['retire'] as String,
|
||||
comment: json['comment'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$FinishDiaryDayModelImplToJson(
|
||||
_$FinishDiaryDayModelImpl instance,
|
||||
) => <String, dynamic>{'wakeUp': instance.wakeUp, 'retire': instance.retire};
|
||||
) => <String, dynamic>{
|
||||
'wakeUp': instance.wakeUp,
|
||||
'retire': instance.retire,
|
||||
if (instance.comment case final value?) 'comment': value,
|
||||
};
|
||||
|
||||
@@ -17,10 +17,7 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
final DiaryRepository diaryRepository;
|
||||
final GlossaryRepository glossaryRepository;
|
||||
|
||||
DiaryCubit({
|
||||
required this.diaryRepository,
|
||||
required this.glossaryRepository,
|
||||
}) : super(const DiaryState.loading()) {
|
||||
DiaryCubit({required this.diaryRepository, required this.glossaryRepository}) : super(const DiaryState.loading()) {
|
||||
today = DateTime.now();
|
||||
selectedDay = today;
|
||||
}
|
||||
@@ -56,16 +53,8 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
}
|
||||
}
|
||||
|
||||
finishDiaryDay({
|
||||
required int diaryId,
|
||||
required String wakeUp,
|
||||
required String retire,
|
||||
}) async {
|
||||
await diaryRepository.finishDiaryDay(
|
||||
diaryId: diaryId,
|
||||
wakeUp: wakeUp,
|
||||
retire: retire,
|
||||
);
|
||||
finishDiaryDay({required int diaryId, required String wakeUp, required String retire, String? comment}) async {
|
||||
await diaryRepository.finishDiaryDay(diaryId: diaryId, wakeUp: wakeUp, retire: retire, comment: comment);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
@@ -126,55 +115,23 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
markEaten({
|
||||
required int diaryId,
|
||||
required int mealId,
|
||||
required int portionId,
|
||||
}) async {
|
||||
await diaryRepository.markEaten(
|
||||
diaryId: diaryId,
|
||||
mealId: mealId,
|
||||
portionId: portionId,
|
||||
);
|
||||
markEaten({required int diaryId, required int mealId, required int portionId}) async {
|
||||
await diaryRepository.markEaten(diaryId: diaryId, mealId: mealId, portionId: portionId);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
unmarkEaten({
|
||||
required int diaryId,
|
||||
required int mealId,
|
||||
required int portionId,
|
||||
}) async {
|
||||
await diaryRepository.unmarkEaten(
|
||||
diaryId: diaryId,
|
||||
mealId: mealId,
|
||||
portionId: portionId,
|
||||
);
|
||||
unmarkEaten({required int diaryId, required int mealId, required int portionId}) async {
|
||||
await diaryRepository.unmarkEaten(diaryId: diaryId, mealId: mealId, portionId: portionId);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
restore({
|
||||
required int diaryId,
|
||||
required int mealId,
|
||||
required int portionId,
|
||||
}) async {
|
||||
await diaryRepository.restore(
|
||||
diaryId: diaryId,
|
||||
mealId: mealId,
|
||||
portionId: portionId,
|
||||
);
|
||||
restore({required int diaryId, required int mealId, required int portionId}) async {
|
||||
await diaryRepository.restore(diaryId: diaryId, mealId: mealId, portionId: portionId);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
deleteProductFromMeal({
|
||||
required int diaryId,
|
||||
required int mealId,
|
||||
required int portionId,
|
||||
}) async {
|
||||
await diaryRepository.deleteProductFromMeal(
|
||||
diaryId: diaryId,
|
||||
mealId: mealId,
|
||||
portionId: portionId,
|
||||
);
|
||||
deleteProductFromMeal({required int diaryId, required int mealId, required int portionId}) async {
|
||||
await diaryRepository.deleteProductFromMeal(diaryId: diaryId, mealId: mealId, portionId: portionId);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
@@ -182,27 +139,13 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
return await glossaryRepository.getGlossaryListByQuery(query);
|
||||
}
|
||||
|
||||
uploadPhotos({
|
||||
required List<File> files,
|
||||
required int diaryId,
|
||||
}) async {
|
||||
await diaryRepository.uploadPhotos(
|
||||
files: await ImageCompressUtility.compressFilesList(files),
|
||||
diaryId: diaryId,
|
||||
mealId: selectedMeal,
|
||||
);
|
||||
uploadPhotos({required List<File> files, required int diaryId}) async {
|
||||
await diaryRepository.uploadPhotos(files: await ImageCompressUtility.compressFilesList(files), diaryId: diaryId, mealId: selectedMeal);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
deletePhoto({
|
||||
required DiaryPhotoModel photo,
|
||||
required int diaryId,
|
||||
}) async {
|
||||
await diaryRepository.deletePhoto(
|
||||
photo: photo,
|
||||
diaryId: diaryId,
|
||||
mealId: selectedMeal,
|
||||
);
|
||||
deletePhoto({required DiaryPhotoModel photo, required int diaryId}) async {
|
||||
await diaryRepository.deletePhoto(photo: photo, diaryId: diaryId, mealId: selectedMeal);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
@@ -214,39 +157,37 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
required double carbohydrates,
|
||||
}) async {
|
||||
try {
|
||||
return await diaryRepository.sendProductToModeration(
|
||||
name: name,
|
||||
energy: energy,
|
||||
proteins: proteins,
|
||||
fats: fats,
|
||||
carbohydrates: carbohydrates,
|
||||
);
|
||||
return await diaryRepository.sendProductToModeration(name: name, energy: energy, proteins: proteins, fats: fats, carbohydrates: carbohydrates);
|
||||
} catch (e, stackTrace) {
|
||||
log(e.toString(), stackTrace: stackTrace);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fillTime({
|
||||
required int diaryId,
|
||||
required String time,
|
||||
}) async {
|
||||
await diaryRepository.fillTime(
|
||||
diaryId: diaryId,
|
||||
mealId: selectedMeal,
|
||||
time: time,
|
||||
);
|
||||
fillTime({required int diaryId, required String time}) async {
|
||||
await diaryRepository.fillTime(diaryId: diaryId, mealId: selectedMeal, time: time);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
fillSatiety({
|
||||
required int diaryId,
|
||||
required int satiety,
|
||||
}) async {
|
||||
await diaryRepository.fillSatiety(
|
||||
diaryId: diaryId,
|
||||
mealId: selectedMeal,
|
||||
satiety: satiety,
|
||||
);
|
||||
fillWakeup({required int diaryId, required String time}) async {
|
||||
await diaryRepository.fillWakeup(diaryId: diaryId, time: time);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
fillRetire({required int diaryId, required String time}) async {
|
||||
await diaryRepository.fillRetire(diaryId: diaryId, time: time);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
fillSatiety({required int diaryId, required int satiety}) async {
|
||||
await diaryRepository.fillSatiety(diaryId: diaryId, mealId: selectedMeal, satiety: satiety);
|
||||
}
|
||||
|
||||
fillMood({required int diaryId, required int mood}) async {
|
||||
await diaryRepository.fillMood(diaryId: diaryId, mealId: selectedMeal, mood: mood);
|
||||
}
|
||||
|
||||
fillComment(String comment) {
|
||||
emit((state as DiaryStateLoaded).copyWith(diary: (state as DiaryStateLoaded).diary.copyWith(comment: comment)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@ import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/calendar_widget.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/calories_chart_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/comment_for_consultant_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/finish_day_button_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/meal_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/wakeup_and_retire_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
@@ -46,8 +48,12 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
children: [
|
||||
CalendarWidget(),
|
||||
if (state is DiaryStateLoading) const Loader(),
|
||||
if (state is DiaryStateLoaded) WakeupAndRetireWidget(),
|
||||
const SizedBox(height: 12),
|
||||
if (state is DiaryStateLoaded) MealWidget(),
|
||||
CaloriesChartWidget(),
|
||||
if (state is DiaryStateLoaded) CaloriesChartWidget(),
|
||||
const SizedBox(height: 12),
|
||||
if (state is DiaryStateLoaded) CommentForConsultantWidget(),
|
||||
if (state is DiaryStateLoaded && state.diary.closed == 0)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class CommentForConsultantWidget extends StatefulWidget {
|
||||
const CommentForConsultantWidget({super.key});
|
||||
|
||||
@override
|
||||
State<CommentForConsultantWidget> createState() => _CommentForConsultantWidgetState();
|
||||
}
|
||||
|
||||
class _CommentForConsultantWidgetState extends State<CommentForConsultantWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Дополнительная информация для консультанта',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF323F4B), height: 1),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
CustomTextFormField(
|
||||
onChanged: (value) {
|
||||
EasyDebounce.debounce('client-typing', Duration(seconds: 3), () => context.read<DiaryCubit>().fillComment(value));
|
||||
},
|
||||
hintText: 'Укажите дополнительную информацию',
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
class FinishDayButtonWidget extends StatefulWidget {
|
||||
final DiaryDayModel diaryDay;
|
||||
|
||||
const FinishDayButtonWidget({
|
||||
super.key,
|
||||
required this.diaryDay,
|
||||
});
|
||||
const FinishDayButtonWidget({super.key, required this.diaryDay});
|
||||
|
||||
@override
|
||||
State<FinishDayButtonWidget> createState() => _FinishDayButtonWidgetState();
|
||||
@@ -20,30 +17,22 @@ class _FinishDayButtonWidgetState extends State<FinishDayButtonWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () => context.read<DiaryCubit>().finishDiaryDay(
|
||||
onTap:
|
||||
() => context.read<DiaryCubit>().finishDiaryDay(
|
||||
diaryId: widget.diaryDay.id,
|
||||
wakeUp: widget.diaryDay.wakeup.toString(),
|
||||
retire: widget.diaryDay.retire.toString(),
|
||||
comment: widget.diaryDay.comment.isEmpty ? null : widget.diaryDay.comment,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
decoration: BoxDecoration(color: appTheme.blueA400, borderRadius: BorderRadius.circular(20)),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Закончить день',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
child: Text('Закончить день', style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.w600)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/add_product_button_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/meal_button_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/mood_rating_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/photo_gallery_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/products_list_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/satiety_rating_widget.dart';
|
||||
@@ -53,6 +54,8 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
PhotoGalleryWidget(),
|
||||
const SizedBox(height: 12),
|
||||
SatietyRatingWidget(),
|
||||
const SizedBox(height: 12),
|
||||
MoodRatingWidget(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
199
lib/features/diary/presentation/widgets/mood_rating_widget.dart
Normal file
199
lib/features/diary/presentation/widgets/mood_rating_widget.dart
Normal file
@@ -0,0 +1,199 @@
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class MoodRatingWidget extends StatefulWidget {
|
||||
@override
|
||||
State<MoodRatingWidget> createState() => _MoodRatingWidgetState();
|
||||
}
|
||||
|
||||
class _MoodRatingWidgetState extends State<MoodRatingWidget> {
|
||||
late double currentSelectedRating;
|
||||
bool isFirstFetch = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DiaryCubit, DiaryState>(
|
||||
builder: (BuildContext context, DiaryState state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
if (isFirstFetch) {
|
||||
currentSelectedRating = state.diary.meals[state.selectedMeal - 1].mood.toDouble() + 1;
|
||||
isFirstFetch = false;
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Ваше настроение после приёма пищи',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
'assets/icons/mood_1.svg',
|
||||
height: 32,
|
||||
width: 32,
|
||||
),
|
||||
RatingBar.builder(
|
||||
initialRating: state.diary.meals[state.selectedMeal - 1].mood.toDouble() + 1,
|
||||
itemCount: 6,
|
||||
itemSize: MediaQuery.of(context).size.width / 6 - (124 / 6),
|
||||
updateOnDrag: true,
|
||||
itemBuilder: (context, index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 1 ? EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFC82222),
|
||||
border: currentSelectedRating == 1
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: Color(0xFFAA3333),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 1
|
||||
? BorderRadius.horizontal(
|
||||
left: Radius.circular(8),
|
||||
right: Radius.circular(2),
|
||||
)
|
||||
: BorderRadius.horizontal(
|
||||
left: Radius.circular(8),
|
||||
),
|
||||
),
|
||||
);
|
||||
case 1:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 2 ? EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFFF3E3E),
|
||||
border: currentSelectedRating == 2
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: Color(0xFF550000),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 2 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
case 2:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 3 ? EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFF8C926),
|
||||
border: currentSelectedRating == 3
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: Color(0xFF8C5D00),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 3 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
case 3:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 4 ? EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFFFF3BF),
|
||||
border: currentSelectedRating == 4
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: Color(0xFFB5911B),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 4 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
case 4:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 5 ? EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFF62E833),
|
||||
border: currentSelectedRating == 5
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: Color(0xFF276918),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 5 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
default:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 6 ? EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFF4DCE20),
|
||||
border: currentSelectedRating == 6
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: Color(0xFF184D12),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 6
|
||||
? BorderRadius.horizontal(
|
||||
left: Radius.circular(2),
|
||||
right: Radius.circular(8),
|
||||
)
|
||||
: BorderRadius.horizontal(
|
||||
right: Radius.circular(8),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
onRatingUpdate: (value) {
|
||||
setState(() {
|
||||
currentSelectedRating = value;
|
||||
});
|
||||
EasyDebounce.debounce(
|
||||
'change-satiety',
|
||||
Duration(milliseconds: 250),
|
||||
() {
|
||||
context.read<DiaryCubit>().fillMood(diaryId: state.diary.id, mood: currentSelectedRating.toInt() - 1);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
SvgPicture.asset(
|
||||
'assets/icons/mood_2.svg',
|
||||
height: 32,
|
||||
width: 32,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class _SatietyRatingWidgetState extends State<SatietyRatingWidget> {
|
||||
builder: (BuildContext context, DiaryState state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
if (isFirstFetch) {
|
||||
currentSelectedRating = state.diary.meals[state.selectedMeal - 1].satiety.toDouble();
|
||||
currentSelectedRating = state.diary.meals[state.selectedMeal - 1].satiety.toDouble() + 1;
|
||||
isFirstFetch = false;
|
||||
}
|
||||
return Padding(
|
||||
@@ -44,7 +44,7 @@ class _SatietyRatingWidgetState extends State<SatietyRatingWidget> {
|
||||
width: 32,
|
||||
),
|
||||
RatingBar.builder(
|
||||
initialRating: state.diary.meals[state.selectedMeal - 1].satiety.toDouble(),
|
||||
initialRating: state.diary.meals[state.selectedMeal - 1].satiety.toDouble() + 1,
|
||||
itemCount: 6,
|
||||
itemSize: MediaQuery.of(context).size.width / 6 - (124 / 6),
|
||||
updateOnDrag: true,
|
||||
@@ -176,7 +176,7 @@ class _SatietyRatingWidgetState extends State<SatietyRatingWidget> {
|
||||
'change-satiety',
|
||||
Duration(milliseconds: 250),
|
||||
() {
|
||||
context.read<DiaryCubit>().fillSatiety(diaryId: state.diary.id, satiety: currentSelectedRating.toInt());
|
||||
context.read<DiaryCubit>().fillSatiety(diaryId: state.diary.id, satiety: currentSelectedRating.toInt() - 1);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
import '../../../../core/theme/theme_helper.dart';
|
||||
|
||||
class WakeupAndRetireWidget extends StatefulWidget {
|
||||
const WakeupAndRetireWidget({super.key});
|
||||
|
||||
@override
|
||||
State<WakeupAndRetireWidget> createState() => _WakeupAndRetireWidgetState();
|
||||
}
|
||||
|
||||
class _WakeupAndRetireWidgetState extends State<WakeupAndRetireWidget> {
|
||||
late final DiaryCubit diaryCubit;
|
||||
DateTime wakeup = DateTime.now().copyWith(hour: 6, minute: 30);
|
||||
DateTime retire = DateTime.now().copyWith(hour: 22, minute: 30);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
diaryCubit = context.read<DiaryCubit>();
|
||||
}
|
||||
|
||||
showTimePicker(int diaryId, bool isWakeup) {
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
builder:
|
||||
(context) => SizedBox(
|
||||
height: MediaQuery.of(context).copyWith().size.height / 3,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CupertinoDatePicker(
|
||||
mode: CupertinoDatePickerMode.time,
|
||||
use24hFormat: true,
|
||||
initialDateTime: DateTime.now(),
|
||||
onDateTimeChanged: (newTime) {
|
||||
if (isWakeup) {
|
||||
wakeup = newTime;
|
||||
} else {
|
||||
retire = newTime;
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
if (isWakeup) {
|
||||
diaryCubit.fillWakeup(
|
||||
diaryId: diaryId,
|
||||
time:
|
||||
'${wakeup.hour.toString().padLeft(2, '0')}:${wakeup.minute.toString().padLeft(2, '0')}:00',
|
||||
);
|
||||
} else {
|
||||
diaryCubit.fillRetire(
|
||||
diaryId: diaryId,
|
||||
time:
|
||||
'${retire.hour.toString().padLeft(2, '0')}:${retire.minute.toString().padLeft(2, '0')}:00',
|
||||
);
|
||||
}
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
height: 52,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Сохранить',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DiaryCubit, DiaryState>(
|
||||
builder: (context, state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Material(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 12,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset('assets/icons/wakeup.svg'),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Подъём',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
InkWell(
|
||||
onTap: () => showTimePicker(state.diary.id, true),
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: Ink(
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
color: Color(0xFFF1F2F6),
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
state.diary.wakeup.toString().substring(
|
||||
0,
|
||||
state.diary.wakeup.toString().length - 3,
|
||||
),
|
||||
style: TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Material(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 12,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset('assets/icons/retire.svg'),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Уход ко сну',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
InkWell(
|
||||
onTap: () => showTimePicker(state.diary.id, false),
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: Ink(
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
color: Color(0xFFF1F2F6),
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
state.diary.retire.toString().substring(
|
||||
0,
|
||||
state.diary.retire.toString().length - 3,
|
||||
),
|
||||
style: TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return SizedBox.shrink();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -158,12 +158,14 @@ class DiaryRepository {
|
||||
required int diaryId,
|
||||
required String wakeUp,
|
||||
required String retire,
|
||||
String? comment,
|
||||
}) async {
|
||||
return await diaryService.finishDiaryDay(
|
||||
diary: diaryId,
|
||||
finishDiaryDayModel: FinishDiaryDayModel(
|
||||
wakeUp: wakeUp,
|
||||
retire: retire,
|
||||
comment: comment
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -202,6 +204,22 @@ class DiaryRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fillMood({
|
||||
required int diaryId,
|
||||
required int mealId,
|
||||
required int mood,
|
||||
}) async {
|
||||
try {
|
||||
return await diaryService.fillMood(
|
||||
diary: diaryId,
|
||||
typeNo: mealId,
|
||||
mood: mood,
|
||||
);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fillTime({
|
||||
required int diaryId,
|
||||
required int mealId,
|
||||
@@ -217,4 +235,32 @@ class DiaryRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fillWakeup({
|
||||
required int diaryId,
|
||||
required String time,
|
||||
}) async {
|
||||
try {
|
||||
return await diaryService.fillWakeup(
|
||||
diary: diaryId,
|
||||
wakeUp: time,
|
||||
);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fillRetire({
|
||||
required int diaryId,
|
||||
required String time,
|
||||
}) async {
|
||||
try {
|
||||
return await diaryService.fillRetire(
|
||||
diary: diaryId,
|
||||
retire: time,
|
||||
);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ abstract class DiaryService {
|
||||
@POST('/api/diary/{diary}/finishDay')
|
||||
Future<void> finishDiaryDay({
|
||||
@Path('diary') required int diary,
|
||||
@Body() required FinishDiaryDayModel finishDiaryDayModel,
|
||||
@Body(nullToAbsent: true) required FinishDiaryDayModel finishDiaryDayModel,
|
||||
});
|
||||
|
||||
@POST('/api/diary/{diary}/meals/{type_no}/satiety/fill')
|
||||
@@ -101,6 +101,13 @@ abstract class DiaryService {
|
||||
@Field() required int satiety,
|
||||
});
|
||||
|
||||
@POST('/api/diary/{diary}/meals/{type_no}/mood/fill')
|
||||
Future<void> fillMood({
|
||||
@Path('diary') required int diary,
|
||||
@Path('type_no') required int typeNo,
|
||||
@Field() required int mood,
|
||||
});
|
||||
|
||||
@POST('/api/diary/{diary}/meals/{type_no}/time/fill')
|
||||
Future<void> fillTime({
|
||||
@Path('diary') required int diary,
|
||||
@@ -108,6 +115,18 @@ abstract class DiaryService {
|
||||
@Field() required String time,
|
||||
});
|
||||
|
||||
@POST('/api/diary/{diary}/wakeUp/fill')
|
||||
Future<void> fillWakeup({
|
||||
@Path('diary') required int diary,
|
||||
@Field() required String wakeUp,
|
||||
});
|
||||
|
||||
@POST('/api/diary/{diary}/retire/fill')
|
||||
Future<void> fillRetire({
|
||||
@Path('diary') required int diary,
|
||||
@Field() required String retire,
|
||||
});
|
||||
|
||||
@POST('/api/diary/product_nutritional_values/sendToModeration')
|
||||
Future<GlossaryModerationModel> sendProductToModeration({
|
||||
@Body() required Map<String, dynamic> data,
|
||||
|
||||
@@ -366,6 +366,29 @@ class _DiaryService implements DiaryService {
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> fillMood({
|
||||
required int diary,
|
||||
required int typeNo,
|
||||
required int mood,
|
||||
}) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = {'mood': mood};
|
||||
final _options = _setStreamType<void>(
|
||||
Options(method: 'POST', headers: _headers, extra: _extra)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/diary/${diary}/meals/${typeNo}/mood/fill',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
|
||||
);
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> fillTime({
|
||||
required int diary,
|
||||
@@ -389,6 +412,44 @@ class _DiaryService implements DiaryService {
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> fillWakeup({required int diary, required String wakeUp}) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = {'wakeUp': wakeUp};
|
||||
final _options = _setStreamType<void>(
|
||||
Options(method: 'POST', headers: _headers, extra: _extra)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/diary/${diary}/wakeUp/fill',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
|
||||
);
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> fillRetire({required int diary, required String retire}) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = {'retire': retire};
|
||||
final _options = _setStreamType<void>(
|
||||
Options(method: 'POST', headers: _headers, extra: _extra)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/diary/${diary}/retire/fill',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
|
||||
);
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GlossaryModerationModel> sendProductToModeration({
|
||||
required Map<String, dynamic> data,
|
||||
|
||||
Reference in New Issue
Block a user