diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 485b5cb9..2566b21b 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -388,7 +388,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 15;
+ CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = VL68C36HYS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@@ -538,7 +538,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 15;
+ CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = VL68C36HYS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@@ -576,7 +576,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 15;
+ CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = VL68C36HYS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 93558f26..24f859fd 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -21,7 +21,7 @@
CFBundleSignature
????
CFBundleVersion
- 15
+ 16
ITSAppUsesNonExemptEncryption
LSRequiresIPhoneOS
diff --git a/lib/core/app_router.dart b/lib/core/app_router.dart
index 1c7210ac..dbcea1bc 100644
--- a/lib/core/app_router.dart
+++ b/lib/core/app_router.dart
@@ -43,7 +43,7 @@ import 'package:eatvio_app/features/profile/presentation/pages/subs_screen.dart'
import 'package:eatvio_app/features/recipe/presentation/about_recipe_screen.dart';
import 'package:eatvio_app/features/create_recipe/presentation/pages/recipe_create_screen.dart';
import 'package:eatvio_app/features/registration/presentation/pages/registration_screen.dart';
-import 'package:eatvio_app/features/registration/presentation/pages/webview_registration_screen.dart';
+import 'package:eatvio_app/features/registration/presentation/pages/verify_screen.dart';
import 'package:eatvio_app/features/settings/entities/settings_entity.dart';
import 'package:eatvio_app/features/settings/presentation/pages/change_email_screen.dart';
import 'package:eatvio_app/features/settings/presentation/pages/change_password_screen.dart';
@@ -76,7 +76,7 @@ class AppRouter {
name: 'authScreen',
builder: (context, state) => const AuthScreen(),
routes: [
- GoRoute(path: 'webView-registration-screen', name: 'webViewRegistrationScreen', builder: (context, state) => const WebViewRegistrationScreen()),
+ // GoRoute(path: 'webView-registration-screen', name: 'webViewRegistrationScreen', builder: (context, state) => const WebViewRegistrationScreen()),
GoRoute(path: 'registration-screen', name: 'registrationScreen', builder: (context, state) => const RegistrationScreen()),
],
),
@@ -103,7 +103,15 @@ class AppRouter {
return const NoTransitionPage(child: ProfileScreen());
},
),
- GoRoute(path: '/feed-screen', name: 'feedScreen', pageBuilder: (context, state) => const NoTransitionPage(child: FeedScreen())),
+ GoRoute(
+ path: '/feed-screen',
+ name: 'feedScreen',
+ pageBuilder: (context, state) => const NoTransitionPage(child: FeedScreen()),
+ redirect: (context, state) async {
+ await sl().initialize();
+ return null;
+ },
+ ),
GoRoute(path: '/diary-screen', name: 'diaryScreen', pageBuilder: (context, state) => const NoTransitionPage(child: DiaryScreen())),
GoRoute(
path: ConsultationsScreen.path,
@@ -342,6 +350,11 @@ class AppRouter {
);
},
),
+ GoRoute(
+ path: '/verify-screen',
+ name: 'verifyScreen',
+ builder: (context, state) => VerifyScreen(passKey: state.extra as String),
+ ),
],
);
}
diff --git a/lib/core/const.dart b/lib/core/const.dart
index 4f38a54e..31c47e9c 100644
--- a/lib/core/const.dart
+++ b/lib/core/const.dart
@@ -1,5 +1,5 @@
-// String baseUrl = 'https://eatvio.ru';
-String baseUrl = 'https://dev2.eatvio.com';
+String baseUrl = 'https://eatvio.ru';
+// String baseUrl = 'https://dev2.eatvio.com';
const List durationValues = [7, 14, 21];
diff --git a/lib/core/data/selectionPopupModel/selection_popup_model.dart b/lib/core/data/selectionPopupModel/selection_popup_model.dart
index f304e8d1..6c93499f 100644
--- a/lib/core/data/selectionPopupModel/selection_popup_model.dart
+++ b/lib/core/data/selectionPopupModel/selection_popup_model.dart
@@ -3,7 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'selection_popup_model.freezed.dart';
@freezed
-class SelectionPopupModel with _$SelectionPopupModel {
+abstract class SelectionPopupModel with _$SelectionPopupModel {
const factory SelectionPopupModel({
int? id,
required String title,
diff --git a/lib/core/dio/phone_verify_error_interceptor.dart b/lib/core/dio/phone_verify_error_interceptor.dart
new file mode 100644
index 00000000..5d764cff
--- /dev/null
+++ b/lib/core/dio/phone_verify_error_interceptor.dart
@@ -0,0 +1,29 @@
+import 'package:dio/dio.dart';
+import 'package:eatvio_app/core/app_router.dart';
+import 'package:eatvio_app/core/locator_service.dart';
+import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
+import 'package:go_router/go_router.dart';
+
+class PhoneVerifyErrorInterceptor extends Interceptor {
+ @override
+ void onError(DioException err, ErrorInterceptorHandler handler) async {
+ if (err.response?.statusCode == 405) {
+ final data = err.response?.data;
+
+ if (data is Map && data['type'] == 'unverificated_phone') {
+ final String phone = await sl().getMyPhone();
+ final String passKey = await sl().getPassKey(phone);
+ AppRouter.navigatorKey.currentContext?.pushNamed('verifyScreen', extra: passKey);
+ return handler.reject(
+ DioException(
+ requestOptions: err.requestOptions,
+ response: err.response,
+ error: 'Phone number not verified',
+ type: DioExceptionType.badResponse,
+ ),
+ );
+ }
+ }
+ return handler.next(err);
+ }
+}
diff --git a/lib/core/locator_service.dart b/lib/core/locator_service.dart
index c82f70fb..fe28d2ec 100644
--- a/lib/core/locator_service.dart
+++ b/lib/core/locator_service.dart
@@ -1,5 +1,6 @@
import 'package:dio/dio.dart';
import 'package:eatvio_app/core/const.dart';
+import 'package:eatvio_app/core/dio/phone_verify_error_interceptor.dart';
import 'package:eatvio_app/core/interceptors/token_interceptor.dart';
import 'package:eatvio_app/core/websockets/ws_manager.dart';
import 'package:eatvio_app/core/websockets/ws_service.dart';
@@ -64,6 +65,8 @@ import 'package:eatvio_app/features/my_finance/services/cards_service.dart';
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart';
import 'package:eatvio_app/features/my_plans/repositories/my_diets_repository.dart';
import 'package:eatvio_app/features/my_plans/services/my_plans_service.dart';
+import 'package:eatvio_app/features/notifications/repository/notifications_repository.dart';
+import 'package:eatvio_app/features/notifications/service/notifications_service.dart';
import 'package:eatvio_app/features/order_info/cubit/order_info_cubit.dart';
import 'package:eatvio_app/features/plans/repositories/plans_repository.dart';
import 'package:eatvio_app/features/plans/services/plans_service.dart';
@@ -97,7 +100,7 @@ Future init() async {
// Cubit singletons
sl.registerLazySingleton(() => WsManager(wsService: sl()));
sl.registerLazySingleton(() => NewMessagesCubit());
- sl.registerLazySingleton(() => NotificationsCubit(wsManager: sl()));
+ sl.registerLazySingleton(() => NotificationsCubit(wsManager: sl(), notificationsRepository: sl()));
sl.registerLazySingleton(() => ProfileAvatarCubit(profileRepository: sl()));
sl.registerLazySingleton(() => ChatsCubit(chatRepository: sl(), wsManager: sl(), profileRepository: sl()));
@@ -122,7 +125,7 @@ Future init() async {
sl.registerFactory(() => CreatePlanCubit(createPlanRepository: sl()));
sl.registerFactory(() => FeedProfileCubit(profileRepository: sl()));
sl.registerFactory(() => AboutPlanCubit(planRepository: sl()));
- sl.registerFactory(() => CreateRecipeCubit(recipeRepository: sl()));
+ sl.registerFactory(() => CreateRecipeCubit(recipeRepository: sl(), glossaryRepository: sl()));
sl.registerFactory(() => MyDietsCubit(myDietsRepository: sl(), createDietRepository: sl()));
sl.registerFactory(() => MyPlansCubit(myPlansRepository: sl()));
sl.registerFactory(() => UserDetailsCubit(profileRepository: sl()));
@@ -161,6 +164,7 @@ Future init() async {
sl.registerLazySingleton(() => ConsultationsRepository(consultationService: sl()));
sl.registerLazySingleton(() => CancelPlanRepository(cancelService: sl()));
sl.registerLazySingleton(() => CreatePlanRepository(createPlanService: sl()));
+ sl.registerLazySingleton(() => NotificationsRepository(notificationsService: sl()));
// Services
sl.registerLazySingleton(() => ChatService(sl()));
@@ -188,10 +192,24 @@ Future init() async {
sl.registerLazySingleton(() => ConsultationService(sl()));
sl.registerLazySingleton(() => CancelPlanService(sl()));
sl.registerLazySingleton(() => CreatePlanService(sl()));
+ sl.registerLazySingleton(() => NotificationsService(sl()));
// External
sl.registerLazySingleton(
- () => Dio(BaseOptions(baseUrl: baseUrl, headers: {'accept': 'application/json', 'content-type': 'application/json'}))..interceptors.add(TokenInterceptor()),
+ () => Dio(
+ BaseOptions(
+ baseUrl: baseUrl,
+ headers: {
+ 'accept': 'application/json',
+ 'content-type': 'application/json',
+ },
+ ),
+ )..interceptors.addAll(
+ [
+ TokenInterceptor(),
+ PhoneVerifyErrorInterceptor(),
+ ],
+ ),
);
sl.registerLazySingleton(() async => const FlutterSecureStorage());
}
diff --git a/lib/core/models/pagination_model.dart b/lib/core/models/pagination_model.dart
index 36f21ed7..947e2f9d 100644
--- a/lib/core/models/pagination_model.dart
+++ b/lib/core/models/pagination_model.dart
@@ -4,7 +4,7 @@ part 'pagination_model.freezed.dart';
part 'pagination_model.g.dart';
@freezed
-class Links with _$Links {
+abstract class Links with _$Links {
const factory Links({
@JsonKey(name: "first") required String first,
@JsonKey(name: "last") required String last,
@@ -16,7 +16,7 @@ class Links with _$Links {
}
@freezed
-class Meta with _$Meta {
+abstract class Meta with _$Meta {
const factory Meta({
@JsonKey(name: "current_page") required int currentPage,
@JsonKey(name: "from") required dynamic from,
@@ -34,7 +34,7 @@ class Meta with _$Meta {
}
@freezed
-class Link with _$Link {
+abstract class Link with _$Link {
const factory Link({
@JsonKey(name: "url") String? url,
@JsonKey(name: "label") String? label,
diff --git a/lib/core/websockets/ws_manager.dart b/lib/core/websockets/ws_manager.dart
index 3a64ff14..ce47f26a 100644
--- a/lib/core/websockets/ws_manager.dart
+++ b/lib/core/websockets/ws_manager.dart
@@ -18,8 +18,7 @@ class WsManager {
PrivateChannel? _privateDirectChatChannel;
Stream? get newMessagesStream => _privateMessagesChannel?.bind('App\\Events\\ChatMessageUpdated');
-
- // TODO: change name of event to a right one
+
Stream? get newNotificationsStream => _privateNotificationChannel?.bind('Illuminate\\Notifications\\Events\\BroadcastNotificationCreated');
Stream? get directChatStream => _privateDirectChatChannel?.bind('App\\Events\\ChatMessageUpdated');
diff --git a/lib/core/widgets/custom_popup.dart b/lib/core/widgets/custom_popup.dart
index 837c165b..67d87da5 100644
--- a/lib/core/widgets/custom_popup.dart
+++ b/lib/core/widgets/custom_popup.dart
@@ -6,7 +6,9 @@ import 'package:eatvio_app/core/utils/toasts.dart';
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart';
+import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart';
import 'package:eatvio_app/features/create_recipe/presentation/pages/recipe_create_screen.dart';
+import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
import 'package:eatvio_app/features/feed/models/recipes_model.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
@@ -28,6 +30,7 @@ class CustomPopup extends StatelessWidget {
final int? id;
final FeedBlogPostModel? feedBlogPostModel;
final Recipe? recipe;
+ final Diet? diet;
const CustomPopup({
super.key,
@@ -38,6 +41,7 @@ class CustomPopup extends StatelessWidget {
this.slug,
this.feedBlogPostModel,
this.recipe,
+ this.diet,
});
@override
@@ -87,18 +91,25 @@ class CustomPopup extends StatelessWidget {
});
addItem('assets/icons/share2.svg', 'Поделиться', () {
final box = context.findRenderObject() as RenderBox?;
- Share.shareUri(
- Uri.parse(
- '$baseUrl/ru/$path',
+ SharePlus.instance.share(
+ ShareParams(
+ uri: Uri.parse(
+ '$baseUrl/ru/$path',
+ ),
+ sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
),
- sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
);
});
- addItem('assets/icons/edit_paint.svg', 'Редактировать', () {
+ addItem('assets/icons/edit_paint.svg', 'Редактировать', () async {
if (complainedContentType == ComplainedContent.posts) {
GoRouter.of(context).pushNamed('blogPostCreateScreen', extra: feedBlogPostModel);
} else if (complainedContentType == ComplainedContent.recipe) {
GoRouter.of(context).pushNamed(RecipeCreateScreen.name, extra: recipe);
+ } else if (complainedContentType == ComplainedContent.diet) {
+ await showErrorDialog(context,
+ title: 'Предупреждение', description: 'Диета будет перенесена в архив. Вы создаете новую диету на основе существующей.');
+ await sl().unpublishDiet(id!);
+ GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: diet);
} else {
showInfoToast('В разработке');
return;
@@ -161,11 +172,13 @@ class CustomPopup extends StatelessWidget {
});
addItem('assets/icons/share2.svg', 'Поделиться', () {
final box = context.findRenderObject() as RenderBox?;
- Share.shareUri(
- Uri.parse(
- '$baseUrl/ru/$path',
+ SharePlus.instance.share(
+ ShareParams(
+ uri: Uri.parse(
+ '$baseUrl/ru/$path',
+ ),
+ sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
),
- sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
);
});
addItem('assets/icons/complain.svg', 'Пожаловаться', () {
diff --git a/lib/core/widgets/show_error_dialog.dart b/lib/core/widgets/show_error_dialog.dart
index a064538c..9685ad14 100644
--- a/lib/core/widgets/show_error_dialog.dart
+++ b/lib/core/widgets/show_error_dialog.dart
@@ -5,8 +5,8 @@ import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
-void showErrorDialog(BuildContext context, {String? title, String? description}) {
- showDialog(
+Future showErrorDialog(BuildContext context, {String? title, String? description}) async {
+ return await showDialog(
context: context,
barrierColor: Colors.transparent,
builder: (BuildContext context) {
diff --git a/lib/features/auth/models/credentials_model.dart b/lib/features/auth/models/credentials_model.dart
index c5c02ca4..04fa0381 100644
--- a/lib/features/auth/models/credentials_model.dart
+++ b/lib/features/auth/models/credentials_model.dart
@@ -5,7 +5,7 @@ part 'credentials_model.freezed.dart';
part 'credentials_model.g.dart';
@freezed
-class CredentialsModel with _$CredentialsModel {
+abstract class CredentialsModel with _$CredentialsModel {
const factory CredentialsModel({
required String email,
required String password,
diff --git a/lib/features/auth/models/token_model.dart b/lib/features/auth/models/token_model.dart
index ca352260..0f9e8f9f 100644
--- a/lib/features/auth/models/token_model.dart
+++ b/lib/features/auth/models/token_model.dart
@@ -5,7 +5,7 @@ part 'token_model.freezed.dart';
part 'token_model.g.dart';
@freezed
-class TokenModel with _$TokenModel {
+abstract class TokenModel with _$TokenModel {
const factory TokenModel({
required String token,
}) = _TokenModel;
diff --git a/lib/features/auth/presentation/bloc/auth_state.dart b/lib/features/auth/presentation/bloc/auth_state.dart
index 994ec3a0..364a8659 100644
--- a/lib/features/auth/presentation/bloc/auth_state.dart
+++ b/lib/features/auth/presentation/bloc/auth_state.dart
@@ -3,7 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'auth_state.freezed.dart';
@freezed
-class AuthState with _$AuthState {
+abstract class AuthState with _$AuthState {
const factory AuthState() = _AuthState;
const factory AuthState.loading() = AuthStateLoading;
diff --git a/lib/features/auth/presentation/pages/auth_screen.dart b/lib/features/auth/presentation/pages/auth_screen.dart
index cbd82a44..8c068755 100644
--- a/lib/features/auth/presentation/pages/auth_screen.dart
+++ b/lib/features/auth/presentation/pages/auth_screen.dart
@@ -119,7 +119,7 @@ class _AuthScreenState extends State {
children: [
const Text('Нет аккаунта? '),
GestureDetector(
- onTap: () => GoRouter.of(context).goNamed('webViewRegistrationScreen'),
+ onTap: () => GoRouter.of(context).goNamed('registrationScreen'),
child: Text(
'Зарегистрироваться',
style: TextStyle(
diff --git a/lib/features/blog_post/presentation/pages/blog_post_screen.dart b/lib/features/blog_post/presentation/pages/blog_post_screen.dart
index e963a812..fe3e7bda 100644
--- a/lib/features/blog_post/presentation/pages/blog_post_screen.dart
+++ b/lib/features/blog_post/presentation/pages/blog_post_screen.dart
@@ -242,9 +242,11 @@ class _BlogPostScreenState extends State {
icon: Icons.reply_rounded,
onTap: () {
final box = context.findRenderObject() as RenderBox?;
- Share.shareUri(
- Uri.parse('$baseUrl/ru/blog_post/${widget.blogPost.id}'),
- sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
+ SharePlus.instance.share(
+ ShareParams(
+ uri: Uri.parse('$baseUrl/ru/blog_post/${widget.blogPost.id}'),
+ sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
+ ),
);
},
),
diff --git a/lib/features/blog_post_create/models/blog_post_create_credentials_model.dart b/lib/features/blog_post_create/models/blog_post_create_credentials_model.dart
index ab3111c3..35c12538 100644
--- a/lib/features/blog_post_create/models/blog_post_create_credentials_model.dart
+++ b/lib/features/blog_post_create/models/blog_post_create_credentials_model.dart
@@ -5,7 +5,7 @@ part '../../../presentation/feed/blog_post_create_screen/models/blog_post_create
part '../../../presentation/feed/blog_post_create_screen/models/blog_post_create_credentials_model.g.dart';
@freezed
-class BlogPostCreateCredentialsModel with _$BlogPostCreateCredentialsModel {
+abstract class BlogPostCreateCredentialsModel with _$BlogPostCreateCredentialsModel {
const factory BlogPostCreateCredentialsModel({
required String title,
required String description,
diff --git a/lib/features/calendar/models/calendar_model.dart b/lib/features/calendar/models/calendar_model.dart
index 26eabe15..40e31ffb 100644
--- a/lib/features/calendar/models/calendar_model.dart
+++ b/lib/features/calendar/models/calendar_model.dart
@@ -5,7 +5,7 @@ part 'calendar_model.freezed.dart';
part 'calendar_model.g.dart';
@freezed
-class CalendarModel with _$CalendarModel {
+abstract class CalendarModel with _$CalendarModel {
const factory CalendarModel({
required String date,
@JsonKey(name: 'is_current_day_included_in_the_chosen_diet_progression') required bool isCurrentDayIncludedInTheChosenDietProgression,
diff --git a/lib/features/cancel_plan_bottom_sheet/cubit/cancel_plan_state.dart b/lib/features/cancel_plan_bottom_sheet/cubit/cancel_plan_state.dart
index 3c5b52d7..917ccadf 100644
--- a/lib/features/cancel_plan_bottom_sheet/cubit/cancel_plan_state.dart
+++ b/lib/features/cancel_plan_bottom_sheet/cubit/cancel_plan_state.dart
@@ -3,7 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'cancel_plan_state.freezed.dart';
@freezed
-class CancelPlanState with _$CancelPlanState {
+abstract class CancelPlanState with _$CancelPlanState {
factory CancelPlanState() = _CancelPlanState;
}
\ No newline at end of file
diff --git a/lib/features/cancel_plan_bottom_sheet/models/cancelation_model.dart b/lib/features/cancel_plan_bottom_sheet/models/cancelation_model.dart
index 0ddfa748..2b50f4c1 100644
--- a/lib/features/cancel_plan_bottom_sheet/models/cancelation_model.dart
+++ b/lib/features/cancel_plan_bottom_sheet/models/cancelation_model.dart
@@ -4,7 +4,7 @@ part 'cancelation_model.freezed.dart';
part 'cancelation_model.g.dart';
@freezed
-class CancelationModel with _$CancelationModel {
+abstract class CancelationModel with _$CancelationModel {
factory CancelationModel({
required String description,
required int price,
diff --git a/lib/features/chat/models/chat_message_model.dart b/lib/features/chat/models/chat_message_model.dart
index 591e5993..7224912a 100644
--- a/lib/features/chat/models/chat_message_model.dart
+++ b/lib/features/chat/models/chat_message_model.dart
@@ -5,7 +5,7 @@ part 'chat_message_model.freezed.dart';
part 'chat_message_model.g.dart';
@freezed
-class ChatMessageModel with _$ChatMessageModel {
+abstract class ChatMessageModel with _$ChatMessageModel {
const factory ChatMessageModel({
required int id,
required String data,
diff --git a/lib/features/chat/models/chat_messages_model.dart b/lib/features/chat/models/chat_messages_model.dart
index 999f598e..aa7c03ee 100644
--- a/lib/features/chat/models/chat_messages_model.dart
+++ b/lib/features/chat/models/chat_messages_model.dart
@@ -6,7 +6,7 @@ part 'chat_messages_model.freezed.dart';
part 'chat_messages_model.g.dart';
@freezed
-class ChatMessagesModel with _$ChatMessagesModel {
+abstract class ChatMessagesModel with _$ChatMessagesModel {
const factory ChatMessagesModel({
@JsonKey(name: 'data') required List messagesList,
required ChatMetaModel meta,
diff --git a/lib/features/chat/models/chat_meta_model.dart b/lib/features/chat/models/chat_meta_model.dart
index b1e68a41..60a61b48 100644
--- a/lib/features/chat/models/chat_meta_model.dart
+++ b/lib/features/chat/models/chat_meta_model.dart
@@ -4,7 +4,7 @@ part 'chat_meta_model.freezed.dart';
part 'chat_meta_model.g.dart';
@freezed
-class ChatMetaModel with _$ChatMetaModel {
+abstract class ChatMetaModel with _$ChatMetaModel {
const factory ChatMetaModel({
@JsonKey(name: "last_page") required int lastPage,
}) = _ChatMetaModel;
diff --git a/lib/features/chat/models/chat_room_model.dart b/lib/features/chat/models/chat_room_model.dart
index 73daf1be..d7bf450a 100644
--- a/lib/features/chat/models/chat_room_model.dart
+++ b/lib/features/chat/models/chat_room_model.dart
@@ -7,7 +7,7 @@ part 'chat_room_model.freezed.dart';
part 'chat_room_model.g.dart';
@freezed
-class ChatRoomModel with _$ChatRoomModel {
+abstract class ChatRoomModel with _$ChatRoomModel {
const factory ChatRoomModel({
required String id,
@JsonKey(name: 'chat_room_setting') required ChatRoomSettingsModel chatRoomSettings,
@@ -20,7 +20,7 @@ class ChatRoomModel with _$ChatRoomModel {
}
@freezed
-class Users with _$Users {
+abstract class Users with _$Users {
const factory Users({
@JsonKey(name: 'from_chat_user') required ChatUserModel sender,
diff --git a/lib/features/chat/models/chat_room_pagination_model.dart b/lib/features/chat/models/chat_room_pagination_model.dart
index 2d7e875d..7bb8ceb5 100644
--- a/lib/features/chat/models/chat_room_pagination_model.dart
+++ b/lib/features/chat/models/chat_room_pagination_model.dart
@@ -6,7 +6,7 @@ part 'chat_room_pagination_model.freezed.dart';
part 'chat_room_pagination_model.g.dart';
@freezed
-class ChatRoomPaginationModel with _$ChatRoomPaginationModel {
+abstract class ChatRoomPaginationModel with _$ChatRoomPaginationModel {
const factory ChatRoomPaginationModel({
@JsonKey(name: "chatRooms") required ChatRooms chatRooms,
@JsonKey(name: "number_of_unread_chat_rooms") required int unreadChatsCount,
@@ -16,7 +16,7 @@ class ChatRoomPaginationModel with _$ChatRoomPaginationModel {
}
@freezed
-class ChatRooms with _$ChatRooms {
+abstract class ChatRooms with _$ChatRooms {
const factory ChatRooms({
@JsonKey(name: "data") required List data,
@JsonKey(name: "last_page") required int lastPage,
@@ -27,7 +27,7 @@ class ChatRooms with _$ChatRooms {
}
@freezed
-class ChatRoom with _$ChatRoom {
+abstract class ChatRoom with _$ChatRoom {
const factory ChatRoom({
@JsonKey(name: "id") required String id,
@JsonKey(name: "room_name") required String roomName,
@@ -48,7 +48,7 @@ ChatMessageModel? parseLastMessage(dynamic json) {
}
@freezed
-class Users with _$Users {
+abstract class Users with _$Users {
const factory Users({
@JsonKey(name: "from_chat_user") required ChatUser fromChatUser,
@JsonKey(name: "to_chat_user") required ChatUser toChatUser,
@@ -58,7 +58,7 @@ class Users with _$Users {
}
@freezed
-class ChatUser with _$ChatUser {
+abstract class ChatUser with _$ChatUser {
const factory ChatUser({
@JsonKey(name: "id") required int id,
@JsonKey(name: "name") required String name,
diff --git a/lib/features/chat/models/chat_room_settings_model.dart b/lib/features/chat/models/chat_room_settings_model.dart
index de41f221..5298d3d9 100644
--- a/lib/features/chat/models/chat_room_settings_model.dart
+++ b/lib/features/chat/models/chat_room_settings_model.dart
@@ -4,7 +4,7 @@ part 'chat_room_settings_model.freezed.dart';
part 'chat_room_settings_model.g.dart';
@freezed
-class ChatRoomSettingsModel with _$ChatRoomSettingsModel {
+abstract class ChatRoomSettingsModel with _$ChatRoomSettingsModel {
const factory ChatRoomSettingsModel({
required int id,
@JsonKey(name: 'room_name') required String roomName,
diff --git a/lib/features/chat/models/chat_user_model.dart b/lib/features/chat/models/chat_user_model.dart
index b68c11ad..14feb316 100644
--- a/lib/features/chat/models/chat_user_model.dart
+++ b/lib/features/chat/models/chat_user_model.dart
@@ -4,7 +4,7 @@ part 'chat_user_model.freezed.dart';
part 'chat_user_model.g.dart';
@freezed
-class ChatUserModel with _$ChatUserModel {
+abstract class ChatUserModel with _$ChatUserModel {
const factory ChatUserModel({
required int id,
required String name,
diff --git a/lib/features/chat/models/payment_model.dart b/lib/features/chat/models/payment_model.dart
index 746c095a..e2c5fbba 100644
--- a/lib/features/chat/models/payment_model.dart
+++ b/lib/features/chat/models/payment_model.dart
@@ -4,7 +4,7 @@ part 'payment_model.freezed.dart';
part 'payment_model.g.dart';
@freezed
-class PaymentModel with _$PaymentModel {
+abstract class PaymentModel with _$PaymentModel {
factory PaymentModel({
@JsonKey(name: 'checkout_url') required String paymentUrl,
diff --git a/lib/features/chat/models/plan_complain_model.dart b/lib/features/chat/models/plan_complain_model.dart
index 63e2af8e..d4c11f7b 100644
--- a/lib/features/chat/models/plan_complain_model.dart
+++ b/lib/features/chat/models/plan_complain_model.dart
@@ -4,7 +4,7 @@ part 'plan_complain_model.freezed.dart';
part 'plan_complain_model.g.dart';
@freezed
-class PlanComplainModel with _$PlanComplainModel {
+abstract class PlanComplainModel with _$PlanComplainModel {
factory PlanComplainModel({
@JsonKey(name: 'description') required String description,
diff --git a/lib/features/chat/models/websocket_info_model.dart b/lib/features/chat/models/websocket_info_model.dart
index ed6167a0..2681626b 100644
--- a/lib/features/chat/models/websocket_info_model.dart
+++ b/lib/features/chat/models/websocket_info_model.dart
@@ -4,7 +4,7 @@ part 'websocket_info_model.freezed.dart';
part 'websocket_info_model.g.dart';
@freezed
-class WebsocketInfoModel with _$WebsocketInfoModel {
+abstract class WebsocketInfoModel with _$WebsocketInfoModel {
const factory WebsocketInfoModel({
required String key,
required String host,
diff --git a/lib/features/chat/presentation/bloc/chats_cubit/chats_state.dart b/lib/features/chat/presentation/bloc/chats_cubit/chats_state.dart
index 700542d0..ca83eb4c 100644
--- a/lib/features/chat/presentation/bloc/chats_cubit/chats_state.dart
+++ b/lib/features/chat/presentation/bloc/chats_cubit/chats_state.dart
@@ -5,7 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'chats_state.freezed.dart';
@freezed
-class ChatsState with _$ChatsState {
+abstract class ChatsState with _$ChatsState {
factory ChatsState({
@Default(BaseState.initial) BaseState state,
diff --git a/lib/features/complaining/models/complain_model.dart b/lib/features/complaining/models/complain_model.dart
index aa7be75f..34a8d91a 100644
--- a/lib/features/complaining/models/complain_model.dart
+++ b/lib/features/complaining/models/complain_model.dart
@@ -4,7 +4,7 @@ part 'complain_model.freezed.dart';
part 'complain_model.g.dart';
@freezed
-class ComplainModel with _$ComplainModel {
+abstract class ComplainModel with _$ComplainModel {
const factory ComplainModel({
@Default(null) String? description,
diff --git a/lib/features/complaining/presentation/cubit/complaining_state.dart b/lib/features/complaining/presentation/cubit/complaining_state.dart
index 1f3e69a2..95c5e761 100644
--- a/lib/features/complaining/presentation/cubit/complaining_state.dart
+++ b/lib/features/complaining/presentation/cubit/complaining_state.dart
@@ -6,7 +6,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'complaining_state.freezed.dart';
@freezed
-class ComplainingState with _$ComplainingState {
+abstract class ComplainingState with _$ComplainingState {
factory ComplainingState({
@Default(false) bool isLoading,
diff --git a/lib/features/consultant/become_consultant/models/consultant_profile_model.dart b/lib/features/consultant/become_consultant/models/consultant_profile_model.dart
index 2298d812..535b58fd 100644
--- a/lib/features/consultant/become_consultant/models/consultant_profile_model.dart
+++ b/lib/features/consultant/become_consultant/models/consultant_profile_model.dart
@@ -5,7 +5,7 @@ part 'consultant_profile_model.freezed.dart';
part 'consultant_profile_model.g.dart';
@freezed
-class ConsultantProfileModel with _$ConsultantProfileModel {
+abstract class ConsultantProfileModel with _$ConsultantProfileModel {
const factory ConsultantProfileModel({
@JsonKey(name: 'has_medical_education', includeIfNull: false) bool? hasMedicalEducation,
@JsonKey(name: 'social_links', includeIfNull: false) SocialLinksModel? socialLinks,
@@ -17,7 +17,7 @@ class ConsultantProfileModel with _$ConsultantProfileModel {
}
@freezed
-class SocialLinksModel with _$SocialLinksModel {
+abstract class SocialLinksModel with _$SocialLinksModel {
const factory SocialLinksModel({
@JsonKey(name: 'vk_link', includeIfNull: false) String? vkLink,
@JsonKey(name: 'tg_link', includeIfNull: false) String? tgLink,
@@ -30,7 +30,7 @@ class SocialLinksModel with _$SocialLinksModel {
}
@freezed
-class CertificatesModel with _$CertificatesModel {
+abstract class CertificatesModel with _$CertificatesModel {
const factory CertificatesModel({
required String title,
required String date,
diff --git a/lib/features/consultant/become_consultant/models/consultation_request_model.dart b/lib/features/consultant/become_consultant/models/consultation_request_model.dart
index aa7377b1..1579fab5 100644
--- a/lib/features/consultant/become_consultant/models/consultation_request_model.dart
+++ b/lib/features/consultant/become_consultant/models/consultation_request_model.dart
@@ -6,7 +6,7 @@ part 'consultation_request_model.freezed.dart';
part 'consultation_request_model.g.dart';
@freezed
-class ConsultationRequestModel with _$ConsultationRequestModel {
+abstract class ConsultationRequestModel with _$ConsultationRequestModel {
const factory ConsultationRequestModel({
@JsonKey(name: 'rating_place') required int ratingPlace,
@JsonKey(name: 'education_resource') required EducationModel educationModel,
@@ -17,7 +17,7 @@ class ConsultationRequestModel with _$ConsultationRequestModel {
}
@freezed
-class CertPhotosModel with _$CertPhotosModel {
+abstract class CertPhotosModel with _$CertPhotosModel {
const factory CertPhotosModel({
required String url,
}) = _CertPhotosModel;
diff --git a/lib/features/consultant_rating/models/rating_model.dart b/lib/features/consultant_rating/models/rating_model.dart
index fbd4fe74..164008dd 100644
--- a/lib/features/consultant_rating/models/rating_model.dart
+++ b/lib/features/consultant_rating/models/rating_model.dart
@@ -4,7 +4,7 @@ part 'rating_model.freezed.dart';
part 'rating_model.g.dart';
@freezed
-class RatingModel with _$RatingModel {
+abstract class RatingModel with _$RatingModel {
factory RatingModel({
required DateTime date,
diff --git a/lib/features/consultations/models/consultation_model.dart b/lib/features/consultations/models/consultation_model.dart
index 4c9464bf..9c32736f 100644
--- a/lib/features/consultations/models/consultation_model.dart
+++ b/lib/features/consultations/models/consultation_model.dart
@@ -6,7 +6,7 @@ part 'consultation_model.freezed.dart';
part 'consultation_model.g.dart';
@freezed
-class ConsultationModel with _$ConsultationModel {
+abstract class ConsultationModel with _$ConsultationModel {
factory ConsultationModel({
required int id,
@JsonKey(name: 'last_state') required ChosenPlanStateEnum chosenPlanState,
@@ -26,7 +26,7 @@ class ConsultationModel with _$ConsultationModel {
}
@freezed
-class DiaryModel with _$DiaryModel {
+abstract class DiaryModel with _$DiaryModel {
factory DiaryModel({
required int id,
required DiaryStateEnum state,
@@ -58,7 +58,7 @@ enum DiaryStateEnum {
}
@freezed
-class ConsultationPaginationModel with _$ConsultationPaginationModel {
+abstract class ConsultationPaginationModel with _$ConsultationPaginationModel {
factory ConsultationPaginationModel({required List data}) = _ConsultationPaginationModel;
factory ConsultationPaginationModel.fromJson(Map json) => _$ConsultationPaginationModelFromJson(json);
diff --git a/lib/features/consultations/presentation/cubit/consultations_state.dart b/lib/features/consultations/presentation/cubit/consultations_state.dart
index e4988f03..30b9b009 100644
--- a/lib/features/consultations/presentation/cubit/consultations_state.dart
+++ b/lib/features/consultations/presentation/cubit/consultations_state.dart
@@ -5,7 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'consultations_state.freezed.dart';
@freezed
-class ConsultationsState with _$ConsultationsState {
+abstract class ConsultationsState with _$ConsultationsState {
factory ConsultationsState({
@Default(BaseState.initial) BaseState state,
diff --git a/lib/features/create_diet/models/create_diet_model.dart b/lib/features/create_diet/models/create_diet_model.dart
index 49f1b752..cab10faf 100644
--- a/lib/features/create_diet/models/create_diet_model.dart
+++ b/lib/features/create_diet/models/create_diet_model.dart
@@ -5,7 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'create_diet_model.freezed.dart';
@freezed
-class CreateDietModel with _$CreateDietModel {
+abstract class CreateDietModel with _$CreateDietModel {
const CreateDietModel._();
const factory CreateDietModel({
diff --git a/lib/features/create_diet/presentation/create_diet_screen.dart b/lib/features/create_diet/presentation/create_diet_screen.dart
index 48d1d27e..f0f729d4 100644
--- a/lib/features/create_diet/presentation/create_diet_screen.dart
+++ b/lib/features/create_diet/presentation/create_diet_screen.dart
@@ -27,8 +27,11 @@ import 'package:go_router/go_router.dart';
class CreateDietScreen extends StatelessWidget {
static const name = 'createDietScreen';
static const path = '/create-diet-screen';
+
const CreateDietScreen({super.key, this.diet});
+
final Diet? diet;
+
@override
Widget build(BuildContext context) {
return BlocProvider(
@@ -40,6 +43,7 @@ class CreateDietScreen extends StatelessWidget {
class CreateDietScreenContent extends StatefulWidget {
const CreateDietScreenContent({super.key, this.diet});
+
final Diet? diet;
@override
@@ -95,7 +99,7 @@ class _CreateDietScreenContentState extends State {
appBar: AppBar(
centerTitle: true,
title: Text(
- widget.diet != null ? 'Редактирование диеты' : s.create_diet,
+ s.create_diet,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
softWrap: true,
@@ -151,7 +155,7 @@ class _CreateDietScreenContentState extends State {
const SizedBox(height: 12),
const DietDurationDropDownWidget(),
const SizedBox(height: 12),
- const StatusDropDownWidget(),
+ StatusDropDownWidget(dietState: widget.diet?.state),
const SizedBox(height: 16),
const DietTypeChoiceWidget(),
const SizedBox(height: 16),
@@ -247,23 +251,13 @@ class _CreateDietScreenContentState extends State {
else
CustomOutlinedButton(
onPressed: () async {
- if (widget.diet != null) {
- final result = await context.read().updateDiet(
- widget.diet!.id,
- );
- if (result == 'error') {
- if (!context.mounted) return;
- showErrorDialog(context, title: '${s.could_not_update_diet} ${state.dietData.name}');
- }
- } else {
- final result = await context.read().createDiet();
- if (result == 'error') {
- if (!context.mounted) return;
- showErrorDialog(context, title: '${s.could_not_publish_diet} ${state.dietData.name}');
- }
+ final result = await context.read().createDiet();
+ if (result == 'error') {
+ if (!context.mounted) return;
+ showErrorDialog(context, title: '${s.could_not_publish_diet} ${state.dietData.name}');
}
},
- text: widget.diet != null ? s.save : s.publish,
+ text: s.publish,
height: 52,
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
buttonStyle: ButtonStyle(
diff --git a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart
index 820d36b7..8e0d4a8b 100644
--- a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart
+++ b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart
@@ -12,6 +12,8 @@ import 'package:eatvio_app/features/glossary/repositories/glossary_repository.da
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
+import 'package:http/http.dart' as http;
+import 'package:path_provider/path_provider.dart';
class CreateDietCubit extends Cubit {
final CreateDietRepository createDietRepository;
@@ -319,18 +321,38 @@ class CreateDietCubit extends Cubit {
return diet;
}
+ Future downloadImageAsFile(String imageUrl) async {
+ final response = await http.get(Uri.parse(imageUrl));
+
+ if (response.statusCode == 200) {
+ final tempDir = await getTemporaryDirectory();
+ final filePath = '${tempDir.path}/${imageUrl.split('/').last}';
+ final file = File(filePath);
+ return await file.writeAsBytes(response.bodyBytes);
+ } else {
+ throw Exception('Не удалось загрузить изображение');
+ }
+ }
+
Future createDiet() async {
emit(state.copyWith(isDietPublishing: true));
if (!_isFromValid()) return 'validation';
try {
- final image = await ImageCompressUtility.compressFile(File(state.dietData.image!.path));
+ File? file;
+ if (state.dietData.imageUrl != null) {
+ file = await downloadImageAsFile(state.dietData.imageUrl!);
+ }
+ File? image;
+ if (state.dietData.image?.path != null) {
+ image = await ImageCompressUtility.compressFile(File(state.dietData.image!.path));
+ }
final dietState = state.dietData.state!;
final dailySchedule = state.dietData.dailySchedule;
await createDietRepository.createDiet(
name: state.dietData.name ?? '',
duration: state.dietData.duration ?? 7,
state: dietState,
- image: image,
+ image: image ?? file!,
meatType: state.dietData.type['meat'] == true ? '1' : '0',
carbType: state.dietData.type['carb'] == true ? '1' : '0',
vegType: state.dietData.type['veg'] == true ? '1' : '0',
diff --git a/lib/features/create_diet/presentation/cubit/create_diet_state.dart b/lib/features/create_diet/presentation/cubit/create_diet_state.dart
index 8e97a087..dc280baa 100644
--- a/lib/features/create_diet/presentation/cubit/create_diet_state.dart
+++ b/lib/features/create_diet/presentation/cubit/create_diet_state.dart
@@ -6,7 +6,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'create_diet_state.freezed.dart';
@freezed
-class CreateDietState with _$CreateDietState {
+abstract class CreateDietState with _$CreateDietState {
const factory CreateDietState({
required bool isLoading,
required bool isDietPublishing,
diff --git a/lib/features/create_diet/presentation/widgets/diet_image_picker_widget.dart b/lib/features/create_diet/presentation/widgets/diet_image_picker_widget.dart
index dd0e44aa..c6250bb4 100644
--- a/lib/features/create_diet/presentation/widgets/diet_image_picker_widget.dart
+++ b/lib/features/create_diet/presentation/widgets/diet_image_picker_widget.dart
@@ -127,11 +127,12 @@ class _DietImagePickerWidgetState extends State {
: Stack(
children: [
DottedBorder(
- stackFit: StackFit.expand,
- dashPattern: const [14, 14],
- color: state.dietImageError != null ? appTheme.red : appTheme.dottedBorder,
- borderType: BorderType.RRect,
- radius: const Radius.circular(12),
+ options: RoundedRectDottedBorderOptions(
+ stackFit: StackFit.expand,
+ dashPattern: const [14, 14],
+ color: state.dietImageError != null ? appTheme.red : appTheme.dottedBorder,
+ radius: const Radius.circular(12),
+ ),
child: const SizedBox.expand(),
),
Center(
diff --git a/lib/features/create_diet/presentation/widgets/status_drop_down_widget.dart b/lib/features/create_diet/presentation/widgets/status_drop_down_widget.dart
index 75b30b59..249e897a 100644
--- a/lib/features/create_diet/presentation/widgets/status_drop_down_widget.dart
+++ b/lib/features/create_diet/presentation/widgets/status_drop_down_widget.dart
@@ -11,7 +11,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:collection/collection.dart';
class StatusDropDownWidget extends StatefulWidget {
- const StatusDropDownWidget({super.key});
+ final DietState? dietState;
+
+ const StatusDropDownWidget({super.key, this.dietState});
@override
State createState() => _StatusDropDownWidgetState();
@@ -19,6 +21,7 @@ class StatusDropDownWidget extends StatefulWidget {
class _StatusDropDownWidgetState extends State {
final List dietStateTitles = [];
+ String? currentState;
// late final List dietStates = DietState.values;
@override
@@ -39,6 +42,13 @@ class _StatusDropDownWidgetState extends State {
// }
// }
}
+ if (widget.dietState != null) {
+ if (widget.dietState == DietState.active) {
+ currentState = dietStateTitles[0];
+ } else if (widget.dietState == DietState.personal) {
+ currentState = dietStateTitles[1];
+ }
+ }
}
@override
@@ -77,7 +87,7 @@ class _StatusDropDownWidgetState extends State {
),
)
.toList(),
- value: state.dietState == DietState.active ? dietStateTitles[0] : state.dietState == DietState.personal ? dietStateTitles[1] : null,
+ value: currentState,
),
if (state.dietStateError != null) ...[
const SizedBox(
diff --git a/lib/features/create_plan/models/create_plan_model.dart b/lib/features/create_plan/models/create_plan_model.dart
index 4b85ffba..1d4d7854 100644
--- a/lib/features/create_plan/models/create_plan_model.dart
+++ b/lib/features/create_plan/models/create_plan_model.dart
@@ -1,7 +1,3 @@
-import 'dart:io';
-
-import 'package:dio/dio.dart';
-import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@@ -9,7 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'create_plan_model.freezed.dart';
@freezed
-class CreatePlanModel with _$CreatePlanModel {
+abstract class CreatePlanModel with _$CreatePlanModel {
const CreatePlanModel._();
const factory CreatePlanModel({
@@ -20,20 +16,5 @@ class CreatePlanModel with _$CreatePlanModel {
required List type,
XFile? image,
required List options,
- }) = _CreatePlanModel;
-
- Future