IceCubesApp/Packages/Account/Sources/Account/AccountsList/AccountsListView.swift
Thomas Ricouard 1f858414d8 format .
2024-02-14 12:48:14 +01:00

156 lines
4.1 KiB
Swift

import DesignSystem
import Env
import Models
import Network
import SwiftUI
@MainActor
public struct AccountsListView: View {
@Environment(Theme.self) private var theme
@Environment(Client.self) private var client
@Environment(CurrentAccount.self) private var currentAccount
@State private var viewModel: AccountsListViewModel
@State private var didAppear: Bool = false
public init(mode: AccountsListMode) {
_viewModel = .init(initialValue: .init(mode: mode))
}
public var body: some View {
listView
#if !os(visionOS)
.scrollContentBackground(.hidden)
.background(theme.primaryBackgroundColor)
#endif
.listStyle(.plain)
.toolbar {
ToolbarItem(placement: .principal) {
VStack {
Text(viewModel.mode.title)
.font(.headline)
if let count = viewModel.totalCount {
Text(String(count))
.font(.footnote)
.foregroundStyle(.secondary)
}
}
}
}
.navigationTitle(viewModel.mode.title)
.navigationBarTitleDisplayMode(.inline)
.task {
viewModel.client = client
guard !didAppear else { return }
didAppear = true
await viewModel.fetch()
}
}
@ViewBuilder
private var listView: some View {
if currentAccount.account?.id == viewModel.accountId {
searchableList
} else {
standardList
}
}
private var searchableList: some View {
List {
listContent
}
.searchable(text: $viewModel.searchQuery,
placement: .navigationBarDrawer(displayMode: .always))
.task(id: viewModel.searchQuery) {
if !viewModel.searchQuery.isEmpty {
await viewModel.search()
}
}
.onChange(of: viewModel.searchQuery) { _, newValue in
if newValue.isEmpty {
Task {
await viewModel.fetch()
}
}
}
}
private var standardList: some View {
List {
listContent
}
}
@ViewBuilder
private var listContent: some View {
switch viewModel.state {
case .loading:
ForEach(Account.placeholders()) { _ in
AccountsListRow(viewModel: .init(account: .placeholder(), relationShip: .placeholder()))
.redacted(reason: .placeholder)
.allowsHitTesting(false)
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
case let .display(accounts, relationships, nextPageState):
if case .followers = viewModel.mode,
!currentAccount.followRequests.isEmpty
{
Section(
header: Text("account.follow-requests.pending-requests"),
footer: Text("account.follow-requests.instructions")
.font(.scaledFootnote)
.foregroundColor(.secondary)
.offset(y: -8)
) {
ForEach(currentAccount.followRequests) { account in
AccountsListRow(
viewModel: .init(account: account),
isFollowRequest: true,
requestUpdated: {
Task {
await viewModel.fetch()
}
}
)
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
}
}
Section {
ForEach(accounts) { account in
if let relationship = relationships.first(where: { $0.id == account.id }) {
AccountsListRow(viewModel: .init(account: account,
relationShip: relationship))
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
}
}
switch nextPageState {
case .hasNextPage:
NextPageView {
try await viewModel.fetchNextPage()
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
case .none:
EmptyView()
}
case let .error(error):
Text(error.localizedDescription)
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
}
}