I am building a social network type product where users have followers and "workout_posts". I have created a similar model to the one outlined by Alex Mamo in this their answer to Firestore - how to structure a feed and follow system.
I have a collection of users, a collection of followers, and a collection of workout posts.
I have effectively set up a query to display all of a single users posts via pagination with the following code. This would work great for showing all of a single users posts in the profile view of the app.
class Workouts extends StatefulWidget {
Workouts({Key key, this.user}) : super(key: key);
final User user;
@override
_WorkoutsState createState() => new _WorkoutsState(
user: user
);
}
class _WorkoutsState extends State<Workouts> {
_WorkoutsState({this.user});
final User user;
Firestore _firestore = Firestore.instance;
List<DocumentSnapshot> _workouts = [];
bool _loadingWorkouts = true;
int _per_page = 8;
DocumentSnapshot _lastWorkout;
ScrollController _scrollController = ScrollController();
bool _gettingMoreWorkouts = false;
bool _moreWorkoutsAvailable = true;
_getWorkouts() async {
Query q = _firestore
.collection('workouts_posts')
.document(user.user_id)
.collection('posts')
.orderBy("post")
.limit(_per_page);
setState(() {
_loadingWorkouts = true;
});
QuerySnapshot querySnapshot = await q.getDocuments();
_workouts = querySnapshot.documents;
_lastWorkout = querySnapshot.documents[querySnapshot.documents.length - 1];
setState(() {
_loadingWorkouts = false;
});
}
_getMoreProducts() async {
print("get more products called");
if (_moreWorkoutsAvailable == false) {
return;
}
if (_gettingMoreWorkouts == true) {
return;
}
_gettingMoreWorkouts = true;
Query q = _firestore
.collection('workouts_posts')
.document(user.user_id)
.collection('posts')
.orderBy("post")
.startAfter([_lastWorkout.data['post']]).limit(_per_page);
QuerySnapshot querySnapshot = await q.getDocuments();
if (querySnapshot.documents.length < _per_page) {
_moreWorkoutsAvailable = false;
}
_lastWorkout = querySnapshot.documents[querySnapshot.documents.length - 1];
_workouts.addAll(querySnapshot.documents);
setState(() {});
_gettingMoreWorkouts = false;
}
@override
void initState() {
super.initState();
_getWorkouts();
_scrollController.addListener(() {
double maxScroll = _scrollController.position.maxScrollExtent;
double currentScroll = _scrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.25;
if (maxScroll - currentScroll < delta) {
_getMoreProducts();
}
});
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
new Expanded(
child: _loadingWorkouts == true
? Container(
child: Center(
child: Text("Loading..."),
),
)
: Container(
child: Center(
child: _workouts.length == 0
? Center(
child: Text("No Workouts to show"),
)
: ListView.builder(
controller: _scrollController,
itemCount: _workouts.length,
itemBuilder: (BuildContext ctx, int index) {
return new PostWidget(
postText: _workouts[index].data['post'],
pictureURL: _workouts[index].data['url'],
goalText: _workouts[index].data['goalText'],
userOfPost: _workouts[index].data['user'],
currentUser: user,
goalType: "workouts",
postID: _workouts[index].documentID,
);
}),
),
),
)
],
);
}
}
My challenge is how to query the posts of all followers for each user, combine them into one list, and then sort by timestamp--all while maintaining the pagination. Does anyone have any experience doing this or advice on the approach? Should I change my data model to denormalize it?