Skip to content

Commit 331d0a3

Browse files
committed
✨ Follow/Un-follow user from follower/following users list
1 parent b8445b9 commit 331d0a3

19 files changed

+314
-85
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* Added link preview in tweet.
1515
* Bug fixed and performance improvements.
1616
* Display suggested users list to follow
17+
* Follow/Un-follow user from follower/following users list
1718
## [1.0.6] - 17 Jul 2020
1819

1920
* In user profile page three tabs are added to filter tweet and comment tweet and tweet with media.

lib/helper/routes.dart

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import 'package:flutter_twitter_clone/ui/page/homePage.dart';
1010
import 'package:flutter_twitter_clone/ui/page/message/conversationInformation/conversationInformation.dart';
1111
import 'package:flutter_twitter_clone/ui/page/message/newMessagePage.dart';
1212
import 'package:flutter_twitter_clone/ui/page/profile/follow/followerListPage.dart';
13-
import 'package:flutter_twitter_clone/ui/page/profile/follow/followingListPage.dart';
1413
import 'package:flutter_twitter_clone/ui/page/search/SearchPage.dart';
1514
import 'package:flutter_twitter_clone/ui/page/settings/accountSettings/about/aboutTwitter.dart';
1615
import 'package:flutter_twitter_clone/ui/page/settings/accountSettings/accessibility/accessibility.dart';
@@ -172,10 +171,6 @@ class Routes {
172171
return CustomRoute<bool>(
173172
builder: (BuildContext context) => const ConversationInformation(),
174173
);
175-
case "FollowingListPage":
176-
return CustomRoute<bool>(
177-
builder: (BuildContext context) => const FollowingListPage(),
178-
);
179174
case "FollowerListPage":
180175
return CustomRoute<bool>(
181176
builder: (BuildContext context) => FollowerListPage(),

lib/main.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:firebase_core/firebase_core.dart';
22
import 'package:flutter/material.dart';
3-
import 'package:flutter_twitter_clone/state/chats/suggestionUserState.dart';
3+
import 'package:flutter_twitter_clone/state/suggestionUserState.dart';
44
import 'package:google_fonts/google_fonts.dart';
55
import 'package:provider/provider.dart';
66

lib/model/notificationModel.dart

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ class NotificationModel {
1010
late String type;
1111
Map<String, dynamic>? data;
1212

13-
NotificationModel(
14-
{this.id,
15-
this.tweetKey,
16-
required this.type,
17-
required this.createdAt,
18-
this.updatedAt,
19-
required this.data});
13+
NotificationModel({
14+
this.id,
15+
this.tweetKey,
16+
required this.type,
17+
required this.createdAt,
18+
this.updatedAt,
19+
required this.data,
20+
});
2021

2122
NotificationModel.fromJson(String tweetId, Map<dynamic, dynamic> map) {
2223
id = tweetId;

lib/model/user.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class UserModel extends Equatable {
111111
String? profilePic,
112112
String? key,
113113
String? contact,
114-
bio,
114+
String? bio,
115115
String? dob,
116116
String? bannerImage,
117117
String? location,
@@ -132,7 +132,7 @@ class UserModel extends Equatable {
132132
createdAt: createdAt ?? this.createdAt,
133133
displayName: displayName ?? this.displayName,
134134
dob: dob ?? this.dob,
135-
followers: followersList?.length,
135+
followers: followers ?? this.followers,
136136
following: following ?? this.following,
137137
isVerified: isVerified ?? this.isVerified,
138138
key: key ?? this.key,

lib/state/authState.dart

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class AuthState extends AppState {
6565
if (_profileQuery == null) {
6666
_profileQuery = kDatabase.child("profile").child(user!.uid);
6767
_profileQuery!.onValue.listen(_onProfileChanged);
68+
_profileQuery!.onChildChanged.listen(_onProfileupdated);
6869
}
6970
} catch (error) {
7071
cprint(error, errorIn: 'databaseInit');
@@ -423,12 +424,35 @@ class AuthState extends AppState {
423424
/// Trigger when logged-in user's profile change or updated
424425
/// Firebase event callback for profile update
425426
void _onProfileChanged(DatabaseEvent event) {
426-
// if (event.snapshot != null) {
427427
final val = event.snapshot.value;
428-
final updatedUser = UserModel.fromJson(val as Map);
429-
_userModel = updatedUser;
430-
cprint('UserModel Updated');
431-
notifyListeners();
432-
// }
428+
if (val is Map) {
429+
final updatedUser = UserModel.fromJson(val);
430+
_userModel = updatedUser;
431+
cprint('UserModel Updated');
432+
getIt<SharedPreferenceHelper>().saveUserProfile(_userModel!);
433+
notifyListeners();
434+
}
435+
}
436+
437+
void _onProfileupdated(DatabaseEvent event) {
438+
final val = event.snapshot.value;
439+
if (val is List &&
440+
['following', 'followers'].contains(event.snapshot.key)) {
441+
final list = val.cast<String>().map((e) => e).toList();
442+
if (event.previousChildKey == 'following') {
443+
_userModel = _userModel!.copyWith(
444+
followingList: val.cast<String>().map((e) => e).toList(),
445+
following: list.length,
446+
);
447+
} else if (event.previousChildKey == 'followers') {
448+
_userModel = _userModel!.copyWith(
449+
followersList: list,
450+
followers: list.length,
451+
);
452+
}
453+
getIt<SharedPreferenceHelper>().saveUserProfile(_userModel!);
454+
cprint('UserModel Updated');
455+
notifyListeners();
456+
}
433457
}
434458
}

lib/state/notificationState.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class NotificationState extends AppState {
2929
_notificationList ??= <NotificationModel>[];
3030

3131
if (!_notificationList!.any((element) => element.id == model.id)) {
32-
_notificationList!.add(model);
32+
_notificationList!.insert(0, model);
3333
}
3434
}
3535

@@ -77,7 +77,7 @@ class NotificationState extends AppState {
7777
addNotificationList(model);
7878
});
7979
_notificationList!
80-
.sort((x, y) => y.timeStamp!.compareTo(x.timeStamp!));
80+
.sort((x, y) => x.timeStamp!.compareTo(y.timeStamp!));
8181
}
8282
}
8383
isBusy = false;

lib/state/chats/suggestionUserState.dart renamed to lib/state/suggestionUserState.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class SuggestionsState extends AppState {
9393
user.followersList ??= [];
9494
user.followersList!.add(currentUser!.userId!);
9595
user.followers = user.followersList!.length;
96-
kDatabase
96+
await kDatabase
9797
.child('profile')
9898
.child(user.userId!)
9999
.child('followerList')
@@ -107,12 +107,14 @@ class SuggestionsState extends AppState {
107107
currentUser!.followingList!
108108
.addAll(_selectedusers.map((e) => e.userId!));
109109
currentUser!.following = currentUser!.followingList!.length;
110-
kDatabase
110+
await kDatabase
111111
.child('profile')
112112
.child(currentUser!.userId!)
113113
.child('followingList')
114114
.set(currentUser!.followingList);
115115

116+
// await getIt<SharedPreferenceHelper>().saveUserProfile(currentUser!);
117+
116118
displaySuggestions = false;
117119
}
118120
} catch (error) {

lib/ui/page/common/sidebar.dart

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter_twitter_clone/helper/constant.dart';
33
import 'package:flutter_twitter_clone/state/authState.dart';
44
import 'package:flutter_twitter_clone/ui/page/bookmark/bookmarkPage.dart';
55
import 'package:flutter_twitter_clone/ui/page/profile/follow/followerListPage.dart';
6+
import 'package:flutter_twitter_clone/ui/page/profile/follow/followingListPage.dart';
67
import 'package:flutter_twitter_clone/ui/page/profile/profilePage.dart';
78
import 'package:flutter_twitter_clone/ui/page/profile/qrCode/scanner.dart';
89
import 'package:flutter_twitter_clone/ui/page/profile/widgets/circular_image.dart';
@@ -126,15 +127,25 @@ class _SidebarMenuState extends State<SidebarMenu> {
126127
switch (navigateTo) {
127128
case "FollowerListPage":
128129
usersList = authstate.userModel!.followersList!;
130+
Navigator.push(
131+
context,
132+
FollowerListPage.getRoute(
133+
profile: authstate.userModel!,
134+
userList: usersList,
135+
),
136+
);
129137
break;
130138
case "FollowingListPage":
131139
usersList = authstate.userModel!.followingList!;
140+
Navigator.push(
141+
context,
142+
FollowingListPage.getRoute(
143+
profile: authstate.userModel!,
144+
userList: usersList,
145+
),
146+
);
132147
break;
133148
}
134-
Navigator.push(
135-
context,
136-
FollowerListPage.getRoute(
137-
profile: authstate.userModel!, userList: usersList));
138149
},
139150
child: Row(
140151
children: <Widget>[

lib/ui/page/common/usersListPage.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@ class UsersListPage extends StatelessWidget {
1616
required this.emptyScreenText,
1717
required this.emptyScreenSubTileText,
1818
this.userIdsList,
19+
this.onFollowPressed,
20+
this.isFollowing,
1921
}) : super(key: key);
2022

2123
final String pageTitle;
2224
final String emptyScreenText;
2325
final String emptyScreenSubTileText;
24-
// final IconData appBarIcon;
26+
final bool Function(UserModel user)? isFollowing;
2527
final List<String>? userIdsList;
28+
final Function(UserModel user)? onFollowPressed;
2629

2730
@override
2831
Widget build(BuildContext context) {
@@ -45,6 +48,8 @@ class UsersListPage extends StatelessWidget {
4548
list: userList!,
4649
emptyScreenText: emptyScreenText,
4750
emptyScreenSubTileText: emptyScreenSubTileText,
51+
onFollowPressed: onFollowPressed,
52+
isFollowing: isFollowing,
4853
)
4954
: Container(
5055
width: context.width,

lib/ui/page/common/widget/userListWidget.dart

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,35 @@ import 'package:provider/provider.dart';
1111

1212
class UserListWidget extends StatelessWidget {
1313
final List<UserModel> list;
14+
1415
final String? emptyScreenText;
1516
final String? emptyScreenSubTileText;
17+
final Function(UserModel user)? onFollowPressed;
18+
final bool Function(UserModel user)? isFollowing;
1619
const UserListWidget({
1720
Key? key,
1821
required this.list,
1922
this.emptyScreenText,
2023
this.emptyScreenSubTileText,
24+
this.onFollowPressed,
25+
this.isFollowing,
2126
}) : super(key: key);
2227

2328
@override
2429
Widget build(BuildContext context) {
2530
var state = Provider.of<AuthState>(context, listen: false);
26-
String myId = state.userModel!.key!;
31+
final currentUser = state.userModel!;
2732
return ListView.separated(
2833
itemBuilder: (context, index) {
2934
return UserTile(
3035
user: list[index],
31-
myId: myId,
32-
onTrailingPressed: () {},
36+
currentUser: currentUser,
37+
isFollowing: isFollowing,
38+
onTrailingPressed: () {
39+
if (onFollowPressed != null) {
40+
onFollowPressed!(list[index]);
41+
}
42+
},
3343
);
3444
},
3545
separatorBuilder: (context, index) {
@@ -44,17 +54,21 @@ class UserListWidget extends StatelessWidget {
4454
}
4555

4656
class UserTile extends StatelessWidget {
47-
const UserTile(
48-
{Key? key,
49-
required this.user,
50-
required this.myId,
51-
required this.onTrailingPressed,
52-
this.trailing})
53-
: super(key: key);
57+
const UserTile({
58+
Key? key,
59+
required this.user,
60+
required this.currentUser,
61+
required this.onTrailingPressed,
62+
this.trailing,
63+
this.isFollowing,
64+
}) : super(key: key);
5465
final UserModel user;
55-
final String myId;
66+
67+
/// User profile of logged-in user
68+
final UserModel currentUser;
5669
final VoidCallback onTrailingPressed;
5770
final Widget? trailing;
71+
final bool Function(UserModel user)? isFollowing;
5872

5973
/// Return empty string for default bio
6074
/// Max length of bio is 100
@@ -72,9 +86,12 @@ class UserTile extends StatelessWidget {
7286

7387
/// Check if user followerlist contain your or not
7488
/// If your id exist in follower list it mean you are following him
75-
bool isFollowing() {
76-
if (user.followersList != null &&
77-
user.followersList!.any((x) => x == myId)) {
89+
bool checkIfFollowing() {
90+
if (isFollowing != null) {
91+
return isFollowing!(user);
92+
}
93+
if (currentUser.followingList != null &&
94+
currentUser.followingList!.any((x) => x == user.userId)) {
7895
return true;
7996
} else {
8097
return false;
@@ -83,7 +100,7 @@ class UserTile extends StatelessWidget {
83100

84101
@override
85102
Widget build(BuildContext context) {
86-
bool isFollow = isFollowing();
103+
bool isFollow = checkIfFollowing();
87104
return Container(
88105
padding: const EdgeInsets.symmetric(vertical: 10),
89106
color: TwitterColor.white,

lib/ui/page/feed/suggestedUsers.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_twitter_clone/state/authState.dart';
3-
import 'package:flutter_twitter_clone/state/chats/suggestionUserState.dart';
3+
import 'package:flutter_twitter_clone/state/suggestionUserState.dart';
44
import 'package:flutter_twitter_clone/state/searchState.dart';
55
import 'package:flutter_twitter_clone/ui/page/common/widget/userListWidget.dart';
66
import 'package:flutter_twitter_clone/ui/theme/theme.dart';
@@ -197,7 +197,7 @@ class _SuggestedUsersState extends State<SuggestedUsers> {
197197
}
198198
return UserTile(
199199
user: user,
200-
myId: authstate.userId,
200+
currentUser: authstate.userModel!,
201201
onTrailingPressed: () {
202202
state.toggleUserSelection(user);
203203
},

lib/ui/page/homePage.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import 'package:flutter_twitter_clone/resource/push_notification_service.dart';
1010
import 'package:flutter_twitter_clone/state/appState.dart';
1111
import 'package:flutter_twitter_clone/state/authState.dart';
1212
import 'package:flutter_twitter_clone/state/chats/chatState.dart';
13-
import 'package:flutter_twitter_clone/state/chats/suggestionUserState.dart';
13+
import 'package:flutter_twitter_clone/state/suggestionUserState.dart';
1414
import 'package:flutter_twitter_clone/state/feedState.dart';
1515
import 'package:flutter_twitter_clone/state/notificationState.dart';
1616
import 'package:flutter_twitter_clone/state/searchState.dart';

0 commit comments

Comments
 (0)