Reputation: 130
This code here currently loads all the brews that are stored in the Firestore collection.. How can i load initially just 10 brews and then later on when the user scrolls down and reaches to the end of the list of 10 brews..it should load 10 more after the last brew..and the brews should be sorted according to the timestamp.
class BrewList extends StatefulWidget {
@override
_BrewListState createState() => _BrewListState();
}
class _BrewListState extends State<BrewList> {
List<Brew> brews = [];
ScrollController _controller = ScrollController();
@override
void initState() {
_startFirst();
super.initState();
_controller.addListener(_scrollListener);
}
_scrollListener() {
setState(() {
if (_controller.position.atEdge) {
if (_controller.position.pixels == 0) {
} else {
}
}
});
}
_startFirst() async {
brews = await DatabaseService().brews ?? [];
setState(() {
brews = brews;
});
}
@override
Widget build(BuildContext context) {
Future<void> _refreshBrews() async {
List<Brew> tempList = await DatabaseService().brews;
setState(() {
brews = tempList;
});
print(brews);
}
return RefreshIndicator(
onRefresh: _refreshBrews,
child: ListView.builder(
controller: _controller,
itemCount: brews.length,
itemBuilder: (context, index) {
return BrewTile(brew: brews[index]);
},
),
);
}
}
Future<List<Brew>> get brewss async {
QuerySnapshot snapshot = await brewsCollection
.orderBy('timestamp', descending: true)
.limit(2)
.getDocuments();
return _postListFromSnapshot(snapshot);
}
Upvotes: 2
Views: 1959
Reputation: 2422
Not sure if the following will help, but here's what I did in my flutter app. Pay special attention to the _onScroll function at the bottom.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../blocs/feed_bloc/feed_events.dart';
import '../../blocs/feed_bloc/bloc.dart';
import '../../blocs/feed_bloc/feed_state.dart';
import './post.dart';
import '../loader.dart';
class Feed extends StatefulWidget {
Feed({ Key key }): super(key: key);
@override
_FeedState createState() => _FeedState();
}
class _FeedState extends State<Feed> {
final _scrollController = ScrollController();
final _scrollThreshold = 300.0;
FeedBloc _feedBloc;
_FeedState();
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
_feedBloc = BlocProvider.of<FeedBloc>(context);
}
@override
Widget build(BuildContext context) {
return BlocBuilder<FeedBloc, FeedState>(
builder: (context, state) {
if (state is FeedUninitialized) {
_feedBloc.add(Init());
return Loader();
}
if (state is FeedLoading) {
return Loader();
}
if (state is FeedLoaded) {
return new RefreshIndicator(
child: ListView(
controller: _scrollController,
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: state.posts.map((post) {
return Post(
postModel: state.postMap[post]
);
}).toList(),
),
onRefresh: () {
_feedBloc.add(Refresh());
return new Future.delayed(new Duration(seconds: 1));
},
);
}
return Center(
child: SizedBox(
height: 33,
child: Text(
'Sorry, there was a problem loading the feed.',
style: TextStyle( color: Colors.white)
),
),
);
}
);
}
int lastScroll = 0;
void _onScroll() {
if (new DateTime.now().millisecondsSinceEpoch - lastScroll > 1000) {
lastScroll = new DateTime.now().millisecondsSinceEpoch;
final maxScroll = _scrollController.position.maxScrollExtent;
final currentScroll = _scrollController.position.pixels;
if (maxScroll - currentScroll <= _scrollThreshold) {
_feedBloc.add(Fetch());
}
}
}
}
I think what you need is startAfterDocument. See below...
Future<Map<String, dynamic>> getPosts({PostModel parent, PostModel lastPost}) async {
// First, we create the initial query.
// We pass in the parent key if there is one.
Query query = Firestore.instance
.collection('posts');
if (parent != null) {
query = query.where('parentId', isEqualTo: parent.key);
} else {
query = query.where('parentId', isNull: true);
}
query = query.orderBy('timestamp', descending: true);
// If we want to start at a certain doc (user is scrolling throught he feed)
// then we specify to start after a certain doc
if (lastPost != null) {
query = query.startAfterDocument(lastPost.rawDoc);
}
// Execute the query
final results = await query
.limit(18)
.getDocuments();
// Create some Lists/Maps we're going to need
List<String> posts = new List<String>();
Map<String, PostModel> postMap = new Map<String, PostModel>();
Map<String, bool> likeMap = new Map<String, bool>();
// Convienience/Brevity
final List<DocumentSnapshot> documents = results.documents;
final int numDocs = documents.length;
if (numDocs > 0) {
final firstDoc = results.documents[0].data;
final lastDoc = results.documents[numDocs-1].data;
// Get all your likes for a certain date range that aligns with the
// documents we just retrieved
likeMap = await getLikes(firstDoc['postCreated'], lastDoc['postCreated']);
}
// Loop through, and create all the PostModels
for (int i = 0; i < numDocs; i++) {
DocumentSnapshot doc = documents[i];
PostModel post = snapshotToPostModel(doc, likeMap[doc.documentID]);
postMap[doc.documentID] = post;
posts.add(post.key);
}
final Map<String, dynamic> res = new Map<String, dynamic>();
res['posts'] = posts;
res['postMap'] = postMap;
return res;
}
Upvotes: 1
Reputation: 624
You could use a scroll controller and a listener to determine if the user has scrolled to the bottom of the screen. If they have then load the next 10 items from the Database Service.
This would look something like the following.
ScrollController _controller = ScrollController();
@override
void initState() {
super.initState();
// add listener
_controller.addListener(_scrollListener);
}
_scrollListener() {
setState(() {
if (_controller.position.atEdge) {
if (_controller.position.pixels == 0)
{
// user is at top of the list
}
else
{
// user is at the bottom of the list.
// load next 10 items and add them to the list of items in the list.
}
}
});
}
Upvotes: 0