Create home tab with different listings
This commit is contained in:
parent
c6a1eff7ed
commit
0734fb42fc
|
@ -0,0 +1,242 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||||
|
|
||||||
|
import '../hooks/infinite_scroll.dart';
|
||||||
|
import '../hooks/stores.dart';
|
||||||
|
import '../util/goto.dart';
|
||||||
|
import '../widgets/bottom_modal.dart';
|
||||||
|
import '../widgets/infinite_scroll.dart';
|
||||||
|
import '../widgets/post.dart';
|
||||||
|
import '../widgets/post_list_options.dart';
|
||||||
|
import 'inbox.dart';
|
||||||
|
|
||||||
|
class HomeTab extends HookWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final selectedList =
|
||||||
|
useState(SelectedList(listingType: PostListingType.subscribed));
|
||||||
|
final accStore = useAccountsStore();
|
||||||
|
final isc = useInfiniteScrollController();
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
|
handleListChange() async {
|
||||||
|
final val = await showModalBottomSheet<SelectedList>(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
isScrollControlled: true,
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
pop(SelectedList thing) => Navigator.of(context).pop(thing);
|
||||||
|
return BottomModal(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: Text('EVERYTHING'),
|
||||||
|
dense: true,
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
visualDensity:
|
||||||
|
VisualDensity(vertical: VisualDensity.minimumDensity),
|
||||||
|
leading: SizedBox(width: 20, height: 20),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('Subscribed'),
|
||||||
|
leading: SizedBox(width: 20, height: 20),
|
||||||
|
onTap: () =>
|
||||||
|
pop(SelectedList(listingType: PostListingType.subscribed)),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('All'),
|
||||||
|
leading: SizedBox(width: 20, height: 20),
|
||||||
|
onTap: () =>
|
||||||
|
pop(SelectedList(listingType: PostListingType.all)),
|
||||||
|
),
|
||||||
|
for (final instance in accStore.instances) ...[
|
||||||
|
Divider(),
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
instance.toUpperCase(),
|
||||||
|
style: TextStyle(
|
||||||
|
color:
|
||||||
|
theme.textTheme.bodyText1.color.withOpacity(0.7)),
|
||||||
|
),
|
||||||
|
dense: true,
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
visualDensity:
|
||||||
|
VisualDensity(vertical: VisualDensity.minimumDensity),
|
||||||
|
leading: SizedBox(width: 30),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('Subscribed'),
|
||||||
|
onTap: () => pop(SelectedList(
|
||||||
|
listingType: PostListingType.subscribed,
|
||||||
|
instanceUrl: instance,
|
||||||
|
)),
|
||||||
|
leading: SizedBox(width: 20),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('All'),
|
||||||
|
onTap: () => pop(SelectedList(
|
||||||
|
listingType: PostListingType.all,
|
||||||
|
instanceUrl: instance,
|
||||||
|
)),
|
||||||
|
leading: SizedBox(width: 20),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (val != null) {
|
||||||
|
print(val);
|
||||||
|
selectedList.value = val;
|
||||||
|
isc.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.notifications),
|
||||||
|
onPressed: () => goTo(context, (_) => InboxPage()),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
centerTitle: true,
|
||||||
|
title: TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(10))),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||||
|
primary: theme.buttonColor,
|
||||||
|
textStyle: theme.textTheme.headline6,
|
||||||
|
),
|
||||||
|
onPressed: handleListChange,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text('Subscribed'),
|
||||||
|
Icon(Icons.arrow_drop_down),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
body: InfiniteHomeList(
|
||||||
|
controller: isc,
|
||||||
|
selectedList: selectedList.value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InfiniteHomeList extends HookWidget {
|
||||||
|
final Function onStyleChange;
|
||||||
|
final InfiniteScrollController controller;
|
||||||
|
final SelectedList selectedList;
|
||||||
|
InfiniteHomeList({
|
||||||
|
@required this.selectedList,
|
||||||
|
this.onStyleChange,
|
||||||
|
this.controller,
|
||||||
|
}) : assert(selectedList != null);
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final accStore = useAccountsStore();
|
||||||
|
|
||||||
|
final sort = useState(SortType.active);
|
||||||
|
|
||||||
|
void changeSorting(SortType newSort) {
|
||||||
|
sort.value = newSort;
|
||||||
|
controller.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<PostView>> ultimateFetcher(
|
||||||
|
int page,
|
||||||
|
int limit,
|
||||||
|
SortType sort,
|
||||||
|
PostListingType listingType,
|
||||||
|
) async {
|
||||||
|
assert(
|
||||||
|
listingType != PostListingType.community, 'only subscribed or all');
|
||||||
|
|
||||||
|
final instances = () {
|
||||||
|
if (listingType == PostListingType.all) {
|
||||||
|
return accStore.instances;
|
||||||
|
} else {
|
||||||
|
return accStore.loggedInInstances;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
final futures =
|
||||||
|
instances.map((instanceUrl) => LemmyApi(instanceUrl).v1.getPosts(
|
||||||
|
type: listingType,
|
||||||
|
sort: sort,
|
||||||
|
page: page,
|
||||||
|
limit: limit,
|
||||||
|
auth: accStore.defaultTokenFor(instanceUrl)?.raw,
|
||||||
|
));
|
||||||
|
final posts =
|
||||||
|
await Future.wait(futures).then((value) => value.expand((e) => e));
|
||||||
|
// TODO: sorting
|
||||||
|
return posts.toList(); // .sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<PostView>> Function(int, int) _fetcherFromInstance(
|
||||||
|
String instanceUrl, PostListingType listingType, SortType sort) {
|
||||||
|
return (page, batchSize) => LemmyApi(instanceUrl).v1.getPosts(
|
||||||
|
type: listingType,
|
||||||
|
sort: sort,
|
||||||
|
page: page,
|
||||||
|
limit: batchSize,
|
||||||
|
auth: accStore.defaultTokenFor(instanceUrl)?.raw,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InfiniteScroll<PostView>(
|
||||||
|
prepend: Column(
|
||||||
|
children: [
|
||||||
|
PostListOptions(
|
||||||
|
onChange: changeSorting,
|
||||||
|
defaultSort: SortType.active,
|
||||||
|
styleButton: onStyleChange != null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
builder: (post) => Column(
|
||||||
|
children: [
|
||||||
|
Post(post),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
fetchMore: selectedList.instanceUrl == null
|
||||||
|
? (page, limit) =>
|
||||||
|
ultimateFetcher(page, limit, sort.value, selectedList.listingType)
|
||||||
|
: _fetcherFromInstance(
|
||||||
|
selectedList.instanceUrl,
|
||||||
|
selectedList.listingType,
|
||||||
|
sort.value,
|
||||||
|
),
|
||||||
|
controller: controller,
|
||||||
|
batchSize: 20,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectedList {
|
||||||
|
final String instanceUrl;
|
||||||
|
final PostListingType listingType;
|
||||||
|
SelectedList({
|
||||||
|
@required this.listingType,
|
||||||
|
this.instanceUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
String toString() =>
|
||||||
|
'SelectedList({instanceUrl: $instanceUrl, listingType: $listingType})';
|
||||||
|
}
|
||||||
|
|
||||||
|
// class _Divider extends StatelessWidget {
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) => Padding(
|
||||||
|
// padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
|
||||||
|
// child: Divider(),
|
||||||
|
// );
|
||||||
|
// }
|
Loading…
Reference in New Issue