Skip to content

Commit

Permalink
FollowStatusButtonとUserStatusRowViewを実装
Browse files Browse the repository at this point in the history
  • Loading branch information
boardguy1024 committed Oct 22, 2023
1 parent ff4551c commit fa2a154
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 11 deletions.
12 changes: 12 additions & 0 deletions TwitterSwiftUI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
2DC4D9492ADC14F30066FF02 /* NewMessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DC4D9482ADC14F30066FF02 /* NewMessageViewModel.swift */; };
2DD92B992AE3CEEA00252362 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DD92B982AE3CEEA00252362 /* String+Extensions.swift */; };
2DE08BE72ADAEBF900DAA3C4 /* NewTweetButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE08BE62ADAEBF900DAA3C4 /* NewTweetButton.swift */; };
2DF74F9D2AE552DD00DFBDD5 /* FollowStatusButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF74F9C2AE552DD00DFBDD5 /* FollowStatusButton.swift */; };
2DF74F9F2AE555B500DFBDD5 /* UserStatusRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF74F9E2AE555B500DFBDD5 /* UserStatusRowView.swift */; };
2DF74FA12AE5576600DFBDD5 /* UserStatusRowViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF74FA02AE5576600DFBDD5 /* UserStatusRowViewModel.swift */; };
FF170EE32AD29E7800B90E2D /* PreviewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF170EE22AD29E7800B90E2D /* PreviewProvider.swift */; };
FF170EE52AD2A09E00B90E2D /* RegistrationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF170EE42AD2A09E00B90E2D /* RegistrationViewModel.swift */; };
FF170EE82AD2A27D00B90E2D /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF170EE72AD2A27D00B90E2D /* LoginViewModel.swift */; };
Expand Down Expand Up @@ -132,6 +135,9 @@
2DC4D9482ADC14F30066FF02 /* NewMessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewMessageViewModel.swift; sourceTree = "<group>"; };
2DD92B982AE3CEEA00252362 /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = "<group>"; };
2DE08BE62ADAEBF900DAA3C4 /* NewTweetButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTweetButton.swift; sourceTree = "<group>"; };
2DF74F9C2AE552DD00DFBDD5 /* FollowStatusButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowStatusButton.swift; sourceTree = "<group>"; };
2DF74F9E2AE555B500DFBDD5 /* UserStatusRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserStatusRowView.swift; sourceTree = "<group>"; };
2DF74FA02AE5576600DFBDD5 /* UserStatusRowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserStatusRowViewModel.swift; sourceTree = "<group>"; };
FF170EE22AD29E7800B90E2D /* PreviewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewProvider.swift; sourceTree = "<group>"; };
FF170EE42AD2A09E00B90E2D /* RegistrationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationViewModel.swift; sourceTree = "<group>"; };
FF170EE72AD2A27D00B90E2D /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -280,6 +286,9 @@
2D7CD6512ADEC894006DECA4 /* UserStatusDetailView.swift */,
2D9F42B82AE161DE000FD971 /* UserStatusDetailViewModel.swift */,
2D9F42BA2AE16912000FD971 /* FollowingUserListView.swift */,
2DF74F9E2AE555B500DFBDD5 /* UserStatusRowView.swift */,
2DF74FA02AE5576600DFBDD5 /* UserStatusRowViewModel.swift */,
2DF74F9C2AE552DD00DFBDD5 /* FollowStatusButton.swift */,
);
path = Users;
sourceTree = "<group>";
Expand Down Expand Up @@ -721,6 +730,7 @@
FF2EE4FB2ABF1C2F000522CF /* TextAreaView.swift in Sources */,
FFFB5D582AC0210600817497 /* ImagePicker.swift in Sources */,
2DC4D9492ADC14F30066FF02 /* NewMessageViewModel.swift in Sources */,
2DF74FA12AE5576600DFBDD5 /* UserStatusRowViewModel.swift in Sources */,
FF2EE50B2ABFE905000522CF /* AuthSubmitButton.swift in Sources */,
FF44B9222ABC8117005B87F4 /* ContentView.swift in Sources */,
FF2EE4EE2ABEF09C000522CF /* SideMenuRowView.swift in Sources */,
Expand Down Expand Up @@ -751,10 +761,12 @@
2D6173EA2AE011260089F1E7 /* Timestamp+Extensions.swift in Sources */,
2D89D9E02AD9955900F20E91 /* ChatViewModel.swift in Sources */,
FFACF2B42AC15A3400A2C911 /* SearchBar.swift in Sources */,
2DF74F9D2AE552DD00DFBDD5 /* FollowStatusButton.swift in Sources */,
FF2EE5042ABF23EE000522CF /* RoundedShape.swift in Sources */,
FF170EEC2AD2D95000B90E2D /* EntryView.swift in Sources */,
FFACF2BE2AC1BD2A00A2C911 /* ProfileViewModel.swift in Sources */,
FF170EE52AD2A09E00B90E2D /* RegistrationViewModel.swift in Sources */,
2DF74F9F2AE555B500DFBDD5 /* UserStatusRowView.swift in Sources */,
2DC291462ADA2B7D006E9E23 /* ConversationsView.swift in Sources */,
FFACF2B22AC1519E00A2C911 /* ExploreViewModel.swift in Sources */,
2D9F42BB2AE16912000FD971 /* FollowingUserListView.swift in Sources */,
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion TwitterSwiftUI/Core/Components/NavigationHeaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,5 @@ struct NavigationHeaderView: View {
}

#Preview {
NavigationHeaderView(showSideMenu: .constant(false), user: .constant(PreviewProvider.shared.user))
NavigationHeaderView(showSideMenu: .constant(false), user: .constant(PreviewProvider.user))
}
56 changes: 56 additions & 0 deletions TwitterSwiftUI/Core/Components/Users/FollowStatusButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// FollowStatusButton.swift
// TwitterSwiftUI
//
// Created by paku on 2023/10/22.
//

import SwiftUI

enum FollowStatus: Int, CaseIterable, Identifiable {
case unfollowing
case following

var title: String {
switch self {
case .unfollowing: "フォローする"
case .following: "フォロー中"
}
}

var id: Int { self.rawValue }
}

struct FollowStatusButton: View {

@Binding var status: FollowStatus
var buttonTapped: () -> Void

init(status: Binding<FollowStatus>, buttonTapped: @escaping () -> Void) {
_status = status
self.buttonTapped = buttonTapped
}

var body: some View {
Button {
buttonTapped()
} label: {
Text(status.title)
.font(.footnote).bold()
.frame(width: 140, height: 28)
.foregroundColor(status == .unfollowing ? .white : .black)
.background(
Color(status == .unfollowing ? .black : .clear)
.cornerRadius(20)
)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.gray, lineWidth: 0.75)
)
}
}
}

#Preview {
FollowStatusButton(status: .constant(.unfollowing), buttonTapped: {})
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct FollowingUserListView: View {
NavigationLink {
ProfileView(user: user)
} label: {
UserRowView(user: user)
UserStatusRowView(user: user)
}
}
}
Expand Down
60 changes: 60 additions & 0 deletions TwitterSwiftUI/Core/Components/Users/UserStatusRowView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// UserStatusRowView.swift
// TwitterSwiftUI
//
// Created by paku on 2023/10/22.
//

import SwiftUI
import Kingfisher

struct UserStatusRowView: View {

@StateObject var viewModel: UserStatusRowViewModel

init(user: User) {
_viewModel = .init(wrappedValue: UserStatusRowViewModel(user: user))
}

var body: some View {

HStack(alignment: .top, spacing: 12) {
KFImage(URL(string: viewModel.user.profileImageUrl))
.resizable()
.scaledToFill()
.frame(width: 48, height: 48)
.clipShape(Circle())

VStack(alignment: .leading) {
HStack {
VStack(alignment: .leading) {
Text(viewModel.user.username)
.font(.subheadline).bold()
.foregroundStyle(.black)

Text("@\(viewModel.user.email.emailUsername ?? "")")
.font(.subheadline)
.foregroundColor(.gray)
}
Spacer()

FollowStatusButton(status: $viewModel.followingStatus) {
viewModel.followButtonTapped()
}
}
if let bio = viewModel.user.bio {
Text(bio)
.font(.subheadline)
.multilineTextAlignment(.leading)
.foregroundColor(.black)
}
}
}
.padding(.horizontal)
.padding(.vertical, 6)
}
}

#Preview {
UserStatusRowView(user: PreviewProvider.user)
}
72 changes: 72 additions & 0 deletions TwitterSwiftUI/Core/Components/Users/UserStatusRowViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//
// UserStatusRowViewModel.swift
// TwitterSwiftUI
//
// Created by paku on 2023/10/22.
//

import Foundation

class UserStatusRowViewModel: ObservableObject {
let user: User

@Published var followingStatus: FollowStatus = .following

init(user: User) {
self.user = user

Task {
try await fetchFollowStatus()
}
}

func followButtonTapped() {
Task {
try await toggleFollowStatus()
}
}

private func toggleFollowStatus() async throws {
Task {
switch followingStatus {
case .unfollowing:
try await follow()
case .following:
try await unfollow()
}
}
}

@MainActor
private func unfollow() async throws {
guard let uid = user.id else { return }

followingStatus = .unfollowing
do {
let _ = try await UserService.shared.unfollowUser(uid: uid)
} catch {
print("Faild unfollow: \(error.localizedDescription)")
followingStatus = .following
}
}

@MainActor
private func follow() async throws {
guard let uid = user.id else { return }

followingStatus = .following
do {
let _ = try await UserService.shared.followUser(uid: uid)
} catch {
print("Faild follow: \(error.localizedDescription)")
followingStatus = .unfollowing
}
}

@MainActor
private func fetchFollowStatus() async throws {
guard let uid = user.id else { return }
let followed = try await UserService.shared.checkIfUserIsFollowing(for: uid)
followingStatus = followed ? .following : .unfollowing
}
}
2 changes: 1 addition & 1 deletion TwitterSwiftUI/Core/Profile/View/TweetListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ struct TweetListView: View {
}

#Preview {
TweetListView(user: PreviewProvider.shared.user, tabType: .tweets)
TweetListView(user: PreviewProvider.user, tabType: .tweets)
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ extension ChatBubbleView {
}

#Preview {
ChatBubbleView(message: PreviewProvider.shared.message)
ChatBubbleView(message: PreviewProvider.message)
}
2 changes: 1 addition & 1 deletion TwitterSwiftUI/Core/TabBar/Conversations/ChatView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,5 @@ extension ChatView {
}

#Preview {
ChatView(user: PreviewProvider.shared.user)
ChatView(user: PreviewProvider.user)
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ struct ConversationRowView: View {
}

#Preview {
ConversationRowView(message: PreviewProvider.shared.message)
ConversationRowView(message: PreviewProvider.message)
}
7 changes: 2 additions & 5 deletions TwitterSwiftUI/Extensions/PreviewProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@
import Foundation

class PreviewProvider {
static let shared = PreviewProvider()

private init() { }

let user = User(username: "username",
static let user = User(username: "username",
profileImageUrl: "profileImageUrl",
profileHeaderImageUrl: "profileHeaderImageUrl",
email: "email",
bio: "",
location: "",
webUrl: "")
let message = Message(user: PreviewProvider.shared.user, dic: ["text": "テキスト"])
static let message = Message(user: PreviewProvider.user, dic: ["text": "テキスト"])
}

0 comments on commit fa2a154

Please sign in to comment.