Skip to content

Commit 5c96c63

Browse files
authored
Merge pull request #121 from kkebo/refine-ruleview
feat: refine `RuleView`
2 parents febbf73 + caf33b9 commit 5c96c63

9 files changed

Lines changed: 380 additions & 308 deletions

DNSecure.xcodeproj/project.pbxproj

Lines changed: 29 additions & 157 deletions
Large diffs are not rendered by default.

DNSecure/Views/ContentView.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,9 @@ extension ContentView: View {
188188
if self.selection == -1 {
189189
HowToActivateView()
190190
} else if let i = self.selection {
191-
self.detailView(at: i)
191+
NavigationStack {
192+
self.detailView(at: i)
193+
}
192194
} else if !self.isEnabled {
193195
HowToActivateView()
194196
} else {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import NetworkExtension
2+
import SwiftUI
3+
4+
struct DNSSearchDomainMatchView {
5+
@Binding var rule: OnDemandRule
6+
}
7+
8+
extension DNSSearchDomainMatchView: View {
9+
var body: some View {
10+
Form {
11+
Section {
12+
ForEach(0..<self.rule.dnsSearchDomainMatch.count, id: \.self) { i in
13+
LazyTextField(
14+
"Search Domain",
15+
// self.$rule.dnsSearchDomainMatch[i] causes crash on deletion
16+
text: .init(
17+
get: { self.rule.dnsSearchDomainMatch[i] },
18+
set: { self.rule.dnsSearchDomainMatch[i] = $0 }
19+
)
20+
)
21+
}
22+
.onDelete { self.rule.dnsSearchDomainMatch.remove(atOffsets: $0) }
23+
.onMove { self.rule.dnsSearchDomainMatch.move(fromOffsets: $0, toOffset: $1) }
24+
Button("Add DNS Search Domain") {
25+
self.rule.dnsSearchDomainMatch.append("")
26+
}
27+
} footer: {
28+
Text(
29+
"If the current default search domain is equal to one of the strings in this array and all of the other conditions in the rule match, then the rule matches."
30+
)
31+
}
32+
}
33+
.navigationTitle("DNS Search Domain Match")
34+
.toolbar {
35+
EditButton()
36+
}
37+
}
38+
}
39+
40+
@available(iOS 17, *)
41+
#Preview {
42+
@Previewable @State var rule = OnDemandRule(name: "Preview Rule")
43+
NavigationStack {
44+
DNSSearchDomainMatchView(rule: $rule)
45+
}
46+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import NetworkExtension
2+
import SwiftUI
3+
4+
struct DNSServerAddressMatchView {
5+
@Binding var rule: OnDemandRule
6+
}
7+
8+
extension DNSServerAddressMatchView: View {
9+
var body: some View {
10+
Form {
11+
Section {
12+
ForEach(0..<self.rule.dnsServerAddressMatch.count, id: \.self) { i in
13+
LazyTextField(
14+
"IP Address",
15+
// self.$rule.dnsServerAddressMatch[i] causes crash on deletion
16+
text: .init(
17+
get: { self.rule.dnsServerAddressMatch[i] },
18+
set: { self.rule.dnsServerAddressMatch[i] = $0 }
19+
)
20+
)
21+
}
22+
.onDelete { self.rule.dnsServerAddressMatch.remove(atOffsets: $0) }
23+
.onMove { self.rule.dnsServerAddressMatch.move(fromOffsets: $0, toOffset: $1) }
24+
Button("Add DNS Server Address") {
25+
self.rule.dnsServerAddressMatch.append("")
26+
}
27+
} footer: {
28+
Text(
29+
"If each of the current default DNS servers is equal to one of the strings in this array and all of the other conditions in the rule match, then the rule matches."
30+
)
31+
}
32+
}
33+
.navigationTitle("DNS Server Address Match")
34+
.toolbar {
35+
EditButton()
36+
}
37+
}
38+
}
39+
40+
@available(iOS 17, *)
41+
#Preview {
42+
@Previewable @State var rule = OnDemandRule(name: "Preview Rule")
43+
NavigationStack {
44+
DNSServerAddressMatchView(rule: $rule)
45+
}
46+
}

DNSecure/Views/DetailView.swift

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,53 +22,6 @@ struct DetailView {
2222
@MainActor
2323
extension DetailView: View {
2424
var body: some View {
25-
if #available(iOS 16, *) {
26-
self.modernBody
27-
} else {
28-
self.legacyBody
29-
}
30-
}
31-
32-
@available(iOS 16, *)
33-
private var modernBody: some View {
34-
NavigationStack {
35-
Form {
36-
Section {
37-
Toggle("Use This Server", isOn: self.$isOn)
38-
}
39-
Section("Name") {
40-
LazyTextField("Name", text: self.$server.name)
41-
}
42-
self.serverConfigurationSections
43-
Section {
44-
ForEach(self.server.onDemandRules) { rule in
45-
NavigationLink(rule.name, value: rule.id)
46-
}
47-
.onDelete { self.server.onDemandRules.remove(atOffsets: $0) }
48-
.onMove { self.server.onDemandRules.move(fromOffsets: $0, toOffset: $1) }
49-
Button("Add New Rule") {
50-
self.server.onDemandRules
51-
.append(OnDemandRule(name: "New Rule"))
52-
}
53-
} header: {
54-
EditButton()
55-
.frame(maxWidth: .infinity, alignment: .trailing)
56-
.overlay(alignment: .leading) {
57-
Text("On Demand Rules")
58-
}
59-
}
60-
}
61-
.navigationDestination(for: UUID.self) { id in
62-
// When RuleView is opened and tap another server on the sidebar, the previous server's rule comes here.
63-
if self.server.onDemandRules.map(\.id).contains(id) {
64-
RuleView(rule: self.binding(for: id))
65-
}
66-
}
67-
}
68-
.navigationTitle(self.server.name)
69-
}
70-
71-
private var legacyBody: some View {
7225
Form {
7326
Section {
7427
Toggle("Use This Server", isOn: self.$isOn)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import NetworkExtension
2+
import SwiftUI
3+
4+
struct InterfaceTypeMatchView {
5+
@Binding var rule: OnDemandRule
6+
}
7+
8+
extension InterfaceTypeMatchView: View {
9+
var body: some View {
10+
Form {
11+
Section {
12+
Picker("Interface Type", selection: self.$rule.interfaceType) {
13+
ForEach(NEOnDemandRuleInterfaceType.allCases, id: \.self) {
14+
Text($0.description)
15+
}
16+
}
17+
.pickerStyle(.inline)
18+
.labelsHidden()
19+
} footer: {
20+
Text(
21+
"If the current primary network interface is of this type and all of the other conditions in the rule match, then the rule matches."
22+
)
23+
}
24+
}
25+
.navigationTitle("Interface Type Match")
26+
}
27+
}
28+
29+
@available(iOS 17, *)
30+
#Preview {
31+
@Previewable @State var rule = OnDemandRule(name: "Preview Rule")
32+
NavigationStack {
33+
InterfaceTypeMatchView(rule: $rule)
34+
}
35+
}

DNSecure/Views/ProbeURLView.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import NetworkExtension
2+
import SwiftUI
3+
4+
struct ProbeURLView {
5+
@Binding var rule: OnDemandRule
6+
7+
private var probeURL: Binding<String> {
8+
.init(
9+
get: { self.rule.probeURL?.absoluteString ?? "" },
10+
set: { self.rule.probeURL = URL(string: $0) }
11+
)
12+
}
13+
}
14+
15+
extension ProbeURLView: View {
16+
var body: some View {
17+
Form {
18+
Section {
19+
LazyTextField("Probe URL", text: self.probeURL)
20+
} footer: {
21+
Text(
22+
"If a request sent to this URL results in a HTTP 200 OK response and all of the other conditions in the rule match, then the rule matches. If you don't want to use this rule, leave it empty."
23+
)
24+
}
25+
}
26+
.navigationTitle("Probe URL")
27+
}
28+
}
29+
30+
@available(iOS 17, *)
31+
#Preview {
32+
@Previewable @State var rule = OnDemandRule(name: "Preview Rule")
33+
NavigationStack {
34+
ProbeURLView(rule: $rule)
35+
}
36+
}

0 commit comments

Comments
 (0)