-
Flutter - 코딩마스터하기|파이어스토어를 통한 팔로/언팔로개발/Flutter 2021. 11. 17. 21:31반응형
fetch all users except me
팔로우한 유저의 포스트를 봐야한다. 그래서 나를 제외한 유저를 불러오는 메소드를 만들 것이다. 일단 user_network_repository.dart에서 Stream으로 Firestore.instance를 통해 받아오는 코드를 만들어 준다. Stream<List<UserModel>> getAllUsersWithoutMe(){ return Firestore.instance.collection(COLLECTION_USERS).snapshots().transform(toUsersExceptMe); } 이렇게 collection을 정해주고 snapshots를 하면 해당 콜렉션의 모든것을 다 불러온다. 거기서 toUsersExceptMe를 Transformers에 만들어 준다. 기존 toUser를 복사해서 만들어 주고 기존 내용을 삭제하고 우선 user 리시트를 저장할 부분을 만들어 준다. List<UserModel> users = [];로 해준다. 그리고 내 현재 아이디를 가져오기 위해 FirebaseAuth.instance.currentUser();도 만들어 준다. 그리고 snapshot.documnets.forEach를 이용하요 documentSnapshot 의 내용들을 저장해주면 된다. 그리고 피드에 상단버튼에 userNetworkRepository.getAllUsersWithoutMe().listen((users) { print(users); }); 를 추가해서 debug 해주면 정상적으로 나오는 것을 알 수 있다.
transformers.dart final toUsersExceptMe = StreamTransformer<QuerySnapshot, List<UserModel>>.fromHandlers( handleData: (snapshot, sink) async { List<UserModel> users = []; FirebaseUser _firebaseUser = await FirebaseAuth.instance.currentUser(); snapshot.documents.forEach((documentSnapshot) { if(_firebaseUser.uid != documentSnapshot.documentID) { users.add(UserModel.fromSnapshot(documentSnapshot)); } }); sink.add(users); });
user_network_repository.dart Stream<List<UserModel>> getAllUsersWithoutMe(){ return Firestore.instance.collection(COLLECTION_USERS).snapshots().transform(toUsersExceptMe); }
show all the users exept me
확인하기 위한 버튼 부분으 getAllUsersWithoutMe() 부분은 삭제해준다. 그리고 search_screen에서 SafeArea에서 StreamBuilder로 감싸준다. <>안에는 List<UserModel>로 바꿔주고 stream에 userNetworkRepository.getAllUsersWithoutMe()로 해준다. 그리고고 return 부분을 if(snapshot.hasData)로{} 안에 넣어줘서 데이터가 있을때만 나오게 해주고, else 부분에 return MyProgressIndicator로 로딩바가 나오게 해준다. 기존 followings 와 같이 사용하던 부분을 모두 삭제해준다. 그리고 ListView에서 return 위에 UserMode userModel = snapshot.data[index]로 각 인덱스에 snapahot을 불러와서 유저정보를 저장해준다. ListTile의 title인 이름이 나오는 부분을 userModel.username을 해주면 된다. 또 하단에 itemCount에 snapshot.data.length로 해당 인원수만큼 보이게 해주면 된다. 실행해보면 정상적으로 나오는 것을 알 수 있다.
class _SearchScreenState extends State<SearchScreen> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Follow/Unfollow"), ), body: StreamBuilder<List<UserModel>>( stream: userNetworkRepository.getAllUsersWithoutMe(), builder: (context, snapshot) { if(snapshot.hasData){ return SafeArea( child: ListView.separated( itemBuilder: (context, index) { UserModel userModel = snapshot.data[index]; return ListTile( onTap: () { setState(() { // followings[index] = !followings[index]; }); }, leading: RoundedAvatar( index: index, ), title: Text(userModel.username), subtitle: Text('this is user bio of ${userModel.username}'), trailing: Container( height: 30, width: 80, alignment: Alignment.center, decoration: BoxDecoration( color: Colors.red[50], border: Border.all( color: Colors.red, width: 0.5, ), borderRadius: BorderRadius.circular(8), ), child: Text( 'Following' , textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.bold, ), ), ), ); }, //(context, index) separatorBuilder: (context, index) { return Divider( color: Colors.grey, ); }, //아이템 사이사이 부분 itemCount: snapshot.data.length, //아이템 갯수 ), );} else{ return MyProgressIndicator(); } } ), ); } }
그리고 페이스북 로그인 시에도 register 메소드에 있는 파이어베이스에 저장하는 부분을 넣어주고 따로 users로 하던부분을 합쳐준다.
void _handleFacebookTokenWithFirebase( BuildContext context, String token) async { final AuthCredential credential = FacebookAuthProvider.getCredential( accessToken: token, ); final AuthResult authResult = await _firebaseAuth.signInWithCredential(credential); _firebaseUser = authResult.user; if (_firebaseUser == null) { simpleSnackbar(context, '페이스북 로그인이 되지 않았습니다. 다시 시도해주시기 바랍니다.'); } else { userNetworkRepository.attemptCreateUser( userKey: _firebaseUser.uid, email: _firebaseUser.email); } notifyListeners(); }
follow-unfollow user method
팔로우와 언팔로우 메소드를 만들어 보자. user_network_repository에 만들자. Future<void> followUser() async{}로 만들어 주는데 내 유저키와 팔로우 할 사람의 유저키를 반드시 받아오게 하자. 그 뒤 내 refernce와 다른 유저의 reference를 가져오고 둘의 스냅샷도 가져온다. 그 후 post처럼 runTransaction을 해서 두개의 스냅샷이 존재할 경우의 if문을 작성하여 준다. 우선 tx.update()를 만들어 주고 myUserRef와 KEY_FOLLOWINGS: FieldValue.arrayUnion([otherUserKey])로 내 팔로잉 목록에 상대방 유저키를 넣어준다. 그리고 현재 상대방의 팔로워 수를 가져와 준다. otherSnapshot.data[KEY_FOLLOWERS]로 가져올수 있다. 그리고 tx.update로 otherUserRef와 KEY_FOLLOWERS: 에 currentFollowers+1을 해서 숫자를 1 늘려줄 수 잇다. unFollowerUser는 똑같이 복사 해준뒤 arrayUnion을 arrayRemove로, currentFollowers-1로 해주면 완성이다.
class UserNetworkRepository with Transformers { Future<void> attemptCreateUser({String userKey, String email}) async { final DocumentReference userRef = Firestore.instance .collection(COLLECTION_USERS) .document(userKey); //document 위치 DocumentSnapshot snapshot = await userRef.get(); // 해당 위치에서 데이터를 가져와 보는것 if (!snapshot.exists) { //exists는 존재하지 않는다. return await userRef.setData(UserModel.getMapForCreateUser(email)); } } Stream<UserModel> getUserModelStream(String userKey) { //get은 한번만 가져와서 안됨. snapshots는 처음에 똑같이 한번 보내고 변할때마다 보내줌. return Firestore.instance .collection(COLLECTION_USERS) .document(userKey) .snapshots() .transform(toUser); } Stream<List<UserModel>> getAllUsersWithoutMe(){ return Firestore.instance.collection(COLLECTION_USERS).snapshots().transform(toUsersExceptMe); } Future<void> followUser({String myUserKey, String otherUserKey}) async{ final DocumentReference myUserRef = Firestore.instance.collection(COLLECTION_USERS).document(myUserKey); final DocumentReference otherUserRef = Firestore.instance.collection(COLLECTION_USERS).document(otherUserKey); final DocumentSnapshot mySnapshot = await myUserRef.get(); final DocumentSnapshot otherSnapshot = await otherUserRef.get(); Firestore.instance.runTransaction((tx) async { if(mySnapshot.exists && otherSnapshot.exists){ await tx.update(myUserRef, {KEY_FOLLOWINGS: FieldValue.arrayUnion([otherUserKey])}); int currentFollowers = otherSnapshot.data[KEY_FOLLOWERS]; //현재 팔로워 수 await tx.update(otherUserRef, {KEY_FOLLOWERS: currentFollowers+1}); } }); Future<void> unFollowUser({String myUserKey, String otherUserKey}) async{ final DocumentReference myUserRef = Firestore.instance.collection(COLLECTION_USERS).document(myUserKey); final DocumentReference otherUserRef = Firestore.instance.collection(COLLECTION_USERS).document(otherUserKey); final DocumentSnapshot mySnapshot = await myUserRef.get(); final DocumentSnapshot otherSnapshot = await otherUserRef.get(); Firestore.instance.runTransaction((tx) async { if(mySnapshot.exists && otherSnapshot.exists){ await tx.update(myUserRef, {KEY_FOLLOWINGS: FieldValue.arrayRemove([otherUserKey])}); int currentFollowers = otherSnapshot.data[KEY_FOLLOWERS]; //현재 팔로워 수 await tx.update(otherUserRef, {KEY_FOLLOWERS: currentFollowers-1}); } }); } } UserNetworkRepository userNetworkRepository = UserNetworkRepository();
follow unfollow implementation
이 부분을 search_screen에서 쓰면된다. ListView 안에 UserModel을 더 명확히 알게 위해 otherUser로 변경해준다. 그리고 나의 유저키를 알기위해서 Provider보다는 consumer를 사용해보자 ListView를 Consumer<UserModelState>로 감싸주고 builder: (BuildContext context, UserModelState myUserModelState, Widget child) {}를 추가 시켜준다. 그리고 child를 없애주고 기존 ListView 부분을 모두 복사해서 return에 붙여넣어주면 된다. 그리고 해당유저를 팔로우 했는지 안했는지 알기위한 메소드를 만들어 보자. user_model_state로 가서 bool로 amIFollowingThisUser(String otherUserKey)로 만들어 준다. _userModel.followings.contains(otherUserKey)로 팔로잉 목록에 유저키가 포함됐는지 확인하면 된다. 이제 다시 search_screen으로 돌아와서 ListView안에 bool amIFollowing = myUserModelState .amIFollowingThisUser(otherUser.userKey);를 만들어 준다. 그리고 setState안에 amIFollowing ? userNetworkRepository.unFollowUser( myUserKey: myUserModelState.userModel.userKey, otherUserKey: otherUser.userKey) : userNetworkRepository.followUser( myUserKey: myUserModelState.userModel.userKey, otherUserKey: otherUser.userKey); });이렇게 넣어주면 된다. 다른 색이나 글씨 부분도 amIFollowing으로 if를 해주면 된다.
class _SearchScreenState extends State<SearchScreen> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Follow/Unfollow"), ), body: StreamBuilder<List<UserModel>>( stream: userNetworkRepository.getAllUsersWithoutMe(), builder: (context, snapshot) { if (snapshot.hasData) { return SafeArea( child: Consumer<UserModelState>( builder: (BuildContext context, UserModelState myUserModelState, Widget child) { return ListView.separated( itemBuilder: (context, index) { UserModel otherUser = snapshot.data[index]; bool amIFollowing = myUserModelState .amIFollowingThisUser(otherUser.userKey); return ListTile( onTap: () { setState(() { amIFollowing ? userNetworkRepository.unFollowUser( myUserKey: myUserModelState.userModel.userKey, otherUserKey: otherUser.userKey) : userNetworkRepository.followUser( myUserKey: myUserModelState.userModel.userKey, otherUserKey: otherUser.userKey); }); }, leading: RoundedAvatar( index: index, ), title: Text(otherUser.username), subtitle: Text('this is user bio of ${otherUser.username}'), trailing: Container( height: 30, width: 80, alignment: Alignment.center, decoration: BoxDecoration( color: amIFollowing ? Colors.blue[50] : Colors.red[50], border: Border.all( color: amIFollowing ? Colors.blue : Colors.red, width: 0.5, ), borderRadius: BorderRadius.circular(8), ), child: FittedBox( child: Text( amIFollowing ? 'Following' : 'Unfollowing', textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.bold, ), ), ), ), ); }, //(context, index) separatorBuilder: (context, index) { return Divider( color: Colors.grey, ); }, //아이템 사이사이 부분 itemCount: snapshot.data.length, //아이템 갯수 ); }, ), ); } else { return MyProgressIndicator(); } }), ); } }
bool amIFollowingThisUser(String otherUserKey){ return _userModel.followings.contains(otherUserKey); }
check null for usermodel
위에 만들었던 유저를 팔로우 하나 안하나 부분에서 null에대한 부분을 확인해 줘야한다. 아래와 같이 해주면 된다.
bool amIFollowingThisUser(String otherUserKey){ if(_userModel == null || _userModel.followings == null || _userModel.followings.isEmpty) return false; return _userModel.followings.contains(otherUserKey); }
반응형'개발 > Flutter' 카테고리의 다른 글
Flutter - 코딩마스터하기|피드페이지도 파이어스토어에 연결하기2 (0) 2021.11.22 Flutter - 코딩마스터하기|피드페이지도 파이어스토어에 연결하기 (0) 2021.11.19 Flutter - 코딩마스터하기|사진 업로드,게시하기3 , storage에 저장한 Post의 데이터를 database에 저장하기 (0) 2021.11.16 Flutter - 코딩마스터하기|사진 업로드,게시하기2 (0) 2021.11.16 Flutter - 코딩마스터하기|사진 업로드,게시하기1 (0) 2021.11.15 댓글