기능 구현 #9
좋아요 기능 추가하기
SNS에서 빠질 수 없는 좋아요 기능을 구현해 본다.
TweetRow의 하트 버튼을 누르면 붉은색으로 표시되고, 이를 모아서 볼 수도 있어야 한다.
기본적인 UI는 이미 존재하는 상태이므로 기능만 구현하면 된다.
좋아요 기능 추가하기
| Tweet model
import FirebaseFirestoreSwift
import Firebase
struct Tweet: Identifiable, Codable {
@DocumentID var id: String?
let caption: String
let timestamp: Timestamp
let uid: String
var likes: Int
var user: User?
var didLike: Bool? = false
}
좋아요 기능을 위해 TweetModel에 새로운 속성을 하나 추가한다.
didLike 속성은 사용자가 좋아요를 한 상태인지 표시하는 데 사용된다.
좋아요 기능 추가하기
| TweetService
Tweet에 관련된 기능들은 TweetService에 정의된다.
이미 uploadTweet, fetchTweets, fetTweets(foruid:)를 구현했고, 새로운 메서드인 likeTweet을 추가한다.
func likeTweet(_ tweet: Tweet, completion: @escaping() -> Void) {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
guard let tweetId = tweet.id else {
return
}
}
현재 접속 중인 사용자의 유효성을 FirebaseQuth의 currentUser.uid 속성을 통해 판단하고,
좋아요를 진행할 Tweet을 판단하기 위해 파라미터로 전달된 Tweet의 id를 바인딩한다.
func likeTweet(_ tweet: Tweet, completion: @escaping() -> Void) {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
guard let tweetId = tweet.id else {
return
}
let userLikesRef = Firestore.firestore().collection("users").document(uid).collection("user-likes")
}
uid를 사용해 해당 사용자의 collection으로 이동하여 user-likes라는 하위 collection을 하나 생성하거나 접근할 수 있도록 경로를 설정하고,
func likeTweet(_ tweet: Tweet, completion: @escaping() -> Void) {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
guard let tweetId = tweet.id else {
return
}
let userLikesRef = Firestore.firestore().collection("users").document(uid).collection("user-likes")
Firestore.firestore().collection("tweets").document(tweetId).updateData(["likes": tweet.likes + 1]) {_ in
userLikesRef.document(tweetId).setData([:]) { _ in
completion()
}
}
}
해당 Tweet의 likes를 1 증가 시킴과 동시에 userLikeRef의 하위 Collection 경로로 이동해
좋아요를 진행한 tweetId를 저장하고, 완료되면 CompletionHandler를 호출한다.
좋아요 기능 추가하기
| TweetRowViewModel
lass TweetRowViewModel: ObservableObject {
private let service = TweetService()
@Published var tweet: Tweet
init(tweet: Tweet) {
self.tweet = tweet
}
func likeTweet() {
service.likeTweet(tweet) {
self.tweet.didLike = true
}
}
}
TweetRowView에 표시할 데이터를 저장할 TweetRowViewModel을 정의한다.
likeTweet에 좋아요를 진행할 tweet을 전달하고, 동작이 완료되면 Tweet의 좋아요 상태를 갱신한다.
좋아요 기능 추가하기
| TweetRowView
HStack {
Button {
// action
} label: {
Image(systemName: "bubble.left")
}
Spacer()
Button {
// action
} label: {
Image(systemName: "arrow.2.squarepath")
}
Spacer()
Button {
// action
} label: {
Image(systemName: "heart")
}
Spacer()
Button {
// action
} label: {
Image(systemName: "bookmark")
}
}
.font(.subheadline)
.padding()
.foregroundColor(.gray)
TweetRowView의 아래에는 각각의 기능에 대한 버튼들이 존재한다.
그중 'heart'를 표시하는 세 번째 버튼이 좋아요 기능을 담당하게 된다.
Button {
viewModel.likeTweet()
} label: {
Image(systemName: viewModel.tweet.didLike ?? false ? "heart.fill" : "heart")
.foregroundColor(viewModel.tweet.didLike ?? false ? .red : .gray)
}
Button은 TweetRowViewModel의 likeTweet 메서드를 호출하고,
표시하려는 Tweet의 didLike 속성에 따라 빈 하트나 빨간색 하트를 표시한다.
Source
import SwiftUI
import Kingfisher
struct TweetRowView: View {
@ObservedObject var viewModel: TweetRowViewModel
init(tweet: Tweet) {
self.viewModel = TweetRowViewModel(tweet: tweet)
}
var body: some View {
VStack(alignment: .leading) {
//profile image & user info & tweet
if let user = viewModel.tweet.user {
HStack(alignment: .top, spacing: 12) {
KFImage(URL(string: user.profileImageUrl))
.resizable()
.scaledToFill()
.clipShape(Circle())
.frame(width: 56, height: 56)
//user info & tweet caption
VStack(alignment: .leading, spacing: 4) {
//user info
HStack {
Text(user.fullname)
.font(.subheadline).bold()
Group {
Text("@\(user.username)")
Text("2d")
}
.foregroundColor(.gray)
.font(.caption)
}
//tweet caption
Text(viewModel.tweet.caption)
.font(.subheadline)
.multilineTextAlignment(.leading)
}
}
}
//action buttons
HStack {
Button {
// action
} label: {
Image(systemName: "bubble.left")
}
Spacer()
Button {
// action
} label: {
Image(systemName: "arrow.2.squarepath")
}
Spacer()
Button {
viewModel.likeTweet()
} label: {
Image(systemName: viewModel.tweet.didLike ?? false ? "heart.fill" : "heart")
.foregroundColor(viewModel.tweet.didLike ?? false ? .red : .gray)
}
Spacer()
Button {
// action
} label: {
Image(systemName: "bookmark")
}
}
.font(.subheadline)
.padding()
.foregroundColor(.gray)
Divider()
}
}
}
'프로젝트 > Twitter Clone App (w∕Firebase)' 카테고리의 다른 글
25. DB와 연결하기 #4 (0) | 2023.01.20 |
---|---|
24. 기능 구현 #10 (0) | 2023.01.20 |
22. 버그수정 #2 (0) | 2023.01.18 |
21. DB와 연결하기 #3 (0) | 2023.01.18 |
20. 기능 구현 #8 (0) | 2023.01.17 |