Merge branch 'bad-host-wizard-flow'
This commit is contained in:
commit
e3d2d54226
|
@ -89,53 +89,50 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
|
||||||
guard let root = window?.rootViewController else {
|
guard let root = window?.rootViewController else {
|
||||||
fatalError("No window.rootViewController?")
|
fatalError("No window.rootViewController?")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let topmost = root.presentedViewController ?? root
|
||||||
|
|
||||||
let fm = FileManager.default
|
let fm = FileManager.default
|
||||||
guard let parsedFile = ParsedFile.from(url, withErrorAlertIn: root) else {
|
guard let parsedFile = ParsedFile.from(url, withErrorAlertIn: topmost) else {
|
||||||
try? fm.removeItem(at: url)
|
try? fm.removeItem(at: url)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if let warning = parsedFile.warning {
|
if let warning = parsedFile.warning {
|
||||||
ParsedFile.alertImportWarning(url: url, in: root, withWarning: warning) {
|
ParsedFile.alertImportWarning(url: url, in: topmost, withWarning: warning) {
|
||||||
if $0 {
|
if $0 {
|
||||||
self.handleParsedFile(parsedFile, in: root)
|
self.handleParsedFile(parsedFile, in: topmost)
|
||||||
} else {
|
} else {
|
||||||
try? fm.removeItem(at: url)
|
try? fm.removeItem(at: url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
handleParsedFile(parsedFile, in: root)
|
handleParsedFile(parsedFile, in: topmost)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleParsedFile(_ parsedFile: ParsedFile, in root: UIViewController) {
|
private func handleParsedFile(_ parsedFile: ParsedFile, in target: UIViewController) {
|
||||||
|
|
||||||
// already presented: update parsed configuration
|
// already presented: update parsed configuration
|
||||||
if let nav = root.presentedViewController as? UINavigationController, let wizard = nav.topViewController as? WizardHostViewController {
|
if let nav = target as? UINavigationController, let wizard = nav.topViewController as? WizardHostViewController {
|
||||||
|
if let oldURL = wizard.parsedFile?.url {
|
||||||
|
try? FileManager.default.removeItem(at: oldURL)
|
||||||
|
}
|
||||||
wizard.parsedFile = parsedFile
|
wizard.parsedFile = parsedFile
|
||||||
wizard.removesConfigurationOnCancel = true
|
wizard.removesConfigurationOnCancel = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// present now
|
// present now
|
||||||
let nav = StoryboardScene.Organizer.wizardHostIdentifier.instantiate()
|
let wizardNav = StoryboardScene.Organizer.wizardHostIdentifier.instantiate()
|
||||||
guard let wizard = nav.topViewController as? WizardHostViewController else {
|
guard let wizard = wizardNav.topViewController as? WizardHostViewController else {
|
||||||
fatalError("Expected WizardHostViewController from storyboard")
|
fatalError("Expected WizardHostViewController from storyboard")
|
||||||
}
|
}
|
||||||
wizard.parsedFile = parsedFile
|
wizard.parsedFile = parsedFile
|
||||||
wizard.removesConfigurationOnCancel = true
|
wizard.removesConfigurationOnCancel = true
|
||||||
|
|
||||||
// best effort to delegate to main vc
|
wizardNav.modalPresentationStyle = .formSheet
|
||||||
let split = root as? UISplitViewController
|
target.present(wizardNav, animated: true, completion: nil)
|
||||||
let master = split?.viewControllers.first as? UINavigationController
|
|
||||||
master?.viewControllers.forEach {
|
|
||||||
if let organizerVC = $0 as? OrganizerViewController {
|
|
||||||
wizard.delegate = organizerVC
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nav.modalPresentationStyle = .formSheet
|
|
||||||
root.present(nav, animated: true, completion: nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,6 @@ class ImportedHostsViewController: UITableViewController {
|
||||||
|
|
||||||
private var parsedFile: ParsedFile?
|
private var parsedFile: ParsedFile?
|
||||||
|
|
||||||
weak var wizardDelegate: WizardDelegate?
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
@ -104,7 +102,6 @@ class ImportedHostsViewController: UITableViewController {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wizard.parsedFile = parsedFile
|
wizard.parsedFile = parsedFile
|
||||||
wizard.delegate = wizardDelegate
|
|
||||||
|
|
||||||
// retain back button
|
// retain back button
|
||||||
wizard.navigationItem.leftBarButtonItem = nil
|
wizard.navigationItem.leftBarButtonItem = nil
|
||||||
|
|
|
@ -69,6 +69,10 @@ class OrganizerViewController: UITableViewController, TableModelHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UIViewController
|
// MARK: UIViewController
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
|
@ -90,6 +94,8 @@ class OrganizerViewController: UITableViewController, TableModelHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
service.delegate = self
|
service.delegate = self
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(wizardDidCreate(notification:)), name: .WizardDidCreate, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
|
@ -134,13 +140,8 @@ class OrganizerViewController: UITableViewController, TableModelHost {
|
||||||
assert(selectedProfile != nil, "No selected profile")
|
assert(selectedProfile != nil, "No selected profile")
|
||||||
|
|
||||||
vc.profile = selectedProfile
|
vc.profile = selectedProfile
|
||||||
} else if let vc = destination as? Wizard {
|
} else if let providerVC = destination as? WizardProviderViewController {
|
||||||
if let providerVC = vc as? WizardProviderViewController {
|
providerVC.availableNames = availableProviderNames ?? []
|
||||||
providerVC.availableNames = availableProviderNames ?? []
|
|
||||||
}
|
|
||||||
vc.delegate = self
|
|
||||||
} else if let vc = destination as? ImportedHostsViewController {
|
|
||||||
vc.wizardDelegate = self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,14 +437,34 @@ extension OrganizerViewController: ConnectionServiceDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension OrganizerViewController: WizardDelegate {
|
extension OrganizerViewController {
|
||||||
func wizard(didCreate profile: ConnectionProfile, withCredentials credentials: Credentials) {
|
@objc private func wizardDidCreate(notification: Notification) {
|
||||||
|
guard let profile = notification.userInfo?[WizardCreationKey.profile] as? ConnectionProfile,
|
||||||
|
let credentials = notification.userInfo?[WizardCreationKey.credentials] as? Credentials else {
|
||||||
|
|
||||||
|
fatalError("WizardDidCreate notification must post profile and credentials")
|
||||||
|
}
|
||||||
|
|
||||||
service.addOrReplaceProfile(profile, credentials: credentials)
|
service.addOrReplaceProfile(profile, credentials: credentials)
|
||||||
TransientStore.shared.serialize() // add
|
TransientStore.shared.serialize() // add
|
||||||
|
|
||||||
reloadModel()
|
reloadModel()
|
||||||
tableView.reloadData()
|
tableView.reloadData()
|
||||||
|
|
||||||
|
// XXX: hack around bad replace when detail presented in compact view
|
||||||
|
if let detailNav = navigationController?.viewControllers.last as? UINavigationController {
|
||||||
|
var existingServiceVC: ServiceViewController?
|
||||||
|
for vc in detailNav.viewControllers {
|
||||||
|
if let found = vc as? ServiceViewController {
|
||||||
|
existingServiceVC = found
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let serviceVC = existingServiceVC ?? (StoryboardScene.Main.serviceIdentifier.instantiate().topViewController as! ServiceViewController)
|
||||||
|
serviceVC.profile = profile
|
||||||
|
detailNav.setViewControllers([serviceVC], animated: true)
|
||||||
|
return
|
||||||
|
}
|
||||||
perform(segue: StoryboardSegue.Organizer.selectProfileSegueIdentifier, sender: profile)
|
perform(segue: StoryboardSegue.Organizer.selectProfileSegueIdentifier, sender: profile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ import SwiftyBeaver
|
||||||
|
|
||||||
private let log = SwiftyBeaver.self
|
private let log = SwiftyBeaver.self
|
||||||
|
|
||||||
class WizardHostViewController: UITableViewController, TableModelHost, Wizard {
|
class WizardHostViewController: UITableViewController, TableModelHost {
|
||||||
@IBOutlet private weak var itemNext: UIBarButtonItem!
|
@IBOutlet private weak var itemNext: UIBarButtonItem!
|
||||||
|
|
||||||
private let existingHosts: [String] = {
|
private let existingHosts: [String] = {
|
||||||
|
@ -46,8 +46,6 @@ class WizardHostViewController: UITableViewController, TableModelHost, Wizard {
|
||||||
|
|
||||||
private var createdProfile: HostConnectionProfile?
|
private var createdProfile: HostConnectionProfile?
|
||||||
|
|
||||||
weak var delegate: WizardDelegate?
|
|
||||||
|
|
||||||
// MARK: TableModelHost
|
// MARK: TableModelHost
|
||||||
|
|
||||||
lazy var model: TableModel<SectionType, RowType> = {
|
lazy var model: TableModel<SectionType, RowType> = {
|
||||||
|
@ -89,12 +87,7 @@ class WizardHostViewController: UITableViewController, TableModelHost, Wizard {
|
||||||
// MARK: Actions
|
// MARK: Actions
|
||||||
|
|
||||||
private func useSuggestedTitle() {
|
private func useSuggestedTitle() {
|
||||||
guard let field = cellTitle?.field else {
|
cellTitle?.field.text = parsedFile?.url.normalizedFilename
|
||||||
return
|
|
||||||
}
|
|
||||||
if field.text?.isEmpty ?? true {
|
|
||||||
field.text = parsedFile?.url.normalizedFilename
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction private func next() {
|
@IBAction private func next() {
|
||||||
|
@ -150,7 +143,10 @@ class WizardHostViewController: UITableViewController, TableModelHost, Wizard {
|
||||||
}
|
}
|
||||||
|
|
||||||
dismiss(animated: true) {
|
dismiss(animated: true) {
|
||||||
self.delegate?.wizard(didCreate: profile, withCredentials: credentials)
|
NotificationCenter.default.post(name: .WizardDidCreate, object: nil, userInfo: [
|
||||||
|
WizardCreationKey.profile: profile,
|
||||||
|
WizardCreationKey.credentials: credentials
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,11 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
class WizardProviderViewController: UITableViewController, Wizard {
|
class WizardProviderViewController: UITableViewController {
|
||||||
var availableNames: [Infrastructure.Name] = []
|
var availableNames: [Infrastructure.Name] = []
|
||||||
|
|
||||||
private var createdProfile: ProviderConnectionProfile?
|
private var createdProfile: ProviderConnectionProfile?
|
||||||
|
|
||||||
weak var delegate: WizardDelegate?
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
@ -55,7 +53,10 @@ class WizardProviderViewController: UITableViewController, Wizard {
|
||||||
fatalError("No profile created?")
|
fatalError("No profile created?")
|
||||||
}
|
}
|
||||||
dismiss(animated: true) {
|
dismiss(animated: true) {
|
||||||
self.delegate?.wizard(didCreate: profile, withCredentials: credentials)
|
NotificationCenter.default.post(name: .WizardDidCreate, object: nil, userInfo: [
|
||||||
|
WizardCreationKey.profile: profile,
|
||||||
|
WizardCreationKey.credentials: credentials
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,12 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol Wizard: class {
|
extension Notification.Name {
|
||||||
var delegate: WizardDelegate? { get set }
|
static let WizardDidCreate = Notification.Name("WizardDidCreate")
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol WizardDelegate: class {
|
enum WizardCreationKey: String {
|
||||||
func wizard(didCreate profile: ConnectionProfile, withCredentials credentials: Credentials)
|
case profile
|
||||||
|
|
||||||
|
case credentials
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue