Refactor follow to shared FollowButton

This commit is contained in:
Thomas Ricouard 2022-12-23 16:21:31 +01:00
parent 7068ad90bb
commit 2f7653d05c
6 changed files with 89 additions and 62 deletions

View file

@ -86,6 +86,9 @@ struct SettingsTabs: View {
.cornerRadius(4)
}
}
Link(destination: URL(string: "https://github.com/Dimillian/IceCubesApp")!) {
Text("https://github.com/Dimillian/IceCubesApp")
}
}
}

View file

@ -10,8 +10,8 @@ struct AccountDetailHeaderView: View {
let isCurrentUser: Bool
let account: Account
@Binding var relationship: Relationshionship?
@Binding var following: Bool
let relationship: Relationshionship?
@Binding var scrollOffset: CGFloat
private var bannerHeight: CGFloat {
@ -97,16 +97,9 @@ struct AccountDetailHeaderView: View {
.foregroundColor(.gray)
}
Spacer()
if relationship != nil && !isCurrentUser {
Button {
following.toggle()
} label: {
if relationship?.requested == true {
Text("Requested")
} else {
Text(following ? "Following" : "Follow")
}
}.buttonStyle(.bordered)
if let relationship = relationship, !isCurrentUser {
FollowButton(viewModel: .init(accountId: account.id,
relationship: relationship))
}
}
Text(account.note.asSafeAttributedString)
@ -135,8 +128,7 @@ struct AccountDetailHeaderView_Previews: PreviewProvider {
static var previews: some View {
AccountDetailHeaderView(isCurrentUser: false,
account: .placeholder(),
relationship: .constant(.placeholder()),
following: .constant(true),
relationship: .placeholder(),
scrollOffset: .constant(0))
}
}

View file

@ -86,26 +86,13 @@ public struct AccountDetailView: View {
case .loading:
AccountDetailHeaderView(isCurrentUser: isCurrentUser,
account: .placeholder(),
relationship: .constant(.placeholder()),
following: .constant(false),
relationship: .placeholder(),
scrollOffset: $scrollOffset)
.redacted(reason: .placeholder)
case let .data(account):
AccountDetailHeaderView(isCurrentUser: isCurrentUser,
account: account,
relationship: $viewModel.relationship,
following:
.init(get: {
viewModel.relationship?.following ?? false
}, set: { following in
Task {
if following {
await viewModel.follow()
} else {
await viewModel.unfollow()
}
}
}),
relationship: viewModel.relationship,
scrollOffset: $scrollOffset)
case let .error(error):
Text("Error: \(error.localizedDescription)")
@ -156,7 +143,7 @@ public struct AccountDetailView: View {
@ViewBuilder
private var familliarFollowers: some View {
if !viewModel.familliarFollowers.isEmpty {
VStack(alignment: .leading, spacing: 0) {
VStack(alignment: .leading, spacing: 2) {
Text("Also followed by")
.font(.headline)
.padding(.leading, DS.Constants.layoutPadding)

View file

@ -0,0 +1,72 @@
import Foundation
import SwiftUI
import Models
import Network
@MainActor
public class FollowButtonViewModel: ObservableObject {
var client: Client?
public let accountId: String
@Published private(set) public var relationship: Relationshionship
@Published private(set) public var isUpdating: Bool = false
public init(accountId: String, relationship: Relationshionship) {
self.accountId = accountId
self.relationship = relationship
}
func follow() async {
guard let client else { return }
isUpdating = true
do {
relationship = try await client.post(endpoint: Accounts.follow(id: accountId))
} catch {
print("Error while following: \(error.localizedDescription)")
}
isUpdating = false
}
func unfollow() async {
guard let client else { return }
isUpdating = true
do {
relationship = try await client.post(endpoint: Accounts.unfollow(id: accountId))
} catch {
print("Error while unfollowing: \(error.localizedDescription)")
}
isUpdating = false
}
}
public struct FollowButton: View {
@EnvironmentObject private var client: Client
@StateObject private var viewModel: FollowButtonViewModel
public init(viewModel: FollowButtonViewModel) {
_viewModel = StateObject(wrappedValue: viewModel)
}
public var body: some View {
Button {
Task {
if viewModel.relationship.following {
await viewModel.unfollow()
} else {
await viewModel.follow()
}
}
} label: {
if viewModel.relationship.requested == true {
Text("Requested")
} else {
Text(viewModel.relationship.following ? "Following" : "Follow")
}
}
.buttonStyle(.bordered)
.disabled(viewModel.isUpdating)
.onAppear {
viewModel.client = client
}
}
}

View file

@ -14,6 +14,7 @@ let package = Package(
targets: ["Explore"]),
],
dependencies: [
.package(name: "Account", path: "../Account"),
.package(name: "Network", path: "../Network"),
.package(name: "Models", path: "../Models"),
.package(name: "Env", path: "../Env"),
@ -24,6 +25,7 @@ let package = Package(
.target(
name: "Explore",
dependencies: [
.product(name: "Account", package: "Account"),
.product(name: "Network", package: "Network"),
.product(name: "Models", package: "Models"),
.product(name: "Env", package: "Env"),

View file

@ -3,6 +3,7 @@ import Models
import Network
import DesignSystem
import Env
import Account
@MainActor
class SuggestedAccountViewModel: ObservableObject {
@ -15,20 +16,6 @@ class SuggestedAccountViewModel: ObservableObject {
self.account = account
self.relationShip = relationShip
}
func follow() async {
guard let client else { return }
do {
self.relationShip = try await client.post(endpoint: Accounts.follow(id: account.id))
} catch {}
}
func unfollow() async {
guard let client else { return }
do {
self.relationShip = try await client.post(endpoint: Accounts.unfollow(id: account.id))
} catch {}
}
}
struct SuggestedAccountRow: View {
@ -54,24 +41,8 @@ struct SuggestedAccountRow: View {
})
}
Spacer()
Button {
Task {
if viewModel.relationShip.following {
await viewModel.unfollow()
} else {
await viewModel.follow()
}
}
} label: {
if viewModel.relationShip.requested {
Text("Requested")
.font(.callout)
} else {
Text(viewModel.relationShip.following ? "Unfollow" : "Follow")
.font(.callout)
}
}
.buttonStyle(.bordered)
FollowButton(viewModel: .init(accountId: viewModel.account.id,
relationship: viewModel.relationShip))
}
.onAppear {
viewModel.client = client