mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-26 10:11:00 +00:00
Refactor follow to shared FollowButton
This commit is contained in:
parent
7068ad90bb
commit
2f7653d05c
6 changed files with 89 additions and 62 deletions
|
@ -86,6 +86,9 @@ struct SettingsTabs: View {
|
||||||
.cornerRadius(4)
|
.cornerRadius(4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Link(destination: URL(string: "https://github.com/Dimillian/IceCubesApp")!) {
|
||||||
|
Text("https://github.com/Dimillian/IceCubesApp")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ struct AccountDetailHeaderView: View {
|
||||||
|
|
||||||
let isCurrentUser: Bool
|
let isCurrentUser: Bool
|
||||||
let account: Account
|
let account: Account
|
||||||
@Binding var relationship: Relationshionship?
|
let relationship: Relationshionship?
|
||||||
@Binding var following: Bool
|
|
||||||
@Binding var scrollOffset: CGFloat
|
@Binding var scrollOffset: CGFloat
|
||||||
|
|
||||||
private var bannerHeight: CGFloat {
|
private var bannerHeight: CGFloat {
|
||||||
|
@ -97,16 +97,9 @@ struct AccountDetailHeaderView: View {
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
if relationship != nil && !isCurrentUser {
|
if let relationship = relationship, !isCurrentUser {
|
||||||
Button {
|
FollowButton(viewModel: .init(accountId: account.id,
|
||||||
following.toggle()
|
relationship: relationship))
|
||||||
} label: {
|
|
||||||
if relationship?.requested == true {
|
|
||||||
Text("Requested")
|
|
||||||
} else {
|
|
||||||
Text(following ? "Following" : "Follow")
|
|
||||||
}
|
|
||||||
}.buttonStyle(.bordered)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Text(account.note.asSafeAttributedString)
|
Text(account.note.asSafeAttributedString)
|
||||||
|
@ -135,8 +128,7 @@ struct AccountDetailHeaderView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
AccountDetailHeaderView(isCurrentUser: false,
|
AccountDetailHeaderView(isCurrentUser: false,
|
||||||
account: .placeholder(),
|
account: .placeholder(),
|
||||||
relationship: .constant(.placeholder()),
|
relationship: .placeholder(),
|
||||||
following: .constant(true),
|
|
||||||
scrollOffset: .constant(0))
|
scrollOffset: .constant(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,26 +86,13 @@ public struct AccountDetailView: View {
|
||||||
case .loading:
|
case .loading:
|
||||||
AccountDetailHeaderView(isCurrentUser: isCurrentUser,
|
AccountDetailHeaderView(isCurrentUser: isCurrentUser,
|
||||||
account: .placeholder(),
|
account: .placeholder(),
|
||||||
relationship: .constant(.placeholder()),
|
relationship: .placeholder(),
|
||||||
following: .constant(false),
|
|
||||||
scrollOffset: $scrollOffset)
|
scrollOffset: $scrollOffset)
|
||||||
.redacted(reason: .placeholder)
|
.redacted(reason: .placeholder)
|
||||||
case let .data(account):
|
case let .data(account):
|
||||||
AccountDetailHeaderView(isCurrentUser: isCurrentUser,
|
AccountDetailHeaderView(isCurrentUser: isCurrentUser,
|
||||||
account: account,
|
account: account,
|
||||||
relationship: $viewModel.relationship,
|
relationship: viewModel.relationship,
|
||||||
following:
|
|
||||||
.init(get: {
|
|
||||||
viewModel.relationship?.following ?? false
|
|
||||||
}, set: { following in
|
|
||||||
Task {
|
|
||||||
if following {
|
|
||||||
await viewModel.follow()
|
|
||||||
} else {
|
|
||||||
await viewModel.unfollow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
scrollOffset: $scrollOffset)
|
scrollOffset: $scrollOffset)
|
||||||
case let .error(error):
|
case let .error(error):
|
||||||
Text("Error: \(error.localizedDescription)")
|
Text("Error: \(error.localizedDescription)")
|
||||||
|
@ -156,7 +143,7 @@ public struct AccountDetailView: View {
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var familliarFollowers: some View {
|
private var familliarFollowers: some View {
|
||||||
if !viewModel.familliarFollowers.isEmpty {
|
if !viewModel.familliarFollowers.isEmpty {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
Text("Also followed by")
|
Text("Also followed by")
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.padding(.leading, DS.Constants.layoutPadding)
|
.padding(.leading, DS.Constants.layoutPadding)
|
||||||
|
|
72
Packages/Account/Sources/Account/Follow/FollowButton.swift
Normal file
72
Packages/Account/Sources/Account/Follow/FollowButton.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ let package = Package(
|
||||||
targets: ["Explore"]),
|
targets: ["Explore"]),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
.package(name: "Account", path: "../Account"),
|
||||||
.package(name: "Network", path: "../Network"),
|
.package(name: "Network", path: "../Network"),
|
||||||
.package(name: "Models", path: "../Models"),
|
.package(name: "Models", path: "../Models"),
|
||||||
.package(name: "Env", path: "../Env"),
|
.package(name: "Env", path: "../Env"),
|
||||||
|
@ -24,6 +25,7 @@ let package = Package(
|
||||||
.target(
|
.target(
|
||||||
name: "Explore",
|
name: "Explore",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
.product(name: "Account", package: "Account"),
|
||||||
.product(name: "Network", package: "Network"),
|
.product(name: "Network", package: "Network"),
|
||||||
.product(name: "Models", package: "Models"),
|
.product(name: "Models", package: "Models"),
|
||||||
.product(name: "Env", package: "Env"),
|
.product(name: "Env", package: "Env"),
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Models
|
||||||
import Network
|
import Network
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
import Env
|
import Env
|
||||||
|
import Account
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class SuggestedAccountViewModel: ObservableObject {
|
class SuggestedAccountViewModel: ObservableObject {
|
||||||
|
@ -15,20 +16,6 @@ class SuggestedAccountViewModel: ObservableObject {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.relationShip = relationShip
|
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 {
|
struct SuggestedAccountRow: View {
|
||||||
|
@ -54,24 +41,8 @@ struct SuggestedAccountRow: View {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
Button {
|
FollowButton(viewModel: .init(accountId: viewModel.account.id,
|
||||||
Task {
|
relationship: viewModel.relationShip))
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewModel.client = client
|
viewModel.client = client
|
||||||
|
|
Loading…
Reference in a new issue