Merge pull request #41 from passepartoutvpn/siri-shortcuts

Siri shortcuts
This commit is contained in:
Davide De Rosa 2019-03-18 22:42:19 +01:00 committed by GitHub
commit 745476e42e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 751 additions and 29 deletions

View File

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- Siri shortcuts. [#41](https://github.com/passepartoutvpn/passepartout-ios/pull/41)
## 1.1.0 Beta 1393 (2019-03-18)
### Fixed

View File

@ -21,6 +21,8 @@ internal enum StoryboardScene {
internal static let configurationIdentifier = SceneType<ConfigurationViewController>(storyboard: Main.self, identifier: "ConfigurationIdentifier")
internal static let providerPoolViewController = SceneType<ProviderPoolViewController>(storyboard: Main.self, identifier: "ProviderPoolViewController")
internal static let serviceIdentifier = SceneType<UIKit.UINavigationController>(storyboard: Main.self, identifier: "ServiceIdentifier")
}
internal enum Organizer: StoryboardType {
@ -32,6 +34,11 @@ internal enum StoryboardScene {
internal static let wizardHostIdentifier = SceneType<UIKit.UINavigationController>(storyboard: Organizer.self, identifier: "WizardHostIdentifier")
}
internal enum Shortcuts: StoryboardType {
internal static let storyboardName = "Shortcuts"
internal static let initialScene = InitialSceneType<UIKit.UINavigationController>(storyboard: Shortcuts.self)
}
}
// swiftlint:enable explicit_type_interface identifier_name line_length type_body_length type_name

View File

@ -26,8 +26,13 @@ internal enum StoryboardSegue {
case importHostSegueIdentifier = "ImportHostSegueIdentifier"
case selectProfileSegueIdentifier = "SelectProfileSegueIdentifier"
case showImportedHostsSegueIdentifier = "ShowImportedHostsSegueIdentifier"
case siriShortcutsSegueIdentifier = "SiriShortcutsSegueIdentifier"
case versionSegueIdentifier = "VersionSegueIdentifier"
}
internal enum Shortcuts: String, SegueType {
case connectToSegueIdentifier = "ConnectToSegueIdentifier"
case pickLocationSegueIdentifier = "PickLocationSegueIdentifier"
}
}
// swiftlint:enable explicit_type_interface identifier_name line_length type_body_length type_name

View File

@ -45,12 +45,19 @@ class OrganizerViewController: UITableViewController, TableModelHost {
let model: TableModel<SectionType, RowType> = TableModel()
model.add(.providers)
model.add(.hosts)
if #available(iOS 12, *) {
model.add(.siri)
}
model.add(.about)
model.add(.destruction)
model.setHeader(L10n.Organizer.Sections.Providers.header, for: .providers)
model.setHeader(L10n.Organizer.Sections.Hosts.header, for: .hosts)
model.setFooter(L10n.Organizer.Sections.Providers.footer, for: .providers)
model.setFooter(L10n.Organizer.Sections.Hosts.footer, for: .hosts)
if #available(iOS 12, *) {
model.setHeader(L10n.Organizer.Sections.Siri.header, for: .siri)
model.set([.siriShortcuts], in: .siri)
}
model.set([.openAbout], in: .about)
model.set([.uninstall], in: .destruction)
if AppConstants.Flags.isBeta {
@ -180,6 +187,10 @@ class OrganizerViewController: UITableViewController, TableModelHost {
perform(segue: StoryboardSegue.Organizer.showImportedHostsSegueIdentifier)
}
private func addShortcuts() {
perform(segue: StoryboardSegue.Organizer.siriShortcutsSegueIdentifier)
}
private func removeProfile(at indexPath: IndexPath) {
let sectionObject = model.section(for: indexPath.section)
let rowProfile = profileKey(at: indexPath)
@ -269,6 +280,8 @@ extension OrganizerViewController {
case hosts
case siri
case about
case destruction
@ -283,6 +296,8 @@ extension OrganizerViewController {
case addHost
case siriShortcuts
case openAbout
case uninstall
@ -347,6 +362,12 @@ extension OrganizerViewController {
cell.leftText = L10n.Organizer.Cells.AddHost.caption
return cell
case .siriShortcuts:
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
cell.applyAction(Theme.current)
cell.leftText = L10n.Organizer.Cells.SiriShortcuts.caption
return cell
case .openAbout:
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
cell.leftText = L10n.Organizer.Cells.About.caption(GroupConstants.App.name)
@ -381,6 +402,9 @@ extension OrganizerViewController {
case .addHost:
addNewHost()
case .siriShortcuts:
addShortcuts()
case .openAbout:
about()

View File

@ -0,0 +1,210 @@
//
// ShortcutsConnectToViewController.swift
// Passepartout-iOS
//
// Created by Davide De Rosa on 3/18/19.
// Copyright (c) 2019 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
import Intents
import IntentsUI
import Passepartout_Core
class ShortcutsConnectToViewController: UITableViewController, TableModelHost {
private let service = TransientStore.shared.service
private var providers: [String] = []
private var hosts: [String] = []
private var selectedProfile: ConnectionProfile?
// MARK: TableModelHost
let model: TableModel<SectionType, RowType> = {
let model: TableModel<SectionType, RowType> = TableModel()
model.setHeader(L10n.Organizer.Sections.Providers.header, for: .providers)
model.setHeader(L10n.Organizer.Sections.Hosts.header, for: .hosts)
return model
}()
func reloadModel() {
providers = service.ids(forContext: .provider).sorted()
hosts = service.ids(forContext: .host).sortedCaseInsensitive()
if !providers.isEmpty {
model.add(.providers)
model.set(.providerShortcut, count: providers.count, in: .providers)
}
if !hosts.isEmpty {
model.add(.hosts)
model.set(.hostShortcut, count: hosts.count, in: .hosts)
}
}
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
title = L10n.Shortcuts.Cells.Connect.caption
reloadModel()
}
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
guard identifier == StoryboardSegue.Shortcuts.pickLocationSegueIdentifier.rawValue else {
return false
}
guard let _ = selectedProfile as? ProviderConnectionProfile else {
return false
}
return true
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let vc = segue.destination as? ProviderPoolViewController else {
return
}
guard let provider = selectedProfile as? ProviderConnectionProfile else {
return
}
vc.pools = provider.sortedPools()
vc.delegate = self
}
}
extension ShortcutsConnectToViewController {
enum SectionType {
case providers
case hosts
}
enum RowType {
case providerShortcut
case hostShortcut
}
override func numberOfSections(in tableView: UITableView) -> Int {
return model.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return model.header(for: section)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.count(for: section)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
cell.apply(Theme.current)
switch model.row(at: indexPath) {
case .providerShortcut:
cell.leftText = providers[indexPath.row]
case .hostShortcut:
cell.leftText = hosts[indexPath.row]
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard #available(iOS 12, *) else {
return
}
switch model.row(at: indexPath) {
case .providerShortcut:
selectedProfile = service.profile(withContext: .provider, id: providers[indexPath.row])
pickProviderLocation()
case .hostShortcut:
selectedProfile = service.profile(withContext: .host, id: hosts[indexPath.row])
addConnect()
}
}
}
// MARK: Actions
@available(iOS 12, *)
extension ShortcutsConnectToViewController {
private func addConnect() {
guard let host = selectedProfile as? HostConnectionProfile else {
fatalError("Not a HostConnectionProfile")
}
let intent = ConnectVPNIntent()
intent.context = host.context.rawValue
intent.profileId = host.id
addShortcut(with: intent)
}
private func addMoveToLocation(pool: Pool) {
guard let provider = selectedProfile as? ProviderConnectionProfile else {
fatalError("Not a ProviderConnectionProfile")
}
let intent = MoveToLocationIntent()
intent.providerId = provider.id
intent.poolId = pool.id
intent.poolName = pool.name
addShortcut(with: intent)
}
private func addShortcut(with intent: INIntent) {
guard let shortcut = INShortcut(intent: intent) else {
return
}
let vc = INUIAddVoiceShortcutViewController(shortcut: shortcut)
vc.delegate = self
present(vc, animated: true, completion: nil)
}
private func pickProviderLocation() {
perform(segue: StoryboardSegue.Shortcuts.pickLocationSegueIdentifier)
}
@IBAction private func done() {
dismiss(animated: true, completion: nil)
}
}
extension ShortcutsConnectToViewController: ProviderPoolViewControllerDelegate {
func providerPoolController(_: ProviderPoolViewController, didSelectPool pool: Pool) {
guard #available(iOS 12, *) else {
return
}
addMoveToLocation(pool: pool)
}
}
@available(iOS 12, *)
extension ShortcutsConnectToViewController: INUIAddVoiceShortcutViewControllerDelegate {
func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) {
navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
}
func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) {
dismiss(animated: true, completion: nil)
}
}

View File

@ -0,0 +1,219 @@
//
// ShortcutsViewController.swift
// Passepartout-iOS
//
// Created by Davide De Rosa on 3/18/19.
// Copyright (c) 2019 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
import IntentsUI
import Passepartout_Core
class ShortcutsViewController: UITableViewController, TableModelHost {
// MARK: TableModel
let model: TableModel<SectionType, RowType> = {
let model: TableModel<SectionType, RowType> = TableModel()
model.add(.vpn)
model.add(.trust)
model.set([.connect, .enableVPN, .disableVPN], in: .vpn)
model.set([.trustWiFi, .untrustWiFi, .trustCellular, .untrustCellular], in: .trust)
model.setHeader(L10n.Shortcuts.Sections.Vpn.header, for: .vpn)
model.setHeader(L10n.Shortcuts.Sections.Trust.header, for: .trust)
return model
}()
func reloadModel() {
}
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
title = L10n.Organizer.Cells.SiriShortcuts.caption
// itemNext.title = L10n.Global.next
}
}
extension ShortcutsViewController {
enum SectionType {
case vpn
case trust
}
enum RowType {
case connect // host or provider+location
case enableVPN
case disableVPN
case trustWiFi
case untrustWiFi
case trustCellular
case untrustCellular
}
override func numberOfSections(in tableView: UITableView) -> Int {
return model.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return model.header(for: section)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.count(for: section)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
switch model.row(at: indexPath) {
case .connect:
cell.leftText = L10n.Shortcuts.Cells.Connect.caption
case .enableVPN:
cell.leftText = L10n.Shortcuts.Cells.EnableVpn.caption
case .disableVPN:
cell.leftText = L10n.Shortcuts.Cells.DisableVpn.caption
case .trustWiFi:
cell.leftText = L10n.Shortcuts.Cells.TrustWifi.caption
case .untrustWiFi:
cell.leftText = L10n.Shortcuts.Cells.UntrustWifi.caption
case .trustCellular:
cell.leftText = L10n.Shortcuts.Cells.TrustCellular.caption
case .untrustCellular:
cell.leftText = L10n.Shortcuts.Cells.UntrustCellular.caption
}
cell.apply(Theme.current)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard #available(iOS 12, *) else {
return
}
switch model.row(at: indexPath) {
case .connect:
addConnect()
case .enableVPN:
addEnable()
case .disableVPN:
addDisable()
case .trustWiFi:
addTrustWiFi()
case .untrustWiFi:
addUntrustWiFi()
case .trustCellular:
addTrustCellular()
case .untrustCellular:
addUntrustCellular()
}
}
}
// MARK: Actions
@available(iOS 12, *)
extension ShortcutsViewController {
private func addConnect() {
guard TransientStore.shared.service.hasProfiles() else {
let alert = Macros.alert(
L10n.Shortcuts.Cells.Connect.caption,
L10n.Shortcuts.Alerts.NoProfiles.message
)
alert.addAction(L10n.Global.ok) {
if let ip = self.tableView.indexPathForSelectedRow {
self.tableView.deselectRow(at: ip, animated: true)
}
}
present(alert, animated: true, completion: nil)
return
}
perform(segue: StoryboardSegue.Shortcuts.connectToSegueIdentifier)
}
private func addEnable() {
addShortcut(with: EnableVPNIntent())
}
private func addDisable() {
addShortcut(with: DisableVPNIntent())
}
private func addTrustWiFi() {
addShortcut(with: TrustCurrentNetworkIntent())
}
private func addUntrustWiFi() {
addShortcut(with: UntrustCurrentNetworkIntent())
}
private func addTrustCellular() {
addShortcut(with: TrustCellularNetworkIntent())
}
private func addUntrustCellular() {
addShortcut(with: UntrustCellularNetworkIntent())
}
private func addShortcut(with intent: INIntent) {
guard let shortcut = INShortcut(intent: intent) else {
return
}
let vc = INUIAddVoiceShortcutViewController(shortcut: shortcut)
vc.delegate = self
present(vc, animated: true, completion: nil)
}
@IBAction private func close() {
dismiss(animated: true, completion: nil)
}
}
@available(iOS 12, *)
extension ShortcutsViewController: INUIAddVoiceShortcutViewControllerDelegate {
func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) {
tableView.reloadData()
dismiss(animated: true, completion: nil)
}
func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) {
dismiss(animated: true, completion: nil)
}
}

View File

@ -50,7 +50,7 @@
<!--Endpoint View Controller-->
<scene sceneID="fdx-Ws-pNk">
<objects>
<viewController id="45O-Za-20g" customClass="EndpointViewController" customModule="Passepartout_iOS" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="45O-Za-20g" customClass="EndpointViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="S0h-YJ-nFv">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -59,7 +59,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="ToggleTableViewCell" textLabel="tkJ-X8-ifj" style="IBUITableViewCellStyleDefault" id="zPV-mL-RCK" customClass="ToggleTableViewCell" customModule="Passepartout_iOS" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="ToggleTableViewCell" textLabel="tkJ-X8-ifj" style="IBUITableViewCellStyleDefault" id="zPV-mL-RCK" customClass="ToggleTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="zPV-mL-RCK" id="Ybl-SJ-ptH">
@ -76,7 +76,7 @@
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="gkx-ms-Uex" detailTextLabel="9lm-24-5Gs" style="IBUITableViewCellStyleValue1" id="2y0-w2-QJ4" customClass="SettingTableViewCell" customModule="Passepartout_iOS" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="gkx-ms-Uex" detailTextLabel="9lm-24-5Gs" style="IBUITableViewCellStyleValue1" id="2y0-w2-QJ4" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="2y0-w2-QJ4" id="yVx-vY-0hM">
@ -128,7 +128,7 @@
<!--Service View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ServiceViewController" customModule="Passepartout_iOS" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="BYZ-38-t0r" customClass="ServiceViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -137,7 +137,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="SdF-Z2-0bH" detailTextLabel="SoE-OW-Xz5" style="IBUITableViewCellStyleValue1" id="RoI-rn-Np8" customClass="SettingTableViewCell" customModule="Passepartout_iOS" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="SdF-Z2-0bH" detailTextLabel="SoE-OW-Xz5" style="IBUITableViewCellStyleValue1" id="RoI-rn-Np8" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="RoI-rn-Np8" id="Dcf-DQ-j3p">
@ -161,7 +161,7 @@
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="ToggleTableViewCell" textLabel="RKE-mt-dZB" style="IBUITableViewCellStyleDefault" id="4W2-Qu-LR8" customClass="ToggleTableViewCell" customModule="Passepartout_iOS" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="ToggleTableViewCell" textLabel="RKE-mt-dZB" style="IBUITableViewCellStyleDefault" id="4W2-Qu-LR8" customClass="ToggleTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="4W2-Qu-LR8" id="6pB-5d-FaW">
@ -242,7 +242,7 @@
<!--Provider Pool View Controller-->
<scene sceneID="JAC-Ym-zYJ">
<objects>
<viewController id="Q5h-Xw-Yfl" customClass="ProviderPoolViewController" customModule="Passepartout_iOS" customModuleProvider="target" sceneMemberID="viewController">
<viewController storyboardIdentifier="ProviderPoolViewController" id="Q5h-Xw-Yfl" customClass="ProviderPoolViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="v5z-OX-y5O">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -251,7 +251,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="NBI-92-bcL" detailTextLabel="YdD-0I-AU2" style="IBUITableViewCellStyleValue1" id="5Tr-TW-Ejx" customClass="SettingTableViewCell" customModule="Passepartout_iOS" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="NBI-92-bcL" detailTextLabel="YdD-0I-AU2" style="IBUITableViewCellStyleValue1" id="5Tr-TW-Ejx" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5Tr-TW-Ejx" id="B1l-Jy-Mbs">
@ -303,7 +303,7 @@
<!--Account View Controller-->
<scene sceneID="ZzS-JO-Pmj">
<objects>
<viewController storyboardIdentifier="AccountIdentifier" id="eIk-8Z-CLS" customClass="AccountViewController" customModule="Passepartout_iOS" customModuleProvider="target" sceneMemberID="viewController">
<viewController storyboardIdentifier="AccountIdentifier" id="eIk-8Z-CLS" customClass="AccountViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="anF-dH-Q6h">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -312,7 +312,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="FieldTableViewCell" textLabel="VNs-lr-Nfh" style="IBUITableViewCellStyleDefault" id="Tqr-a6-Dqp" customClass="FieldTableViewCell" customModule="Passepartout_iOS" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="FieldTableViewCell" textLabel="VNs-lr-Nfh" style="IBUITableViewCellStyleDefault" id="Tqr-a6-Dqp" customClass="FieldTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Tqr-a6-Dqp" id="CnP-ta-5hH">
@ -363,7 +363,7 @@
<!--Debug Log View Controller-->
<scene sceneID="Icu-BA-Eze">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" id="KmS-dJ-DVx" customClass="DebugLogViewController" customModule="Passepartout_iOS" customModuleProvider="target" sceneMemberID="viewController">
<viewController extendedLayoutIncludesOpaqueBars="YES" id="KmS-dJ-DVx" customClass="DebugLogViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="DQA-dJ-PeF">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -422,7 +422,7 @@
<!--Provider Preset View Controller-->
<scene sceneID="H2q-58-oRM">
<objects>
<viewController id="9Kr-G1-asf" customClass="ProviderPresetViewController" customModule="Passepartout_iOS" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="9Kr-G1-asf" customClass="ProviderPresetViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="E57-aB-gwD">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -431,7 +431,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="8XN-Gu-lda" detailTextLabel="yBN-RJ-fm3" style="IBUITableViewCellStyleValue1" id="lIy-Qd-iAj" customClass="SettingTableViewCell" customModule="Passepartout_iOS" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="8XN-Gu-lda" detailTextLabel="yBN-RJ-fm3" style="IBUITableViewCellStyleValue1" id="lIy-Qd-iAj" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="lIy-Qd-iAj" id="XAe-s1-42s">
@ -483,7 +483,7 @@
<!--Configuration View Controller-->
<scene sceneID="EIh-pV-nh3">
<objects>
<viewController storyboardIdentifier="ConfigurationIdentifier" id="NJT-2N-LTa" customClass="ConfigurationViewController" customModule="Passepartout_iOS" customModuleProvider="target" sceneMemberID="viewController">
<viewController storyboardIdentifier="ConfigurationIdentifier" id="NJT-2N-LTa" customClass="ConfigurationViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="SJB-KR-s1d">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -492,7 +492,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="Bao-7G-pd5" detailTextLabel="Def-Vc-dwD" style="IBUITableViewCellStyleValue1" id="i8V-jj-yVi" customClass="SettingTableViewCell" customModule="Passepartout_iOS" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="Bao-7G-pd5" detailTextLabel="Def-Vc-dwD" style="IBUITableViewCellStyleValue1" id="i8V-jj-yVi" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="i8V-jj-yVi" id="zoa-z4-XD8">

View File

@ -165,13 +165,13 @@
<scene sceneID="0zM-zA-ZTU">
<objects>
<tableViewController id="c0p-pg-Arz" customClass="ImportedHostsViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="j8e-Ab-2SM">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="j8e-Ab-2SM">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="h2k-uQ-JBT" detailTextLabel="Tnk-4u-fB2" style="IBUITableViewCellStyleValue1" id="4dG-dn-eeq" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="4dG-dn-eeq" id="c48-Fg-ve4">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
@ -294,6 +294,7 @@
<segue destination="NVA-bQ-iIE" kind="presentation" identifier="AddProviderSegueIdentifier" modalPresentationStyle="formSheet" id="Win-5U-mIc"/>
<segue destination="a3d-vD-Pr7" kind="presentation" identifier="AboutSegueIdentifier" id="fd4-we-46n"/>
<segue destination="z6E-m6-Op0" kind="presentation" identifier="ShowImportedHostsSegueIdentifier" modalPresentationStyle="formSheet" id="TZv-OK-8vU"/>
<segue destination="BIO-UT-cpg" kind="presentation" identifier="SiriShortcutsSegueIdentifier" id="I9b-aK-jPT"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bGp-H5-24W" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -328,34 +329,34 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Kan-Ro-DbI">
<rect key="frame" x="0.0" y="0.0" width="375" height="491"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="309"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RP1-au-v0h">
<rect key="frame" x="28" y="40" width="319" height="411"/>
<rect key="frame" x="28" y="40" width="319" height="229"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logo" translatesAutoresizingMaskIntoConstraints="NO" id="eRj-AM-Edq">
<rect key="frame" x="59.5" y="0.0" width="200" height="200"/>
<rect key="frame" x="150.5" y="0.0" width="18" height="18"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;title&gt;" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Zek-qD-saW">
<rect key="frame" x="0.0" y="220" width="319" height="29"/>
<rect key="frame" x="0.0" y="38" width="319" height="29"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="24"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;version&gt;" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tOJ-Gb-6TL">
<rect key="frame" x="0.0" y="254" width="319" height="20.5"/>
<rect key="frame" x="0.0" y="72" width="319" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;intro&gt;" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="F6g-5X-yGY">
<rect key="frame" x="0.0" y="294.5" width="319" height="20.5"/>
<rect key="frame" x="0.0" y="112.5" width="319" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wV2-Nx-RuF">
<rect key="frame" x="0.0" y="335" width="319" height="33"/>
<rect key="frame" x="0.0" y="153" width="319" height="33"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<state key="normal" title="&lt;CL&gt;"/>
<connections>
@ -363,7 +364,7 @@
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rtK-wa-fgh">
<rect key="frame" x="0.0" y="378" width="319" height="33"/>
<rect key="frame" x="0.0" y="196" width="319" height="33"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<state key="normal" title="&lt;CRD&gt;"/>
<connections>
@ -624,9 +625,17 @@
</objects>
<point key="canvasLocation" x="-1012" y="-2248"/>
</scene>
<!--Shortcuts-->
<scene sceneID="JTQ-YD-jwv">
<objects>
<viewControllerPlaceholder storyboardName="Shortcuts" id="BIO-UT-cpg" sceneMemberID="viewController"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="Pbd-BC-bBJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-2449" y="-280"/>
</scene>
</scenes>
<resources>
<image name="logo" width="200" height="200"/>
<image name="logo" width="18.75" height="18.75"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="kwN-PZ-Zg5"/>

View File

@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="5sh-GP-KYT">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Shortcuts View Controller-->
<scene sceneID="F0m-Xp-5pf">
<objects>
<tableViewController id="mG2-gQ-aPy" customClass="ShortcutsViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="Iib-qS-k2f">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="uM1-Q0-TNy" detailTextLabel="3qI-Ca-OLt" style="IBUITableViewCellStyleValue1" id="fOB-T2-oQ9" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="fOB-T2-oQ9" id="lKF-U0-Np6">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="uM1-Q0-TNy">
<rect key="frame" x="16" y="12" width="33.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="3qI-Ca-OLt">
<rect key="frame" x="315" y="12" width="44" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="mG2-gQ-aPy" id="MGV-hJ-tKt"/>
<outlet property="delegate" destination="mG2-gQ-aPy" id="wNK-aT-dNi"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="Yck-NS-FzJ">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="8HE-Ax-VIa">
<connections>
<action selector="close" destination="mG2-gQ-aPy" id="Eua-Wd-kuz"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<segue destination="zpj-mS-isI" kind="show" identifier="ConnectToSegueIdentifier" id="Qer-qI-Oyn"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="0dW-yk-veP" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1494" y="-815"/>
</scene>
<!--Shortcuts Connect To View Controller-->
<scene sceneID="OTI-UR-MGw">
<objects>
<tableViewController id="zpj-mS-isI" customClass="ShortcutsConnectToViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="srP-K7-dae">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="4LM-xw-0Rx" detailTextLabel="4RM-B9-uCO" style="IBUITableViewCellStyleValue1" id="aw4-ca-yyE" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="aw4-ca-yyE" id="HBB-Gp-iw2">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="4LM-xw-0Rx">
<rect key="frame" x="16" y="12" width="33.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="4RM-B9-uCO">
<rect key="frame" x="315" y="12" width="44" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="zpj-mS-isI" id="tAY-f0-123"/>
<outlet property="delegate" destination="zpj-mS-isI" id="zex-yh-op8"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="kUu-WC-MJQ">
<barButtonItem key="rightBarButtonItem" style="done" systemItem="done" id="m8u-XK-MLx">
<connections>
<action selector="done" destination="zpj-mS-isI" id="f5U-ko-QS3"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<segue destination="bPc-ex-Jwe" kind="show" identifier="PickLocationSegueIdentifier" id="ah9-pc-zoh"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="HGx-xo-QOi" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2367" y="-815"/>
</scene>
<!--ProviderPoolViewController-->
<scene sceneID="Lbb-vN-6TM">
<objects>
<viewControllerPlaceholder storyboardName="Main" referencedIdentifier="ProviderPoolViewController" id="bPc-ex-Jwe" sceneMemberID="viewController"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="wiW-YP-buh" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3024" y="-816"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="qTb-wr-bYf">
<objects>
<navigationController id="5sh-GP-KYT" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="l2p-Xo-gm2">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="mG2-gQ-aPy" kind="relationship" relationship="rootViewController" id="vcT-cA-gf6"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dqv-Kz-2i6" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="674" y="-815"/>
</scene>
</scenes>
</document>

View File

@ -60,6 +60,10 @@
0E3152DD223FA06100F61841 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E05C5DF20D198B9006EE732 /* Localizable.strings */; };
0E3152DE223FA06400F61841 /* Web in Resources */ = {isa = PBXBuildFile; fileRef = 0E0EABC721DF853C0069DAE7 /* Web */; };
0E3152DF223FA1DD00F61841 /* ConnectionService.json in Resources */ = {isa = PBXBuildFile; fileRef = 0EBBE8F121822B4D00106008 /* ConnectionService.json */; };
0E36D24D2240234B006AF062 /* ShortcutsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E36D24C2240234B006AF062 /* ShortcutsViewController.swift */; };
0E36D25822403469006AF062 /* Shortcuts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E36D25A22403469006AF062 /* Shortcuts.storyboard */; };
0E36D25C224034AD006AF062 /* ShortcutsConnectToViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E36D25B224034AD006AF062 /* ShortcutsConnectToViewController.swift */; };
0E36D25D2240440B006AF062 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 0ED993B32240105E00B0F9C9 /* Intents.intentdefinition */; settings = {ATTRIBUTES = (no_codegen, ); }; };
0E3DA371215CB5BF00B40FC9 /* VersionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3DA370215CB5BF00B40FC9 /* VersionViewController.swift */; };
0E4C9CBB20DCF0D600A0C59C /* DestructiveTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E4C9CBA20DCF0D600A0C59C /* DestructiveTableViewCell.swift */; };
0E4FD7F120D58618002221FF /* Macros.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E4FD7F020D58618002221FF /* Macros.swift */; };
@ -172,6 +176,9 @@
0E31529E223F9EF500F61841 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0E3152A3223F9EF500F61841 /* Passepartout-CoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Passepartout-CoreTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0E3152AC223F9EF500F61841 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0E36D24C2240234B006AF062 /* ShortcutsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsViewController.swift; sourceTree = "<group>"; };
0E36D25922403469006AF062 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/Shortcuts.storyboard; sourceTree = "<group>"; };
0E36D25B224034AD006AF062 /* ShortcutsConnectToViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsConnectToViewController.swift; sourceTree = "<group>"; };
0E39BCEF214B9EF10035E9DE /* WebServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebServices.swift; sourceTree = "<group>"; };
0E39BCF2214DA9310035E9DE /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = "<group>"; };
0E3DA370215CB5BF00B40FC9 /* VersionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionViewController.swift; sourceTree = "<group>"; };
@ -391,6 +398,7 @@
0E57F63B20C83FC5008323CF /* AppDelegate.swift */,
0E57F63F20C83FC5008323CF /* Main.storyboard */,
0ED38ADC213F44D00004D387 /* Organizer.storyboard */,
0E36D25A22403469006AF062 /* Shortcuts.storyboard */,
0E57F64220C83FC7008323CF /* Assets.xcassets */,
0E57F64420C83FC7008323CF /* LaunchScreen.storyboard */,
0E57F64720C83FC7008323CF /* Info.plist */,
@ -406,6 +414,8 @@
0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */,
0EFD943F215BED8E00529B64 /* LabelViewController.swift */,
0EBE3A78213C4E5400BFA2F5 /* OrganizerViewController.swift */,
0E36D25B224034AD006AF062 /* ShortcutsConnectToViewController.swift */,
0E36D24C2240234B006AF062 /* ShortcutsViewController.swift */,
0E3DA370215CB5BF00B40FC9 /* VersionViewController.swift */,
0ED38AD8213F33150004D387 /* WizardHostViewController.swift */,
0E89DFCD213EEDFA00741BA1 /* WizardProviderViewController.swift */,
@ -756,6 +766,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E36D25822403469006AF062 /* Shortcuts.storyboard in Resources */,
0ED38ADA213F44D00004D387 /* Organizer.storyboard in Resources */,
0E57F64620C83FC7008323CF /* LaunchScreen.storyboard in Resources */,
0E57F64320C83FC7008323CF /* Assets.xcassets in Resources */,
@ -975,6 +986,7 @@
buildActionMask = 2147483647;
files = (
0ECEE44E20E1122200A6BB43 /* TableModel.swift in Sources */,
0E36D25D2240440B006AF062 /* Intents.intentdefinition in Sources */,
0ED38AD9213F33150004D387 /* WizardHostViewController.swift in Sources */,
0EE3BBB2215ED3A900F30952 /* AboutViewController.swift in Sources */,
0EBE3A79213C4E5500BFA2F5 /* OrganizerViewController.swift in Sources */,
@ -982,6 +994,7 @@
0EF5CF252141CE58004FF1BD /* HUD.swift in Sources */,
0E05C5D720D1645F006EE732 /* ToggleTableViewCell.swift in Sources */,
0E05C5D420D1645F006EE732 /* FieldTableViewCell.swift in Sources */,
0E36D25C224034AD006AF062 /* ShortcutsConnectToViewController.swift in Sources */,
0E05C61D20D27C82006EE732 /* Theme.swift in Sources */,
0ED38AEC2141260D0004D387 /* ConfigurationModificationDelegate.swift in Sources */,
0ECEE45020E1182E00A6BB43 /* Theme+Cells.swift in Sources */,
@ -1002,6 +1015,7 @@
0EB60FDA2111136E00AD27F3 /* UITextView+Search.swift in Sources */,
0EB67D6B2184581E00BA6200 /* ImportedHostsViewController.swift in Sources */,
0E57F63E20C83FC5008323CF /* ServiceViewController.swift in Sources */,
0E36D24D2240234B006AF062 /* ShortcutsViewController.swift in Sources */,
0EA068F4218475F800C320AD /* ParsingResult+Alerts.swift in Sources */,
0E57F63C20C83FC5008323CF /* AppDelegate.swift in Sources */,
0ED31C2920CF2A340027975F /* AccountViewController.swift in Sources */,
@ -1050,6 +1064,14 @@
name = Localizable.strings;
sourceTree = "<group>";
};
0E36D25A22403469006AF062 /* Shortcuts.storyboard */ = {
isa = PBXVariantGroup;
children = (
0E36D25922403469006AF062 /* en */,
);
name = Shortcuts.storyboard;
sourceTree = "<group>";
};
0E57F63F20C83FC5008323CF /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (

View File

@ -39,9 +39,11 @@
"organizer.sections.providers.footer" = "Here you find a few public infrastructures offering preset configuration profiles.";
"organizer.sections.hosts.header" = "Hosts";
"organizer.sections.hosts.footer" = "Import hosts from raw .ovpn configuration files.";
"organizer.sections.siri.header" = "Siri";
"organizer.cells.profile.value.current" = "In use";
"organizer.cells.add_provider.caption" = "Add new network";
"organizer.cells.add_host.caption" = "Add new host";
"organizer.cells.siri_shortcuts.caption" = "Add shortcuts";
"organizer.cells.about.caption" = "About %@";
"organizer.cells.uninstall.caption" = "Remove VPN configuration";
"organizer.alerts.exhausted_providers.message" = "You have created profiles for any available network.";
@ -190,6 +192,17 @@
"issue_reporter.email.body" = "Hi,\n\n%@\n\n%@\n\nRegards";
"issue_reporter.email.description" = "description of the issue:";
"shortcuts.sections.vpn.header" = "VPN";
"shortcuts.sections.trust.header" = "Trust";
"shortcuts.cells.connect.caption" = "Connect to";
"shortcuts.cells.enable_vpn.caption" = "Enable VPN";
"shortcuts.cells.disable_vpn.caption" = "Disable VPN";
"shortcuts.cells.trust_wifi.caption" = "Trust current Wi-Fi";
"shortcuts.cells.untrust_wifi.caption" = "Untrust current Wi-Fi";
"shortcuts.cells.trust_cellular.caption" = "Trust cellular network";
"shortcuts.cells.untrust_cellular.caption" = "Untrust cellular network";
"shortcuts.alerts.no_profiles.message" = "There is no profile to connect to.";
"about.title" = "About";
"about.sections.web.header" = "Web";
"about.sections.share.header" = "Share";

View File

@ -173,7 +173,7 @@
<key>INIntentRestrictions</key>
<integer>0</integer>
<key>INIntentTitle</key>
<string>Trust current network</string>
<string>Trust current Wi-Fi</string>
<key>INIntentTitleID</key>
<string>m2E7SI</string>
<key>INIntentType</key>
@ -317,7 +317,7 @@
<key>INIntentRestrictions</key>
<integer>0</integer>
<key>INIntentTitle</key>
<string>Untrust current network</string>
<string>Untrust current Wi-Fi</string>
<key>INIntentTitleID</key>
<string>rd1T8p</string>
<key>INIntentType</key>

View File

@ -291,6 +291,10 @@ public class ConnectionService: Codable {
// MARK: Profiles
public func hasProfiles() -> Bool {
return !cache.isEmpty
}
public func addProfile(_ profile: ConnectionProfile, credentials: Credentials?) -> Bool {
guard cache.index(forKey: ProfileKey(profile)) == nil else {
return false

View File

@ -352,6 +352,10 @@ public enum L10n {
public static let current = L10n.tr("Localizable", "organizer.cells.profile.value.current")
}
}
public enum SiriShortcuts {
/// Add shortcuts
public static let caption = L10n.tr("Localizable", "organizer.cells.siri_shortcuts.caption")
}
public enum Uninstall {
/// Remove VPN configuration
public static let caption = L10n.tr("Localizable", "organizer.cells.uninstall.caption")
@ -370,6 +374,10 @@ public enum L10n {
/// Networks
public static let header = L10n.tr("Localizable", "organizer.sections.providers.header")
}
public enum Siri {
/// Siri
public static let header = L10n.tr("Localizable", "organizer.sections.siri.header")
}
}
}
@ -642,6 +650,55 @@ public enum L10n {
public static let message = L10n.tr("Localizable", "share.message")
}
public enum Shortcuts {
public enum Alerts {
public enum NoProfiles {
/// There is no profile to connect to.
public static let message = L10n.tr("Localizable", "shortcuts.alerts.no_profiles.message")
}
}
public enum Cells {
public enum Connect {
/// Connect to
public static let caption = L10n.tr("Localizable", "shortcuts.cells.connect.caption")
}
public enum DisableVpn {
/// Disable VPN
public static let caption = L10n.tr("Localizable", "shortcuts.cells.disable_vpn.caption")
}
public enum EnableVpn {
/// Enable VPN
public static let caption = L10n.tr("Localizable", "shortcuts.cells.enable_vpn.caption")
}
public enum TrustCellular {
/// Trust cellular network
public static let caption = L10n.tr("Localizable", "shortcuts.cells.trust_cellular.caption")
}
public enum TrustWifi {
/// Trust current Wi-Fi
public static let caption = L10n.tr("Localizable", "shortcuts.cells.trust_wifi.caption")
}
public enum UntrustCellular {
/// Untrust cellular network
public static let caption = L10n.tr("Localizable", "shortcuts.cells.untrust_cellular.caption")
}
public enum UntrustWifi {
/// Untrust current Wi-Fi
public static let caption = L10n.tr("Localizable", "shortcuts.cells.untrust_wifi.caption")
}
}
public enum Sections {
public enum Trust {
/// Trust
public static let header = L10n.tr("Localizable", "shortcuts.sections.trust.header")
}
public enum Vpn {
/// VPN
public static let header = L10n.tr("Localizable", "shortcuts.sections.vpn.header")
}
}
}
public enum Version {
/// Version
public static let title = L10n.tr("Localizable", "version.title")

View File

@ -11,6 +11,7 @@ ib:
inputs:
- Passepartout-iOS/en.lproj/Main.storyboard
- Passepartout-iOS/en.lproj/Organizer.storyboard
- Passepartout-iOS/en.lproj/Shortcuts.storyboard
outputs:
- templateName: scenes-swift4
output: Passepartout-iOS/Global/SwiftGen+Scenes.swift