Compare commits
1 Commits
eab5301c2f
...
630caeceae
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
630caeceae |
74
App/Settings/AddSearchEngineViewController.swift
Normal file
74
App/Settings/AddSearchEngineViewController.swift
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// AddSearchEngineViewController.swift
|
||||||
|
// App
|
||||||
|
//
|
||||||
|
// Created by James Magahern on 9/29/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
struct AddSearchEngineView: View
|
||||||
|
{
|
||||||
|
@State var model: ViewModel
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Form {
|
||||||
|
Section {
|
||||||
|
HStack {
|
||||||
|
Text("Name")
|
||||||
|
TextField("Name", text: $model.name)
|
||||||
|
.multilineTextAlignment(.trailing)
|
||||||
|
.autocorrectionDisabled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Section {
|
||||||
|
HStack {
|
||||||
|
Text("URL")
|
||||||
|
TextField("https://example.com/query=%q", text: $model.url)
|
||||||
|
.multilineTextAlignment(.trailing)
|
||||||
|
.autocorrectionDisabled()
|
||||||
|
.textContentType(.none)
|
||||||
|
}
|
||||||
|
} footer: {
|
||||||
|
Text("URL must contain %q, which will be replaced by the query. ")
|
||||||
|
}
|
||||||
|
|
||||||
|
Section {
|
||||||
|
Toggle("Set as default", isOn: $model.makeDefault)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationTitle("Add Search Engine")
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
@Observable
|
||||||
|
class ViewModel
|
||||||
|
{
|
||||||
|
var name: String = ""
|
||||||
|
var url: String = ""
|
||||||
|
var makeDefault: Bool = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class AddSearchEngineViewController: UIHostingController<AddSearchEngineView>
|
||||||
|
{
|
||||||
|
public var viewModel: AddSearchEngineView.ViewModel
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.viewModel = AddSearchEngineView.ViewModel()
|
||||||
|
super.init(rootView: AddSearchEngineView(model: viewModel))
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor @preconcurrency required dynamic init?(coder aDecoder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
@Previewable @State var model = AddSearchEngineView.ViewModel()
|
||||||
|
AddSearchEngineView(model: model)
|
||||||
|
}
|
||||||
@@ -113,15 +113,11 @@ class GeneralSettingsViewController: UIViewController
|
|||||||
typealias Item = String
|
typealias Item = String
|
||||||
|
|
||||||
static let SearchProviderPopupItem = "searchProvider.popup"
|
static let SearchProviderPopupItem = "searchProvider.popup"
|
||||||
static let SearchEngineNameFieldItem = "searchEngine.add.name"
|
|
||||||
static let SearchEngineURLFieldItem = "searchEngine.add.url"
|
|
||||||
static let SyncServerItem = "syncServer.field"
|
static let SyncServerItem = "syncServer.field"
|
||||||
|
|
||||||
let dataSource: UICollectionViewDiffableDataSource<Section, Item>
|
let dataSource: UICollectionViewDiffableDataSource<Section, Item>
|
||||||
let collectionView: UICollectionView
|
let collectionView: UICollectionView
|
||||||
|
let viewModel: ViewModel
|
||||||
private var pendingEngineName: String = ""
|
|
||||||
private var pendingEngineURL: String = ""
|
|
||||||
|
|
||||||
static func createLayout(forIdiom idiom: UIUserInterfaceIdiom) -> UICollectionViewLayout {
|
static func createLayout(forIdiom idiom: UIUserInterfaceIdiom) -> UICollectionViewLayout {
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
@@ -171,7 +167,7 @@ class GeneralSettingsViewController: UIViewController
|
|||||||
textAlignment: .right
|
textAlignment: .right
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
var config = UIListContentConfiguration.plainHeader()
|
var config = UIListContentConfiguration.header()
|
||||||
config.text = sectionName
|
config.text = sectionName
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
@@ -189,41 +185,24 @@ class GeneralSettingsViewController: UIViewController
|
|||||||
Settings.shared.defaultSearchEngineName = engineName
|
Settings.shared.defaultSearchEngineName = engineName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let viewModel = ViewModel()
|
||||||
let itemCellRegistry = UICollectionView.CellRegistration<UICollectionViewCell, Item> { cell, indexPath, identifier in
|
let itemCellRegistry = UICollectionView.CellRegistration<UICollectionViewCell, Item> { cell, indexPath, identifier in
|
||||||
if identifier == Self.SearchProviderPopupItem {
|
if identifier == Self.SearchProviderPopupItem {
|
||||||
let names = Settings.shared.searchEngines.keys.sorted()
|
let names = Settings.shared.searchEngines.keys.sorted()
|
||||||
let menu = UIMenu(children: names.map { name in
|
var engineMenuItems: [UIMenuElement] = names.map { name in
|
||||||
let action = UIAction(title: name, handler: actionHandler)
|
let action = UIAction(title: name, handler: actionHandler)
|
||||||
action.state = (Settings.shared.defaultSearchEngineName == name) ? .on : .off
|
action.state = (Settings.shared.defaultSearchEngineName == name) ? .on : .off
|
||||||
return action
|
return action
|
||||||
|
}
|
||||||
|
|
||||||
|
engineMenuItems.append(UIMenu(options: .displayInline, children: [
|
||||||
|
UIAction(title: "Manage Search Engines…", handler: { _ in
|
||||||
|
viewModel.onManageSearchEngines()
|
||||||
})
|
})
|
||||||
|
]))
|
||||||
|
|
||||||
|
let menu = UIMenu(children: engineMenuItems)
|
||||||
cell.contentConfiguration = ButtonContentConfiguration(menu: menu)
|
cell.contentConfiguration = ButtonContentConfiguration(menu: menu)
|
||||||
} else if identifier == Self.SearchEngineNameFieldItem {
|
|
||||||
cell.contentConfiguration = TextFieldContentConfiguration(
|
|
||||||
text: self.pendingEngineName,
|
|
||||||
placeholderText: "Name (e.g., Startpage)",
|
|
||||||
textChanged: { [weak self] newString in
|
|
||||||
self?.pendingEngineName = newString
|
|
||||||
},
|
|
||||||
pressedReturn: { $0.resignFirstResponder() },
|
|
||||||
keyboardType: .default,
|
|
||||||
returnKeyType: .next
|
|
||||||
)
|
|
||||||
} else if identifier == Self.SearchEngineURLFieldItem {
|
|
||||||
cell.contentConfiguration = TextFieldContentConfiguration(
|
|
||||||
text: self.pendingEngineURL,
|
|
||||||
placeholderText: "URL template (use %q or %s)",
|
|
||||||
textChanged: { [weak self] newString in
|
|
||||||
self?.pendingEngineURL = newString
|
|
||||||
},
|
|
||||||
pressedReturn: { [weak self] textField in
|
|
||||||
guard let self = self else { return }
|
|
||||||
self.tryAddPendingSearchEngine()
|
|
||||||
textField.resignFirstResponder()
|
|
||||||
},
|
|
||||||
keyboardType: .URL,
|
|
||||||
returnKeyType: .done
|
|
||||||
)
|
|
||||||
} else if identifier == Self.SyncServerItem {
|
} else if identifier == Self.SyncServerItem {
|
||||||
cell.contentConfiguration = TextFieldContentConfiguration(
|
cell.contentConfiguration = TextFieldContentConfiguration(
|
||||||
text: Settings.shared.syncServer ?? "",
|
text: Settings.shared.syncServer ?? "",
|
||||||
@@ -238,7 +217,7 @@ class GeneralSettingsViewController: UIViewController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if !targetEnvironment(macCatalyst)
|
#if !targetEnvironment(macCatalyst)
|
||||||
cell.backgroundConfiguration = UIBackgroundConfiguration.listGroupedCell()
|
cell.backgroundConfiguration = UIBackgroundConfiguration.listCell()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,11 +240,66 @@ class GeneralSettingsViewController: UIViewController
|
|||||||
return collectionView.dequeueConfiguredReusableSupplementary(using: sectionHeaderRegistry, for: indexPath)
|
return collectionView.dequeueConfiguredReusableSupplementary(using: sectionHeaderRegistry, for: indexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.viewModel = viewModel
|
||||||
|
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
tabBarItem.title = "General"
|
tabBarItem.title = "General"
|
||||||
tabBarItem.image = UIImage(systemName: "gear")
|
tabBarItem.image = UIImage(systemName: "gear")
|
||||||
|
|
||||||
|
let resetPopup = { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
var snapshot = dataSource.snapshot()
|
||||||
|
snapshot.reloadItems([ Self.SearchProviderPopupItem ])
|
||||||
|
dataSource.apply(snapshot, animatingDifferences: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.onManageSearchEngines = { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
// Reset menu item (to show currently selected search engine)
|
||||||
|
resetPopup()
|
||||||
|
|
||||||
|
let viewController = ManageSearchEnginesViewController()
|
||||||
|
viewController.title = "Manage Search Engines"
|
||||||
|
|
||||||
|
viewController.model.onAddSearchEngine = { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
let addSearchEngineViewController = AddSearchEngineViewController()
|
||||||
|
let navController = UINavigationController(rootViewController: addSearchEngineViewController)
|
||||||
|
|
||||||
|
// Cancel
|
||||||
|
addSearchEngineViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .cancel, primaryAction: UIAction { _ in
|
||||||
|
navController.dismiss(animated: true)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Done
|
||||||
|
addSearchEngineViewController.navigationItem.rightBarButtonItem = UIBarButtonItem(systemItem: .done, primaryAction: UIAction { [weak self] _ in
|
||||||
|
self?.saveCustomSearchEngine(model: addSearchEngineViewController.viewModel)
|
||||||
|
navController.dismiss(animated: true)
|
||||||
|
|
||||||
|
resetPopup()
|
||||||
|
viewController.model.reloadConfiguredEngines()
|
||||||
|
})
|
||||||
|
|
||||||
|
self.present(navController, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewController.model.onChangeEngines = {
|
||||||
|
resetPopup()
|
||||||
|
}
|
||||||
|
|
||||||
|
#if targetEnvironment(macCatalyst)
|
||||||
|
let alertController = UIAlertController(title: "Not yet implemented for macOS.", message: nil, preferredStyle: .alert)
|
||||||
|
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in alertController.dismiss(animated: true) }))
|
||||||
|
present(alertController, animated: true)
|
||||||
|
#else
|
||||||
|
navigationController?.pushViewController(viewController, animated: true)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@@ -281,6 +315,14 @@ class GeneralSettingsViewController: UIViewController
|
|||||||
applySnapshot(animatingDifferences: false)
|
applySnapshot(animatingDifferences: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Types
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
@Observable
|
||||||
|
class ViewModel
|
||||||
|
{
|
||||||
|
var onManageSearchEngines: () -> Void = {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension GeneralSettingsViewController : UICollectionViewDelegate {
|
extension GeneralSettingsViewController : UICollectionViewDelegate {
|
||||||
@@ -293,17 +335,16 @@ private extension GeneralSettingsViewController {
|
|||||||
func applySnapshot(animatingDifferences: Bool) {
|
func applySnapshot(animatingDifferences: Bool) {
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
snapshot.appendSections(Section.allCases)
|
snapshot.appendSections(Section.allCases)
|
||||||
snapshot.appendItems([ Self.SearchProviderPopupItem,
|
snapshot.appendItems([ Self.SearchProviderPopupItem ], toSection: .searchEngine)
|
||||||
Self.SearchEngineNameFieldItem,
|
|
||||||
Self.SearchEngineURLFieldItem ], toSection: .searchEngine)
|
|
||||||
snapshot.appendItems([ Self.SyncServerItem ], toSection: .syncServer)
|
snapshot.appendItems([ Self.SyncServerItem ], toSection: .syncServer)
|
||||||
dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
|
dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryAddPendingSearchEngine() {
|
func saveCustomSearchEngine(model: AddSearchEngineView.ViewModel) {
|
||||||
let name = pendingEngineName.trimmingCharacters(in: .whitespacesAndNewlines)
|
let name = model.name.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
let url = pendingEngineURL.trimmingCharacters(in: .whitespacesAndNewlines)
|
let url = model.url.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
guard !name.isEmpty, !url.isEmpty else { return }
|
guard !name.isEmpty, !url.isEmpty else { return }
|
||||||
|
|
||||||
// Require placeholder
|
// Require placeholder
|
||||||
guard url.contains("%q") || url.contains("%s") else { return }
|
guard url.contains("%q") || url.contains("%s") else { return }
|
||||||
|
|
||||||
@@ -312,9 +353,13 @@ private extension GeneralSettingsViewController {
|
|||||||
engines[name] = url
|
engines[name] = url
|
||||||
Settings.shared.searchEngines = engines
|
Settings.shared.searchEngines = engines
|
||||||
|
|
||||||
|
if model.makeDefault {
|
||||||
|
Settings.shared.defaultSearchEngineName = name
|
||||||
|
}
|
||||||
|
|
||||||
// Reset inputs and refresh UI
|
// Reset inputs and refresh UI
|
||||||
pendingEngineName = ""
|
var snapshot = dataSource.snapshot()
|
||||||
pendingEngineURL = ""
|
snapshot.reloadItems([ Self.SearchProviderPopupItem ])
|
||||||
applySnapshot(animatingDifferences: true)
|
dataSource.apply(snapshot, animatingDifferences: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
139
App/Settings/ManageSearchEnginesViewController.swift
Normal file
139
App/Settings/ManageSearchEnginesViewController.swift
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
@@ -81,8 +81,6 @@ class Settings
|
|||||||
public var searchEngines: [String: String] = [
|
public var searchEngines: [String: String] = [
|
||||||
"Google": "https://google.com/search?q=%q&gbv=1",
|
"Google": "https://google.com/search?q=%q&gbv=1",
|
||||||
"DuckDuckGo": "https://html.duckduckgo.com/html/?q=%q",
|
"DuckDuckGo": "https://html.duckduckgo.com/html/?q=%q",
|
||||||
"Searx.nor": "http://searx.nor/search?q=%q&categories=general",
|
|
||||||
"Whoogle.nor": "http://whoogle.nor/search?q=%q"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// Name of the default search engine from `searchEngines`
|
// Name of the default search engine from `searchEngines`
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
CD361CF6271A3718006E9CA5 /* SBRScriptPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = CD361CF5271A3718006E9CA5 /* SBRScriptPolicy.m */; };
|
CD361CF6271A3718006E9CA5 /* SBRScriptPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = CD361CF5271A3718006E9CA5 /* SBRScriptPolicy.m */; };
|
||||||
CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */; };
|
CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */; };
|
||||||
CD470C4425DE070400AFBE0E /* BrowserViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */; };
|
CD470C4425DE070400AFBE0E /* BrowserViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */; };
|
||||||
|
CD4930D92E8B390200ADDE99 /* AddSearchEngineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4930D82E8B38FC00ADDE99 /* AddSearchEngineViewController.swift */; };
|
||||||
|
CD4930DB2E8B3F6500ADDE99 /* ManageSearchEnginesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4930DA2E8B3F5B00ADDE99 /* ManageSearchEnginesViewController.swift */; };
|
||||||
CD7313E22705349700053347 /* ScriptPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7313E12705349700053347 /* ScriptPolicyViewController.swift */; };
|
CD7313E22705349700053347 /* ScriptPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7313E12705349700053347 /* ScriptPolicyViewController.swift */; };
|
||||||
CD7313E4270534B800053347 /* ScriptPolicyViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7313E3270534B800053347 /* ScriptPolicyViewControllerDelegate.swift */; };
|
CD7313E4270534B800053347 /* ScriptPolicyViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7313E3270534B800053347 /* ScriptPolicyViewControllerDelegate.swift */; };
|
||||||
CD7A7E9D2686A9A500E20BA3 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A7E9C2686A9A500E20BA3 /* SettingsViewController.swift */; };
|
CD7A7E9D2686A9A500E20BA3 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A7E9C2686A9A500E20BA3 /* SettingsViewController.swift */; };
|
||||||
@@ -143,6 +145,8 @@
|
|||||||
CD3D6CED2DA9F8910099667F /* WebKitDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebKitDefines.h; sourceTree = "<group>"; };
|
CD3D6CED2DA9F8910099667F /* WebKitDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebKitDefines.h; sourceTree = "<group>"; };
|
||||||
CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+WebKitDelegate.swift"; sourceTree = "<group>"; };
|
CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+WebKitDelegate.swift"; sourceTree = "<group>"; };
|
||||||
CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+Keyboard.swift"; sourceTree = "<group>"; };
|
CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+Keyboard.swift"; sourceTree = "<group>"; };
|
||||||
|
CD4930D82E8B38FC00ADDE99 /* AddSearchEngineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSearchEngineViewController.swift; sourceTree = "<group>"; };
|
||||||
|
CD4930DA2E8B3F5B00ADDE99 /* ManageSearchEnginesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageSearchEnginesViewController.swift; sourceTree = "<group>"; };
|
||||||
CD7313E12705349700053347 /* ScriptPolicyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewController.swift; sourceTree = "<group>"; };
|
CD7313E12705349700053347 /* ScriptPolicyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewController.swift; sourceTree = "<group>"; };
|
||||||
CD7313E3270534B800053347 /* ScriptPolicyViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewControllerDelegate.swift; sourceTree = "<group>"; };
|
CD7313E3270534B800053347 /* ScriptPolicyViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewControllerDelegate.swift; sourceTree = "<group>"; };
|
||||||
CD7A7E9C2686A9A500E20BA3 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
|
CD7A7E9C2686A9A500E20BA3 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
|
||||||
@@ -477,6 +481,8 @@
|
|||||||
CD7A7E9C2686A9A500E20BA3 /* SettingsViewController.swift */,
|
CD7A7E9C2686A9A500E20BA3 /* SettingsViewController.swift */,
|
||||||
CD7A7E9E2686B29100E20BA3 /* GeneralSettingsViewController.swift */,
|
CD7A7E9E2686B29100E20BA3 /* GeneralSettingsViewController.swift */,
|
||||||
CD7A7EA02686B2E600E20BA3 /* RedirectRulesSettingsViewController.swift */,
|
CD7A7EA02686B2E600E20BA3 /* RedirectRulesSettingsViewController.swift */,
|
||||||
|
CD4930D82E8B38FC00ADDE99 /* AddSearchEngineViewController.swift */,
|
||||||
|
CD4930DA2E8B3F5B00ADDE99 /* ManageSearchEnginesViewController.swift */,
|
||||||
CDF3468F276C14BD00FB3141 /* CodeEditorSettingsViewController.swift */,
|
CDF3468F276C14BD00FB3141 /* CodeEditorSettingsViewController.swift */,
|
||||||
);
|
);
|
||||||
path = Settings;
|
path = Settings;
|
||||||
@@ -569,6 +575,7 @@
|
|||||||
files = (
|
files = (
|
||||||
1ADFF46024C7DE53006DC7AE /* AppDelegate.swift in Sources */,
|
1ADFF46024C7DE53006DC7AE /* AppDelegate.swift in Sources */,
|
||||||
1AD3104325254FB900A4A952 /* FindOnPageViewController.swift in Sources */,
|
1AD3104325254FB900A4A952 /* FindOnPageViewController.swift in Sources */,
|
||||||
|
CD4930D92E8B390200ADDE99 /* AddSearchEngineViewController.swift in Sources */,
|
||||||
1A03811424E73EB300826501 /* SegmentedReliefButton.swift in Sources */,
|
1A03811424E73EB300826501 /* SegmentedReliefButton.swift in Sources */,
|
||||||
1A03811024E71CF000826501 /* ReliefButton.swift in Sources */,
|
1A03811024E71CF000826501 /* ReliefButton.swift in Sources */,
|
||||||
CD8ACBC22DC9A2F7008BF856 /* Hacks.m in Sources */,
|
CD8ACBC22DC9A2F7008BF856 /* Hacks.m in Sources */,
|
||||||
@@ -604,6 +611,7 @@
|
|||||||
CD853BCE24E7763900D2BDCC /* BrowserHistory.swift in Sources */,
|
CD853BCE24E7763900D2BDCC /* BrowserHistory.swift in Sources */,
|
||||||
1A03810B24E71C5600826501 /* ToolbarButtonContainerView.swift in Sources */,
|
1A03810B24E71C5600826501 /* ToolbarButtonContainerView.swift in Sources */,
|
||||||
CD8DBE7B2A85D892006A0FE0 /* LayoutLatch.swift in Sources */,
|
CD8DBE7B2A85D892006A0FE0 /* LayoutLatch.swift in Sources */,
|
||||||
|
CD4930DB2E8B3F6500ADDE99 /* ManageSearchEnginesViewController.swift in Sources */,
|
||||||
CD7A7EA12686B2E600E20BA3 /* RedirectRulesSettingsViewController.swift in Sources */,
|
CD7A7EA12686B2E600E20BA3 /* RedirectRulesSettingsViewController.swift in Sources */,
|
||||||
1ADFF4CB24CB8278006DC7AE /* ScriptControllerIconView.swift in Sources */,
|
1ADFF4CB24CB8278006DC7AE /* ScriptControllerIconView.swift in Sources */,
|
||||||
CD7A8915251975B70075991E /* AutocompleteViewController.swift in Sources */,
|
CD7A8915251975B70075991E /* AutocompleteViewController.swift in Sources */,
|
||||||
@@ -784,7 +792,7 @@
|
|||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 5;
|
CURRENT_PROJECT_VERSION = 5;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_TEAM = DQQH5H6GBD;
|
DEVELOPMENT_TEAM = 3SJALV9BQ7;
|
||||||
INFOPLIST_FILE = "App/Supporting Files/Info.plist";
|
INFOPLIST_FILE = "App/Supporting Files/Info.plist";
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Attractor;
|
INFOPLIST_KEY_CFBundleDisplayName = Attractor;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||||
@@ -819,7 +827,7 @@
|
|||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 5;
|
CURRENT_PROJECT_VERSION = 5;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_TEAM = DQQH5H6GBD;
|
DEVELOPMENT_TEAM = 3SJALV9BQ7;
|
||||||
INFOPLIST_FILE = "App/Supporting Files/Info.plist";
|
INFOPLIST_FILE = "App/Supporting Files/Info.plist";
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Attractor;
|
INFOPLIST_KEY_CFBundleDisplayName = Attractor;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||||
|
|||||||
Reference in New Issue
Block a user