Simplify import .ovpn from Files
- Browse files directly from Organizer - Add "Import new host" entry to open imported hosts
This commit is contained in:
parent
7c6a404e4a
commit
2485c5b588
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Sge-vR-hZB">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Sge-vR-hZB">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
|
@ -206,11 +206,6 @@
|
|||
<action selector="close" destination="c0p-pg-Arz" id="yVS-jW-gwZ"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem key="rightBarButtonItem" systemItem="organize" id="Lcp-oT-AOy">
|
||||
<connections>
|
||||
<action selector="openConfigurationFile" destination="c0p-pg-Arz" id="E7s-pJ-8y6"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="c40-c8-YA4" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
@ -238,7 +233,7 @@
|
|||
<objects>
|
||||
<navigationController storyboardIdentifier="WizardHostIdentifier" id="xKb-d1-xzB" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="7oY-rT-q4A">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
|
@ -247,7 +242,7 @@
|
|||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="BvG-Pe-O1S" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-1727" y="-357"/>
|
||||
<point key="canvasLocation" x="-1700" y="-357"/>
|
||||
</scene>
|
||||
<!--Donation View Controller-->
|
||||
<scene sceneID="NrW-UF-gN3">
|
||||
|
@ -388,6 +383,7 @@
|
|||
<segue destination="POR-9u-PsE" kind="presentation" identifier="AboutSegueIdentifier" modalPresentationStyle="formSheet" id="78g-ra-Yhp"/>
|
||||
<segue destination="5ku-HX-5yk" kind="presentation" identifier="DonateSegueIdentifier" modalPresentationStyle="formSheet" id="H4q-BS-PmK"/>
|
||||
<segue destination="pel-Q7-aOe" kind="showDetail" identifier="SelectProfileSegueIdentifier" id="bkI-h9-mGF"/>
|
||||
<segue destination="xKb-d1-xzB" kind="presentation" identifier="ImportHostSegueIdentifier" id="lvz-gb-YiL"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="bGp-H5-24W" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue