diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj index 9ad2ee8..712da23 100644 --- a/WireGuard/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 6FDEF7FC21863B6100D8FBF6 /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF7F721863B6100D8FBF6 /* zip.c */; }; 6FDEF80021863C0100D8FBF6 /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF7FF21863C0100D8FBF6 /* ioapi.c */; }; 6FDEF802218646BA00D8FBF6 /* ZipArchive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF801218646B900D8FBF6 /* ZipArchive.swift */; }; + 6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */; }; 6FF4AC1F211EC472002C96EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC1E211EC472002C96EB /* Assets.xcassets */; }; 6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC20211EC472002C96EB /* LaunchScreen.storyboard */; }; 6FF4AC472120B9E0002C96EB /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */; }; @@ -103,6 +104,7 @@ 6FDEF7FE21863C0100D8FBF6 /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = ""; }; 6FDEF7FF21863C0100D8FBF6 /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = ""; }; 6FDEF801218646B900D8FBF6 /* ZipArchive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZipArchive.swift; sourceTree = ""; }; + 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = ""; }; 6FF4AC14211EC46F002C96EB /* WireGuard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuard.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6FF4AC1E211EC472002C96EB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 6FF4AC21211EC472002C96EB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -187,6 +189,7 @@ 6F7774E321718281006A79B3 /* TunnelsListTableViewController.swift */, 6F7774F221774263006A79B3 /* TunnelEditTableViewController.swift */, 6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */, + 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */, ); path = iOS; sourceTree = ""; @@ -449,6 +452,7 @@ 6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */, 6F7774F321774263006A79B3 /* TunnelEditTableViewController.swift in Sources */, 6FDEF802218646BA00D8FBF6 /* ZipArchive.swift in Sources */, + 6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */, 6F7774E1217181B1006A79B3 /* MainViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift b/WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift new file mode 100644 index 0000000..8cbaa2d --- /dev/null +++ b/WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018 WireGuard LLC. All rights reserved. + +import UIKit + +class SettingsTableViewController: UITableViewController { + + enum SettingsFields: String { + case iosAppVersion = "WireGuard for iOS" + case goBackendVersion = "WireGuard Go Backend" + case exportZipArchive = "Export zip archive" + } + + let settingsFieldsBySection : [[SettingsFields]] = [ + [.iosAppVersion, .goBackendVersion], + [.exportZipArchive] + ] + + init() { + super.init(style: .grouped) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + self.title = "Settings" + self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped)) + + self.tableView.rowHeight = 44 + self.tableView.allowsSelection = false + + self.tableView.register(TunnelSettingsTableViewKeyValueCell.self, forCellReuseIdentifier: TunnelSettingsTableViewKeyValueCell.id) + self.tableView.register(TunnelSettingsTableViewButtonCell.self, forCellReuseIdentifier: TunnelSettingsTableViewButtonCell.id) + } + + @objc func doneTapped() { + dismiss(animated: true, completion: nil) + } +} + +// MARK: UITableViewDataSource + +extension SettingsTableViewController { + override func numberOfSections(in tableView: UITableView) -> Int { + return settingsFieldsBySection.count + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return settingsFieldsBySection[section].count + } + + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + switch (section) { + case 0: + return "About" + case 1: + return "Export configurations" + default: + return nil + } + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let field = settingsFieldsBySection[indexPath.section][indexPath.row] + if (field == .iosAppVersion || field == .goBackendVersion) { + let cell = tableView.dequeueReusableCell(withIdentifier: TunnelSettingsTableViewKeyValueCell.id, for: indexPath) as! TunnelSettingsTableViewKeyValueCell + cell.key = field.rawValue + if (field == .iosAppVersion) { + let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown version" + cell.value = appVersion + } else if (field == .goBackendVersion) { + cell.value = "TODO" + } + return cell + } else { + assert(field == .exportZipArchive) + let cell = tableView.dequeueReusableCell(withIdentifier: TunnelSettingsTableViewButtonCell.id, for: indexPath) as! TunnelSettingsTableViewButtonCell + cell.buttonText = field.rawValue + return cell + } + } +} + +class TunnelSettingsTableViewKeyValueCell: UITableViewCell { + static let id: String = "TunnelSettingsTableViewKeyValueCell" + var key: String { + get { return textLabel?.text ?? "" } + set(value) { textLabel?.text = value } + } + var value: String { + get { return detailTextLabel?.text ?? "" } + set(value) { detailTextLabel?.text = value } + } + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: .value1, reuseIdentifier: TunnelSettingsTableViewKeyValueCell.id) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prepareForReuse() { + super.prepareForReuse() + key = "" + value = "" + } +} + +class TunnelSettingsTableViewButtonCell: UITableViewCell { + static let id: String = "TunnelSettingsTableViewButtonCell" + var buttonText: String { + get { return button.title(for: .normal) ?? "" } + set(value) { button.setTitle(value, for: .normal) } + } + var onTapped: (() -> Void)? = nil + + let button: UIButton + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + button = UIButton(type: .system) + super.init(style: style, reuseIdentifier: reuseIdentifier) + contentView.addSubview(button) + button.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + button.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor) + ]) + button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) + } + + @objc func buttonTapped() { + onTapped?() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prepareForReuse() { + super.prepareForReuse() + buttonText = "" + onTapped = nil + } +} diff --git a/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift b/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift index eacd896..2533a16 100644 --- a/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift @@ -22,6 +22,8 @@ class TunnelsListTableViewController: UITableViewController { self.title = "WireGuard" let addButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addButtonTapped(sender:))) self.navigationItem.rightBarButtonItem = addButtonItem + let settingsButtonItem = UIBarButtonItem(title: "Settings", style: .plain, target: self, action: #selector(settingsButtonTapped(sender:))) + self.navigationItem.leftBarButtonItem = settingsButtonItem self.tableView.rowHeight = 60 @@ -68,6 +70,13 @@ class TunnelsListTableViewController: UITableViewController { self.present(alert, animated: true, completion: nil) } + @objc func settingsButtonTapped(sender: UIBarButtonItem!) { + let settingsVC = SettingsTableViewController() + let settingsNC = UINavigationController(rootViewController: settingsVC) + settingsNC.modalPresentationStyle = .formSheet + self.present(settingsNC, animated: true) + } + func openForEditing(configFileURL: URL) { let tunnelConfiguration: TunnelConfiguration? let name = configFileURL.deletingPathExtension().lastPathComponent