Add deduplication
This commit is contained in:
parent
b35507c3ad
commit
e0cb1a0a83
|
@ -38,6 +38,7 @@ class CommunitiesListPage extends StatelessWidget {
|
|||
)
|
||||
],
|
||||
),
|
||||
uniqueProp: (item) => item.community.id,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -118,6 +118,7 @@ class InboxPage extends HookWidget {
|
|||
canBeMarkedAsRead: true,
|
||||
hideOnRead: unreadOnly.value,
|
||||
),
|
||||
uniqueProp: (item) => item.comment.id,
|
||||
),
|
||||
SortableInfiniteList<PersonMentionView>(
|
||||
noItems: const Text('no mentions'),
|
||||
|
@ -135,6 +136,7 @@ class InboxPage extends HookWidget {
|
|||
umv,
|
||||
hideOnRead: unreadOnly.value,
|
||||
),
|
||||
uniqueProp: (item) => item.personMention.id,
|
||||
),
|
||||
InfiniteScroll<PrivateMessageView>(
|
||||
noItems: const Padding(
|
||||
|
@ -154,6 +156,7 @@ class InboxPage extends HookWidget {
|
|||
privateMessageView: mv,
|
||||
hideOnRead: unreadOnly.value,
|
||||
),
|
||||
uniqueProp: (item) => item.privateMessage.id,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -120,6 +120,20 @@ class _SearchResultsList extends HookWidget {
|
|||
throw UnimplementedError();
|
||||
}
|
||||
},
|
||||
uniqueProp: (item) {
|
||||
switch (type) {
|
||||
case SearchType.comments:
|
||||
return (item as CommentView).comment.id;
|
||||
case SearchType.communities:
|
||||
return (item as CommunityView).community.id;
|
||||
case SearchType.posts:
|
||||
return (item as PostView).post.id;
|
||||
case SearchType.users:
|
||||
return (item as PersonViewSafe).person.id;
|
||||
default:
|
||||
return item;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:collection';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
|
@ -47,6 +49,10 @@ class InfiniteScroll<T> extends HookWidget {
|
|||
/// Widget that will be displayed if there are no items
|
||||
final Widget noItems;
|
||||
|
||||
/// Maps an item to its unique property that will allow to detect possible
|
||||
/// duplicates thus perfoming deduplication
|
||||
final Object Function(T item) uniqueProp;
|
||||
|
||||
const InfiniteScroll({
|
||||
this.batchSize = 10,
|
||||
this.leading = const SizedBox.shrink(),
|
||||
|
@ -57,6 +63,7 @@ class InfiniteScroll<T> extends HookWidget {
|
|||
@required this.fetcher,
|
||||
this.controller,
|
||||
this.noItems = const SizedBox.shrink(),
|
||||
this.uniqueProp,
|
||||
}) : assert(itemBuilder != null),
|
||||
assert(fetcher != null),
|
||||
assert(batchSize > 0);
|
||||
|
@ -64,6 +71,8 @@ class InfiniteScroll<T> extends HookWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final data = useState<List<T>>([]);
|
||||
// holds unique props of the data
|
||||
final dataSet = useRef(HashSet<Object>());
|
||||
final hasMore = useRef(true);
|
||||
final isFetching = useRef(false);
|
||||
|
||||
|
@ -111,13 +120,19 @@ class InfiniteScroll<T> extends HookWidget {
|
|||
// if it's already fetching more, skip
|
||||
if (!isFetching.current) {
|
||||
isFetching.current = true;
|
||||
fetcher(page, batchSize).then((newData) {
|
||||
fetcher(page, batchSize).then((incoming) {
|
||||
// if got less than the batchSize, mark the list as done
|
||||
if (newData.length < batchSize) {
|
||||
if (incoming.length < batchSize) {
|
||||
hasMore.current = false;
|
||||
}
|
||||
|
||||
final newData = incoming.where(
|
||||
(e) => !dataSet.current.contains(uniqueProp?.call(e) ?? e),
|
||||
);
|
||||
|
||||
// append new data
|
||||
data.value = [...data.value, ...newData];
|
||||
dataSet.current.addAll(newData.map(uniqueProp ?? (e) => e));
|
||||
}).whenComplete(() => isFetching.current = false);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ class SortableInfiniteList<T> extends HookWidget {
|
|||
final Function onStyleChange;
|
||||
final Widget noItems;
|
||||
final SortType defaultSort;
|
||||
final Object Function(T item) uniqueProp;
|
||||
|
||||
const SortableInfiniteList({
|
||||
@required this.fetcher,
|
||||
|
@ -28,6 +29,7 @@ class SortableInfiniteList<T> extends HookWidget {
|
|||
this.onStyleChange,
|
||||
this.noItems,
|
||||
this.defaultSort = SortType.active,
|
||||
this.uniqueProp,
|
||||
}) : assert(fetcher != null),
|
||||
assert(itemBuilder != null),
|
||||
assert(defaultSort != null);
|
||||
|
@ -56,49 +58,41 @@ class SortableInfiniteList<T> extends HookWidget {
|
|||
controller: isc,
|
||||
batchSize: 20,
|
||||
noItems: noItems,
|
||||
uniqueProp: uniqueProp,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class InfinitePostList extends StatelessWidget {
|
||||
final FetcherWithSorting<PostView> fetcher;
|
||||
final InfiniteScrollController controller;
|
||||
|
||||
const InfinitePostList({
|
||||
@required this.fetcher,
|
||||
this.controller,
|
||||
}) : assert(fetcher != null);
|
||||
|
||||
Widget build(BuildContext context) => SortableInfiniteList<PostView>(
|
||||
onStyleChange: () {},
|
||||
itemBuilder: (post) => Column(
|
||||
children: [
|
||||
PostWidget(post),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
fetcher: fetcher,
|
||||
controller: controller,
|
||||
noItems: const Text('there are no posts'),
|
||||
);
|
||||
class InfinitePostList extends SortableInfiniteList<PostView> {
|
||||
InfinitePostList({
|
||||
@required FetcherWithSorting<PostView> fetcher,
|
||||
InfiniteScrollController controller,
|
||||
}) : super(
|
||||
itemBuilder: (post) => Column(
|
||||
children: [
|
||||
PostWidget(post),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
fetcher: fetcher,
|
||||
controller: controller,
|
||||
noItems: const Text('there are no posts'),
|
||||
uniqueProp: (item) => item.post.id,
|
||||
);
|
||||
}
|
||||
|
||||
class InfiniteCommentList extends StatelessWidget {
|
||||
final FetcherWithSorting<CommentView> fetcher;
|
||||
final InfiniteScrollController controller;
|
||||
|
||||
const InfiniteCommentList({
|
||||
@required this.fetcher,
|
||||
this.controller,
|
||||
}) : assert(fetcher != null);
|
||||
|
||||
Widget build(BuildContext context) => SortableInfiniteList<CommentView>(
|
||||
itemBuilder: (comment) => CommentWidget(
|
||||
CommentTree(comment),
|
||||
detached: true,
|
||||
),
|
||||
fetcher: fetcher,
|
||||
controller: controller,
|
||||
noItems: const Text('there are no comments'),
|
||||
);
|
||||
class InfiniteCommentList extends SortableInfiniteList<CommentView> {
|
||||
InfiniteCommentList({
|
||||
@required FetcherWithSorting<CommentView> fetcher,
|
||||
InfiniteScrollController controller,
|
||||
}) : super(
|
||||
itemBuilder: (comment) => CommentWidget(
|
||||
CommentTree(comment),
|
||||
detached: true,
|
||||
),
|
||||
fetcher: fetcher,
|
||||
controller: controller,
|
||||
noItems: const Text('there are no comments'),
|
||||
uniqueProp: (item) => item.comment.id,
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue