Profile Navigation And Follow System
Today, we’re making Connect feel even more interactive! 🚀
We’re enhancing the profile experience, allowing users to:
✅ Tap on profiles from posts and navigate seamlessly.
✅ Display profile images dynamically using cached data.
✅ Implement a follow/unfollow system to build connections.
This is a major step towards making Connect a social-first progress-sharing app. By the end of this, profiles will be fully functional, and users can start following others!
Let’s get started. 🔥
GitHub Code Link: https://github.com/maitry4/Connect/
Refer to this alongside as it’s tough to display everything here.
Contents
Profile Navigation And Follow System
STEP 1: Make Profiles Clickable in Post Tiles
Let’s start by making user profiles tappable in post tiles.
1️⃣ Wrap the username and avatar in a GestureDetector
.
2️⃣ On tap, navigate to the profile page using Navigator.push()
.
3️⃣ Pass a fromHome
boolean to the profile page:
- If
true
, ensure returning to the home page reloads all posts instead of just the visited user’s posts.
//in profile page
final String uid;
bool fromHome;
CProfilePage({super.key, required this.uid, this.fromHome = false});
//When you pass it from post tile make it true.
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.surface,
leading: widget.fromHome
? IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
context
.read<CPostCubit>()
.fetchAllPosts(); // Refresh home on return
},
)
: null,
),
Profile Navigation And Follow System Profile Navigation And Follow System Profile Navigation And Follow System Profile Navigation And Follow System
If the profile being viewed isn’t the current user’s, hide the Edit Profile button.
Pass another optional parameter for the current user ID.
Now, if the profile user matches the current user, display the edit profile button. Else do not.
if (widget.uid == widget.currentUserId)
Add this above the edit profile button.
And yes don’t forget to modify the profile card widget for the same on desktop.
STEP 2: Display Profile Images in Post Tiles
Now, let’s make posts feel more personal by showing the user’s profile image.
🔹 Modify CPostCubit
to store a cache of user profiles (avoids excessive Firebase calls).
🔹 Add a method to fetch multiple users when loading posts.
Create a new state for multiple profiles:
class CProfilesLoadedState extends CProfileState {
final List<CProfileUser> profiles;
CProfilesLoadedState(this.profiles);
}
Profile Navigation And Follow System Profile Navigation And Follow System Profile Navigation And Follow System Profile Navigation And Follow System
In the home page initState modify:
postCubit.fetchAllPosts().then((_) {
final posts = postCubit.state is CPostsLoadedState
? (postCubit.state as CPostsLoadedState).posts
: [];
final userIds = posts.map((post) => post.userId).toSet().toList();
// Fetch all profiles at once
context.read<CProfileCubit>().fetchUserProfiles(userIds);
});
💡 Now, pass profile images to both desktop and mobile post UI components and replace the placeholder with the user’s profile image.
- in the bloc builder of the home page scaffold, we will have another bloc builder to provide profile images.
- pass the profile images to the build mobile and build desktop methods.
- now go ahead and pass these to your post-specific UI for both mobile and desktop(From the home page). and receive them here in the post UI pages.
In the profile page you won’t need to work really hard just do this:
.map((post) => CPostUi(post: post, profileImageUrl: usr.profileImageUrl,)).toList(),
.map((post) => CPostUiDesktop(post: post, profileImageUrl: usr.profileImageUrl,))
And now let’s move on to the follow system in our app.
Profile Navigation And Follow System Profile Navigation And Follow System Profile Navigation And Follow System Profile Navigation And Follow System
STEP 3: Modify Post and Profile Entities for the Follow System
Next, let’s lay the groundwork for the follow/unfollow system.
🔹 Add a private
boolean to CPost
(for future private/public post settings).
🔹 Modify CProfileUser
to include followers and following lists:
final List<String> followers;
final List<String> following;
CProfileUser copyWith({
String? newBio,
String? newProfileImageUrl,
List<String>? newFollowers,
List<String>? newFollowing,
}) {
return CProfileUser(
uid: uid,
email: email,
name: name,
bio: newBio ?? bio,
profileImageUrl: newProfileImageUrl ?? profileImageUrl,
followers: newFollowers ?? followers,
following: newFollowing ?? following,
);
}
//Map<String, dynamic> toJson()
'followers':followers,
'following':following,
followers: List<String>.from(jsonUser['followers'] ?? []),
following: List<String>.from(jsonUser['following'] ?? []),
STEP 4: Implement Follow/Unfollow in Firebase and ProfileCubit
Now, we’ll add the logic to follow and unfollow users.
🔹 First, add the method to profile_repo.dart
:
Future<void> toggleFollow(String currentUid, String targetUid);
🔹 Implement it in firebase_profile_repo.dart
:
Future<void> toggleFollow(String currentUid, String targetUid) async {
try {
// get both the users
final currentUserDoc = await firebaseFirestore.collection('users').doc(currentUid).get();
final targetUserDoc = await firebaseFirestore.collection('users').doc(targetUid).get();
// see if they are present
if (currentUserDoc.exists && targetUserDoc.exists) {
// get data from both
final currentUserData = currentUserDoc.data();
final targetUserData = targetUserDoc.data();
// check if the data is correct
if (currentUserData != null && targetUserData != null){
// get current followings
final List<String> currentFollowing = List<String>.from(currentUserData['following'] ?? []);
// check if the user is already following the target user.
if(currentFollowing.contains(targetUid)) {
// unfollow
// remove from current user
await firebaseFirestore.collection('users').doc(currentUid).update({
'following':FieldValue.arrayRemove([targetUid]),
});
// remove from target user
await firebaseFirestore.collection('users').doc(targetUid).update({
'followers':FieldValue.arrayRemove([currentUid]),
});
} else {
// follow
// add to current user
await firebaseFirestore.collection('users').doc(currentUid).update({
'following':FieldValue.arrayUnion([targetUid]),
});
// remove from target user
await firebaseFirestore.collection('users').doc(targetUid).update({
'followers':FieldValue.arrayUnion([currentUid]),
});
}
}
}
} catch(e) {
}
}
🔹 Now, update ProfileCubit
to call this method:
Future<void> toggleFollow(String currentUid, String targetUid) async {
try {
await profileRepo.toggleFollow(currentUid, targetUid);
await fetchUserProfile(targetUid);
}
catch(e) {
emit(CProfileErrorState("Error : $e"));
}
}
STEP 5: Implement Follow/Unfollow in the UI
Create a CFollowButton
component that takes:
✔️ onPressed
callback
✔️ isFollowing
boolean
Now, display it in the profile page (only if the user isn’t viewing their own profile):
if (widget.uid != widget.currentUserId)
CFollowButton(
onPressed: followButtonPress,
isFollowing: usr.followers.contains(widget.currentUserId),
),
Make the Follow Button Functional
Add a method in the profile page to toggle follow/unfollow:
void followButtonPress() {
final profileState = profileCubit.state;
if (profileState is! CProfileLoadedState) return; // Couldn't load profile
final profileUser = profileState.profileUser;
final isFollowing = profileUser.followers.contains(widget.currentUserId);
// Optimistically update UI
setState(() {
if (isFollowing) {
profileUser.followers.remove(widget.currentUserId);
} else {
profileUser.followers.add(widget.currentUserId);
}
});
// Perform follow/unfollow in Firebase
profileCubit.toggleFollow(widget.currentUserId, widget.uid).catchError((error) {
// Revert UI if error occurs
setState(() {
if (isFollowing) {
profileUser.followers.add(widget.currentUserId);
} else {
profileUser.followers.remove(widget.currentUserId);
}
});
});
}
Now, call followButtonPress
inside the CFollowButton
component in both desktop and mobile layouts.
You can also show the followers and following stats dynamically after this.
And yes don’t forget to add empty followers and following lists to all the users in your database. And a private boolean in all the posts too.
Conclusion
With today’s update, profiles in Connect are now interactive and dynamic. Users can now visit profiles, follow/unfollow, and engage more deeply.
Tomorrow, we’ll take it a step further by:
📌 Creating a Followers/Following list
📌 Adding a search user feature
📌 Prepping for UI improvements & deployment checks and a few more features we have planned on the way.
We’re just a few steps away from launching Connect—can’t wait to see it live! Do you have any more suggestions??
Let me know! 🚀💬