Impressia/Vernissage/Views/InstanceView.swift

142 lines
5.2 KiB
Swift
Raw Normal View History

2023-03-26 09:40:05 +02:00
//
// https://mczachurski.dev
// Copyright © 2023 Marcin Czachurski and the repository contributors.
2023-03-28 10:35:38 +02:00
// Licensed under the Apache License 2.0.
2023-03-26 09:40:05 +02:00
//
2023-03-26 09:40:05 +02:00
import SwiftUI
import Foundation
import PixelfedKit
2023-04-07 14:20:12 +02:00
import ClientKit
2023-04-07 14:38:50 +02:00
import ServicesKit
2023-03-26 09:40:05 +02:00
struct InstanceView: View {
@EnvironmentObject private var applicationState: ApplicationState
@EnvironmentObject private var routerPath: RouterPath
@EnvironmentObject private var client: Client
2023-03-26 09:40:05 +02:00
@State private var state: ViewState = .loading
@State private var instance: Instance?
var body: some View {
self.mainBody()
.navigationTitle("instance.navigationBar.title")
}
@ViewBuilder
private func mainBody() -> some View {
2023-03-26 09:40:05 +02:00
switch state {
case .loading:
LoadingIndicator()
.task {
await self.loadData()
}
case .loaded:
if let instance = self.instance {
self.details(instance: instance)
} else {
NoDataView(imageSystemName: "server.rack", text: "instance.error.noInstanceData")
}
case .error(let error):
ErrorView(error: error) {
self.state = .loading
await self.loadData()
}
.padding()
}
}
2023-03-26 09:40:05 +02:00
@ViewBuilder
private func details(instance: Instance) -> some View {
List {
Section("instance.title.instanceInfo") {
self.dataRow(title: "instance.title.name", value: instance.title ?? String.empty())
self.dataRow(title: "instance.title.address", value: "https://\(instance.uri)")
2023-03-26 09:40:05 +02:00
VStack(alignment: .leading) {
if let description = instance.description {
MarkdownFormattedText(description.asMarkdown)
.font(.subheadline)
.environment(\.openURL, OpenURLAction { url in
routerPath.handle(url: url)
})
.padding(.vertical, 4)
}
2023-03-26 09:40:05 +02:00
if let shortDescription = instance.shortDescription {
Text(shortDescription)
.font(.footnote)
.foregroundColor(.lightGrayColor)
}
}
2023-03-26 09:40:05 +02:00
self.dataRow(title: "instance.title.version", value: instance.version)
self.dataRow(title: "instance.title.users", value: "\(instance.stats?.userCount ?? 0)")
self.dataRow(title: "instance.title.posts", value: "\(instance.stats?.statusCount ?? 0)")
self.dataRow(title: "instance.title.domains", value: "\(instance.stats?.domainCount ?? 0)")
2023-03-26 09:40:05 +02:00
Toggle("instance.title.registrations", isOn: Binding.constant(instance.registrations))
.disabled(true)
Toggle("instance.title.approvalRequired", isOn: Binding.constant(instance.approvalRequired))
.disabled(true)
}
2023-03-26 09:40:05 +02:00
Section("instance.title.contact") {
self.dataRow(title: "instance.title.email", value: instance.email ?? String.empty())
2023-03-26 09:40:05 +02:00
if let contactAccount = instance.contactAccount {
NavigationLink(value: RouteurDestinations.userProfile(
accountId: contactAccount.id,
accountDisplayName: contactAccount.displayNameWithoutEmojis,
accountUserName: contactAccount.acct)
) {
HStack {
Text("instance.title.pixelfedAccount", comment: "Pixelfed account")
Spacer()
Text("@\(contactAccount.displayNameWithoutEmojis)")
.font(.subheadline)
.foregroundColor(.accentColor)
}
}
}
}
2023-03-26 09:40:05 +02:00
if let rules = self.instance?.rules {
Section("instance.title.rules") {
ForEach(rules, id: \.id) { rule in
Text(rule.text)
}
}
}
}
}
2023-03-26 09:40:05 +02:00
@ViewBuilder
private func dataRow(title: LocalizedStringKey, value: String) -> some View {
HStack {
Text(title, comment: "Title")
Spacer()
Text(value)
.foregroundColor(.lightGrayColor)
.font(.subheadline)
}
}
2023-03-26 09:40:05 +02:00
private func loadData() async {
do {
if let serverUrl = self.applicationState.account?.serverUrl {
self.instance = try await self.client.instances.instance(url: serverUrl)
}
2023-03-26 09:40:05 +02:00
self.state = .loaded
} catch {
if !Task.isCancelled {
ErrorService.shared.handle(error, message: "instance.error.loadingDataFailed", showToastr: true)
self.state = .error(error)
} else {
ErrorService.shared.handle(error, message: "instance.error.loadingDataFailed", showToastr: false)
}
}
}
}