mirror of
https://github.com/kkebo/DNSecure.git
synced 2026-03-11 08:54:36 +00:00
Merge pull request #84 from kkebo/restore-from-presets
This commit is contained in:
commit
2a5c61fb6b
3 changed files with 88 additions and 0 deletions
|
|
@ -24,6 +24,7 @@
|
|||
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 */; };
|
||||
|
|
@ -75,6 +76,7 @@
|
|||
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>"; };
|
||||
|
|
@ -112,6 +114,7 @@
|
|||
893AA816258F790D0060B022 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
894F33642C46D2A20060F385 /* RestorationView.swift */,
|
||||
8940023D24ACBD2700EBE74B /* ContentView.swift */,
|
||||
89CB922025209DD100B6983C /* HowToActivateView.swift */,
|
||||
890B80D4251DC3A20046BAA0 /* DetailView.swift */,
|
||||
|
|
@ -354,6 +357,7 @@
|
|||
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 */,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ struct ContentView {
|
|||
@State private var alertTitle = ""
|
||||
@State private var alertMessage = ""
|
||||
@State private var guideIsPresented = false
|
||||
@State private var isRestoring = false
|
||||
|
||||
private func addNewDoTServer() {
|
||||
self.servers.append(
|
||||
|
|
@ -40,6 +41,10 @@ struct ContentView {
|
|||
self.selection = self.servers.count - 1
|
||||
}
|
||||
|
||||
private func restoreFromPresets(resolvers: Set<Resolver>) {
|
||||
self.servers.append(contentsOf: resolvers)
|
||||
}
|
||||
|
||||
private func removeServers(at indexSet: IndexSet) {
|
||||
if let current = self.selection, indexSet.contains(where: { $0 <= current }) {
|
||||
// FIXME: This is a workaround not to crash on deletion.
|
||||
|
|
@ -271,9 +276,15 @@ extension ContentView: View {
|
|||
Menu {
|
||||
Button("DNS-over-TLS", action: self.addNewDoTServer)
|
||||
Button("DNS-over-HTTPS", action: self.addNewDoHServer)
|
||||
Button("Restore from Presets") {
|
||||
self.isRestoring = true
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
.sheet(isPresented: self.$isRestoring) {
|
||||
RestorationView(onAdd: self.restoreFromPresets)
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
EditButton()
|
||||
|
|
|
|||
73
DNSecure/Views/RestorationView.swift
Normal file
73
DNSecure/Views/RestorationView.swift
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// RestorationView.swift
|
||||
// DNSecure
|
||||
//
|
||||
// Created by Kenta Kubo on 7/17/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct RestorationView {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@State private var selection = Set<Resolver>()
|
||||
@State private var keyword = ""
|
||||
let onAdd: (Set<Resolver>) -> ()
|
||||
|
||||
private var servers: Resolvers {
|
||||
guard !self.keyword.isEmpty else { return Presets.servers }
|
||||
return Presets.servers.filter { $0.name.localizedCaseInsensitiveContains(self.keyword) }
|
||||
}
|
||||
}
|
||||
|
||||
extension RestorationView: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List(self.servers, id: \.self) { resolver in
|
||||
Button {
|
||||
if self.selection.contains(resolver) {
|
||||
self.selection.remove(resolver)
|
||||
} else {
|
||||
self.selection.insert(resolver)
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text(resolver.name)
|
||||
Text(resolver.configuration.description)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
if self.selection.contains(resolver) {
|
||||
Image(systemName: "checkmark")
|
||||
}
|
||||
}
|
||||
.tint(.primary)
|
||||
}
|
||||
}
|
||||
.navigationTitle("Presets")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button("Add") {
|
||||
self.onAdd(self.selection)
|
||||
self.dismiss()
|
||||
}
|
||||
.disabled(self.selection.isEmpty)
|
||||
}
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Cancel", role: .cancel) {
|
||||
self.dismiss()
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .bottomBar) {
|
||||
Text("\(self.selection.count) Selected")
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(.stack)
|
||||
.searchable(text: self.$keyword, placement: .navigationBarDrawer(displayMode: .always))
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
RestorationView { _ in }
|
||||
}
|
||||
Loading…
Reference in a new issue