diff --git a/Passepartout-iOS/Base.lproj/Organizer.storyboard b/Passepartout-iOS/Base.lproj/Organizer.storyboard index eb1941a3..8271a132 100644 --- a/Passepartout-iOS/Base.lproj/Organizer.storyboard +++ b/Passepartout-iOS/Base.lproj/Organizer.storyboard @@ -1,9 +1,9 @@ - + - + @@ -206,11 +206,6 @@ - - - - - @@ -238,7 +233,7 @@ - + @@ -247,7 +242,7 @@ - + @@ -388,6 +383,7 @@ + diff --git a/Passepartout-iOS/Global/SwiftGen+Strings.swift b/Passepartout-iOS/Global/SwiftGen+Strings.swift index 2e8e82a6..048d5ee5 100644 --- a/Passepartout-iOS/Global/SwiftGen+Strings.swift +++ b/Passepartout-iOS/Global/SwiftGen+Strings.swift @@ -58,13 +58,17 @@ internal enum L10n { internal enum Organizer { internal enum Cells { internal enum AddHost { - /// Add new host + /// Browse configurations internal static let caption = L10n.tr("App", "organizer.cells.add_host.caption") } internal enum AddProvider { /// Add new provider internal static let caption = L10n.tr("App", "organizer.cells.add_provider.caption") } + internal enum ImportHost { + /// Imported configurations + internal static let caption = L10n.tr("App", "organizer.cells.import_host.caption") + } } } internal enum Provider { diff --git a/Passepartout-iOS/Global/en.lproj/App.strings b/Passepartout-iOS/Global/en.lproj/App.strings index b82035d3..e16302e7 100644 --- a/Passepartout-iOS/Global/en.lproj/App.strings +++ b/Passepartout-iOS/Global/en.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Add new provider"; -"organizer.cells.add_host.caption" = "Add new host"; +"organizer.cells.add_host.caption" = "Browse configurations"; +"organizer.cells.import_host.caption" = "Imported configurations"; "wizards.host.cells.title_input.caption" = "Title"; "wizards.host.sections.existing.header" = "Existing profiles"; diff --git a/Passepartout-iOS/Scenes/Organizer/ImportedHostsViewController.swift b/Passepartout-iOS/Scenes/Organizer/ImportedHostsViewController.swift index c317547c..be763f92 100644 --- a/Passepartout-iOS/Scenes/Organizer/ImportedHostsViewController.swift +++ b/Passepartout-iOS/Scenes/Organizer/ImportedHostsViewController.swift @@ -70,13 +70,6 @@ class ImportedHostsViewController: UITableViewController { // MARK: Actions - @IBAction private func openConfigurationFile() { - let picker = UIDocumentPickerViewController(documentTypes: AppConstants.URLs.filetypes, in: .import) - picker.allowsMultipleSelection = false - picker.delegate = self - present(picker, animated: true, completion: nil) - } - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { // segue parses configuration file if not yet @@ -145,15 +138,3 @@ extension ImportedHostsViewController { tableView.deleteRows(at: [indexPath], with: .top) } } - -extension ImportedHostsViewController: UIDocumentPickerDelegate { - func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { - } - - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - guard let url = urls.first else { - return - } - _ = tryParseURL(url, cell: nil) - } -} diff --git a/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift b/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift index bc9f3ef8..b0e0deae 100644 --- a/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift +++ b/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift @@ -41,6 +41,10 @@ class OrganizerViewController: UITableViewController, StrongTableHost { private var hosts: [String] = [] private var didShowSubreddit = false + + private var importer: HostImporter? + + private var hostParsingResult: OpenVPN.ConfigurationParser.Result? // MARK: StrongTableHost @@ -93,6 +97,7 @@ class OrganizerViewController: UITableViewController, StrongTableHost { var hostRows = [RowType](repeating: .profile, count: hosts.count) providerRows.append(.addProvider) hostRows.append(.addHost) + hostRows.append(.importHost) model.set(providerRows, forSection: .providers) model.set(hostRows, forSection: .hosts) @@ -170,6 +175,8 @@ class OrganizerViewController: UITableViewController, StrongTableHost { } vc.setProfile(selectedProfile) + } else if let vc = destination as? WizardHostViewController { + vc.parsingResult = hostParsingResult } } @@ -200,6 +207,27 @@ class OrganizerViewController: UITableViewController, StrongTableHost { } private func addNewHost() { + if TransientStore.shared.service.hasReachedMaximumNumberOfHosts { + guard ProductManager.shared.isEligible(forFeature: .unlimitedHosts) else { + presentPurchaseScreen(forProduct: .unlimitedHosts) + return + } + } + let picker = UIDocumentPickerViewController(documentTypes: AppConstants.URLs.filetypes, in: .import) + picker.allowsMultipleSelection = false + picker.delegate = self + present(picker, animated: true, completion: nil) + } + + private func tryParseHostURL(_ url: URL) { + importer = HostImporter(withConfigurationURL: url, parentViewController: self) + importer?.importHost(withPassphrase: nil, removeOnError: false, removeOnCancel: false) { + self.hostParsingResult = $0 + self.perform(segue: StoryboardSegue.Organizer.importHostSegueIdentifier) + } + } + + private func importNewHost() { if TransientStore.shared.service.hasReachedMaximumNumberOfHosts { guard ProductManager.shared.isEligible(forFeature: .unlimitedHosts) else { presentPurchaseScreen(forProduct: .unlimitedHosts) @@ -419,6 +447,8 @@ extension OrganizerViewController { case addHost + case importHost + case siriShortcuts case donate @@ -499,6 +529,12 @@ extension OrganizerViewController { cell.leftText = L10n.App.Organizer.Cells.AddHost.caption return cell + case .importHost: + let cell = Cells.setting.dequeue(from: tableView, for: indexPath) + cell.applyAction(.current) + cell.leftText = L10n.App.Organizer.Cells.ImportHost.caption + return cell + case .siriShortcuts: let cell = Cells.setting.dequeue(from: tableView, for: indexPath) cell.applyAction(.current) @@ -572,6 +608,9 @@ extension OrganizerViewController { case .addHost: addNewHost() + case .importHost: + importNewHost() + case .siriShortcuts: addShortcuts() @@ -737,6 +776,18 @@ extension OrganizerViewController: ConnectionServiceDelegate { } } +extension OrganizerViewController: UIDocumentPickerDelegate { + func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { + } + + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + guard let url = urls.first else { + return + } + tryParseHostURL(url) + } +} + extension OrganizerViewController: MFMailComposeViewControllerDelegate { func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { dismiss(animated: true, completion: nil)