From 55b541403ea811521b4b618485452285133a6527 Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Mon, 1 Sep 2025 02:00:37 +0900 Subject: [PATCH 01/11] feat: refine `RuleView` --- DNSecure/Views/RuleView.swift | 311 +++++++++++++++++++++------------- 1 file changed, 193 insertions(+), 118 deletions(-) diff --git a/DNSecure/Views/RuleView.swift b/DNSecure/Views/RuleView.swift index 65e8fb7..9c14818 100644 --- a/DNSecure/Views/RuleView.swift +++ b/DNSecure/Views/RuleView.swift @@ -19,6 +19,199 @@ extension RuleView: View { LazyTextField("Name", text: self.$rule.name) } + Section("Matching Conditions") { + NavigationLink { + Form { + Section { + Picker("Interface Type", selection: self.$rule.interfaceType) { + ForEach(NEOnDemandRuleInterfaceType.allCases, id: \.self) { + Text($0.description) + } + } + .pickerStyle(.inline) + .labelsHidden() + } footer: { + Text( + "If the current primary network interface is of this type and all of the other conditions in the rule match, then the rule matches." + ) + } + } + .navigationTitle("Interface Type Match") + } label: { + HStack { + Text("Interface Type Match") + Spacer() + Text(self.rule.interfaceType.description) + .foregroundStyle(.secondary) + } + } + + if self.rule.interfaceType.isSSIDUsed { + NavigationLink { + Form { + Section { + ForEach(0.. Date: Tue, 2 Sep 2025 01:58:02 +0900 Subject: [PATCH 02/11] test: fix `RuleView` preview --- DNSecure/Views/RuleView.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DNSecure/Views/RuleView.swift b/DNSecure/Views/RuleView.swift index 9c14818..b73827a 100644 --- a/DNSecure/Views/RuleView.swift +++ b/DNSecure/Views/RuleView.swift @@ -225,5 +225,7 @@ extension RuleView: View { } #Preview { - RuleView(rule: .constant(OnDemandRule(name: "Preview Rule"))) + NavigationStack { + RuleView(rule: .constant(OnDemandRule(name: "Preview Rule"))) + } } From 2c3f8a4b2f3855d8342648f4106fd4cac220c905 Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Tue, 2 Sep 2025 02:24:37 +0900 Subject: [PATCH 03/11] refactor: divide each `Form` into its own separate file --- DNSecure/Views/DNSSearchDomainMatchView.swift | 46 +++++++ .../Views/DNSServerAddressMatchView.swift | 46 +++++++ DNSecure/Views/InterfaceTypeMatchView.swift | 35 +++++ DNSecure/Views/ProbeURLView.swift | 36 ++++++ DNSecure/Views/RuleView.swift | 120 +----------------- DNSecure/Views/SSIDMatchView.swift | 48 +++++++ 6 files changed, 216 insertions(+), 115 deletions(-) create mode 100644 DNSecure/Views/DNSSearchDomainMatchView.swift create mode 100644 DNSecure/Views/DNSServerAddressMatchView.swift create mode 100644 DNSecure/Views/InterfaceTypeMatchView.swift create mode 100644 DNSecure/Views/ProbeURLView.swift create mode 100644 DNSecure/Views/SSIDMatchView.swift diff --git a/DNSecure/Views/DNSSearchDomainMatchView.swift b/DNSecure/Views/DNSSearchDomainMatchView.swift new file mode 100644 index 0000000..12318da --- /dev/null +++ b/DNSecure/Views/DNSSearchDomainMatchView.swift @@ -0,0 +1,46 @@ +import NetworkExtension +import SwiftUI + +struct DNSSearchDomainMatchView { + @Binding var rule: OnDemandRule +} + +extension DNSSearchDomainMatchView: View { + var body: some View { + Form { + Section { + ForEach(0.. { + .init( + get: { self.rule.probeURL?.absoluteString ?? "" }, + set: { self.rule.probeURL = URL(string: $0) } + ) + } +} + +extension ProbeURLView: View { + var body: some View { + Form { + Section { + LazyTextField("Probe URL", text: self.probeURL) + } footer: { + Text( + "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." + ) + } + } + .navigationTitle("Probe URL") + } +} + +@available(iOS 17, *) +#Preview { + @Previewable @State var rule = OnDemandRule(name: "Preview Rule") + NavigationStack { + ProbeURLView(rule: $rule) + } +} diff --git a/DNSecure/Views/RuleView.swift b/DNSecure/Views/RuleView.swift index b73827a..e994a21 100644 --- a/DNSecure/Views/RuleView.swift +++ b/DNSecure/Views/RuleView.swift @@ -21,22 +21,7 @@ extension RuleView: View { Section("Matching Conditions") { NavigationLink { - Form { - Section { - Picker("Interface Type", selection: self.$rule.interfaceType) { - ForEach(NEOnDemandRuleInterfaceType.allCases, id: \.self) { - Text($0.description) - } - } - .pickerStyle(.inline) - .labelsHidden() - } footer: { - Text( - "If the current primary network interface is of this type and all of the other conditions in the rule match, then the rule matches." - ) - } - } - .navigationTitle("Interface Type Match") + InterfaceTypeMatchView(rule: self.$rule) } label: { HStack { Text("Interface Type Match") @@ -48,35 +33,7 @@ extension RuleView: View { if self.rule.interfaceType.isSSIDUsed { NavigationLink { - Form { - Section { - ForEach(0.. Date: Tue, 2 Sep 2025 02:26:14 +0900 Subject: [PATCH 04/11] fix: fix build failure --- DNSecure/Views/RuleView.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DNSecure/Views/RuleView.swift b/DNSecure/Views/RuleView.swift index e994a21..b6a4276 100644 --- a/DNSecure/Views/RuleView.swift +++ b/DNSecure/Views/RuleView.swift @@ -114,8 +114,10 @@ extension RuleView: View { } } +@available(iOS 17, *) #Preview { + @Previewable @State var rule = OnDemandRule(name: "Preview Rule") NavigationStack { - RuleView(rule: .constant(OnDemandRule(name: "Preview Rule"))) + RuleView(rule: $rule) } } From 7433d5545037360f4d02da634be43a40a69bb81d Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Tue, 2 Sep 2025 02:36:19 +0900 Subject: [PATCH 05/11] fix: fix build failure by converting groups into folders --- DNSecure.xcodeproj/project.pbxproj | 114 ++++++++++------------------- 1 file changed, 37 insertions(+), 77 deletions(-) diff --git a/DNSecure.xcodeproj/project.pbxproj b/DNSecure.xcodeproj/project.pbxproj index 7c3c3e6..5477d4b 100644 --- a/DNSecure.xcodeproj/project.pbxproj +++ b/DNSecure.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 70; objects = { /* Begin PBXBuildFile section */ @@ -23,14 +23,6 @@ 8940024E24ACBD2800EBE74B /* DNSecureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940024D24ACBD2800EBE74B /* DNSecureTests.swift */; }; 8940025924ACBD2800EBE74B /* DNSecureUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940025824ACBD2800EBE74B /* DNSecureUITests.swift */; }; 8940026924ACBE4900EBE74B /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8940026824ACBE4900EBE74B /* NetworkExtension.framework */; }; - 894958AD2548405E009691D5 /* RuleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 894958AC2548405E009691D5 /* RuleView.swift */; }; - 894F33652C46D2F00060F385 /* RestorationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 894F33642C46D2A20060F385 /* RestorationView.swift */; }; - 8963FDFB251DF1BC00E3DFE7 /* Bundle+displayName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8963FDFA251DF1BC00E3DFE7 /* Bundle+displayName.swift */; }; - 8986CDCF251D9B3400D947CD /* Resolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8986CDCE251D9B3400D947CD /* Resolver.swift */; }; - 8998041628DCDED800C8B421 /* DoTSections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8998041528DCDED800C8B421 /* DoTSections.swift */; }; - 8998041828DCDEEF00C8B421 /* DoHSections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8998041728DCDEEF00C8B421 /* DoHSections.swift */; }; - 89CB922125209DD100B6983C /* HowToActivateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CB922025209DD100B6983C /* HowToActivateView.swift */; }; - 89E8B71A29F80164002C2AEF /* LazyTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89E8B71929F80164002C2AEF /* LazyTextField.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -51,8 +43,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 890B80D4251DC3A20046BAA0 /* DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailView.swift; sourceTree = ""; }; - 890B80DE251DC6B50046BAA0 /* Presets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Presets.swift; sourceTree = ""; }; 8924EDF324C9CDF1004AF871 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 893AA852258F99630060B022 /* NEOnDemandRuleInterfaceType+CaseIterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+CaseIterable.swift"; sourceTree = ""; }; 893AA857258F996F0060B022 /* NEOnDemandRuleInterfaceType+CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+CustomStringConvertible.swift"; sourceTree = ""; }; @@ -62,29 +52,41 @@ 893AA86B258F99A10060B022 /* NEOnDemandRuleAction+CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleAction+CustomStringConvertible.swift"; sourceTree = ""; }; 893AA870258F99AD0060B022 /* NEOnDemandRuleAction+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleAction+Codable.swift"; sourceTree = ""; }; 8940023824ACBD2700EBE74B /* DNSecure.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DNSecure.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 8940023B24ACBD2700EBE74B /* DNSecureApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSecureApp.swift; sourceTree = ""; }; - 8940023D24ACBD2700EBE74B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; - 8940023F24ACBD2800EBE74B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 8940024224ACBD2800EBE74B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 8940024424ACBD2800EBE74B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8940024924ACBD2800EBE74B /* DNSecureTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DNSecureTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 8940024D24ACBD2800EBE74B /* DNSecureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSecureTests.swift; sourceTree = ""; }; - 8940024F24ACBD2800EBE74B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8940025424ACBD2800EBE74B /* DNSecureUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DNSecureUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 8940025824ACBD2800EBE74B /* DNSecureUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSecureUITests.swift; sourceTree = ""; }; - 8940025A24ACBD2800EBE74B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 8940026624ACBE4900EBE74B /* DNSecure.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DNSecure.entitlements; sourceTree = ""; }; 8940026824ACBE4900EBE74B /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; - 894958AC2548405E009691D5 /* RuleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleView.swift; sourceTree = ""; }; - 894F33642C46D2A20060F385 /* RestorationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationView.swift; sourceTree = ""; }; - 8963FDFA251DF1BC00E3DFE7 /* Bundle+displayName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+displayName.swift"; sourceTree = ""; }; - 8986CDCE251D9B3400D947CD /* Resolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Resolver.swift; sourceTree = ""; }; - 8998041528DCDED800C8B421 /* DoTSections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoTSections.swift; sourceTree = ""; }; - 8998041728DCDEEF00C8B421 /* DoHSections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoHSections.swift; sourceTree = ""; }; - 89CB922025209DD100B6983C /* HowToActivateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HowToActivateView.swift; sourceTree = ""; }; - 89E8B71929F80164002C2AEF /* LazyTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyTextField.swift; sourceTree = ""; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + 899AD03F2E66100500449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = 8940023724ACBD2700EBE74B /* DNSecure */; + }; + 899AD0442E66100E00449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + DNSecureTests.swift, + ); + target = 8940024824ACBD2800EBE74B /* DNSecureTests */; + }; + 899AD0492E66101100449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + DNSecureUITests.swift, + ); + target = 8940025324ACBD2800EBE74B /* DNSecureUITests */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 899AD0232E66100500449710 /* DNSecure */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (899AD03F2E66100500449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = DNSecure; sourceTree = ""; }; + 899AD0422E66100E00449710 /* DNSecureTests */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (899AD0442E66100E00449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = DNSecureTests; sourceTree = ""; }; + 899AD0472E66101100449710 /* DNSecureUITests */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (899AD0492E66101100449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = DNSecureUITests; sourceTree = ""; }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 8940023524ACBD2700EBE74B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -154,9 +156,9 @@ isa = PBXGroup; children = ( 8924EDF324C9CDF1004AF871 /* README.md */, - 8940023A24ACBD2700EBE74B /* DNSecure */, - 8940024C24ACBD2800EBE74B /* DNSecureTests */, - 8940025724ACBD2800EBE74B /* DNSecureUITests */, + 899AD0232E66100500449710 /* DNSecure */, + 899AD0422E66100E00449710 /* DNSecureTests */, + 899AD0472E66101100449710 /* DNSecureUITests */, 8940023924ACBD2700EBE74B /* Products */, 8940026724ACBE4900EBE74B /* Frameworks */, ); @@ -172,47 +174,6 @@ name = Products; sourceTree = ""; }; - 8940023A24ACBD2700EBE74B /* DNSecure */ = { - isa = PBXGroup; - children = ( - 8940026624ACBE4900EBE74B /* DNSecure.entitlements */, - 8940023B24ACBD2700EBE74B /* DNSecureApp.swift */, - 893AA816258F790D0060B022 /* Views */, - 893AA817258F79F70060B022 /* Models */, - 893AA818258F7A0C0060B022 /* Extensions */, - 8940023F24ACBD2800EBE74B /* Assets.xcassets */, - 8940024424ACBD2800EBE74B /* Info.plist */, - 8940024124ACBD2800EBE74B /* Preview Content */, - ); - path = DNSecure; - sourceTree = ""; - }; - 8940024124ACBD2800EBE74B /* Preview Content */ = { - isa = PBXGroup; - children = ( - 8940024224ACBD2800EBE74B /* Preview Assets.xcassets */, - ); - path = "Preview Content"; - sourceTree = ""; - }; - 8940024C24ACBD2800EBE74B /* DNSecureTests */ = { - isa = PBXGroup; - children = ( - 8940024D24ACBD2800EBE74B /* DNSecureTests.swift */, - 8940024F24ACBD2800EBE74B /* Info.plist */, - ); - path = DNSecureTests; - sourceTree = ""; - }; - 8940025724ACBD2800EBE74B /* DNSecureUITests */ = { - isa = PBXGroup; - children = ( - 8940025824ACBD2800EBE74B /* DNSecureUITests.swift */, - 8940025A24ACBD2800EBE74B /* Info.plist */, - ); - path = DNSecureUITests; - sourceTree = ""; - }; 8940026724ACBE4900EBE74B /* Frameworks */ = { isa = PBXGroup; children = ( @@ -236,6 +197,9 @@ ); dependencies = ( ); + fileSystemSynchronizedGroups = ( + 899AD0232E66100500449710 /* DNSecure */, + ); name = DNSecure; productName = DNSecure; productReference = 8940023824ACBD2700EBE74B /* DNSecure.app */; @@ -325,8 +289,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8940024324ACBD2800EBE74B /* Preview Assets.xcassets in Resources */, - 8940024024ACBD2800EBE74B /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -377,7 +339,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8940024E24ACBD2800EBE74B /* DNSecureTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -385,7 +346,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8940025924ACBD2800EBE74B /* DNSecureUITests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 67a8db045dd333fefdade7cdab6a463b836a76b3 Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Tue, 2 Sep 2025 02:51:07 +0900 Subject: [PATCH 06/11] refactor: use `LabeledContent` on newer OSes --- DNSecure/Views/RuleView.swift | 207 +++++++++++++++++++++++++--------- 1 file changed, 153 insertions(+), 54 deletions(-) diff --git a/DNSecure/Views/RuleView.swift b/DNSecure/Views/RuleView.swift index b6a4276..6ba4692 100644 --- a/DNSecure/Views/RuleView.swift +++ b/DNSecure/Views/RuleView.swift @@ -23,82 +23,33 @@ extension RuleView: View { NavigationLink { InterfaceTypeMatchView(rule: self.$rule) } label: { - HStack { - Text("Interface Type Match") - Spacer() - Text(self.rule.interfaceType.description) - .foregroundStyle(.secondary) - } + self.interfaceTypeMatchLabel } if self.rule.interfaceType.isSSIDUsed { NavigationLink { SSIDMatchView(rule: self.$rule) } label: { - HStack { - Text("SSID Match") - Spacer() - Group { - if !self.rule.ssidMatch.isEmpty { - Text("\(self.rule.ssidMatch.count)") - } else { - Text("Not Used") - } - } - .foregroundStyle(.secondary) - } + self.ssidMatchLabel } } NavigationLink { DNSSearchDomainMatchView(rule: self.$rule) } label: { - HStack { - Text("DNS Search Domain Match") - Spacer() - Group { - if !self.rule.dnsSearchDomainMatch.isEmpty { - Text("\(self.rule.dnsSearchDomainMatch.count)") - } else { - Text("Not Used") - } - } - .foregroundStyle(.secondary) - } + self.dnsSearchDomainMatchLabel } NavigationLink { DNSServerAddressMatchView(rule: self.$rule) } label: { - HStack { - Text("DNS Server Address Match") - Spacer() - Group { - if !self.rule.dnsServerAddressMatch.isEmpty { - Text("\(self.rule.dnsServerAddressMatch.count)") - } else { - Text("Not Used") - } - } - .foregroundStyle(.secondary) - } + self.dnsServerAddressMatchLabel } NavigationLink { ProbeURLView(rule: self.$rule) } label: { - HStack { - Text("Probe URL") - Spacer() - Group { - if let url = self.rule.probeURL?.absoluteString { - Text(url) - } else { - Text("Not Used") - } - } - .foregroundStyle(.secondary) - } + self.probeURLLabel } } @@ -112,6 +63,154 @@ extension RuleView: View { } .navigationTitle(self.rule.name) } + + private var interfaceTypeMatchLabel: some View { + @available(iOS 16, *) + var modern: some View { + LabeledContent("Interface Type Match", value: self.rule.interfaceType.description) + } + var legacy: some View { + HStack { + Text("Interface Type Match") + Spacer() + Text(self.rule.interfaceType.description) + .foregroundStyle(.secondary) + } + } + if #available(iOS 16, *) { + return modern + } else { + return legacy + } + } + + private var ssidMatchLabel: some View { + @available(iOS 16, *) + var modern: some View { + LabeledContent("SSID Match") { + if !self.rule.ssidMatch.isEmpty { + Text("\(self.rule.ssidMatch.count)") + } else { + Text("Not Used") + } + } + } + var legacy: some View { + HStack { + Text("SSID Match") + Spacer() + Group { + if !self.rule.ssidMatch.isEmpty { + Text("\(self.rule.ssidMatch.count)") + } else { + Text("Not Used") + } + } + .foregroundStyle(.secondary) + } + } + if #available(iOS 16, *) { + return modern + } else { + return legacy + } + } + + private var dnsSearchDomainMatchLabel: some View { + @available(iOS 16, *) + var modern: some View { + LabeledContent("DNS Search Domain Match") { + if !self.rule.dnsSearchDomainMatch.isEmpty { + Text("\(self.rule.dnsSearchDomainMatch.count)") + } else { + Text("Not Used") + } + } + } + var legacy: some View { + HStack { + Text("DNS Search Domain Match") + Spacer() + Group { + if !self.rule.dnsSearchDomainMatch.isEmpty { + Text("\(self.rule.dnsSearchDomainMatch.count)") + } else { + Text("Not Used") + } + } + .foregroundStyle(.secondary) + } + } + if #available(iOS 16, *) { + return modern + } else { + return legacy + } + } + + private var dnsServerAddressMatchLabel: some View { + @available(iOS 16, *) + var modern: some View { + LabeledContent("DNS Server Address Match") { + if !self.rule.dnsServerAddressMatch.isEmpty { + Text("\(self.rule.dnsServerAddressMatch.count)") + } else { + Text("Not Used") + } + } + } + var legacy: some View { + HStack { + Text("DNS Server Address Match") + Spacer() + Group { + if !self.rule.dnsServerAddressMatch.isEmpty { + Text("\(self.rule.dnsServerAddressMatch.count)") + } else { + Text("Not Used") + } + } + .foregroundStyle(.secondary) + } + } + if #available(iOS 16, *) { + return modern + } else { + return legacy + } + } + + private var probeURLLabel: some View { + @available(iOS 16, *) + var modern: some View { + LabeledContent("Probe URL") { + if let url = self.rule.probeURL?.absoluteString { + Text(url) + } else { + Text("Not Used") + } + } + } + var legacy: some View { + HStack { + Text("Probe URL") + Spacer() + Group { + if let url = self.rule.probeURL?.absoluteString { + Text(url) + } else { + Text("Not Used") + } + } + .foregroundStyle(.secondary) + } + } + if #available(iOS 16, *) { + return modern + } else { + return legacy + } + } } @available(iOS 17, *) From 0cec7bbf9c0a448b638f75d788117a066acd720b Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Tue, 2 Sep 2025 03:02:07 +0900 Subject: [PATCH 07/11] refactor: fix lint warnings --- DNSecure/Views/RuleView.swift | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/DNSecure/Views/RuleView.swift b/DNSecure/Views/RuleView.swift index 6ba4692..e7d253b 100644 --- a/DNSecure/Views/RuleView.swift +++ b/DNSecure/Views/RuleView.swift @@ -77,11 +77,10 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - if #available(iOS 16, *) { - return modern - } else { + guard #available(iOS 16, *) else { return legacy } + return modern } private var ssidMatchLabel: some View { @@ -109,11 +108,10 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - if #available(iOS 16, *) { - return modern - } else { + guard #available(iOS 16, *) else { return legacy } + return modern } private var dnsSearchDomainMatchLabel: some View { @@ -141,11 +139,10 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - if #available(iOS 16, *) { - return modern - } else { + guard #available(iOS 16, *) else { return legacy } + return modern } private var dnsServerAddressMatchLabel: some View { @@ -173,11 +170,10 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - if #available(iOS 16, *) { - return modern - } else { + guard #available(iOS 16, *) else { return legacy } + return modern } private var probeURLLabel: some View { @@ -205,11 +201,10 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - if #available(iOS 16, *) { - return modern - } else { + guard #available(iOS 16, *) else { return legacy } + return modern } } From 3d2c9d6019bc6fa34cd3115279ed36816ed3a168 Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Tue, 2 Sep 2025 23:06:10 +0900 Subject: [PATCH 08/11] fix: fix build failure --- DNSecure/Views/RuleView.swift | 60 +++++++++-------------------------- 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/DNSecure/Views/RuleView.swift b/DNSecure/Views/RuleView.swift index e7d253b..b23bc3c 100644 --- a/DNSecure/Views/RuleView.swift +++ b/DNSecure/Views/RuleView.swift @@ -64,12 +64,10 @@ extension RuleView: View { .navigationTitle(self.rule.name) } - private var interfaceTypeMatchLabel: some View { - @available(iOS 16, *) - var modern: some View { + @ViewBuilder private var interfaceTypeMatchLabel: some View { + if #available(iOS 16, *) { LabeledContent("Interface Type Match", value: self.rule.interfaceType.description) - } - var legacy: some View { + } else { HStack { Text("Interface Type Match") Spacer() @@ -77,15 +75,10 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - guard #available(iOS 16, *) else { - return legacy - } - return modern } - private var ssidMatchLabel: some View { - @available(iOS 16, *) - var modern: some View { + @ViewBuilder private var ssidMatchLabel: some View { + if #available(iOS 16, *) { LabeledContent("SSID Match") { if !self.rule.ssidMatch.isEmpty { Text("\(self.rule.ssidMatch.count)") @@ -93,8 +86,7 @@ extension RuleView: View { Text("Not Used") } } - } - var legacy: some View { + } else { HStack { Text("SSID Match") Spacer() @@ -108,15 +100,10 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - guard #available(iOS 16, *) else { - return legacy - } - return modern } - private var dnsSearchDomainMatchLabel: some View { - @available(iOS 16, *) - var modern: some View { + @ViewBuilder private var dnsSearchDomainMatchLabel: some View { + if #available(iOS 16, *) { LabeledContent("DNS Search Domain Match") { if !self.rule.dnsSearchDomainMatch.isEmpty { Text("\(self.rule.dnsSearchDomainMatch.count)") @@ -124,8 +111,7 @@ extension RuleView: View { Text("Not Used") } } - } - var legacy: some View { + } else { HStack { Text("DNS Search Domain Match") Spacer() @@ -139,15 +125,10 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - guard #available(iOS 16, *) else { - return legacy - } - return modern } - private var dnsServerAddressMatchLabel: some View { - @available(iOS 16, *) - var modern: some View { + @ViewBuilder private var dnsServerAddressMatchLabel: some View { + if #available(iOS 16, *) { LabeledContent("DNS Server Address Match") { if !self.rule.dnsServerAddressMatch.isEmpty { Text("\(self.rule.dnsServerAddressMatch.count)") @@ -155,8 +136,7 @@ extension RuleView: View { Text("Not Used") } } - } - var legacy: some View { + } else { HStack { Text("DNS Server Address Match") Spacer() @@ -170,15 +150,10 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - guard #available(iOS 16, *) else { - return legacy - } - return modern } - private var probeURLLabel: some View { - @available(iOS 16, *) - var modern: some View { + @ViewBuilder private var probeURLLabel: some View { + if #available(iOS 16, *) { LabeledContent("Probe URL") { if let url = self.rule.probeURL?.absoluteString { Text(url) @@ -186,8 +161,7 @@ extension RuleView: View { Text("Not Used") } } - } - var legacy: some View { + } else { HStack { Text("Probe URL") Spacer() @@ -201,10 +175,6 @@ extension RuleView: View { .foregroundStyle(.secondary) } } - guard #available(iOS 16, *) else { - return legacy - } - return modern } } From 103dc02919a1aafe595b0431f43269ed641b8fb3 Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Tue, 2 Sep 2025 23:07:04 +0900 Subject: [PATCH 09/11] chore: fix project file --- DNSecure.xcodeproj/project.pbxproj | 104 +++-------------------------- 1 file changed, 8 insertions(+), 96 deletions(-) diff --git a/DNSecure.xcodeproj/project.pbxproj b/DNSecure.xcodeproj/project.pbxproj index 5477d4b..0f24fbe 100644 --- a/DNSecure.xcodeproj/project.pbxproj +++ b/DNSecure.xcodeproj/project.pbxproj @@ -7,21 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 890B80D5251DC3A20046BAA0 /* DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890B80D4251DC3A20046BAA0 /* DetailView.swift */; }; - 890B80DF251DC6B50046BAA0 /* Presets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890B80DE251DC6B50046BAA0 /* Presets.swift */; }; - 893AA853258F99630060B022 /* NEOnDemandRuleInterfaceType+CaseIterable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893AA852258F99630060B022 /* NEOnDemandRuleInterfaceType+CaseIterable.swift */; }; - 893AA858258F996F0060B022 /* NEOnDemandRuleInterfaceType+CustomStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893AA857258F996F0060B022 /* NEOnDemandRuleInterfaceType+CustomStringConvertible.swift */; }; - 893AA85D258F997A0060B022 /* NEOnDemandRuleInterfaceType+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893AA85C258F997A0060B022 /* NEOnDemandRuleInterfaceType+Codable.swift */; }; - 893AA862258F998C0060B022 /* NEOnDemandRuleInterfaceType+isSSIDUsed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893AA861258F998C0060B022 /* NEOnDemandRuleInterfaceType+isSSIDUsed.swift */; }; - 893AA867258F99990060B022 /* NEOnDemandRuleAction+CaseIterable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893AA866258F99990060B022 /* NEOnDemandRuleAction+CaseIterable.swift */; }; - 893AA86C258F99A10060B022 /* NEOnDemandRuleAction+CustomStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893AA86B258F99A10060B022 /* NEOnDemandRuleAction+CustomStringConvertible.swift */; }; - 893AA871258F99AD0060B022 /* NEOnDemandRuleAction+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893AA870258F99AD0060B022 /* NEOnDemandRuleAction+Codable.swift */; }; - 8940023C24ACBD2700EBE74B /* DNSecureApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940023B24ACBD2700EBE74B /* DNSecureApp.swift */; }; - 8940023E24ACBD2700EBE74B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940023D24ACBD2700EBE74B /* ContentView.swift */; }; - 8940024024ACBD2800EBE74B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8940023F24ACBD2800EBE74B /* Assets.xcassets */; }; - 8940024324ACBD2800EBE74B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8940024224ACBD2800EBE74B /* Preview Assets.xcassets */; }; - 8940024E24ACBD2800EBE74B /* DNSecureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940024D24ACBD2800EBE74B /* DNSecureTests.swift */; }; - 8940025924ACBD2800EBE74B /* DNSecureUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8940025824ACBD2800EBE74B /* DNSecureUITests.swift */; }; 8940026924ACBE4900EBE74B /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8940026824ACBE4900EBE74B /* NetworkExtension.framework */; }; /* End PBXBuildFile section */ @@ -44,13 +29,6 @@ /* Begin PBXFileReference section */ 8924EDF324C9CDF1004AF871 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 893AA852258F99630060B022 /* NEOnDemandRuleInterfaceType+CaseIterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+CaseIterable.swift"; sourceTree = ""; }; - 893AA857258F996F0060B022 /* NEOnDemandRuleInterfaceType+CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+CustomStringConvertible.swift"; sourceTree = ""; }; - 893AA85C258F997A0060B022 /* NEOnDemandRuleInterfaceType+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+Codable.swift"; sourceTree = ""; }; - 893AA861258F998C0060B022 /* NEOnDemandRuleInterfaceType+isSSIDUsed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+isSSIDUsed.swift"; sourceTree = ""; }; - 893AA866258F99990060B022 /* NEOnDemandRuleAction+CaseIterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleAction+CaseIterable.swift"; sourceTree = ""; }; - 893AA86B258F99A10060B022 /* NEOnDemandRuleAction+CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleAction+CustomStringConvertible.swift"; sourceTree = ""; }; - 893AA870258F99AD0060B022 /* NEOnDemandRuleAction+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleAction+Codable.swift"; sourceTree = ""; }; 8940023824ACBD2700EBE74B /* DNSecure.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DNSecure.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8940024924ACBD2800EBE74B /* DNSecureTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DNSecureTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8940025424ACBD2800EBE74B /* DNSecureUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DNSecureUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -65,26 +43,12 @@ ); target = 8940023724ACBD2700EBE74B /* DNSecure */; }; - 899AD0442E66100E00449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - DNSecureTests.swift, - ); - target = 8940024824ACBD2800EBE74B /* DNSecureTests */; - }; - 899AD0492E66101100449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - DNSecureUITests.swift, - ); - target = 8940025324ACBD2800EBE74B /* DNSecureUITests */; - }; /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ 899AD0232E66100500449710 /* DNSecure */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (899AD03F2E66100500449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = DNSecure; sourceTree = ""; }; - 899AD0422E66100E00449710 /* DNSecureTests */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (899AD0442E66100E00449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = DNSecureTests; sourceTree = ""; }; - 899AD0472E66101100449710 /* DNSecureUITests */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (899AD0492E66101100449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = DNSecureUITests; sourceTree = ""; }; + 899AD0422E66100E00449710 /* DNSecureTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = DNSecureTests; sourceTree = ""; }; + 899AD0472E66101100449710 /* DNSecureUITests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = DNSecureUITests; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ @@ -113,45 +77,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 893AA816258F790D0060B022 /* Views */ = { - isa = PBXGroup; - children = ( - 894F33642C46D2A20060F385 /* RestorationView.swift */, - 8940023D24ACBD2700EBE74B /* ContentView.swift */, - 89CB922025209DD100B6983C /* HowToActivateView.swift */, - 890B80D4251DC3A20046BAA0 /* DetailView.swift */, - 894958AC2548405E009691D5 /* RuleView.swift */, - 8998041528DCDED800C8B421 /* DoTSections.swift */, - 8998041728DCDEEF00C8B421 /* DoHSections.swift */, - 89E8B71929F80164002C2AEF /* LazyTextField.swift */, - ); - path = Views; - sourceTree = ""; - }; - 893AA817258F79F70060B022 /* Models */ = { - isa = PBXGroup; - children = ( - 8986CDCE251D9B3400D947CD /* Resolver.swift */, - 890B80DE251DC6B50046BAA0 /* Presets.swift */, - ); - path = Models; - sourceTree = ""; - }; - 893AA818258F7A0C0060B022 /* Extensions */ = { - isa = PBXGroup; - children = ( - 8963FDFA251DF1BC00E3DFE7 /* Bundle+displayName.swift */, - 893AA852258F99630060B022 /* NEOnDemandRuleInterfaceType+CaseIterable.swift */, - 893AA857258F996F0060B022 /* NEOnDemandRuleInterfaceType+CustomStringConvertible.swift */, - 893AA85C258F997A0060B022 /* NEOnDemandRuleInterfaceType+Codable.swift */, - 893AA861258F998C0060B022 /* NEOnDemandRuleInterfaceType+isSSIDUsed.swift */, - 893AA866258F99990060B022 /* NEOnDemandRuleAction+CaseIterable.swift */, - 893AA86B258F99A10060B022 /* NEOnDemandRuleAction+CustomStringConvertible.swift */, - 893AA870258F99AD0060B022 /* NEOnDemandRuleAction+Codable.swift */, - ); - path = Extensions; - sourceTree = ""; - }; 8940022F24ACBD2700EBE74B = { isa = PBXGroup; children = ( @@ -218,6 +143,9 @@ dependencies = ( 8940024B24ACBD2800EBE74B /* PBXTargetDependency */, ); + fileSystemSynchronizedGroups = ( + 899AD0422E66100E00449710 /* DNSecureTests */, + ); name = DNSecureTests; productName = DNSecureTests; productReference = 8940024924ACBD2800EBE74B /* DNSecureTests.xctest */; @@ -236,6 +164,9 @@ dependencies = ( 8940025624ACBD2800EBE74B /* PBXTargetDependency */, ); + fileSystemSynchronizedGroups = ( + 899AD0472E66101100449710 /* DNSecureUITests */, + ); name = DNSecureUITests; productName = DNSecureUITests; productReference = 8940025424ACBD2800EBE74B /* DNSecureUITests.xctest */; @@ -313,25 +244,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8986CDCF251D9B3400D947CD /* Resolver.swift in Sources */, - 89CB922125209DD100B6983C /* HowToActivateView.swift in Sources */, - 890B80D5251DC3A20046BAA0 /* DetailView.swift in Sources */, - 893AA853258F99630060B022 /* NEOnDemandRuleInterfaceType+CaseIterable.swift in Sources */, - 893AA871258F99AD0060B022 /* NEOnDemandRuleAction+Codable.swift in Sources */, - 893AA85D258F997A0060B022 /* NEOnDemandRuleInterfaceType+Codable.swift in Sources */, - 894F33652C46D2F00060F385 /* RestorationView.swift in Sources */, - 8940023E24ACBD2700EBE74B /* ContentView.swift in Sources */, - 894958AD2548405E009691D5 /* RuleView.swift in Sources */, - 8998041828DCDEEF00C8B421 /* DoHSections.swift in Sources */, - 89E8B71A29F80164002C2AEF /* LazyTextField.swift in Sources */, - 890B80DF251DC6B50046BAA0 /* Presets.swift in Sources */, - 893AA858258F996F0060B022 /* NEOnDemandRuleInterfaceType+CustomStringConvertible.swift in Sources */, - 8940023C24ACBD2700EBE74B /* DNSecureApp.swift in Sources */, - 8998041628DCDED800C8B421 /* DoTSections.swift in Sources */, - 893AA862258F998C0060B022 /* NEOnDemandRuleInterfaceType+isSSIDUsed.swift in Sources */, - 893AA867258F99990060B022 /* NEOnDemandRuleAction+CaseIterable.swift in Sources */, - 893AA86C258F99A10060B022 /* NEOnDemandRuleAction+CustomStringConvertible.swift in Sources */, - 8963FDFB251DF1BC00E3DFE7 /* Bundle+displayName.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From ba48c966a1097b4da5a962e7c33a33f25163e240 Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Tue, 2 Sep 2025 23:36:57 +0900 Subject: [PATCH 10/11] fix: fix build failure --- DNSecure/Views/RuleView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/DNSecure/Views/RuleView.swift b/DNSecure/Views/RuleView.swift index b23bc3c..72dbe7d 100644 --- a/DNSecure/Views/RuleView.swift +++ b/DNSecure/Views/RuleView.swift @@ -12,6 +12,7 @@ struct RuleView { @Binding var rule: OnDemandRule } +@MainActor extension RuleView: View { var body: some View { Form { From caf33b9ce1e3252d87873d060790501a658855e1 Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Wed, 3 Sep 2025 00:29:20 +0900 Subject: [PATCH 11/11] fix: fix iOS 16 issue --- DNSecure/Views/ContentView.swift | 4 ++- DNSecure/Views/DetailView.swift | 47 -------------------------------- 2 files changed, 3 insertions(+), 48 deletions(-) diff --git a/DNSecure/Views/ContentView.swift b/DNSecure/Views/ContentView.swift index 904d5a7..c1fce01 100644 --- a/DNSecure/Views/ContentView.swift +++ b/DNSecure/Views/ContentView.swift @@ -188,7 +188,9 @@ extension ContentView: View { if self.selection == -1 { HowToActivateView() } else if let i = self.selection { - self.detailView(at: i) + NavigationStack { + self.detailView(at: i) + } } else if !self.isEnabled { HowToActivateView() } else { diff --git a/DNSecure/Views/DetailView.swift b/DNSecure/Views/DetailView.swift index 56782b3..29c4c5f 100644 --- a/DNSecure/Views/DetailView.swift +++ b/DNSecure/Views/DetailView.swift @@ -22,53 +22,6 @@ struct DetailView { @MainActor extension DetailView: View { var body: some View { - if #available(iOS 16, *) { - self.modernBody - } else { - self.legacyBody - } - } - - @available(iOS 16, *) - private var modernBody: some View { - NavigationStack { - Form { - Section { - Toggle("Use This Server", isOn: self.$isOn) - } - Section("Name") { - LazyTextField("Name", text: self.$server.name) - } - self.serverConfigurationSections - Section { - ForEach(self.server.onDemandRules) { rule in - NavigationLink(rule.name, value: rule.id) - } - .onDelete { self.server.onDemandRules.remove(atOffsets: $0) } - .onMove { self.server.onDemandRules.move(fromOffsets: $0, toOffset: $1) } - Button("Add New Rule") { - self.server.onDemandRules - .append(OnDemandRule(name: "New Rule")) - } - } header: { - EditButton() - .frame(maxWidth: .infinity, alignment: .trailing) - .overlay(alignment: .leading) { - Text("On Demand Rules") - } - } - } - .navigationDestination(for: UUID.self) { id in - // When RuleView is opened and tap another server on the sidebar, the previous server's rule comes here. - if self.server.onDemandRules.map(\.id).contains(id) { - RuleView(rule: self.binding(for: id)) - } - } - } - .navigationTitle(self.server.name) - } - - private var legacyBody: some View { Form { Section { Toggle("Use This Server", isOn: self.$isOn)