krz/rune
an ios client for njalla
clone: git clone https://gitbay.org/krz/rune.git
main: Rune/Views/Domains/DomainListView.swift · raw
1import SwiftUI
2
3struct DomainListView: View {
4 @ObservedObject var viewModel: DomainViewModel
5 let client: NjallaClient?
6
7 var body: some View {
8 NavigationStack {
9 Group {
10 if let client {
11 content(client: client)
12 } else {
13 ContentUnavailableView("Sign in required", systemImage: "key.fill", description: Text("Add a valid Njalla API token to load domains."))
14 }
15 }
16 .navigationTitle("Domains")
17 }
18 }
19
20 @ViewBuilder
21 private func content(client: NjallaClient) -> some View {
22 List {
23 if let errorMessage = viewModel.domainsErrorMessage {
24 Section {
25 InlineErrorView(message: errorMessage, retryTitle: "Retry Domains") {
26 Task {
27 await viewModel.loadDomains(client: client)
28 }
29 }
30 .listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
31 }
32 }
33
34 if (!viewModel.hasLoadedDomains || viewModel.isLoadingDomains) && viewModel.domains.isEmpty {
35 Section {
36 HStack {
37 Spacer()
38 ProgressView("Loading Domains")
39 Spacer()
40 }
41 }
42 } else if viewModel.domains.isEmpty {
43 Section {
44 ContentUnavailableView(
45 "No Domains",
46 systemImage: "globe",
47 description: Text("No domains found. Pull to refresh after domains are added to this account.")
48 )
49 }
50 } else {
51 ForEach(viewModel.domains) { domain in
52 NavigationLink {
53 DomainDetailView(domainName: domain.name, viewModel: viewModel, client: client)
54 } label: {
55 DomainRow(domain: domain)
56 }
57 }
58 }
59 }
60 .listStyle(.insetGrouped)
61 .refreshable {
62 await viewModel.loadDomains(client: client)
63 }
64 }
65}
66
67private struct DomainRow: View {
68 let domain: Domain
69
70 var body: some View {
71 VStack(alignment: .leading, spacing: 6) {
72 Text(domain.name)
73 .font(.headline)
74
75 HStack {
76 if let status = domain.status {
77 Text(status)
78 }
79
80 if let expiry = domain.expiry {
81 Text("Expiry: \(expiry.formattedExpiry())")
82 }
83 }
84 .font(.subheadline)
85 .foregroundStyle(.secondary)
86
87 if let autorenew = domain.autorenew {
88 Text(autorenew ? "Autorenew On" : "Autorenew Off")
89 .font(.subheadline)
90 .foregroundStyle(.secondary)
91 }
92 }
93 .padding(.vertical, 4)
94 }
95}