State restoration

This commit is contained in:
Shadowfacts 2021-09-28 21:03:37 -04:00
parent afa2a7b771
commit ebdd06738a
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
6 changed files with 110 additions and 14 deletions

View File

@ -50,6 +50,13 @@ class BrowserNavigationController: UIViewController {
.slide
}
override var userActivity: NSUserActivity? {
get {
currentBrowserVC?.userActivity
}
set {}
}
private var cancellables = [AnyCancellable]()
init(navigator: NavigationManager) {
@ -75,6 +82,9 @@ class BrowserNavigationController: UIViewController {
currentBrowserVC.scrollViewDelegate = self
embedChild(currentBrowserVC, in: browserContainer)
backBrowserVCs = navigator.backStack.map(createBrowserVC(url:))
forwardBrowserVCs = navigator.forwardStack.map(createBrowserVC(url:))
navBarView = NavigationBarView(navigator: navigator)
navBarView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navBarView)

View File

@ -45,6 +45,9 @@ class BrowserWebViewController: UIViewController {
self.url = url
super.init(nibName: nil, bundle: nil)
userActivity = NSUserActivity(geminiURL: url)
userActivity!.isEligibleForPrediction = true
}
required init?(coder: NSCoder) {
@ -358,8 +361,19 @@ extension BrowserWebViewController: WKUIDelegate {
return SFSafariViewController(url: url)
}
} actionProvider: { (_) in
guard #available(iOS 15.0, *),
url.scheme == "gemini" else {
return nil
}
return UIMenu(children: [
UIWindowScene.ActivationAction({ (_) in
let options = UIWindowScene.ActivationRequestOptions()
// automatic presents in the prominent style even when a fullscreen window is the only existing one
options.preferredPresentationStyle = .standard
return UIWindowScene.ActivationConfiguration(userActivity: NSUserActivity(geminiURL: url), options: options, preview: nil)
})
])
}
completionHandler(config)
}

View File

@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSUserActivityTypes</key>
<array>
<string>$(PRODUCE_BUNDLE_IDENTIFIER).activity.browse</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>

View File

@ -24,19 +24,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
let initialURL: URL
if let context = connectionOptions.urlContexts.first {
initialURL = context.url
} else {
if ProcessInfo.processInfo.environment.keys.contains("DEFAULT_URL") {
initialURL = URL(string: ProcessInfo.processInfo.environment["DEFAULT_URL"]!)!
} else {
initialURL = Preferences.shared.homepage
}
}
navigationManager = NavigationManager(url: initialURL)
navigationManager = createNavigationManager(for: session, with: connectionOptions)
navigationManager.delegate = self
// Create the SwiftUI view that provides the window contents.
@ -94,6 +82,36 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// to restore the scene back to its current state.
}
func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? {
return NSUserActivity(navigationManager: navigationManager)
}
private func createNavigationManager(for session: UISceneSession, with connectionOptions: UIScene.ConnectionOptions) -> NavigationManager {
var initialURL: URL? = nil
if let activity = session.stateRestorationActivity ?? connectionOptions.userActivities.first {
if let manager = activity.navigationManager {
return manager
} else if let url = activity.geminiURL {
initialURL = url
}
}
if initialURL == nil {
initialURL = connectionOptions.urlContexts.first?.url
}
if initialURL == nil {
if ProcessInfo.processInfo.environment.keys.contains("DEFAULT_URL") {
initialURL = URL(string: ProcessInfo.processInfo.environment["DEFAULT_URL"]!)!
} else {
initialURL = Preferences.shared.homepage
}
}
return NavigationManager(url: initialURL!)
}
}
extension SceneDelegate: NavigationManagerDelegate {

View File

@ -0,0 +1,46 @@
//
// UserActivities.swift
// Gemini-iOS
//
// Created by Shadowfacts on 9/28/21.
//
import Foundation
import BrowserCore
private let type = "space.vaccor.Gemini.activity.browse"
extension NSUserActivity {
convenience init(geminiURL url: URL) {
self.init(activityType: type)
self.userInfo = [
"url": url,
]
}
convenience init(navigationManager manager: NavigationManager) {
self.init(activityType: type)
self.userInfo = [
"url": manager.currentURL,
"back": manager.backStack,
"forward": manager.forwardStack,
]
}
var navigationManager: NavigationManager? {
guard activityType == type,
let url = userInfo?["url"] as? URL else { return nil }
let back = userInfo?["back"] as? [URL] ?? []
let forward = userInfo?["forward"] as? [URL] ?? []
let manager = NavigationManager(url: url)
manager.backStack = back
manager.forwardStack = forward
return manager
}
var geminiURL: URL? {
guard activityType == type,
let url = userInfo?["url"] as? URL else { return nil }
return url
}
}

View File

@ -51,6 +51,7 @@
D688F64A258C17F3003A0A73 /* SymbolCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F649258C17F3003A0A73 /* SymbolCache.swift */; };
D688F65A258C2256003A0A73 /* BrowserNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F659258C2256003A0A73 /* BrowserNavigationController.swift */; };
D688F663258C2479003A0A73 /* UIViewController+Children.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F662258C2479003A0A73 /* UIViewController+Children.swift */; };
D68C1E002703EA13002D642B /* UserActivities.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68C1DFF2703EA13002D642B /* UserActivities.swift */; };
D691A64E25217C6F00348C4B /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A64D25217C6F00348C4B /* Preferences.swift */; };
D691A66725217FD800348C4B /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A66625217FD800348C4B /* PreferencesView.swift */; };
D69F00AC24BE9DD300E37622 /* GeminiDataTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69F00AB24BE9DD300E37622 /* GeminiDataTask.swift */; };
@ -321,6 +322,7 @@
D688F649258C17F3003A0A73 /* SymbolCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolCache.swift; sourceTree = "<group>"; };
D688F659258C2256003A0A73 /* BrowserNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserNavigationController.swift; sourceTree = "<group>"; };
D688F662258C2479003A0A73 /* UIViewController+Children.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Children.swift"; sourceTree = "<group>"; };
D68C1DFF2703EA13002D642B /* UserActivities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivities.swift; sourceTree = "<group>"; };
D691A64D25217C6F00348C4B /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
D691A66625217FD800348C4B /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
D69F00AB24BE9DD300E37622 /* GeminiDataTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeminiDataTask.swift; sourceTree = "<group>"; };
@ -612,6 +614,7 @@
D653F40C26799F2F004E32B1 /* HomepagePrefView.swift */,
D653F40A267996FF004E32B1 /* ActivityItemSource.swift */,
D653F40E2679A0AB004E32B1 /* SetHomepageActivity.swift */,
D68C1DFF2703EA13002D642B /* UserActivities.swift */,
D688F618258AD231003A0A73 /* Resources */,
D6376A6E26DDAF57005AD89C /* Vendor */,
D6E152AA24BFFDF600FDF9D3 /* Assets.xcassets */,
@ -1142,6 +1145,7 @@
D653F40D26799F2F004E32B1 /* HomepagePrefView.swift in Sources */,
D691A64E25217C6F00348C4B /* Preferences.swift in Sources */,
D6BC9ABC258E9862008652BC /* NavigationBarView.swift in Sources */,
D68C1E002703EA13002D642B /* UserActivities.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};