--- /dev/null
+//
+// 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
+}