forked from eatvio/eatvio_app
feat(views): added view handling for diets, recipes, plans and posts
This commit is contained in:
@@ -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<FeedScreenContent> {
|
||||
final consultantsController = TextEditingController();
|
||||
|
||||
late final List<String> 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<FeedCubit>();
|
||||
@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<FeedScreenContent> {
|
||||
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<FeedScreenContent> {
|
||||
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<int> postsIds = <int>{};
|
||||
final Set<int> plansIds = <int>{};
|
||||
final Set<int> dietsIds = <int>{};
|
||||
final Set<int> recipesIds = <int>{};
|
||||
|
||||
final Map<ViewableContentType, Map<int, Timer>> _visibilityTimers = {
|
||||
ViewableContentType.posts: <int, Timer>{},
|
||||
ViewableContentType.plans: <int, Timer>{},
|
||||
ViewableContentType.diets: <int, Timer>{},
|
||||
ViewableContentType.recipes: <int, Timer>{},
|
||||
};
|
||||
|
||||
Set<int> _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<FeedScreenContent> {
|
||||
];
|
||||
},
|
||||
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<FeedScreenContent> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum ViewableContentType {
|
||||
plans,
|
||||
posts,
|
||||
diets,
|
||||
recipes;
|
||||
|
||||
String getStringifiedVersion() => switch (this) {
|
||||
ViewableContentType.plans => 'plans',
|
||||
|
||||
ViewableContentType.posts => 'blog_posts',
|
||||
|
||||
ViewableContentType.diets => 'diets',
|
||||
|
||||
ViewableContentType.recipes => 'recipes',
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user