// // OAuthWebViewController.swift // OAuthSwift // // Created by Dongri Jin on 2/11/15. // Copyright (c) 2015 Dongri Jin. All rights reserved. // import Foundation #if os(iOS) || os(tvOS) import UIKit public typealias OAuthViewController = UIViewController #elseif os(watchOS) import WatchKit public typealias OAuthViewController = WKInterfaceController #elseif os(OSX) import AppKit public typealias OAuthViewController = NSViewController #endif /// Delegate for OAuthWebViewController public protocol OAuthWebViewControllerDelegate: class { #if os(iOS) || os(tvOS) /// Did web view presented (work only without navigation controller) func oauthWebViewControllerDidPresent() /// Did web view dismiss (work only without navigation controller) func oauthWebViewControllerDidDismiss() #endif func oauthWebViewControllerWillAppear() func oauthWebViewControllerDidAppear() func oauthWebViewControllerWillDisappear() func oauthWebViewControllerDidDisappear() } /// A web view controller, which handler OAuthSwift authentification. open class OAuthWebViewController: OAuthViewController, OAuthSwiftURLHandlerType { #if os(iOS) || os(tvOS) || os(OSX) /// Delegate for this view public weak var delegate: OAuthWebViewControllerDelegate? #endif #if os(iOS) || os(tvOS) /// If controller have an navigation controller, application top view controller could be used if true public var useTopViewControlerInsteadOfNavigation = false /// Set false to disable present animation. public var presentViewControllerAnimated = true /// Set false to disable dismiss animation. public var dismissViewControllerAnimated = true public var topViewController: UIViewController? { #if !OAUTH_APP_EXTENSIONS return UIApplication.topViewController #else return nil #endif } #elseif os(OSX) /// How to present this view controller if parent view controller set public enum Present { case asModalWindow case asSheet case asPopover(relativeToRect: NSRect, ofView : NSView, preferredEdge: NSRectEdge, behavior: NSPopover.Behavior) case transitionFrom(fromViewController: NSViewController, options: NSViewController.TransitionOptions) case animator(animator: NSViewControllerPresentationAnimator) case segue(segueIdentifier: String) } public var present: Present = .asModalWindow #endif open func handle(_ url: URL) { // do UI in main thread OAuthSwift.main { [unowned self] in self.doHandle(url) } } #if os(watchOS) public static var userActivityType: String = "org.github.dongri.oauthswift.connect" #endif open func doHandle(_ url: URL) { #if os(iOS) || os(tvOS) let completion: () -> Void = { [unowned self] in self.delegate?.oauthWebViewControllerDidPresent() } if let navigationController = self.navigationController, (!useTopViewControlerInsteadOfNavigation || self.topViewController == nil) { navigationController.pushViewController(self, animated: presentViewControllerAnimated) } else if let p = self.parent { p.present(self, animated: presentViewControllerAnimated, completion: completion) } else if let topViewController = topViewController { topViewController.present(self, animated: presentViewControllerAnimated, completion: completion) } else { // assert no presentation assertionFailure("Failed to present. Maybe add a parent") } #elseif os(watchOS) if url.scheme == "http" || url.scheme == "https" { self.updateUserActivity(OAuthWebViewController.userActivityType, userInfo: nil, webpageURL: url) } #elseif os(OSX) if let p = self.parent { // default behaviour if this controller affected as child controller switch self.present { case .asSheet: p.presentViewControllerAsSheet(self) case .asModalWindow: p.presentViewControllerAsModalWindow(self) // FIXME: if we present as window, window close must detected and oauthswift.cancel() must be called... case .asPopover(let positioningRect, let positioningView, let preferredEdge, let behavior): p.presentViewController(self, asPopoverRelativeTo: positioningRect, of: positioningView, preferredEdge: preferredEdge, behavior: behavior) case .transitionFrom(let fromViewController, let options): let completion: () -> Void = { /*[unowned self] in*/ //self.delegate?.oauthWebViewControllerDidPresent() } p.transition(from: fromViewController, to: self, options: options, completionHandler: completion) case .animator(let animator): p.presentViewController(self, animator: animator) case .segue(let segueIdentifier): p.performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: segueIdentifier), sender: self) // The segue must display self.view } } else if let window = self.view.window { window.makeKeyAndOrderFront(nil) } else { assertionFailure("Failed to present. Add controller into a window or add a parent") } // or create an NSWindow or NSWindowController (/!\ keep a strong reference on it) #endif } open func dismissWebViewController() { #if os(iOS) || os(tvOS) let completion: () -> Void = { [unowned self] in self.delegate?.oauthWebViewControllerDidDismiss() } if let navigationController = self.navigationController, (!useTopViewControlerInsteadOfNavigation || self.topViewController == nil) { navigationController.popViewController(animated: dismissViewControllerAnimated) } else if let parentViewController = self.parent { // The presenting view controller is responsible for dismissing the view controller it presented parentViewController.dismiss(animated: dismissViewControllerAnimated, completion: completion) } else if let topViewController = topViewController { topViewController.dismiss(animated: dismissViewControllerAnimated, completion: completion) } else { // keep old code... self.dismiss(animated: dismissViewControllerAnimated, completion: completion) } #elseif os(watchOS) self.dismiss() #elseif os(OSX) if self.presenting != nil { self.dismiss(nil) if self.parent != nil { self.removeFromParentViewController() } } else if let window = self.view.window { window.performClose(nil) } #endif } // MARK: overrides #if os(iOS) || os(tvOS) open override func viewWillAppear(_ animated: Bool) { self.delegate?.oauthWebViewControllerWillAppear() } open override func viewDidAppear(_ animated: Bool) { self.delegate?.oauthWebViewControllerDidAppear() } open override func viewWillDisappear(_ animated: Bool) { self.delegate?.oauthWebViewControllerWillDisappear() } open override func viewDidDisappear(_ animated: Bool) { self.delegate?.oauthWebViewControllerDidDisappear() } #elseif os(OSX) open override func viewWillAppear() { self.delegate?.oauthWebViewControllerWillAppear() } open override func viewDidAppear() { self.delegate?.oauthWebViewControllerDidAppear() } open override func viewWillDisappear() { self.delegate?.oauthWebViewControllerWillDisappear() } open override func viewDidDisappear() { self.delegate?.oauthWebViewControllerDidDisappear() } #endif }