forked from eatvio/eatvio_app
Merge pull request 'new test cases' (#218) from misha/eatvio_app:main into main
Reviewed-on: eatvio/eatvio_app#218
This commit is contained in:
@@ -154,7 +154,17 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
if ((index + 1 != state.chatMessages.length &&
|
||||
DateTime.parse(state.chatMessages[index].updatedAt).day != DateTime.parse(state.chatMessages[index + 1].updatedAt).day) ||
|
||||
index + 1 == state.chatMessages.length) {
|
||||
return _messageDate(state.chatMessages[index].updatedAt);
|
||||
return Column(
|
||||
children: [
|
||||
_messageDate(state.chatMessages[index].updatedAt),
|
||||
ChatBubbleWidget(
|
||||
sendTime: state.chatMessages[index].updatedAt,
|
||||
text: state.chatMessages[index].data.trim(),
|
||||
isCurrentUser: state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId,
|
||||
mediaData: state.chatMessages[index].mediaData ?? [],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return ChatBubbleWidget(
|
||||
sendTime: state.chatMessages[index].updatedAt,
|
||||
|
||||
@@ -25,7 +25,7 @@ class DevToolsScreenContent extends StatefulWidget {
|
||||
|
||||
class _DevToolsScreenContentState extends State<DevToolsScreenContent> {
|
||||
String baseUrlForTest = '';
|
||||
final List<TestCases> testCases = [Test850task()];
|
||||
final List<TestCases> testCases = [Test850task(), GetChatRoomPreviews(), GetChatRoom(), SendMessage(), GetChatMessages(), GetChatRoomIdByUserSlug()];
|
||||
final controller = TextEditingController();
|
||||
late final List<TestState> testsStates;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'dart:developer';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/features/chat/services/chat_service.dart';
|
||||
import 'package:eatvio_app/features/diets/services/diet_service.dart';
|
||||
import 'package:eatvio_app/features/feed/services/feed_service.dart';
|
||||
import 'package:eatvio_app/features/profile/services/profile_service.dart';
|
||||
@@ -113,3 +114,106 @@ class Test850task implements TestCases {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetChatRoomPreviews implements TestCases {
|
||||
@override
|
||||
String get name => '/api/chat/index';
|
||||
|
||||
@override
|
||||
Future<bool> run({required String baseUrl}) async {
|
||||
try {
|
||||
// get all of needed services
|
||||
final dio = sl<Dio>();
|
||||
final chatService = ChatService(dio, baseUrl: baseUrl);
|
||||
|
||||
await chatService.getChatRoomPreviews();
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetChatRoom implements TestCases {
|
||||
@override
|
||||
String get name => '/api/chat/show/{id}';
|
||||
|
||||
@override
|
||||
Future<bool> run({required String baseUrl}) async {
|
||||
try {
|
||||
final dio = sl<Dio>();
|
||||
final chatService = ChatService(dio, baseUrl: baseUrl);
|
||||
|
||||
final chatRoomsModels = await chatService.getChatRoomPreviews();
|
||||
await chatService.getChatRoom(id: chatRoomsModels.chatRooms.firstOrNull?.id ?? '');
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SendMessage implements TestCases {
|
||||
@override
|
||||
String get name => '/api/chat/{id}/message/send';
|
||||
|
||||
@override
|
||||
Future<bool> run({required String baseUrl}) async {
|
||||
try {
|
||||
final dio = sl<Dio>();
|
||||
final chatService = ChatService(dio, baseUrl: baseUrl);
|
||||
|
||||
final chatRoomsModels = await chatService.getChatRoomPreviews();
|
||||
await chatService.sendMessage(id: chatRoomsModels.chatRooms.firstOrNull?.id ?? '', data: 'test message');
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetChatMessages implements TestCases {
|
||||
@override
|
||||
String get name => '/api/chat/show/{id}/messages?page={page}';
|
||||
|
||||
@override
|
||||
Future<bool> run({required String baseUrl}) async {
|
||||
try {
|
||||
final dio = sl<Dio>();
|
||||
final chatService = ChatService(dio, baseUrl: baseUrl);
|
||||
|
||||
final chatRoomsModels = await chatService.getChatRoomPreviews();
|
||||
await chatService.getChatMessages(id: chatRoomsModels.chatRooms.firstOrNull?.id ?? '', page: 1);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetChatRoomIdByUserSlug implements TestCases {
|
||||
@override
|
||||
String get name => '/api/chat/get_by_user/{user}';
|
||||
|
||||
@override
|
||||
Future<bool> run({required String baseUrl}) async {
|
||||
try {
|
||||
final dio = sl<Dio>();
|
||||
final chatService = ChatService(dio, baseUrl: baseUrl);
|
||||
final consultantService = FeedService(dio, baseUrl: baseUrl);
|
||||
final profileService = ProfileService(dio, baseUrl: baseUrl);
|
||||
final myProfile = await profileService.getMyProfile();
|
||||
final consultantsModel = await consultantService.getConsultants();
|
||||
|
||||
for (var consultant in consultantsModel.data) {
|
||||
if (consultant.slug != myProfile.slug) {
|
||||
await chatService.getChatRoomIdByUserSlug(user: consultant.slug);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_state.dart';
|
||||
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class AboutDietCubit extends Cubit<AboutDietState> {
|
||||
AboutDietCubit({required this.dietsRepository}) : super(AboutDietState.initial());
|
||||
AboutDietCubit({required this.dietsRepository, required this.profileRepository}) : super(AboutDietState.initial());
|
||||
final DietRepository dietsRepository;
|
||||
final ProfileRepository profileRepository;
|
||||
bool isCurrentDietStarted = false;
|
||||
bool hasStartedDiet = false;
|
||||
String? userStartedDietName;
|
||||
|
||||
Future<void> getDiet(int id, {int? index}) async {
|
||||
try {
|
||||
@@ -16,17 +23,30 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
||||
if (index != null) {
|
||||
dietsRepository.emitCommentsStateToFeed(CommentsState(index: index, totalComments: diet.totalComments));
|
||||
}
|
||||
emit(AboutDietState.loaded(diet));
|
||||
emit(AboutDietState.loaded(diet: diet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getDietWithLoading(int id) async {
|
||||
Future<void> initDietPage(int id) async {
|
||||
try {
|
||||
emit(AboutDietState.loading());
|
||||
final diet = await dietsRepository.getDiet(id);
|
||||
emit(AboutDietState.loaded(diet));
|
||||
final chosenDiets = await profileRepository.getChosenDiets();
|
||||
final lastChosenDiet = chosenDiets.firstOrNull;
|
||||
if (lastChosenDiet != null && ['inited', 'started'].contains(lastChosenDiet.state)) {
|
||||
hasStartedDiet = true;
|
||||
if (diet.id == lastChosenDiet.dietId) {
|
||||
isCurrentDietStarted = true;
|
||||
} else {
|
||||
if (lastChosenDiet.dietId != null) {
|
||||
final chosenDiet = await dietsRepository.getDiet(lastChosenDiet.dietId!);
|
||||
userStartedDietName = chosenDiet.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
emit(AboutDietState.loaded(diet: diet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
@@ -45,7 +65,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
||||
if (dietIndexInFeed != null) {
|
||||
dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed));
|
||||
}
|
||||
emit(AboutDietState.loaded(updatedDiet));
|
||||
emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||
} else {
|
||||
final updatedDiet = currentDiet.copyWith(
|
||||
totalLikes: currentDiet.totalLikes + 1,
|
||||
@@ -54,7 +74,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
||||
if (dietIndexInFeed != null) {
|
||||
dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed));
|
||||
}
|
||||
emit(AboutDietState.loaded(updatedDiet));
|
||||
emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||
}
|
||||
|
||||
EasyDebounce.debounce(
|
||||
@@ -69,7 +89,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
||||
dietsRepository
|
||||
.emitLikesStateToFeed(LikesState(wasLikedByMe: currentDiet.wasLikedByMe, totalLikes: currentDiet.totalLikes, index: dietIndexInFeed));
|
||||
}
|
||||
emit(AboutDietState.loaded(currentDiet));
|
||||
emit(AboutDietState.loaded(diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -86,7 +106,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
||||
if (dietIndex != null) {
|
||||
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex));
|
||||
}
|
||||
emit(AboutDietState.loaded(updatedDiet));
|
||||
emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||
|
||||
EasyDebounce.debounce(
|
||||
'add_or_remove_diet_to_favorites',
|
||||
@@ -100,7 +120,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
||||
if (dietIndex != null) {
|
||||
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex));
|
||||
}
|
||||
emit(AboutDietState.loaded(currentDiet));
|
||||
emit(AboutDietState.loaded(diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -117,7 +137,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
||||
if (dietIndex != null) {
|
||||
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex));
|
||||
}
|
||||
emit(AboutDietState.loaded(updatedDiet));
|
||||
emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||
|
||||
EasyDebounce.debounce(
|
||||
'add_or_remove_diet_to_favorites',
|
||||
@@ -131,9 +151,50 @@ class AboutDietCubit extends Cubit<AboutDietState> {
|
||||
if (dietIndex != null) {
|
||||
dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex));
|
||||
}
|
||||
emit(AboutDietState.loaded(currentDiet));
|
||||
emit(AboutDietState.loaded(diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> startDiet(DateTime date) async {
|
||||
try {
|
||||
if (state is! DietStateLoaded) return false;
|
||||
|
||||
final id = (state as DietStateLoaded).diet.id;
|
||||
final stringDate = date.format('yyyy-MM-dd');
|
||||
await dietsRepository.startDiet(id, stringDate);
|
||||
return true;
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> cancelDiet() async {
|
||||
try {
|
||||
if (state is! DietStateLoaded) return false;
|
||||
final id = (state as DietStateLoaded).diet.id;
|
||||
await dietsRepository.cancelDiet(id);
|
||||
return true;
|
||||
} on DioException catch (e) {
|
||||
log(e.toString());
|
||||
return false;
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void clearStartedDietsState() {
|
||||
if (state is! DietStateLoaded) return;
|
||||
final diet = (state as DietStateLoaded).diet;
|
||||
emit(AboutDietState.loaded(diet: diet));
|
||||
}
|
||||
|
||||
void emitCurrentStartedDietsState() {
|
||||
if (state is! DietStateLoaded) return;
|
||||
final diet = (state as DietStateLoaded).diet;
|
||||
emit(AboutDietState.loaded(diet: diet, isStarted: true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@ class AboutDietState with _$AboutDietState {
|
||||
|
||||
const factory AboutDietState.initial() = DietStateInitial;
|
||||
const factory AboutDietState.loading() = DietStateLoading;
|
||||
const factory AboutDietState.loaded(Diet diet) = DietStateLoaded;
|
||||
const factory AboutDietState.loaded({
|
||||
required Diet diet,
|
||||
@Default(false) bool isStarted,
|
||||
@Default(false) bool hasStartedDiet,
|
||||
}) = DietStateLoaded;
|
||||
const factory AboutDietState.error({required String message}) = DietStateError;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ mixin _$AboutDietState {
|
||||
TResult Function() $default, {
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(Diet diet) loaded,
|
||||
required TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@@ -30,7 +31,7 @@ mixin _$AboutDietState {
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(Diet diet)? loaded,
|
||||
TResult? Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@@ -39,7 +40,7 @@ mixin _$AboutDietState {
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(Diet diet)? loaded,
|
||||
TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
@@ -139,7 +140,8 @@ class _$AboutDietStateImpl implements _AboutDietState {
|
||||
TResult Function() $default, {
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(Diet diet) loaded,
|
||||
required TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return $default();
|
||||
@@ -151,7 +153,7 @@ class _$AboutDietStateImpl implements _AboutDietState {
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(Diet diet)? loaded,
|
||||
TResult? Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return $default?.call();
|
||||
@@ -163,7 +165,7 @@ class _$AboutDietStateImpl implements _AboutDietState {
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(Diet diet)? loaded,
|
||||
TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@@ -262,7 +264,8 @@ class _$DietStateInitialImpl implements DietStateInitial {
|
||||
TResult Function() $default, {
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(Diet diet) loaded,
|
||||
required TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return initial();
|
||||
@@ -274,7 +277,7 @@ class _$DietStateInitialImpl implements DietStateInitial {
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(Diet diet)? loaded,
|
||||
TResult? Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return initial?.call();
|
||||
@@ -286,7 +289,7 @@ class _$DietStateInitialImpl implements DietStateInitial {
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(Diet diet)? loaded,
|
||||
TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@@ -385,7 +388,8 @@ class _$DietStateLoadingImpl implements DietStateLoading {
|
||||
TResult Function() $default, {
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(Diet diet) loaded,
|
||||
required TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return loading();
|
||||
@@ -397,7 +401,7 @@ class _$DietStateLoadingImpl implements DietStateLoading {
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(Diet diet)? loaded,
|
||||
TResult? Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return loading?.call();
|
||||
@@ -409,7 +413,7 @@ class _$DietStateLoadingImpl implements DietStateLoading {
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(Diet diet)? loaded,
|
||||
TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@@ -470,7 +474,7 @@ abstract class _$$DietStateLoadedImplCopyWith<$Res> {
|
||||
$Res Function(_$DietStateLoadedImpl) then) =
|
||||
__$$DietStateLoadedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({Diet diet});
|
||||
$Res call({Diet diet, bool isStarted, bool hasStartedDiet});
|
||||
|
||||
$DietCopyWith<$Res> get diet;
|
||||
}
|
||||
@@ -489,12 +493,22 @@ class __$$DietStateLoadedImplCopyWithImpl<$Res>
|
||||
@override
|
||||
$Res call({
|
||||
Object? diet = null,
|
||||
Object? isStarted = null,
|
||||
Object? hasStartedDiet = null,
|
||||
}) {
|
||||
return _then(_$DietStateLoadedImpl(
|
||||
null == diet
|
||||
diet: null == diet
|
||||
? _value.diet
|
||||
: diet // ignore: cast_nullable_to_non_nullable
|
||||
as Diet,
|
||||
isStarted: null == isStarted
|
||||
? _value.isStarted
|
||||
: isStarted // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
hasStartedDiet: null == hasStartedDiet
|
||||
? _value.hasStartedDiet
|
||||
: hasStartedDiet // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -512,14 +526,23 @@ class __$$DietStateLoadedImplCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
|
||||
class _$DietStateLoadedImpl implements DietStateLoaded {
|
||||
const _$DietStateLoadedImpl(this.diet);
|
||||
const _$DietStateLoadedImpl(
|
||||
{required this.diet,
|
||||
this.isStarted = false,
|
||||
this.hasStartedDiet = false});
|
||||
|
||||
@override
|
||||
final Diet diet;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isStarted;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool hasStartedDiet;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AboutDietState.loaded(diet: $diet)';
|
||||
return 'AboutDietState.loaded(diet: $diet, isStarted: $isStarted, hasStartedDiet: $hasStartedDiet)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -527,11 +550,15 @@ class _$DietStateLoadedImpl implements DietStateLoaded {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$DietStateLoadedImpl &&
|
||||
(identical(other.diet, diet) || other.diet == diet));
|
||||
(identical(other.diet, diet) || other.diet == diet) &&
|
||||
(identical(other.isStarted, isStarted) ||
|
||||
other.isStarted == isStarted) &&
|
||||
(identical(other.hasStartedDiet, hasStartedDiet) ||
|
||||
other.hasStartedDiet == hasStartedDiet));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, diet);
|
||||
int get hashCode => Object.hash(runtimeType, diet, isStarted, hasStartedDiet);
|
||||
|
||||
/// Create a copy of AboutDietState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -548,10 +575,11 @@ class _$DietStateLoadedImpl implements DietStateLoaded {
|
||||
TResult Function() $default, {
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(Diet diet) loaded,
|
||||
required TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return loaded(diet);
|
||||
return loaded(diet, isStarted, hasStartedDiet);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -560,10 +588,10 @@ class _$DietStateLoadedImpl implements DietStateLoaded {
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(Diet diet)? loaded,
|
||||
TResult? Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return loaded?.call(diet);
|
||||
return loaded?.call(diet, isStarted, hasStartedDiet);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -572,12 +600,12 @@ class _$DietStateLoadedImpl implements DietStateLoaded {
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(Diet diet)? loaded,
|
||||
TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(diet);
|
||||
return loaded(diet, isStarted, hasStartedDiet);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
@@ -624,9 +652,14 @@ class _$DietStateLoadedImpl implements DietStateLoaded {
|
||||
}
|
||||
|
||||
abstract class DietStateLoaded implements AboutDietState {
|
||||
const factory DietStateLoaded(final Diet diet) = _$DietStateLoadedImpl;
|
||||
const factory DietStateLoaded(
|
||||
{required final Diet diet,
|
||||
final bool isStarted,
|
||||
final bool hasStartedDiet}) = _$DietStateLoadedImpl;
|
||||
|
||||
Diet get diet;
|
||||
bool get isStarted;
|
||||
bool get hasStartedDiet;
|
||||
|
||||
/// Create a copy of AboutDietState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -707,7 +740,8 @@ class _$DietStateErrorImpl implements DietStateError {
|
||||
TResult Function() $default, {
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(Diet diet) loaded,
|
||||
required TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return error(message);
|
||||
@@ -719,7 +753,7 @@ class _$DietStateErrorImpl implements DietStateError {
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(Diet diet)? loaded,
|
||||
TResult? Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return error?.call(message);
|
||||
@@ -731,7 +765,7 @@ class _$DietStateErrorImpl implements DietStateError {
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(Diet diet)? loaded,
|
||||
TResult Function(Diet diet, bool isStarted, bool hasStartedDiet)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_cubit.da
|
||||
import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_state.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart';
|
||||
import 'package:eatvio_app/core/widgets/cpfc_container.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/cancel_diet_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
@@ -75,7 +76,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return BlocProvider(
|
||||
create: (context) => dietsCubit..getDietWithLoading(widget.diet.id),
|
||||
create: (context) => dietsCubit..initDietPage(widget.diet.id),
|
||||
child: BlocProvider<CommentsCubit>(
|
||||
create: (BuildContext context) => commentsCubit
|
||||
..getComments(
|
||||
@@ -130,18 +131,37 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
backgroundColor: appTheme.greenA700,
|
||||
backgroundColor: dietState.isStarted ? appTheme.transparentRed : appTheme.greenA700,
|
||||
onPressed: () {
|
||||
final cubit = context.read<AboutDietCubit>();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => StartDietBottomSheet(
|
||||
aboutDietCubit: cubit,
|
||||
),
|
||||
);
|
||||
|
||||
if (dietState.isStarted) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => CancelDietBottomSheet(
|
||||
aboutDietCubit: cubit,
|
||||
dietName: dietState.diet.name,
|
||||
),
|
||||
);
|
||||
} else if (dietState.hasStartedDiet) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => CancelDietBottomSheet(
|
||||
aboutDietCubit: cubit,
|
||||
title: 'Вы собираетесь начать диету ${dietState.diet.name}, завершить диету ${cubit.userStartedDietName}?',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => StartDietBottomSheet(
|
||||
aboutDietCubit: cubit,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
label: Text(
|
||||
s.startDiet,
|
||||
dietState.isStarted ? 'Отменить диету' : s.startDiet,
|
||||
style: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -5,8 +5,8 @@ import 'package:intl/intl.dart';
|
||||
import 'package:table_calendar/table_calendar.dart';
|
||||
|
||||
class CalendarWidget extends StatefulWidget {
|
||||
const CalendarWidget({super.key});
|
||||
|
||||
const CalendarWidget({super.key, required this.startDate});
|
||||
final List<DateTime> startDate;
|
||||
@override
|
||||
State<CalendarWidget> createState() => _CalendarWidgetState();
|
||||
}
|
||||
@@ -56,6 +56,9 @@ class _CalendarWidgetState extends State<CalendarWidget> {
|
||||
_selectedDay = selectedDay;
|
||||
_focusedDay = focusedDay;
|
||||
});
|
||||
if (widget.startDate.isNotEmpty) {
|
||||
widget.startDate[0] = selectedDay;
|
||||
}
|
||||
}
|
||||
},
|
||||
onFormatChanged: (format) {
|
||||
@@ -69,6 +72,7 @@ class _CalendarWidgetState extends State<CalendarWidget> {
|
||||
_focusedDay = focusedDay;
|
||||
},
|
||||
calendarStyle: CalendarStyle(
|
||||
outsideDaysVisible: true,
|
||||
weekendTextStyle: TextStyle(
|
||||
color: appTheme.gray,
|
||||
),
|
||||
@@ -90,6 +94,17 @@ class _CalendarWidgetState extends State<CalendarWidget> {
|
||||
color: appTheme.blueA400,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
outsideTextStyle: TextStyle(
|
||||
color: appTheme.gray,
|
||||
),
|
||||
outsideDecoration: BoxDecoration(
|
||||
color: appTheme.dividerColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
withinRangeDecoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
todayTextStyle: TextStyle(
|
||||
color: appTheme.gray,
|
||||
),
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/start_diet_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CancelDietBottomSheet extends StatelessWidget {
|
||||
const CancelDietBottomSheet({super.key, required this.aboutDietCubit, this.title, this.dietName});
|
||||
final AboutDietCubit aboutDietCubit;
|
||||
final String? title;
|
||||
final String? dietName;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(height: 4),
|
||||
BottomSheetHandlerBar(),
|
||||
SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25.0),
|
||||
child: Text(
|
||||
title ?? 'Вы действительно хотите отменить прохождение диеты ${dietName ?? ''}?',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyles.headingXLSemibold.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () async {
|
||||
if (title != null) {
|
||||
final result = await aboutDietCubit.cancelDiet();
|
||||
if (result) {
|
||||
Navigator.pop(context);
|
||||
showSuccessToast('предыдущая диета отменена');
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => StartDietBottomSheet(
|
||||
aboutDietCubit: aboutDietCubit,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
showErrorToast('Не удалось отменить диету');
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} else {
|
||||
final result = await aboutDietCubit.cancelDiet();
|
||||
if (result) {
|
||||
showSuccessToast('Диета отменена');
|
||||
Navigator.pop(context);
|
||||
aboutDietCubit.clearStartedDietsState();
|
||||
} else {
|
||||
showErrorToast('Не удалось отменить диету');
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
},
|
||||
height: 60,
|
||||
text: 'Подтвердить',
|
||||
buttonTextStyle: TextStyles.textLSemibold.copyWith(
|
||||
color: appTheme.whiteA700,
|
||||
),
|
||||
buttonStyle: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_cubit.dart';
|
||||
@@ -8,9 +9,16 @@ import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StartDietBottomSheet extends StatelessWidget {
|
||||
class StartDietBottomSheet extends StatefulWidget {
|
||||
const StartDietBottomSheet({super.key, required this.aboutDietCubit});
|
||||
final AboutDietCubit aboutDietCubit;
|
||||
|
||||
@override
|
||||
State<StartDietBottomSheet> createState() => _StartDietBottomSheetState();
|
||||
}
|
||||
|
||||
class _StartDietBottomSheetState extends State<StartDietBottomSheet> {
|
||||
final startDate = [DateTime.now()];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
@@ -42,11 +50,23 @@ class StartDietBottomSheet extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: CustomDivider(),
|
||||
),
|
||||
CalendarWidget(),
|
||||
CalendarWidget(
|
||||
startDate: startDate,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {},
|
||||
onPressed: () async {
|
||||
final result = await widget.aboutDietCubit.startDiet(startDate[0]);
|
||||
if (result) {
|
||||
showSuccessToast('Диета успешно начата');
|
||||
Navigator.pop(context);
|
||||
widget.aboutDietCubit.emitCurrentStartedDietsState();
|
||||
} else {
|
||||
showErrorToast('Не удалось начать диету');
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
height: 60,
|
||||
text: s.startDiet,
|
||||
buttonTextStyle: TextStyles.textLSemibold.copyWith(
|
||||
|
||||
@@ -49,6 +49,22 @@ class DietRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> startDiet(int id, String date) async {
|
||||
try {
|
||||
return await dietsService.startDiet(id: id, body: {'date': date});
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> cancelDiet(int id) async{
|
||||
try {
|
||||
return await dietsService.cancelDiet(id: id);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void emitLikesStateToFeed(LikesState state) => _dietLikeStateStreamController.add(state);
|
||||
void emitFavoriteStateToFeed(FavoriteState state) => _dietFavoriteStateStreamController.add(state);
|
||||
void emitCommentsStateToFeed(CommentsState state) => _dietCommentsStateStreamController.add(state);
|
||||
|
||||
@@ -267,7 +267,7 @@ class PlansCubit extends Cubit<PlansState> {
|
||||
Duration(milliseconds: 200),
|
||||
() async {
|
||||
try {
|
||||
await planRepository.addToFavorite(slug);
|
||||
await planRepository.removeFromFavorite(slug);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:eatvio_app/features/feed/presentation/bloc/profile_cubit/profile
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/profile_cubit/profile_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/blog_posts.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/chip_group.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/consultants.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/diets.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/plans.dart';
|
||||
@@ -18,13 +18,13 @@ import 'package:eatvio_app/features/feed/presentation/widgets/tags_modal_widget.
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/recipes/presentation/pages/recipe_create_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../widgets/recipes.dart';
|
||||
|
||||
final bucket = PageStorageBucket();
|
||||
|
||||
class FeedScreen extends StatelessWidget {
|
||||
const FeedScreen({super.key});
|
||||
@@ -122,6 +122,7 @@ class _FeedScreenContentState extends State<FeedScreenContent> {
|
||||
recipesScrollController.dispose();
|
||||
dietsScrollController.dispose();
|
||||
plansScrollController.dispose();
|
||||
consultantsScrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -179,7 +180,18 @@ class _FeedScreenContentState extends State<FeedScreenContent> {
|
||||
floating: true,
|
||||
snap: true,
|
||||
scrolledUnderElevation: 0,
|
||||
bottom: _chipGroup(),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size(MediaQuery.of(context).size.width, 32),
|
||||
child: ChipGroup(
|
||||
selectedChipIndex: _selectedChipIndex,
|
||||
chipsLabelList: chipsLabelList,
|
||||
setSelectedChipIndex: (index) {
|
||||
setState(() {
|
||||
_selectedChipIndex = index;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
CustomSearchBar(
|
||||
@@ -245,7 +257,7 @@ class _FeedScreenContentState extends State<FeedScreenContent> {
|
||||
SizedBox(width: 12),
|
||||
switch (_selectedChipIndex) {
|
||||
1 => AddItemButton(
|
||||
onTap: () => GoRouter.of(context).pushNamed('recipeCreateScreen'),
|
||||
onTap: () => GoRouter.of(context).pushNamed(RecipeCreateScreen.name),
|
||||
),
|
||||
2 => AddItemButton(
|
||||
onTap: state.profile?.role == 'consultant' ? () => GoRouter.of(context).pushNamed(CreateDietScreen.name) : null,
|
||||
@@ -273,80 +285,4 @@ class _FeedScreenContentState extends State<FeedScreenContent> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_chipGroup() {
|
||||
return PreferredSize(
|
||||
preferredSize: Size(MediaQuery.of(context).size.width, 32),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: [
|
||||
ChoiceChipWidget(
|
||||
index: 0,
|
||||
selectedChipIndex: _selectedChipIndex,
|
||||
chipsLabelList: chipsLabelList,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
_selectedChipIndex = 0;
|
||||
FocusScope.of(context).requestFocus(new FocusNode());
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
ChoiceChipWidget(
|
||||
index: 1,
|
||||
selectedChipIndex: _selectedChipIndex,
|
||||
chipsLabelList: chipsLabelList,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
_selectedChipIndex = 1;
|
||||
FocusScope.of(context).requestFocus(new FocusNode());
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
ChoiceChipWidget(
|
||||
index: 2,
|
||||
selectedChipIndex: _selectedChipIndex,
|
||||
chipsLabelList: chipsLabelList,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
_selectedChipIndex = 2;
|
||||
FocusScope.of(context).requestFocus(new FocusNode());
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
ChoiceChipWidget(
|
||||
index: 3,
|
||||
selectedChipIndex: _selectedChipIndex,
|
||||
chipsLabelList: chipsLabelList,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
_selectedChipIndex = 3;
|
||||
FocusScope.of(context).requestFocus(new FocusNode());
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
ChoiceChipWidget(
|
||||
index: 4,
|
||||
selectedChipIndex: _selectedChipIndex,
|
||||
chipsLabelList: chipsLabelList,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
_selectedChipIndex = 4;
|
||||
FocusScope.of(context).requestFocus(new FocusNode());
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
44
lib/features/feed/presentation/widgets/chip_group.dart
Normal file
44
lib/features/feed/presentation/widgets/chip_group.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class ChipGroup extends StatelessWidget {
|
||||
const ChipGroup({
|
||||
super.key,
|
||||
required this.selectedChipIndex,
|
||||
required this.chipsLabelList,
|
||||
required this.setSelectedChipIndex,
|
||||
});
|
||||
final int selectedChipIndex;
|
||||
final List<String> chipsLabelList;
|
||||
final void Function(int) setSelectedChipIndex;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: [
|
||||
...List.generate(
|
||||
5,
|
||||
(index) => Padding(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: ChoiceChipWidget(
|
||||
index: index,
|
||||
selectedChipIndex: selectedChipIndex,
|
||||
chipsLabelList: chipsLabelList,
|
||||
onSelected: (bool selected) {
|
||||
setSelectedChipIndex(index);
|
||||
FocusScope.of(context).requestFocus(new FocusNode());
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ class MenuScreen extends StatelessWidget {
|
||||
),
|
||||
_divider(context),
|
||||
_tile(
|
||||
leading: ImageConstant.icnSupport,
|
||||
leading: ImageConstant.icnDevTools,
|
||||
title: 'Для разработчиков',
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(DevToolsScreen.name);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/chosen_diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/circumference_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/sub_model.dart';
|
||||
@@ -171,4 +172,12 @@ class ProfileRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<ChosenDietModel>> getChosenDiets() async {
|
||||
try {
|
||||
return (await profileService.getChosenDiets()).diets;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:eatvio_app/features/recipes/models/ingredient.dart';
|
||||
import 'package:eatvio_app/features/recipes/models/recipe_model.dart';
|
||||
import 'package:eatvio_app/features/recipes/models/step.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'recipe_create_entity.freezed.dart';
|
||||
@@ -11,11 +14,71 @@ enum TypeOfRecipe {
|
||||
snacks,
|
||||
sweets,
|
||||
drinks,
|
||||
other,
|
||||
other;
|
||||
|
||||
String toString() {
|
||||
switch (this) {
|
||||
case TypeOfRecipe.first_meals:
|
||||
return 'Первые блюда';
|
||||
case TypeOfRecipe.second_meals:
|
||||
return 'Вторые блюда';
|
||||
case TypeOfRecipe.salads:
|
||||
return 'Салаты';
|
||||
case TypeOfRecipe.snacks:
|
||||
return 'Закуски';
|
||||
case TypeOfRecipe.sweets:
|
||||
return 'Сладости';
|
||||
case TypeOfRecipe.drinks:
|
||||
return 'Напитки';
|
||||
case TypeOfRecipe.other:
|
||||
return 'Другое';
|
||||
}
|
||||
}
|
||||
|
||||
String toApiType() {
|
||||
switch (this) {
|
||||
case TypeOfRecipe.first_meals:
|
||||
return 'first_meals';
|
||||
case TypeOfRecipe.second_meals:
|
||||
return 'second_meals';
|
||||
case TypeOfRecipe.salads:
|
||||
return 'salads';
|
||||
case TypeOfRecipe.snacks:
|
||||
return 'snacks';
|
||||
case TypeOfRecipe.sweets:
|
||||
return 'sweets';
|
||||
case TypeOfRecipe.drinks:
|
||||
return 'drinks';
|
||||
case TypeOfRecipe.other:
|
||||
return 'other';
|
||||
}
|
||||
}
|
||||
|
||||
static TypeOfRecipe? fromString(String value) {
|
||||
switch (value) {
|
||||
case 'Первые блюда':
|
||||
return TypeOfRecipe.first_meals;
|
||||
case 'Вторые блюда':
|
||||
return TypeOfRecipe.second_meals;
|
||||
case 'Салаты':
|
||||
return TypeOfRecipe.salads;
|
||||
case 'Закуски':
|
||||
return TypeOfRecipe.snacks;
|
||||
case 'Сладости':
|
||||
return TypeOfRecipe.sweets;
|
||||
case 'Напитки':
|
||||
return TypeOfRecipe.drinks;
|
||||
case 'Другое':
|
||||
return TypeOfRecipe.other;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class RecipeCreateEntity with _$RecipeCreateEntity {
|
||||
const RecipeCreateEntity._();
|
||||
const factory RecipeCreateEntity({
|
||||
String? title,
|
||||
TypeOfRecipe? typeOfRecipe,
|
||||
@@ -26,19 +89,25 @@ class RecipeCreateEntity with _$RecipeCreateEntity {
|
||||
String? description,
|
||||
File? image,
|
||||
String? videoUrl,
|
||||
required List<IngredientEntity> ingredients,
|
||||
required List<Ingredient> ingredients,
|
||||
required List<StepEntity> steps,
|
||||
required List<String> tags, // tags for search
|
||||
}) = _RecipeCreateEntity;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class IngredientEntity with _$IngredientEntity {
|
||||
const factory IngredientEntity({
|
||||
required String name,
|
||||
required String unit,
|
||||
required String portion,
|
||||
}) = _IngredientEntity;
|
||||
RecipeModel toModel() => RecipeModel(
|
||||
title: title,
|
||||
type: typeOfRecipe?.toApiType(),
|
||||
servings: countOfPortions,
|
||||
energyPerServing: energyInOnePortion?.toInt(),
|
||||
totalCookingTime: totalCookTime?.split(':').fold(0, (value, element) => (int.tryParse(element) ?? 0)),
|
||||
activeCookTime: activeCookTime?.split(':').fold(0, (value, element) => (int.tryParse(element) ?? 0)),
|
||||
description: description,
|
||||
image: image?.path,
|
||||
video_url: videoUrl,
|
||||
ingredients: ingredients,
|
||||
steps: steps.map((step) => Step(image: step.image?.path ?? '', description: step.description ?? '')).toList(),
|
||||
tags: tags,
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
@@ -25,7 +25,7 @@ mixin _$RecipeCreateEntity {
|
||||
String? get description => throw _privateConstructorUsedError;
|
||||
File? get image => throw _privateConstructorUsedError;
|
||||
String? get videoUrl => throw _privateConstructorUsedError;
|
||||
List<IngredientEntity> get ingredients => throw _privateConstructorUsedError;
|
||||
List<Ingredient> get ingredients => throw _privateConstructorUsedError;
|
||||
List<StepEntity> get steps => throw _privateConstructorUsedError;
|
||||
List<String> get tags => throw _privateConstructorUsedError;
|
||||
|
||||
@@ -52,7 +52,7 @@ abstract class $RecipeCreateEntityCopyWith<$Res> {
|
||||
String? description,
|
||||
File? image,
|
||||
String? videoUrl,
|
||||
List<IngredientEntity> ingredients,
|
||||
List<Ingredient> ingredients,
|
||||
List<StepEntity> steps,
|
||||
List<String> tags});
|
||||
}
|
||||
@@ -125,7 +125,7 @@ class _$RecipeCreateEntityCopyWithImpl<$Res, $Val extends RecipeCreateEntity>
|
||||
ingredients: null == ingredients
|
||||
? _value.ingredients
|
||||
: ingredients // ignore: cast_nullable_to_non_nullable
|
||||
as List<IngredientEntity>,
|
||||
as List<Ingredient>,
|
||||
steps: null == steps
|
||||
? _value.steps
|
||||
: steps // ignore: cast_nullable_to_non_nullable
|
||||
@@ -156,7 +156,7 @@ abstract class _$$RecipeCreateEntityImplCopyWith<$Res>
|
||||
String? description,
|
||||
File? image,
|
||||
String? videoUrl,
|
||||
List<IngredientEntity> ingredients,
|
||||
List<Ingredient> ingredients,
|
||||
List<StepEntity> steps,
|
||||
List<String> tags});
|
||||
}
|
||||
@@ -227,7 +227,7 @@ class __$$RecipeCreateEntityImplCopyWithImpl<$Res>
|
||||
ingredients: null == ingredients
|
||||
? _value._ingredients
|
||||
: ingredients // ignore: cast_nullable_to_non_nullable
|
||||
as List<IngredientEntity>,
|
||||
as List<Ingredient>,
|
||||
steps: null == steps
|
||||
? _value._steps
|
||||
: steps // ignore: cast_nullable_to_non_nullable
|
||||
@@ -242,7 +242,7 @@ class __$$RecipeCreateEntityImplCopyWithImpl<$Res>
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$RecipeCreateEntityImpl implements _RecipeCreateEntity {
|
||||
class _$RecipeCreateEntityImpl extends _RecipeCreateEntity {
|
||||
const _$RecipeCreateEntityImpl(
|
||||
{this.title,
|
||||
this.typeOfRecipe,
|
||||
@@ -253,12 +253,13 @@ class _$RecipeCreateEntityImpl implements _RecipeCreateEntity {
|
||||
this.description,
|
||||
this.image,
|
||||
this.videoUrl,
|
||||
required final List<IngredientEntity> ingredients,
|
||||
required final List<Ingredient> ingredients,
|
||||
required final List<StepEntity> steps,
|
||||
required final List<String> tags})
|
||||
: _ingredients = ingredients,
|
||||
_steps = steps,
|
||||
_tags = tags;
|
||||
_tags = tags,
|
||||
super._();
|
||||
|
||||
@override
|
||||
final String? title;
|
||||
@@ -280,9 +281,9 @@ class _$RecipeCreateEntityImpl implements _RecipeCreateEntity {
|
||||
final File? image;
|
||||
@override
|
||||
final String? videoUrl;
|
||||
final List<IngredientEntity> _ingredients;
|
||||
final List<Ingredient> _ingredients;
|
||||
@override
|
||||
List<IngredientEntity> get ingredients {
|
||||
List<Ingredient> get ingredients {
|
||||
if (_ingredients is EqualUnmodifiableListView) return _ingredients;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_ingredients);
|
||||
@@ -362,7 +363,7 @@ class _$RecipeCreateEntityImpl implements _RecipeCreateEntity {
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _RecipeCreateEntity implements RecipeCreateEntity {
|
||||
abstract class _RecipeCreateEntity extends RecipeCreateEntity {
|
||||
const factory _RecipeCreateEntity(
|
||||
{final String? title,
|
||||
final TypeOfRecipe? typeOfRecipe,
|
||||
@@ -373,9 +374,10 @@ abstract class _RecipeCreateEntity implements RecipeCreateEntity {
|
||||
final String? description,
|
||||
final File? image,
|
||||
final String? videoUrl,
|
||||
required final List<IngredientEntity> ingredients,
|
||||
required final List<Ingredient> ingredients,
|
||||
required final List<StepEntity> steps,
|
||||
required final List<String> tags}) = _$RecipeCreateEntityImpl;
|
||||
const _RecipeCreateEntity._() : super._();
|
||||
|
||||
@override
|
||||
String? get title;
|
||||
@@ -396,7 +398,7 @@ abstract class _RecipeCreateEntity implements RecipeCreateEntity {
|
||||
@override
|
||||
String? get videoUrl;
|
||||
@override
|
||||
List<IngredientEntity> get ingredients;
|
||||
List<Ingredient> get ingredients;
|
||||
@override
|
||||
List<StepEntity> get steps;
|
||||
@override
|
||||
@@ -410,171 +412,6 @@ abstract class _RecipeCreateEntity implements RecipeCreateEntity {
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$IngredientEntity {
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
String get unit => throw _privateConstructorUsedError;
|
||||
String get portion => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of IngredientEntity
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$IngredientEntityCopyWith<IngredientEntity> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $IngredientEntityCopyWith<$Res> {
|
||||
factory $IngredientEntityCopyWith(
|
||||
IngredientEntity value, $Res Function(IngredientEntity) then) =
|
||||
_$IngredientEntityCopyWithImpl<$Res, IngredientEntity>;
|
||||
@useResult
|
||||
$Res call({String name, String unit, String portion});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$IngredientEntityCopyWithImpl<$Res, $Val extends IngredientEntity>
|
||||
implements $IngredientEntityCopyWith<$Res> {
|
||||
_$IngredientEntityCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of IngredientEntity
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? name = null,
|
||||
Object? unit = null,
|
||||
Object? portion = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
unit: null == unit
|
||||
? _value.unit
|
||||
: unit // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
portion: null == portion
|
||||
? _value.portion
|
||||
: portion // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$IngredientEntityImplCopyWith<$Res>
|
||||
implements $IngredientEntityCopyWith<$Res> {
|
||||
factory _$$IngredientEntityImplCopyWith(_$IngredientEntityImpl value,
|
||||
$Res Function(_$IngredientEntityImpl) then) =
|
||||
__$$IngredientEntityImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String name, String unit, String portion});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$IngredientEntityImplCopyWithImpl<$Res>
|
||||
extends _$IngredientEntityCopyWithImpl<$Res, _$IngredientEntityImpl>
|
||||
implements _$$IngredientEntityImplCopyWith<$Res> {
|
||||
__$$IngredientEntityImplCopyWithImpl(_$IngredientEntityImpl _value,
|
||||
$Res Function(_$IngredientEntityImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of IngredientEntity
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? name = null,
|
||||
Object? unit = null,
|
||||
Object? portion = null,
|
||||
}) {
|
||||
return _then(_$IngredientEntityImpl(
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
unit: null == unit
|
||||
? _value.unit
|
||||
: unit // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
portion: null == portion
|
||||
? _value.portion
|
||||
: portion // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$IngredientEntityImpl implements _IngredientEntity {
|
||||
const _$IngredientEntityImpl(
|
||||
{required this.name, required this.unit, required this.portion});
|
||||
|
||||
@override
|
||||
final String name;
|
||||
@override
|
||||
final String unit;
|
||||
@override
|
||||
final String portion;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'IngredientEntity(name: $name, unit: $unit, portion: $portion)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$IngredientEntityImpl &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
(identical(other.unit, unit) || other.unit == unit) &&
|
||||
(identical(other.portion, portion) || other.portion == portion));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, name, unit, portion);
|
||||
|
||||
/// Create a copy of IngredientEntity
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$IngredientEntityImplCopyWith<_$IngredientEntityImpl> get copyWith =>
|
||||
__$$IngredientEntityImplCopyWithImpl<_$IngredientEntityImpl>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _IngredientEntity implements IngredientEntity {
|
||||
const factory _IngredientEntity(
|
||||
{required final String name,
|
||||
required final String unit,
|
||||
required final String portion}) = _$IngredientEntityImpl;
|
||||
|
||||
@override
|
||||
String get name;
|
||||
@override
|
||||
String get unit;
|
||||
@override
|
||||
String get portion;
|
||||
|
||||
/// Create a copy of IngredientEntity
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$IngredientEntityImplCopyWith<_$IngredientEntityImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$StepEntity {
|
||||
String? get description => throw _privateConstructorUsedError;
|
||||
|
||||
@@ -13,4 +13,4 @@ class Ingredient with _$Ingredient {
|
||||
}) = _Ingredient;
|
||||
|
||||
factory Ingredient.fromJson(Map<String, Object?> json) => _$IngredientFromJson(json);
|
||||
}
|
||||
}
|
||||
@@ -11,13 +11,17 @@ class RecipeModel with _$RecipeModel {
|
||||
const factory RecipeModel({
|
||||
List<Ingredient?>? ingredients,
|
||||
List<Step?>? steps,
|
||||
List<String>? tags,
|
||||
String? type,
|
||||
String? state,
|
||||
String? title,
|
||||
String? description,
|
||||
String? video_url,
|
||||
String? image,
|
||||
int? cooking_time,
|
||||
int? totalCookingTime,
|
||||
int? activeCookTime,
|
||||
int? servings,
|
||||
int? energyPerServing,
|
||||
}) = _RecipeModel;
|
||||
|
||||
factory RecipeModel.fromJson(Map<String, Object?> json) => _$RecipeModelFromJson(json);
|
||||
|
||||
@@ -22,13 +22,17 @@ RecipeModel _$RecipeModelFromJson(Map<String, dynamic> json) {
|
||||
mixin _$RecipeModel {
|
||||
List<Ingredient?>? get ingredients => throw _privateConstructorUsedError;
|
||||
List<Step?>? get steps => throw _privateConstructorUsedError;
|
||||
List<String>? get tags => throw _privateConstructorUsedError;
|
||||
String? get type => throw _privateConstructorUsedError;
|
||||
String? get state => throw _privateConstructorUsedError;
|
||||
String? get title => throw _privateConstructorUsedError;
|
||||
String? get description => throw _privateConstructorUsedError;
|
||||
String? get video_url => throw _privateConstructorUsedError;
|
||||
String? get image => throw _privateConstructorUsedError;
|
||||
int? get cooking_time => throw _privateConstructorUsedError;
|
||||
int? get totalCookingTime => throw _privateConstructorUsedError;
|
||||
int? get activeCookTime => throw _privateConstructorUsedError;
|
||||
int? get servings => throw _privateConstructorUsedError;
|
||||
int? get energyPerServing => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this RecipeModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@@ -49,13 +53,17 @@ abstract class $RecipeModelCopyWith<$Res> {
|
||||
$Res call(
|
||||
{List<Ingredient?>? ingredients,
|
||||
List<Step?>? steps,
|
||||
List<String>? tags,
|
||||
String? type,
|
||||
String? state,
|
||||
String? title,
|
||||
String? description,
|
||||
String? video_url,
|
||||
String? image,
|
||||
int? cooking_time});
|
||||
int? totalCookingTime,
|
||||
int? activeCookTime,
|
||||
int? servings,
|
||||
int? energyPerServing});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -75,13 +83,17 @@ class _$RecipeModelCopyWithImpl<$Res, $Val extends RecipeModel>
|
||||
$Res call({
|
||||
Object? ingredients = freezed,
|
||||
Object? steps = freezed,
|
||||
Object? tags = freezed,
|
||||
Object? type = freezed,
|
||||
Object? state = freezed,
|
||||
Object? title = freezed,
|
||||
Object? description = freezed,
|
||||
Object? video_url = freezed,
|
||||
Object? image = freezed,
|
||||
Object? cooking_time = freezed,
|
||||
Object? totalCookingTime = freezed,
|
||||
Object? activeCookTime = freezed,
|
||||
Object? servings = freezed,
|
||||
Object? energyPerServing = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
ingredients: freezed == ingredients
|
||||
@@ -92,6 +104,10 @@ class _$RecipeModelCopyWithImpl<$Res, $Val extends RecipeModel>
|
||||
? _value.steps
|
||||
: steps // ignore: cast_nullable_to_non_nullable
|
||||
as List<Step?>?,
|
||||
tags: freezed == tags
|
||||
? _value.tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
type: freezed == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
@@ -116,9 +132,21 @@ class _$RecipeModelCopyWithImpl<$Res, $Val extends RecipeModel>
|
||||
? _value.image
|
||||
: image // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
cooking_time: freezed == cooking_time
|
||||
? _value.cooking_time
|
||||
: cooking_time // ignore: cast_nullable_to_non_nullable
|
||||
totalCookingTime: freezed == totalCookingTime
|
||||
? _value.totalCookingTime
|
||||
: totalCookingTime // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
activeCookTime: freezed == activeCookTime
|
||||
? _value.activeCookTime
|
||||
: activeCookTime // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
servings: freezed == servings
|
||||
? _value.servings
|
||||
: servings // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
energyPerServing: freezed == energyPerServing
|
||||
? _value.energyPerServing
|
||||
: energyPerServing // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
) as $Val);
|
||||
}
|
||||
@@ -135,13 +163,17 @@ abstract class _$$RecipeModelImplCopyWith<$Res>
|
||||
$Res call(
|
||||
{List<Ingredient?>? ingredients,
|
||||
List<Step?>? steps,
|
||||
List<String>? tags,
|
||||
String? type,
|
||||
String? state,
|
||||
String? title,
|
||||
String? description,
|
||||
String? video_url,
|
||||
String? image,
|
||||
int? cooking_time});
|
||||
int? totalCookingTime,
|
||||
int? activeCookTime,
|
||||
int? servings,
|
||||
int? energyPerServing});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -159,13 +191,17 @@ class __$$RecipeModelImplCopyWithImpl<$Res>
|
||||
$Res call({
|
||||
Object? ingredients = freezed,
|
||||
Object? steps = freezed,
|
||||
Object? tags = freezed,
|
||||
Object? type = freezed,
|
||||
Object? state = freezed,
|
||||
Object? title = freezed,
|
||||
Object? description = freezed,
|
||||
Object? video_url = freezed,
|
||||
Object? image = freezed,
|
||||
Object? cooking_time = freezed,
|
||||
Object? totalCookingTime = freezed,
|
||||
Object? activeCookTime = freezed,
|
||||
Object? servings = freezed,
|
||||
Object? energyPerServing = freezed,
|
||||
}) {
|
||||
return _then(_$RecipeModelImpl(
|
||||
ingredients: freezed == ingredients
|
||||
@@ -176,6 +212,10 @@ class __$$RecipeModelImplCopyWithImpl<$Res>
|
||||
? _value._steps
|
||||
: steps // ignore: cast_nullable_to_non_nullable
|
||||
as List<Step?>?,
|
||||
tags: freezed == tags
|
||||
? _value._tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>?,
|
||||
type: freezed == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
@@ -200,9 +240,21 @@ class __$$RecipeModelImplCopyWithImpl<$Res>
|
||||
? _value.image
|
||||
: image // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
cooking_time: freezed == cooking_time
|
||||
? _value.cooking_time
|
||||
: cooking_time // ignore: cast_nullable_to_non_nullable
|
||||
totalCookingTime: freezed == totalCookingTime
|
||||
? _value.totalCookingTime
|
||||
: totalCookingTime // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
activeCookTime: freezed == activeCookTime
|
||||
? _value.activeCookTime
|
||||
: activeCookTime // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
servings: freezed == servings
|
||||
? _value.servings
|
||||
: servings // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
energyPerServing: freezed == energyPerServing
|
||||
? _value.energyPerServing
|
||||
: energyPerServing // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
));
|
||||
}
|
||||
@@ -214,15 +266,20 @@ class _$RecipeModelImpl implements _RecipeModel {
|
||||
const _$RecipeModelImpl(
|
||||
{final List<Ingredient?>? ingredients,
|
||||
final List<Step?>? steps,
|
||||
final List<String>? tags,
|
||||
this.type,
|
||||
this.state,
|
||||
this.title,
|
||||
this.description,
|
||||
this.video_url,
|
||||
this.image,
|
||||
this.cooking_time})
|
||||
this.totalCookingTime,
|
||||
this.activeCookTime,
|
||||
this.servings,
|
||||
this.energyPerServing})
|
||||
: _ingredients = ingredients,
|
||||
_steps = steps;
|
||||
_steps = steps,
|
||||
_tags = tags;
|
||||
|
||||
factory _$RecipeModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$RecipeModelImplFromJson(json);
|
||||
@@ -247,6 +304,16 @@ class _$RecipeModelImpl implements _RecipeModel {
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
final List<String>? _tags;
|
||||
@override
|
||||
List<String>? get tags {
|
||||
final value = _tags;
|
||||
if (value == null) return null;
|
||||
if (_tags is EqualUnmodifiableListView) return _tags;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
final String? type;
|
||||
@override
|
||||
@@ -260,11 +327,17 @@ class _$RecipeModelImpl implements _RecipeModel {
|
||||
@override
|
||||
final String? image;
|
||||
@override
|
||||
final int? cooking_time;
|
||||
final int? totalCookingTime;
|
||||
@override
|
||||
final int? activeCookTime;
|
||||
@override
|
||||
final int? servings;
|
||||
@override
|
||||
final int? energyPerServing;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RecipeModel(ingredients: $ingredients, steps: $steps, type: $type, state: $state, title: $title, description: $description, video_url: $video_url, image: $image, cooking_time: $cooking_time)';
|
||||
return 'RecipeModel(ingredients: $ingredients, steps: $steps, tags: $tags, type: $type, state: $state, title: $title, description: $description, video_url: $video_url, image: $image, totalCookingTime: $totalCookingTime, activeCookTime: $activeCookTime, servings: $servings, energyPerServing: $energyPerServing)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -275,6 +348,7 @@ class _$RecipeModelImpl implements _RecipeModel {
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._ingredients, _ingredients) &&
|
||||
const DeepCollectionEquality().equals(other._steps, _steps) &&
|
||||
const DeepCollectionEquality().equals(other._tags, _tags) &&
|
||||
(identical(other.type, type) || other.type == type) &&
|
||||
(identical(other.state, state) || other.state == state) &&
|
||||
(identical(other.title, title) || other.title == title) &&
|
||||
@@ -283,8 +357,14 @@ class _$RecipeModelImpl implements _RecipeModel {
|
||||
(identical(other.video_url, video_url) ||
|
||||
other.video_url == video_url) &&
|
||||
(identical(other.image, image) || other.image == image) &&
|
||||
(identical(other.cooking_time, cooking_time) ||
|
||||
other.cooking_time == cooking_time));
|
||||
(identical(other.totalCookingTime, totalCookingTime) ||
|
||||
other.totalCookingTime == totalCookingTime) &&
|
||||
(identical(other.activeCookTime, activeCookTime) ||
|
||||
other.activeCookTime == activeCookTime) &&
|
||||
(identical(other.servings, servings) ||
|
||||
other.servings == servings) &&
|
||||
(identical(other.energyPerServing, energyPerServing) ||
|
||||
other.energyPerServing == energyPerServing));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -293,13 +373,17 @@ class _$RecipeModelImpl implements _RecipeModel {
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_ingredients),
|
||||
const DeepCollectionEquality().hash(_steps),
|
||||
const DeepCollectionEquality().hash(_tags),
|
||||
type,
|
||||
state,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
image,
|
||||
cooking_time);
|
||||
totalCookingTime,
|
||||
activeCookTime,
|
||||
servings,
|
||||
energyPerServing);
|
||||
|
||||
/// Create a copy of RecipeModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -321,13 +405,17 @@ abstract class _RecipeModel implements RecipeModel {
|
||||
const factory _RecipeModel(
|
||||
{final List<Ingredient?>? ingredients,
|
||||
final List<Step?>? steps,
|
||||
final List<String>? tags,
|
||||
final String? type,
|
||||
final String? state,
|
||||
final String? title,
|
||||
final String? description,
|
||||
final String? video_url,
|
||||
final String? image,
|
||||
final int? cooking_time}) = _$RecipeModelImpl;
|
||||
final int? totalCookingTime,
|
||||
final int? activeCookTime,
|
||||
final int? servings,
|
||||
final int? energyPerServing}) = _$RecipeModelImpl;
|
||||
|
||||
factory _RecipeModel.fromJson(Map<String, dynamic> json) =
|
||||
_$RecipeModelImpl.fromJson;
|
||||
@@ -337,6 +425,8 @@ abstract class _RecipeModel implements RecipeModel {
|
||||
@override
|
||||
List<Step?>? get steps;
|
||||
@override
|
||||
List<String>? get tags;
|
||||
@override
|
||||
String? get type;
|
||||
@override
|
||||
String? get state;
|
||||
@@ -349,7 +439,13 @@ abstract class _RecipeModel implements RecipeModel {
|
||||
@override
|
||||
String? get image;
|
||||
@override
|
||||
int? get cooking_time;
|
||||
int? get totalCookingTime;
|
||||
@override
|
||||
int? get activeCookTime;
|
||||
@override
|
||||
int? get servings;
|
||||
@override
|
||||
int? get energyPerServing;
|
||||
|
||||
/// Create a copy of RecipeModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@@ -16,24 +16,32 @@ _$RecipeModelImpl _$$RecipeModelImplFromJson(Map<String, dynamic> json) =>
|
||||
?.map((e) =>
|
||||
e == null ? null : Step.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
tags: (json['tags'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||
type: json['type'] as String?,
|
||||
state: json['state'] as String?,
|
||||
title: json['title'] as String?,
|
||||
description: json['description'] as String?,
|
||||
video_url: json['video_url'] as String?,
|
||||
image: json['image'] as String?,
|
||||
cooking_time: (json['cooking_time'] as num?)?.toInt(),
|
||||
totalCookingTime: (json['totalCookingTime'] as num?)?.toInt(),
|
||||
activeCookTime: (json['activeCookTime'] as num?)?.toInt(),
|
||||
servings: (json['servings'] as num?)?.toInt(),
|
||||
energyPerServing: (json['energyPerServing'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$RecipeModelImplToJson(_$RecipeModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'ingredients': instance.ingredients,
|
||||
'steps': instance.steps,
|
||||
'tags': instance.tags,
|
||||
'type': instance.type,
|
||||
'state': instance.state,
|
||||
'title': instance.title,
|
||||
'description': instance.description,
|
||||
'video_url': instance.video_url,
|
||||
'image': instance.image,
|
||||
'cooking_time': instance.cooking_time,
|
||||
'totalCookingTime': instance.totalCookingTime,
|
||||
'activeCookTime': instance.activeCookTime,
|
||||
'servings': instance.servings,
|
||||
'energyPerServing': instance.energyPerServing,
|
||||
};
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:eatvio_app/features/recipes/entities/recipe_create_entity.dart';
|
||||
import 'package:eatvio_app/features/recipes/models/ingredient.dart';
|
||||
import 'package:eatvio_app/features/recipes/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
|
||||
import 'package:eatvio_app/features/recipes/reporitories/recipe_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class CreateRecipeCubit extends Cubit<CreateRecipeState> {
|
||||
CreateRecipeCubit()
|
||||
final RecipeRepository recipeRepository;
|
||||
CreateRecipeCubit({required this.recipeRepository})
|
||||
: super(
|
||||
CreateRecipeState(
|
||||
RecipeCreateEntity(
|
||||
typeOfRecipe: TypeOfRecipe.first_meals,
|
||||
ingredients: [],
|
||||
steps: [],
|
||||
tags: [],
|
||||
@@ -38,7 +42,7 @@ class CreateRecipeCubit extends Cubit<CreateRecipeState> {
|
||||
);
|
||||
}
|
||||
|
||||
addIngredient(IngredientEntity entity) {
|
||||
addIngredient(Ingredient entity) {
|
||||
emit(
|
||||
CreateRecipeState(
|
||||
state.entity.copyWith(
|
||||
@@ -52,7 +56,7 @@ class CreateRecipeCubit extends Cubit<CreateRecipeState> {
|
||||
}
|
||||
|
||||
removeIngredient(int index) {
|
||||
List<IngredientEntity> ingredients = [...state.entity.ingredients];
|
||||
List<Ingredient> ingredients = [...state.entity.ingredients];
|
||||
ingredients.removeAt(index);
|
||||
|
||||
emit(
|
||||
@@ -65,8 +69,8 @@ class CreateRecipeCubit extends Cubit<CreateRecipeState> {
|
||||
}
|
||||
|
||||
replaceIngredientPosition(int oldIndex, int newIndex) {
|
||||
List<IngredientEntity> ingredients = [...state.entity.ingredients];
|
||||
final IngredientEntity item = ingredients.removeAt(oldIndex);
|
||||
List<Ingredient> ingredients = [...state.entity.ingredients];
|
||||
final item = ingredients.removeAt(oldIndex);
|
||||
ingredients.insert(newIndex, item);
|
||||
emit(
|
||||
CreateRecipeState(
|
||||
@@ -216,4 +220,12 @@ class CreateRecipeCubit extends Cubit<CreateRecipeState> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> publishRecipe() async {
|
||||
try {
|
||||
await recipeRepository.publishRecipe(state.entity.toModel());
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
class RecipeCreateScreen extends StatefulWidget {
|
||||
const RecipeCreateScreen({super.key});
|
||||
|
||||
static const name = 'recipeCreateScreen';
|
||||
static const path = '/recipe-create-screen';
|
||||
|
||||
@override
|
||||
State<RecipeCreateScreen> createState() => _RecipeCreateScreenState();
|
||||
}
|
||||
@@ -39,28 +42,34 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
InfoAboutRecipeWidget(),
|
||||
IngredientsWidget(),
|
||||
StepsWidget(),
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
Builder(
|
||||
builder: (context) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
context.read<CreateRecipeCubit>().publishRecipe();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Опубликовать',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600,
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Опубликовать',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -18,14 +18,7 @@ class InfoAboutRecipeWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _InfoAboutRecipeWidgetState extends State<InfoAboutRecipeWidget> {
|
||||
final List<SelectionPopupModel> items = const [
|
||||
SelectionPopupModel(title: 'Первые Блюда'),
|
||||
SelectionPopupModel(title: 'Вторые Блюда'),
|
||||
SelectionPopupModel(title: 'Салаты'),
|
||||
SelectionPopupModel(title: 'Сладости'),
|
||||
SelectionPopupModel(title: 'Напитки'),
|
||||
SelectionPopupModel(title: 'Прочее'),
|
||||
];
|
||||
final List<SelectionPopupModel> items = TypeOfRecipe.values.map((e) => SelectionPopupModel(title: e.toString())).toList();
|
||||
late SelectionPopupModel selectedType;
|
||||
late final CreateRecipeCubit createRecipeCubit;
|
||||
|
||||
@@ -64,14 +57,7 @@ class _InfoAboutRecipeWidgetState extends State<InfoAboutRecipeWidget> {
|
||||
selectedType = newSelectedType;
|
||||
});
|
||||
createRecipeCubit.changeType(
|
||||
switch (selectedType.title) {
|
||||
'Первые Блюда' => TypeOfRecipe.first_meals,
|
||||
'Вторые Блюда' => TypeOfRecipe.second_meals,
|
||||
'Салаты' => TypeOfRecipe.salads,
|
||||
'Сладости' => TypeOfRecipe.sweets,
|
||||
'Напитки' => TypeOfRecipe.drinks,
|
||||
_ => TypeOfRecipe.other,
|
||||
},
|
||||
TypeOfRecipe.fromString(selectedType.title) ?? TypeOfRecipe.other,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/features/recipes/entities/recipe_create_entity.dart';
|
||||
import 'package:eatvio_app/features/recipes/models/ingredient.dart';
|
||||
import 'package:eatvio_app/features/recipes/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart';
|
||||
import 'package:eatvio_app/features/recipes/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -161,7 +161,7 @@ class _IngredientsWidgetState extends State<IngredientsWidget> {
|
||||
onTap: () {
|
||||
if (nameController.text.isNotEmpty && (pcsController.text.isNotEmpty || gramsController.text.isNotEmpty)) {
|
||||
createRecipeCubit.addIngredient(
|
||||
IngredientEntity(
|
||||
Ingredient(
|
||||
name: nameController.text,
|
||||
unit: gramsController.text.isEmpty ? pcsController.text : gramsController.text,
|
||||
portion: gramsController.text.isEmpty ? 'pcs' : 'gr',
|
||||
|
||||
@@ -19,11 +19,14 @@ class RecipeRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<RecipeModel> publishRecipe(RecipeModel recipe) async {
|
||||
Future<RecipeModel?> publishRecipe(RecipeModel recipe) async {
|
||||
try {
|
||||
final File file = File(recipe.image ?? '');
|
||||
if (recipe.image == null || (recipe.image?.isEmpty ?? true)) {
|
||||
return null;
|
||||
}
|
||||
final file = File(recipe.image ?? '');
|
||||
|
||||
List<Map<String, Object>> ingredientsMap = recipe.ingredients?.map((ingredient) {
|
||||
final ingredientsMap = recipe.ingredients?.map((ingredient) {
|
||||
return {
|
||||
'name': ingredient!.name,
|
||||
'unit': ingredient.unit,
|
||||
@@ -32,25 +35,42 @@ class RecipeRepository {
|
||||
}).toList() ??
|
||||
[];
|
||||
|
||||
List<Map<String, Object>> stepsMap = recipe.steps?.map((step) {
|
||||
final stepsMap = recipe.steps?.map((step) {
|
||||
return {
|
||||
'image': File(step?.image ?? ""),
|
||||
'description': step?.description ?? "",
|
||||
};
|
||||
}).toList() ??
|
||||
[];
|
||||
|
||||
return await recipeService.publishRecipe(
|
||||
recipe.type,
|
||||
recipe.state,
|
||||
recipe.title,
|
||||
recipe.description,
|
||||
recipe.video_url,
|
||||
ingredientsMap,
|
||||
stepsMap,
|
||||
recipe.cooking_time,
|
||||
file,
|
||||
);
|
||||
// recipe.steps?.map((step) {
|
||||
// return File(step?.image ?? "");
|
||||
// }).toList() ??
|
||||
// [];
|
||||
|
||||
if (recipe.type != null &&
|
||||
recipe.description != null &&
|
||||
recipe.totalCookingTime != null &&
|
||||
recipe.activeCookTime != null &&
|
||||
recipe.servings != null &&
|
||||
recipe.energyPerServing != null &&
|
||||
ingredientsMap.isNotEmpty) {
|
||||
return await recipeService.publishRecipe(
|
||||
type: recipe.type!,
|
||||
state: 'active',
|
||||
title: recipe.title,
|
||||
tags: recipe.tags,
|
||||
description: recipe.description!,
|
||||
video_url: recipe.video_url,
|
||||
ingredients: ingredientsMap,
|
||||
steps: stepsMap,
|
||||
cooking_time: recipe.totalCookingTime!,
|
||||
active_time: recipe.activeCookTime!,
|
||||
image: file,
|
||||
servings: recipe.servings!,
|
||||
energy_per_serving: recipe.energyPerServing!,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
@@ -19,18 +19,25 @@ abstract class RecipeService {
|
||||
@GET('/api/diary/product_nutritional_values/filter')
|
||||
Future<Map<String, List<Product>>> getInputProduct(@Query('name') String name);
|
||||
|
||||
|
||||
@POST('/api/recipes/create')
|
||||
Future<RecipeModel> publishRecipe(
|
||||
@Part() String? type,
|
||||
@Part() String? state,
|
||||
@MultiPart()
|
||||
Future<RecipeModel> publishRecipe({
|
||||
@Part() required String type,
|
||||
@Part() required String state,
|
||||
@Part() String? title,
|
||||
@Part() String? description,
|
||||
@Part() required String description,
|
||||
@Part() String? video_url,
|
||||
@Part() List<Map<String, Object>> ingredients,
|
||||
@Part() List<Map<String, Object>> steps,
|
||||
@Part() List<Map<String, Object>>? ingredients,
|
||||
@Part() List<Map<String, Object>>? steps,
|
||||
@Part() List<String>? tags,
|
||||
@Part() int? cooking_time,
|
||||
@Part() File image,
|
||||
);
|
||||
@Part() int? active_time,
|
||||
@Part() required int servings,
|
||||
@Part() required int energy_per_serving,
|
||||
@Part() File? image,
|
||||
|
||||
});
|
||||
|
||||
@POST('/api/recipes/update/{id}')
|
||||
Future<RecipeModel> editRecipe(@Part() Map<String, Object?> recipe, String id);
|
||||
|
||||
@@ -92,75 +92,95 @@ class _RecipeService implements RecipeService {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<RecipeModel> publishRecipe(
|
||||
String? type,
|
||||
String? state,
|
||||
Future<RecipeModel> publishRecipe({
|
||||
required String type,
|
||||
required String state,
|
||||
String? title,
|
||||
String? description,
|
||||
required String description,
|
||||
String? video_url,
|
||||
List<Map<String, Object>> ingredients,
|
||||
List<Map<String, Object>> steps,
|
||||
List<Map<String, Object>>? ingredients,
|
||||
List<Map<String, Object>>? steps,
|
||||
List<String>? tags,
|
||||
int? cooking_time,
|
||||
File image,
|
||||
) async {
|
||||
int? active_time,
|
||||
required int servings,
|
||||
required int energy_per_serving,
|
||||
File? image,
|
||||
}) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
queryParameters.removeWhere((k, v) => v == null);
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = FormData();
|
||||
if (type != null) {
|
||||
_data.fields.add(MapEntry(
|
||||
'type',
|
||||
type,
|
||||
));
|
||||
}
|
||||
if (state != null) {
|
||||
_data.fields.add(MapEntry(
|
||||
'state',
|
||||
state,
|
||||
));
|
||||
}
|
||||
_data.fields.add(MapEntry(
|
||||
'type',
|
||||
type,
|
||||
));
|
||||
_data.fields.add(MapEntry(
|
||||
'state',
|
||||
state,
|
||||
));
|
||||
if (title != null) {
|
||||
_data.fields.add(MapEntry(
|
||||
'title',
|
||||
title,
|
||||
));
|
||||
}
|
||||
if (description != null) {
|
||||
_data.fields.add(MapEntry(
|
||||
'description',
|
||||
description,
|
||||
));
|
||||
}
|
||||
_data.fields.add(MapEntry(
|
||||
'description',
|
||||
description,
|
||||
));
|
||||
if (video_url != null) {
|
||||
_data.fields.add(MapEntry(
|
||||
'video_url',
|
||||
video_url,
|
||||
));
|
||||
}
|
||||
ingredients.forEach((i) {
|
||||
ingredients?.forEach((i) {
|
||||
_data.fields.add(MapEntry('ingredients', jsonEncode(i)));
|
||||
});
|
||||
steps.forEach((i) {
|
||||
steps?.forEach((i) {
|
||||
_data.fields.add(MapEntry('steps', jsonEncode(i)));
|
||||
});
|
||||
tags?.forEach((i) {
|
||||
_data.fields.add(MapEntry('tags', i));
|
||||
});
|
||||
if (cooking_time != null) {
|
||||
_data.fields.add(MapEntry(
|
||||
'cooking_time',
|
||||
cooking_time.toString(),
|
||||
));
|
||||
}
|
||||
_data.files.add(MapEntry(
|
||||
'image',
|
||||
MultipartFile.fromFileSync(
|
||||
image.path,
|
||||
filename: image.path.split(Platform.pathSeparator).last,
|
||||
),
|
||||
if (active_time != null) {
|
||||
_data.fields.add(MapEntry(
|
||||
'active_time',
|
||||
active_time.toString(),
|
||||
));
|
||||
}
|
||||
_data.fields.add(MapEntry(
|
||||
'servings',
|
||||
servings.toString(),
|
||||
));
|
||||
_data.fields.add(MapEntry(
|
||||
'energy_per_serving',
|
||||
energy_per_serving.toString(),
|
||||
));
|
||||
if (image != null) {
|
||||
if (image != null) {
|
||||
_data.files.add(MapEntry(
|
||||
'image',
|
||||
MultipartFile.fromFileSync(
|
||||
image.path,
|
||||
filename: image.path.split(Platform.pathSeparator).last,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
final _options = _setStreamType<RecipeModel>(Options(
|
||||
method: 'POST',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
contentType: 'multipart/form-data',
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/core/app_router.dart';
|
||||
|
||||
import 'package:eatvio_app/core/token_storage.dart';
|
||||
@@ -57,7 +59,7 @@ class RegistrationCubit extends Cubit<RegistrationState> {
|
||||
await TokenStorage.saveTokenInStorage(token);
|
||||
AppRouter.navigatorKey.currentContext?.go('/my-profile-screen');
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ abstract class SettingsService {
|
||||
@GET('/api/profile/settings')
|
||||
Future<ProfileSettingsModel> getProfileSettings();
|
||||
|
||||
@POST('/api/profile/settings/update')
|
||||
@PUT('/api/profile/settings/update')
|
||||
Future<ProfileSettingsModel> updateProfileSettings({
|
||||
@Body() required Map<String, dynamic> data,
|
||||
});
|
||||
|
||||
@POST('/api/profile/update')
|
||||
@PUT('/api/profile/update')
|
||||
Future<ProfileDetailsModel> updateProfileDetails({
|
||||
@Body() required Map<String, dynamic> data,
|
||||
});
|
||||
|
||||
@@ -63,7 +63,7 @@ class _SettingsService implements SettingsService {
|
||||
final _data = <String, dynamic>{};
|
||||
_data.addAll(data);
|
||||
final _options = _setStreamType<ProfileSettingsModel>(Options(
|
||||
method: 'POST',
|
||||
method: 'PUT',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
@@ -98,7 +98,7 @@ class _SettingsService implements SettingsService {
|
||||
final _data = <String, dynamic>{};
|
||||
_data.addAll(data);
|
||||
final _options = _setStreamType<ProfileDetailsModel>(Options(
|
||||
method: 'POST',
|
||||
method: 'PUT',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user