2022-12-23 17:47:19 +00:00
|
|
|
import Models
|
|
|
|
import Network
|
2023-09-18 05:01:23 +00:00
|
|
|
import Observation
|
2023-01-17 10:36:01 +00:00
|
|
|
import SwiftUI
|
2022-12-23 17:47:19 +00:00
|
|
|
|
2022-12-24 12:41:25 +00:00
|
|
|
public enum AccountsListMode {
|
|
|
|
case following(accountId: String), followers(accountId: String)
|
2023-01-24 05:35:43 +00:00
|
|
|
case favoritedBy(statusId: String), rebloggedBy(statusId: String)
|
2023-02-13 06:00:42 +00:00
|
|
|
case accountsList(accounts: [Account])
|
2023-01-22 05:38:30 +00:00
|
|
|
|
2023-01-19 17:14:08 +00:00
|
|
|
var title: LocalizedStringKey {
|
2022-12-24 12:41:25 +00:00
|
|
|
switch self {
|
|
|
|
case .following:
|
2023-09-16 12:15:03 +00:00
|
|
|
"account.following"
|
2022-12-24 12:41:25 +00:00
|
|
|
case .followers:
|
2023-09-16 12:15:03 +00:00
|
|
|
"account.followers"
|
2023-01-24 05:35:43 +00:00
|
|
|
case .favoritedBy:
|
2023-09-16 12:15:03 +00:00
|
|
|
"account.favorited-by"
|
2022-12-24 12:41:25 +00:00
|
|
|
case .rebloggedBy:
|
2023-09-16 12:15:03 +00:00
|
|
|
"account.boosted-by"
|
2023-02-13 06:00:42 +00:00
|
|
|
case .accountsList:
|
2023-09-16 12:15:03 +00:00
|
|
|
""
|
2022-12-24 12:41:25 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-23 17:47:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@MainActor
|
2023-09-18 05:01:23 +00:00
|
|
|
@Observable class AccountsListViewModel {
|
2022-12-23 17:47:19 +00:00
|
|
|
var client: Client?
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 17:47:19 +00:00
|
|
|
let mode: AccountsListMode
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 17:47:19 +00:00
|
|
|
public enum State {
|
|
|
|
public enum PagingState {
|
|
|
|
case hasNextPage, loadingNextPage, none
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 17:47:19 +00:00
|
|
|
case loading
|
|
|
|
case display(accounts: [Account],
|
2023-01-17 14:14:50 +00:00
|
|
|
relationships: [Relationship],
|
2022-12-23 17:47:19 +00:00
|
|
|
nextPageState: PagingState)
|
|
|
|
case error(error: Error)
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 17:47:19 +00:00
|
|
|
private var accounts: [Account] = []
|
2023-01-17 14:14:50 +00:00
|
|
|
private var relationships: [Relationship] = []
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-09-18 05:01:23 +00:00
|
|
|
var state = State.loading
|
2024-01-01 16:29:15 +00:00
|
|
|
var totalCount: Int?
|
2024-01-09 12:28:51 +00:00
|
|
|
var accountId: String?
|
|
|
|
|
|
|
|
var searchQuery: String = ""
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-24 08:21:04 +00:00
|
|
|
private var nextPageId: String?
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-24 12:41:25 +00:00
|
|
|
init(mode: AccountsListMode) {
|
2022-12-23 17:47:19 +00:00
|
|
|
self.mode = mode
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 17:47:19 +00:00
|
|
|
func fetch() async {
|
|
|
|
guard let client else { return }
|
|
|
|
do {
|
|
|
|
state = .loading
|
2022-12-24 08:21:04 +00:00
|
|
|
let link: LinkHandler?
|
2022-12-23 17:47:19 +00:00
|
|
|
switch mode {
|
2022-12-24 12:41:25 +00:00
|
|
|
case let .followers(accountId):
|
2024-01-06 10:21:07 +00:00
|
|
|
let account: Account = try await client.get(endpoint: Accounts.accounts(id: accountId))
|
2024-01-01 16:29:15 +00:00
|
|
|
totalCount = account.followersCount
|
2022-12-24 08:21:04 +00:00
|
|
|
(accounts, link) = try await client.getWithLink(endpoint: Accounts.followers(id: accountId,
|
2022-12-24 12:41:25 +00:00
|
|
|
maxId: nil))
|
|
|
|
case let .following(accountId):
|
2024-01-09 12:28:51 +00:00
|
|
|
self.accountId = accountId
|
2024-01-06 10:21:07 +00:00
|
|
|
let account: Account = try await client.get(endpoint: Accounts.accounts(id: accountId))
|
2024-01-01 16:29:15 +00:00
|
|
|
totalCount = account.followingCount
|
2022-12-24 08:21:04 +00:00
|
|
|
(accounts, link) = try await client.getWithLink(endpoint: Accounts.following(id: accountId,
|
2022-12-24 12:41:25 +00:00
|
|
|
maxId: nil))
|
|
|
|
case let .rebloggedBy(statusId):
|
|
|
|
(accounts, link) = try await client.getWithLink(endpoint: Statuses.rebloggedBy(id: statusId,
|
|
|
|
maxId: nil))
|
2023-01-24 05:35:43 +00:00
|
|
|
case let .favoritedBy(statusId):
|
|
|
|
(accounts, link) = try await client.getWithLink(endpoint: Statuses.favoritedBy(id: statusId,
|
2023-01-25 12:02:28 +00:00
|
|
|
maxId: nil))
|
2023-02-13 06:00:42 +00:00
|
|
|
case let .accountsList(accounts):
|
|
|
|
self.accounts = accounts
|
|
|
|
link = nil
|
2022-12-23 17:47:19 +00:00
|
|
|
}
|
2022-12-24 08:21:04 +00:00
|
|
|
nextPageId = link?.maxId
|
2022-12-23 17:47:19 +00:00
|
|
|
relationships = try await client.get(endpoint:
|
2023-09-16 12:15:03 +00:00
|
|
|
Accounts.relationships(ids: accounts.map(\.id)))
|
2022-12-23 17:47:19 +00:00
|
|
|
state = .display(accounts: accounts,
|
|
|
|
relationships: relationships,
|
2022-12-24 14:09:17 +00:00
|
|
|
nextPageState: link?.maxId != nil ? .hasNextPage : .none)
|
2023-01-17 10:36:01 +00:00
|
|
|
} catch {}
|
2022-12-23 17:47:19 +00:00
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 17:47:19 +00:00
|
|
|
func fetchNextPage() async {
|
2022-12-24 08:21:04 +00:00
|
|
|
guard let client, let nextPageId else { return }
|
2022-12-23 17:47:19 +00:00
|
|
|
do {
|
|
|
|
state = .display(accounts: accounts, relationships: relationships, nextPageState: .loadingNextPage)
|
|
|
|
let newAccounts: [Account]
|
2022-12-24 08:21:04 +00:00
|
|
|
let link: LinkHandler?
|
2022-12-23 17:47:19 +00:00
|
|
|
switch mode {
|
2022-12-24 12:41:25 +00:00
|
|
|
case let .followers(accountId):
|
2022-12-24 08:21:04 +00:00
|
|
|
(newAccounts, link) = try await client.getWithLink(endpoint: Accounts.followers(id: accountId,
|
2022-12-24 12:41:25 +00:00
|
|
|
maxId: nextPageId))
|
|
|
|
case let .following(accountId):
|
2022-12-24 08:21:04 +00:00
|
|
|
(newAccounts, link) = try await client.getWithLink(endpoint: Accounts.following(id: accountId,
|
2022-12-24 12:41:25 +00:00
|
|
|
maxId: nextPageId))
|
|
|
|
case let .rebloggedBy(statusId):
|
|
|
|
(newAccounts, link) = try await client.getWithLink(endpoint: Statuses.rebloggedBy(id: statusId,
|
|
|
|
maxId: nextPageId))
|
2023-01-24 05:35:43 +00:00
|
|
|
case let .favoritedBy(statusId):
|
|
|
|
(newAccounts, link) = try await client.getWithLink(endpoint: Statuses.favoritedBy(id: statusId,
|
2023-01-25 12:02:28 +00:00
|
|
|
maxId: nextPageId))
|
2023-02-13 06:00:42 +00:00
|
|
|
case .accountsList:
|
|
|
|
newAccounts = []
|
|
|
|
link = nil
|
2022-12-23 17:47:19 +00:00
|
|
|
}
|
|
|
|
accounts.append(contentsOf: newAccounts)
|
2023-01-17 14:14:50 +00:00
|
|
|
let newRelationships: [Relationship] =
|
2023-09-16 12:15:03 +00:00
|
|
|
try await client.get(endpoint: Accounts.relationships(ids: newAccounts.map(\.id)))
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 17:47:19 +00:00
|
|
|
relationships.append(contentsOf: newRelationships)
|
2022-12-24 08:21:04 +00:00
|
|
|
self.nextPageId = link?.maxId
|
2022-12-23 17:47:19 +00:00
|
|
|
state = .display(accounts: accounts,
|
|
|
|
relationships: relationships,
|
2022-12-24 14:09:17 +00:00
|
|
|
nextPageState: link?.maxId != nil ? .hasNextPage : .none)
|
2022-12-23 17:47:19 +00:00
|
|
|
} catch {
|
|
|
|
print(error)
|
|
|
|
}
|
|
|
|
}
|
2024-01-09 12:28:51 +00:00
|
|
|
|
|
|
|
func search() async {
|
|
|
|
guard let client, !searchQuery.isEmpty else { return }
|
|
|
|
do {
|
|
|
|
state = .loading
|
|
|
|
try await Task.sleep(for: .milliseconds(250))
|
|
|
|
var results: SearchResults = try await client.get(endpoint: Search.search(query: searchQuery,
|
|
|
|
type: "accounts",
|
|
|
|
offset: nil,
|
|
|
|
following: true),
|
|
|
|
forceVersion: .v2)
|
|
|
|
let relationships: [Relationship] =
|
|
|
|
try await client.get(endpoint: Accounts.relationships(ids: results.accounts.map(\.id)))
|
|
|
|
results.relationships = relationships
|
|
|
|
withAnimation {
|
|
|
|
state = .display(accounts: results.accounts,
|
|
|
|
relationships: relationships,
|
|
|
|
nextPageState: .none)
|
|
|
|
}
|
|
|
|
} catch {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2022-12-23 17:47:19 +00:00
|
|
|
}
|