From 2485c5b58863b28e551950674df8a74634cce098 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Fri, 17 Jul 2020 13:33:34 +0200 Subject: [PATCH 1/4] Simplify import .ovpn from Files - Browse files directly from Organizer - Add "Import new host" entry to open imported hosts --- .../Base.lproj/Organizer.storyboard | 14 ++--- .../Global/SwiftGen+Strings.swift | 6 ++- Passepartout-iOS/Global/en.lproj/App.strings | 3 +- .../ImportedHostsViewController.swift | 19 ------- .../Organizer/OrganizerViewController.swift | 51 +++++++++++++++++++ 5 files changed, 63 insertions(+), 30 deletions(-) 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) From 0acef41a7fafdb2d7293b6559a2c4d950d1e0fea Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Fri, 17 Jul 2020 14:20:41 +0200 Subject: [PATCH 2/4] Share import logic between browser and imported --- .../ImportedHostsViewController.swift | 74 +++---------------- .../Organizer/OrganizerViewController.swift | 10 +++ 2 files changed, 22 insertions(+), 62 deletions(-) diff --git a/Passepartout-iOS/Scenes/Organizer/ImportedHostsViewController.swift b/Passepartout-iOS/Scenes/Organizer/ImportedHostsViewController.swift index be763f92..d6914e6c 100644 --- a/Passepartout-iOS/Scenes/Organizer/ImportedHostsViewController.swift +++ b/Passepartout-iOS/Scenes/Organizer/ImportedHostsViewController.swift @@ -30,12 +30,14 @@ import PassepartoutCore private let log = SwiftyBeaver.self +protocol ImportedHostsViewControllerDelegate: class { + func importedHostsController(_: ImportedHostsViewController, didImport url: URL) +} + class ImportedHostsViewController: UITableViewController { private lazy var pendingConfigurationURLs = TransientStore.shared.service.pendingConfigurationURLs().sortedCaseInsensitive() - private var importer: HostImporter? - - private var parsingResult: OpenVPN.ConfigurationParser.Result? + weak var delegate: ImportedHostsViewControllerDelegate? override func viewDidLoad() { super.viewDidLoad() @@ -43,65 +45,8 @@ class ImportedHostsViewController: UITableViewController { title = L10n.App.ImportedHosts.title } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - parsingResult = nil - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - -// guard !pendingConfigurationURLs.isEmpty else { -// let alert = UIAlertController.asAlert( -// title, -// L10n.Core.Organizer.Alerts.AddHost.message -// ) -// alert.addCancelAction(L10n.Core.Global.ok) { -// self.close() -// } -// present(alert, animated: true, completion: nil) -// return -// } - if let selectedIP = tableView.indexPathForSelectedRow { - tableView.deselectRow(at: selectedIP, animated: true) - } - } - - // MARK: Actions - - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { - - // segue parses configuration file if not yet - if parsingResult == nil { - guard let cell = sender as? UITableViewCell, let indexPath = tableView.indexPath(for: cell) else { - return false - } - let url = pendingConfigurationURLs[indexPath.row] - return tryParseURL(url, cell: cell) - } - return true - } - - private func tryParseURL(_ url: URL, cell: UITableViewCell?) -> Bool { - deselectSelectedRow() - - importer = HostImporter(withConfigurationURL: url, parentViewController: self) - importer?.importHost(withPassphrase: nil, removeOnError: false, removeOnCancel: false) { - self.parsingResult = $0 - self.perform(segue: StoryboardSegue.Organizer.importHostSegueIdentifier) - } - return true - } - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - guard let wizard = segue.destination as? WizardHostViewController else { - return - } - wizard.parsingResult = parsingResult - - // retain back button - wizard.navigationItem.leftBarButtonItem = nil + private func selectHost(withUrl url: URL) { + delegate?.importedHostsController(self, didImport: url) } @IBAction private func close() { @@ -126,6 +71,11 @@ extension ImportedHostsViewController { cell.leftText = url.normalizedFilename return cell } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let url = pendingConfigurationURLs[indexPath.row] + selectHost(withUrl: url) + } override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true diff --git a/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift b/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift index b0e0deae..40dd79a1 100644 --- a/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift +++ b/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift @@ -175,6 +175,8 @@ class OrganizerViewController: UITableViewController, StrongTableHost { } vc.setProfile(selectedProfile) + } else if let vc = destination as? ImportedHostsViewController { + vc.delegate = self } else if let vc = destination as? WizardHostViewController { vc.parsingResult = hostParsingResult } @@ -788,6 +790,14 @@ extension OrganizerViewController: UIDocumentPickerDelegate { } } +extension OrganizerViewController: ImportedHostsViewControllerDelegate { + func importedHostsController(_: ImportedHostsViewController, didImport url: URL) { + dismiss(animated: true) { + self.tryParseHostURL(url) + } + } +} + extension OrganizerViewController: MFMailComposeViewControllerDelegate { func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { dismiss(animated: true, completion: nil) From 17aff3c9541b3a73aca4bf05d1f5f4a8b0a67857 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Thu, 23 Jul 2020 12:11:38 +0200 Subject: [PATCH 3/4] Add translations --- Passepartout-iOS/Global/SwiftGen+Strings.swift | 4 ++-- Passepartout-iOS/Global/de.lproj/App.strings | 3 ++- Passepartout-iOS/Global/el.lproj/App.strings | 3 ++- Passepartout-iOS/Global/en.lproj/App.strings | 4 ++-- Passepartout-iOS/Global/es.lproj/App.strings | 3 ++- Passepartout-iOS/Global/fr.lproj/App.strings | 3 ++- Passepartout-iOS/Global/it.lproj/App.strings | 3 ++- Passepartout-iOS/Global/nl.lproj/App.strings | 3 ++- Passepartout-iOS/Global/pl.lproj/App.strings | 3 ++- Passepartout-iOS/Global/pt.lproj/App.strings | 3 ++- Passepartout-iOS/Global/ru.lproj/App.strings | 3 ++- Passepartout-iOS/Global/sv.lproj/App.strings | 3 ++- Passepartout-iOS/Global/zh-Hans.lproj/App.strings | 3 ++- 13 files changed, 26 insertions(+), 15 deletions(-) diff --git a/Passepartout-iOS/Global/SwiftGen+Strings.swift b/Passepartout-iOS/Global/SwiftGen+Strings.swift index 048d5ee5..051fead4 100644 --- a/Passepartout-iOS/Global/SwiftGen+Strings.swift +++ b/Passepartout-iOS/Global/SwiftGen+Strings.swift @@ -58,7 +58,7 @@ internal enum L10n { internal enum Organizer { internal enum Cells { internal enum AddHost { - /// Browse configurations + /// Add from Files internal static let caption = L10n.tr("App", "organizer.cells.add_host.caption") } internal enum AddProvider { @@ -66,7 +66,7 @@ internal enum L10n { internal static let caption = L10n.tr("App", "organizer.cells.add_provider.caption") } internal enum ImportHost { - /// Imported configurations + /// Add from imported internal static let caption = L10n.tr("App", "organizer.cells.import_host.caption") } } diff --git a/Passepartout-iOS/Global/de.lproj/App.strings b/Passepartout-iOS/Global/de.lproj/App.strings index fcbadf9a..8769385e 100644 --- a/Passepartout-iOS/Global/de.lproj/App.strings +++ b/Passepartout-iOS/Global/de.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Neuen Anbieter hinzufügen"; -"organizer.cells.add_host.caption" = "Neuen Host hinzufügen"; +"organisator.cells.add_host.caption" = "Aus Dateien hinzufügen"; +"organisator.cells.import_host.caption" = "Vom Import hinzufügen"; "wizards.host.cells.title_input.caption" = "Titel"; "wizards.host.sections.existing.header" = "Bestehende Profile"; diff --git a/Passepartout-iOS/Global/el.lproj/App.strings b/Passepartout-iOS/Global/el.lproj/App.strings index 96f23493..4678174f 100644 --- a/Passepartout-iOS/Global/el.lproj/App.strings +++ b/Passepartout-iOS/Global/el.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Προσθήκη νέου παρόχου"; -"organizer.cells.add_host.caption" = "Προσθήκη νέου διακομιστή"; +"organizer.cells.add_host.caption" = "Προσθήκη από αρχεία"; +"organizer.cells.import_host.caption" = "Προσθήκη από εισαγωγή"; "wizards.host.cells.title_input.caption" = "Τίτλος"; "wizards.host.sections.existing.header" = "Υπάρχον Προφίλ"; diff --git a/Passepartout-iOS/Global/en.lproj/App.strings b/Passepartout-iOS/Global/en.lproj/App.strings index e16302e7..fe33797f 100644 --- a/Passepartout-iOS/Global/en.lproj/App.strings +++ b/Passepartout-iOS/Global/en.lproj/App.strings @@ -24,8 +24,8 @@ // "organizer.cells.add_provider.caption" = "Add new provider"; -"organizer.cells.add_host.caption" = "Browse configurations"; -"organizer.cells.import_host.caption" = "Imported configurations"; +"organizer.cells.add_host.caption" = "Add from Files"; +"organizer.cells.import_host.caption" = "Add from imported"; "wizards.host.cells.title_input.caption" = "Title"; "wizards.host.sections.existing.header" = "Existing profiles"; diff --git a/Passepartout-iOS/Global/es.lproj/App.strings b/Passepartout-iOS/Global/es.lproj/App.strings index 12b2a9fe..5a98b937 100644 --- a/Passepartout-iOS/Global/es.lproj/App.strings +++ b/Passepartout-iOS/Global/es.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Añadir proveedor"; -"organizer.cells.add_host.caption" = "Añadir host"; +"organizer.cells.add_host.caption" = "Añadir desde Ficheros"; +"organizer.cells.import_host.caption" = "Añadir desde importados"; "wizards.host.cells.title_input.caption" = "Título"; "wizards.host.sections.existing.header" = "Perfiles existentes"; diff --git a/Passepartout-iOS/Global/fr.lproj/App.strings b/Passepartout-iOS/Global/fr.lproj/App.strings index c8ca5a90..da0b8640 100644 --- a/Passepartout-iOS/Global/fr.lproj/App.strings +++ b/Passepartout-iOS/Global/fr.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Ajouter un nouveau fournisseur"; -"organizer.cells.add_host.caption" = "Ajouter un nouvel hôte"; +"organizer.cells.add_host.caption" = "Ajouter de Fichiers"; +"organizer.cells.import_host.caption" = "Ajouter depuis importé"; "wizards.host.cells.title_input.caption" = "Titre"; "wizards.host.sections.existing.header" = "Profiles existants"; diff --git a/Passepartout-iOS/Global/it.lproj/App.strings b/Passepartout-iOS/Global/it.lproj/App.strings index 2b40000a..9af69e9d 100644 --- a/Passepartout-iOS/Global/it.lproj/App.strings +++ b/Passepartout-iOS/Global/it.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Aggiungi provider"; -"organizer.cells.add_host.caption" = "Aggiungi host"; +"organizer.cells.add_host.caption" = "Aggiungi da Files"; +"organizer.cells.import_host.caption" = "Aggiungi da importati"; "wizards.host.cells.title_input.caption" = "Titolo"; "wizards.host.sections.existing.header" = "Profili esistenti"; diff --git a/Passepartout-iOS/Global/nl.lproj/App.strings b/Passepartout-iOS/Global/nl.lproj/App.strings index 03c7c9d5..bb255f01 100644 --- a/Passepartout-iOS/Global/nl.lproj/App.strings +++ b/Passepartout-iOS/Global/nl.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Voeg nieuwe aanbieder toe"; -"organizer.cells.add_host.caption" = "Voeg nieuwe host toe"; +"organizer.cells.add_host.caption" = "Toevoegen vanuit Bestanden"; +"organizer.cells.import_host.caption" = "Toevoegen vanuit geïmporteerd"; "wizards.host.cells.title_input.caption" = "Titel"; "wizards.host.sections.existing.header" = "Bestaande profielen"; diff --git a/Passepartout-iOS/Global/pl.lproj/App.strings b/Passepartout-iOS/Global/pl.lproj/App.strings index 5033479f..3ce258d7 100644 --- a/Passepartout-iOS/Global/pl.lproj/App.strings +++ b/Passepartout-iOS/Global/pl.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Dodaj nowego usługodawcę"; -"organizer.cells.add_host.caption" = "Dodaj nowy host"; +"organizer.cells.add_host.caption" = "Dodaj z Plików"; +"organizer.cells.import_host.caption" = "Dodaj z zaimportowanych"; "wizards.host.cells.title_input.caption" = "Tytuł"; "wizards.host.sections.existing.header" = "Istniejące profile"; diff --git a/Passepartout-iOS/Global/pt.lproj/App.strings b/Passepartout-iOS/Global/pt.lproj/App.strings index 603fa37a..4ac636c4 100644 --- a/Passepartout-iOS/Global/pt.lproj/App.strings +++ b/Passepartout-iOS/Global/pt.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Adicionar novo perfil"; -"organizer.cells.add_host.caption" = "Adicionar novo host"; +"organizer.cells.add_host.caption" = "Adicionar dos Arquivos"; +"organizer.cells.import_host.caption" = "Adicionar dos importados"; "wizards.host.cells.title_input.caption" = "Título"; "wizards.host.sections.existing.header" = "Perfis existentes"; diff --git a/Passepartout-iOS/Global/ru.lproj/App.strings b/Passepartout-iOS/Global/ru.lproj/App.strings index e0958731..d025836b 100644 --- a/Passepartout-iOS/Global/ru.lproj/App.strings +++ b/Passepartout-iOS/Global/ru.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Добавить нового провайдера"; -"organizer.cells.add_host.caption" = "Добавить новый хост"; +"organizer.cells.add_host.caption" = "Добавить из файлов"; +"organizer.cells.import_host.caption" = "Добавить из импортированных"; "wizards.host.cells.title_input.caption" = "Название"; "wizards.host.sections.existing.header" = "Существующие профили"; diff --git a/Passepartout-iOS/Global/sv.lproj/App.strings b/Passepartout-iOS/Global/sv.lproj/App.strings index 084f2032..d17d40c0 100644 --- a/Passepartout-iOS/Global/sv.lproj/App.strings +++ b/Passepartout-iOS/Global/sv.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "Lägg till ny leverantör"; -"organizer.cells.add_host.caption" = "Lägg till ny värd"; +"organizer.cells.add_host.caption" = "Lägg till från Filer"; +"organizer.cells.import_host.caption" = "Lägg till från importerad"; "wizards.host.cells.title_input.caption" = "Namn"; "wizards.host.sections.existing.header" = "Befintliga profiler"; diff --git a/Passepartout-iOS/Global/zh-Hans.lproj/App.strings b/Passepartout-iOS/Global/zh-Hans.lproj/App.strings index 3d0ba88b..af954b11 100644 --- a/Passepartout-iOS/Global/zh-Hans.lproj/App.strings +++ b/Passepartout-iOS/Global/zh-Hans.lproj/App.strings @@ -24,7 +24,8 @@ // "organizer.cells.add_provider.caption" = "添加新的提供商配置"; -"organizer.cells.add_host.caption" = "添加新的主机配置"; +"organizer.cells.add_host.caption" = "从文件添加"; +"organizer.cells.import_host.caption" = "从导入中添加"; "wizards.host.cells.title_input.caption" = "名称"; "wizards.host.sections.existing.header" = "已存在的配置"; From 27220cbf6a342354f57a492dc262660c32886181 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Thu, 23 Jul 2020 12:17:08 +0200 Subject: [PATCH 4/4] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed99c731..0c2aa991 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Changed +- Improved host import flow. - Use active profile name in iOS settings. ## 1.11.5 (2020-06-23)