Replace UINavigationController with custom navigation controller
This commit is contained in:
parent
314d8cf82c
commit
abb80df9a7
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
public protocol NavigationManagerDelegate: class {
|
||||
func loadNonGeminiURL(_ url: URL)
|
||||
|
@ -19,6 +20,8 @@ public class NavigationManager: NSObject, ObservableObject {
|
|||
@Published public var backStack = [URL]()
|
||||
@Published public var forwardStack = [URL]()
|
||||
|
||||
public let navigationOperation = PassthroughSubject<Operation, Never>()
|
||||
|
||||
public var displayURL: String {
|
||||
var components = URLComponents(url: currentURL, resolvingAgainstBaseURL: false)!
|
||||
if components.port == 1965 {
|
||||
|
@ -58,6 +61,8 @@ public class NavigationManager: NSObject, ObservableObject {
|
|||
backStack.append(currentURL)
|
||||
currentURL = url
|
||||
forwardStack = []
|
||||
|
||||
navigationOperation.send(.go)
|
||||
}
|
||||
|
||||
public func reload() {
|
||||
|
@ -66,9 +71,7 @@ public class NavigationManager: NSObject, ObservableObject {
|
|||
}
|
||||
|
||||
@objc public func back() {
|
||||
guard !backStack.isEmpty else { return }
|
||||
forwardStack.insert(currentURL, at: 0)
|
||||
currentURL = backStack.removeLast()
|
||||
back(count: 1)
|
||||
}
|
||||
|
||||
public func back(count: Int) {
|
||||
|
@ -78,12 +81,12 @@ public class NavigationManager: NSObject, ObservableObject {
|
|||
forwardStack.insert(currentURL, at: 0)
|
||||
currentURL = removed.removeFirst()
|
||||
forwardStack.insert(contentsOf: removed, at: 0)
|
||||
|
||||
navigationOperation.send(.backward(count: count))
|
||||
}
|
||||
|
||||
@objc public func forward() {
|
||||
guard !forwardStack.isEmpty else { return }
|
||||
backStack.append(currentURL)
|
||||
currentURL = forwardStack.removeFirst()
|
||||
forward(count: 1)
|
||||
}
|
||||
|
||||
public func forward(count: Int) {
|
||||
|
@ -93,6 +96,14 @@ public class NavigationManager: NSObject, ObservableObject {
|
|||
backStack.append(currentURL)
|
||||
currentURL = removed.removeLast()
|
||||
backStack.append(contentsOf: removed)
|
||||
|
||||
navigationOperation.send(.forward(count: count))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension NavigationManager {
|
||||
enum Operation {
|
||||
case go, forward(count: Int), backward(count: Int)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,21 +2,22 @@
|
|||
// BrowserNavigationController.swift
|
||||
// Gemini-iOS
|
||||
//
|
||||
// Created by Shadowfacts on 12/16/20.
|
||||
// Created by Shadowfacts on 12/17/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import BrowserCore
|
||||
import Combine
|
||||
|
||||
class BrowserNavigationController: UINavigationController {
|
||||
class BrowserNavigationController: UIViewController {
|
||||
|
||||
let navigator: NavigationManager
|
||||
|
||||
var poppedViewControllers = [UIViewController]()
|
||||
var skipResetPoppedOnNextPush = false
|
||||
private var backBrowserVCs = [BrowserWebViewController]()
|
||||
private var forwardBrowserVCs = [BrowserWebViewController]()
|
||||
private var currentBrowserVC: BrowserWebViewController!
|
||||
|
||||
private var interactivePushTransition: InteractivePushTransition!
|
||||
private var gestureState: GestureState?
|
||||
|
||||
private var cancellables = [AnyCancellable]()
|
||||
|
||||
|
@ -24,74 +25,169 @@ class BrowserNavigationController: UINavigationController {
|
|||
self.navigator = navigator
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
navigator.$currentURL
|
||||
.sink { [weak self] (newURL) in
|
||||
self?.pushViewController(BrowserWebViewController(navigator: navigator, url: newURL), animated: true)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
interactivePushTransition = InteractivePushTransition(navigationController: self)
|
||||
view.backgroundColor = .systemBackground
|
||||
|
||||
currentBrowserVC = BrowserWebViewController(navigator: navigator, url: navigator.currentURL)
|
||||
embedChild(currentBrowserVC)
|
||||
|
||||
navigator.navigationOperation
|
||||
.sink(receiveValue: self.onNavigate)
|
||||
.store(in: &cancellables)
|
||||
|
||||
view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized)))
|
||||
}
|
||||
|
||||
override func popViewController(animated: Bool) -> UIViewController? {
|
||||
if let popped = super.popViewController(animated: animated) {
|
||||
poppedViewControllers.insert(popped, at: 0)
|
||||
return popped
|
||||
} else {
|
||||
return nil
|
||||
private func onNavigate(_ operation: NavigationManager.Operation) {
|
||||
let newVC: BrowserWebViewController
|
||||
|
||||
switch operation {
|
||||
case .go:
|
||||
backBrowserVCs.append(currentBrowserVC)
|
||||
newVC = BrowserWebViewController(navigator: navigator, url: navigator.currentURL)
|
||||
|
||||
case let .backward(count: count):
|
||||
var removed = backBrowserVCs.suffix(count)
|
||||
backBrowserVCs.removeLast(count)
|
||||
forwardBrowserVCs.insert(currentBrowserVC, at: 0)
|
||||
newVC = removed.removeFirst()
|
||||
forwardBrowserVCs.insert(contentsOf: removed, at: 0)
|
||||
|
||||
case let .forward(count: count):
|
||||
var removed = forwardBrowserVCs.prefix(count)
|
||||
forwardBrowserVCs.removeFirst(count)
|
||||
backBrowserVCs.append(currentBrowserVC)
|
||||
newVC = removed.removeFirst()
|
||||
backBrowserVCs.append(contentsOf: removed)
|
||||
}
|
||||
|
||||
currentBrowserVC.removeViewAndController()
|
||||
currentBrowserVC = newVC
|
||||
embedChild(newVC)
|
||||
}
|
||||
|
||||
private let startEdgeNavigationSwipeDistance: CGFloat = 75
|
||||
private let finishEdgeNavigationVelocityThreshold: CGFloat = 500
|
||||
private let edgeNavigationMaxDimmingAlpha: CGFloat = 0.35
|
||||
private let edgeNavigationParallaxFactor: CGFloat = 0.25
|
||||
private let totalEdgeNavigationTime: TimeInterval = 0.4
|
||||
|
||||
@objc private func panGestureRecognized(_ recognizer: UIPanGestureRecognizer) {
|
||||
let location = recognizer.location(in: view)
|
||||
let velocity = recognizer.velocity(in: view)
|
||||
|
||||
switch recognizer.state {
|
||||
case .began:
|
||||
if location.x < startEdgeNavigationSwipeDistance && velocity.x > 0 && navigator.backStack.count > 0 {
|
||||
let older = backBrowserVCs.last ?? BrowserWebViewController(navigator: navigator, url: navigator.backStack.last!)
|
||||
embedChild(older)
|
||||
older.view.layer.zPosition = -2
|
||||
older.view.transform = CGAffineTransform(translationX: -1 * edgeNavigationParallaxFactor * view.bounds.width, y: 0)
|
||||
|
||||
let dimmingView = UIView()
|
||||
dimmingView.translatesAutoresizingMaskIntoConstraints = false
|
||||
dimmingView.backgroundColor = .black
|
||||
dimmingView.layer.zPosition = -1
|
||||
dimmingView.alpha = edgeNavigationMaxDimmingAlpha
|
||||
view.embedSubview(dimmingView)
|
||||
let animator = UIViewPropertyAnimator(duration: totalEdgeNavigationTime, curve: .easeInOut) {
|
||||
dimmingView.alpha = 0
|
||||
older.view.transform = .identity
|
||||
self.currentBrowserVC.view.transform = CGAffineTransform(translationX: self.view.bounds.width, y: 0)
|
||||
}
|
||||
animator.addCompletion { (position) in
|
||||
dimmingView.removeFromSuperview()
|
||||
|
||||
older.view.transform = .identity
|
||||
older.view.layer.zPosition = 0
|
||||
older.removeViewAndController()
|
||||
|
||||
self.currentBrowserVC.view.transform = .identity
|
||||
|
||||
if position == .end {
|
||||
self.navigator.back()
|
||||
}
|
||||
}
|
||||
gestureState = .backwards(animator)
|
||||
} else if location.x > view.bounds.width - startEdgeNavigationSwipeDistance && velocity.x < 0 && navigator.forwardStack.count > 0 {
|
||||
let newer = forwardBrowserVCs.first ?? BrowserWebViewController(navigator: navigator, url: navigator.backStack.first!)
|
||||
embedChild(newer)
|
||||
newer.view.transform = CGAffineTransform(translationX: view.bounds.width, y: 0)
|
||||
newer.view.layer.zPosition = 2
|
||||
|
||||
let dimmingView = UIView()
|
||||
dimmingView.translatesAutoresizingMaskIntoConstraints = false
|
||||
dimmingView.backgroundColor = .black
|
||||
dimmingView.layer.zPosition = 1
|
||||
dimmingView.alpha = 0
|
||||
view.embedSubview(dimmingView)
|
||||
let animator = UIViewPropertyAnimator(duration: totalEdgeNavigationTime, curve: .easeInOut) {
|
||||
dimmingView.alpha = self.edgeNavigationMaxDimmingAlpha
|
||||
newer.view.transform = .identity
|
||||
self.currentBrowserVC.view.transform = CGAffineTransform(translationX: -1 * self.edgeNavigationParallaxFactor * self.view.bounds.width, y: 0)
|
||||
}
|
||||
animator.addCompletion { (position) in
|
||||
dimmingView.removeFromSuperview()
|
||||
|
||||
newer.removeViewAndController()
|
||||
newer.view.layer.zPosition = 0
|
||||
newer.view.transform = .identity
|
||||
|
||||
self.currentBrowserVC.view.transform = .identity
|
||||
|
||||
if position == .end {
|
||||
self.navigator.forward()
|
||||
}
|
||||
}
|
||||
gestureState = .forwards(animator)
|
||||
}
|
||||
|
||||
case .changed:
|
||||
let translation = recognizer.translation(in: view)
|
||||
|
||||
switch gestureState {
|
||||
case let .backwards(animator):
|
||||
animator.fractionComplete = translation.x / view.bounds.width
|
||||
case let .forwards(animator):
|
||||
animator.fractionComplete = abs(translation.x) / view.bounds.width
|
||||
case nil:
|
||||
break
|
||||
}
|
||||
|
||||
case .ended, .cancelled:
|
||||
switch gestureState {
|
||||
case let .backwards(animator):
|
||||
let shouldComplete = location.x > view.bounds.width / 2 || velocity.x > finishEdgeNavigationVelocityThreshold
|
||||
animator.isReversed = !shouldComplete
|
||||
animator.startAnimation()
|
||||
case let .forwards(animator):
|
||||
let shouldComplete = location.x < view.bounds.width / 2 || velocity.x < -finishEdgeNavigationVelocityThreshold
|
||||
animator.isReversed = !shouldComplete
|
||||
animator.startAnimation()
|
||||
case nil:
|
||||
break
|
||||
}
|
||||
|
||||
gestureState = nil
|
||||
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override func popToRootViewController(animated: Bool) -> [UIViewController]? {
|
||||
if let popped = super.popToRootViewController(animated: animated) {
|
||||
poppedViewControllers = popped
|
||||
return popped
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
override func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? {
|
||||
if let popped = super.popToViewController(viewController, animated: animated) {
|
||||
poppedViewControllers.insert(contentsOf: popped, at: 0)
|
||||
return popped
|
||||
} else {
|
||||
return nil
|
||||
extension BrowserNavigationController {
|
||||
enum GestureState {
|
||||
case backwards(UIViewPropertyAnimator)
|
||||
case forwards(UIViewPropertyAnimator)
|
||||
}
|
||||
}
|
||||
|
||||
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
|
||||
if skipResetPoppedOnNextPush {
|
||||
skipResetPoppedOnNextPush = false
|
||||
} else {
|
||||
self.poppedViewControllers = []
|
||||
}
|
||||
super.pushViewController(viewController, animated: animated)
|
||||
}
|
||||
|
||||
func onWillShow() {
|
||||
self.transitionCoordinator?.notifyWhenInteractionChanges({ (context) in
|
||||
if context.isCancelled {
|
||||
if self.interactivePushTransition.interactive {
|
||||
// when an interactive push gesture is cancelled, make sure to adding the VC that was being pushed back onto the popped stack so it doesn't disappear
|
||||
self.poppedViewControllers.insert(self.interactivePushTransition.pushingViewController!, at: 0)
|
||||
} else {
|
||||
// when an interactive pop gesture is cancelled (i.e. the user lifts their finger before it triggers),
|
||||
// the popViewController(animated:) method has already been called so the VC has already been added to the popped stack
|
||||
// so we make sure to remove it, otherwise there could be duplicate VCs on the navigation stasck
|
||||
self.poppedViewControllers.remove(at: 0)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -63,6 +63,8 @@ class BrowserWebViewController: UIViewController {
|
|||
view.backgroundColor = .systemBackground
|
||||
|
||||
webView = WKWebView()
|
||||
webView.backgroundColor = .systemBackground
|
||||
webView.isOpaque = false
|
||||
webView.navigationDelegate = self
|
||||
webView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(webView)
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
//
|
||||
// InteractivePushTransition.swift
|
||||
// Gemini-iOS
|
||||
//
|
||||
// Created by Shadowfacts on 12/16/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// Allows interactively moving forward through the navigation stack after popping
|
||||
/// Based on https://github.com/NSExceptional/TBInteractivePushTransition
|
||||
class InteractivePushTransition: UIPercentDrivenInteractiveTransition {
|
||||
|
||||
fileprivate let minimumPushVelocityThreshold: CGFloat = 700
|
||||
fileprivate let minimumPushDistanceThreshold: CGFloat = 0.5
|
||||
fileprivate let pushAnimationDuration: TimeInterval = 0.35
|
||||
|
||||
private(set) weak var navigationController: BrowserNavigationController!
|
||||
|
||||
private(set) weak var interactivePushGestureRecognizer: UIScreenEdgePanGestureRecognizer!
|
||||
|
||||
private(set) var interactive = false
|
||||
private(set) weak var pushingViewController: UIViewController?
|
||||
|
||||
init(navigationController: BrowserNavigationController) {
|
||||
super.init()
|
||||
|
||||
self.navigationController = navigationController
|
||||
|
||||
let interactivePushGestureRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handleSwipeForward(_:)))
|
||||
self.interactivePushGestureRecognizer = interactivePushGestureRecognizer
|
||||
|
||||
navigationController.delegate = self
|
||||
interactivePushGestureRecognizer.edges = .right
|
||||
interactivePushGestureRecognizer.require(toFail: navigationController.interactivePopGestureRecognizer!)
|
||||
navigationController.view.addGestureRecognizer(interactivePushGestureRecognizer)
|
||||
|
||||
let trackpadGestureRecognizer = TrackpadScrollGestureRecognizer(target: self, action: #selector(handleSwipeForward(_:)))
|
||||
trackpadGestureRecognizer.require(toFail: navigationController.interactivePopGestureRecognizer!)
|
||||
navigationController.view.addGestureRecognizer(trackpadGestureRecognizer)
|
||||
}
|
||||
|
||||
@objc func handleSwipeForward(_ recognizer: UIPanGestureRecognizer) {
|
||||
interactive = true
|
||||
|
||||
let velocity = recognizer.velocity(in: recognizer.view)
|
||||
let translation = recognizer.translation(in: recognizer.view)
|
||||
let dx = -translation.x / navigationController.view.bounds.width
|
||||
let vx = -velocity.x
|
||||
|
||||
switch recognizer.state {
|
||||
case .began:
|
||||
if let viewController = navigationController.poppedViewControllers.first {
|
||||
pushingViewController = viewController
|
||||
navigationController.poppedViewControllers.removeFirst()
|
||||
navigationController.skipResetPoppedOnNextPush = true
|
||||
navigationController.pushViewController(viewController, animated: true)
|
||||
} else {
|
||||
interactive = false
|
||||
}
|
||||
|
||||
case .changed:
|
||||
update(dx)
|
||||
|
||||
case .ended:
|
||||
if (dx > minimumPushDistanceThreshold || vx > minimumPushVelocityThreshold) {
|
||||
finish()
|
||||
} else {
|
||||
cancel()
|
||||
}
|
||||
interactive = false
|
||||
|
||||
default:
|
||||
cancel()
|
||||
interactive = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension InteractivePushTransition: UINavigationControllerDelegate {
|
||||
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
|
||||
self.navigationController.onWillShow()
|
||||
}
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
if operation == .push, interactive {
|
||||
return self
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
|
||||
if interactive {
|
||||
return self
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
extension InteractivePushTransition: UIViewControllerAnimatedTransitioning {
|
||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
return pushAnimationDuration
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
let toView = transitionContext.view(forKey: .to)!
|
||||
let fromView = transitionContext.view(forKey: .from)!
|
||||
|
||||
let dimmingView = UIView()
|
||||
dimmingView.backgroundColor = .black
|
||||
dimmingView.alpha = 0
|
||||
dimmingView.frame = fromView.frame
|
||||
|
||||
transitionContext.containerView.addSubview(dimmingView)
|
||||
transitionContext.containerView.addSubview(toView)
|
||||
|
||||
// modify frame of presented view to go from x = <screen width> to x = 0
|
||||
var frame = fromView.frame
|
||||
frame.origin.x = frame.width
|
||||
toView.frame = frame
|
||||
frame.origin.x = 0
|
||||
|
||||
// we want it linear while interactive, but we want the "ease out" animation
|
||||
// if the user flicks the screen ahrd enough to finish the transition without interaction
|
||||
let options = interactive ? UIView.AnimationOptions.curveLinear : .curveEaseOut
|
||||
|
||||
let duration = transitionDuration(using: transitionContext)
|
||||
UIView.animate(withDuration: duration, delay: 0, options: options, animations: {
|
||||
// these magic numbers scientifically determined by repeatedly adjusting and comparing to the system animation
|
||||
let translationDistance = -frame.size.width * 0.3
|
||||
fromView.transform = CGAffineTransform(translationX: translationDistance, y: 0)
|
||||
toView.frame = frame
|
||||
dimmingView.alpha = 0.075
|
||||
}) { (finished) in
|
||||
fromView.transform = .identity
|
||||
dimmingView.removeFromSuperview()
|
||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// UIViewController+Children.swift
|
||||
// Gemini-iOS
|
||||
//
|
||||
// Created by Shadowfacts on 12/17/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
// Based on MVCTodo by Dave DeLong: https://github.com/davedelong/MVCTodo/blob/841649dd6aa31bacda3ad7ef9a9a836f66281e50/MVCTodo/Extensions/UIViewController.swift
|
||||
extension UIViewController {
|
||||
func embedChild(_ newChild: UIViewController, in container: UIView? = nil) {
|
||||
// if the view controller is already a child of something else, remove it
|
||||
if let oldParent = newChild.parent, oldParent != self {
|
||||
newChild.beginAppearanceTransition(false, animated: false)
|
||||
newChild.willMove(toParent: nil)
|
||||
newChild.removeFromParent()
|
||||
|
||||
if newChild.viewIfLoaded?.superview != nil {
|
||||
newChild.viewIfLoaded?.removeFromSuperview()
|
||||
}
|
||||
|
||||
newChild.endAppearanceTransition()
|
||||
}
|
||||
|
||||
// since .view returns an IUO, by default the type of this is "UIView?"
|
||||
// explicitly type the variable because We Know Better™
|
||||
var targetContainer: UIView = container ?? self.view
|
||||
if !targetContainer.isContainedWithin(view) {
|
||||
targetContainer = view
|
||||
}
|
||||
|
||||
// add the view controller as a child
|
||||
if newChild.parent != self {
|
||||
newChild.beginAppearanceTransition(true, animated: false)
|
||||
addChild(newChild)
|
||||
newChild.didMove(toParent: self)
|
||||
targetContainer.embedSubview(newChild.view)
|
||||
newChild.endAppearanceTransition()
|
||||
} else {
|
||||
// the view controller is already a child
|
||||
// make sure it's in the right view
|
||||
|
||||
// we don't do the appearance transition stuff here,
|
||||
// because the vc is already a child, so *presumably*
|
||||
// that transition stuff has already appened
|
||||
targetContainer.embedSubview(newChild.view)
|
||||
}
|
||||
}
|
||||
|
||||
func removeViewAndController() {
|
||||
view.removeFromSuperview()
|
||||
removeFromParent()
|
||||
}
|
||||
}
|
||||
|
||||
// Based on MVCTodo by Dave DeLong: https://github.com/davedelong/MVCTodo/blob/841649dd6aa31bacda3ad7ef9a9a836f66281e50/MVCTodo/Extensions/UIView.swift
|
||||
extension UIView {
|
||||
func embedSubview(_ subview: UIView) {
|
||||
if subview.superview == self { return }
|
||||
|
||||
if subview.superview != nil {
|
||||
subview.removeFromSuperview()
|
||||
}
|
||||
|
||||
subview.frame = bounds
|
||||
addSubview(subview)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
subview.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
subview.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
subview.topAnchor.constraint(equalTo: topAnchor),
|
||||
subview.bottomAnchor.constraint(equalTo: bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
func isContainedWithin(_ other: UIView) -> Bool {
|
||||
var current: UIView? = self
|
||||
while let proposedView = current {
|
||||
if proposedView == other { return true }
|
||||
current = proposedView.superview
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -44,10 +44,10 @@
|
|||
D688F590258AC814003A0A73 /* HTMLEntities in Frameworks */ = {isa = PBXBuildFile; productRef = D688F58F258AC814003A0A73 /* HTMLEntities */; };
|
||||
D688F599258ACAAE003A0A73 /* BrowserWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F598258ACAAE003A0A73 /* BrowserWebViewController.swift */; };
|
||||
D688F5FF258ACE6B003A0A73 /* browser.css in Resources */ = {isa = PBXBuildFile; fileRef = D688F5FE258ACE6B003A0A73 /* browser.css */; };
|
||||
D688F621258B0811003A0A73 /* BrowserNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F620258B0811003A0A73 /* BrowserNavigationController.swift */; };
|
||||
D688F62A258B0833003A0A73 /* InteractivePushTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F629258B0833003A0A73 /* InteractivePushTransition.swift */; };
|
||||
D688F633258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */; };
|
||||
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 */; };
|
||||
D691A64E25217C6F00348C4B /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A64D25217C6F00348C4B /* Preferences.swift */; };
|
||||
D691A66725217FD800348C4B /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A66625217FD800348C4B /* PreferencesView.swift */; };
|
||||
D691A68725223A4700348C4B /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A68625223A4600348C4B /* NavigationBar.swift */; };
|
||||
|
@ -309,10 +309,10 @@
|
|||
D688F585258AC738003A0A73 /* GeminiHTMLRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeminiHTMLRenderer.swift; sourceTree = "<group>"; };
|
||||
D688F598258ACAAE003A0A73 /* BrowserWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserWebViewController.swift; sourceTree = "<group>"; };
|
||||
D688F5FE258ACE6B003A0A73 /* browser.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = browser.css; sourceTree = "<group>"; };
|
||||
D688F620258B0811003A0A73 /* BrowserNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserNavigationController.swift; sourceTree = "<group>"; };
|
||||
D688F629258B0833003A0A73 /* InteractivePushTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractivePushTransition.swift; sourceTree = "<group>"; };
|
||||
D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
D691A6762522382E00348C4B /* BrowserViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -581,10 +581,10 @@
|
|||
D6E152A424BFFDF500FDF9D3 /* AppDelegate.swift */,
|
||||
D6E152A624BFFDF500FDF9D3 /* SceneDelegate.swift */,
|
||||
D688F649258C17F3003A0A73 /* SymbolCache.swift */,
|
||||
D688F620258B0811003A0A73 /* BrowserNavigationController.swift */,
|
||||
D688F629258B0833003A0A73 /* InteractivePushTransition.swift */,
|
||||
D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */,
|
||||
D688F659258C2256003A0A73 /* BrowserNavigationController.swift */,
|
||||
D688F598258ACAAE003A0A73 /* BrowserWebViewController.swift */,
|
||||
D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */,
|
||||
D688F662258C2479003A0A73 /* UIViewController+Children.swift */,
|
||||
D691A6762522382E00348C4B /* BrowserViewController.swift */,
|
||||
D6E152A824BFFDF500FDF9D3 /* ContentView.swift */,
|
||||
D691A68625223A4600348C4B /* NavigationBar.swift */,
|
||||
|
@ -1103,9 +1103,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D688F621258B0811003A0A73 /* BrowserNavigationController.swift in Sources */,
|
||||
D691A66725217FD800348C4B /* PreferencesView.swift in Sources */,
|
||||
D688F62A258B0833003A0A73 /* InteractivePushTransition.swift in Sources */,
|
||||
D688F599258ACAAE003A0A73 /* BrowserWebViewController.swift in Sources */,
|
||||
D688F633258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift in Sources */,
|
||||
D6E152A524BFFDF500FDF9D3 /* AppDelegate.swift in Sources */,
|
||||
|
@ -1113,7 +1111,9 @@
|
|||
D6E152A724BFFDF500FDF9D3 /* SceneDelegate.swift in Sources */,
|
||||
D688F64A258C17F3003A0A73 /* SymbolCache.swift in Sources */,
|
||||
D62BCEE2252553620031D894 /* ActivityView.swift in Sources */,
|
||||
D688F65A258C2256003A0A73 /* BrowserNavigationController.swift in Sources */,
|
||||
D691A68725223A4700348C4B /* NavigationBar.swift in Sources */,
|
||||
D688F663258C2479003A0A73 /* UIViewController+Children.swift in Sources */,
|
||||
D691A64E25217C6F00348C4B /* Preferences.swift in Sources */,
|
||||
D6E152A924BFFDF500FDF9D3 /* ContentView.swift in Sources */,
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue