diff --git a/android/app/build.gradle b/android/app/build.gradle index 8fc22d6d..79e6d71d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -19,15 +19,15 @@ def yandexClientId = project.hasProperty('YANDEX_CLIENT_ID') ? project.property( android { namespace = "com.eatvioapp.app" compileSdk = flutter.compileSdkVersion - ndkVersion = "27.0.12077973" + ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() + jvmTarget = JavaVersion.VERSION_17.toString() } defaultConfig { diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart index 6b17ebb2..b42bf76e 100644 --- a/lib/features/chat/presentation/pages/chat_screen.dart +++ b/lib/features/chat/presentation/pages/chat_screen.dart @@ -135,12 +135,12 @@ class _ChatScreenState extends State { } 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; + } else if (chosenOption?.hasPersonalDiet == true && amIConsultant && chosenPlan.chosenPlanState != ChosenPlanStateEnum.stateDone) { + bannerType = BannerType.setPersonalDiet; } return Scaffold( diff --git a/lib/features/consultations/presentation/widgets/consultation_card_widget.dart b/lib/features/consultations/presentation/widgets/consultation_card_widget.dart index f9fa4143..b1529280 100644 --- a/lib/features/consultations/presentation/widgets/consultation_card_widget.dart +++ b/lib/features/consultations/presentation/widgets/consultation_card_widget.dart @@ -63,25 +63,28 @@ class _ConsultationCardWidgetState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - CircleAvatar(radius: 30, backgroundImage: NetworkImage(widget.consultationsModel.userProfilePhotoUrl)), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.consultationsModel.userName, - style: const TextStyle(height: 1, color: Color(0xFF323F4B), fontSize: 16, fontWeight: FontWeight.w600), - ), - const SizedBox(height: 4), - Text( - widget.consultationsModel.planTitle, - style: const TextStyle(height: 1, color: Color(0xFF88949F), fontSize: 14, fontWeight: FontWeight.w500), - ), - ], - ), - ], + GestureDetector( + onTap: () => GoRouter.of(context).pushNamed('profileScreen', extra: widget.consultationsModel.userSlug), + child: Row( + children: [ + CircleAvatar(radius: 30, backgroundImage: NetworkImage(widget.consultationsModel.userProfilePhotoUrl)), + const SizedBox(width: 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.consultationsModel.userName, + style: const TextStyle(height: 1, color: Color(0xFF323F4B), fontSize: 16, fontWeight: FontWeight.w600), + ), + const SizedBox(height: 4), + Text( + widget.consultationsModel.planTitle, + style: const TextStyle(height: 1, color: Color(0xFF88949F), fontSize: 14, fontWeight: FontWeight.w500), + ), + ], + ), + ], + ), ), const SizedBox(height: 12), GestureDetector( diff --git a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart index 242db660..7d50d11c 100644 --- a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart +++ b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart @@ -302,7 +302,10 @@ class CreateDietCubit extends Cubit { Future createDiet() async { emit(state.copyWith(isDietPublishing: true)); - if (!_isFromValid()) return 'validation'; + if (!_isFromValid()) { + emit(state.copyWith(isDietPublishing: false)); + return 'validation'; + } try { File? file; if (state.dietData.imageUrl != null) { diff --git a/lib/features/diets/presentation/widgets/author_card.dart b/lib/features/diets/presentation/widgets/author_card.dart index 3be70bce..3a7c17b8 100644 --- a/lib/features/diets/presentation/widgets/author_card.dart +++ b/lib/features/diets/presentation/widgets/author_card.dart @@ -29,7 +29,7 @@ class AuthorCard extends StatelessWidget { child: Stack( children: [ Padding( - padding: const EdgeInsets.only(left: 16, top: 16, bottom: 24), + padding: const EdgeInsets.only(left: 16, top: 16, bottom: 24, right: 16), child: Column( children: [ ListTile( @@ -68,20 +68,23 @@ class AuthorCard extends StatelessWidget { if (author.authorPlaceInRating != null) InfoBouble( radius: 12, - backgroundColor: appTheme.whiteA700, + backgroundColor: appTheme.cardBackground, children: [ Text('${author.authorPlaceInRating}-й в рейтинге', style: TextStyles.textMMediumAuto.copyWith(color: appTheme.blueA400)), ], ), ] else - GestureDetector( - onTap: () { - GoRouter.of(context).pushNamed(UserDetailsScreen.name, extra: customerProfile!.slug); - }, - child: InfoBouble( - radius: 12, - backgroundColor: appTheme.whiteA700, - children: [Text('Анкета пользователя', style: TextStyles.textMMediumAuto.copyWith(color: appTheme.blueA400))], + Expanded( + child: GestureDetector( + onTap: () { + GoRouter.of(context).pushNamed(UserDetailsScreen.name, extra: customerProfile!.slug); + }, + child: InfoBouble( + radius: 12, + backgroundColor: appTheme.cardBackground, + mainAxisAlignment: MainAxisAlignment.center, + children: [Text('Анкета пользователя', style: TextStyles.textMMediumAuto.copyWith(color: appTheme.blueA400))], + ), ), ), ], diff --git a/lib/features/diets/presentation/widgets/info_bouble.dart b/lib/features/diets/presentation/widgets/info_bouble.dart index d32c534c..1cb12f9d 100644 --- a/lib/features/diets/presentation/widgets/info_bouble.dart +++ b/lib/features/diets/presentation/widgets/info_bouble.dart @@ -2,20 +2,25 @@ import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:flutter/material.dart'; class InfoBouble extends StatelessWidget { - const InfoBouble({super.key, required this.children, this.backgroundColor, this.radius = 100, this.padding}); + const InfoBouble({ + super.key, + required this.children, + this.backgroundColor, + this.radius = 100, + this.padding, + this.mainAxisAlignment = MainAxisAlignment.start, + }); final List children; final Color? backgroundColor; final double radius; final EdgeInsetsGeometry? padding; + final MainAxisAlignment mainAxisAlignment; @override Widget build(BuildContext context) { return Container( padding: padding ?? const EdgeInsets.symmetric(horizontal: 12, vertical: 8.5), - decoration: BoxDecoration( - color: backgroundColor ?? appTheme.gray50, - borderRadius: BorderRadius.circular(radius), - ), - child: Row(mainAxisSize: MainAxisSize.min, children: children), + decoration: BoxDecoration(color: backgroundColor ?? appTheme.gray50, borderRadius: BorderRadius.circular(radius)), + child: Row(mainAxisSize: MainAxisSize.min, mainAxisAlignment: mainAxisAlignment, children: children), ); } } diff --git a/lib/features/notifications/models/notification_model.dart b/lib/features/notifications/models/notification_model.dart index 55c79e51..cc77616e 100644 --- a/lib/features/notifications/models/notification_model.dart +++ b/lib/features/notifications/models/notification_model.dart @@ -316,7 +316,7 @@ class ChosenPlanFinishedToConsultantNotification implements BaseNotificationMode type: type, planName: json['plan_name'], customerName: json['client_name'], - planId: json['plan_id'], + planId: json['chosen_plan_id'], isRead: isRead ?? false, createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()), ); @@ -1695,6 +1695,35 @@ class DiaryReminderForUsersNotification implements BaseNotificationModel { } } +class PersonalDietIsDefinedToCustomerNotification implements BaseNotificationModel { + @override + final NotificationType type; + @override + final bool isRead; + @override + final DateTime createdAt; + final String dietName; + final int dietId; + + PersonalDietIsDefinedToCustomerNotification({ + required this.type, + required this.isRead, + required this.createdAt, + required this.dietName, + required this.dietId, + }); + + factory PersonalDietIsDefinedToCustomerNotification.fromJson(Map json, NotificationType type, {bool? isRead, String? createdAt}) { + return PersonalDietIsDefinedToCustomerNotification( + type: type, + isRead: isRead ?? false, + createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()), + dietName: json['diet_name'] ?? '', + dietId: json['diet_id'], + ); + } +} + enum NotificationType { // Diet related dietCancelled, @@ -1726,6 +1755,7 @@ enum NotificationType { userDailyReportCompleted, chosenPlanFinishedToConsultant, stayOnTrackToCustomer, + personalDietIsDefinedToCustomer, // Comments entityCommented, @@ -1834,6 +1864,7 @@ enum NotificationType { 'chosen-plan-finished-to-consultant' => NotificationType.chosenPlanFinishedToConsultant, 'stay-on-track-to-customer' => NotificationType.stayOnTrackToCustomer, 'diary-reminder-for-users' => NotificationType.diaryReminderForUsers, + 'personal-diet-is-defined-to-customer' => NotificationType.personalDietIsDefinedToCustomer, // Legacy mapping 'App\\Notifications\\Plan\\PlanSubscriptionStartedToAuthor' => NotificationType.planSubscriptionStartedToAuthor, diff --git a/lib/features/notifications/presentation/notifications_cubit/notifications_cubit.dart b/lib/features/notifications/presentation/notifications_cubit/notifications_cubit.dart index 8c8c5aaa..110607c0 100644 --- a/lib/features/notifications/presentation/notifications_cubit/notifications_cubit.dart +++ b/lib/features/notifications/presentation/notifications_cubit/notifications_cubit.dart @@ -261,6 +261,12 @@ class NotificationsCubit extends Cubit { createdAt: createdAt, ), NotificationType.diaryReminderForUsers => DiaryReminderForUsersNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt), + NotificationType.personalDietIsDefinedToCustomer => PersonalDietIsDefinedToCustomerNotification.fromJson( + notificationJson, + type, + isRead: isRead, + createdAt: createdAt, + ), NotificationType.unknown => UnknownNotification(type: type), }; } catch (e) { diff --git a/lib/features/notifications/presentation/widgets/notification_widget.dart b/lib/features/notifications/presentation/widgets/notification_widget.dart index 6b675382..c6bd5328 100644 --- a/lib/features/notifications/presentation/widgets/notification_widget.dart +++ b/lib/features/notifications/presentation/widgets/notification_widget.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/core/routing/route_constants.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/utils/date_time_utils.dart'; @@ -113,7 +114,11 @@ class NotificationWidget extends StatelessWidget { notification: notification as ProductStatusUpdatedForAuthorNotification, ), DiaryReminderForUsersNotification() => _DiaryReminderForUsersWidget(notification: notification as DiaryReminderForUsersNotification), + PersonalDietIsDefinedToCustomerNotification() => _PersonalDietIsDefinedToCustomerWidget( + notification: notification as PersonalDietIsDefinedToCustomerNotification, + ), UnknownNotification() => _UnknownNotificationWidget(notification: notification as UnknownNotification), + // TODO: Handle this case. }; } } @@ -364,34 +369,38 @@ class _ChosenPlanFinishedToConsultantWidget extends StatelessWidget { // CardSettingsScreen class _BaseNotificationWidget extends StatelessWidget { - const _BaseNotificationWidget({required this.notificationsText, required this.isRead, required this.createdAt}); + const _BaseNotificationWidget({required this.notificationsText, required this.isRead, required this.createdAt, this.onTap}); final String notificationsText; final bool isRead; final DateTime createdAt; + final void Function()? onTap; @override Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: Text(notificationsText, style: TextStyles.textMMedium.copyWith(color: appTheme.black)), - ), - if (!isRead) - Container( - decoration: BoxDecoration(color: appTheme.blueA400, shape: BoxShape.circle), - width: 8, - height: 8, + return GestureDetector( + onTap: onTap, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text(notificationsText, style: TextStyles.textMMedium.copyWith(color: appTheme.black)), ), - ], - ), - const SizedBox(height: 4), - Text( - '${createdAt.day} ${_getMonthName(createdAt.month)} ${createdAt.hour.toString().padLeft(2, '0')}:${createdAt.minute.toString().padLeft(2, '0')}', - style: TextStyles.textSMedium.copyWith(color: appTheme.gray600), - ), - ], + if (!isRead) + Container( + decoration: BoxDecoration(color: appTheme.blueA400, shape: BoxShape.circle), + width: 8, + height: 8, + ), + ], + ), + const SizedBox(height: 4), + Text( + '${createdAt.day} ${_getMonthName(createdAt.month)} ${createdAt.hour.toString().padLeft(2, '0')}:${createdAt.minute.toString().padLeft(2, '0')}', + style: TextStyles.textSMedium.copyWith(color: appTheme.gray600), + ), + ], + ), ); } @@ -1053,3 +1062,17 @@ class _DiaryReminderForUsersWidget extends StatelessWidget { return _BaseNotificationWidget(isRead: notification.isRead, notificationsText: 'Напоминание о заполнении дневника', createdAt: notification.createdAt); } } + +class _PersonalDietIsDefinedToCustomerWidget extends StatelessWidget { + const _PersonalDietIsDefinedToCustomerWidget({required this.notification}); + final PersonalDietIsDefinedToCustomerNotification notification; + @override + Widget build(BuildContext context) { + return _BaseNotificationWidget( + isRead: notification.isRead, + onTap: () => GoRouter.of(context).push(RouteConstants.aboutDietScreen, extra: {'id': notification.dietId, 'navigateToComments': false}), + notificationsText: 'Персональная диета "${notification.dietName}" установлена', + createdAt: notification.createdAt, + ); + } +} diff --git a/lib/features/notifications/service/notifications_service.dart b/lib/features/notifications/service/notifications_service.dart index 5b3ca78b..1fd5e4d6 100644 --- a/lib/features/notifications/service/notifications_service.dart +++ b/lib/features/notifications/service/notifications_service.dart @@ -407,6 +407,12 @@ class NotificationsService { isRead: readDate != null, createdAt: createdAt, ), + NotificationType.personalDietIsDefinedToCustomer => PersonalDietIsDefinedToCustomerNotification.fromJson( + notificationJson['data'], + type, + isRead: readDate != null, + createdAt: createdAt, + ), NotificationType.unknown => UnknownNotification(type: type, createdAt: parseDate(createdAt)), }; } catch (e) { diff --git a/lib/features/order_info/presentation/widgets/payment_banner.dart b/lib/features/order_info/presentation/widgets/payment_banner.dart index bd570581..5dc56d90 100644 --- a/lib/features/order_info/presentation/widgets/payment_banner.dart +++ b/lib/features/order_info/presentation/widgets/payment_banner.dart @@ -11,11 +11,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; class PaymentBanner extends StatefulWidget { - const PaymentBanner({ - super.key, - required this.successfulPayment, - - }); + const PaymentBanner({super.key, required this.successfulPayment}); final bool successfulPayment; @override @@ -29,8 +25,9 @@ class _PaymentBannerState extends State { final s = S.of(context); final size = MediaQuery.sizeOf(context); return MainBackgroundBouble( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Stack(children: [ + padding: const EdgeInsets.symmetric(vertical: 16), + child: Stack( + children: [ Positioned( left: 0, top: 0, @@ -38,8 +35,9 @@ class _PaymentBannerState extends State { child: Container( width: 4, decoration: BoxDecoration( - color: widget.successfulPayment ? appTheme.blueA400 : appTheme.strongRed, - borderRadius: const BorderRadius.only(topRight: Radius.circular(20), bottomRight: Radius.circular(20))), + color: widget.successfulPayment ? appTheme.blueA400 : appTheme.strongRed, + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), bottomRight: Radius.circular(20)), + ), ), ), Padding( @@ -50,78 +48,65 @@ class _PaymentBannerState extends State { ? [ SizedBox( width: size.width * 0.6, - child: Text( - s.cunsutation_was_paid_successfully, - style: TextStyles.textLSemibold.copyWith(color: appTheme.black), - ), - ), - const SizedBox( - height: 8, + child: Text(s.cunsutation_was_paid_successfully, style: TextStyles.textLSemibold.copyWith(color: appTheme.black)), ), + const SizedBox(height: 8), SizedBox( width: size.width * 0.6, - child: Text( - s.wait_for_start_day, - style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black), - ), - ), - const SizedBox( - height: 16, + child: Text(s.wait_for_start_day, style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black)), ), + const SizedBox(height: 16), isLoading ? const Center(child: Loader()) : CustomOutlinedButton( text: s.go_to_diary, height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: - ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)), + buttonStyle: ButtonStyle( + side: const WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), + ), onPressed: () async { GoRouter.of(context).pushReplacement('/diary-screen'); }, ), + const SizedBox(height: 10), isLoading ? const Center(child: Loader()) : CustomOutlinedButton( text: s.back_to_chat, height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: - ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)), + buttonStyle: ButtonStyle( + side: const WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), + ), onPressed: () { GoRouter.of(context).pop(); }, - ) + ), ] : [ SizedBox( width: size.width * 0.6, - child: Text( - s.smth_went_wrong_payment_failed, - style: TextStyles.textLSemibold.copyWith(color: appTheme.black), - ), - ), - const SizedBox( - height: 8, + child: Text(s.smth_went_wrong_payment_failed, style: TextStyles.textLSemibold.copyWith(color: appTheme.black)), ), + const SizedBox(height: 8), SizedBox( width: size.width * 0.6, - child: Text( - s.try_again_2, - style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black), - ), - ), - const SizedBox( - height: 16, + child: Text(s.try_again_2, style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black)), ), + const SizedBox(height: 16), isLoading ? const Center(child: Loader()) : CustomOutlinedButton( text: s.pay, height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: - ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)), + buttonStyle: ButtonStyle( + side: const WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), + ), onPressed: () async { final planId = context.read().state.chosenPlan?.id; setState(() { @@ -133,16 +118,15 @@ class _PaymentBannerState extends State { }); if (paymentLink != null && planId != null) { if (!context.mounted) return; - GoRouter.of(context).pushReplacement( - PaymentScreen.path, - extra: {'url': paymentLink, 'planId': planId}, - ); + GoRouter.of(context).pushReplacement(PaymentScreen.path, extra: {'url': paymentLink, 'planId': planId}); } }, - ) + ), ], ), - ) - ])); + ), + ], + ), + ); } } diff --git a/lib/features/registration_v2/cubit/registration_cubit.dart b/lib/features/registration_v2/cubit/registration_cubit.dart index 0a55ecff..67cd5a0d 100644 --- a/lib/features/registration_v2/cubit/registration_cubit.dart +++ b/lib/features/registration_v2/cubit/registration_cubit.dart @@ -7,7 +7,7 @@ import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dar import 'package:eatvio_app/features/registration_v2/models/registration_model.dart'; import 'package:eatvio_app/features/registration_v2/repositories/registration_repository_v2.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_password_generator/flutter_password_generator.dart'; +import 'package:gpassword/gpassword.dart'; class RegistrationCubitV2 extends Cubit { final RegistrationRepositoryV2 registrationRepository; @@ -230,9 +230,8 @@ class RegistrationCubitV2 extends Cubit { } Future _generatePassword() async { - final generator = FlutterPasswordGenerator(length: 8); - final result = await generator.generatePassword(); - final password = result['password'] as String; + final generator = GPassword(); + final password = generator.generate(passwordLength: 10); emit(state.copyWith(password: password)); return password; } diff --git a/lib/features/registration_v2/presentation/widgets/password_field.dart b/lib/features/registration_v2/presentation/widgets/password_field.dart index 859f9b67..b4fea946 100644 --- a/lib/features/registration_v2/presentation/widgets/password_field.dart +++ b/lib/features/registration_v2/presentation/widgets/password_field.dart @@ -42,6 +42,7 @@ class _PasswordFieldState extends State { copied = true; }); Future.delayed(const Duration(seconds: 3), () { + if (!context.mounted) return; setState(() { copied = false; }); diff --git a/lib/features/user_details/presentation/user_details_screen.dart b/lib/features/user_details/presentation/user_details_screen.dart index 46e986f4..a5552802 100644 --- a/lib/features/user_details/presentation/user_details_screen.dart +++ b/lib/features/user_details/presentation/user_details_screen.dart @@ -49,8 +49,7 @@ class _UserDetailsContentState extends State { final List chipsIntervalList = ['1', '3', '6', '12', 'all']; List weightPoints = []; - List circumferencePoints = []; - int _selectedChipIndex = 0; + List circumferencePoints = []; int _selectedChipIndex = 0; int _selectedIntervalChipIndex = 0; bool isMoreOptionsVisible = false; @override diff --git a/pubspec.yaml b/pubspec.yaml index 92c7d8a7..b1f430db 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -25,10 +25,10 @@ dependencies: flutter_form_builder: ^10.2.0 image_picker: ^1.2.0 flutter_typeahead: ^5.2.0 - go_router: ^16.1.0 + go_router: ^17.0.0 keyboard_dismisser: ^3.0.0 retrofit: ^4.7.1 - get_it: ^8.2.0 + get_it: ^9.0.5 dio: ^5.9.0 dart_pusher_channels: ^1.2.3 photo_view: ^0.15.0 @@ -37,11 +37,11 @@ dependencies: easy_debounce: ^2.0.3 badges: ^3.1.2 google_fonts: ^6.3.0 - syncfusion_flutter_charts: ^30.2.5 - syncfusion_flutter_gauges: ^30.2.5 + syncfusion_flutter_charts: ^31.2.10 + syncfusion_flutter_gauges: ^31.2.10 table_calendar: ^3.2.0 flutter_keyboard_visibility: ^6.0.0 - share_plus: ^11.1.0 + share_plus: ^12.0.1 flutter_html: ^3.0.0 file_picker: ^10.3.1 audioplayers: ^6.5.0 @@ -49,7 +49,7 @@ dependencies: mask_text_input_formatter: ^2.9.0 lottie: ^3.3.1 flutter_portal: ^1.1.4 - fluttertoast: ^8.2.12 + fluttertoast: ^9.0.0 flutter_rating_bar: ^4.0.1 flutter_image_compress: ^2.4.0 image: ^4.5.4 @@ -57,8 +57,8 @@ dependencies: http: ^1.5.0 flutter_native_splash: ^2.4.6 webview_flutter: ^4.13.0 - sentry_flutter: ^9.6.0 - connectivity_plus: ^6.1.5 + sentry_flutter: ^9.8.0 + connectivity_plus: ^7.0.0 visibility_detector: ^0.4.0+2 firebase_core: ^4.0.0 firebase_messaging: ^16.0.0 @@ -67,17 +67,18 @@ dependencies: collection: ^1.19.1 shared_preferences: ^2.5.3 version: ^3.0.2 - package_info_plus: ^8.3.1 - device_info_plus: ^11.5.0 + package_info_plus: ^9.0.0 + device_info_plus: ^12.2.0 permission_handler: ^12.0.1 qr_code_scanner_plus: ^2.0.10+1 - flutter_dotenv: ^5.2.1 - uuid: ^4.5.1 + flutter_dotenv: ^6.0.0 + uuid: ^4.5.2 appmetrica_plugin: ^3.3.0 vk_id: ^1.0.3 flutter_login_yandex: ^0.0.5 markdown: ^7.3.0 - flutter_password_generator: ^1.0.3 + gpassword: ^1.0.0 + mobile_scanner: ^7.1.3 dev_dependencies: build_runner: ^2.7.0 diff --git a/test/features/create_diet/integration_widget_test.dart b/test/features/create_diet/integration_widget_test.dart index 76f7de0b..0d8c7b31 100644 --- a/test/features/create_diet/integration_widget_test.dart +++ b/test/features/create_diet/integration_widget_test.dart @@ -35,7 +35,7 @@ void main() { setUp(() async { await sl.reset(); // Ensure dotenv has required keys before AppConfig constructor reads them - dotenv.testLoad(fileInput: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); + dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); // Register minimal AppConfig for tests to satisfy dependencies (e.g. image URL building) sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); mockCreateDietRepository = MockCreateDietRepository(); diff --git a/test/features/create_recipe/widget_test.dart b/test/features/create_recipe/widget_test.dart index 1b85ac35..6a60b0b3 100644 --- a/test/features/create_recipe/widget_test.dart +++ b/test/features/create_recipe/widget_test.dart @@ -35,7 +35,7 @@ void main() { setUp(() async { await sl.reset(); - dotenv.testLoad(fileInput: 'DEV_BASE_URL=\nBASE_URL=\n'); + dotenv.loadFromString(envString: 'DEV_BASE_URL=\nBASE_URL=\n'); mockRecipeRepository = MockRecipeRepository(); mockGlossaryRepository = MockGlossaryRepository(); createRecipeCubit = CreateRecipeCubit(recipeRepository: mockRecipeRepository, glossaryRepository: mockGlossaryRepository);