Merge pull request #84 from kkebo/restore-from-presets

This commit is contained in:
Kenta Kubo 2024-07-17 03:11:02 +09:00 committed by GitHub
commit 2a5c61fb6b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 88 additions and 0 deletions

View file

@ -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 */,

View file

@ -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()

View 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 }
}