mirror of
https://github.com/kkebo/DNSecure.git
synced 2026-03-11 08:54:36 +00:00
Merge pull request #121 from kkebo/refine-ruleview
feat: refine `RuleView`
This commit is contained in:
commit
5c96c63613
9 changed files with 396 additions and 324 deletions
|
|
@ -3,34 +3,11 @@
|
|||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 70;
|
||||
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 */; };
|
||||
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,40 +28,29 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
890B80D4251DC3A20046BAA0 /* DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailView.swift; sourceTree = "<group>"; };
|
||||
890B80DE251DC6B50046BAA0 /* Presets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Presets.swift; sourceTree = "<group>"; };
|
||||
8924EDF324C9CDF1004AF871 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
893AA852258F99630060B022 /* NEOnDemandRuleInterfaceType+CaseIterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+CaseIterable.swift"; sourceTree = "<group>"; };
|
||||
893AA857258F996F0060B022 /* NEOnDemandRuleInterfaceType+CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+CustomStringConvertible.swift"; sourceTree = "<group>"; };
|
||||
893AA85C258F997A0060B022 /* NEOnDemandRuleInterfaceType+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+Codable.swift"; sourceTree = "<group>"; };
|
||||
893AA861258F998C0060B022 /* NEOnDemandRuleInterfaceType+isSSIDUsed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleInterfaceType+isSSIDUsed.swift"; sourceTree = "<group>"; };
|
||||
893AA866258F99990060B022 /* NEOnDemandRuleAction+CaseIterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleAction+CaseIterable.swift"; sourceTree = "<group>"; };
|
||||
893AA86B258F99A10060B022 /* NEOnDemandRuleAction+CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleAction+CustomStringConvertible.swift"; sourceTree = "<group>"; };
|
||||
893AA870258F99AD0060B022 /* NEOnDemandRuleAction+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEOnDemandRuleAction+Codable.swift"; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
8940023D24ACBD2700EBE74B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
8940023F24ACBD2800EBE74B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
8940024224ACBD2800EBE74B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
8940024424ACBD2800EBE74B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
8940024F24ACBD2800EBE74B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
8940025A24ACBD2800EBE74B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
8940026624ACBE4900EBE74B /* DNSecure.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DNSecure.entitlements; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
894F33642C46D2A20060F385 /* RestorationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationView.swift; sourceTree = "<group>"; };
|
||||
8963FDFA251DF1BC00E3DFE7 /* Bundle+displayName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+displayName.swift"; sourceTree = "<group>"; };
|
||||
8986CDCE251D9B3400D947CD /* Resolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Resolver.swift; sourceTree = "<group>"; };
|
||||
8998041528DCDED800C8B421 /* DoTSections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoTSections.swift; sourceTree = "<group>"; };
|
||||
8998041728DCDEEF00C8B421 /* DoHSections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoHSections.swift; sourceTree = "<group>"; };
|
||||
89CB922025209DD100B6983C /* HowToActivateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HowToActivateView.swift; sourceTree = "<group>"; };
|
||||
89E8B71929F80164002C2AEF /* LazyTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyTextField.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
899AD03F2E66100500449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Info.plist,
|
||||
);
|
||||
target = 8940023724ACBD2700EBE74B /* DNSecure */;
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
899AD0232E66100500449710 /* DNSecure */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (899AD03F2E66100500449710 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = DNSecure; sourceTree = "<group>"; };
|
||||
899AD0422E66100E00449710 /* DNSecureTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = DNSecureTests; sourceTree = "<group>"; };
|
||||
899AD0472E66101100449710 /* DNSecureUITests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = DNSecureUITests; sourceTree = "<group>"; };
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
8940023524ACBD2700EBE74B /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
|
|
@ -111,52 +77,13 @@
|
|||
/* 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 = "<group>";
|
||||
};
|
||||
893AA817258F79F70060B022 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8986CDCE251D9B3400D947CD /* Resolver.swift */,
|
||||
890B80DE251DC6B50046BAA0 /* Presets.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
};
|
||||
8940022F24ACBD2700EBE74B = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8924EDF324C9CDF1004AF871 /* README.md */,
|
||||
8940023A24ACBD2700EBE74B /* DNSecure */,
|
||||
8940024C24ACBD2800EBE74B /* DNSecureTests */,
|
||||
8940025724ACBD2800EBE74B /* DNSecureUITests */,
|
||||
899AD0232E66100500449710 /* DNSecure */,
|
||||
899AD0422E66100E00449710 /* DNSecureTests */,
|
||||
899AD0472E66101100449710 /* DNSecureUITests */,
|
||||
8940023924ACBD2700EBE74B /* Products */,
|
||||
8940026724ACBE4900EBE74B /* Frameworks */,
|
||||
);
|
||||
|
|
@ -172,47 +99,6 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
};
|
||||
8940024124ACBD2800EBE74B /* Preview Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8940024224ACBD2800EBE74B /* Preview Assets.xcassets */,
|
||||
);
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8940024C24ACBD2800EBE74B /* DNSecureTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8940024D24ACBD2800EBE74B /* DNSecureTests.swift */,
|
||||
8940024F24ACBD2800EBE74B /* Info.plist */,
|
||||
);
|
||||
path = DNSecureTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8940025724ACBD2800EBE74B /* DNSecureUITests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8940025824ACBD2800EBE74B /* DNSecureUITests.swift */,
|
||||
8940025A24ACBD2800EBE74B /* Info.plist */,
|
||||
);
|
||||
path = DNSecureUITests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8940026724ACBE4900EBE74B /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -236,6 +122,9 @@
|
|||
);
|
||||
dependencies = (
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
899AD0232E66100500449710 /* DNSecure */,
|
||||
);
|
||||
name = DNSecure;
|
||||
productName = DNSecure;
|
||||
productReference = 8940023824ACBD2700EBE74B /* DNSecure.app */;
|
||||
|
|
@ -254,6 +143,9 @@
|
|||
dependencies = (
|
||||
8940024B24ACBD2800EBE74B /* PBXTargetDependency */,
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
899AD0422E66100E00449710 /* DNSecureTests */,
|
||||
);
|
||||
name = DNSecureTests;
|
||||
productName = DNSecureTests;
|
||||
productReference = 8940024924ACBD2800EBE74B /* DNSecureTests.xctest */;
|
||||
|
|
@ -272,6 +164,9 @@
|
|||
dependencies = (
|
||||
8940025624ACBD2800EBE74B /* PBXTargetDependency */,
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
899AD0472E66101100449710 /* DNSecureUITests */,
|
||||
);
|
||||
name = DNSecureUITests;
|
||||
productName = DNSecureUITests;
|
||||
productReference = 8940025424ACBD2800EBE74B /* DNSecureUITests.xctest */;
|
||||
|
|
@ -325,8 +220,6 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8940024324ACBD2800EBE74B /* Preview Assets.xcassets in Resources */,
|
||||
8940024024ACBD2800EBE74B /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -351,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;
|
||||
};
|
||||
|
|
@ -377,7 +251,6 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8940024E24ACBD2800EBE74B /* DNSecureTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -385,7 +258,6 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8940025924ACBD2800EBE74B /* DNSecureUITests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
46
DNSecure/Views/DNSSearchDomainMatchView.swift
Normal file
46
DNSecure/Views/DNSSearchDomainMatchView.swift
Normal file
|
|
@ -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..<self.rule.dnsSearchDomainMatch.count, id: \.self) { i in
|
||||
LazyTextField(
|
||||
"Search Domain",
|
||||
// self.$rule.dnsSearchDomainMatch[i] causes crash on deletion
|
||||
text: .init(
|
||||
get: { self.rule.dnsSearchDomainMatch[i] },
|
||||
set: { self.rule.dnsSearchDomainMatch[i] = $0 }
|
||||
)
|
||||
)
|
||||
}
|
||||
.onDelete { self.rule.dnsSearchDomainMatch.remove(atOffsets: $0) }
|
||||
.onMove { self.rule.dnsSearchDomainMatch.move(fromOffsets: $0, toOffset: $1) }
|
||||
Button("Add DNS Search Domain") {
|
||||
self.rule.dnsSearchDomainMatch.append("")
|
||||
}
|
||||
} footer: {
|
||||
Text(
|
||||
"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."
|
||||
)
|
||||
}
|
||||
}
|
||||
.navigationTitle("DNS Search Domain Match")
|
||||
.toolbar {
|
||||
EditButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17, *)
|
||||
#Preview {
|
||||
@Previewable @State var rule = OnDemandRule(name: "Preview Rule")
|
||||
NavigationStack {
|
||||
DNSSearchDomainMatchView(rule: $rule)
|
||||
}
|
||||
}
|
||||
46
DNSecure/Views/DNSServerAddressMatchView.swift
Normal file
46
DNSecure/Views/DNSServerAddressMatchView.swift
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import NetworkExtension
|
||||
import SwiftUI
|
||||
|
||||
struct DNSServerAddressMatchView {
|
||||
@Binding var rule: OnDemandRule
|
||||
}
|
||||
|
||||
extension DNSServerAddressMatchView: View {
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
ForEach(0..<self.rule.dnsServerAddressMatch.count, id: \.self) { i in
|
||||
LazyTextField(
|
||||
"IP Address",
|
||||
// self.$rule.dnsServerAddressMatch[i] causes crash on deletion
|
||||
text: .init(
|
||||
get: { self.rule.dnsServerAddressMatch[i] },
|
||||
set: { self.rule.dnsServerAddressMatch[i] = $0 }
|
||||
)
|
||||
)
|
||||
}
|
||||
.onDelete { self.rule.dnsServerAddressMatch.remove(atOffsets: $0) }
|
||||
.onMove { self.rule.dnsServerAddressMatch.move(fromOffsets: $0, toOffset: $1) }
|
||||
Button("Add DNS Server Address") {
|
||||
self.rule.dnsServerAddressMatch.append("")
|
||||
}
|
||||
} footer: {
|
||||
Text(
|
||||
"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."
|
||||
)
|
||||
}
|
||||
}
|
||||
.navigationTitle("DNS Server Address Match")
|
||||
.toolbar {
|
||||
EditButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17, *)
|
||||
#Preview {
|
||||
@Previewable @State var rule = OnDemandRule(name: "Preview Rule")
|
||||
NavigationStack {
|
||||
DNSServerAddressMatchView(rule: $rule)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
35
DNSecure/Views/InterfaceTypeMatchView.swift
Normal file
35
DNSecure/Views/InterfaceTypeMatchView.swift
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import NetworkExtension
|
||||
import SwiftUI
|
||||
|
||||
struct InterfaceTypeMatchView {
|
||||
@Binding var rule: OnDemandRule
|
||||
}
|
||||
|
||||
extension InterfaceTypeMatchView: View {
|
||||
var body: some View {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17, *)
|
||||
#Preview {
|
||||
@Previewable @State var rule = OnDemandRule(name: "Preview Rule")
|
||||
NavigationStack {
|
||||
InterfaceTypeMatchView(rule: $rule)
|
||||
}
|
||||
}
|
||||
36
DNSecure/Views/ProbeURLView.swift
Normal file
36
DNSecure/Views/ProbeURLView.swift
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import NetworkExtension
|
||||
import SwiftUI
|
||||
|
||||
struct ProbeURLView {
|
||||
@Binding var rule: OnDemandRule
|
||||
|
||||
private var probeURL: Binding<String> {
|
||||
.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)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ struct RuleView {
|
|||
@Binding var rule: OnDemandRule
|
||||
}
|
||||
|
||||
@MainActor
|
||||
extension RuleView: View {
|
||||
var body: some View {
|
||||
Form {
|
||||
|
|
@ -19,6 +20,40 @@ extension RuleView: View {
|
|||
LazyTextField("Name", text: self.$rule.name)
|
||||
}
|
||||
|
||||
Section("Matching Conditions") {
|
||||
NavigationLink {
|
||||
InterfaceTypeMatchView(rule: self.$rule)
|
||||
} label: {
|
||||
self.interfaceTypeMatchLabel
|
||||
}
|
||||
|
||||
if self.rule.interfaceType.isSSIDUsed {
|
||||
NavigationLink {
|
||||
SSIDMatchView(rule: self.$rule)
|
||||
} label: {
|
||||
self.ssidMatchLabel
|
||||
}
|
||||
}
|
||||
|
||||
NavigationLink {
|
||||
DNSSearchDomainMatchView(rule: self.$rule)
|
||||
} label: {
|
||||
self.dnsSearchDomainMatchLabel
|
||||
}
|
||||
|
||||
NavigationLink {
|
||||
DNSServerAddressMatchView(rule: self.$rule)
|
||||
} label: {
|
||||
self.dnsServerAddressMatchLabel
|
||||
}
|
||||
|
||||
NavigationLink {
|
||||
ProbeURLView(rule: self.$rule)
|
||||
} label: {
|
||||
self.probeURLLabel
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
Picker("Action", selection: self.$rule.action) {
|
||||
ForEach(NEOnDemandRuleAction.allCases, id: \.self) {
|
||||
|
|
@ -26,129 +61,128 @@ extension RuleView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
Picker("Interface Type", selection: self.$rule.interfaceType) {
|
||||
ForEach(NEOnDemandRuleInterfaceType.allCases, id: \.self) {
|
||||
Text($0.description)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Interface Type Match")
|
||||
} 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."
|
||||
)
|
||||
}
|
||||
|
||||
if self.rule.interfaceType.isSSIDUsed {
|
||||
Section {
|
||||
ForEach(0..<self.rule.ssidMatch.count, id: \.self) { i in
|
||||
LazyTextField(
|
||||
"SSID",
|
||||
// self.$rule.ssidMatch[i] causes crash on deletion
|
||||
text: .init(
|
||||
get: { self.rule.ssidMatch[i] },
|
||||
set: { self.rule.ssidMatch[i] = $0 }
|
||||
)
|
||||
)
|
||||
}
|
||||
.onDelete { self.rule.ssidMatch.remove(atOffsets: $0) }
|
||||
.onMove { self.rule.ssidMatch.move(fromOffsets: $0, toOffset: $1) }
|
||||
Button("Add SSID") {
|
||||
NEHotspotNetwork.fetchCurrent { network in
|
||||
self.rule.ssidMatch.append(network?.ssid ?? "")
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
EditButton()
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
.overlay(alignment: .leading) {
|
||||
Text("SSID Match")
|
||||
}
|
||||
} footer: {
|
||||
Text(
|
||||
"If the Service Set Identifier (SSID) of the current primary connected network matches one of the strings in this array and all of the other conditions in the rule match, then the rule matches."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
ForEach(0..<self.rule.dnsSearchDomainMatch.count, id: \.self) { i in
|
||||
LazyTextField(
|
||||
"Search Domain",
|
||||
// self.$rule.dnsSearchDomainMatch[i] causes crash on deletion
|
||||
text: .init(
|
||||
get: { self.rule.dnsSearchDomainMatch[i] },
|
||||
set: { self.rule.dnsSearchDomainMatch[i] = $0 }
|
||||
)
|
||||
)
|
||||
}
|
||||
.onDelete { self.rule.dnsSearchDomainMatch.remove(atOffsets: $0) }
|
||||
.onMove { self.rule.dnsSearchDomainMatch.move(fromOffsets: $0, toOffset: $1) }
|
||||
Button("Add DNS Search Domain") {
|
||||
self.rule.dnsSearchDomainMatch.append("")
|
||||
}
|
||||
} header: {
|
||||
EditButton()
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
.overlay(alignment: .leading) {
|
||||
Text("DNS Search Domain Match")
|
||||
}
|
||||
} footer: {
|
||||
Text(
|
||||
"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."
|
||||
)
|
||||
}
|
||||
|
||||
Section {
|
||||
ForEach(0..<self.rule.dnsServerAddressMatch.count, id: \.self) { i in
|
||||
LazyTextField(
|
||||
"IP Address",
|
||||
// self.$rule.dnsServerAddressMatch[i] causes crash on deletion
|
||||
text: .init(
|
||||
get: { self.rule.dnsServerAddressMatch[i] },
|
||||
set: { self.rule.dnsServerAddressMatch[i] = $0 }
|
||||
)
|
||||
)
|
||||
}
|
||||
.onDelete { self.rule.dnsServerAddressMatch.remove(atOffsets: $0) }
|
||||
.onMove { self.rule.dnsServerAddressMatch.move(fromOffsets: $0, toOffset: $1) }
|
||||
Button("Add DNS Server Address") {
|
||||
self.rule.dnsServerAddressMatch.append("")
|
||||
}
|
||||
} header: {
|
||||
EditButton()
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
.overlay(alignment: .leading) {
|
||||
Text("DNS Server Address Match")
|
||||
}
|
||||
} footer: {
|
||||
Text(
|
||||
"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."
|
||||
)
|
||||
}
|
||||
|
||||
Section {
|
||||
LazyTextField(
|
||||
"Probe URL",
|
||||
text: .init(
|
||||
get: { self.rule.probeURL?.absoluteString ?? "" },
|
||||
set: { self.rule.probeURL = URL(string: $0) }
|
||||
)
|
||||
)
|
||||
} header: {
|
||||
Text("Probe URL Match")
|
||||
} 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(self.rule.name)
|
||||
}
|
||||
|
||||
@ViewBuilder private var interfaceTypeMatchLabel: some View {
|
||||
if #available(iOS 16, *) {
|
||||
LabeledContent("Interface Type Match", value: self.rule.interfaceType.description)
|
||||
} else {
|
||||
HStack {
|
||||
Text("Interface Type Match")
|
||||
Spacer()
|
||||
Text(self.rule.interfaceType.description)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private var ssidMatchLabel: some View {
|
||||
if #available(iOS 16, *) {
|
||||
LabeledContent("SSID Match") {
|
||||
if !self.rule.ssidMatch.isEmpty {
|
||||
Text("\(self.rule.ssidMatch.count)")
|
||||
} else {
|
||||
Text("Not Used")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HStack {
|
||||
Text("SSID Match")
|
||||
Spacer()
|
||||
Group {
|
||||
if !self.rule.ssidMatch.isEmpty {
|
||||
Text("\(self.rule.ssidMatch.count)")
|
||||
} else {
|
||||
Text("Not Used")
|
||||
}
|
||||
}
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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)")
|
||||
} else {
|
||||
Text("Not Used")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HStack {
|
||||
Text("DNS Search Domain Match")
|
||||
Spacer()
|
||||
Group {
|
||||
if !self.rule.dnsSearchDomainMatch.isEmpty {
|
||||
Text("\(self.rule.dnsSearchDomainMatch.count)")
|
||||
} else {
|
||||
Text("Not Used")
|
||||
}
|
||||
}
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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)")
|
||||
} else {
|
||||
Text("Not Used")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HStack {
|
||||
Text("DNS Server Address Match")
|
||||
Spacer()
|
||||
Group {
|
||||
if !self.rule.dnsServerAddressMatch.isEmpty {
|
||||
Text("\(self.rule.dnsServerAddressMatch.count)")
|
||||
} else {
|
||||
Text("Not Used")
|
||||
}
|
||||
}
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private var probeURLLabel: some View {
|
||||
if #available(iOS 16, *) {
|
||||
LabeledContent("Probe URL") {
|
||||
if let url = self.rule.probeURL?.absoluteString {
|
||||
Text(url)
|
||||
} else {
|
||||
Text("Not Used")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HStack {
|
||||
Text("Probe URL")
|
||||
Spacer()
|
||||
Group {
|
||||
if let url = self.rule.probeURL?.absoluteString {
|
||||
Text(url)
|
||||
} else {
|
||||
Text("Not Used")
|
||||
}
|
||||
}
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17, *)
|
||||
#Preview {
|
||||
RuleView(rule: .constant(OnDemandRule(name: "Preview Rule")))
|
||||
@Previewable @State var rule = OnDemandRule(name: "Preview Rule")
|
||||
NavigationStack {
|
||||
RuleView(rule: $rule)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
48
DNSecure/Views/SSIDMatchView.swift
Normal file
48
DNSecure/Views/SSIDMatchView.swift
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import NetworkExtension
|
||||
import SwiftUI
|
||||
|
||||
struct SSIDMatchView {
|
||||
@Binding var rule: OnDemandRule
|
||||
}
|
||||
|
||||
extension SSIDMatchView: View {
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
ForEach(0..<self.rule.ssidMatch.count, id: \.self) { i in
|
||||
LazyTextField(
|
||||
"SSID",
|
||||
// self.$rule.ssidMatch[i] causes crash on deletion
|
||||
text: .init(
|
||||
get: { self.rule.ssidMatch[i] },
|
||||
set: { self.rule.ssidMatch[i] = $0 }
|
||||
)
|
||||
)
|
||||
}
|
||||
.onDelete { self.rule.ssidMatch.remove(atOffsets: $0) }
|
||||
.onMove { self.rule.ssidMatch.move(fromOffsets: $0, toOffset: $1) }
|
||||
Button("Add SSID") {
|
||||
NEHotspotNetwork.fetchCurrent { network in
|
||||
self.rule.ssidMatch.append(network?.ssid ?? "")
|
||||
}
|
||||
}
|
||||
} footer: {
|
||||
Text(
|
||||
"If the Service Set Identifier (SSID) of the current primary connected network matches one of the strings in this array and all of the other conditions in the rule match, then the rule matches."
|
||||
)
|
||||
}
|
||||
}
|
||||
.navigationTitle("SSID Match")
|
||||
.toolbar {
|
||||
EditButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17, *)
|
||||
#Preview {
|
||||
@Previewable @State var rule = OnDemandRule(name: "Preview Rule")
|
||||
NavigationStack {
|
||||
SSIDMatchView(rule: $rule)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue