I am trying to build an app in which users can share and like posts similar to social media apps. My problem is with liking posts. With the current code, I am getting the length of the 'likes' list from firebase, and when the user clicks the like button for the first time, adding the user's id to the list, and if the user clicks again, removing the id.
The problem is that when the user clicks the like button, there is a delay and the like count doesn't update instantly like in every other app.
What can I do to show the updates instantly?
This is the main screen:
class MainScreen extends StatelessWidget {
MainScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
TextEditingController textController = TextEditingController();
final PostController postController = Get.put(PostController());
return Scaffold(
body: Column(
children: [
Expanded(child: Obx(
() {
return ListView.builder(
itemCount: postController.postList.length,
controller: postController.scrollController,
itemBuilder: (context, index) {
var postData = postController.postList[index];
return PostBuilder(post: postData);
This is the PostBuider widget:
class PostBuilder extends StatelessWidget {
final Post post;
PostBuilder({
Key? key,
required this.post,
}) : super(key: key);
@override
Widget build(BuildContext context) {
PostController postController = Get.find();
return Column(
children: [
ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(post.profile_picture),
),
trailing: PopupMenuButton(
onSelected: (value) {},
itemBuilder: (BuildContext context) {
return [
const PopupMenuItem(
value: MenuSelection.selection1,
child: Text(' '),
),
const PopupMenuItem(
value: MenuSelection.selection2,
child: Text(
' ',
style: TextStyle(color: Colors.red),
),
),
];
},
),
title: Text(
post.full_name ?? '',
style: TextStyle(
color: Colors.indigo.shade900,
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
post.date.toString(),
style: const TextStyle(color: Colors.grey),
),
),
Container(
alignment: Alignment.topLeft,
height: 99,
padding: const EdgeInsets.symmetric(horizontal: 20),
child: SingleChildScrollView(
child: Text(
post.text ?? '',
textAlign: TextAlign.left,
),
),
),
Container(
padding: const EdgeInsets.only(left: 12, right: 28),
child: Obx(
() => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
IconButton(
onPressed: () {
postController.likePost(post.id);
},
icon: Icon(Icons.thumb_up),
),
Text(
postController.likeCount.value.toString(),
style: kGreyText,
)
],
),
Row(
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.messenger),
),
Text(
'0',
style: kGreyText,
),
],
)
],
),
),
)
],
);
}
}
This is the PostController Class:
class PostController extends GetxController {
late Post post;
var isDataProcessing = false.obs;
final int _perPage = 10;
RxList<dynamic> postSnapshots = [].obs;
RxList<dynamic> postList = [].obs;
RxInt likeCount = 0.obs;
//For Pagination
ScrollController scrollController = ScrollController();
var isMoreDataAvailable = true.obs;
@override
void onInit() {
super.onInit();
getInitialPosts();
paginateList();
}
getInitialPosts() async {
print('getİnitialPosts called');
Query q = fbFireStore
.collection('posts')
.orderBy('timestamp', descending: true)
.limit(_perPage);
QuerySnapshot snap = await q.get();
postSnapshots = snap.docs.obs;
for (int i = 0; i < postSnapshots.length; i++) {
post = Post.fromSnap(postSnapshots[i]);
postList.add(post);
}
}
void paginateList() {
scrollController.addListener(() {
if (scrollController.position.pixels ==
scrollController.position.maxScrollExtent) {
print('reached end of the page');
getMorePosts();
}
});
}
getMorePosts() async {
try {
print('getMorePosts called');
Query q = fbFireStore
.collection('posts')
.orderBy('timestamp', descending: true)
.startAfterDocument(postSnapshots[postSnapshots.length - 1])
.limit(_perPage);
QuerySnapshot snap = await q.get();
postSnapshots.value = snap.docs;
print('postSnapshots length is ${postSnapshots.length}');
for (int i = 0; i < postSnapshots.length; i++) {
post = Post.fromSnap(postSnapshots[i]);
postList.add(post);
}
Post lastPostCheck = postList[postList.length - 1];
print(lastPostCheck.full_name);
print('postList length is ${postList.length}');
} catch (e) {
Get.snackbar('error', e.toString());
}
}
void likePost(String id) async {
print(id);
DocumentSnapshot q = await fbFireStore.collection('posts').doc(id).get();
likeCount.value = q['likes'].length;
DocumentSnapshot doc = await fbFireStore.collection('posts').doc(id).get();
var uid = authController.user.uid;
if (doc['likes'].contains(uid)) {
likeCount.value--;
await fbFireStore.collection('posts').doc(id).update(
{
'likes': FieldValue.arrayRemove([uid]),
},
);
} else {
likeCount.value++;
await fbFireStore.collection('posts').doc(id).update({
'likes': FieldValue.arrayUnion([uid])
});
}
}
}
This is the Post Model:
class Post {
String? full_name;
String profile_picture;
String uid;
String? client;
String? full_url;
String id;
List? likes;
String? text;
String? thumb_storage_uri;
String? userid;
String? date;
Post({
required this.full_name,
this.profile_picture =
' ',
required this.uid,
required this.client,
this.full_url = '',
this.id = '',
required this.likes,
required this.text,
this.thumb_storage_uri = '',
required this.userid,
required this.date,
});
Map<String, dynamic> toJson() => {
'author': {
'full_name': full_name,
'profile_picture': profile_picture,
'uid': uid,
},
'client': client,
'full_url': full_url,
'id': id,
'likes': likes,
'text': text,
'thumb_storage_uri': thumb_storage_uri,
'userid': userid,
'timestamp': FieldValue.serverTimestamp(),
};
static Post fromSnap(DocumentSnapshot snap) {
var snapShot = snap.data() as Map<String, dynamic>;
return Post(
full_name: snapShot['author']['full_name'],
profile_picture: snapShot['author']['profile_picture'],
uid: snapShot['author']['uid'],
client: snapShot['client'],
id: snapShot['id'],
likes: snapShot['likes'],
text: snapShot['text'],
userid: snapShot['userid'],
date: snapShot['timestamp'].toString());
}
}
The solution I could think of was that when getting the posts for the ListViewBuilder, saving the length of the 'likes' list as a static value and using it as an observable integer but I couldn't achieve it with getx.
I am also very new in app development. If you have any advice about the rest of the code I would appreciate it.