Compare commits

...

17 Commits

Author SHA1 Message Date
misha
a72c40d8ee Merge remote-tracking branch 'upstream/main' into personalDiets 2025-10-31 13:26:05 +03:00
misha
6ed7faed15 feat(personalDiets): addde base url from app config for consultation widget 2025-10-31 13:23:13 +03:00
misha
16fccaea8e Merge remote-tracking branch 'upstream/main' into personalDiets 2025-10-31 12:41:36 +03:00
Username1548
a723673d23 Merge branch 'main' of http://gitea.office.local:3000/eatvio/eatvio_app 2025-10-31 12:39:49 +03:00
Username1548
89f697f7a6 changed app version 2025-10-31 12:38:02 +03:00
d883c9e19a Merge pull request 'feat(marketing)' (#745) from misha/eatvio_app:issue-689 into main
Reviewed-on: eatvio/eatvio_app#745
2025-10-31 09:10:18 +00:00
misha
2e3172bc45 Merge remote-tracking branch 'upstream/main' into personalDiets 2025-10-24 13:21:03 +03:00
misha
46841fb502 feat(personalDiets): fixed PlanState widget in order to show personal diet state 2025-10-02 13:49:58 +03:00
misha
8e72350152 Merge remote-tracking branch 'upstream/main' into personalDiets 2025-10-02 12:25:40 +03:00
Username1548
8c2cd5eedd Merge remote-tracking branch 'upstream/main' into personalDiets 2025-09-05 11:28:51 +03:00
Username1548
996f2ecd70 Merge branch 'main' into personalDiets 2025-07-16 17:04:21 +07:00
Username1548
19787f459e feat(personalDiet): fixed wrong path for attach diet method 2025-07-16 17:03:46 +07:00
Username1548
7e64b24a8c added layout for suggestions page 2025-07-15 21:49:47 +07:00
Username1548
a07d085ba7 feat(personalDiets): preapared chats for consultations with personal diets 2025-07-14 20:24:40 +07:00
Username1548
5616bedd25 feat(personalDiets): diets suggestions 2025-07-14 13:44:44 +07:00
Username1548
0a3d9e577d Merge branch 'main' into personalDiets 2025-07-14 12:17:37 +07:00
Username1548
55e3abec99 feat(personal diets): added personal diet option to plans 2025-07-14 12:15:26 +07:00
31 changed files with 1066 additions and 169 deletions

View File

@@ -406,7 +406,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.2.3; MARKETING_VERSION = 1.3.3;
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app; PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044";
@@ -557,7 +557,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.2.3; MARKETING_VERSION = 1.3.3;
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app; PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044";
@@ -596,7 +596,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.2.3; MARKETING_VERSION = 1.3.3;
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app; PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044";

View File

@@ -21,7 +21,7 @@
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>81</string> <string>82</string>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
<false/> <false/>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>

View File

@@ -39,6 +39,7 @@ import 'package:eatvio_app/features/my_finance/presentation/cubit/user_cards_cub
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart'; import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart';
import 'package:eatvio_app/features/notifications/presentation/notifications_cubit/notifications_cubit.dart'; import 'package:eatvio_app/features/notifications/presentation/notifications_cubit/notifications_cubit.dart';
import 'package:eatvio_app/features/order_info/cubit/order_info_cubit.dart'; import 'package:eatvio_app/features/order_info/cubit/order_info_cubit.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart';
import 'package:eatvio_app/features/plans/presentation/cubit/about_plan_cubit.dart'; import 'package:eatvio_app/features/plans/presentation/cubit/about_plan_cubit.dart';
import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart' as profile_plans; import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart' as profile_plans;
import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart';
@@ -145,5 +146,6 @@ class CubitRegistrations {
sl.registerFactory<UserDetailsCubit>(() => UserDetailsCubit(profileRepository: sl())); sl.registerFactory<UserDetailsCubit>(() => UserDetailsCubit(profileRepository: sl()));
sl.registerFactory<MenuCubit>(() => MenuCubit(sl())); sl.registerFactory<MenuCubit>(() => MenuCubit(sl()));
sl.registerFactory<MarketingCubit>(() => MarketingCubit(sl())); sl.registerFactory<MarketingCubit>(() => MarketingCubit(sl()));
sl.registerFactory<PersonalDietSuggestionCubit>(() => PersonalDietSuggestionCubit(dietRepository: sl(), personalDietSuggestionService: sl()));
} }
} }

View File

@@ -23,6 +23,7 @@ import 'package:eatvio_app/features/my_diets/repositories/my_diets_repository.da
import 'package:eatvio_app/features/my_finance/repositories/cards_repository.dart'; import 'package:eatvio_app/features/my_finance/repositories/cards_repository.dart';
import 'package:eatvio_app/features/my_plans/repositories/my_diets_repository.dart'; import 'package:eatvio_app/features/my_plans/repositories/my_diets_repository.dart';
import 'package:eatvio_app/features/notifications/repository/notifications_repository.dart'; import 'package:eatvio_app/features/notifications/repository/notifications_repository.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/repository/personal_diet_suggestion_repository.dart';
import 'package:eatvio_app/features/plans/repositories/plan_repository.dart'; import 'package:eatvio_app/features/plans/repositories/plan_repository.dart';
import 'package:eatvio_app/features/plans/repositories/plans_repository.dart'; import 'package:eatvio_app/features/plans/repositories/plans_repository.dart';
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
@@ -68,6 +69,7 @@ class RepositoryRegistrations {
sl.registerLazySingleton<BlockedUsersRepository>(() => BlockedUsersRepository(blockedUserService: sl())); sl.registerLazySingleton<BlockedUsersRepository>(() => BlockedUsersRepository(blockedUserService: sl()));
sl.registerLazySingleton<CommentsRepository>(() => CommentsRepository(service: sl())); sl.registerLazySingleton<CommentsRepository>(() => CommentsRepository(service: sl()));
sl.registerLazySingleton<NotificationSettingsRepository>(() => NotificationSettingsRepository(sl())); sl.registerLazySingleton<NotificationSettingsRepository>(() => NotificationSettingsRepository(sl()));
sl.registerLazySingleton<PersonalDietSuggestionRepository>(() => PersonalDietSuggestionRepository(personalDietSuggestionService: sl()));
// Content repositories // Content repositories
sl.registerLazySingleton<BlogPostRepository>(() => BlogPostRepository(blogPostService: sl())); sl.registerLazySingleton<BlogPostRepository>(() => BlogPostRepository(blogPostService: sl()));

View File

@@ -25,6 +25,7 @@ import 'package:eatvio_app/features/my_diets/services/my_diets_service.dart';
import 'package:eatvio_app/features/my_finance/services/cards_service.dart'; import 'package:eatvio_app/features/my_finance/services/cards_service.dart';
import 'package:eatvio_app/features/my_plans/services/my_plans_service.dart'; import 'package:eatvio_app/features/my_plans/services/my_plans_service.dart';
import 'package:eatvio_app/features/notifications/service/notifications_service.dart'; import 'package:eatvio_app/features/notifications/service/notifications_service.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/services/personal_diet_suggestion_service.dart';
import 'package:eatvio_app/features/plans/services/plan_service.dart'; import 'package:eatvio_app/features/plans/services/plan_service.dart';
import 'package:eatvio_app/features/plans/services/plans_service.dart'; import 'package:eatvio_app/features/plans/services/plans_service.dart';
import 'package:eatvio_app/features/profile/services/profile_service.dart'; import 'package:eatvio_app/features/profile/services/profile_service.dart';
@@ -76,6 +77,7 @@ class ServiceRegistrations {
sl.registerLazySingleton<ConsultantRatingService>(() => ConsultantRatingService(sl())); sl.registerLazySingleton<ConsultantRatingService>(() => ConsultantRatingService(sl()));
sl.registerLazySingleton<NotificationSettingsService>(() => NotificationSettingsService(sl())); sl.registerLazySingleton<NotificationSettingsService>(() => NotificationSettingsService(sl()));
sl.registerLazySingleton<ViewsService>(() => ViewsService(sl())); sl.registerLazySingleton<ViewsService>(() => ViewsService(sl()));
sl.registerLazySingleton<PersonalDietSuggestionService>(() => PersonalDietSuggestionService(sl()));
// Content services // Content services
sl.registerLazySingleton<CreateRecipeService>(() => CreateRecipeService(sl())); sl.registerLazySingleton<CreateRecipeService>(() => CreateRecipeService(sl()));

View File

@@ -29,6 +29,7 @@ import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.
import 'package:eatvio_app/features/my_finance/presentation/pages/user_finance_screen.dart'; import 'package:eatvio_app/features/my_finance/presentation/pages/user_finance_screen.dart';
import 'package:eatvio_app/features/my_plans/presentation/my_plans_screen.dart'; import 'package:eatvio_app/features/my_plans/presentation/my_plans_screen.dart';
import 'package:eatvio_app/features/order_info/presentation/info_by_order_screen.dart'; import 'package:eatvio_app/features/order_info/presentation/info_by_order_screen.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/presentation/personal_diet_suggestion_screen.dart';
import 'package:eatvio_app/features/profile/models/profile_model.dart'; import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/features/profile/presentation/pages/profile_screen.dart'; import 'package:eatvio_app/features/profile/presentation/pages/profile_screen.dart';
import 'package:eatvio_app/features/profile/presentation/pages/subs_screen.dart'; import 'package:eatvio_app/features/profile/presentation/pages/subs_screen.dart';
@@ -239,6 +240,11 @@ class OtherRoutes {
return UserDiaryScreen(diaryId: diaryId, currentPlanDay: currentPlanDay); return UserDiaryScreen(diaryId: diaryId, currentPlanDay: currentPlanDay);
}, },
), ),
GoRoute(
path: PersonalDietSuggestionScreen.path,
name: PersonalDietSuggestionScreen.name,
builder: (context, state) => PersonalDietSuggestionScreen(dietId: state.extra as int,),
),
]; ];
} }
} }

View File

@@ -150,6 +150,8 @@ class PrimaryColors {
Color get green => const Color(0XFF0BB450); Color get green => const Color(0XFF0BB450);
Color get transparentGreen => const Color.fromARGB(12, 1, 154, 63);
// LightGreen // LightGreen
Color get lightGreen300 => const Color(0XFFB2DF8A); Color get lightGreen300 => const Color(0XFFB2DF8A);

View File

@@ -9,9 +9,10 @@ import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class OptionWidget extends StatelessWidget { class OptionWidget extends StatelessWidget {
const OptionWidget({super.key, required this.option, this.disableDuration = false}); const OptionWidget({super.key, required this.option, this.disableDuration = false, required this.duration});
final PacketOptions? option; final PacketOptions? option;
final bool disableDuration; final bool disableDuration;
final int duration;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (option == null) { if (option == null) {
@@ -34,8 +35,12 @@ class OptionWidget extends StatelessWidget {
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
if (!disableDuration) ...[ if (!disableDuration) ...[
const _OptionDurationWidget(duration: 7), _OptionDurationWidget(duration: duration),
const SizedBox(height: 16), SizedBox(height: option?.hasPersonalDiet ?? false ? 8 : 12),
],
if ((option?.hasPersonalDiet ?? false) && !disableDuration) ...[
const _OptionHasPersonalDietWidget(),
const SizedBox(height: 12),
], ],
const CustomDivider(), const CustomDivider(),
const SizedBox(height: 16), const SizedBox(height: 16),
@@ -52,7 +57,6 @@ class OptionWidget extends StatelessWidget {
} }
} }
class _OptionDurationWidget extends StatelessWidget { class _OptionDurationWidget extends StatelessWidget {
const _OptionDurationWidget({required this.duration}); const _OptionDurationWidget({required this.duration});
final int duration; final int duration;
@@ -92,3 +96,43 @@ class _OptionDurationWidget extends StatelessWidget {
); );
} }
} }
class _OptionHasPersonalDietWidget extends StatelessWidget {
const _OptionHasPersonalDietWidget();
@override
Widget build(BuildContext context) {
final s = S.of(context);
return Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(4), color: appTheme.transparentGreen),
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Container(
width: 4,
height: 20,
decoration: BoxDecoration(
color: appTheme.green,
borderRadius: const BorderRadius.only(
topRight: Radius.circular(100),
bottomRight: Radius.circular(100),
),
),
),
),
const SizedBox(
width: 12,
),
Text(
s.personalDietCreating,
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
),
const SizedBox(
width: 12,
),
],
),
);
}
}

View File

@@ -114,25 +114,6 @@ class _ChatScreenState extends State<ChatScreen> {
ChosenPlanStateEnum.statePendingPayment, ChosenPlanStateEnum.statePendingPayment,
ChosenPlanStateEnum.stateInCoordination, ChosenPlanStateEnum.stateInCoordination,
].contains(chosenPlan?.chosenPlanState); ].contains(chosenPlan?.chosenPlanState);
final showAboutOrderButton =
state.chatRoom.chosenPlan != null && state.chatRoom.chosenPlan!.chosenPlanState != ChosenPlanStateEnum.stateCanceledByTheInitiator;
BannerType? bannerType;
if (chosenPlan == null || chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateCanceledByTheInitiator) {
bannerType = null;
} else if (amIConsultant && !state.hasCard) {
bannerType = BannerType.card;
} else if (amIConsultant && chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateInCoordination) {
bannerType = BannerType.date;
} else if (!amIConsultant &&
(chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateStartDateHasBeenSet || chosenPlan.chosenPlanState == ChosenPlanStateEnum.statePendingPayment)) {
bannerType = BannerType.payment;
} else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateDone && amIConsultant) {
bannerType = BannerType.collectCharge;
} else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateLastDayFinished && !amIConsultant) {
bannerType = BannerType.finishPlan;
}
PacketOptions? chosenOption; PacketOptions? chosenOption;
if (chosenPlan?.optionType == 'options1') { if (chosenPlan?.optionType == 'options1') {
chosenOption = chosenPlan?.plan.packet1Options; chosenOption = chosenPlan?.plan.packet1Options;
@@ -141,6 +122,27 @@ class _ChatScreenState extends State<ChatScreen> {
} else if (chosenPlan?.optionType == 'options3') { } else if (chosenPlan?.optionType == 'options3') {
chosenOption = chosenPlan?.plan.packet3Options; chosenOption = chosenPlan?.plan.packet3Options;
} }
final showAboutOrderButton =
state.chatRoom.chosenPlan != null && state.chatRoom.chosenPlan!.chosenPlanState != ChosenPlanStateEnum.stateCanceledByTheInitiator;
BannerType? bannerType;
if (chosenPlan == null || chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateCanceledByTheInitiator) {
bannerType = null;
} else if (amIConsultant && !state.hasCard && chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateInCoordination) {
bannerType = BannerType.card;
} else if (amIConsultant && chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateInCoordination) {
bannerType = BannerType.date;
} else if (!amIConsultant &&
(chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateStartDateHasBeenSet || chosenPlan.chosenPlanState == ChosenPlanStateEnum.statePendingPayment)) {
bannerType = BannerType.payment;
} else if (chosenOption?.hasPersonalDiet == true && amIConsultant) {
bannerType = BannerType.setPersonalDiet;
} else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateDone && amIConsultant) {
bannerType = BannerType.collectCharge;
} else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateLastDayFinished && !amIConsultant) {
bannerType = BannerType.finishPlan;
}
return Scaffold( return Scaffold(
resizeToAvoidBottomInset: true, resizeToAvoidBottomInset: true,
appBar: AppBar( appBar: AppBar(
@@ -317,6 +319,7 @@ class _ChatScreenState extends State<ChatScreen> {
chosenPlanId: chosenPlan?.id, chosenPlanId: chosenPlan?.id,
planName: chosenPlan?.plan.name, planName: chosenPlan?.plan.name,
planPrice: chosenOption?.price.toDouble(), planPrice: chosenOption?.price.toDouble(),
hasPersonalDiet: chosenOption?.hasPersonalDiet ?? false,
), ),
), ),
], ],

View File

@@ -9,17 +9,28 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:flutter_svg/flutter_svg.dart';
class ChosePlanDateWidget extends StatefulWidget { class ChosePlanDateWidget extends StatefulWidget {
const ChosePlanDateWidget({super.key, required this.chatCubit}); const ChosePlanDateWidget({super.key, required this.chatCubit, required this.hasPersonalDiet});
final ChatRoomCubit chatCubit; final ChatRoomCubit chatCubit;
final bool hasPersonalDiet;
@override @override
State<ChosePlanDateWidget> createState() => _ChosePlanDateWidget(); State<ChosePlanDateWidget> createState() => _ChosePlanDateWidget();
} }
class _ChosePlanDateWidget extends State<ChosePlanDateWidget> { class _ChosePlanDateWidget extends State<ChosePlanDateWidget> {
final startDate = [DateTime.now()]; late final List<DateTime> startDate;
bool visible = false;
@override
void initState() {
super.initState();
if (widget.hasPersonalDiet) {
startDate = [DateTime.now().add(const Duration(days: 2))];
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final s = S.of(context); final s = S.of(context);
@@ -27,64 +38,129 @@ class _ChosePlanDateWidget extends State<ChosePlanDateWidget> {
if (widget.chatCubit.state is ChatRoomStateLoaded) { if (widget.chatCubit.state is ChatRoomStateLoaded) {
planName = (widget.chatCubit.state as ChatRoomStateLoaded).chatRoom.chosenPlan?.plan.name; planName = (widget.chatCubit.state as ChatRoomStateLoaded).chatRoom.chosenPlan?.plan.name;
} }
return Column( return GestureDetector(
mainAxisSize: MainAxisSize.min, child: Column(
children: [ mainAxisSize: MainAxisSize.min,
const SizedBox(height: 4), children: [
const BottomSheetHandlerBar(), const SizedBox(height: 4),
const SizedBox(height: 12), const BottomSheetHandlerBar(),
Text( const SizedBox(height: 12),
planName ?? '', Row(
style: TextStyles.headingXLSemibold.copyWith( mainAxisAlignment: MainAxisAlignment.center,
color: appTheme.black, crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
planName ?? '',
style: TextStyles.headingXLSemibold.copyWith(
color: appTheme.black,
),
),
if (widget.hasPersonalDiet) ...[
const SizedBox(
width: 8,
),
PortalTarget(
closeDuration: const Duration(milliseconds: 20),
anchor: const Aligned(
shiftToWithinBound: AxisFlag(x: true, y: true),
follower: Alignment.topRight,
target: Alignment.bottomLeft,
),
portalFollower: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: visible ? appTheme.whiteA700 : Colors.transparent,
boxShadow: visible
? [
BoxShadow(
color: appTheme.black900.withValues(alpha: 0.15),
blurRadius: 4,
offset: const Offset(0, 4),
),
]
: null,
),
child: AnimatedDefaultTextStyle(
style: TextStyles.textMMediumAuto.copyWith(
color: visible ? appTheme.black : Colors.transparent,
),
duration: const Duration(milliseconds: 300),
child: Text(
s.chosenPlanStartDateDescr,
),
),
),
),
child: GestureDetector(
onTap: () {
setState(() {
visible = !visible;
});
},
child: SvgPicture.asset(
'assets/icons/question_mark.svg',
width: 22,
height: 22,
colorFilter: ColorFilter.mode(
appTheme.blueA400,
BlendMode.srcIn,
),
),
),
)
]
],
), ),
), const SizedBox(height: 12),
const SizedBox(height: 12), Padding(
Padding( padding: const EdgeInsets.symmetric(horizontal: 25.0),
padding: const EdgeInsets.symmetric(horizontal: 25.0), child: Text(
child: Text( s.chose_plan_start_date_2,
s.chose_plan_start_date_2, textAlign: TextAlign.center,
textAlign: TextAlign.center, style: TextStyles.textMMedium.copyWith(
style: TextStyles.textMMedium.copyWith( color: appTheme.black,
color: appTheme.black, ),
), ),
), ),
), const SizedBox(height: 12),
const SizedBox(height: 12), const Padding(
const Padding( padding: EdgeInsets.symmetric(horizontal: 16.0),
padding: EdgeInsets.symmetric(horizontal: 16.0), child: CustomDivider(),
child: CustomDivider(), ),
), CalendarWidget(
CalendarWidget( startDate: startDate,
startDate: startDate, ),
), Padding(
Padding( padding: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28),
padding: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28), child: CustomOutlinedButton(
child: CustomOutlinedButton( onPressed: () async {
onPressed: () async { final result = await widget.chatCubit.choseStartPlanDate(startDate[0]);
final result = await widget.chatCubit.choseStartPlanDate(startDate[0]); if (result) {
if (result) { showSuccessToast('Дата установлена');
showSuccessToast('Дата установлена'); if (!context.mounted) return;
if (!context.mounted) return; Navigator.pop(context);
Navigator.pop(context); } else {
} else { showErrorToast('Не удалось установить дату');
showErrorToast('Не удалось установить дату'); if (!context.mounted) return;
if (!context.mounted) return; Navigator.pop(context);
Navigator.pop(context); }
} },
}, height: 60,
height: 60, text: s.confirm,
text: s.confirm, buttonTextStyle: TextStyles.textLSemibold.copyWith(
buttonTextStyle: TextStyles.textLSemibold.copyWith( color: appTheme.whiteA700,
color: appTheme.whiteA700, ),
), buttonStyle: ButtonStyle(
buttonStyle: ButtonStyle( backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), side: const WidgetStatePropertyAll(BorderSide.none),
side: const WidgetStatePropertyAll(BorderSide.none), ),
), ),
), ),
), ],
], ),
); );
} }
} }

View File

@@ -9,6 +9,7 @@ import 'package:eatvio_app/features/chat/presentation/pages/payment_screen.dart'
import 'package:eatvio_app/features/chat/presentation/widgets/chose_plan_date_widget.dart'; import 'package:eatvio_app/features/chat/presentation/widgets/chose_plan_date_widget.dart';
import 'package:eatvio_app/features/chat/presentation/widgets/complete_plan_bottom_sheet.dart'; import 'package:eatvio_app/features/chat/presentation/widgets/complete_plan_bottom_sheet.dart';
import 'package:eatvio_app/features/chat/presentation/widgets/plan_complain_bottom_sheet.dart'; import 'package:eatvio_app/features/chat/presentation/widgets/plan_complain_bottom_sheet.dart';
import 'package:eatvio_app/features/my_diets/presentation/my_diets_screen.dart';
import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart'; import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart';
import 'package:eatvio_app/generated/l10n.dart'; import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -17,12 +18,12 @@ import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
class NotificationBanner extends StatefulWidget { class NotificationBanner extends StatefulWidget {
const NotificationBanner({super.key, required this.bannerType, this.planPrice, this.planName, this.chosenPlanId}); const NotificationBanner({super.key, required this.bannerType, this.planPrice, this.planName, this.chosenPlanId, this.hasPersonalDiet = false});
final BannerType bannerType; final BannerType bannerType;
final double? planPrice; final double? planPrice;
final String? planName; final String? planName;
final int? chosenPlanId; final int? chosenPlanId;
final bool hasPersonalDiet;
@override @override
State<NotificationBanner> createState() => _NotificationBannerState(); State<NotificationBanner> createState() => _NotificationBannerState();
} }
@@ -68,7 +69,8 @@ class _NotificationBannerState extends State<NotificationBanner> {
BannerType.date => [ BannerType.date => [
SizedBox( SizedBox(
width: size.width * 0.6, width: size.width * 0.6,
child: Text(s.choose_plan_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)), child: Text(widget.hasPersonalDiet == true ? s.choose_plan_start_date_with_personal_diet : s.choose_plan_start_date,
style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
GestureDetector( GestureDetector(
@@ -78,6 +80,7 @@ class _NotificationBannerState extends State<NotificationBanner> {
context: context, context: context,
builder: (context) => ChosePlanDateWidget( builder: (context) => ChosePlanDateWidget(
chatCubit: cubit, chatCubit: cubit,
hasPersonalDiet: widget.hasPersonalDiet,
), ),
); );
}, },
@@ -155,6 +158,20 @@ class _NotificationBannerState extends State<NotificationBanner> {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
], ],
BannerType.setPersonalDiet => [
SizedBox(
width: size.width * 0.6,
child: Text(s.createPersonalDiet, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
),
const SizedBox(height: 12),
GestureDetector(
onTap: () {
GoRouter.of(context).pushNamed(MyDietsScreen.name);
},
child: Text(s.goToMyDiets, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
),
const SizedBox(height: 16),
],
}, },
), ),
), ),
@@ -242,4 +259,4 @@ class _StarIcon extends StatelessWidget {
} }
} }
enum BannerType { date, card, payment, collectCharge, finishPlan } enum BannerType { date, card, payment, collectCharge, finishPlan, setPersonalDiet }

View File

@@ -22,6 +22,7 @@ abstract class ConsultationModel with _$ConsultationModel {
@JsonKey(name: 'end_date', fromJson: parseDate) required DateTime endDate, @JsonKey(name: 'end_date', fromJson: parseDate) required DateTime endDate,
@JsonKey(name: 'consultant_id') required int consultantId, @JsonKey(name: 'consultant_id') required int consultantId,
required List<DiaryModel> diaries, required List<DiaryModel> diaries,
@JsonKey(name: 'personal_diet_id') required int? personalDietId,
}) = _ConsultationModel; }) = _ConsultationModel;
factory ConsultationModel.fromJson(Map<String, dynamic> json) => _$ConsultationModelFromJson(json); factory ConsultationModel.fromJson(Map<String, dynamic> json) => _$ConsultationModelFromJson(json);

View File

@@ -67,6 +67,13 @@ class CreatePlanCubit extends Cubit<CreatePlanState> {
validateSelectedOptionItems(); validateSelectedOptionItems();
} }
void togglePersonalizedDietOptionState() {
final options = [...state.planData.options];
options[state.selectedOptionIndex ?? 0] =
options[state.selectedOptionIndex ?? 0].copyWith(hasPersonalDiet: !options[state.selectedOptionIndex ?? 0].hasPersonalDiet);
emit(state.copyWith(planData: state.planData.copyWith(options: options)));
}
void setDuration(int index) { void setDuration(int index) {
emit( emit(
state.copyWith( state.copyWith(
@@ -418,18 +425,21 @@ class CreatePlanCubit extends Cubit<CreatePlanState> {
'price': int.parse((state.planData.options[0].price as double).toStringAsFixed(0)), 'price': int.parse((state.planData.options[0].price as double).toStringAsFixed(0)),
'description_md': state.planData.options[0].description, 'description_md': state.planData.options[0].description,
'items': Map.fromIterable(state.planData.options[0].items), 'items': Map.fromIterable(state.planData.options[0].items),
'has_personal_diet': state.planData.options[0].hasPersonalDiet ? '1' : '0',
}, },
'packet2_options': { 'packet2_options': {
'short': state.planData.options[1].short, 'short': state.planData.options[1].short,
'price': int.parse((state.planData.options[1].price as double).toStringAsFixed(0)), 'price': int.parse((state.planData.options[1].price as double).toStringAsFixed(0)),
'description_md': state.planData.options[1].description, 'description_md': state.planData.options[1].description,
'items': Map.fromIterable(state.planData.options[1].items), 'items': Map.fromIterable(state.planData.options[1].items),
'has_personal_diet': state.planData.options[1].hasPersonalDiet ? '1' : '0',
}, },
'packet3_options': { 'packet3_options': {
'short': state.planData.options[2].short, 'short': state.planData.options[2].short,
'price': int.parse((state.planData.options[2].price as double).toStringAsFixed(0)), 'price': int.parse((state.planData.options[2].price as double).toStringAsFixed(0)),
'description_md': state.planData.options[2].description, 'description_md': state.planData.options[2].description,
'items': Map.fromIterable(state.planData.options[2].items), 'items': Map.fromIterable(state.planData.options[2].items),
'has_personal_diet': state.planData.options[2].hasPersonalDiet ? '1' : '0',
}, },
}); });
} else { } else {
@@ -440,6 +450,7 @@ class CreatePlanCubit extends Cubit<CreatePlanState> {
'price': int.parse((state.planData.options[0].price as double).toStringAsFixed(0)), 'price': int.parse((state.planData.options[0].price as double).toStringAsFixed(0)),
'description_md': state.planData.options[0].description, 'description_md': state.planData.options[0].description,
'items': Map.fromIterable(state.planData.options[0].items), 'items': Map.fromIterable(state.planData.options[0].items),
'has_personal_diet': state.planData.options[0].hasPersonalDiet ? '1' : '0',
}, },
}); });
} }

View File

@@ -255,33 +255,31 @@ class _OptionWidgetState extends State<OptionWidget> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
const CustomDivider(), const CustomDivider(),
// const SizedBox(height: 16), const SizedBox(height: 16),
// Row( Row(
// children: [ children: [
// Checkbox( Checkbox(
// value: isChecked, value: state.planData.options[selectedOptionIndex].hasPersonalDiet,
// activeColor: appTheme.gray, activeColor: appTheme.gray,
// checkColor: appTheme.gray, checkColor: appTheme.gray,
// fillColor: const WidgetStatePropertyAll(Colors.transparent), fillColor: const WidgetStatePropertyAll(Colors.transparent),
// side: WidgetStateBorderSide.resolveWith( side: WidgetStateBorderSide.resolveWith(
// (Set<WidgetState> states) { (Set<WidgetState> states) {
// return BorderSide(width: 1, color: appTheme.gray); return BorderSide(width: 1, color: appTheme.gray);
// }, },
// ), ),
// onChanged: (bool? value) { onChanged: (bool? value) {
// setState(() { context.read<CreatePlanCubit>().togglePersonalizedDietOptionState();
// isChecked = value ?? false; },
// }); ),
// }, Expanded(
// ), child: Text(
// Expanded( s.option_personal_diet_desc,
// child: Text( style: TextStyles.textMMedium.copyWith(color: appTheme.black),
// s.option_personal_diet_desc, ),
// style: TextStyles.textMMedium.copyWith(color: appTheme.black), ),
// ), ],
// ), ),
// ],
// ),
], ],
), ),
); );

View File

@@ -13,8 +13,15 @@ class CalendarWidget extends StatefulWidget {
class _CalendarWidgetState extends State<CalendarWidget> { class _CalendarWidgetState extends State<CalendarWidget> {
CalendarFormat _calendarFormat = CalendarFormat.week; CalendarFormat _calendarFormat = CalendarFormat.week;
DateTime _focusedDay = DateTime.now(); late DateTime _focusedDay;
DateTime? _selectedDay = DateTime.now(); DateTime? _selectedDay;
@override
void initState() {
super.initState();
_selectedDay = widget.startDate.isEmpty ? DateTime.now() : widget.startDate[0];
_focusedDay = widget.startDate.isEmpty ? DateTime.now() : widget.startDate[0];
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
@@ -23,7 +30,7 @@ class _CalendarWidgetState extends State<CalendarWidget> {
Padding( Padding(
padding: const EdgeInsets.only(top: 5), padding: const EdgeInsets.only(top: 5),
child: TableCalendar( child: TableCalendar(
firstDay: DateTime.now(), firstDay: widget.startDate.isEmpty ? DateTime.now() : widget.startDate[0],
lastDay: DateTime.utc(2030, 3, 14), lastDay: DateTime.utc(2030, 3, 14),
locale: 'ru_RU', locale: 'ru_RU',
startingDayOfWeek: StartingDayOfWeek.monday, startingDayOfWeek: StartingDayOfWeek.monday,

View File

@@ -67,11 +67,19 @@ abstract class PacketOptions with _$PacketOptions {
@JsonKey(name: "price") required dynamic price, @JsonKey(name: "price") required dynamic price,
@JsonKey(name: "short") required String short, @JsonKey(name: "short") required String short,
@JsonKey(name: "description_md") required String description, @JsonKey(name: "description_md") required String description,
@JsonKey(name: "has_personal_diet", fromJson: _parseHasPersonalDietField) required bool hasPersonalDiet,
}) = _PacketOptions; }) = _PacketOptions;
factory PacketOptions.fromJson(Map<String, dynamic> json) => _$PacketOptionsFromJson(json); factory PacketOptions.fromJson(Map<String, dynamic> json) => _$PacketOptionsFromJson(json);
factory PacketOptions.empty() => PacketOptions(items: [], price: double.parse('1200'), short: '', description: ''); factory PacketOptions.empty() => PacketOptions(items: [], price: double.parse('1200'), short: '', description: '', hasPersonalDiet: false);
}
bool _parseHasPersonalDietField(dynamic json) {
if (json == null) return false;
if (json == '1') return true;
if (json == '0') return false;
return json as bool;
} }
List<String> _parseItems(dynamic json) { List<String> _parseItems(dynamic json) {

View File

@@ -17,6 +17,7 @@ import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_cubit.d
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart'; import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart';
import 'package:eatvio_app/features/my_diets/presentation/widgets/diet_deleted_bottom_sheet.dart'; import 'package:eatvio_app/features/my_diets/presentation/widgets/diet_deleted_bottom_sheet.dart';
import 'package:eatvio_app/features/my_diets/presentation/widgets/diet_drafetd_bottom_sheet.dart'; import 'package:eatvio_app/features/my_diets/presentation/widgets/diet_drafetd_bottom_sheet.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/presentation/personal_diet_suggestion_screen.dart';
import 'package:eatvio_app/generated/l10n.dart'; import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@@ -146,6 +147,7 @@ class _MyDietWidgetState extends State<MyDietWidget> {
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
} }
} else if (state.selectedStateIndex == 2) { } else if (state.selectedStateIndex == 2) {
GoRouter.of(context).pushNamed(PersonalDietSuggestionScreen.name, extra: widget.diet.id);
} else { } else {
GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: widget.diet); GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: widget.diet);
} }

View File

@@ -132,9 +132,9 @@ class _InfoByOrderScreenContentState extends State<InfoByOrderScreenContent> {
const SizedBox(height: 8), const SizedBox(height: 8),
PlanInfo(title: plan.plan.name, description: plan.plan.details, imagePath: plan.plan.image), PlanInfo(title: plan.plan.name, description: plan.plan.details, imagePath: plan.plan.image),
const SizedBox(height: 8), const SizedBox(height: 8),
OptionWidget(option: chosenOption, disableDuration: true), OptionWidget(option: chosenOption, disableDuration: true, duration: plan.plan.duration),
const SizedBox(height: 8), const SizedBox(height: 8),
PlanState(state: plan.chosenPlanState), PlanState(state: plan.chosenPlanState, hasPersonalDiet: chosenOption?.hasPersonalDiet ?? false,),
const SizedBox(height: 20), const SizedBox(height: 20),
if (widget.successfulPayment == null) if (widget.successfulPayment == null)
CustomOutlinedButton( CustomOutlinedButton(

View File

@@ -5,42 +5,65 @@ import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
import 'package:eatvio_app/generated/l10n.dart'; import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class PlanState extends StatelessWidget { class PlanState extends StatefulWidget {
PlanState({super.key, required this.state}); const PlanState({super.key, required this.state, required this.hasPersonalDiet});
final ChosenPlanStateEnum state; final ChosenPlanStateEnum state;
final List<List<ChosenPlanStateEnum>> states = [ final bool hasPersonalDiet;
[
ChosenPlanStateEnum.stateInited, @override
ChosenPlanStateEnum.stateInCoordination, State<PlanState> createState() => _PlanStateState();
], }
[
ChosenPlanStateEnum.stateStartDateHasBeenSet, class _PlanStateState extends State<PlanState> {
ChosenPlanStateEnum.statePendingPayment, late final List<List<ChosenPlanStateEnum>> states;
],
[ @override
ChosenPlanStateEnum.statePaid, void initState() {
], super.initState();
[ if (widget.hasPersonalDiet) {
ChosenPlanStateEnum.stateStarted, states = [
ChosenPlanStateEnum.stateInProgress, [ChosenPlanStateEnum.stateInited, ChosenPlanStateEnum.stateInCoordination],
ChosenPlanStateEnum.stateLastDayStarted, [ChosenPlanStateEnum.stateStartDateHasBeenSet, ChosenPlanStateEnum.statePendingPayment],
ChosenPlanStateEnum.stateLastDayFinished, [ChosenPlanStateEnum.statePaid],
], [ChosenPlanStateEnum.personalDietSet],
[ [
ChosenPlanStateEnum.stateComplained, ChosenPlanStateEnum.stateStarted,
ChosenPlanStateEnum.stateDone, ChosenPlanStateEnum.stateInProgress,
ChosenPlanStateEnum.stateChargeWasCollected, ChosenPlanStateEnum.stateLastDayStarted,
] ChosenPlanStateEnum.stateLastDayFinished,
]; ],
[ChosenPlanStateEnum.stateComplained, ChosenPlanStateEnum.stateDone, ChosenPlanStateEnum.stateChargeWasCollected],
];
} else {
states = [
[ChosenPlanStateEnum.stateInited, ChosenPlanStateEnum.stateInCoordination],
[ChosenPlanStateEnum.stateStartDateHasBeenSet, ChosenPlanStateEnum.statePendingPayment],
[ChosenPlanStateEnum.statePaid],
[
ChosenPlanStateEnum.stateStarted,
ChosenPlanStateEnum.stateInProgress,
ChosenPlanStateEnum.stateLastDayStarted,
ChosenPlanStateEnum.stateLastDayFinished,
],
[ChosenPlanStateEnum.stateComplained, ChosenPlanStateEnum.stateDone, ChosenPlanStateEnum.stateChargeWasCollected],
];
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final s = S.of(context); final s = S.of(context);
final titles = [s.order_created, s.startDateHasBeenSet, s.order_paid, s.in_progress, s.done]; final List<String> titles;
if (widget.hasPersonalDiet) {
titles = [s.order_created, s.startDateHasBeenSet, s.order_paid, s.personal_diet_set, s.in_progress, s.done];
} else {
titles = [s.order_created, s.startDateHasBeenSet, s.order_paid, s.in_progress, s.done];
}
return MainBackgroundBouble( return MainBackgroundBouble(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Column( child: Column(
children: List.generate(states.length, (index) { children: List.generate(states.length, (index) {
final color = index <= states.indexWhere((element) => element.contains(state)) ? appTheme.greenA700 : appTheme.lightGray00; final color = index <= states.indexWhere((element) => element.contains(widget.state)) ? appTheme.greenA700 : appTheme.lightGray00;
final text = titles[index]; final text = titles[index];
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -51,29 +74,16 @@ class PlanState extends StatelessWidget {
width: 24, width: 24,
height: 24, height: 24,
decoration: BoxDecoration(shape: BoxShape.circle, color: color), decoration: BoxDecoration(shape: BoxShape.circle, color: color),
child: Center( child: Center(child: Icon(Icons.check, color: appTheme.whiteA700, size: 14)),
child: Icon(
Icons.check,
color: appTheme.whiteA700,
size: 14,
),
),
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
Text( Text(text, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
text,
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
),
], ],
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 12), padding: const EdgeInsets.only(left: 12),
child: Container( child: Container(height: 12, width: 1, color: color),
height: 12, ),
width: 1,
color: color,
),
)
], ],
); );
}), }),

View File

@@ -0,0 +1,67 @@
import 'dart:developer';
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_state.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/repository/personal_diet_suggestion_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class PersonalDietSuggestionCubit extends Cubit<PersonalDietSuggestionState> {
final DietRepository dietRepository;
final PersonalDietSuggestionRepository personalDietSuggestionService;
late final int dietId;
PersonalDietSuggestionCubit({required this.dietRepository, required this.personalDietSuggestionService}) : super(PersonalDietSuggestionState());
Future<void> setDietName(int dietId) async {
try {
emit(state.copyWith(isLoading: true, error: null));
final diet = await dietRepository.getDiet(dietId);
emit(state.copyWith(isLoading: false, dietName: diet.name));
} catch (e, st) {
log(e.toString(), stackTrace: st);
emit(state.copyWith(isLoading: false, error: e.toString()));
}
}
Future<void> getConsultationWithPersonalDiets(int dietId) async {
try {
this.dietId = dietId;
emit(state.copyWith(isLoading: true, error: null));
setDietName(dietId);
final consultations = await personalDietSuggestionService.getConsultationWithPersonalDiets();
final consultationWithDiet = consultations.where((consultation) => consultation.personalDietId != null).toList();
final consultationWithoutDiet = consultations.where((consultation) => consultation.personalDietId == null).toList();
emit(state.copyWith(
isLoading: false,
consultationsWithDiet: consultationWithDiet,
consultationsWithoutDiet: consultationWithoutDiet,
));
} catch (e, st) {
log(e.toString(), stackTrace: st);
emit(state.copyWith(isLoading: false, error: e.toString()));
}
}
Future<bool> attachDietToConsultation({
required int consultationId,
}) async {
try {
await personalDietSuggestionService.attachPersonalDiet(consultationId: consultationId, dietId: dietId);
return true;
} catch (e, st) {
log(e.toString(), stackTrace: st);
return false;
}
}
Future<bool> reattachDietToConsultation({
required int consultationId,
}) async {
try {
await personalDietSuggestionService.reattachPersonalDiet(consultationId: consultationId, dietId: dietId);
return true;
} catch (e, st) {
log(e.toString(), stackTrace: st);
return false;
}
}
}

View File

@@ -0,0 +1,16 @@
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'personal_diet_suggestion_state.freezed.dart';
@freezed
abstract class PersonalDietSuggestionState with _$PersonalDietSuggestionState {
factory PersonalDietSuggestionState({
@Default([]) List<ConsultationModel> consultationsWithDiet,
@Default([]) List<ConsultationModel> consultationsWithoutDiet,
@Default('') String dietName,
@Default(false) bool isLoading,
@Default(null) String? error,
}) = _PersonalDietSuggestionState;
}

View File

@@ -0,0 +1,358 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_router.dart';
import 'package:eatvio_app/core/locator_service.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/bottom_sheet_handler_bar.dart';
import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart';
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
class ConsultationWidget extends StatelessWidget {
const ConsultationWidget({super.key, required this.consultationModel, required this.dietName});
final ConsultationModel consultationModel;
final String dietName;
@override
Widget build(BuildContext context) {
final s = S.of(context);
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: appTheme.whiteA700,
),
child: Column(
children: [
if (consultationModel.personalDietId == null)
Row(
children: [
CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(sl<AppConfig>().baseUrl + consultationModel.userProfilePhotoUrl),
),
const SizedBox(width: 12),
Column(
mainAxisSize: MainAxisSize.min,
spacing: 4,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
consultationModel.userName,
style: TextStyles.textLSemibold.copyWith(color: appTheme.black),
),
Text(
consultationModel.planTitle,
style: TextStyles.textMMedium.copyWith(color: const Color(0xFF88949F)),
),
Text(
'Старт: ${consultationModel.userName}',
style: TextStyles.textMMedium.copyWith(color: const Color(0xFF88949F)),
),
],
)
],
)
else
Row(
children: [
CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(sl<AppConfig>().baseUrl + consultationModel.userProfilePhotoUrl),
),
const SizedBox(width: 12),
Column(
mainAxisSize: MainAxisSize.min,
spacing: 4,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
consultationModel.userName,
style: TextStyles.textLSemibold.copyWith(color: appTheme.black),
),
Text(
consultationModel.planTitle,
style: TextStyles.textMMedium.copyWith(color: const Color(0xFF88949F)),
),
],
)
],
),
const SizedBox(
height: 12,
),
if (consultationModel.personalDietId != null)
CustomOutlinedButton(
text: s.changeDiet,
height: 52,
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray),
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.dividerColor)),
onPressed: () async {
showBottomSheetWithBlur(
userRootNavigator: true,
context: context,
height: null,
child: SuggestDietBottomSheet(
userName: consultationModel.userName,
dietName: dietName,
onTap: () async {
final result = await context.read<PersonalDietSuggestionCubit>().attachDietToConsultation(consultationId: consultationModel.id);
AppRouter.navigatorKey.currentContext?.pop();
if (result) {
if (!context.mounted) return;
showBottomSheetWithBlur(
userRootNavigator: true,
context: context,
height: null,
child: SuggestionSuccessBottomSheet(
userName: consultationModel.userName,
dietName: dietName,
),
);
return;
}
if (!context.mounted) return;
showBottomSheetWithBlur(
userRootNavigator: true,
context: context,
height: null,
child: SuggestionFailureBottomSheet(
userName: consultationModel.userName,
dietName: dietName,
),
);
},
),
);
},
)
else
CustomOutlinedButton(
text: s.suggestDiet,
height: 52,
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
onPressed: () async {
showBottomSheetWithBlur(
userRootNavigator: true,
context: context,
height: null,
child: SuggestDietBottomSheet(
userName: consultationModel.userName,
dietName: dietName,
onTap: () async {
AppRouter.navigatorKey.currentContext?.pop();
final result = await context.read<PersonalDietSuggestionCubit>().attachDietToConsultation(consultationId: consultationModel.id);
if (result) {
if (!context.mounted) return;
showBottomSheetWithBlur(
userRootNavigator: true,
context: context,
height: null,
child: SuggestionSuccessBottomSheet(
userName: consultationModel.userName,
dietName: dietName,
),
);
return;
}
if (!context.mounted) return;
showBottomSheetWithBlur(
userRootNavigator: true,
context: context,
height: null,
child: SuggestionFailureBottomSheet(
userName: consultationModel.userName,
dietName: dietName,
),
);
},
),
);
},
)
],
),
);
}
}
class SuggestDietBottomSheet extends StatefulWidget {
const SuggestDietBottomSheet({
super.key,
required this.userName,
required this.dietName,
required this.onTap,
});
final String userName;
final String dietName;
final Future<void> Function() onTap;
@override
State<SuggestDietBottomSheet> createState() => _SuggestDietBottomSheet();
}
class _SuggestDietBottomSheet extends State<SuggestDietBottomSheet> {
@override
Widget build(BuildContext context) {
final s = S.of(context);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 8,
),
const BottomSheetHandlerBar(),
const SizedBox(
height: 20,
),
Text('Предложение диеты', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
const SizedBox(
height: 16,
),
Text(
'Предложить пользователю ${widget.userName} «${widget.dietName}»',
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
textAlign: TextAlign.center,
),
const SizedBox(
height: 8,
),
CustomOutlinedButton(
text: s.toOffer,
height: 52,
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
onPressed: widget.onTap,
),
const SizedBox(
height: 40,
),
],
),
);
}
}
class SuggestionSuccessBottomSheet extends StatefulWidget {
const SuggestionSuccessBottomSheet({
super.key,
required this.userName,
required this.dietName,
});
final String userName;
final String dietName;
@override
State<SuggestionSuccessBottomSheet> createState() => _SuggestionSuccessBottomSheet();
}
class _SuggestionSuccessBottomSheet extends State<SuggestionSuccessBottomSheet> {
@override
Widget build(BuildContext context) {
final s = S.of(context);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 8,
),
const BottomSheetHandlerBar(),
const SizedBox(
height: 20,
),
Text('Предложение диеты', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
const SizedBox(
height: 16,
),
Text(
'«${widget.dietName}» предложена пользователю ${widget.userName}',
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
textAlign: TextAlign.center,
),
const SizedBox(
height: 8,
),
CustomOutlinedButton(
text: s.ok,
height: 52,
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
onPressed: () async {
AppRouter.navigatorKey.currentContext?.pop();
},
),
const SizedBox(
height: 40,
),
],
),
);
}
}
class SuggestionFailureBottomSheet extends StatefulWidget {
const SuggestionFailureBottomSheet({
super.key,
required this.userName,
required this.dietName,
});
final String userName;
final String dietName;
@override
State<SuggestionFailureBottomSheet> createState() => _SuggestionFailureBottomSheet();
}
class _SuggestionFailureBottomSheet extends State<SuggestionFailureBottomSheet> {
@override
Widget build(BuildContext context) {
final s = S.of(context);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 8,
),
const BottomSheetHandlerBar(),
const SizedBox(
height: 20,
),
Text('Предложение диеты', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
const SizedBox(
height: 16,
),
Text(
'Не удалось предложить диету ${widget.dietName} пользователю ${widget.userName}',
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
textAlign: TextAlign.center,
),
const SizedBox(
height: 8,
),
CustomOutlinedButton(
text: s.ok,
height: 52,
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
onPressed: () async {
AppRouter.navigatorKey.currentContext?.pop();
},
),
const SizedBox(
height: 40,
),
],
),
);
}
}

View File

@@ -0,0 +1,69 @@
import 'package:eatvio_app/core/locator_service.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/loader.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_state.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/presentation/consultation_widget.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class PersonalDietSuggestionScreen extends StatelessWidget {
final int dietId;
const PersonalDietSuggestionScreen({super.key, required this.dietId});
static const path = '/personal-diet-suggestion';
static const name = 'personalDietSuggestion';
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => sl<PersonalDietSuggestionCubit>()..getConsultationWithPersonalDiets(dietId),
child: const PersonalDietSuggestionScreenContent(),
);
}
}
class PersonalDietSuggestionScreenContent extends StatelessWidget {
const PersonalDietSuggestionScreenContent({super.key});
@override
Widget build(BuildContext context) {
final s = S.of(context);
return BlocBuilder<PersonalDietSuggestionCubit, PersonalDietSuggestionState>(
builder: (context, state) {
return Scaffold(
backgroundColor: appTheme.gray100,
appBar: AppBar(
centerTitle: true,
title: Text(
'${s.dietSuggestion}\n«${state.dietName}»',
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
),
),
body: state.isLoading
? const Center(child: Loader())
: SingleChildScrollView(
child: Column(
children: [
...List.generate(state.consultationsWithDiet.length, (index) {
return ConsultationWidget(
consultationModel: state.consultationsWithDiet[index],
dietName: state.dietName,
);
}),
const SizedBox(
height: 12,
),
...List.generate(state.consultationsWithoutDiet.length, (index) {
return ConsultationWidget(
consultationModel: state.consultationsWithoutDiet[index],
dietName: state.dietName,
);
})
],
),
),
);
},
);
}
}

View File

@@ -0,0 +1,32 @@
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/services/personal_diet_suggestion_service.dart';
class PersonalDietSuggestionRepository {
final PersonalDietSuggestionService personalDietSuggestionService;
PersonalDietSuggestionRepository({required this.personalDietSuggestionService});
Future<List<ConsultationModel>> getConsultationWithPersonalDiets() async{
try {
return (await personalDietSuggestionService.getConsultationWithPersonalDiets()).data;
} catch (e) {
rethrow;
}
}
Future<void> attachPersonalDiet({required int consultationId, required int dietId}) {
try {
return personalDietSuggestionService.attachPersonalDiet(consultationId: consultationId, dietId: dietId);
} catch (e) {
rethrow;
}
}
Future<void> reattachPersonalDiet({required int consultationId, required int dietId}) {
try {
return personalDietSuggestionService.reattachPersonalDiet(consultationId: consultationId, dietId: dietId);
} catch (e) {
rethrow;
}
}
}

View File

@@ -0,0 +1,36 @@
import 'package:dio/dio.dart';
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
class PersonalDietSuggestionService {
final Dio dio;
PersonalDietSuggestionService(this.dio);
Future<ConsultationPaginationModel> getConsultationWithPersonalDiets() async {
try {
final response = await dio.get('/api/consultations', queryParameters: {
'filters[plan][has_personal_diet][\$personal_diet]': '1',
'filters[last_state][\$notIn][]': ['done', 'charge_was_collected', 'complained', 'last_day_finished', 'canceled_by_the_initiator', 'inited'],
'sort[]': 'start_date:desc',
});
return ConsultationPaginationModel.fromJson(response.data);
} catch (e) {
rethrow;
}
}
Future<void> attachPersonalDiet({required int consultationId, required int dietId}) async {
try {
await dio.post('/api/chosen_plans/$consultationId/attach_diet', data: {'diet_id': dietId});
} catch (e) {
rethrow;
}
}
Future<void> reattachPersonalDiet({required int consultationId, required int dietId}) async {
try {
await dio.post('/api/chosen_plans/$consultationId/re_attach_diet', data: {'diet_id': dietId});
} catch (e) {
rethrow;
}
}
}

View File

@@ -27,6 +27,8 @@ enum ChosenPlanStateEnum {
stateComplained, stateComplained,
@JsonValue('done') @JsonValue('done')
stateDone, stateDone,
@JsonValue('personal_diet_setted')
personalDietSet,
@JsonValue('charge_was_collected') @JsonValue('charge_was_collected')
stateChargeWasCollected; stateChargeWasCollected;
@@ -40,6 +42,7 @@ enum ChosenPlanStateEnum {
ChosenPlanStateEnum.stateLastDayFinished, ChosenPlanStateEnum.stateLastDayFinished,
ChosenPlanStateEnum.stateDone, ChosenPlanStateEnum.stateDone,
ChosenPlanStateEnum.stateInProgress, ChosenPlanStateEnum.stateInProgress,
ChosenPlanStateEnum.personalDietSet,
]; ];
} }
@@ -64,7 +67,8 @@ enum ChosenPlanStateEnum {
ChosenPlanStateEnum.stateLastDayStarted, ChosenPlanStateEnum.stateLastDayStarted,
ChosenPlanStateEnum.stateLastDayFinished, ChosenPlanStateEnum.stateLastDayFinished,
ChosenPlanStateEnum.stateComplained, ChosenPlanStateEnum.stateComplained,
ChosenPlanStateEnum.stateDone ChosenPlanStateEnum.stateDone,
ChosenPlanStateEnum.personalDietSet
]; ];
} }
} }

View File

@@ -505,12 +505,15 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
switch (state.chosenOptionIndex) { switch (state.chosenOptionIndex) {
1 => OptionWidget( 1 => OptionWidget(
option: state.planModel?.packet2Options, option: state.planModel?.packet2Options,
duration: state.planModel?.duration ?? 0,
), ),
2 => OptionWidget( 2 => OptionWidget(
option: state.planModel?.packet3Options, option: state.planModel?.packet3Options,
duration: state.planModel?.duration ?? 0,
), ),
_ => OptionWidget( _ => OptionWidget(
option: state.planModel?.packet1Options, option: state.planModel?.packet1Options,
duration: state.planModel?.duration ?? 0,
), ),
}, },
const SizedBox( const SizedBox(

View File

@@ -138,6 +138,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Если вы любите мучные продукты, но хотите придерживаться диеты, вам подходит диета с добавленим мучных блюд на основе цельнозерновых вариантов. В них больше сложных углеводов и клетчатки, что способствует длительному чувству сытости и поддерживает здоровье пищеварительной системы.", "Если вы любите мучные продукты, но хотите придерживаться диеты, вам подходит диета с добавленим мучных блюд на основе цельнозерновых вариантов. В них больше сложных углеводов и клетчатки, что способствует длительному чувству сытости и поддерживает здоровье пищеварительной системы.",
), ),
"carbohydrates": MessageLookupByLibrary.simpleMessage("Углеводы"), "carbohydrates": MessageLookupByLibrary.simpleMessage("Углеводы"),
"changeDiet": MessageLookupByLibrary.simpleMessage("Заменить диету"),
"chargeApproved": MessageLookupByLibrary.simpleMessage("Выплата одобрена"), "chargeApproved": MessageLookupByLibrary.simpleMessage("Выплата одобрена"),
"chargeCollectionFailed": MessageLookupByLibrary.simpleMessage( "chargeCollectionFailed": MessageLookupByLibrary.simpleMessage(
"Не удалось оформить выплату", "Не удалось оформить выплату",
@@ -158,6 +159,10 @@ class MessageLookup extends MessageLookupByLibrary {
"choose_plan_start_date": MessageLookupByLibrary.simpleMessage( "choose_plan_start_date": MessageLookupByLibrary.simpleMessage(
"Выберите дату старта плана питания", "Выберите дату старта плана питания",
), ),
"choose_plan_start_date_with_personal_diet":
MessageLookupByLibrary.simpleMessage(
"Выберите дату старта плана питания с учетом составления персональной диеты",
),
"choose_start_diet_date": MessageLookupByLibrary.simpleMessage( "choose_start_diet_date": MessageLookupByLibrary.simpleMessage(
"Выберите дату старты диеты. Она отобразиться у Вас в дневнике", "Выберите дату старты диеты. Она отобразиться у Вас в дневнике",
), ),
@@ -165,6 +170,9 @@ class MessageLookup extends MessageLookupByLibrary {
"chose_plan_start_date_2": MessageLookupByLibrary.simpleMessage( "chose_plan_start_date_2": MessageLookupByLibrary.simpleMessage(
"Выберите дату старты плана. Она отобразиться в дневнике пользователя", "Выберите дату старты плана. Она отобразиться в дневнике пользователя",
), ),
"chosenPlanStartDateDescr": MessageLookupByLibrary.simpleMessage(
"Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты",
),
"circumference_empty": MessageLookupByLibrary.simpleMessage( "circumference_empty": MessageLookupByLibrary.simpleMessage(
"Все замеры обязательны к заполнению", "Все замеры обязательны к заполнению",
), ),
@@ -246,6 +254,9 @@ class MessageLookup extends MessageLookupByLibrary {
"Не удалось обновить диету", "Не удалось обновить диету",
), ),
"country": MessageLookupByLibrary.simpleMessage("Страна"), "country": MessageLookupByLibrary.simpleMessage("Страна"),
"createPersonalDiet": MessageLookupByLibrary.simpleMessage(
"Составьте персональную диету",
),
"create_diet": MessageLookupByLibrary.simpleMessage("Создание диеты"), "create_diet": MessageLookupByLibrary.simpleMessage("Создание диеты"),
"cunsutation_was_paid_successfully": MessageLookupByLibrary.simpleMessage( "cunsutation_was_paid_successfully": MessageLookupByLibrary.simpleMessage(
"Поздравляем, консультация успешно оплачена", "Поздравляем, консультация успешно оплачена",
@@ -274,6 +285,7 @@ class MessageLookup extends MessageLookupByLibrary {
"deleted": MessageLookupByLibrary.simpleMessage("Удалена"), "deleted": MessageLookupByLibrary.simpleMessage("Удалена"),
"diary": MessageLookupByLibrary.simpleMessage("Дневник"), "diary": MessageLookupByLibrary.simpleMessage("Дневник"),
"diet": MessageLookupByLibrary.simpleMessage("Диета"), "diet": MessageLookupByLibrary.simpleMessage("Диета"),
"dietSuggestion": MessageLookupByLibrary.simpleMessage("Предложение диеты"),
"diet_author": MessageLookupByLibrary.simpleMessage("Автор диеты"), "diet_author": MessageLookupByLibrary.simpleMessage("Автор диеты"),
"diet_has_been_sent_to_draft": MessageLookupByLibrary.simpleMessage( "diet_has_been_sent_to_draft": MessageLookupByLibrary.simpleMessage(
"снята с публикации и перенесена в черновик", "снята с публикации и перенесена в черновик",
@@ -393,6 +405,9 @@ class MessageLookup extends MessageLookupByLibrary {
"from_z_to_a": MessageLookupByLibrary.simpleMessage("Название: Я-А"), "from_z_to_a": MessageLookupByLibrary.simpleMessage("Название: Я-А"),
"gallery": MessageLookupByLibrary.simpleMessage("Галерея"), "gallery": MessageLookupByLibrary.simpleMessage("Галерея"),
"general_info": MessageLookupByLibrary.simpleMessage("Общая информация"), "general_info": MessageLookupByLibrary.simpleMessage("Общая информация"),
"goToMyDiets": MessageLookupByLibrary.simpleMessage(
"Перейти к моим диетам",
),
"go_to_diary": MessageLookupByLibrary.simpleMessage("Перейти в дневник"), "go_to_diary": MessageLookupByLibrary.simpleMessage("Перейти в дневник"),
"gr": MessageLookupByLibrary.simpleMessage("гр"), "gr": MessageLookupByLibrary.simpleMessage("гр"),
"grams": MessageLookupByLibrary.simpleMessage("гр"), "grams": MessageLookupByLibrary.simpleMessage("гр"),
@@ -570,6 +585,12 @@ class MessageLookup extends MessageLookupByLibrary {
"pcs": MessageLookupByLibrary.simpleMessage("шт"), "pcs": MessageLookupByLibrary.simpleMessage("шт"),
"pending_payment": MessageLookupByLibrary.simpleMessage("Ожидается оплата"), "pending_payment": MessageLookupByLibrary.simpleMessage("Ожидается оплата"),
"personal": MessageLookupByLibrary.simpleMessage("Персональные"), "personal": MessageLookupByLibrary.simpleMessage("Персональные"),
"personalDietCreating": MessageLookupByLibrary.simpleMessage(
"Составление индивидуальной диеты",
),
"personal_diet_set": MessageLookupByLibrary.simpleMessage(
"Персональная диета установлена",
),
"personal_diet_state": MessageLookupByLibrary.simpleMessage("Персональная"), "personal_diet_state": MessageLookupByLibrary.simpleMessage("Персональная"),
"photo": MessageLookupByLibrary.simpleMessage("Фото"), "photo": MessageLookupByLibrary.simpleMessage("Фото"),
"physical_fitness": MessageLookupByLibrary.simpleMessage( "physical_fitness": MessageLookupByLibrary.simpleMessage(
@@ -699,6 +720,7 @@ class MessageLookup extends MessageLookupByLibrary {
"successfully_published": MessageLookupByLibrary.simpleMessage( "successfully_published": MessageLookupByLibrary.simpleMessage(
"успешно опубликован", "успешно опубликован",
), ),
"suggestDiet": MessageLookupByLibrary.simpleMessage("Предложить диету"),
"suicide": MessageLookupByLibrary.simpleMessage("Склонение к самоубийству"), "suicide": MessageLookupByLibrary.simpleMessage("Склонение к самоубийству"),
"takes_pills": MessageLookupByLibrary.simpleMessage("Принимает лекарства"), "takes_pills": MessageLookupByLibrary.simpleMessage("Принимает лекарства"),
"tap_on_link_to_pay": MessageLookupByLibrary.simpleMessage( "tap_on_link_to_pay": MessageLookupByLibrary.simpleMessage(

View File

@@ -3434,6 +3434,86 @@ class S {
); );
} }
/// `Составление индивидуальной диеты`
String get personalDietCreating {
return Intl.message(
'Составление индивидуальной диеты',
name: 'personalDietCreating',
desc: '',
args: [],
);
}
/// `Предложение диеты`
String get dietSuggestion {
return Intl.message(
'Предложение диеты',
name: 'dietSuggestion',
desc: '',
args: [],
);
}
/// `Предложить диету`
String get suggestDiet {
return Intl.message(
'Предложить диету',
name: 'suggestDiet',
desc: '',
args: [],
);
}
/// `Заменить диету`
String get changeDiet {
return Intl.message(
'Заменить диету',
name: 'changeDiet',
desc: '',
args: [],
);
}
/// `Выберите дату старта плана питания с учетом составления персональной диеты`
String get choose_plan_start_date_with_personal_diet {
return Intl.message(
'Выберите дату старта плана питания с учетом составления персональной диеты',
name: 'choose_plan_start_date_with_personal_diet',
desc: '',
args: [],
);
}
/// `Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты`
String get chosenPlanStartDateDescr {
return Intl.message(
'Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты',
name: 'chosenPlanStartDateDescr',
desc: '',
args: [],
);
}
/// `Составьте персональную диету`
String get createPersonalDiet {
return Intl.message(
'Составьте персональную диету',
name: 'createPersonalDiet',
desc: '',
args: [],
);
}
/// `Перейти к моим диетам`
String get goToMyDiets {
return Intl.message(
'Перейти к моим диетам',
name: 'goToMyDiets',
desc: '',
args: [],
);
}
/// `Удаление аккаунта` /// `Удаление аккаунта`
String get accountDeleting { String get accountDeleting {
return Intl.message( return Intl.message(
@@ -3504,6 +3584,16 @@ class S {
return Intl.message('Покупатель', name: 'customer', desc: '', args: []); return Intl.message('Покупатель', name: 'customer', desc: '', args: []);
} }
/// `Персональная диета установлена`
String get personal_diet_set {
return Intl.message(
'Персональная диета установлена',
name: 'personal_diet_set',
desc: '',
args: [],
);
}
/// `Поздравляем!` /// `Поздравляем!`
String get congratulations { String get congratulations {
return Intl.message( return Intl.message(

View File

@@ -408,6 +408,14 @@
"copy": "Скопировать", "copy": "Скопировать",
"reply": "Ответить", "reply": "Ответить",
"deleteComment": "Удалить комментарий", "deleteComment": "Удалить комментарий",
"personalDietCreating": "Составление индивидуальной диеты",
"dietSuggestion": "Предложение диеты",
"suggestDiet": "Предложить диету",
"changeDiet": "Заменить диету",
"choose_plan_start_date_with_personal_diet": "Выберите дату старта плана питания с учетом составления персональной диеты",
"chosenPlanStartDateDescr": "Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты",
"createPersonalDiet": "Составьте персональную диету",
"goToMyDiets": "Перейти к моим диетам",
"accountDeleting": "Удаление аккаунта", "accountDeleting": "Удаление аккаунта",
"youShureYouWantToDeleteAccount": "Вы уверены, что хотите удалить аккаунт?", "youShureYouWantToDeleteAccount": "Вы уверены, что хотите удалить аккаунт?",
"itCantBeRecovered": "Его нельзя будет восстановить", "itCantBeRecovered": "Его нельзя будет восстановить",
@@ -416,6 +424,7 @@
"resend": "Отправить повторно", "resend": "Отправить повторно",
"notifications": "Уведомления", "notifications": "Уведомления",
"customer": "Покупатель", "customer": "Покупатель",
"personal_diet_set": "Персональная диета установлена",
"congratulations": "Поздравляем!", "congratulations": "Поздравляем!",
"youWithUs": "Вы с итвио уже\n", "youWithUs": "Вы с итвио уже\n",
"fourteenDays": "14 дней", "fourteenDays": "14 дней",

View File

@@ -1,6 +1,6 @@
name: eatvio_app name: eatvio_app
description: A new Flutter project. description: A new Flutter project.
version: 1.3.2+81 version: 1.3.3+82
publish_to: 'none' publish_to: 'none'
environment: environment: