đ´ Let's Build Twitter with SwiftUI (iOS 15, Xcode 13, Firebase, SwiftUI 3.0)
func likeTweet(_ tweet: TweetModel, completion: @escaping(Result<Bool, Error>) -> Void) {
guard
let uid = Auth.auth().currentUser?.uid,
let tweetId = tweet.id else {
completion(.failure(URLError(.badURL)))
return
}
let userLikesRef = Firestore.firestore().collection("users").document(uid).collection("user-likes")
let tweetRef = Firestore.firestore().collection("tweets").document(tweetId)
tweetRef.getDocument { snapshot, error in
guard
let currentTweet = try? snapshot?.data(as: TweetModel.self),
error == nil else {
if let error = error {
completion(.failure(error))
} else {
completion(.failure(URLError(.badURL)))
}
return
}
let updatedCount = currentTweet.likes + 1
tweetRef.updateData(["likes": updatedCount]) { error in
if let error = error {
completion(.failure(error))
} else {
userLikesRef.document(tweetId).setData([:]) { error in
if let error = error {
completion(.failure(error))
} else {
completion(.success(true))
}
}
}
}
}
}
getDocument
뼟 íľí´ í ěě íě´ě´ë˛ ě´ě¤ ë´ ěĄ´ěŹíë í¸ěí° ë°ě´í°ëĽź í¨ěš func dislikeTweet(_ tweet: TweetModel, completion: @escaping(Result<Bool, Error>) -> Void) {
guard
let uid = Auth.auth().currentUser?.uid,
let tweetId = tweet.id else {
completion(.failure(URLError(.badURL)))
return
}
let userLikesRef = Firestore.firestore().collection("users").document(uid).collection("user-likes").document(tweetId)
let tweetRef = Firestore.firestore().collection("tweets").document(tweetId)
tweetRef.getDocument { snapshot, error in
guard
let currentTweet = try? snapshot?.data(as: TweetModel.self),
error == nil else {
if let error = error {
completion(.failure(error))
} else {
completion(.failure(URLError(.badURL)))
}
return
}
let updatedCount = currentTweet.likes - 1
tweetRef.updateData(["likes": updatedCount]) { error in
if let error = error {
completion(.failure(error))
} else {
userLikesRef.delete { error in
if let error = error {
completion(.failure(error))
} else {
completion(.success(true))
}
}
}
}
}
}
func checkIfUserLikedTweet(_ tweet: TweetModel, completion: @escaping(Result<Bool, Error>) -> Void) {
guard
let uid = Auth.auth().currentUser?.uid,
let tweetId = tweet.id else {
completion(.failure(URLError(.badURL)))
return
}
let userLikesRef = Firestore.firestore().collection("users").document(uid)
.collection("user-likes").document(tweetId)
userLikesRef
.getDocument { snapshot, error in
guard
let snapshot = snapshot,
error == nil else {
if let error = error {
completion(.failure(error))
} else {
completion(.failure(URLError(.badURL)))
}
return
}
completion(.success(snapshot.exists))
}
}
func fetchLikedTweets(for uid: String, completion: @escaping(Result<[TweetModel], Error>) -> Void) {
var tweets: [TweetModel] = []
Firestore.firestore().collection("users").document(uid).collection("user-likes").getDocuments { snapshot, error in
guard
let documents = snapshot?.documents,
error == nil else {
if let error = error {
completion(.failure(error))
} else {
completion(.failure(URLError(.badURL)))
}
return
}
documents.forEach { document in
let tweetId = document.documentID
Firestore.firestore().collection("tweets")
.document(tweetId)
.getDocument { snapshot, error in
guard
let tweet = try? snapshot?.data(as: TweetModel.self) else { return }
tweets.append(tweet)
completion(.success(tweets))
}
}
}
}
func fetchLikedTweets() {
guard let uid = user.id else { return }
service.fetchLikedTweets(for: uid) { [weak self] result in
switch result {
case .success(var tweets):
tweets = tweets.map({ [weak self] tweet in
var tweet = tweet
tweet.user = self?.user
return tweet
})
self?.likedTweets = tweets
case .failure(let error): print(error.localizedDescription)
}
}
}
func filterTweets(with filter: TweetFilterViewModel) -> [TweetModel] {
switch filter {
case .tweets:
return tweets
case .replies:
return tweets
case .likes:
return likedTweets
}
}
private var heartButton: some View {
Button {
viewModel.didLikeTweet ? viewModel.dislikeTweet() : viewModel.likeTweet()
} label: {
Image(systemName: viewModel.didLikeTweet ? "heart.fill" : "heart")
.font(.subheadline)
.foregroundColor(viewModel.didLikeTweet ? .red : .gray)
}
}
ObservableObject
ë°@Published
뼟 íěŠí ęšëí ë°ě´í° ě˛ëŚŹę° ę°ëĽí SwiftUIě ě ë Ľ! ě ëëŠě´ě ě ëłëëĄ ë¤ě´ěë¤.