diff --git a/.gitignore b/.gitignore index 4f05e3a1..06e89a5e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ *.mocks.dart android/build/ ios/XCBuildData/ -env/.env \ No newline at end of file +env/.env +.env \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 198e6f7b..668075b4 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -410,6 +410,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -560,6 +561,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -598,6 +600,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/lib/core/const.dart b/lib/core/const.dart index 98f7bc4a..a5f06149 100644 --- a/lib/core/const.dart +++ b/lib/core/const.dart @@ -1,6 +1,6 @@ import 'package:eatvio_app/core/env_config.dart'; -String baseUrl = EnvConfig.baseUrl; +String baseUrl = EnvConfig.devBaseUrl; bool hidePlans = const bool.fromEnvironment('HIDE_PLANS', defaultValue: false); const buildDate = String.fromEnvironment('BUILD_DATE', defaultValue: ''); diff --git a/lib/features/feed/models/view_model.dart b/lib/features/feed/models/view_model.dart new file mode 100644 index 00000000..f04022e9 --- /dev/null +++ b/lib/features/feed/models/view_model.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'view_model.freezed.dart'; +part 'view_model.g.dart'; + +@freezed +abstract class ViewModel with _$ViewModel { + + factory ViewModel({ + required String type, + List? ids, + List? slugs, + }) = _ViewModel; + + factory ViewModel.fromJson(Map json) => _$ViewModelFromJson(json); +} \ No newline at end of file diff --git a/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart index d3ba615a..39ccdc6a 100644 --- a/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart +++ b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart @@ -1,7 +1,9 @@ import 'dart:developer'; import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; +import 'package:eatvio_app/features/feed/models/view_model.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart'; +import 'package:eatvio_app/features/feed/presentation/pages/feed_screen.dart'; import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -81,4 +83,10 @@ class FeedCubit extends Cubit { Future viewRecipe(String slug) async => await feedRepository.viewRecipe(slug); Future viewDiet(int id) async => await feedRepository.viewDiet(id); Future viewPlan(String slug) async => await feedRepository.viewPlan(slug); + + Future viewContent({required ViewableContentType type, List? ids, List? slugs}) async { + feedRepository.viewContent( + viewModel: ViewModel(type: type.getStringifiedVersion(), ids: ids, slugs: slugs), + ); + } } diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart index ce29b884..2bfaf897 100644 --- a/lib/features/feed/presentation/pages/feed_screen.dart +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:easy_debounce/easy_debounce.dart'; import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/widgets/add_item_button.dart'; @@ -60,18 +62,19 @@ class _FeedScreenContentState extends State { final consultantsController = TextEditingController(); late final List chipsLabelList; + late final AppLifecycleListener _listener; int _selectedChipIndex = 0; final blogPostsScrollController = ScrollController(); final recipesScrollController = ScrollController(); final dietsScrollController = ScrollController(); final plansScrollController = ScrollController(); final consultantsScrollController = ScrollController(); - + final _feedCubit = sl(); @override void initState() { // Initialize chipsLabelList based on hidePlans setting chipsLabelList = hidePlans ? ['Все', 'Рецепты', 'Диеты', 'Консультанты'] : ['Все', 'Рецепты', 'Диеты', 'Планы питания', 'Консультанты']; - + _listener = AppLifecycleListener(onDetach: _sendViews); consultantsScrollController.addListener(_onScrollConsultants); super.initState(); } @@ -80,6 +83,21 @@ class _FeedScreenContentState extends State { if (consultantsScrollController.offset >= consultantsScrollController.position.maxScrollExtent && !consultantsScrollController.position.outOfRange) {} } + void _sendViews() { + if (postsIds.isNotEmpty) { + _feedCubit.viewContent(type: ViewableContentType.posts, ids: postsIds.toList()); + } + if (plansIds.isNotEmpty) { + _feedCubit.viewContent(type: ViewableContentType.plans, ids: plansIds.toList()); + } + if (dietsIds.isNotEmpty) { + _feedCubit.viewContent(type: ViewableContentType.diets, ids: dietsIds.toList()); + } + if (recipesIds.isNotEmpty) { + _feedCubit.viewContent(type: ViewableContentType.recipes, ids: recipesIds.toList()); + } + } + @override void dispose() { blogPostsScrollController.dispose(); @@ -87,9 +105,64 @@ class _FeedScreenContentState extends State { dietsScrollController.dispose(); plansScrollController.dispose(); consultantsScrollController.dispose(); + for (final map in _visibilityTimers.values) { + for (final t in map.values) { + t.cancel(); + } + map.clear(); + } + _listener.dispose(); + _sendViews(); super.dispose(); } + final Set postsIds = {}; + final Set plansIds = {}; + final Set dietsIds = {}; + final Set recipesIds = {}; + + final Map> _visibilityTimers = { + ViewableContentType.posts: {}, + ViewableContentType.plans: {}, + ViewableContentType.diets: {}, + ViewableContentType.recipes: {}, + }; + + Set _idsForType(ViewableContentType type) { + switch (type) { + case ViewableContentType.posts: + return postsIds; + case ViewableContentType.plans: + return plansIds; + case ViewableContentType.diets: + return dietsIds; + case ViewableContentType.recipes: + return recipesIds; + } + } + + void _handleVisibility({required double visibleFraction, required int id, required ViewableContentType type}) { + final timers = _visibilityTimers[type]!; + final ids = _idsForType(type); + + if (ids.contains(id)) { + timers[id]?.cancel(); + timers.remove(id); + return; + } + + if (visibleFraction >= 0.5) { + if (timers.containsKey(id)) return; + timers[id] = Timer(const Duration(seconds: 1), () { + ids.add(id); + timers.remove(id); + }); + } else { + timers[id]?.cancel(); + timers.remove(id); + } + } + @override Widget build(BuildContext context) { FlutterNativeSplash.remove(); @@ -228,10 +301,10 @@ class _FeedScreenContentState extends State { ]; }, body: switch (_selectedChipIndex) { - 0 => const BlogPosts(), - 1 => const Recipes(), - 2 => const Diets(), - 3 when !hidePlans => const Plans(), + 0 => BlogPosts(handleVisibility: _handleVisibility), + 1 => Recipes(handleVisibility: _handleVisibility), + 2 => Diets(handleVisibility: _handleVisibility), + 3 when !hidePlans => Plans(handleVisibility: _handleVisibility), 3 when hidePlans => const Consultants(), 4 when !hidePlans => const Consultants(), _ => Center(child: Text(chipsLabelList[_selectedChipIndex])), @@ -240,3 +313,20 @@ class _FeedScreenContentState extends State { ); } } + +enum ViewableContentType { + plans, + posts, + diets, + recipes; + + String getStringifiedVersion() => switch (this) { + ViewableContentType.plans => 'plans', + + ViewableContentType.posts => 'blog_posts', + + ViewableContentType.diets => 'diets', + + ViewableContentType.recipes => 'recipes', + }; +} diff --git a/lib/features/feed/presentation/widgets/blog_posts.dart b/lib/features/feed/presentation/widgets/blog_posts.dart index 8c918515..b9da2ecc 100644 --- a/lib/features/feed/presentation/widgets/blog_posts.dart +++ b/lib/features/feed/presentation/widgets/blog_posts.dart @@ -3,13 +3,16 @@ import 'package:eatvio_app/core/widgets/data_error_widget.dart'; import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart'; +import 'package:eatvio_app/features/feed/presentation/pages/feed_screen.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/blog_post_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:visibility_detector/visibility_detector.dart'; class BlogPosts extends StatelessWidget { - const BlogPosts({super.key}); - + const BlogPosts({super.key, required this.handleVisibility}); + final Function({required double visibleFraction,required int id, required ViewableContentType type}) handleVisibility; + @override Widget build(BuildContext context) { return RefreshIndicator( @@ -29,25 +32,26 @@ class BlogPosts extends StatelessWidget { if (index == state.feedBlogPostList.length) { return const Loader(); } - return BlogPostWidget(index: index); + return VisibilityDetector( + onVisibilityChanged: (info) { + final id = state.feedBlogPostList[index].id; + handleVisibility(visibleFraction: info.visibleFraction, id: id, type: ViewableContentType.posts); + }, + key: ValueKey(index), + child: BlogPostWidget(index: index), + ); }, separatorBuilder: (context, index) => const SizedBox(height: 8), itemCount: state.isLoading ? state.feedBlogPostList.length + 1 : state.feedBlogPostList.length, ), ); } else if (state is FeedStateError) { - return DataErrorWidget( - onReload: () => context.read().loadFeedBlogPostList(), - ); + return DataErrorWidget(onReload: () => context.read().loadFeedBlogPostList()); } else { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); + return Scaffold(backgroundColor: Colors.grey.shade200, body: const Loader()); } }, ), ); } } - diff --git a/lib/features/feed/presentation/widgets/diets.dart b/lib/features/feed/presentation/widgets/diets.dart index c08a82a6..c5e5592a 100644 --- a/lib/features/feed/presentation/widgets/diets.dart +++ b/lib/features/feed/presentation/widgets/diets.dart @@ -3,15 +3,17 @@ import 'package:eatvio_app/core/widgets/data_error_widget.dart'; import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart'; +import 'package:eatvio_app/features/feed/presentation/pages/feed_screen.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/diet_filter_bottom_sheet.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/diets_widget.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/filter_badge.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:visibility_detector/visibility_detector.dart'; class Diets extends StatelessWidget { - const Diets({super.key}); - + const Diets({super.key, required this.handleVisibility}); + final Function({required double visibleFraction, required int id, required ViewableContentType type}) handleVisibility; @override Widget build(BuildContext context) { return RefreshIndicator( @@ -19,10 +21,7 @@ class Diets extends StatelessWidget { child: BlocBuilder( builder: (BuildContext context, DietsState state) { if (state.isLoading) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); + return Scaffold(backgroundColor: Colors.grey.shade200, body: const Loader()); } else if (state.errorMessage != null) { return DataErrorWidget(onReload: () => context.read().loadDiets()); } else { @@ -39,7 +38,14 @@ class Diets extends StatelessWidget { shrinkWrap: true, physics: const BouncingScrollPhysics(), itemBuilder: (context, index) { - return DietsWidget(diet: state.dietsList[index], index: index); + return VisibilityDetector( + key: ValueKey(index), + onVisibilityChanged: (info) { + final id = state.dietsList[index].id; + handleVisibility(visibleFraction: info.visibleFraction, id: id, type: ViewableContentType.posts); + }, + child: DietsWidget(diet: state.dietsList[index], index: index), + ); }, separatorBuilder: (context, index) { return const SizedBox(height: 8); @@ -50,11 +56,7 @@ class Diets extends StatelessWidget { Positioned( right: 0, bottom: 74, - child: FilterBadge( - filterBottomSheet: DietFilterBottomSheet( - dietsCubit: context.read(), - ), - ), + child: FilterBadge(filterBottomSheet: DietFilterBottomSheet(dietsCubit: context.read())), ), ], ); diff --git a/lib/features/feed/presentation/widgets/plans.dart b/lib/features/feed/presentation/widgets/plans.dart index 005c9ee9..4a620945 100644 --- a/lib/features/feed/presentation/widgets/plans.dart +++ b/lib/features/feed/presentation/widgets/plans.dart @@ -3,15 +3,17 @@ import 'package:eatvio_app/core/widgets/data_error_widget.dart'; import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_state.dart'; +import 'package:eatvio_app/features/feed/presentation/pages/feed_screen.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/filter_badge.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/plan_widget.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/plans_filter_bottom_sheet.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:visibility_detector/visibility_detector.dart'; class Plans extends StatelessWidget { - const Plans({super.key}); - + const Plans({super.key, required this.handleVisibility}); + final Function({required double visibleFraction, required int id, required ViewableContentType type}) handleVisibility; @override Widget build(BuildContext context) { return RefreshIndicator( @@ -19,10 +21,7 @@ class Plans extends StatelessWidget { child: BlocBuilder( builder: (BuildContext context, PlansState state) { if (state.isLoading) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); + return Scaffold(backgroundColor: Colors.grey.shade200, body: const Loader()); } else if (state.errorMessage != null) { return DataErrorWidget(onReload: () => context.read().loadPlans()); } @@ -39,9 +38,13 @@ class Plans extends StatelessWidget { shrinkWrap: true, physics: const BouncingScrollPhysics(), itemBuilder: (context, index) { - return PlanWidget( - plan: state.plans[index], - index: index, + return VisibilityDetector( + key: ValueKey(index), + onVisibilityChanged: (info) { + final id = state.plans[index].id; + handleVisibility(visibleFraction: info.visibleFraction, id: id, type: ViewableContentType.posts); + }, + child: PlanWidget(plan: state.plans[index], index: index), ); }, separatorBuilder: (context, index) { @@ -53,11 +56,7 @@ class Plans extends StatelessWidget { Positioned( right: 0, bottom: 74, - child: FilterBadge( - filterBottomSheet: PlansFilterBottomSheet( - plansCubit: context.read(), - ), - ), + child: FilterBadge(filterBottomSheet: PlansFilterBottomSheet(plansCubit: context.read())), ), ], ); diff --git a/lib/features/feed/presentation/widgets/recipes.dart b/lib/features/feed/presentation/widgets/recipes.dart index 914c31fe..d286949e 100644 --- a/lib/features/feed/presentation/widgets/recipes.dart +++ b/lib/features/feed/presentation/widgets/recipes.dart @@ -3,13 +3,15 @@ import 'package:eatvio_app/core/widgets/data_error_widget.dart'; import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart'; +import 'package:eatvio_app/features/feed/presentation/pages/feed_screen.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/recipes_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:visibility_detector/visibility_detector.dart'; class Recipes extends StatelessWidget { - const Recipes({super.key}); - + const Recipes({super.key, required this.handleVisibility}); + final Function({required double visibleFraction,required int id, required ViewableContentType type}) handleVisibility; @override Widget build(BuildContext context) { return RefreshIndicator( @@ -40,9 +42,16 @@ class Recipes extends StatelessWidget { shrinkWrap: true, physics: const BouncingScrollPhysics(), itemBuilder: (context, index) { - return RecipesWidget( - recipe: state.recipesList[index], - index: index, + return VisibilityDetector( + key: ValueKey(index), + onVisibilityChanged: (info) { + final id = state.recipesList[index].id; + handleVisibility(visibleFraction: info.visibleFraction, id: id, type: ViewableContentType.posts); + }, + child: RecipesWidget( + recipe: state.recipesList[index], + index: index, + ), ); }, separatorBuilder: (context, index) { diff --git a/lib/features/feed/repositories/feed_repository.dart b/lib/features/feed/repositories/feed_repository.dart index e6e95969..108a8b11 100644 --- a/lib/features/feed/repositories/feed_repository.dart +++ b/lib/features/feed/repositories/feed_repository.dart @@ -5,103 +5,55 @@ import 'package:eatvio_app/features/feed/models/feed_blog_post_settings_model.da import 'package:eatvio_app/features/feed/models/feed_consultant_model.dart'; import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/recipes_model.dart'; +import 'package:eatvio_app/features/feed/models/view_model.dart'; import 'package:eatvio_app/features/feed/services/feed_service.dart'; class FeedRepository { final FeedService feedService; - FeedRepository({ - required this.feedService, - }); + FeedRepository({required this.feedService}); - Future getFeedBlogPosts({ - String? query, - int page = 1, - }) async { + Future getFeedBlogPosts({String? query, int page = 1}) async { try { - return (await feedService.getBlogPostList( - page: page, - query: query, - )); + return (await feedService.getBlogPostList(page: page, query: query)); } catch (e) { rethrow; } } - Future getBlogPost({ - required int id - }) async { + Future getBlogPost({required int id}) async { try { - return await feedService.getBlogPost( - postId: id - ); + return await feedService.getBlogPost(postId: id); } catch (e) { rethrow; } } - Future> getRecipes({ - String? query, - List? tags, - int page = 1, - }) async { + Future> getRecipes({String? query, List? tags, int page = 1}) async { try { - return (await feedService.getRecipes( - query: query, - tags: tags, - page: page, - )) - .recipesList; + return (await feedService.getRecipes(query: query, tags: tags, page: page)).recipesList; } catch (e) { rethrow; } } - Future getDiets({ - int page = 1, - String? query, - String? types, - int? duration, - String? sorting, - }) async { + Future getDiets({int page = 1, String? query, String? types, int? duration, String? sorting}) async { try { - return (await feedService.getDiets( - page: page, - query: query, - types: types, - duration: duration, - sorting: sorting, - )); + return (await feedService.getDiets(page: page, query: query, types: types, duration: duration, sorting: sorting)); } catch (e) { rethrow; } } - Future getPlans({ - int page = 1, - String? query, - String? types, - int? duration, - int? minPrice, - int? maxPrice, - }) async { + Future getPlans({int page = 1, String? query, String? types, int? duration, int? minPrice, int? maxPrice}) async { try { - return (await feedService.getPlans( - page: page, - query: query, - types: types, - duration: duration, - minPrice: minPrice, - maxPrice: maxPrice, - )); + return (await feedService.getPlans(page: page, query: query, types: types, duration: duration, minPrice: minPrice, maxPrice: maxPrice)); } catch (e) { rethrow; } } - Future getBlogPostComments({ - required String id, - }) async { + Future getBlogPostComments({required String id}) async { try { return (await feedService.getBlogPostComments(id: id)); } catch (e) { @@ -109,25 +61,15 @@ class FeedRepository { } } - Future sendBlogPostComment({ - required String id, - required String commentText, - int? parentCommentId, - }) async { + Future sendBlogPostComment({required String id, required String commentText, int? parentCommentId}) async { try { - await feedService.sendBlogPostComment( - id: id, - body: commentText, - parentCommentId: parentCommentId, - ); + await feedService.sendBlogPostComment(id: id, body: commentText, parentCommentId: parentCommentId); } catch (e) { rethrow; } } - Future getDietsComments({ - required String id, - }) async { + Future getDietsComments({required String id}) async { try { return (await feedService.getDietsComments(id: id)); } catch (e) { @@ -135,25 +77,15 @@ class FeedRepository { } } - Future sendDietsComment({ - required String id, - required String commentText, - int? parentCommentId, - }) async { + Future sendDietsComment({required String id, required String commentText, int? parentCommentId}) async { try { - await feedService.sendDietsComment( - id: id, - body: commentText, - parentCommentId: parentCommentId, - ); + await feedService.sendDietsComment(id: id, body: commentText, parentCommentId: parentCommentId); } catch (e) { rethrow; } } - Future getRecipesComments({ - required String id, - }) async { + Future getRecipesComments({required String id}) async { try { return (await feedService.getRecipesComments(id: id)); } catch (e) { @@ -161,25 +93,15 @@ class FeedRepository { } } - Future sendRecipesComment({ - required String id, - required String commentText, - int? parentCommentId, - }) async { + Future sendRecipesComment({required String id, required String commentText, int? parentCommentId}) async { try { - await feedService.sendRecipesComment( - id: id, - body: commentText, - parentCommentId: parentCommentId, - ); + await feedService.sendRecipesComment(id: id, body: commentText, parentCommentId: parentCommentId); } catch (e) { rethrow; } } - Future getPlansComments({ - required String slug, - }) async { + Future getPlansComments({required String slug}) async { try { return (await feedService.getPlansComments(slug: slug)); } catch (e) { @@ -187,25 +109,15 @@ class FeedRepository { } } - Future sendPlansComment({ - required String slug, - required String commentText, - int? parentCommentId, - }) async { + Future sendPlansComment({required String slug, required String commentText, int? parentCommentId}) async { try { - await feedService.sendPlansComment( - slug: slug, - body: commentText, - parentCommentId: parentCommentId, - ); + await feedService.sendPlansComment(slug: slug, body: commentText, parentCommentId: parentCommentId); } catch (e) { rethrow; } } - Future likeBlogPost({ - required int id, - }) async { + Future likeBlogPost({required int id}) async { try { await feedService.likeBlogPost(id: id); } catch (e) { @@ -213,9 +125,7 @@ class FeedRepository { } } - Future unlikedBlogPost({ - required int id, - }) async { + Future unlikedBlogPost({required int id}) async { try { await feedService.unlikedBlogPost(id: id); } catch (e) { @@ -262,4 +172,12 @@ class FeedRepository { rethrow; } } + + Future viewContent({required ViewModel viewModel}) async { + try { + await feedService.viewContent(viewModel: viewModel); + } catch (e) { + rethrow; + } + } } diff --git a/lib/features/feed/services/feed_service.dart b/lib/features/feed/services/feed_service.dart index cb5de3d0..265c2d38 100644 --- a/lib/features/feed/services/feed_service.dart +++ b/lib/features/feed/services/feed_service.dart @@ -6,6 +6,7 @@ import 'package:eatvio_app/features/feed/models/feed_blog_post_settings_model.da import 'package:eatvio_app/features/feed/models/feed_consultant_model.dart'; import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/recipes_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/view_model.dart'; import 'package:retrofit/retrofit.dart'; part 'feed_service.g.dart'; @@ -131,4 +132,9 @@ abstract class FeedService { Future viewPlan({ @Path() required String slug, }); + + @POST('/api/views') + Future viewContent({ + @Body() required ViewModel viewModel, + }); }