diff --git a/lib/core/routing/content_routes.dart b/lib/core/routing/content_routes.dart index 69d7ebf4..0556fab6 100644 --- a/lib/core/routing/content_routes.dart +++ b/lib/core/routing/content_routes.dart @@ -44,10 +44,15 @@ class ContentRoutes { builder: (context, state) { final slug = state.uri.queryParameters['slug']; if (slug != null) { - return AboutDietScreen(slug: slug, index: null, navigateToComments: false); + return AboutDietScreen(id: null, slug: slug, index: null, navigateToComments: false); } final data = state.extra as Map; - return AboutDietScreen(slug: data['slug'] as String, index: data['index'] as int?, navigateToComments: data['navigateToComments'] as bool); + return AboutDietScreen( + id: data['id'] as int?, + slug: data['slug'] as String?, + index: data['index'] as int?, + navigateToComments: data['navigateToComments'] as bool, + ); }, ), GoRoute( diff --git a/lib/features/auth/sdk/social_auth_facade.dart b/lib/features/auth/sdk/social_auth_facade.dart index 140da37b..b3543700 100644 --- a/lib/features/auth/sdk/social_auth_facade.dart +++ b/lib/features/auth/sdk/social_auth_facade.dart @@ -188,7 +188,7 @@ class SocialAuthFacade { try { final controller = VkIDController(clID: int.parse(clientIdStr)); - final authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: provider); + final authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: provider, scopes: [VkScope.phone, VkScope.email,]); final codeVerifier = authUri.key; final authUrl = authUri.value.toString(); final redirectScheme = 'vk$clientIdStr://'; diff --git a/lib/features/diary/presentation/widgets/chosen_diet_widget.dart b/lib/features/diary/presentation/widgets/chosen_diet_widget.dart index 3b5f23fd..622e0e5e 100644 --- a/lib/features/diary/presentation/widgets/chosen_diet_widget.dart +++ b/lib/features/diary/presentation/widgets/chosen_diet_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/widgets/custom_divider.dart'; @@ -6,77 +7,84 @@ import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.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 ChosenDietWidget extends StatelessWidget { const ChosenDietWidget({super.key}); @override Widget build(BuildContext context) { - return BlocBuilder(builder: (context, state) { - if (state is DiaryStateLoaded) { - if (state.diary.typeOfDiary.hasChosenDiet) { - return ChosenDietWidgetContent( - currentDietDay: state.diary.dayOfChosenDiet ?? 0, - dietName: state.diary.diet?.name ?? '', - dietDuration: state.diary.diet?.duration ?? 0, - ); + return BlocBuilder( + builder: (context, state) { + if (state is DiaryStateLoaded) { + if (state.diary.typeOfDiary.hasChosenDiet) { + return ChosenDietWidgetContent( + currentDietDay: state.diary.dayOfChosenDiet ?? 0, + dietName: state.diary.diet?.name ?? '', + dietDuration: state.diary.diet?.duration ?? 0, + dietId: state.diary.diet?.id ?? 0, + ); + } } - } - if (state is DiaryStateLoadedTomorrowWithDiet) { - if (state.diary.typeOfDiary.hasChosenDiet) { - return Column( - children: [ - const CustomDivider(), - const SizedBox(height: 16), - ChosenDietWidgetContent( - currentDietDay: state.diary.dayOfChosenDiet ?? 0, - dietName: state.diary.diet?.name ?? '', - dietDuration: state.diary.diet?.duration ?? 0, - ), - ], - ); + if (state is DiaryStateLoadedTomorrowWithDiet) { + if (state.diary.typeOfDiary.hasChosenDiet) { + return Column( + children: [ + const CustomDivider(), + const SizedBox(height: 16), + ChosenDietWidgetContent( + currentDietDay: state.diary.dayOfChosenDiet ?? 0, + dietName: state.diary.diet?.name ?? '', + dietDuration: state.diary.diet?.duration ?? 0, + dietId: state.diary.diet?.id ?? 0, + ), + ], + ); + } } - } - return const SizedBox.shrink(); - }); + return const SizedBox.shrink(); + }, + ); } } class ChosenDietWidgetContent extends StatelessWidget { - const ChosenDietWidgetContent({ - super.key, - required this.currentDietDay, - required this.dietName, - required this.dietDuration, - }); + const ChosenDietWidgetContent({super.key, required this.currentDietDay, required this.dietName, required this.dietDuration, required this.dietId}); final int currentDietDay; final String dietName; final int dietDuration; + final int dietId; @override Widget build(BuildContext context) { final size = MediaQuery.sizeOf(context); final s = S.of(context); - return Column( - children: [ - Row( - children: [ - SizedBox( - width: size.width * 0.4, - child: Text(dietName, style: TextStyles.textLMedium.copyWith(color: appTheme.black)), - ), - const Spacer(), - Container( - decoration: BoxDecoration(color: appTheme.dividerColor, borderRadius: BorderRadius.circular(12)), - padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), - child: Text('${s.day} $currentDietDay из $dietDuration', style: TextStyles.textMSemibold.copyWith(color: appTheme.gray)), - ) - ], - ), - const SizedBox( - height: 16, - ) - ], + return GestureDetector( + onTap: () { + GoRouter.of(context).push(RouteConstants.aboutDietScreen, extra: {'id': dietId, 'navigateToComments': false}); + }, + child: Column( + children: [ + Row( + children: [ + SizedBox( + width: size.width * 0.4, + child: Text( + dietName, + style: TextStyles.textLMedium.copyWith(color: appTheme.black, decoration: TextDecoration.underline), + ), + ), + const Spacer(), + Container( + decoration: BoxDecoration(color: appTheme.dividerColor, borderRadius: BorderRadius.circular(12)), + padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), + child: Text('${s.day} $currentDietDay из $dietDuration', style: TextStyles.textMSemibold.copyWith(color: appTheme.gray)), + ), + ], + ), + const SizedBox(height: 16), + ], + ), ); } } diff --git a/lib/features/diets/presentation/cubit/about_diet_cubit.dart b/lib/features/diets/presentation/cubit/about_diet_cubit.dart index 9d02534e..6ba7980f 100644 --- a/lib/features/diets/presentation/cubit/about_diet_cubit.dart +++ b/lib/features/diets/presentation/cubit/about_diet_cubit.dart @@ -19,9 +19,14 @@ class AboutDietCubit extends Cubit { String? userStartedDietName; List _selectedIndexes = []; - Future getDiet(String slug, {int? index}) async { + Future getDiet({String? slug, int? id, int? index}) async { try { - final diet = await dietsRepository.getDietBySlug(slug); + final Diet diet; + if (slug != null) { + diet = await dietsRepository.getDietBySlug(slug); + } else { + diet = await dietsRepository.getDiet(id!); + } if (index != null) { dietsRepository.emitCommentsStateToFeed(CommentsState(index: index, totalComments: diet.totalComments)); } @@ -32,10 +37,16 @@ class AboutDietCubit extends Cubit { } } - Future initDietPage(String slug) async { + Future initDietPage({String? slug, int? id}) async { try { emit(const AboutDietState.loading()); - final diet = await dietsRepository.getDietBySlug(slug); + final Diet diet; + if (slug != null) { + diet = await dietsRepository.getDietBySlug(slug); + } else { + diet = await dietsRepository.getDiet(id!); + } + final chosenDiets = await profileRepository.getChosenDiets(); final lastChosenDiet = chosenDiets.firstOrNull; if (lastChosenDiet != null && ['inited', 'started'].contains(lastChosenDiet.state)) { @@ -50,12 +61,7 @@ class AboutDietCubit extends Cubit { } } _selectedIndexes = List.generate(diet.dailySchedule.length, (index) => 0); - emit(AboutDietState.loaded( - diet: diet, - isStarted: isCurrentDietStarted, - hasStartedDiet: hasStartedDiet, - selectedIndexes: _selectedIndexes, - )); + emit(AboutDietState.loaded(diet: diet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet, selectedIndexes: _selectedIndexes)); } catch (e) { log(e.toString()); emit(AboutDietState.error(message: e.toString())); @@ -68,41 +74,30 @@ class AboutDietCubit extends Cubit { final currentDiet = (state as DietStateLoaded).diet; if (currentDiet.wasLikedByMe) { - final updatedDiet = currentDiet.copyWith( - totalLikes: currentDiet.totalLikes - 1, - wasLikedByMe: false, - ); + final updatedDiet = currentDiet.copyWith(totalLikes: currentDiet.totalLikes - 1, wasLikedByMe: false); if (dietIndexInFeed != null) { dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed)); } emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet, selectedIndexes: _selectedIndexes)); } else { - final updatedDiet = currentDiet.copyWith( - totalLikes: currentDiet.totalLikes + 1, - wasLikedByMe: true, - ); + final updatedDiet = currentDiet.copyWith(totalLikes: currentDiet.totalLikes + 1, wasLikedByMe: true); if (dietIndexInFeed != null) { dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed)); } emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet, selectedIndexes: _selectedIndexes)); } - EasyDebounce.debounce( - 'like_diet', - const Duration(seconds: 1), - () async { - try { - await dietsRepository.likeDiet(id); - } catch (e) { - log(e.toString()); - if (dietIndexInFeed != null) { - dietsRepository - .emitLikesStateToFeed(LikesState(wasLikedByMe: currentDiet.wasLikedByMe, totalLikes: currentDiet.totalLikes, index: dietIndexInFeed)); - } - emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); + EasyDebounce.debounce('like_diet', const Duration(seconds: 1), () async { + try { + await dietsRepository.likeDiet(id); + } catch (e) { + log(e.toString()); + if (dietIndexInFeed != null) { + dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: currentDiet.wasLikedByMe, totalLikes: currentDiet.totalLikes, index: dietIndexInFeed)); } - }, - ); + emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); + } + }); } Future addToFavorite(int id, int? dietIndex) async { @@ -110,30 +105,24 @@ class AboutDietCubit extends Cubit { final currentDiet = (state as DietStateLoaded).diet; - final updatedDiet = currentDiet.copyWith( - isFavorite: true, - ); + final updatedDiet = currentDiet.copyWith(isFavorite: true); if (dietIndex != null) { dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex)); } - emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); + emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); - EasyDebounce.debounce( - 'add_or_remove_diet_to_favorites', - const Duration(seconds: 1), - () async { - try { - await dietsRepository.addToFavorite(id); - } catch (e) { - log(e.toString()); - showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); - if (dietIndex != null) { - dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex)); - } - emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); + EasyDebounce.debounce('add_or_remove_diet_to_favorites', const Duration(seconds: 1), () async { + try { + await dietsRepository.addToFavorite(id); + } catch (e) { + log(e.toString()); + showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); + if (dietIndex != null) { + dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex)); } - }, - ); + emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); + } + }); } Future removeFromFavorite(int id, int? dietIndex) async { @@ -141,30 +130,24 @@ class AboutDietCubit extends Cubit { final currentDiet = (state as DietStateLoaded).diet; - final updatedDiet = currentDiet.copyWith( - isFavorite: false, - ); + final updatedDiet = currentDiet.copyWith(isFavorite: false); if (dietIndex != null) { dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex)); } - emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); + emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); - EasyDebounce.debounce( - 'add_or_remove_diet_to_favorites', - const Duration(seconds: 1), - () async { - try { - await dietsRepository.removeFromFavorite(id); - } catch (e) { - log(e.toString()); - showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); - if (dietIndex != null) { - dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex)); - } - emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); + EasyDebounce.debounce('add_or_remove_diet_to_favorites', const Duration(seconds: 1), () async { + try { + await dietsRepository.removeFromFavorite(id); + } catch (e) { + log(e.toString()); + showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); + if (dietIndex != null) { + dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex)); } - }, - ); + emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); + } + }); } Future startDiet(DateTime date) async { @@ -199,13 +182,13 @@ class AboutDietCubit extends Cubit { void clearStartedDietsState() { if (state is! DietStateLoaded) return; final diet = (state as DietStateLoaded).diet; - emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: diet)); + emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: diet)); } void emitCurrentStartedDietsState() { if (state is! DietStateLoaded) return; final diet = (state as DietStateLoaded).diet; - emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes,diet: diet, isStarted: true)); + emit(AboutDietState.loaded(selectedIndexes: _selectedIndexes, diet: diet, isStarted: true)); } Future getDietBySlug(String slug) async { diff --git a/lib/features/diets/presentation/pages/about_diet_screen.dart b/lib/features/diets/presentation/pages/about_diet_screen.dart index e06989f1..9057c59b 100644 --- a/lib/features/diets/presentation/pages/about_diet_screen.dart +++ b/lib/features/diets/presentation/pages/about_diet_screen.dart @@ -35,11 +35,12 @@ import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; class AboutDietScreen extends StatefulWidget { - final String slug; + final String? slug; + final int? id; final int? index; final bool navigateToComments; - const AboutDietScreen({super.key, required this.index, required this.navigateToComments, required this.slug}); + const AboutDietScreen({super.key, required this.index, required this.navigateToComments, required this.slug, required this.id}); @override State createState() => _AboutDietScreenState(); @@ -79,7 +80,7 @@ class _AboutDietScreenState extends State { final s = S.of(context); return BlocProvider( - create: (context) => dietsCubit..initDietPage(widget.slug), + create: (context) => dietsCubit..initDietPage(slug: widget.slug, id: widget.id), child: BlocProvider( create: (BuildContext context) => commentsCubit, child: BlocConsumer( @@ -283,7 +284,7 @@ class _AboutDietScreenState extends State { replyId = null; }); Future.delayed(const Duration(milliseconds: 500), () { - dietsCubit.getDiet(dietState.diet.slug, index: widget.index); + dietsCubit.getDiet(slug: dietState.diet.slug, index: widget.index); }); FocusManager.instance.primaryFocus?.unfocus(); } @@ -526,7 +527,7 @@ class _AboutDietScreenState extends State { ), ), body: DataErrorWidget( - onReload: () => context.read().getDiet(widget.slug, index: widget.index), + onReload: () => context.read().getDiet(slug: widget.slug, id: widget.id, index: widget.index), ), ); } diff --git a/lib/features/diets/presentation/widgets/author_card.dart b/lib/features/diets/presentation/widgets/author_card.dart index 548b9263..34131dac 100644 --- a/lib/features/diets/presentation/widgets/author_card.dart +++ b/lib/features/diets/presentation/widgets/author_card.dart @@ -38,45 +38,25 @@ class AuthorCard extends StatelessWidget { decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( - image: NetworkImage(sl().baseUrl + author.authorProfileIcon), + image: NetworkImage( + author.authorProfileIcon.contains('https') ? author.authorProfileIcon : sl().baseUrl + author.authorProfileIcon, + ), fit: BoxFit.cover, ), ), ), - subtitle: Text( - author.authorName, - style: TextStyles.textLSemibold.copyWith( - color: appTheme.black, - ), - ), - title: Text( - title, - style: titleStyle ?? TextStyles.textSSemibold.copyWith( - color: appTheme.gray, - ), - ), + subtitle: Text(author.authorName, style: TextStyles.textLSemibold.copyWith(color: appTheme.black)), + title: Text(title, style: titleStyle ?? TextStyles.textSSemibold.copyWith(color: appTheme.gray)), ), Row( children: [ - Text( - 'Консультант', - style: TextStyles.textMMedium.copyWith( - color: appTheme.black, - ), - ), + Text('Консультант', style: TextStyles.textMMedium.copyWith(color: appTheme.black)), const SizedBox(width: 10), if (author.authorPlaceInRating != null) InfoBouble( radius: 12, backgroundColor: appTheme.whiteA700, - children: [ - Text( - '${author.authorPlaceInRating}-й в рейтинге', - style: TextStyles.textMMediumAuto.copyWith( - color: appTheme.blueA400, - ), - ), - ], + children: [Text('${author.authorPlaceInRating}-й в рейтинге', style: TextStyles.textMMediumAuto.copyWith(color: appTheme.blueA400))], ), ], ), @@ -89,18 +69,8 @@ class AuthorCard extends StatelessWidget { child: Container( width: 28, height: 28, - decoration: BoxDecoration( - color: appTheme.whiteA700, - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: SvgPicture.asset( - 'assets/icons/arrow.svg', - width: 12, - height: 12, - fit: BoxFit.none, - ), - ), + decoration: BoxDecoration(color: appTheme.whiteA700, borderRadius: BorderRadius.circular(8)), + child: Center(child: SvgPicture.asset('assets/icons/arrow.svg', width: 12, height: 12, fit: BoxFit.none)), ), ), ],