forked from eatvio/eatvio_app
Merge branch 'main' of http://gitea.office.local:3000/mso7nueh/eatvio_app
This commit is contained in:
@@ -406,7 +406,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.2.3;
|
||||
MARKETING_VERSION = 1.3.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044";
|
||||
@@ -557,7 +557,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.2.3;
|
||||
MARKETING_VERSION = 1.3.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044";
|
||||
@@ -596,7 +596,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.2.3;
|
||||
MARKETING_VERSION = 1.3.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044";
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>81</string>
|
||||
<string>82</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
||||
@@ -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/notifications/presentation/notifications_cubit/notifications_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/profile/presentation/bloc/plans_cubit/plans_cubit.dart' as profile_plans;
|
||||
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<MenuCubit>(() => MenuCubit(sl()));
|
||||
sl.registerFactory<MarketingCubit>(() => MarketingCubit(sl()));
|
||||
sl.registerFactory<PersonalDietSuggestionCubit>(() => PersonalDietSuggestionCubit(dietRepository: sl(), personalDietSuggestionService: sl()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_plans/repositories/my_diets_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/plans_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<CommentsRepository>(() => CommentsRepository(service: sl()));
|
||||
sl.registerLazySingleton<NotificationSettingsRepository>(() => NotificationSettingsRepository(sl()));
|
||||
sl.registerLazySingleton<PersonalDietSuggestionRepository>(() => PersonalDietSuggestionRepository(personalDietSuggestionService: sl()));
|
||||
|
||||
// Content repositories
|
||||
sl.registerLazySingleton<BlogPostRepository>(() => BlogPostRepository(blogPostService: sl()));
|
||||
|
||||
@@ -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_plans/services/my_plans_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/plans_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<NotificationSettingsService>(() => NotificationSettingsService(sl()));
|
||||
sl.registerLazySingleton<ViewsService>(() => ViewsService(sl()));
|
||||
sl.registerLazySingleton<PersonalDietSuggestionService>(() => PersonalDietSuggestionService(sl()));
|
||||
|
||||
// Content services
|
||||
sl.registerLazySingleton<CreateRecipeService>(() => CreateRecipeService(sl()));
|
||||
|
||||
@@ -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_plans/presentation/my_plans_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/presentation/pages/profile_screen.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/pages/subs_screen.dart';
|
||||
@@ -243,6 +244,11 @@ class OtherRoutes {
|
||||
return UserDiaryScreen(diaryId: diaryId, currentPlanDay: currentPlanDay);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: PersonalDietSuggestionScreen.path,
|
||||
name: PersonalDietSuggestionScreen.name,
|
||||
builder: (context, state) => PersonalDietSuggestionScreen(dietId: state.extra as int,),
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ class PrimaryColors {
|
||||
// Blue
|
||||
Color get blue400 => const Color(0XFF43A6F2);
|
||||
|
||||
Color get blueA400 => const Color(0XFF2F80ED);
|
||||
Color get blueA400 => const Color(0XFF2F80ED);
|
||||
// BlueGray
|
||||
Color get blueGray400 => const Color(0XFF7B8794);
|
||||
|
||||
@@ -150,6 +150,8 @@ class PrimaryColors {
|
||||
|
||||
Color get green => const Color(0XFF0BB450);
|
||||
|
||||
Color get transparentGreen => const Color.fromARGB(12, 1, 154, 63);
|
||||
|
||||
// LightGreen
|
||||
Color get lightGreen300 => const Color(0XFFB2DF8A);
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
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 bool disableDuration;
|
||||
final int duration;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (option == null) {
|
||||
@@ -34,8 +35,12 @@ class OptionWidget extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
if (!disableDuration) ...[
|
||||
const _OptionDurationWidget(duration: 7),
|
||||
const SizedBox(height: 16),
|
||||
_OptionDurationWidget(duration: duration),
|
||||
SizedBox(height: option?.hasPersonalDiet ?? false ? 8 : 12),
|
||||
],
|
||||
if ((option?.hasPersonalDiet ?? false) && !disableDuration) ...[
|
||||
const _OptionHasPersonalDietWidget(),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
const CustomDivider(),
|
||||
const SizedBox(height: 16),
|
||||
@@ -52,7 +57,6 @@ class OptionWidget extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _OptionDurationWidget extends StatelessWidget {
|
||||
const _OptionDurationWidget({required this.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,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,25 +114,6 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
ChosenPlanStateEnum.statePendingPayment,
|
||||
ChosenPlanStateEnum.stateInCoordination,
|
||||
].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;
|
||||
if (chosenPlan?.optionType == 'options1') {
|
||||
chosenOption = chosenPlan?.plan.packet1Options;
|
||||
@@ -141,6 +122,27 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
} else if (chosenPlan?.optionType == 'options3') {
|
||||
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(
|
||||
resizeToAvoidBottomInset: true,
|
||||
appBar: AppBar(
|
||||
@@ -317,6 +319,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
chosenPlanId: chosenPlan?.id,
|
||||
planName: chosenPlan?.plan.name,
|
||||
planPrice: chosenOption?.price.toDouble(),
|
||||
hasPersonalDiet: chosenOption?.hasPersonalDiet ?? false,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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/widgets/custom_outlined_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
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 bool hasPersonalDiet;
|
||||
@override
|
||||
State<ChosePlanDateWidget> createState() => _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
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
@@ -27,64 +38,129 @@ class _ChosePlanDateWidget extends State<ChosePlanDateWidget> {
|
||||
if (widget.chatCubit.state is ChatRoomStateLoaded) {
|
||||
planName = (widget.chatCubit.state as ChatRoomStateLoaded).chatRoom.chosenPlan?.plan.name;
|
||||
}
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 4),
|
||||
const BottomSheetHandlerBar(),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
planName ?? '',
|
||||
style: TextStyles.headingXLSemibold.copyWith(
|
||||
color: appTheme.black,
|
||||
return GestureDetector(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 4),
|
||||
const BottomSheetHandlerBar(),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
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),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25.0),
|
||||
child: Text(
|
||||
s.chose_plan_start_date_2,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyles.textMMedium.copyWith(
|
||||
color: appTheme.black,
|
||||
const SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25.0),
|
||||
child: Text(
|
||||
s.chose_plan_start_date_2,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyles.textMMedium.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: CustomDivider(),
|
||||
),
|
||||
CalendarWidget(
|
||||
startDate: startDate,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () async {
|
||||
final result = await widget.chatCubit.choseStartPlanDate(startDate[0]);
|
||||
if (result) {
|
||||
showSuccessToast('Дата установлена');
|
||||
if (!context.mounted) return;
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
showErrorToast('Не удалось установить дату');
|
||||
if (!context.mounted) return;
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
height: 60,
|
||||
text: s.confirm,
|
||||
buttonTextStyle: TextStyles.textLSemibold.copyWith(
|
||||
color: appTheme.whiteA700,
|
||||
),
|
||||
buttonStyle: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
const SizedBox(height: 12),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: CustomDivider(),
|
||||
),
|
||||
CalendarWidget(
|
||||
startDate: startDate,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () async {
|
||||
final result = await widget.chatCubit.choseStartPlanDate(startDate[0]);
|
||||
if (result) {
|
||||
showSuccessToast('Дата установлена');
|
||||
if (!context.mounted) return;
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
showErrorToast('Не удалось установить дату');
|
||||
if (!context.mounted) return;
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
height: 60,
|
||||
text: s.confirm,
|
||||
buttonTextStyle: TextStyles.textLSemibold.copyWith(
|
||||
color: appTheme.whiteA700,
|
||||
),
|
||||
buttonStyle: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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/complete_plan_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/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -17,12 +18,12 @@ import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
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 double? planPrice;
|
||||
final String? planName;
|
||||
final int? chosenPlanId;
|
||||
|
||||
final bool hasPersonalDiet;
|
||||
@override
|
||||
State<NotificationBanner> createState() => _NotificationBannerState();
|
||||
}
|
||||
@@ -68,7 +69,8 @@ class _NotificationBannerState extends State<NotificationBanner> {
|
||||
BannerType.date => [
|
||||
SizedBox(
|
||||
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),
|
||||
GestureDetector(
|
||||
@@ -78,6 +80,7 @@ class _NotificationBannerState extends State<NotificationBanner> {
|
||||
context: context,
|
||||
builder: (context) => ChosePlanDateWidget(
|
||||
chatCubit: cubit,
|
||||
hasPersonalDiet: widget.hasPersonalDiet,
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -155,6 +158,20 @@ class _NotificationBannerState extends State<NotificationBanner> {
|
||||
),
|
||||
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 }
|
||||
|
||||
@@ -22,6 +22,7 @@ abstract class ConsultationModel with _$ConsultationModel {
|
||||
@JsonKey(name: 'end_date', fromJson: parseDate) required DateTime endDate,
|
||||
@JsonKey(name: 'consultant_id') required int consultantId,
|
||||
required List<DiaryModel> diaries,
|
||||
@JsonKey(name: 'personal_diet_id') required int? personalDietId,
|
||||
}) = _ConsultationModel;
|
||||
|
||||
factory ConsultationModel.fromJson(Map<String, dynamic> json) => _$ConsultationModelFromJson(json);
|
||||
|
||||
@@ -67,6 +67,13 @@ class CreatePlanCubit extends Cubit<CreatePlanState> {
|
||||
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) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
@@ -418,18 +425,21 @@ class CreatePlanCubit extends Cubit<CreatePlanState> {
|
||||
'price': int.parse((state.planData.options[0].price as double).toStringAsFixed(0)),
|
||||
'description_md': state.planData.options[0].description,
|
||||
'items': Map.fromIterable(state.planData.options[0].items),
|
||||
'has_personal_diet': state.planData.options[0].hasPersonalDiet ? '1' : '0',
|
||||
},
|
||||
'packet2_options': {
|
||||
'short': state.planData.options[1].short,
|
||||
'price': int.parse((state.planData.options[1].price as double).toStringAsFixed(0)),
|
||||
'description_md': state.planData.options[1].description,
|
||||
'items': Map.fromIterable(state.planData.options[1].items),
|
||||
'has_personal_diet': state.planData.options[1].hasPersonalDiet ? '1' : '0',
|
||||
},
|
||||
'packet3_options': {
|
||||
'short': state.planData.options[2].short,
|
||||
'price': int.parse((state.planData.options[2].price as double).toStringAsFixed(0)),
|
||||
'description_md': state.planData.options[2].description,
|
||||
'items': Map.fromIterable(state.planData.options[2].items),
|
||||
'has_personal_diet': state.planData.options[2].hasPersonalDiet ? '1' : '0',
|
||||
},
|
||||
});
|
||||
} else {
|
||||
@@ -440,6 +450,7 @@ class CreatePlanCubit extends Cubit<CreatePlanState> {
|
||||
'price': int.parse((state.planData.options[0].price as double).toStringAsFixed(0)),
|
||||
'description_md': state.planData.options[0].description,
|
||||
'items': Map.fromIterable(state.planData.options[0].items),
|
||||
'has_personal_diet': state.planData.options[0].hasPersonalDiet ? '1' : '0',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class _OptionWidgetState extends State<OptionWidget> {
|
||||
2 => thirdOptionCustomerPriceController,
|
||||
_ => secondOptionCustomerPriceController,
|
||||
};
|
||||
|
||||
|
||||
final price = double.tryParse(customerPriceController.text.replaceAll('₽', ''));
|
||||
creatorPriceController.text = '${((price ?? 0) * 0.8).toStringAsFixed(2)}₽';
|
||||
firstOptionTitleController.text = state.planData.options[selectedOptionIndex].short;
|
||||
@@ -255,33 +255,31 @@ class _OptionWidgetState extends State<OptionWidget> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const CustomDivider(),
|
||||
// const SizedBox(height: 16),
|
||||
// Row(
|
||||
// children: [
|
||||
// Checkbox(
|
||||
// value: isChecked,
|
||||
// activeColor: appTheme.gray,
|
||||
// checkColor: appTheme.gray,
|
||||
// fillColor: const WidgetStatePropertyAll(Colors.transparent),
|
||||
// side: WidgetStateBorderSide.resolveWith(
|
||||
// (Set<WidgetState> states) {
|
||||
// return BorderSide(width: 1, color: appTheme.gray);
|
||||
// },
|
||||
// ),
|
||||
// onChanged: (bool? value) {
|
||||
// setState(() {
|
||||
// isChecked = value ?? false;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// Expanded(
|
||||
// child: Text(
|
||||
// s.option_personal_diet_desc,
|
||||
// style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: state.planData.options[selectedOptionIndex].hasPersonalDiet,
|
||||
activeColor: appTheme.gray,
|
||||
checkColor: appTheme.gray,
|
||||
fillColor: const WidgetStatePropertyAll(Colors.transparent),
|
||||
side: WidgetStateBorderSide.resolveWith(
|
||||
(Set<WidgetState> states) {
|
||||
return BorderSide(width: 1, color: appTheme.gray);
|
||||
},
|
||||
),
|
||||
onChanged: (bool? value) {
|
||||
context.read<CreatePlanCubit>().togglePersonalizedDietOptionState();
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
s.option_personal_diet_desc,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -13,8 +13,15 @@ class CalendarWidget extends StatefulWidget {
|
||||
|
||||
class _CalendarWidgetState extends State<CalendarWidget> {
|
||||
CalendarFormat _calendarFormat = CalendarFormat.week;
|
||||
DateTime _focusedDay = DateTime.now();
|
||||
DateTime? _selectedDay = DateTime.now();
|
||||
late DateTime _focusedDay;
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
@@ -23,7 +30,7 @@ class _CalendarWidgetState extends State<CalendarWidget> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: TableCalendar(
|
||||
firstDay: DateTime.now(),
|
||||
firstDay: widget.startDate.isEmpty ? DateTime.now() : widget.startDate[0],
|
||||
lastDay: DateTime.utc(2030, 3, 14),
|
||||
locale: 'ru_RU',
|
||||
startingDayOfWeek: StartingDayOfWeek.monday,
|
||||
|
||||
@@ -67,11 +67,19 @@ abstract class PacketOptions with _$PacketOptions {
|
||||
@JsonKey(name: "price") required dynamic price,
|
||||
@JsonKey(name: "short") required String short,
|
||||
@JsonKey(name: "description_md") required String description,
|
||||
@JsonKey(name: "has_personal_diet", fromJson: _parseHasPersonalDietField) required bool hasPersonalDiet,
|
||||
}) = _PacketOptions;
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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/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/personal_diet_suggestion/presentation/personal_diet_suggestion_screen.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@@ -146,6 +147,7 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
||||
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
||||
}
|
||||
} else if (state.selectedStateIndex == 2) {
|
||||
GoRouter.of(context).pushNamed(PersonalDietSuggestionScreen.name, extra: widget.diet.id);
|
||||
} else {
|
||||
GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: widget.diet);
|
||||
}
|
||||
|
||||
@@ -132,9 +132,9 @@ class _InfoByOrderScreenContentState extends State<InfoByOrderScreenContent> {
|
||||
const SizedBox(height: 8),
|
||||
PlanInfo(title: plan.plan.name, description: plan.plan.details, imagePath: plan.plan.image),
|
||||
const SizedBox(height: 8),
|
||||
OptionWidget(option: chosenOption, disableDuration: true),
|
||||
OptionWidget(option: chosenOption, disableDuration: true, duration: plan.plan.duration),
|
||||
const SizedBox(height: 8),
|
||||
PlanState(state: plan.chosenPlanState),
|
||||
PlanState(state: plan.chosenPlanState, hasPersonalDiet: chosenOption?.hasPersonalDiet ?? false,),
|
||||
const SizedBox(height: 20),
|
||||
if (widget.successfulPayment == null)
|
||||
CustomOutlinedButton(
|
||||
|
||||
@@ -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:flutter/material.dart';
|
||||
|
||||
class PlanState extends StatelessWidget {
|
||||
PlanState({super.key, required this.state});
|
||||
class PlanState extends StatefulWidget {
|
||||
const PlanState({super.key, required this.state, required this.hasPersonalDiet});
|
||||
final ChosenPlanStateEnum state;
|
||||
final List<List<ChosenPlanStateEnum>> 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,
|
||||
]
|
||||
];
|
||||
final bool hasPersonalDiet;
|
||||
|
||||
@override
|
||||
State<PlanState> createState() => _PlanStateState();
|
||||
}
|
||||
|
||||
class _PlanStateState extends State<PlanState> {
|
||||
late final List<List<ChosenPlanStateEnum>> states;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.hasPersonalDiet) {
|
||||
states = [
|
||||
[ChosenPlanStateEnum.stateInited, ChosenPlanStateEnum.stateInCoordination],
|
||||
[ChosenPlanStateEnum.stateStartDateHasBeenSet, ChosenPlanStateEnum.statePendingPayment],
|
||||
[ChosenPlanStateEnum.statePaid],
|
||||
[ChosenPlanStateEnum.personalDietSet],
|
||||
[
|
||||
ChosenPlanStateEnum.stateStarted,
|
||||
ChosenPlanStateEnum.stateInProgress,
|
||||
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
|
||||
Widget build(BuildContext 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(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
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];
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -51,29 +74,16 @@ class PlanState extends StatelessWidget {
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.check,
|
||||
color: appTheme.whiteA700,
|
||||
size: 14,
|
||||
),
|
||||
),
|
||||
child: Center(child: Icon(Icons.check, color: appTheme.whiteA700, size: 14)),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
text,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
Text(text, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Container(
|
||||
height: 12,
|
||||
width: 1,
|
||||
color: color,
|
||||
),
|
||||
)
|
||||
child: Container(height: 12, width: 1, color: color),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
);
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ enum ChosenPlanStateEnum {
|
||||
stateComplained,
|
||||
@JsonValue('done')
|
||||
stateDone,
|
||||
@JsonValue('personal_diet_setted')
|
||||
personalDietSet,
|
||||
@JsonValue('charge_was_collected')
|
||||
stateChargeWasCollected;
|
||||
|
||||
@@ -40,6 +42,7 @@ enum ChosenPlanStateEnum {
|
||||
ChosenPlanStateEnum.stateLastDayFinished,
|
||||
ChosenPlanStateEnum.stateDone,
|
||||
ChosenPlanStateEnum.stateInProgress,
|
||||
ChosenPlanStateEnum.personalDietSet,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -64,7 +67,8 @@ enum ChosenPlanStateEnum {
|
||||
ChosenPlanStateEnum.stateLastDayStarted,
|
||||
ChosenPlanStateEnum.stateLastDayFinished,
|
||||
ChosenPlanStateEnum.stateComplained,
|
||||
ChosenPlanStateEnum.stateDone
|
||||
ChosenPlanStateEnum.stateDone,
|
||||
ChosenPlanStateEnum.personalDietSet
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,12 +505,15 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
switch (state.chosenOptionIndex) {
|
||||
1 => OptionWidget(
|
||||
option: state.planModel?.packet2Options,
|
||||
duration: state.planModel?.duration ?? 0,
|
||||
),
|
||||
2 => OptionWidget(
|
||||
option: state.planModel?.packet3Options,
|
||||
duration: state.planModel?.duration ?? 0,
|
||||
),
|
||||
_ => OptionWidget(
|
||||
option: state.planModel?.packet1Options,
|
||||
duration: state.planModel?.duration ?? 0,
|
||||
),
|
||||
},
|
||||
const SizedBox(
|
||||
|
||||
@@ -138,6 +138,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Если вы любите мучные продукты, но хотите придерживаться диеты, вам подходит диета с добавленим мучных блюд на основе цельнозерновых вариантов. В них больше сложных углеводов и клетчатки, что способствует длительному чувству сытости и поддерживает здоровье пищеварительной системы.",
|
||||
),
|
||||
"carbohydrates": MessageLookupByLibrary.simpleMessage("Углеводы"),
|
||||
"changeDiet": MessageLookupByLibrary.simpleMessage("Заменить диету"),
|
||||
"chargeApproved": MessageLookupByLibrary.simpleMessage("Выплата одобрена"),
|
||||
"chargeCollectionFailed": MessageLookupByLibrary.simpleMessage(
|
||||
"Не удалось оформить выплату",
|
||||
@@ -158,6 +159,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"choose_plan_start_date": MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите дату старта плана питания",
|
||||
),
|
||||
"choose_plan_start_date_with_personal_diet":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите дату старта плана питания с учетом составления персональной диеты",
|
||||
),
|
||||
"choose_start_diet_date": MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите дату старты диеты. Она отобразиться у Вас в дневнике",
|
||||
),
|
||||
@@ -165,6 +170,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"chose_plan_start_date_2": MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите дату старты плана. Она отобразиться в дневнике пользователя",
|
||||
),
|
||||
"chosenPlanStartDateDescr": MessageLookupByLibrary.simpleMessage(
|
||||
"Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты",
|
||||
),
|
||||
"circumference_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Все замеры обязательны к заполнению",
|
||||
),
|
||||
@@ -246,6 +254,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Не удалось обновить диету",
|
||||
),
|
||||
"country": MessageLookupByLibrary.simpleMessage("Страна"),
|
||||
"createPersonalDiet": MessageLookupByLibrary.simpleMessage(
|
||||
"Составьте персональную диету",
|
||||
),
|
||||
"create_diet": MessageLookupByLibrary.simpleMessage("Создание диеты"),
|
||||
"cunsutation_was_paid_successfully": MessageLookupByLibrary.simpleMessage(
|
||||
"Поздравляем, консультация успешно оплачена",
|
||||
@@ -274,6 +285,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"deleted": MessageLookupByLibrary.simpleMessage("Удалена"),
|
||||
"diary": MessageLookupByLibrary.simpleMessage("Дневник"),
|
||||
"diet": MessageLookupByLibrary.simpleMessage("Диета"),
|
||||
"dietSuggestion": MessageLookupByLibrary.simpleMessage("Предложение диеты"),
|
||||
"diet_author": MessageLookupByLibrary.simpleMessage("Автор диеты"),
|
||||
"diet_has_been_sent_to_draft": MessageLookupByLibrary.simpleMessage(
|
||||
"снята с публикации и перенесена в черновик",
|
||||
@@ -393,6 +405,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"from_z_to_a": MessageLookupByLibrary.simpleMessage("Название: Я-А"),
|
||||
"gallery": MessageLookupByLibrary.simpleMessage("Галерея"),
|
||||
"general_info": MessageLookupByLibrary.simpleMessage("Общая информация"),
|
||||
"goToMyDiets": MessageLookupByLibrary.simpleMessage(
|
||||
"Перейти к моим диетам",
|
||||
),
|
||||
"go_to_diary": MessageLookupByLibrary.simpleMessage("Перейти в дневник"),
|
||||
"gr": MessageLookupByLibrary.simpleMessage("гр"),
|
||||
"grams": MessageLookupByLibrary.simpleMessage("гр"),
|
||||
@@ -570,6 +585,12 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"pcs": MessageLookupByLibrary.simpleMessage("шт"),
|
||||
"pending_payment": MessageLookupByLibrary.simpleMessage("Ожидается оплата"),
|
||||
"personal": MessageLookupByLibrary.simpleMessage("Персональные"),
|
||||
"personalDietCreating": MessageLookupByLibrary.simpleMessage(
|
||||
"Составление индивидуальной диеты",
|
||||
),
|
||||
"personal_diet_set": MessageLookupByLibrary.simpleMessage(
|
||||
"Персональная диета установлена",
|
||||
),
|
||||
"personal_diet_state": MessageLookupByLibrary.simpleMessage("Персональная"),
|
||||
"photo": MessageLookupByLibrary.simpleMessage("Фото"),
|
||||
"physical_fitness": MessageLookupByLibrary.simpleMessage(
|
||||
@@ -699,6 +720,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"successfully_published": MessageLookupByLibrary.simpleMessage(
|
||||
"успешно опубликован",
|
||||
),
|
||||
"suggestDiet": MessageLookupByLibrary.simpleMessage("Предложить диету"),
|
||||
"suicide": MessageLookupByLibrary.simpleMessage("Склонение к самоубийству"),
|
||||
"takes_pills": MessageLookupByLibrary.simpleMessage("Принимает лекарства"),
|
||||
"tap_on_link_to_pay": MessageLookupByLibrary.simpleMessage(
|
||||
|
||||
@@ -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 {
|
||||
return Intl.message(
|
||||
@@ -3504,6 +3584,16 @@ class S {
|
||||
return Intl.message('Покупатель', name: 'customer', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Персональная диета установлена`
|
||||
String get personal_diet_set {
|
||||
return Intl.message(
|
||||
'Персональная диета установлена',
|
||||
name: 'personal_diet_set',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Поздравляем!`
|
||||
String get congratulations {
|
||||
return Intl.message(
|
||||
|
||||
@@ -408,6 +408,14 @@
|
||||
"copy": "Скопировать",
|
||||
"reply": "Ответить",
|
||||
"deleteComment": "Удалить комментарий",
|
||||
"personalDietCreating": "Составление индивидуальной диеты",
|
||||
"dietSuggestion": "Предложение диеты",
|
||||
"suggestDiet": "Предложить диету",
|
||||
"changeDiet": "Заменить диету",
|
||||
"choose_plan_start_date_with_personal_diet": "Выберите дату старта плана питания с учетом составления персональной диеты",
|
||||
"chosenPlanStartDateDescr": "Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты",
|
||||
"createPersonalDiet": "Составьте персональную диету",
|
||||
"goToMyDiets": "Перейти к моим диетам",
|
||||
"accountDeleting": "Удаление аккаунта",
|
||||
"youShureYouWantToDeleteAccount": "Вы уверены, что хотите удалить аккаунт?",
|
||||
"itCantBeRecovered": "Его нельзя будет восстановить",
|
||||
@@ -416,6 +424,7 @@
|
||||
"resend": "Отправить повторно",
|
||||
"notifications": "Уведомления",
|
||||
"customer": "Покупатель",
|
||||
"personal_diet_set": "Персональная диета установлена",
|
||||
"congratulations": "Поздравляем!",
|
||||
"youWithUs": "Вы с итвио уже\n",
|
||||
"fourteenDays": "14 дней",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: eatvio_app
|
||||
description: A new Flutter project.
|
||||
version: 1.3.2+81
|
||||
version: 1.3.3+82
|
||||
publish_to: 'none'
|
||||
|
||||
environment:
|
||||
|
||||
Reference in New Issue
Block a user