140 lines
3.9 KiB
Swift
140 lines
3.9 KiB
Swift
//
|
|
// ManageSearchEnginesViewController.swift
|
|
// App
|
|
//
|
|
// Created by James Magahern on 9/29/25.
|
|
//
|
|
|
|
import SwiftUI
|
|
import UIKit
|
|
|
|
@MainActor
|
|
struct ManageSearchEnginesView: View
|
|
{
|
|
@State var model: ViewModel
|
|
|
|
var body: some View {
|
|
Form {
|
|
Section {
|
|
List($model.configuredEngines, editActions: .delete) { row in
|
|
HStack {
|
|
Image(uiImage: .checkmark)
|
|
.opacity(row.wrappedValue.isDefault ? 1.0 : 0.0)
|
|
|
|
VStack(alignment: .leading) {
|
|
Text(row.wrappedValue.name)
|
|
.font(.body)
|
|
.bold()
|
|
|
|
Text(row.wrappedValue.url)
|
|
.font(.caption)
|
|
}
|
|
}
|
|
.id(row.id)
|
|
|
|
.swipeActions(edge: .leading) {
|
|
Button { model.makeDefault(row.id) } label: {
|
|
Label("Make Default", systemImage: "checkmark")
|
|
}
|
|
.tint(.blue)
|
|
}
|
|
|
|
.swipeActions(edge: .trailing) {
|
|
Button(role: .destructive) { model.deleteEngine(row.id) } label: {
|
|
Label("Delete", systemImage: "trash")
|
|
}
|
|
.disabled(model.configuredEngines.count <= 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
Section {
|
|
Button("Add Search Engine…") {
|
|
model.onAddSearchEngine()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Types
|
|
|
|
@MainActor
|
|
@Observable
|
|
class ViewModel
|
|
{
|
|
var configuredEngines: [ConfiguredEngine] = []
|
|
var onAddSearchEngine: () -> Void = {}
|
|
var onChangeEngines: () -> Void = {}
|
|
|
|
init() {
|
|
reloadConfiguredEngines()
|
|
}
|
|
|
|
func reloadConfiguredEngines() {
|
|
let defaultEngine = Settings.shared.defaultSearchEngineName
|
|
self.configuredEngines = Settings.shared.searchEngines.map { val in
|
|
ConfiguredEngine(
|
|
name: val.key,
|
|
url: val.value,
|
|
isDefault: val.key == defaultEngine
|
|
)
|
|
}
|
|
}
|
|
|
|
func deleteEngine(_ id: ConfiguredEngine.ID) {
|
|
let engine = configuredEngines.first { $0.url == id }!
|
|
|
|
var engines = Settings.shared.searchEngines
|
|
engines.removeValue(forKey: engine.name)
|
|
Settings.shared.searchEngines = engines
|
|
|
|
if engine.isDefault {
|
|
// Pick another default
|
|
if let firstEngine = engines.first {
|
|
Settings.shared.defaultSearchEngineName = firstEngine.key
|
|
}
|
|
}
|
|
|
|
reloadConfiguredEngines()
|
|
onChangeEngines()
|
|
}
|
|
|
|
func makeDefault(_ id: ConfiguredEngine.ID) {
|
|
let engineName = configuredEngines.first { $0.url == id }!.name
|
|
Settings.shared.defaultSearchEngineName = engineName
|
|
|
|
reloadConfiguredEngines()
|
|
onChangeEngines()
|
|
}
|
|
}
|
|
|
|
struct ConfiguredEngine: Identifiable
|
|
{
|
|
let name: String
|
|
let url: String
|
|
let isDefault: Bool
|
|
|
|
var id: String { url }
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
class ManageSearchEnginesViewController: UIHostingController<ManageSearchEnginesView>
|
|
{
|
|
let model: ManageSearchEnginesView.ViewModel
|
|
|
|
init() {
|
|
self.model = ManageSearchEnginesView.ViewModel()
|
|
super.init(rootView: ManageSearchEnginesView(model: model))
|
|
}
|
|
|
|
required dynamic init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
@Previewable @State var model = ManageSearchEnginesView.ViewModel()
|
|
ManageSearchEnginesView(model: model)
|
|
}
|