diff --git a/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 60f2a286..dbc1700b 100644 --- a/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/kean/Nuke", "state" : { - "revision" : "2e9337168d08acccf72c039bf9324be24a1cf7d7", - "version" : "11.5.3" + "revision" : "81f6a3dea0c8ce3b87389c241c48601be07af0b1", + "version" : "11.5.1" } }, { @@ -50,8 +50,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/scinfu/SwiftSoup.git", "state" : { - "revision" : "f707b8680cddb96dc1855632340a572ef37bbb98", - "version" : "2.5.3" + "revision" : "6778575285177365cbad3e5b8a72f2a20583cfec", + "version" : "2.4.3" } }, { diff --git a/Packages/Account/Sources/Account/AccountDetailHeaderView.swift b/Packages/Account/Sources/Account/AccountDetailHeaderView.swift index 27994c67..01dbf037 100644 --- a/Packages/Account/Sources/Account/AccountDetailHeaderView.swift +++ b/Packages/Account/Sources/Account/AccountDetailHeaderView.swift @@ -12,9 +12,8 @@ struct AccountDetailHeaderView: View { @EnvironmentObject private var routeurPath: RouterPath @Environment(\.redactionReasons) private var reasons - let isCurrentUser: Bool + @ObservedObject var viewModel: AccountDetailViewModel let account: Account - let relationship: Relationshionship? let scrollViewProxy: ScrollViewProxy? @Binding var scrollOffset: CGFloat @@ -55,7 +54,7 @@ struct AccountDetailHeaderView: View { .frame(height: bannerHeight) } - if relationship?.followedBy == true { + if viewModel.relationship?.followedBy == true { Text("Follows You") .font(.footnote) .fontWeight(.semibold) @@ -116,9 +115,11 @@ struct AccountDetailHeaderView: View { .foregroundColor(.gray) } Spacer() - if let relationship = relationship, !isCurrentUser { - FollowButton(viewModel: .init(accountId: account.id, - relationship: relationship)) + if let relationship = viewModel.relationship, !viewModel.isCurrentUser { + HStack { + FollowButton(viewModel: .init(accountId: account.id, + relationship: relationship)) + } } } EmojiText(account.note, emojis: account.emojis) @@ -146,9 +147,8 @@ struct AccountDetailHeaderView: View { struct AccountDetailHeaderView_Previews: PreviewProvider { static var previews: some View { - AccountDetailHeaderView(isCurrentUser: false, + AccountDetailHeaderView(viewModel: .init(account: .placeholder()), account: .placeholder(), - relationship: .placeholder(), scrollViewProxy: nil, scrollOffset: .constant(0)) } diff --git a/Packages/Account/Sources/Account/AccountDetailView.swift b/Packages/Account/Sources/Account/AccountDetailView.swift index 996972f0..ef6ee48d 100644 --- a/Packages/Account/Sources/Account/AccountDetailView.swift +++ b/Packages/Account/Sources/Account/AccountDetailView.swift @@ -122,17 +122,15 @@ public struct AccountDetailView: View { private func makeHeaderView(proxy: ScrollViewProxy?) -> some View { switch viewModel.accountState { case .loading: - AccountDetailHeaderView(isCurrentUser: isCurrentUser, + AccountDetailHeaderView(viewModel: viewModel, account: .placeholder(), - relationship: .placeholder(), scrollViewProxy: proxy, scrollOffset: $scrollOffset) .redacted(reason: .placeholder) .shimmering() case let .data(account): - AccountDetailHeaderView(isCurrentUser: isCurrentUser, + AccountDetailHeaderView(viewModel: viewModel, account: account, - relationship: viewModel.relationship, scrollViewProxy: proxy, scrollOffset: $scrollOffset) case let .error(error): diff --git a/Packages/Account/Sources/Account/AccountDetailViewModel.swift b/Packages/Account/Sources/Account/AccountDetailViewModel.swift index 61b01b7f..9ebd3b47 100644 --- a/Packages/Account/Sources/Account/AccountDetailViewModel.swift +++ b/Packages/Account/Sources/Account/AccountDetailViewModel.swift @@ -212,25 +212,7 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher { tabState = .statuses(statusesState: .error(error: error)) } } - - func follow() async { - guard let client else { return } - do { - relationship = try await client.post(endpoint: Accounts.follow(id: accountId)) - } catch { - print("Error while following: \(error.localizedDescription)") - } - } - - func unfollow() async { - guard let client else { return } - do { - relationship = try await client.post(endpoint: Accounts.unfollow(id: accountId)) - } catch { - print("Error while unfollowing: \(error.localizedDescription)") - } - } - + private func reloadTabState() { switch selectedTab { case .statuses, .postsAndReplies, .media: diff --git a/Packages/Account/Sources/Account/Follow/FollowButton.swift b/Packages/Account/Sources/Account/Follow/FollowButton.swift index 317c04f7..05013488 100644 --- a/Packages/Account/Sources/Account/Follow/FollowButton.swift +++ b/Packages/Account/Sources/Account/Follow/FollowButton.swift @@ -20,7 +20,7 @@ public class FollowButtonViewModel: ObservableObject { guard let client else { return } isUpdating = true do { - relationship = try await client.post(endpoint: Accounts.follow(id: accountId)) + relationship = try await client.post(endpoint: Accounts.follow(id: accountId, notify: false)) } catch { print("Error while following: \(error.localizedDescription)") } @@ -37,6 +37,15 @@ public class FollowButtonViewModel: ObservableObject { } isUpdating = false } + + func toggleNotify() async { + guard let client else { return } + do { + relationship = try await client.post(endpoint: Accounts.follow(id: accountId, notify: !relationship.notifying)) + } catch { + print("Error while following: \(error.localizedDescription)") + } + } } public struct FollowButton: View { @@ -48,23 +57,36 @@ public struct FollowButton: View { } public var body: some View { - Button { - Task { - if viewModel.relationship.following { - await viewModel.unfollow() + HStack { + Button { + Task { + if viewModel.relationship.following { + await viewModel.unfollow() + } else { + await viewModel.follow() + } + } + } label: { + if viewModel.relationship.requested == true { + Text("Requested") } else { - await viewModel.follow() + Text(viewModel.relationship.following ? "Following" : "Follow") } } - } label: { - if viewModel.relationship.requested == true { - Text("Requested") - } else { - Text(viewModel.relationship.following ? "Following" : "Follow") + .buttonStyle(.bordered) + .disabled(viewModel.isUpdating) + if viewModel.relationship.following { + Button { + Task { + await viewModel.toggleNotify() + } + } label: { + Image(systemName: viewModel.relationship.notifying ? "bell.fill" : "bell") + } + .buttonStyle(.bordered) + .disabled(viewModel.isUpdating) } } - .buttonStyle(.bordered) - .disabled(viewModel.isUpdating) .onAppear { viewModel.client = client } diff --git a/Packages/Models/Sources/Models/Relationshionship.swift b/Packages/Models/Sources/Models/Relationshionship.swift index 6e2dee38..b8478eb6 100644 --- a/Packages/Models/Sources/Models/Relationshionship.swift +++ b/Packages/Models/Sources/Models/Relationshionship.swift @@ -13,6 +13,7 @@ public struct Relationshionship: Codable { public let domainBlocking: Bool public let endorsed: Bool public let note: String + public let notifying: Bool static public func placeholder() -> Relationshionship { .init(id: UUID().uuidString, @@ -26,6 +27,7 @@ public struct Relationshionship: Codable { requested: false, domainBlocking: false, endorsed: false, - note: "") + note: "", + notifying: false) } } diff --git a/Packages/Network/Sources/Network/Endpoint/Accounts.swift b/Packages/Network/Sources/Network/Endpoint/Accounts.swift index ae32039f..c04ef8a8 100644 --- a/Packages/Network/Sources/Network/Endpoint/Accounts.swift +++ b/Packages/Network/Sources/Network/Endpoint/Accounts.swift @@ -22,7 +22,7 @@ public enum Accounts: Endpoint { excludeReplies: Bool?, pinned: Bool?) case relationships(ids: [String]) - case follow(id: String) + case follow(id: String, notify: Bool) case unfollow(id: String) case familiarFollowers(withAccount: String) case suggestions @@ -51,7 +51,7 @@ public enum Accounts: Endpoint { return "accounts/\(id)/statuses" case .relationships: return "accounts/relationships" - case .follow(let id): + case .follow(let id, _): return "accounts/\(id)/follow" case .unfollow(let id): return "accounts/\(id)/unfollow" @@ -94,6 +94,8 @@ public enum Accounts: Endpoint { return ids.map { URLQueryItem(name: "id[]", value: $0) } + case let .follow(_, notify): + return [.init(name: "notify", value: notify ? "true" : "false")] case let .familiarFollowers(withAccount): return [.init(name: "id[]", value: withAccount)] case let .followers(_, maxId):