Merge pull request #60 from krawieck/infinite-list-in-action
This commit is contained in:
commit
f37f01951f
|
@ -122,8 +122,8 @@ class MyHomePage extends HookWidget {
|
|||
children: [
|
||||
tabButton(Icons.home),
|
||||
tabButton(Icons.list),
|
||||
Container(),
|
||||
Container(),
|
||||
SizedBox.shrink(),
|
||||
SizedBox.shrink(),
|
||||
tabButton(Icons.search),
|
||||
tabButton(Icons.person),
|
||||
],
|
||||
|
|
|
@ -120,7 +120,7 @@ class AddAccountPage extends HookWidget {
|
|||
url: icon.value,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: icon.value,
|
||||
errorWidget: (_, __, ___) => Container(),
|
||||
errorWidget: (_, __, ___) => SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -80,7 +80,7 @@ class AddInstancePage extends HookWidget {
|
|||
child: FullscreenableImage(
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: icon.value,
|
||||
errorWidget: (_, __, ___) => Container(),
|
||||
errorWidget: (_, __, ___) => SizedBox.shrink(),
|
||||
),
|
||||
url: icon.value,
|
||||
))
|
||||
|
|
|
@ -5,58 +5,69 @@ import 'package:lemmy_api_client/lemmy_api_client.dart';
|
|||
import '../util/extensions/api.dart';
|
||||
import '../util/goto.dart';
|
||||
import '../widgets/markdown_text.dart';
|
||||
import '../widgets/sortable_infinite_list.dart';
|
||||
|
||||
class CommunitiesListPage extends StatelessWidget {
|
||||
final String title;
|
||||
final List<CommunityView> communities;
|
||||
final Future<List<CommunityView>> Function(
|
||||
int page,
|
||||
int batchSize,
|
||||
SortType sortType,
|
||||
) fetcher;
|
||||
|
||||
const CommunitiesListPage({Key key, @required this.communities, this.title})
|
||||
: assert(communities != null),
|
||||
const CommunitiesListPage({Key key, @required this.fetcher, this.title = ''})
|
||||
: assert(fetcher != null),
|
||||
assert(title != null),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
// TODO: abillity to load more, right now its 10 - default page size
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(title ?? '', style: theme.textTheme.headline6),
|
||||
centerTitle: true,
|
||||
backgroundColor: theme.cardColor,
|
||||
iconTheme: theme.iconTheme,
|
||||
),
|
||||
body: ListView.builder(
|
||||
itemBuilder: (context, i) => ListTile(
|
||||
title: Text(communities[i].name),
|
||||
subtitle: communities[i].description != null
|
||||
? Opacity(
|
||||
opacity: 0.5,
|
||||
child: MarkdownText(
|
||||
communities[i].description,
|
||||
instanceUrl: communities[i].instanceUrl,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
onTap: () => goToCommunity.byId(
|
||||
context, communities[i].instanceUrl, communities[i].id),
|
||||
leading: communities[i].icon != null
|
||||
? CachedNetworkImage(
|
||||
height: 50,
|
||||
width: 50,
|
||||
imageUrl: communities[i].icon,
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.cover, image: imageProvider),
|
||||
appBar: AppBar(
|
||||
brightness: theme.brightness,
|
||||
title: Text(title, style: theme.textTheme.headline6),
|
||||
centerTitle: true,
|
||||
backgroundColor: theme.cardColor,
|
||||
iconTheme: theme.iconTheme,
|
||||
),
|
||||
body: SortableInfiniteList<CommunityView>(
|
||||
fetcher: fetcher,
|
||||
builder: (community) => Column(
|
||||
children: [
|
||||
Divider(),
|
||||
ListTile(
|
||||
title: Text(community.name),
|
||||
subtitle: community.description != null
|
||||
? Opacity(
|
||||
opacity: 0.5,
|
||||
child: MarkdownText(
|
||||
community.description,
|
||||
instanceUrl: community.instanceUrl,
|
||||
),
|
||||
),
|
||||
errorWidget: (_, __, ___) => SizedBox(width: 50),
|
||||
)
|
||||
: SizedBox(width: 50),
|
||||
// TODO: add trailing button for un/subscribing to communities
|
||||
),
|
||||
itemCount: communities.length,
|
||||
));
|
||||
)
|
||||
: null,
|
||||
onTap: () => goToCommunity.byId(
|
||||
context, community.instanceUrl, community.id),
|
||||
leading: community.icon != null
|
||||
? CachedNetworkImage(
|
||||
height: 50,
|
||||
width: 50,
|
||||
imageUrl: community.icon,
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.cover, image: imageProvider),
|
||||
),
|
||||
),
|
||||
errorWidget: (_, __, ___) => SizedBox(width: 50),
|
||||
)
|
||||
: SizedBox(width: 50),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ class CommunitiesTab extends HookWidget {
|
|||
toggleCollapse(int i) => isCollapsed.value =
|
||||
isCollapsed.value.mapWithIndex((e, j) => j == i ? !e : e).toList();
|
||||
|
||||
// TODO: add observer
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
actions: [
|
||||
|
@ -140,6 +141,7 @@ class CommunitiesTab extends HookWidget {
|
|||
Column(
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () {}, // TODO: open instance
|
||||
onLongPress: () => toggleCollapse(i),
|
||||
leading: instances[i].icon != null
|
||||
? CachedNetworkImage(
|
||||
|
@ -172,6 +174,7 @@ class CommunitiesTab extends HookWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 17),
|
||||
child: ListTile(
|
||||
onTap: () {}, // TODO: open community
|
||||
dense: true,
|
||||
leading: VerticalDivider(
|
||||
color: theme.hintColor,
|
||||
|
|
|
@ -19,6 +19,7 @@ import '../widgets/badge.dart';
|
|||
import '../widgets/bottom_modal.dart';
|
||||
import '../widgets/fullscreenable_image.dart';
|
||||
import '../widgets/markdown_text.dart';
|
||||
import '../widgets/sortable_infinite_list.dart';
|
||||
|
||||
class CommunityPage extends HookWidget {
|
||||
final CommunityView _community;
|
||||
|
@ -207,16 +208,28 @@ class CommunityPage extends HookWidget {
|
|||
],
|
||||
body: TabBarView(
|
||||
children: [
|
||||
ListView(
|
||||
children: [
|
||||
Center(child: Text('posts go here')),
|
||||
],
|
||||
),
|
||||
ListView(
|
||||
children: [
|
||||
Center(child: Text('comments go here')),
|
||||
],
|
||||
InfinitePostList(
|
||||
fetcher: (page, batchSize, sort) =>
|
||||
LemmyApi(community.instanceUrl).v1.getPosts(
|
||||
type: PostListingType.community,
|
||||
sort: sort,
|
||||
communityId: community.id,
|
||||
page: page,
|
||||
limit: batchSize,
|
||||
),
|
||||
),
|
||||
InfiniteCommentList(
|
||||
fetcher: (page, batchSize, sortType) =>
|
||||
LemmyApi(community.instanceUrl).v1.getComments(
|
||||
communityId: community.id,
|
||||
auth: accountsStore
|
||||
.defaultTokenFor(community.instanceUrl)
|
||||
?.raw,
|
||||
type: CommentListingType.community,
|
||||
sort: sortType,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
)),
|
||||
_AboutTab(
|
||||
community: community,
|
||||
moderators: fullCommunitySnap.data?.moderators,
|
||||
|
@ -289,7 +302,7 @@ class _CommunityOverview extends StatelessWidget {
|
|||
url: community.banner,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: community.banner,
|
||||
errorWidget: (_, __, ___) => Container(),
|
||||
errorWidget: (_, __, ___) => SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
SafeArea(
|
||||
|
@ -486,7 +499,7 @@ class _AboutTab extends StatelessWidget {
|
|||
for (final mod in moderators)
|
||||
ListTile(
|
||||
title: Text(mod.userPreferredUsername ?? '@${mod.userName}'),
|
||||
onTap: () => goToUser.byId(context, mod.instanceUrl, mod.id),
|
||||
onTap: () => goToUser.byId(context, mod.instanceUrl, mod.userId),
|
||||
),
|
||||
]
|
||||
],
|
||||
|
@ -512,7 +525,6 @@ class _Badge extends StatelessWidget {
|
|||
style:
|
||||
TextStyle(color: textColorBasedOnBackground(theme.accentColor)),
|
||||
),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:intl/intl.dart';
|
|||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:url_launcher/url_launcher.dart' as ul;
|
||||
|
||||
import '../hooks/stores.dart';
|
||||
import '../util/extensions/api.dart';
|
||||
import '../util/goto.dart';
|
||||
import '../util/text_color.dart';
|
||||
|
@ -14,6 +15,7 @@ import '../widgets/badge.dart';
|
|||
import '../widgets/bottom_modal.dart';
|
||||
import '../widgets/fullscreenable_image.dart';
|
||||
import '../widgets/markdown_text.dart';
|
||||
import '../widgets/sortable_infinite_list.dart';
|
||||
import 'communities_list.dart';
|
||||
import 'users_list.dart';
|
||||
|
||||
|
@ -36,6 +38,7 @@ class InstancePage extends HookWidget {
|
|||
final theme = Theme.of(context);
|
||||
final siteSnap = useFuture(siteFuture);
|
||||
final colorOnCard = textColorBasedOnBackground(theme.cardColor);
|
||||
final accStore = useAccountsStore();
|
||||
|
||||
if (!siteSnap.hasData) {
|
||||
return Scaffold(
|
||||
|
@ -165,7 +168,7 @@ class InstancePage extends HookWidget {
|
|||
url: site.site.banner,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: site.site.banner,
|
||||
errorWidget: (_, __, ___) => Container(),
|
||||
errorWidget: (_, __, ___) => SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
SafeArea(
|
||||
|
@ -212,16 +215,25 @@ class InstancePage extends HookWidget {
|
|||
],
|
||||
body: TabBarView(
|
||||
children: [
|
||||
ListView(
|
||||
children: [
|
||||
Center(child: Text('posts go here')),
|
||||
],
|
||||
),
|
||||
ListView(
|
||||
children: [
|
||||
Center(child: Text('comments go here')),
|
||||
],
|
||||
),
|
||||
InfinitePostList(
|
||||
fetcher: (page, batchSize, sort) =>
|
||||
LemmyApi(instanceUrl).v1.getPosts(
|
||||
// TODO: switch between all and subscribed
|
||||
type: PostListingType.all,
|
||||
sort: sort,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
auth: accStore.defaultTokenFor(instanceUrl)?.raw,
|
||||
)),
|
||||
InfiniteCommentList(
|
||||
fetcher: (page, batchSize, sort) =>
|
||||
LemmyApi(instanceUrl).v1.getComments(
|
||||
type: CommentListingType.all,
|
||||
sort: sort,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
auth: accStore.defaultTokenFor(instanceUrl)?.raw,
|
||||
)),
|
||||
_AboutTab(site,
|
||||
communitiesFuture: communitiesFuture,
|
||||
instanceUrl: instanceUrl),
|
||||
|
@ -284,13 +296,21 @@ class _AboutTab extends HookWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final commSnap = useFuture(communitiesFuture);
|
||||
final accStore = useAccountsStore();
|
||||
|
||||
void goToCommunities() {
|
||||
goTo(
|
||||
context,
|
||||
(_) => CommunitiesListPage(
|
||||
communities: commSnap.data,
|
||||
title: 'Communities of ${site.site.name}'),
|
||||
fetcher: (page, batchSize, sortType) =>
|
||||
LemmyApi(instanceUrl).v1.listCommunities(
|
||||
sort: sortType,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
auth: accStore.defaultTokenFor(instanceUrl)?.raw,
|
||||
),
|
||||
title: 'Communities of ${site.site.name}',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -436,7 +456,6 @@ class _Badge extends StatelessWidget {
|
|||
style:
|
||||
TextStyle(color: textColorBasedOnBackground(theme.accentColor)),
|
||||
),
|
||||
// TODO: change border radius
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import 'package:provider/provider.dart';
|
|||
import 'package:url_launcher/url_launcher.dart' as ul;
|
||||
|
||||
import 'pages/community.dart';
|
||||
import 'pages/full_post.dart';
|
||||
import 'pages/instance.dart';
|
||||
import 'pages/media_view.dart';
|
||||
import 'pages/user.dart';
|
||||
import 'stores/accounts_store.dart';
|
||||
import 'util/goto.dart';
|
||||
|
@ -22,15 +22,16 @@ Future<void> linkLauncher({
|
|||
final instances = context.read<AccountsStore>().users.keys.toList();
|
||||
|
||||
final chonks = url.split('/');
|
||||
if (chonks.length == 1) return openInBrowser(url);
|
||||
|
||||
// CHECK IF LINK TO USER
|
||||
if (chonks[1] == 'u') {
|
||||
if (url.startsWith('/u/')) {
|
||||
return push(
|
||||
() => UserPage.fromName(instanceUrl: instanceUrl, username: chonks[2]));
|
||||
}
|
||||
|
||||
// CHECK IF LINK TO COMMUNITY
|
||||
if (chonks[1] == 'c') {
|
||||
if (url.startsWith('/c/')) {
|
||||
return push(() => CommunityPage.fromName(
|
||||
communityName: chonks[2], instanceUrl: instanceUrl));
|
||||
}
|
||||
|
@ -50,28 +51,23 @@ Future<void> linkLauncher({
|
|||
final split = rest.split('/');
|
||||
switch (split[1]) {
|
||||
case 'c':
|
||||
return push(() => CommunityPage.fromName(
|
||||
communityName: split[2], instanceUrl: matchedInstance));
|
||||
return goToCommunity.byName(context, matchedInstance, split[2]);
|
||||
|
||||
case 'u':
|
||||
return push(() => UserPage.fromName(
|
||||
instanceUrl: matchedInstance, username: split[2]));
|
||||
return goToUser.byName(context, matchedInstance, split[2]);
|
||||
|
||||
case 'post':
|
||||
if (split.length == 3) {
|
||||
return push(() => FullPostPage(
|
||||
id: int.parse(split[2]), instanceUrl: matchedInstance));
|
||||
return goToPost(context, matchedInstance, int.parse(split[2]));
|
||||
} else if (split.length == 5) {
|
||||
// TODO: post with focus on comment thread
|
||||
print('comment in post');
|
||||
return;
|
||||
return goToPost(context, matchedInstance, int.parse(split[2]));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'pictrs':
|
||||
// TODO: put here push to media view
|
||||
print('pictrs');
|
||||
return;
|
||||
return push(() => MediaViewPage(url));
|
||||
|
||||
case 'communities':
|
||||
// TODO: put here push to communities page
|
||||
|
|
|
@ -6,7 +6,7 @@ class Badge extends StatelessWidget {
|
|||
|
||||
Badge({
|
||||
@required this.child,
|
||||
this.borderRadius = const BorderRadius.all(Radius.circular(5)),
|
||||
this.borderRadius = const BorderRadius.all(Radius.circular(10)),
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
|
@ -251,7 +251,7 @@ class Comment extends HookWidget {
|
|||
}();
|
||||
|
||||
final actions = collapsed.value
|
||||
? Container()
|
||||
? SizedBox.shrink()
|
||||
: Row(children: [
|
||||
if (selectable.value && !comment.deleted && !comment.removed)
|
||||
_CommentAction(
|
||||
|
@ -324,7 +324,7 @@ class Comment extends HookWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
errorWidget: (_, __, ___) => Container(),
|
||||
errorWidget: (_, __, ___) => SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -24,9 +24,13 @@ class InfiniteScroll<T> extends HookWidget {
|
|||
final Widget Function(T data) builder;
|
||||
final Future<List<T>> Function(int page, int batchSize) fetchMore;
|
||||
final InfiniteScrollController controller;
|
||||
final Widget prepend;
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
InfiniteScroll({
|
||||
this.batchSize = 10,
|
||||
this.prepend = const SizedBox.shrink(),
|
||||
this.padding,
|
||||
this.loadingWidget =
|
||||
const ListTile(title: Center(child: CircularProgressIndicator())),
|
||||
@required this.builder,
|
||||
|
@ -54,14 +58,20 @@ class InfiniteScroll<T> extends HookWidget {
|
|||
final page = data.value.length ~/ batchSize + 1;
|
||||
|
||||
return ListView.builder(
|
||||
// +1 for the loading widget
|
||||
itemCount: data.value.length + 1,
|
||||
padding: padding,
|
||||
// +2 for the loading widget and prepend widget
|
||||
itemCount: data.value.length + 2,
|
||||
itemBuilder: (_, i) {
|
||||
if (i == 0) {
|
||||
return prepend;
|
||||
}
|
||||
i -= 1;
|
||||
|
||||
// reached the bottom, fetch more
|
||||
if (i == data.value.length) {
|
||||
// if there are no more, skip
|
||||
if (!hasMore.current) {
|
||||
return Container();
|
||||
return SizedBox.shrink();
|
||||
}
|
||||
|
||||
// if it's already fetching more, skip
|
||||
|
|
|
@ -25,10 +25,11 @@ enum MediaType {
|
|||
gallery,
|
||||
video,
|
||||
other,
|
||||
none,
|
||||
}
|
||||
|
||||
MediaType whatType(String url) {
|
||||
if (url == null) return MediaType.other;
|
||||
if (url == null || url.isEmpty) return MediaType.none;
|
||||
|
||||
// TODO: make detection more nuanced
|
||||
if (url.endsWith('.jpg') ||
|
||||
|
@ -141,7 +142,7 @@ class Post extends HookWidget {
|
|||
linkLauncher(context: context, url: post.url, instanceUrl: instanceUrl);
|
||||
|
||||
final urlDomain = () {
|
||||
if (post.url == null) return null;
|
||||
if (whatType(post.url) == MediaType.none) return null;
|
||||
|
||||
final url = post.url.split('/')[2];
|
||||
if (url.startsWith('www.')) return url.substring(4);
|
||||
|
@ -262,6 +263,9 @@ class Post extends HookWidget {
|
|||
IconButton(
|
||||
onPressed: () => showMoreMenu(context, post),
|
||||
icon: Icon(Icons.more_vert),
|
||||
iconSize: 24,
|
||||
padding: EdgeInsets.all(0),
|
||||
visualDensity: VisualDensity.compact,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
@ -283,8 +287,7 @@ class Post extends HookWidget {
|
|||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
if (post.url != null &&
|
||||
whatType(post.url) == MediaType.other &&
|
||||
if (whatType(post.url) == MediaType.other &&
|
||||
post.thumbnailUrl != null) ...[
|
||||
Spacer(),
|
||||
InkWell(
|
||||
|
@ -342,11 +345,12 @@ class Post extends HookWidget {
|
|||
]),
|
||||
Row(children: [
|
||||
Flexible(
|
||||
child: Text('${post.embedTitle}',
|
||||
child: Text('${post.embedTitle ?? ''}',
|
||||
style: theme.textTheme.subtitle1
|
||||
.apply(fontWeightDelta: 2)))
|
||||
]),
|
||||
if (post.embedDescription != null)
|
||||
if (post.embedDescription != null &&
|
||||
post.embedDescription.isNotEmpty)
|
||||
Row(children: [
|
||||
Flexible(child: Text(post.embedDescription))
|
||||
]),
|
||||
|
@ -416,9 +420,10 @@ class Post extends HookWidget {
|
|||
children: [
|
||||
info(),
|
||||
title(),
|
||||
if (whatType(post.url) != MediaType.other)
|
||||
if (whatType(post.url) != MediaType.other &&
|
||||
whatType(post.url) != MediaType.none)
|
||||
postImage()
|
||||
else if (post.url != null)
|
||||
else if (post.url != null && post.url.isNotEmpty)
|
||||
linkPreview(),
|
||||
if (post.body != null)
|
||||
Padding(
|
||||
|
|
|
@ -8,9 +8,11 @@ import 'bottom_modal.dart';
|
|||
class PostListOptions extends HookWidget {
|
||||
final void Function(SortType sort) onChange;
|
||||
final SortType defaultSort;
|
||||
final bool styleButton;
|
||||
|
||||
PostListOptions({
|
||||
@required this.onChange,
|
||||
this.styleButton = true,
|
||||
this.defaultSort = SortType.active,
|
||||
});
|
||||
|
||||
|
@ -31,9 +33,7 @@ class PostListOptions extends HookWidget {
|
|||
RadioListTile<SortType>(
|
||||
value: x,
|
||||
groupValue: sort.value,
|
||||
// TODO: use something more robust and user-friendly
|
||||
// than describeEnum
|
||||
title: Text(describeEnum(x)),
|
||||
title: Text(x.value),
|
||||
onChanged: (val) {
|
||||
sort.value = val;
|
||||
onChange(val);
|
||||
|
@ -57,17 +57,19 @@ class PostListOptions extends HookWidget {
|
|||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(describeEnum(sort.value)),
|
||||
Text(sort.value.value),
|
||||
const SizedBox(width: 8),
|
||||
Icon(Icons.arrow_drop_down),
|
||||
],
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
IconButton(
|
||||
icon: Icon(Icons.view_stream),
|
||||
onPressed: () => print('TBD'),
|
||||
)
|
||||
if (styleButton)
|
||||
IconButton(
|
||||
icon: Icon(Icons.view_stream),
|
||||
// TODO: create compact post and dropdown for selecting
|
||||
onPressed: () => print('TBD'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
|
||||
import '../comment_tree.dart';
|
||||
import '../hooks/infinite_scroll.dart';
|
||||
import 'comment.dart';
|
||||
import 'infinite_scroll.dart';
|
||||
import 'post.dart';
|
||||
import 'post_list_options.dart';
|
||||
|
||||
/// Infinite list of posts
|
||||
class SortableInfiniteList<T> extends HookWidget {
|
||||
final Future<List<T>> Function(int page, int batchSize, SortType sortType)
|
||||
fetcher;
|
||||
final Widget Function(T) builder;
|
||||
final Function onStyleChange;
|
||||
|
||||
SortableInfiniteList({
|
||||
@required this.fetcher,
|
||||
@required this.builder,
|
||||
this.onStyleChange,
|
||||
}) : assert(fetcher != null),
|
||||
assert(builder != null);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isc = useInfiniteScrollController();
|
||||
final sort = useState(SortType.active);
|
||||
|
||||
void changeSorting(SortType newSort) {
|
||||
sort.value = newSort;
|
||||
isc.clear();
|
||||
}
|
||||
|
||||
return InfiniteScroll<T>(
|
||||
prepend: PostListOptions(
|
||||
onChange: changeSorting,
|
||||
defaultSort: SortType.active,
|
||||
styleButton: onStyleChange != null,
|
||||
),
|
||||
builder: builder,
|
||||
padding: EdgeInsets.zero,
|
||||
fetchMore: (page, batchSize) => fetcher(page, batchSize, sort.value),
|
||||
controller: isc,
|
||||
batchSize: 20,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class InfinitePostList extends StatelessWidget {
|
||||
final Future<List<PostView>> Function(
|
||||
int page, int batchSize, SortType sortType) fetcher;
|
||||
|
||||
InfinitePostList({@required this.fetcher}) : assert(fetcher != null);
|
||||
|
||||
Widget build(BuildContext context) => SortableInfiniteList<PostView>(
|
||||
onStyleChange: () {},
|
||||
builder: (post) => Column(
|
||||
children: [
|
||||
Post(post),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
fetcher: fetcher,
|
||||
);
|
||||
}
|
||||
|
||||
class InfiniteCommentList extends StatelessWidget {
|
||||
final Future<List<CommentView>> Function(
|
||||
int page, int batchSize, SortType sortType) fetcher;
|
||||
|
||||
InfiniteCommentList({@required this.fetcher}) : assert(fetcher != null);
|
||||
|
||||
Widget build(BuildContext context) => SortableInfiniteList<CommentView>(
|
||||
builder: (comment) => Comment(
|
||||
CommentTree(comment),
|
||||
postCreatorId: null,
|
||||
),
|
||||
fetcher: fetcher,
|
||||
);
|
||||
}
|
|
@ -96,7 +96,7 @@ class UserProfile extends HookWidget {
|
|||
if (userViewSnap.data?.banner != null)
|
||||
CachedNetworkImage(
|
||||
imageUrl: userViewSnap.data.banner,
|
||||
errorWidget: (_, __, ___) => Container(),
|
||||
errorWidget: (_, __, ___) => SizedBox.shrink(),
|
||||
)
|
||||
else
|
||||
Container(
|
||||
|
@ -155,7 +155,7 @@ class UserProfile extends HookWidget {
|
|||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: userViewSnap.data.avatar,
|
||||
errorWidget: (_, __, ___) => Container(),
|
||||
errorWidget: (_, __, ___) => SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -379,7 +379,7 @@ packages:
|
|||
name: lemmy_api_client
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
version: "0.6.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -31,9 +31,10 @@ dependencies:
|
|||
flutter_hooks: ^0.13.2
|
||||
cached_network_image: ^2.2.0+1
|
||||
timeago: ^2.0.27
|
||||
lemmy_api_client: ^0.5.0
|
||||
fuzzy: <1.0.0
|
||||
|
||||
lemmy_api_client: ^0.6.0
|
||||
|
||||
mobx: ^1.2.1
|
||||
flutter_mobx: ^1.1.0
|
||||
provider: ^4.3.1
|
||||
|
|
Loading…
Reference in New Issue