IceCubesApp/Packages/Account/Sources/Account/AccountDetailViewModel.swift

158 lines
4.8 KiB
Swift
Raw Normal View History

2022-11-29 11:18:06 +00:00
import SwiftUI
import Network
import Models
2022-12-19 06:17:01 +00:00
import Status
2022-11-29 11:18:06 +00:00
@MainActor
2022-12-19 06:17:01 +00:00
class AccountDetailViewModel: ObservableObject, StatusesFetcher {
2022-11-29 11:18:06 +00:00
let accountId: String
2022-12-19 11:28:55 +00:00
var client: Client?
2022-11-29 11:18:06 +00:00
enum AccountState {
2022-12-01 08:05:26 +00:00
case loading, data(account: Account), error(error: Error)
2022-11-29 11:18:06 +00:00
}
enum Tab: Int, CaseIterable {
case statuses, favourites, followedTags
var title: String {
switch self {
case .statuses: return "Posts"
case .favourites: return "Favourites"
case .followedTags: return "Followed Tags"
}
}
}
2022-12-18 19:30:19 +00:00
enum TabState {
case followedTags(tags: [Tag])
case statuses(statusesState: StatusesState)
}
@Published var accountState: AccountState = .loading
@Published var tabState: TabState = .statuses(statusesState: .loading) {
didSet {
/// Forward viewModel tabState related to statusesState to statusesState property
/// for `StatusesFetcher` conformance as we wrap StatusesState in TabState
switch tabState {
case let .statuses(statusesState):
self.statusesState = statusesState
default:
break
}
}
}
2022-12-18 19:30:19 +00:00
@Published var statusesState: StatusesState = .loading
2022-12-20 08:37:07 +00:00
@Published var title: String = ""
2022-12-20 16:11:12 +00:00
@Published var relationship: Relationshionship?
@Published var favourites: [Status] = []
@Published var followedTags: [Tag] = []
2022-12-21 19:26:38 +00:00
@Published var featuredTags: [FeaturedTag] = []
2022-12-21 19:53:23 +00:00
@Published var fields: [Account.Field] = []
@Published var selectedTab = Tab.statuses {
didSet {
2022-12-21 11:39:29 +00:00
reloadTabState()
}
}
2022-12-18 19:30:19 +00:00
2022-12-20 08:37:07 +00:00
private var account: Account?
2022-12-20 16:11:12 +00:00
2022-12-20 15:08:09 +00:00
private(set) var statuses: [Status] = []
2022-12-20 16:11:12 +00:00
private let isCurrentUser: Bool
2022-11-29 11:18:06 +00:00
/// When coming from a URL like a mention tap in a status.
2022-11-29 11:18:06 +00:00
init(accountId: String) {
self.accountId = accountId
2022-12-20 16:11:12 +00:00
self.isCurrentUser = false
2022-11-29 11:18:06 +00:00
}
/// When the account is already fetched by the parent caller.
2022-12-20 16:11:12 +00:00
init(account: Account, isCurrentUser: Bool) {
2022-12-17 12:37:46 +00:00
self.accountId = account.id
self.accountState = .data(account: account)
2022-12-20 16:11:12 +00:00
self.isCurrentUser = isCurrentUser
2022-12-17 12:37:46 +00:00
}
2022-11-29 11:18:06 +00:00
func fetchAccount() async {
2022-12-19 11:28:55 +00:00
guard let client else { return }
2022-11-29 11:18:06 +00:00
do {
2022-12-20 08:37:07 +00:00
let account: Account = try await client.get(endpoint: Accounts.accounts(id: accountId))
2022-12-21 19:53:23 +00:00
self.fields = account.fields
if isCurrentUser {
self.followedTags = try await client.get(endpoint: Accounts.followedTags)
} else {
2022-12-20 16:11:12 +00:00
let relationships: [Relationshionship] = try await client.get(endpoint: Accounts.relationships(id: accountId))
self.relationship = relationships.first
}
2022-12-21 19:26:38 +00:00
self.featuredTags = try await client.get(endpoint: Accounts.featuredTags(id: accountId))
self.featuredTags.sort { $0.statusesCountInt > $1.statusesCountInt }
2022-12-20 08:37:07 +00:00
self.title = account.displayName
accountState = .data(account: account)
2022-11-29 11:18:06 +00:00
} catch {
accountState = .error(error: error)
2022-11-29 11:18:06 +00:00
}
}
2022-12-18 19:30:19 +00:00
func fetchStatuses() async {
2022-12-19 11:28:55 +00:00
guard let client else { return }
2022-12-18 19:30:19 +00:00
do {
tabState = .statuses(statusesState: .loading)
2022-12-21 19:26:38 +00:00
statuses = try await client.get(endpoint: Accounts.statuses(id: accountId, sinceId: nil, tag: nil))
if isCurrentUser {
favourites = try await client.get(endpoint: Accounts.favourites)
}
2022-12-21 11:39:29 +00:00
reloadTabState()
2022-12-18 19:30:19 +00:00
} catch {
tabState = .statuses(statusesState: .error(error: error))
2022-12-18 19:30:19 +00:00
}
}
2022-12-19 06:17:01 +00:00
func fetchNextPage() async {
2022-12-19 11:28:55 +00:00
guard let client else { return }
2022-12-18 19:30:19 +00:00
do {
switch selectedTab {
case .statuses:
guard let lastId = statuses.last?.id else { return }
tabState = .statuses(statusesState: .display(statuses: statuses, nextPageState: .loadingNextPage))
2022-12-21 19:26:38 +00:00
let newStatuses: [Status] = try await client.get(endpoint: Accounts.statuses(id: accountId, sinceId: lastId, tag: nil))
statuses.append(contentsOf: newStatuses)
tabState = .statuses(statusesState: .display(statuses: statuses, nextPageState: .hasNextPage))
case .favourites, .followedTags:
break
}
2022-12-18 19:30:19 +00:00
} catch {
tabState = .statuses(statusesState: .error(error: error))
2022-12-18 19:30:19 +00:00
}
}
2022-12-20 16:11:12 +00:00
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)")
}
}
2022-12-21 11:39:29 +00:00
private func reloadTabState() {
switch selectedTab {
case .statuses:
tabState = .statuses(statusesState: .display(statuses: statuses, nextPageState: .hasNextPage))
case .favourites:
tabState = .statuses(statusesState: .display(statuses: favourites, nextPageState: .none))
case .followedTags:
tabState = .followedTags(tags: followedTags)
}
}
2022-11-29 11:18:06 +00:00
}