Add server network screen

This commit is contained in:
Davide De Rosa 2019-10-23 10:52:15 +02:00
parent 458041bdc8
commit e0a9fadac4
8 changed files with 352 additions and 5 deletions

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="AAm-3V-G5F">
<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="AAm-3V-G5F">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -123,6 +123,51 @@
</objects>
<point key="canvasLocation" x="1623" y="615"/>
</scene>
<!--Server Network View Controller-->
<scene sceneID="zvO-7K-cxo">
<objects>
<tableViewController storyboardIdentifier="ServerNetworkViewController" id="U8z-C0-niN" customClass="ServerNetworkViewController" 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="IuJ-mU-wUI">
<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="C7r-of-xgp" detailTextLabel="3ra-wB-Rsp" style="IBUITableViewCellStyleValue1" id="Nje-05-XmA" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Nje-05-XmA" id="Dzn-g9-D3E">
<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="C7r-of-xgp">
<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="3ra-wB-Rsp">
<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="U8z-C0-niN" id="Loi-e1-yhX"/>
<outlet property="delegate" destination="U8z-C0-niN" id="Cg5-CL-mfg"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="f3v-na-5fa"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="0cT-d7-YMm" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2818" y="950"/>
</scene>
<!--Service View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
@ -232,6 +277,7 @@
<segue destination="9Kr-G1-asf" kind="show" identifier="ProviderPresetSegueIdentifier" id="kGf-Yu-KdY"/>
<segue destination="KmS-dJ-DVx" kind="show" identifier="DebugLogSegueIdentifier" id="XyI-by-AhD"/>
<segue destination="BCT-c7-ovS" kind="show" identifier="NetworkSettingsSegueIdentifier" id="5nM-PM-q9h"/>
<segue destination="U8z-C0-niN" kind="show" identifier="ServerNetworkSegueIdentifier" id="s57-gm-HT0"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>

View File

@ -28,6 +28,8 @@ internal enum StoryboardScene {
internal static let providerPoolViewController = SceneType<ProviderPoolViewController>(storyboard: Main.self, identifier: "ProviderPoolViewController")
internal static let serverNetworkViewController = SceneType<ServerNetworkViewController>(storyboard: Main.self, identifier: "ServerNetworkViewController")
internal static let serviceIdentifier = SceneType<UIKit.UINavigationController>(storyboard: Main.self, identifier: "ServiceIdentifier")
}
internal enum Organizer: StoryboardType {

View File

@ -24,6 +24,7 @@ internal enum StoryboardSegue {
case networkSettingsSegueIdentifier = "NetworkSettingsSegueIdentifier"
case providerPoolSegueIdentifier = "ProviderPoolSegueIdentifier"
case providerPresetSegueIdentifier = "ProviderPresetSegueIdentifier"
case serverNetworkSegueIdentifier = "ServerNetworkSegueIdentifier"
}
internal enum Organizer: String, SegueType {
case aboutSegueIdentifier = "AboutSegueIdentifier"

View File

@ -706,6 +706,14 @@ internal enum L10n {
internal static let subscribe = L10n.tr("Core", "reddit.buttons.subscribe")
}
}
internal enum ServerNetwork {
internal enum Cells {
internal enum Route {
/// Route
internal static let caption = L10n.tr("Core", "server_network.cells.route.caption")
}
}
}
internal enum Service {
internal enum Alerts {
internal enum Buttons {

View File

@ -0,0 +1,283 @@
//
// ServerNetworkViewController.swift
// Passepartout-iOS
//
// Created by Davide De Rosa on 10/23/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 TunnelKit
import SwiftyBeaver
import PassepartoutCore
import Convenience
private let log = SwiftyBeaver.self
class ServerNetworkViewController: UITableViewController, StrongTableHost {
var configuration: OpenVPN.Configuration!
private let indexOfFirstRoute4 = 2
private let indexOfFirstRoute6 = 2
private var indexOfFirstDNSAddress = 0
private var indexOfFirstProxyBypassDomain = 0
// MARK: StrongTableHost
lazy var model: StrongTableModel<SectionType, RowType> = {
let model: StrongTableModel<SectionType, RowType> = StrongTableModel()
var rows: [RowType]
if let ipv4 = configuration.ipv4 {
model.add(.ipv4)
rows = [.address, .defaultGateway]
for i in 0..<ipv4.routes.count {
rows.append(.route)
}
model.set(rows, forSection: .ipv4)
}
if let ipv6 = configuration.ipv6 {
model.add(.ipv6)
rows = [.address, .defaultGateway]
for i in 0..<ipv6.routes.count {
rows.append(.route)
}
model.set(rows, forSection: .ipv6)
}
rows = []
if let dnsDomain = configuration.searchDomain, !dnsDomain.isEmpty {
indexOfFirstDNSAddress = 1
rows.append(.dnsDomain)
}
if let dnsServers = configuration.dnsServers, !dnsServers.isEmpty {
for i in 0..<dnsServers.count {
rows.append(.dnsAddress)
}
}
if !rows.isEmpty {
model.add(.dns)
model.set(rows, forSection: .dns)
}
if let proxy = configuration.httpsProxy ?? configuration.httpProxy {
model.add(.proxy)
var rows: [RowType] = []
rows.append(.proxyAddress)
if let autoConfigurationURL = configuration.proxyAutoConfigurationURL {
rows.append(.proxyAutoConfigurationURL)
}
indexOfFirstProxyBypassDomain = rows.count
if let bypassDomains = configuration.proxyBypassDomains, !bypassDomains.isEmpty {
for i in 0..<bypassDomains.count {
rows.append(.proxyBypassDomains)
}
}
model.set(rows, forSection: .proxy)
}
// headers
model.setHeader("IPv4", forSection: .ipv4)
model.setHeader("IPv6", forSection: .ipv6)
model.setHeader(L10n.Core.NetworkSettings.Dns.title, forSection: .dns)
model.setHeader(L10n.Core.NetworkSettings.Proxy.title, forSection: .proxy)
return model
}()
func reloadModel() {
}
// MARK: UIViewController
override func awakeFromNib() {
super.awakeFromNib()
applyDetailTitle(Theme.current)
}
override func viewDidLoad() {
super.viewDidLoad()
guard let _ = configuration else {
fatalError("Configuration not set")
}
}
}
// MARK: -
extension ServerNetworkViewController {
enum SectionType: Int {
case ipv4
case ipv6
case dns
case proxy
}
enum RowType: Int {
case address
case defaultGateway
case route
case dnsAddress
case dnsDomain
case proxyAddress
case proxyBypassDomains
case proxyAutoConfigurationURL
}
override func numberOfSections(in tableView: UITableView) -> Int {
return model.numberOfSections
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return model.header(forSection: section)
}
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return model.footer(forSection: section)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.numberOfRows(forSection: section)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let section = model.section(forIndex: indexPath.section)
let row = model.row(at: indexPath)
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
cell.accessoryType = .none
cell.isTappable = false
// family-specific rows
switch section {
case .ipv4:
switch row {
case .address:
cell.leftText = L10n.Core.Global.Captions.address
if let ipv4 = configuration.ipv4 {
cell.rightText = "\(ipv4.address)/\(ipv4.addressMask)"
} else {
cell.rightText = L10n.Core.Global.Values.none
}
case .defaultGateway:
cell.leftText = L10n.Core.NetworkSettings.Gateway.title
cell.rightText = configuration.ipv4?.defaultGateway ?? L10n.Core.Global.Values.none
case .route:
guard let route = configuration.ipv4?.routes[indexPath.row - indexOfFirstRoute4] else {
fatalError("Got an IPv4 route cell with empty routes")
}
cell.leftText = L10n.Core.ServerNetwork.Cells.Route.caption
cell.rightText = "\(route.destination)/\(route.mask) -> \(route.gateway)"
default:
break
}
case .ipv6:
switch row {
case .address:
cell.leftText = L10n.Core.Global.Captions.address
if let ipv6 = configuration.ipv6 {
cell.rightText = "\(ipv6.address)/\(ipv6.addressPrefixLength)"
} else {
cell.rightText = L10n.Core.Global.Values.none
}
case .defaultGateway:
cell.leftText = L10n.Core.NetworkSettings.Gateway.title
cell.rightText = configuration.ipv6?.defaultGateway ?? L10n.Core.Global.Values.none
case .route:
guard let route = configuration.ipv6?.routes[indexPath.row - indexOfFirstRoute6] else {
fatalError("Got an IPv6 route cell with empty routes")
}
cell.leftText = L10n.Core.ServerNetwork.Cells.Route.caption
cell.rightText = "\(route.destination)/\(route.prefixLength) -> \(route.gateway)"
default:
break
}
default:
break
}
// shared rows
switch row {
case .dnsDomain:
guard let domain = configuration.searchDomain, !domain.isEmpty else {
fatalError("Got DNS domain without a domain")
}
cell.leftText = L10n.Core.NetworkSettings.Dns.Cells.Domain.caption
cell.rightText = domain
case .dnsAddress:
guard let server = configuration.dnsServers?[indexPath.row - indexOfFirstDNSAddress] else {
fatalError("Got DNS server with empty servers")
}
cell.leftText = L10n.Core.Global.Captions.address
cell.rightText = server
case .proxyAddress:
guard let proxy = configuration.httpsProxy ?? configuration.httpProxy else {
fatalError("Got proxy section without a proxy")
}
cell.leftText = L10n.Core.Global.Captions.address
cell.rightText = "\(proxy.address):\(proxy.port)"
case .proxyAutoConfigurationURL:
cell.leftText = "PAC"
guard let url = configuration.proxyAutoConfigurationURL else {
fatalError("Got PAC cell without a PAC")
}
cell.rightText = url.absoluteString
case .proxyBypassDomains:
guard let domain = configuration.proxyBypassDomains?[indexPath.row - indexOfFirstProxyBypassDomain] else {
fatalError("Got proxy bypass domain with empty domains")
}
cell.leftText = L10n.App.NetworkSettings.Cells.ProxyBypass.caption
cell.rightText = domain
default:
break
}
return cell
}
}

View File

@ -194,6 +194,9 @@ class ServiceViewController: UIViewController, StrongTableHost {
vc?.title = L10n.Core.NetworkSettings.title
vc?.profile = profile
case .serverNetworkSegueIdentifier:
break
case .debugLogSegueIdentifier:
break
}
@ -489,9 +492,9 @@ class ServiceViewController: UIViewController, StrongTableHost {
private func discloseServerNetwork() {
let caption = L10n.Core.Service.Cells.ServerNetwork.caption
tryRequestServerConfiguration(withCaption: caption) { [weak self] in
let vc = StoryboardScene.Main.configurationIdentifier.instantiate()
let vc = StoryboardScene.Main.serverNetworkViewController.instantiate()
vc.title = caption
vc.initialConfiguration = $0
vc.configuration = $0
self?.navigationController?.pushViewController(vc, animated: true)
}
}

View File

@ -84,6 +84,7 @@
0E89DFCE213EEDFA00741BA1 /* WizardProviderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E89DFCD213EEDFA00741BA1 /* WizardProviderViewController.swift */; };
0E9CD7872257462800D033B4 /* Providers.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E9CD7862257462800D033B4 /* Providers.xcassets */; };
0E9CD789225746B300D033B4 /* Flags.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E9CD788225746B300D033B4 /* Flags.xcassets */; };
0E9CDB6723604AD5006733B4 /* ServerNetworkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9CDB6623604AD5006733B4 /* ServerNetworkViewController.swift */; };
0EAAD71920E6669A0088754A /* GroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE8DED20C93E4C004C739C /* GroupConstants.swift */; };
0EB60FDA2111136E00AD27F3 /* UITextView+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */; };
0EB67D6B2184581E00BA6200 /* ImportedHostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */; };
@ -248,6 +249,7 @@
0E8D97E121388B52006FB4A0 /* InfrastructurePreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfrastructurePreset.swift; sourceTree = "<group>"; };
0E9CD7862257462800D033B4 /* Providers.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Providers.xcassets; sourceTree = "<group>"; };
0E9CD788225746B300D033B4 /* Flags.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Flags.xcassets; sourceTree = "<group>"; };
0E9CDB6623604AD5006733B4 /* ServerNetworkViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerNetworkViewController.swift; sourceTree = "<group>"; };
0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+Search.swift"; sourceTree = "<group>"; };
0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportedHostsViewController.swift; sourceTree = "<group>"; };
0EBBE8F42182361700106008 /* ConnectionService+Migration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConnectionService+Migration.swift"; sourceTree = "<group>"; };
@ -590,6 +592,7 @@
0EFB90192276D7F1006405E4 /* NetworkSettingsViewController.swift */,
0ED31C2B20CF2D6F0027975F /* ProviderPoolViewController.swift */,
0E1D72B1213BFFCF00BA1586 /* ProviderPresetViewController.swift */,
0E9CDB6623604AD5006733B4 /* ServerNetworkViewController.swift */,
0E57F63D20C83FC5008323CF /* ServiceViewController.swift */,
);
path = Scenes;
@ -986,6 +989,7 @@
0E05C5D620D1645F006EE732 /* SwiftGen+Scenes.swift in Sources */,
0E773BF8224BF37600CDDC8E /* ShortcutsViewController.swift in Sources */,
0E3419AD2350815E00419E18 /* Donation.swift in Sources */,
0E9CDB6723604AD5006733B4 /* ServerNetworkViewController.swift in Sources */,
0E3262D9235EE8DA00B5E470 /* HostImporter.swift in Sources */,
0EFD9440215BED8E00529B64 /* LabelViewController.swift in Sources */,
0ED31C2C20CF2D6F0027975F /* ProviderPoolViewController.swift in Sources */,

@ -1 +1 @@
Subproject commit 8c09f2c3c70da0478cc1b6e94837b1aeb3a0ddde
Subproject commit 0afd18fec96f0e915a6bddc9917f5846c95919f6