From 5ee0b5d4b0ce125c908ef938772014dbbb1e883b Mon Sep 17 00:00:00 2001 From: horizonvert1027 Date: Sun, 3 May 2020 19:15:19 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=97=83Update=20notification=20,=20followi?= =?UTF-8?q?ng=20and=20followers=20db=20schema.=201.=F0=9F=97=83Change=20in?= =?UTF-8?q?=20db=20schema.=202.:children=5Fcrossing:=20Last=20notificaiton?= =?UTF-8?q?=20on=20top=20implementation.=20https://github.com/TheAlphamerc?= =?UTF-8?q?/flutter=5Ftwitter=5Fclone/issues/26?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/helper/enum.dart | 3 +- lib/model/feedModel.dart | 195 ++++++++----------- lib/model/notificationModel.dart | 6 +- lib/model/user.dart | 2 +- lib/page/notification/notificationPage.dart | 6 +- lib/state/authState.dart | 7 +- lib/state/feedState.dart | 70 +++---- lib/state/notificationState.dart | 9 +- lib/widgets/tweet/widgets/tweetIconsRow.dart | 32 +-- 9 files changed, 148 insertions(+), 182 deletions(-) diff --git a/lib/helper/enum.dart b/lib/helper/enum.dart index cf464cd..603e0bf 100644 --- a/lib/helper/enum.dart +++ b/lib/helper/enum.dart @@ -25,5 +25,6 @@ enum NotificationType{ Reply, Retweet, Follow, - Mention + Mention, + Like } \ No newline at end of file diff --git a/lib/model/feedModel.dart b/lib/model/feedModel.dart index fc657ff..7b9872e 100644 --- a/lib/model/feedModel.dart +++ b/lib/model/feedModel.dart @@ -1,4 +1,3 @@ - import 'package:flutter_twitter_clone/model/user.dart'; class FeedModel { @@ -8,7 +7,7 @@ class FeedModel { String description; String userId; int likeCount; - List likeList; + List likeList; int commentCount; int retweetCount; String createdAt; @@ -16,132 +15,96 @@ class FeedModel { List tags; List replyTweetKeyList; User user; - FeedModel({ - this.key, - this.description, - this.userId, - this.likeCount, - this.commentCount, - this.retweetCount, - this.createdAt, - this.imagePath, - this.likeList, - this.tags, - this.user, - this.replyTweetKeyList, - this.parentkey, - this.childRetwetkey - }); + FeedModel( + {this.key, + this.description, + this.userId, + this.likeCount, + this.commentCount, + this.retweetCount, + this.createdAt, + this.imagePath, + this.likeList, + this.tags, + this.user, + this.replyTweetKeyList, + this.parentkey, + this.childRetwetkey}); toJson() { - Map map; - if(likeList != null && likeList.length > 0){ - map = Map.fromIterable(likeList, key: (v) =>v.key, value: (v){ - var list = LikeList(key: v.key, userId: v.userId); - return list.toJson(); - }); - } return { "userId": userId, "description": description, - "likeCount":likeCount, - "commentCount":commentCount ?? 0, + "likeCount": likeCount, + "commentCount": commentCount ?? 0, "retweetCount": retweetCount ?? 0, - "createdAt":createdAt, - "imagePath":imagePath, - "likeList":map, - "tags":tags, - "replyTweetKeyList":replyTweetKeyList, - "user":user == null ? null : user.toJson(), + "createdAt": createdAt, + "imagePath": imagePath, + "likeList": likeList, + "tags": tags, + "replyTweetKeyList": replyTweetKeyList, + "user": user == null ? null : user.toJson(), "parentkey": parentkey, - "childRetwetkey":childRetwetkey + "childRetwetkey": childRetwetkey }; } - dynamic getLikeList(List list){ - if(list != null && list.length > 0){ - var result = Map.fromIterable(list, key: (v) =>'userId', value: (v) => v[0]); - return result; - } - } + FeedModel.fromJson(Map map) { - if(likeList == null){ + key = map['key']; + description = map['description']; + userId = map['userId']; + // name = map['name']; + // profilePic = map['profilePic']; + likeCount = map['likeCount']; + commentCount = map['commentCount']; + retweetCount = map["retweetCount"] ?? 0; + imagePath = map['imagePath']; + createdAt = map['createdAt']; + imagePath = map['imagePath']; + // username = map['username']; + user = User.fromJson(map['user']); + parentkey = map['parentkey']; + childRetwetkey = map['childRetwetkey']; + if (map['tags'] != null) { + tags = List(); + map['tags'].forEach((value) { + tags.add(value); + }); + } + if (map["likeList"] != null) { + likeList = List(); + map['likeList'].forEach((value) { + likeList.add(value); + }); + likeCount = likeList.length; + } else { likeList = []; + likeCount = 0; + } + if (map['replyTweetKeyList'] != null) { + map['replyTweetKeyList'].forEach((value) { + replyTweetKeyList = List(); + map['replyTweetKeyList'].forEach((value) { + replyTweetKeyList.add(value); + }); + }); + commentCount = replyTweetKeyList.length; + } else { + replyTweetKeyList = []; + commentCount = 0; } - key = map['key']; - description = map['description']; - userId = map['userId']; - // name = map['name']; - // profilePic = map['profilePic']; - likeCount = map['likeCount']; - commentCount = map['commentCount']; - retweetCount = map["retweetCount"] ?? 0; - imagePath = map['imagePath']; - createdAt = map['createdAt']; - imagePath = map['imagePath']; - // username = map['username']; - user = User.fromJson(map['user']); - parentkey = map['parentkey']; - childRetwetkey = map['childRetwetkey']; - if(map['tags'] != null){ - tags = List(); - map['tags'].forEach((value){ - tags.add(value); - }); - } - if(map['likeList'] != null){ - map['likeList'].forEach((key,value){ - if(value.containsKey('userId')){ - LikeList list = LikeList(key:key,userId: value['userId']); - likeList.add(list); - } - }); - likeCount = likeList.length; - } - else{ - likeList = []; - likeCount = 0; - } - if(map['replyTweetKeyList'] != null){ - map['replyTweetKeyList'].forEach((value){ - replyTweetKeyList = List(); - map['replyTweetKeyList'].forEach((value){ - replyTweetKeyList.add(value); - }); - }); - commentCount = replyTweetKeyList.length; - } - else{ - replyTweetKeyList = []; - commentCount = 0; - } } - bool get isValidTweet { - bool isValid =false; - if(description != null - && description.isNotEmpty - && this.user != null - && this.user.userName != null - && this.user.userName.isNotEmpty - ){ - isValid = true; - } - else{ - print("Invalid Tweet found. Id:- $key"); - } - return isValid; - } -} -class LikeList{ - String key; - String userId; - LikeList({this.key,this.userId}); - LikeList.fromJson(Map map,{String key}) { - key = key; - userId = map['userId']; - } - toJson(){ - return { - 'userId':userId - }; + bool get isValidTweet { + bool isValid = false; + if (description != null && + description.isNotEmpty && + this.user != null && + this.user.userName != null && + this.user.userName.isNotEmpty) { + isValid = true; + } else { + print("Invalid Tweet found. Id:- $key"); + } + return isValid; } } \ No newline at end of file diff --git a/lib/model/notificationModel.dart b/lib/model/notificationModel.dart index 2c75335..cb913c8 100644 --- a/lib/model/notificationModel.dart +++ b/lib/model/notificationModel.dart @@ -1,12 +1,16 @@ class NotificationModel { String tweetKey; + String updatedAt; + String type; NotificationModel({ this.tweetKey, }); - NotificationModel.fromJson(String tweetId) { + NotificationModel.fromJson(String tweetId, String updatedAt,String type) { tweetKey = tweetId; + this.updatedAt = updatedAt; + this.type = type; } Map toJson() => { diff --git a/lib/model/user.dart b/lib/model/user.dart index c9a1180..5f02f0a 100644 --- a/lib/model/user.dart +++ b/lib/model/user.dart @@ -90,7 +90,7 @@ class User { 'location': location, 'createdAt': createdAt, 'followers': followersList != null ? followersList.length : null, - 'following': followersList!= null ? followersList.length : null, + 'following': followingList!= null ? followingList.length : null, 'userName': userName, 'webSite': webSite, 'isVerified': isVerified ?? false, diff --git a/lib/page/notification/notificationPage.dart b/lib/page/notification/notificationPage.dart index 0384bb3..571f9d6 100644 --- a/lib/page/notification/notificationPage.dart +++ b/lib/page/notification/notificationPage.dart @@ -113,7 +113,7 @@ class NotificationPageBody extends StatelessWidget { class NotificationTile extends StatelessWidget { final FeedModel model; const NotificationTile({Key key, this.model}) : super(key: key); - Widget _userList(BuildContext context, List list) { + Widget _userList(BuildContext context, List list) { // List names = []; var length = list.length; List avaterList = []; @@ -122,8 +122,8 @@ class NotificationTile extends StatelessWidget { if (list != null && list.length > 5) { list = list.take(5).toList(); } - avaterList = list.map((x) { - return _userAvater(x.userId, state, (name) { + avaterList = list.map((userId) { + return _userAvater(userId, state, (name) { // names.add(name); }); }).toList(); diff --git a/lib/state/authState.dart b/lib/state/authState.dart index 6873c35..cc9ca41 100644 --- a/lib/state/authState.dart +++ b/lib/state/authState.dart @@ -436,15 +436,16 @@ class AuthState extends AppState { profileUserModel.followers = profileUserModel.followersList.length; // update logged-in user's following count userModel.following = userModel.followingList.length; - kDatabase .child('profile') .child(profileUserModel.userId) - .set(profileUserModel.toJson()); + .child('followerList') + .set(profileUserModel.followersList); kDatabase .child('profile') .child(userModel.userId) - .set(userModel.toJson()); + .child('followingList') + .set(userModel.followingList); cprint('user added to following list', event: 'add_follow'); notifyListeners(); } catch (error) { diff --git a/lib/state/feedState.dart b/lib/state/feedState.dart index ba220a6..185c5ba 100644 --- a/lib/state/feedState.dart +++ b/lib/state/feedState.dart @@ -123,7 +123,7 @@ class FeedState extends AppState { if (_feedQuery == null) { _feedQuery = kDatabase.child("tweet"); _feedQuery.onChildAdded.listen(_onTweetAdded); - _feedQuery.onChildChanged.listen(_onTweetChanged); + _feedQuery.onValue.listen(_onTweetChanged); _feedQuery.onChildRemoved.listen(_onTweetRemoved); } @@ -173,7 +173,7 @@ class FeedState extends AppState { /// get [Tweet Detail] from firebase realtime kDatabase /// If model is null then fetch tweet from firebase /// [getpostDetailFromDatabase] is used to set prepare Tweetr to display Tweet detail - /// After getting tweet detail fetch tweet coments from firebase + /// After getting tweet detail fetch tweet coments from firebase void getpostDetailFromDatabase(String postID, {FeedModel model}) async { try { FeedModel _tweetDetail; @@ -249,15 +249,16 @@ class FeedState extends AppState { /// Retweet itself is a type of `Tweet` Future fetchTweet(String postID) async { FeedModel _tweetDetail; + /// If tweet is availabe in feedlist then no need to fetch it from firebase if (feedlist.any((x) => x.key == postID)) { _tweetDetail = feedlist.firstWhere((x) => x.key == postID); - } + } + /// If tweet is not available in feedlist then need to fetch it from firebase else { cprint("Fetched from DB: " + postID); - var model = - await kDatabase.child('tweet').child(postID).once().then( + var model = await kDatabase.child('tweet').child(postID).once().then( (DataSnapshot snapshot) { if (snapshot.value != null) { var map = snapshot.value; @@ -268,10 +269,8 @@ class FeedState extends AppState { }, ); if (model != null) { - _tweetDetail = model; - } - else{ + } else { cprint("Fetched null value from DB"); } } @@ -384,40 +383,35 @@ class FeedState extends AppState { try { if (tweet.likeList != null && tweet.likeList.length > 0 && - tweet.likeList.any((x) => x.userId == userId)) { - tweet.likeList.removeWhere( - (x) => x.userId == userId, - ); - // If user unlike Tweet + tweet.likeList.any((id) => id == userId)) { + // If user wants to undo/remove his like on tweet + tweet.likeList.removeWhere((id) => id == userId); tweet.likeCount -= 1; - updateTweet(tweet); - kDatabase - .child('notification') - .child(tweet.userId) - .child( - tweet.key, - ) - .child('likeList') - .child(userId) - .remove(); } else { // If user like Tweet - kDatabase - .child('tweet') - .child(tweet.key) - .child('likeList') - .child(userId) - .set({'userId': userId}); - kDatabase - .child('notification') - .child(tweet.userId) - .child( - tweet.key, - ) - .child('likeList') - .child(userId) - .set({'userId': userId}); + if (tweet.likeList == null) { + tweet.likeList = []; + } + tweet.likeList.add(userId); + tweet.likeCount += 1; } + // update likelist of a tweet + kDatabase + .child('tweet') + .child(tweet.key) + .child('likeList') + .set(tweet.likeList); + + // Sends notification to user who created tweet + // User owner can see notification on notification page + kDatabase.child('notification').child(tweet.userId).child(tweet.key).set({ + 'type': tweet.likeList.length == 0 + ? null + : NotificationType.Like.toString(), + 'updatedAt': tweet.likeList.length == 0 + ? null + : DateTime.now().toUtc().toString(), + }); } catch (error) { cprint(error, errorIn: 'addLikeToTweet'); } diff --git a/lib/state/notificationState.dart b/lib/state/notificationState.dart index 97bfeae..d2ae7aa 100644 --- a/lib/state/notificationState.dart +++ b/lib/state/notificationState.dart @@ -60,9 +60,10 @@ class NotificationState extends AppState { var map = snapshot.value; if (map != null) { map.forEach((tweetKey, value) { - var model = NotificationModel.fromJson(tweetKey); + var model = NotificationModel.fromJson(tweetKey,value["updatedAt"],snapshot.value["type"]); _notificationList.add(model); }); + _notificationList.sort((x,y)=> DateTime.parse(y.updatedAt).compareTo(DateTime.parse(x.updatedAt))); } } loading = false; @@ -115,7 +116,7 @@ class NotificationState extends AppState { /// Trigger when somneone like your tweet void _onNotificationAdded(Event event) { if (event.snapshot.value != null) { - var model = NotificationModel.fromJson(event.snapshot.key); + var model = NotificationModel.fromJson(event.snapshot.key, event.snapshot.value["updatedAt"],event.snapshot.value["type"]); if (_notificationList == null) { _notificationList = List(); } @@ -129,7 +130,7 @@ class NotificationState extends AppState { /// Trigger when someone changed his like preference void _onNotificationChanged(Event event) { if (event.snapshot.value != null) { - var model = NotificationModel.fromJson(event.snapshot.key); + var model = NotificationModel.fromJson(event.snapshot.key, event.snapshot.value["updatedAt"],event.snapshot.value["type"]); //update notification list _notificationList .firstWhere((x) => x.tweetKey == model.tweetKey) @@ -142,7 +143,7 @@ class NotificationState extends AppState { /// Trigger when someone undo his like on tweet void _onNotificationRemoved(Event event) { if (event.snapshot.value != null) { - var model = NotificationModel.fromJson(event.snapshot.key); + var model = NotificationModel.fromJson(event.snapshot.key, event.snapshot.value["updatedAt"],event.snapshot.value["type"]); // remove notification from list _notificationList.removeWhere((x) => x.tweetKey == model.tweetKey); notifyListeners(); diff --git a/lib/widgets/tweet/widgets/tweetIconsRow.dart b/lib/widgets/tweet/widgets/tweetIconsRow.dart index fe736d3..498c7e1 100644 --- a/lib/widgets/tweet/widgets/tweetIconsRow.dart +++ b/lib/widgets/tweet/widgets/tweetIconsRow.dart @@ -59,17 +59,21 @@ class TweetIconsRow extends StatelessWidget { size: size ?? 20, onPressed: () { TweetBottomSheet().openRetweetbottomSheet(context, type, model); }), - _iconWidget(context, - text: isTweetDetail ? '' : model.likeCount.toString(), - icon: model.likeList.any((x) => x.userId == authState.userId) - ? AppIcon.heartFill - : AppIcon.heartEmpty, onPressed: () { - addLikeToTweet(context); - }, - iconColor: model.likeList.any((x) => x.userId == authState.userId) - ? iconEnableColor - : iconColor, - size: size ?? 20), + _iconWidget( + context, + text: isTweetDetail ? '' : model.likeCount.toString(), + icon: model.likeList.any((userId) => userId == authState.userId) + ? AppIcon.heartFill + : AppIcon.heartEmpty, + onPressed: () { + addLikeToTweet(context); + }, + iconColor: + model.likeList.any((userId) => userId == authState.userId) + ? iconEnableColor + : iconColor, + size: size ?? 20, + ), _iconWidget(context, text: '', icon: null, sysIcon: Icons.share, onPressed: () { share('${model.description}', @@ -123,9 +127,7 @@ class TweetIconsRow extends StatelessWidget { Widget _timeWidget(BuildContext context) { return Column( children: [ - SizedBox( - height: 8 - ), + SizedBox(height: 8), Row( children: [ SizedBox(width: 5), @@ -226,7 +228,7 @@ class TweetIconsRow extends StatelessWidget { CustomRoute( builder: (BuildContext context) => UsersListPage( pageTitle: "Liked by", - userIdsList: model.likeList.map((x) => x.userId).toList(), + userIdsList: model.likeList.map((userId) => userId).toList(), ), ), );