cloud-dns-ios/dns/HomeView.swift

224 lines
9.2 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
struct HomeView: View {
@Environment(\.scenePhase)
private var scenePhase
@EnvironmentObject
private var viewModel: ViewModel
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 {
NavigationCompat {
List {
// Main toggle section
Section {
HStack {
VStack(alignment: .leading, spacing: 4) {
Text("DNS Protection")
.font(.headline)
Text(viewModel.isDnsEnabled ? "Active" : "Inactive")
.font(.caption)
.foregroundStyle(viewModel.isDnsEnabled ? .green : .secondary)
}
Spacer()
Toggle("", isOn: $viewModel.isDnsEnabled)
.labelsHidden()
.disabled(true)
.tint(.green)
}
.padding(.vertical, 4)
}
if !viewModel.isDnsEnabled {
Section {
VStack(alignment: .leading, spacing: 4) {
Text(String(format: NSLocalizedString("To enable %@:", comment: ""), ViewModel.title))
Text(String(format: NSLocalizedString("%1$@ Tap \"%2$@\"", comment: ""), "", NSLocalizedString("Open Settings", comment: "")))
Text(String(format: NSLocalizedString("%1$@ Go to General", comment: ""), ""))
Text(String(format: NSLocalizedString("%1$@ VPN & Network", comment: ""), ""))
Text(String(format: NSLocalizedString("%1$@ DNS", comment: ""), ""))
Text(String(format: NSLocalizedString("%1$@ Select \"%2$@\"", comment: ""), "", viewModel.blocklist.title))
Spacer()
Button {
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url)
}
} label: {
Text(NSLocalizedString("Open Settings", comment: ""))
.frame(maxWidth: .infinity, minHeight: 32)
}
.buttonStyle(.borderedProminent)
}
}
}
// Blocklist selection
Section {
ForEach(BlocklistOption.allCases) { option in
BlocklistRow(
option: option,
isSelected: viewModel.blocklist == option
)
.contentShape(Rectangle())
.onTapGesture {
guard option.enabled else { return }
withAnimation(.spring(duration: 0.3)) {
viewModel.blocklist = option
}
}
.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 {
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)
.foregroundStyle(.secondary)
.font(.system(.body, design: .monospaced))
}
HStack {
Label("IPv4", systemImage: "globe")
Spacer()
Text(viewModel.blocklist.ipv4)
.foregroundStyle(.secondary)
.font(.system(.body, design: .monospaced))
}
HStack {
Label("IPv6", systemImage: "globe")
Spacer()
Text(viewModel.blocklist.ipv6)
.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(viewModel.summaryStatus.color)
.frame(width: 12, height: 12)
VStack(alignment: .leading, spacing: 4) {
Text("Service Status")
.font(.headline)
Text(viewModel.summaryStatus.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(ViewModel.title)
.animation(.default, value: viewModel.isDnsEnabled)
.onChange(of: scenePhase) { _, newPhase in
if newPhase == .active {
Task {
await viewModel.refreshConfig()
}
}
}
}
}
}
#Preview {
HomeView()
.environmentObject(ViewModel())
}