BrowserViewController: break up into extensions

This commit is contained in:
James Magahern
2021-02-17 18:28:18 -08:00
parent 372a0f32e9
commit 18d74efa89
4 changed files with 301 additions and 268 deletions

View File

@@ -0,0 +1,103 @@
//
// BrowserViewController+Keyboard.swift
// App
//
// Created by James Magahern on 2/17/21.
//
import Foundation
extension BrowserViewController: ShortcutResponder
{
internal func updateCommandKeyState(forPresses presses: Set<UIPress>) {
guard let press = presses.first else { return }
if let key = press.key {
if key.modifierFlags == [.command] {
let isDown = press.phase == .began || press.phase == .changed || press.phase == .stationary
self.commandKeyHeld = isDown
}
}
}
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
super.pressesBegan(presses, with: event)
updateCommandKeyState(forPresses: presses)
}
override func pressesCancelled(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
super.pressesCancelled(presses, with: event)
updateCommandKeyState(forPresses: presses)
}
override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
super.pressesEnded(presses, with: event)
updateCommandKeyState(forPresses: presses)
}
// MARK: Keyboard Shortcuts
func focusURLBar(_ sender: Any?) {
toolbarController.urlBar.textField.becomeFirstResponder()
}
func goBack(_ sender: Any?) {
tab.webView.goBack()
}
func goForward(_ sender: Any?) {
tab.webView.goForward()
}
func createTab(_ sender: Any?) {
createNewTab(withURL: nil)
}
func previousTab(_ sender: Any?) {
if let tabIndex = tabController.tabs.firstIndex(of: self.tab) {
if tabIndex - 1 >= 0 {
self.tab = tabController.tabs[tabIndex - 1]
}
}
}
func nextTab(_ sender: Any?) {
if let tabIndex = tabController.tabs.firstIndex(of: self.tab) {
if tabIndex + 1 < tabController.tabs.count {
self.tab = tabController.tabs[tabIndex + 1]
}
}
}
func closeTab(_ sender: Any?) {
if tabController.tabs.count > 1 {
tabController.closeTab(self.tab)
} else {
#if targetEnvironment(macCatalyst)
if let originWindowScene = self.view.window?.windowScene {
UIApplication.shared.requestSceneSessionDestruction(originWindowScene.session, options: nil) { error in
print("Error when requesting scene destruction: " + error.localizedDescription)
}
}
#endif
}
}
func findOnPage(_ sender: Any?) {
browserView.setFindOnPageVisible(true, animated: true)
findOnPageController.findOnPageView.textField.becomeFirstResponder()
}
func refresh(_ sender: Any?) {
webView.reload()
}
override func increaseSize(_ sender: Any?) {
tab.webView._viewScale += 0.10
}
override func decreaseSize(_ sender: Any?) {
tab.webView._viewScale -= 0.10
}
}

View File

@@ -0,0 +1,146 @@
//
// BrowserViewController+WebKitDelegate.swift
// App
//
// Created by James Magahern on 2/17/21.
//
import WebKit
extension BrowserViewController: WKNavigationDelegate, WKUIDelegate
{
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
loadError = nil
// Check to make sure we have connected to the web content process
if !tab.bridge.webContentProcessConnected {
// This means we started loading a page but the web content process hasn't loaded, which means
// scripts are not getting blocked.
// If you're ad-hoc signing this, you'll need to disable library validation:
// sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation DisableLibraryValidation -bool YES
DispatchQueue.main.async { [unowned self] in
// Stop loading now
webView.stopLoading()
// Show an alert
let alert = UIAlertController(title: "Web Process Not Loaded",
message: "The web content process never contacted the host application",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
alert.dismiss(animated: true, completion: nil)
}))
present(alert, animated: true, completion: nil)
}
}
// Reset tracking this
tab.allowedScriptOrigins.removeAll()
tab.blockedScriptOrigins.removeAll()
updateScriptBlockerButton()
// Blur url bar if applicable
toolbarController.urlBar.textField.resignFirstResponder()
updateTitleAndURL(forWebView: webView)
if let url = webView.url {
// Start requesting favicon
tab.updateFaviconForURL(url)
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
toolbarController.urlBar.loadProgress = .complete
// Update history
if let url = webView.url {
let title = webView.title ?? ""
BrowserHistory.shared.didNavigate(toURL: url, title: title)
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void)
{
// Handle command+click
if (commandKeyHeld || windowButtonHeld) && navigationAction.navigationType == .linkActivated {
// Cancel navigation in this tab
decisionHandler(.cancel, preferences)
// Start navigation in a new tab
let tab = tabController.createNewTab(url: navigationAction.request.url)
self.tab = tab
// Reset this flag.
commandKeyHeld = false
windowButtonHeld = false
return
}
var allowJavaScript = tab.javaScriptEnabled
if !allowJavaScript, let host = navigationAction.request.url?.host {
// Check origin policy
allowJavaScript = policyManager.allowedOriginsForScriptResources().contains(host)
}
preferences.allowsContentJavaScript = allowJavaScript
if let url = navigationAction.request.url,
let redirectedURL = redirectRules.redirectedURL(for: url)
{
tab.beginLoadingURL(redirectedURL)
decisionHandler(.cancel, preferences)
} else {
decisionHandler(.allow, preferences)
}
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
self.loadError = error
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
self.loadError = error
}
// MARK: WKUIDelegate
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView?
{
let newTab = tabController.createNewTab(url: nil, webViewConfiguration: configuration)
newTab.webView.load(navigationAction.request)
self.tab = newTab
return newTab.webView
}
func webView(_ webView: WKWebView, contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo, completionHandler: @escaping (UIContextMenuConfiguration?) -> Void) {
let menuConfig = UIContextMenuConfiguration(identifier: nil,
previewProvider: nil) { (menuElements: [UIMenuElement]) -> UIMenu? in
let openInNewTab = UIAction(title: "Open in New Tab",
image: UIImage(systemName: "plus.app"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .off) { [unowned self] _ in
let newTab = tabController.createNewTab(url: elementInfo.linkURL)
self.tab = newTab
}
return UIMenu(title: elementInfo.linkURL?.absoluteString ?? "Link",
image: nil,
identifier: nil,
options: .displayInline,
children: [ openInNewTab ] + menuElements)
}
completionHandler(menuConfig)
}
}

View File

@@ -9,23 +9,21 @@ import Combine
import UIKit import UIKit
import UniformTypeIdentifiers import UniformTypeIdentifiers
class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegate, ScriptPolicyViewControllerDelegate, class BrowserViewController: UIViewController
UIPopoverPresentationControllerDelegate, TabDelegate, TabPickerViewControllerDelegate,
AutocompleteViewControllerDelegate, ShortcutResponder
{ {
let browserView = BrowserView() let browserView = BrowserView()
var tab: Tab { didSet { didChangeTab(tab) } } var tab: Tab { didSet { didChangeTab(tab) } }
var webView: WKWebView { tab.webView } var webView: WKWebView { tab.webView }
private let tabController = TabController() internal let tabController = TabController()
private let tabBarViewController: TabBarViewController internal let tabBarViewController: TabBarViewController
private let toolbarController = ToolbarViewController() internal let toolbarController = ToolbarViewController()
private let findOnPageController = FindOnPageViewController() internal let findOnPageController = FindOnPageViewController()
private let autocompleteViewController = AutocompleteViewController() internal let autocompleteViewController = AutocompleteViewController()
private let redirectRules = PersonalRedirectRules() internal let redirectRules = PersonalRedirectRules()
private var policyManager: ResourcePolicyManager { tabController.policyManager } internal var policyManager: ResourcePolicyManager { tabController.policyManager }
override var canBecomeFirstResponder: Bool { true } override var canBecomeFirstResponder: Bool { true }
@@ -36,10 +34,10 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
private var activeTabObservation: AnyCancellable? private var activeTabObservation: AnyCancellable?
private var faviconObservation: AnyCancellable? private var faviconObservation: AnyCancellable?
private var loadError: Error? internal var loadError: Error?
private var commandKeyHeld: Bool = false internal var commandKeyHeld: Bool = false
private var windowButtonHeld: Bool { internal var windowButtonHeld: Bool {
get { toolbarController.newTabButton.isTracking } get { toolbarController.newTabButton.isTracking }
set { toolbarController.newTabButton.cancelTracking(with: nil) } set { toolbarController.newTabButton.cancelTracking(with: nil) }
} }
@@ -305,7 +303,7 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
self.view = browserView self.view = browserView
} }
private func updateLoadProgress(forWebView webView: WKWebView) { internal func updateLoadProgress(forWebView webView: WKWebView) {
if let loadError = loadError { if let loadError = loadError {
toolbarController.urlBar.loadProgress = .error(error: loadError) toolbarController.urlBar.loadProgress = .error(error: loadError)
} else if webView.estimatedProgress == 1.0 { } else if webView.estimatedProgress == 1.0 {
@@ -315,7 +313,7 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
} }
} }
private func updateTitleAndURL(forWebView webView: WKWebView) { internal func updateTitleAndURL(forWebView webView: WKWebView) {
if webView == browserView.webView { if webView == browserView.webView {
browserView.titlebarView.setTitle(webView.title ?? "") browserView.titlebarView.setTitle(webView.title ?? "")
@@ -403,33 +401,7 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
toolbarController.traitCollectionDidChange(previousTraitCollection) toolbarController.traitCollectionDidChange(previousTraitCollection)
} }
private func updateCommandKeyState(forPresses presses: Set<UIPress>) { internal func updateScriptBlockerButton() {
guard let press = presses.first else { return }
if let key = press.key {
if key.modifierFlags == [.command] {
let isDown = press.phase == .began || press.phase == .changed || press.phase == .stationary
self.commandKeyHeld = isDown
}
}
}
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
super.pressesBegan(presses, with: event)
updateCommandKeyState(forPresses: presses)
}
override func pressesCancelled(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
super.pressesCancelled(presses, with: event)
updateCommandKeyState(forPresses: presses)
}
override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
super.pressesEnded(presses, with: event)
updateCommandKeyState(forPresses: presses)
}
private func updateScriptBlockerButton() {
var numBlockedScripts: Int = tab.blockedScriptOrigins.count var numBlockedScripts: Int = tab.blockedScriptOrigins.count
if tab.url != nil, tab.javaScriptEnabled == false { if tab.url != nil, tab.javaScriptEnabled == false {
// Because the page is blocked too, notify. // Because the page is blocked too, notify.
@@ -451,158 +423,46 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
let newTab = tabController.createNewTab(url: url) let newTab = tabController.createNewTab(url: url)
self.tab = newTab self.tab = newTab
} }
}
// MARK: UIPopoverPresentationControllerDelegate extension BrowserViewController: UIPopoverPresentationControllerDelegate
{
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
// Forces popovers to present on iPhone // Forces popovers to present on iPhone
return .none return .none
} }
// MARK: Navigation Delegate
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
loadError = nil
// Check to make sure we have connected to the web content process
if !tab.bridge.webContentProcessConnected {
// This means we started loading a page but the web content process hasn't loaded, which means
// scripts are not getting blocked.
// If you're ad-hoc signing this, you'll need to disable library validation:
// sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation DisableLibraryValidation -bool YES
DispatchQueue.main.async { [unowned self] in
// Stop loading now
webView.stopLoading()
// Show an alert
let alert = UIAlertController(title: "Web Process Not Loaded",
message: "The web content process never contacted the host application",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
alert.dismiss(animated: true, completion: nil)
}))
present(alert, animated: true, completion: nil)
}
} }
// Reset tracking this extension BrowserViewController: ScriptPolicyViewControllerDelegate
tab.allowedScriptOrigins.removeAll()
tab.blockedScriptOrigins.removeAll()
updateScriptBlockerButton()
// Blur url bar if applicable
toolbarController.urlBar.textField.resignFirstResponder()
updateTitleAndURL(forWebView: webView)
if let url = webView.url {
// Start requesting favicon
tab.updateFaviconForURL(url)
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
toolbarController.urlBar.loadProgress = .complete
// Update history
if let url = webView.url {
let title = webView.title ?? ""
BrowserHistory.shared.didNavigate(toURL: url, title: title)
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void)
{ {
// Handle command+click func didChangeScriptPolicy() {
if (commandKeyHeld || windowButtonHeld) && navigationAction.navigationType == .linkActivated { tab.bridge.policyDataSourceDidChange()
// Cancel navigation in this tab webView.reload()
decisionHandler(.cancel, preferences)
// Start navigation in a new tab
let tab = tabController.createNewTab(url: navigationAction.request.url)
self.tab = tab
// Reset this flag.
commandKeyHeld = false
windowButtonHeld = false
return
} }
var allowJavaScript = tab.javaScriptEnabled func setScriptsEnabledForTab(_ enabled: Bool) {
if !allowJavaScript, let host = navigationAction.request.url?.host { tab.javaScriptEnabled = enabled
// Check origin policy toolbarController.scriptControllerIconView.shieldsDown = enabled
allowJavaScript = policyManager.allowedOriginsForScriptResources().contains(host) }
} }
preferences.allowsContentJavaScript = allowJavaScript extension BrowserViewController: AutocompleteViewControllerDelegate
if let url = navigationAction.request.url,
let redirectedURL = redirectRules.redirectedURL(for: url)
{ {
tab.beginLoadingURL(redirectedURL) func autocompleteController(_: AutocompleteViewController, didSelectHistoryItem item: HistoryItem) {
decisionHandler(.cancel, preferences) tab.beginLoadingURL(item.url)
} else { autocompleteViewController.view.isHidden = true
decisionHandler(.allow, preferences)
} }
} }
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { extension BrowserViewController: TabDelegate
self.loadError = error
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
self.loadError = error
}
// MARK: WKUIDelegate
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView?
{ {
let newTab = tabController.createNewTab(url: nil, webViewConfiguration: configuration)
newTab.webView.load(navigationAction.request)
self.tab = newTab
return newTab.webView
}
func webView(_ webView: WKWebView, contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo, completionHandler: @escaping (UIContextMenuConfiguration?) -> Void) {
let menuConfig = UIContextMenuConfiguration(identifier: nil,
previewProvider: nil) { (menuElements: [UIMenuElement]) -> UIMenu? in
let openInNewTab = UIAction(title: "Open in New Tab",
image: UIImage(systemName: "plus.app"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .off) { [unowned self] _ in
let newTab = tabController.createNewTab(url: elementInfo.linkURL)
self.tab = newTab
}
return UIMenu(title: elementInfo.linkURL?.absoluteString ?? "Link",
image: nil,
identifier: nil,
options: .displayInline,
children: [ openInNewTab ] + menuElements)
}
completionHandler(menuConfig)
}
// MARK: Tab Delegate
func didBlockScriptOrigin(_ origin: String, forTab: Tab) { func didBlockScriptOrigin(_ origin: String, forTab: Tab) {
updateScriptBlockerButton() updateScriptBlockerButton()
} }
}
// MARK: Tab Picker Delegate extension BrowserViewController: TabPickerViewControllerDelegate
{
func tabPicker(_ picker: TabPickerViewController, didSelectTab tab: Tab) { func tabPicker(_ picker: TabPickerViewController, didSelectTab tab: Tab) {
self.tab = tab self.tab = tab
picker.dismiss(animated: true, completion: nil) picker.dismiss(animated: true, completion: nil)
@@ -614,90 +474,6 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
picker.dismiss(animated: true, completion: nil) picker.dismiss(animated: true, completion: nil)
} }
} }
// MARK: Script Policy View Controller Delegate
func didChangeScriptPolicy() {
tab.bridge.policyDataSourceDidChange()
webView.reload()
}
func setScriptsEnabledForTab(_ enabled: Bool) {
tab.javaScriptEnabled = enabled
toolbarController.scriptControllerIconView.shieldsDown = enabled
}
// MARK: Autocomplete Controller Delegate
func autocompleteController(_: AutocompleteViewController, didSelectHistoryItem item: HistoryItem) {
tab.beginLoadingURL(item.url)
autocompleteViewController.view.isHidden = true
}
// MARK: Keyboard shortcuts
func focusURLBar(_ sender: Any?) {
toolbarController.urlBar.textField.becomeFirstResponder()
}
func goBack(_ sender: Any?) {
tab.webView.goBack()
}
func goForward(_ sender: Any?) {
tab.webView.goForward()
}
func createTab(_ sender: Any?) {
createNewTab(withURL: nil)
}
func previousTab(_ sender: Any?) {
if let tabIndex = tabController.tabs.firstIndex(of: self.tab) {
if tabIndex - 1 >= 0 {
self.tab = tabController.tabs[tabIndex - 1]
}
}
}
func nextTab(_ sender: Any?) {
if let tabIndex = tabController.tabs.firstIndex(of: self.tab) {
if tabIndex + 1 < tabController.tabs.count {
self.tab = tabController.tabs[tabIndex + 1]
}
}
}
func closeTab(_ sender: Any?) {
if tabController.tabs.count > 1 {
tabController.closeTab(self.tab)
} else {
#if targetEnvironment(macCatalyst)
if let originWindowScene = self.view.window?.windowScene {
UIApplication.shared.requestSceneSessionDestruction(originWindowScene.session, options: nil) { error in
print("Error when requesting scene destruction: " + error.localizedDescription)
}
}
#endif
}
}
func findOnPage(_ sender: Any?) {
browserView.setFindOnPageVisible(true, animated: true)
findOnPageController.findOnPageView.textField.becomeFirstResponder()
}
func refresh(_ sender: Any?) {
webView.reload()
}
override func increaseSize(_ sender: Any?) {
tab.webView._viewScale += 0.10
}
override func decreaseSize(_ sender: Any?) {
tab.webView._viewScale -= 0.10
}
} }
extension BrowserViewController: UITextFieldDelegate extension BrowserViewController: UITextFieldDelegate

View File

@@ -42,6 +42,8 @@
1ADFF4D024CBBCD1006DC7AE /* ScriptPolicyControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */; }; 1ADFF4D024CBBCD1006DC7AE /* ScriptPolicyControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */; };
CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5A4254A10BB00189CDC /* TabBarView.swift */; }; CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5A4254A10BB00189CDC /* TabBarView.swift */; };
CD01D5AB254A206D00189CDC /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5AA254A206D00189CDC /* TabBarViewController.swift */; }; CD01D5AB254A206D00189CDC /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5AA254A206D00189CDC /* TabBarViewController.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 */; };
CD7A8915251975B70075991E /* AutocompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A8914251975B70075991E /* AutocompleteViewController.swift */; }; CD7A8915251975B70075991E /* AutocompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A8914251975B70075991E /* AutocompleteViewController.swift */; };
CD7A89172519872D0075991E /* KeyboardShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A89162519872D0075991E /* KeyboardShortcuts.swift */; }; CD7A89172519872D0075991E /* KeyboardShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A89162519872D0075991E /* KeyboardShortcuts.swift */; };
CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */; }; CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */; };
@@ -127,6 +129,8 @@
1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyControl.swift; sourceTree = "<group>"; }; 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyControl.swift; sourceTree = "<group>"; };
CD01D5A4254A10BB00189CDC /* TabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarView.swift; sourceTree = "<group>"; }; CD01D5A4254A10BB00189CDC /* TabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarView.swift; sourceTree = "<group>"; };
CD01D5AA254A206D00189CDC /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.swift; sourceTree = "<group>"; }; CD01D5AA254A206D00189CDC /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.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>"; };
CD7A8914251975B70075991E /* AutocompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteViewController.swift; sourceTree = "<group>"; }; CD7A8914251975B70075991E /* AutocompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteViewController.swift; sourceTree = "<group>"; };
CD7A89162519872D0075991E /* KeyboardShortcuts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardShortcuts.swift; sourceTree = "<group>"; }; CD7A89162519872D0075991E /* KeyboardShortcuts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardShortcuts.swift; sourceTree = "<group>"; };
CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKeyCommand+ConvInit.swift"; sourceTree = "<group>"; }; CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKeyCommand+ConvInit.swift"; sourceTree = "<group>"; };
@@ -274,8 +278,10 @@
1ADFF47724C7DFE8006DC7AE /* Browser View */ = { 1ADFF47724C7DFE8006DC7AE /* Browser View */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
1ADFF47324C7DE9C006DC7AE /* BrowserViewController.swift */,
1ADFF47824C7DFF8006DC7AE /* BrowserView.swift */, 1ADFF47824C7DFF8006DC7AE /* BrowserView.swift */,
1ADFF47324C7DE9C006DC7AE /* BrowserViewController.swift */,
CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */,
CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */,
); );
path = "Browser View"; path = "Browser View";
sourceTree = "<group>"; sourceTree = "<group>";
@@ -490,6 +496,7 @@
CDCE2666251AA840007FE92A /* StackView.swift in Sources */, CDCE2666251AA840007FE92A /* StackView.swift in Sources */,
CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */, CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */,
1AD31040252545BF00A4A952 /* FindOnPageView.swift in Sources */, 1AD31040252545BF00A4A952 /* FindOnPageView.swift in Sources */,
CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */,
CDEDD8AA25D62ADB00862605 /* UITraitCollection+MacLike.swift in Sources */, CDEDD8AA25D62ADB00862605 /* UITraitCollection+MacLike.swift in Sources */,
CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */, CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */,
1ADFF4C724CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift in Sources */, 1ADFF4C724CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift in Sources */,
@@ -499,6 +506,7 @@
CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */, CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */,
1ADFF4D024CBBCD1006DC7AE /* ScriptPolicyControl.swift in Sources */, 1ADFF4D024CBBCD1006DC7AE /* ScriptPolicyControl.swift in Sources */,
1A03810D24E71CA700826501 /* ToolbarView.swift in Sources */, 1A03810D24E71CA700826501 /* ToolbarView.swift in Sources */,
CD470C4425DE070400AFBE0E /* BrowserViewController+Keyboard.swift in Sources */,
CD853BD424E77BF900D2BDCC /* HistoryItem.swift in Sources */, CD853BD424E77BF900D2BDCC /* HistoryItem.swift in Sources */,
1ADFF48D24C8C176006DC7AE /* SBRProcessBundleBridge.m in Sources */, 1ADFF48D24C8C176006DC7AE /* SBRProcessBundleBridge.m in Sources */,
1AD3103D252541E600A4A952 /* PersonalRedirectRules.swift in Sources */, 1AD3103D252541E600A4A952 /* PersonalRedirectRules.swift in Sources */,