cloud-dns-ios/dns/HomeView.swift

224 lines
8.1 KiB
Swift
Raw Permalink Normal View History

2026-04-13 14:18:42 +01:00
import SwiftUI
enum ServiceStatus {
case pending
case operational
case degraded
case outage
var description: String {
switch self {
case .pending:
return "Fetching service status"
case .operational:
return "No issues detected"
case .degraded:
return "Performance degraded"
case .outage:
return "Service disruption"
}
}
var color: Color {
switch self {
case .pending:
return .gray
case .operational:
return .green
case .degraded:
return .orange
case .outage:
return .red
}
}
}
struct HomeView: View {
@EnvironmentObject
private var viewModel: ViewModel
2026-04-13 14:18:42 +01:00
@State private var serviceStatus: ServiceStatus = .operational
private let falsePositiveURL = URL(string: "https://www.sr2.uk/contact")!
private let statusURL = URL(string:
"https://status.sr2.uk/")!
private let tosURL = URL(string: "https://www.sr2.uk/terms")!
private let privacyPolicyURL = URL(string: "https://www.sr2.uk/privacy")!
var body: some View {
NavigationStack {
List {
// Main toggle section
Section {
HStack {
VStack(alignment: .leading, spacing: 4) {
Text("DNS Protection")
.font(.headline)
Text(viewModel.isDnsEnabled ? "Active" : "Inactive")
2026-04-13 14:18:42 +01:00
.font(.caption)
.foregroundStyle(viewModel.isDnsEnabled ? .green : .secondary)
2026-04-13 14:18:42 +01:00
}
Spacer()
Toggle("", isOn: $viewModel.isDnsEnabled)
2026-04-13 14:18:42 +01:00
.labelsHidden()
.tint(.green)
}
.padding(.vertical, 4)
}
// Blocklist selection
Section {
ForEach(BlocklistOption.allCases) { option in
BlocklistRow(
option: option,
isSelected: viewModel.blocklist == option
2026-04-13 14:18:42 +01:00
)
.contentShape(Rectangle())
.onTapGesture {
guard option.enabled else { return }
withAnimation(.spring(duration: 0.3)) {
viewModel.blocklist = option
2026-04-13 14:18:42 +01:00
}
}
.opacity(option.enabled ? 1 : 0.6)
}
} header: {
Text("Blocklist")
} footer: {
Text("Select the level of protection for your DNS queries")
}
// Status section
if viewModel.isDnsEnabled {
2026-04-13 14:18:42 +01:00
Section {
HStack {
Label("Status", systemImage: "checkmark.circle.fill")
.foregroundStyle(.green)
Spacer()
Text("Connected")
.foregroundStyle(.secondary)
}
HStack {
Label("Server", systemImage: "server.rack")
Spacer()
Text(viewModel.blocklist.server)
2026-04-13 14:18:42 +01:00
.foregroundStyle(.secondary)
.font(.system(.body, design: .monospaced))
}
HStack {
Label("IPv4", systemImage: "globe")
Spacer()
Text(viewModel.blocklist.ipv4)
2026-04-13 14:18:42 +01:00
.foregroundStyle(.secondary)
.font(.system(.body, design: .monospaced))
}
HStack {
Label("IPv6", systemImage: "globe")
Spacer()
Text(viewModel.blocklist.ipv6)
2026-04-13 14:18:42 +01:00
.foregroundStyle(.secondary)
.font(.system(.body, design: .monospaced))
}
HStack {
Label("Domains in blocklist", systemImage: "xmark.shield.fill")
Spacer()
BlockedCount()
.foregroundStyle(.secondary)
}
} header: {
Text("Connection Details")
}
}
// Support section
Section {
Link(destination: falsePositiveURL) {
HStack {
Label {
Text("Report False Positive")
} icon: {
Image(systemName: "exclamationmark.bubble")
.foregroundStyle(.orange)
}
Spacer()
Image(systemName: "arrow.up.right.square")
.font(.caption)
.foregroundStyle(.secondary)
}
}.foregroundStyle(.primary)
} footer: {
Text("Submit incorrectly blocked domains for review")
}
// Service status section
Section {
Link(destination: statusURL) {
HStack(spacing: 12) {
Circle()
.fill(serviceStatus.color)
.frame(width: 12, height: 12)
VStack(alignment: .leading, spacing: 4) {
Text("Service Status")
.font(.headline)
Text(serviceStatus.description)
.font(.caption)
.foregroundStyle(.secondary)
}
Spacer()
Image(systemName: "arrow.up.right.square")
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(.vertical, 4)
}.foregroundStyle(.primary)
Link(destination: tosURL) {
HStack(spacing: 12) {
Image(systemName: "doc.text")
Text("Terms of Service")
Spacer()
Image(systemName: "arrow.up.right.square")
.font(.caption)
.foregroundStyle(.secondary)
}
}.foregroundStyle(.primary)
Link(destination: privacyPolicyURL) {
HStack(spacing: 12) {
Image(systemName: "doc.text")
Text("Privacy Policy")
Spacer()
Image(systemName: "arrow.up.right.square")
.font(.caption)
.foregroundStyle(.secondary)
}
}.foregroundStyle(.primary)
}
}
.navigationTitle("SR2® Cloud DNS")
.animation(.default, value: viewModel.isDnsEnabled)
2026-04-13 14:18:42 +01:00
}
}
}
#Preview {
HomeView()
.environmentObject(ViewModel())
2026-04-13 14:18:42 +01:00
}