diff --git a/App/AppDelegate.swift b/App/AppDelegate.swift index 625d3ba..7474b7b 100644 --- a/App/AppDelegate.swift +++ b/App/AppDelegate.swift @@ -22,6 +22,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } + static func appMenuShortcuts() -> [UIKeyCommand] { + [ + // Preferences + UIKeyCommand( + modifiers: .command, + input: ",", + title: "Preferences", + action: #selector(ShortcutResponder.showPreferences) + ) + ] + } + static func fileMenuShortcuts() -> [UIKeyCommand] { [ // Open Location... @@ -90,13 +102,31 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } override var keyCommands: [UIKeyCommand]? { - get { return Self.fileMenuShortcuts() } + get { return Self.fileMenuShortcuts() + Self.appMenuShortcuts() } } override func buildMenu(with builder: UIMenuBuilder) { builder.replaceChildren(ofMenu: .file) { children in return Self.fileMenuShortcuts() + children } + + builder.replaceChildren(ofMenu: .application, from: { children in + let index = children.firstIndex(where: { elem in + if let elem = elem as? UIMenu { + return elem.identifier == .about + } + return false + }) + + var newChildren = children + if let index = index { + newChildren.insert(contentsOf: Self.appMenuShortcuts(), at: index + 1) + } else { + newChildren.append(contentsOf: Self.appMenuShortcuts()) + } + + return newChildren + }) } } diff --git a/App/Browser View/BrowserViewController+Keyboard.swift b/App/Browser View/BrowserViewController+Keyboard.swift index ca86b07..31b0dc8 100644 --- a/App/Browser View/BrowserViewController+Keyboard.swift +++ b/App/Browser View/BrowserViewController+Keyboard.swift @@ -146,4 +146,7 @@ extension BrowserViewController: ShortcutResponder tab.webView._viewScale -= 0.10 } + func showPreferences(_ sender: Any?) { + showSettingsWindow() + } } diff --git a/App/Browser View/BrowserViewController.swift b/App/Browser View/BrowserViewController.swift index b3163af..002c63a 100644 --- a/App/Browser View/BrowserViewController.swift +++ b/App/Browser View/BrowserViewController.swift @@ -286,6 +286,12 @@ class BrowserViewController: UIViewController documentControls.dismiss(animated: true, completion: nil) }, for: .touchUpInside) + // Settings + documentControls.settingsView.addAction(UIAction { [unowned self] _ in + documentControls.dismiss(animated: false, completion: nil) + showSettingsWindow() + }, for: .touchUpInside) + present(documentControls, animated: true, completion: nil) }), for: .touchUpInside) @@ -312,6 +318,16 @@ class BrowserViewController: UIViewController self.view = browserView } + internal func showSettingsWindow() { + #if targetEnvironment(macCatalyst) + let userActivity = NSUserActivity(activityType: SessionActivityType.SettingsWindow.rawValue) + UIApplication.shared.requestSceneSessionActivation(nil, userActivity: userActivity, options: .none, errorHandler: nil) + #else + let settingsVC = SettingsViewController() + present(settingsVC, animated: true, completion: nil) + #endif + } + internal func updateLoadProgress(forWebView webView: WKWebView) { if let loadError = loadError { toolbarController.urlBar.loadProgress = .error(error: loadError) diff --git a/App/KeyboardShortcuts.swift b/App/KeyboardShortcuts.swift index e46220c..8786bfc 100644 --- a/App/KeyboardShortcuts.swift +++ b/App/KeyboardShortcuts.swift @@ -35,4 +35,7 @@ protocol ShortcutResponder: AnyObject { @objc optional func refresh(_ sender: Any?) + + @objc + optional func showPreferences(_ sender: Any?) } diff --git a/App/SceneDelegate.swift b/App/SceneDelegate.swift index c60edac..baf1252 100644 --- a/App/SceneDelegate.swift +++ b/App/SceneDelegate.swift @@ -7,28 +7,43 @@ import UIKit +public enum SessionActivityType: String { + case BrowserWindow = "net.buzzert.rossler-attix.browser" + case SettingsWindow = "net.buzzert.rossler-attix.settings" +} + class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - let navigationController = UINavigationController() - let browserViewController = BrowserViewController() + + var browserViewController: BrowserViewController? + var settingsViewController: SettingsViewController? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } - navigationController.viewControllers = [ browserViewController ] - navigationController.setNavigationBarHidden(true, animated: false) - let window = UIWindow(windowScene: windowScene) - window.rootViewController = navigationController + if let userActivity = connectionOptions.userActivities.first { + if userActivity.activityType == SessionActivityType.SettingsWindow.rawValue { + let settingsViewController = SettingsViewController() + self.settingsViewController = settingsViewController + window.rootViewController = settingsViewController + windowScene.sizeRestrictions?.maximumSize = CGSize(width: 500.0, height: 1200.0) + } + } else { + let browserViewController = BrowserViewController() + self.browserViewController = browserViewController + window.rootViewController = browserViewController + + if let urlContext = connectionOptions.urlContexts.first { + let url = urlContext.url + browserViewController.tab.beginLoadingURL(url) + } + } + window.makeKeyAndVisible() self.window = window - if let urlContext = connectionOptions.urlContexts.first { - let url = urlContext.url - browserViewController.tab.beginLoadingURL(url) - } - #if targetEnvironment(macCatalyst) windowScene.titlebar?.titleVisibility = .hidden windowScene.titlebar?.separatorStyle = .none @@ -38,7 +53,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { for urlContext in URLContexts { - browserViewController.createNewTab(withURL: urlContext.url) + browserViewController?.createNewTab(withURL: urlContext.url) } } } diff --git a/App/Settings/SettingsView.swift b/App/Settings/SettingsView.swift new file mode 100644 index 0000000..dff0d87 --- /dev/null +++ b/App/Settings/SettingsView.swift @@ -0,0 +1,49 @@ +// +// SettingsView.swift +// App +// +// Created by James Magahern on 3/3/21. +// + +import SwiftUI + +struct SettingsCategoryCell: View { + @State var title: String = "" + + var body: some View { + HStack { + Text(title) + .bold() + .frame(height: 34.0) + } + } +} + +struct SettingsView: View { + @Environment(\.presentationMode) + @Binding private var presentationMode + + var body: some View { + NavigationView { + List { + Section(header: Text("Redirect Rules"), content: { + Text("To Do") + }) + } + .listStyle(InsetGroupedListStyle()) + .navigationBarTitle("Settings", displayMode: .inline) + .toolbar(content: { + #if !targetEnvironment(macCatalyst) + Button("Done", action: { presentationMode.dismiss() }) + #endif + }) + } + .navigationViewStyle(StackNavigationViewStyle()) + } +} + +struct SettingsView_Previews: PreviewProvider { + static var previews: some View { + SettingsView() + } +} diff --git a/App/Settings/SettingsViewController.swift b/App/Settings/SettingsViewController.swift new file mode 100644 index 0000000..d94b05d --- /dev/null +++ b/App/Settings/SettingsViewController.swift @@ -0,0 +1,22 @@ +// +// SettingsViewController.swift +// App +// +// Created by James Magahern on 3/3/21. +// + +import SwiftUI +import UIKit + +class SettingsViewController: UIHostingController +{ + var settingsView = SettingsView() + + init() { + super.init(rootView: settingsView) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/SBrowser.xcodeproj/project.pbxproj b/SBrowser.xcodeproj/project.pbxproj index 9c80507..acd254b 100644 --- a/SBrowser.xcodeproj/project.pbxproj +++ b/SBrowser.xcodeproj/project.pbxproj @@ -58,6 +58,8 @@ CDCE2664251AA80F007FE92A /* DocumentControlViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */; }; CDCE2666251AA840007FE92A /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2665251AA840007FE92A /* StackView.swift */; }; CDCE2668251AAA9A007FE92A /* FontSizeAdjustView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */; }; + CDE6A30425F023BC00E912A4 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE6A30325F023BC00E912A4 /* SettingsViewController.swift */; }; + CDE6A30625F023EA00E912A4 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE6A30525F023EA00E912A4 /* SettingsView.swift */; }; CDEDD8AA25D62ADB00862605 /* UITraitCollection+MacLike.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDEDD8A925D62ADB00862605 /* UITraitCollection+MacLike.swift */; }; /* End PBXBuildFile section */ @@ -146,6 +148,8 @@ CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentControlViewController.swift; sourceTree = ""; }; CDCE2665251AA840007FE92A /* StackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackView.swift; sourceTree = ""; }; CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSizeAdjustView.swift; sourceTree = ""; }; + CDE6A30325F023BC00E912A4 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; + CDE6A30525F023EA00E912A4 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; CDEDD8A925D62ADB00862605 /* UITraitCollection+MacLike.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITraitCollection+MacLike.swift"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -256,6 +260,7 @@ 1AD3104125254FA300A4A952 /* Find on Page */, CDC5DA3C25DB7A5500BA8D99 /* Reader View */, 1ADFF4CE24CBBCBD006DC7AE /* Script Policy UI */, + CDE6A30225F023A000E912A4 /* Settings */, 1AB88F0324D3E1EC0006F850 /* Tabs */, 1AB88F0424D3E1F90006F850 /* Titlebar and URL Bar */, 1ADFF4C124CA6AE4006DC7AE /* Utilities */, @@ -387,6 +392,15 @@ path = "Document Controls UI"; sourceTree = ""; }; + CDE6A30225F023A000E912A4 /* Settings */ = { + isa = PBXGroup; + children = ( + CDE6A30325F023BC00E912A4 /* SettingsViewController.swift */, + CDE6A30525F023EA00E912A4 /* SettingsView.swift */, + ); + path = Settings; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -521,11 +535,13 @@ 1ADFF4CB24CB8278006DC7AE /* ScriptControllerIconView.swift in Sources */, CD7A8915251975B70075991E /* AutocompleteViewController.swift in Sources */, CDC5DA3E25DB7C2C00BA8D99 /* ReaderViewController.swift in Sources */, + CDE6A30625F023EA00E912A4 /* SettingsView.swift in Sources */, 1AB88EFD24D3BA560006F850 /* TabController.swift in Sources */, 1ADFF4C324CA6AF6006DC7AE /* Geometry.swift in Sources */, 1ADFF4C924CA793E006DC7AE /* ToolbarViewController.swift in Sources */, CD7A89172519872D0075991E /* KeyboardShortcuts.swift in Sources */, 1ADFF4CD24CBB0C8006DC7AE /* ScriptPolicyViewController.swift in Sources */, + CDE6A30425F023BC00E912A4 /* SettingsViewController.swift in Sources */, 1A14FC2824D26749009B3F83 /* Tab.swift in Sources */, CD01D5AB254A206D00189CDC /* TabBarViewController.swift in Sources */, 1ADFF47924C7DFF8006DC7AE /* BrowserView.swift in Sources */,