Add intermediate "Info" screen.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
3a8f8ef9e6
commit
6104546fc6
|
@ -35,6 +35,7 @@
|
|||
4A61D83520D98D25006C7A76 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A61D83420D98D25006C7A76 /* NetworkExtension.framework */; };
|
||||
4A8AABD820B6A79100B6D8C1 /* UITableView+WireGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A8AABD720B6A79100B6D8C1 /* UITableView+WireGuard.swift */; };
|
||||
4AADEA2B212616F7008C24FD /* String+Arrays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FA1D50F2124D80C00DBA2E6 /* String+Arrays.swift */; };
|
||||
4ABF718E214D8B0300A1E0BF /* TunnelInfoTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ABF718D214D8B0300A1E0BF /* TunnelInfoTableViewController.swift */; };
|
||||
4ABFFEA0212D39A000107136 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 4ABFFE9F212D39A000107136 /* x25519.c */; };
|
||||
4ABFFEA3212D3C8300107136 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ABFFEA2212D3C8300107136 /* Security.framework */; };
|
||||
4AC086832120B9F900CEE5ED /* ProviderConfigurationKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC086822120B9F900CEE5ED /* ProviderConfigurationKeys.swift */; };
|
||||
|
@ -121,6 +122,7 @@
|
|||
4A61D83320D98D07006C7A76 /* WireGuard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuard.entitlements; sourceTree = "<group>"; };
|
||||
4A61D83420D98D25006C7A76 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
|
||||
4A8AABD720B6A79100B6D8C1 /* UITableView+WireGuard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+WireGuard.swift"; sourceTree = "<group>"; };
|
||||
4ABF718D214D8B0300A1E0BF /* TunnelInfoTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelInfoTableViewController.swift; sourceTree = "<group>"; };
|
||||
4ABFFE9D212D399F00107136 /* WireGuard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuard-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
4ABFFE9E212D39A000107136 /* x25519.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x25519.h; sourceTree = "<group>"; };
|
||||
4ABFFE9F212D39A000107136 /* x25519.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x25519.c; sourceTree = "<group>"; };
|
||||
|
@ -252,6 +254,7 @@
|
|||
4A4BAD1220B5F82400F12B28 /* Identifyable.swift */,
|
||||
4A8AABD720B6A79100B6D8C1 /* UITableView+WireGuard.swift */,
|
||||
4A4BACE720B5F1BF00F12B28 /* TunnelsTableViewController.swift */,
|
||||
4ABF718D214D8B0300A1E0BF /* TunnelInfoTableViewController.swift */,
|
||||
4A4BA6D720B73CBA00223AB8 /* TunnelConfigurationTableViewController.swift */,
|
||||
5FCC4342212B3092009A9C58 /* QRScanViewController.swift */,
|
||||
);
|
||||
|
@ -591,6 +594,7 @@
|
|||
5FA1D5122124DA6400DBA2E6 /* String+Base64.swift in Sources */,
|
||||
4AC5462E2116306F00749D21 /* Tunnel+Extension.swift in Sources */,
|
||||
5FCC4343212B3092009A9C58 /* QRScanViewController.swift in Sources */,
|
||||
4ABF718E214D8B0300A1E0BF /* TunnelInfoTableViewController.swift in Sources */,
|
||||
4A4BAD0E20B5F6C300F12B28 /* Coordinator.swift in Sources */,
|
||||
4ABFFEA0212D39A000107136 /* x25519.c in Sources */,
|
||||
4A4BA6D820B73CBA00223AB8 /* TunnelConfigurationTableViewController.swift in Sources */,
|
||||
|
|
|
@ -514,7 +514,311 @@
|
|||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="j96-PK-ghN" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="122" y="-239"/>
|
||||
<point key="canvasLocation" x="916" y="-263"/>
|
||||
</scene>
|
||||
<!--Tunnel info-->
|
||||
<scene sceneID="jJx-Qm-bKA">
|
||||
<objects>
|
||||
<tableViewController storyboardIdentifier="TunnelInfoTableViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="h8W-vj-IcI" customClass="TunnelInfoTableViewController" customModule="WireGuard" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" allowsSelection="NO" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="I7I-Kf-A49">
|
||||
<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"/>
|
||||
<inset key="separatorInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="InterfaceInfoTableViewCell" rowHeight="400" id="4nk-ch-nYS" customClass="InterfaceInfoTableViewCell" customModule="WireGuard" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="28" width="375" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="4nk-ch-nYS" id="eBg-fg-M9P">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="399.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="LbD-1j-3B4">
|
||||
<rect key="frame" x="16" y="11" width="343" height="378"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Interface" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qcg-LJ-nRV">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="51.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="wJ9-cl-tZH">
|
||||
<rect key="frame" x="0.0" y="65.5" width="343" height="51"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mov-bF-HkG">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="30.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="t89-wK-B5h">
|
||||
<rect key="frame" x="0.0" y="30.5" width="343" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Ao6-49-xJm">
|
||||
<rect key="frame" x="0.0" y="130.5" width="343" height="51.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Private key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vWC-ql-O8v">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="16"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bCm-fp-MGf">
|
||||
<rect key="frame" x="0.0" y="16" width="343" height="35.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="J6k-WI-jjf">
|
||||
<rect key="frame" x="0.0" y="196" width="343" height="51.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Listen port" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TTJ-6b-ome">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="16"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="I9X-NK-kCV">
|
||||
<rect key="frame" x="0.0" y="16" width="343" height="35.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="bu6-xb-eu0">
|
||||
<rect key="frame" x="0.0" y="261.5" width="343" height="51"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Addresses" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GWn-Of-NWj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="16"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nxw-Kz-Bhj">
|
||||
<rect key="frame" x="0.0" y="16" width="343" height="35"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="ua3-dP-NKH">
|
||||
<rect key="frame" x="0.0" y="326.5" width="343" height="51.5"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="YDF-kD-W2c">
|
||||
<rect key="frame" x="0.0" y="0.0" width="232" height="51.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="DNS servers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3yE-yO-hwt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="232" height="31"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MYs-AI-nbx">
|
||||
<rect key="frame" x="0.0" y="31" width="232" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="1EB-sf-JeM">
|
||||
<rect key="frame" x="240" y="0.0" width="103" height="51.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="MTU" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GWI-hc-UbS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="103" height="16"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="r3L-cH-wX1">
|
||||
<rect key="frame" x="0.0" y="16" width="103" height="35.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="1EB-sf-JeM" firstAttribute="width" secondItem="LbD-1j-3B4" secondAttribute="width" multiplier="0.3" id="ZdE-IM-Xz4"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="LbD-1j-3B4" firstAttribute="leading" secondItem="eBg-fg-M9P" secondAttribute="leadingMargin" id="MpF-dU-5q1"/>
|
||||
<constraint firstItem="LbD-1j-3B4" firstAttribute="top" secondItem="eBg-fg-M9P" secondAttribute="topMargin" id="Zyd-bw-Q0S"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="LbD-1j-3B4" secondAttribute="bottom" id="vpm-rN-QXf"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="LbD-1j-3B4" secondAttribute="trailing" id="whd-a8-RKi"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="addressesField" destination="nxw-Kz-Bhj" id="e7Y-Z0-3Mk"/>
|
||||
<outlet property="dnsField" destination="MYs-AI-nbx" id="Pge-e9-zYk"/>
|
||||
<outlet property="listenPortField" destination="I9X-NK-kCV" id="EjP-bc-q5B"/>
|
||||
<outlet property="mtuField" destination="r3L-cH-wX1" id="beI-fZ-cSs"/>
|
||||
<outlet property="nameField" destination="t89-wK-B5h" id="6fz-z4-Gf5"/>
|
||||
<outlet property="privateKeyField" destination="bCm-fp-MGf" id="ELY-n7-1Cc"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="PeerInfoTableViewCell" rowHeight="308" id="E8O-dS-GmI" customClass="PeerInfoTableViewCell" customModule="WireGuard" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="428" width="375" height="308"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="E8O-dS-GmI" id="Igy-0b-NWe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="307.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="QR4-dk-gU5">
|
||||
<rect key="frame" x="16" y="11" width="343" height="286"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Peer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5qD-R9-tZb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="46"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="1NC-ix-aSU">
|
||||
<rect key="frame" x="0.0" y="60" width="343" height="46"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Public key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="quD-G5-mlN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="25.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QB9-fz-eN5">
|
||||
<rect key="frame" x="0.0" y="25.5" width="343" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="pVH-s6-OWU">
|
||||
<rect key="frame" x="0.0" y="120" width="343" height="46"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Pre-shared key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="i6i-mE-2aX">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="16"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kz0-I7-wvc">
|
||||
<rect key="frame" x="0.0" y="16" width="343" height="30"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="1v9-H0-PWt">
|
||||
<rect key="frame" x="0.0" y="180" width="343" height="46"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Allowed IPs" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3fw-zF-zA7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="16"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="h84-DM-thL">
|
||||
<rect key="frame" x="0.0" y="16" width="343" height="30"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="qMd-me-JGQ">
|
||||
<rect key="frame" x="0.0" y="240" width="343" height="46"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="2h1-6W-ZsL">
|
||||
<rect key="frame" x="0.0" y="0.0" width="232" height="46"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Endpoint" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TYO-NN-8gk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="232" height="25.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pju-S6-5Ls">
|
||||
<rect key="frame" x="0.0" y="25.5" width="232" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="7TC-8I-7Ms">
|
||||
<rect key="frame" x="240" y="0.0" width="103" height="46"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Persistent keepalive" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="Vmu-2v-xFe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="103" height="16"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.60784313729999995" green="0.60784313729999995" blue="0.60784313729999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UvC-3x-kth">
|
||||
<rect key="frame" x="0.0" y="16" width="103" height="30"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="7TC-8I-7Ms" firstAttribute="width" secondItem="QR4-dk-gU5" secondAttribute="width" multiplier="0.3" id="SNf-fC-Uq3"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="QR4-dk-gU5" secondAttribute="trailing" id="gEw-tD-Dbc"/>
|
||||
<constraint firstItem="QR4-dk-gU5" firstAttribute="top" secondItem="Igy-0b-NWe" secondAttribute="topMargin" id="gH2-UQ-fHW"/>
|
||||
<constraint firstItem="QR4-dk-gU5" firstAttribute="leading" secondItem="Igy-0b-NWe" secondAttribute="leadingMargin" id="nQT-10-aQB"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="QR4-dk-gU5" secondAttribute="bottom" id="uxe-Fp-xgz"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="allowedIpsField" destination="h84-DM-thL" id="CR8-i3-y2q"/>
|
||||
<outlet property="endpointField" destination="pju-S6-5Ls" id="y3c-20-rkp"/>
|
||||
<outlet property="persistentKeepaliveField" destination="UvC-3x-kth" id="5kQ-cy-TaW"/>
|
||||
<outlet property="preSharedKeyField" destination="kz0-I7-wvc" id="TJa-5a-tEU"/>
|
||||
<outlet property="publicKeyField" destination="QB9-fz-eN5" id="hfg-EO-IRw"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="h8W-vj-IcI" id="BDC-pZ-8RJ"/>
|
||||
<outlet property="delegate" destination="h8W-vj-IcI" id="Huk-uM-0lZ"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Tunnel info" id="Eh1-Vi-78e">
|
||||
<barButtonItem key="rightBarButtonItem" systemItem="edit" id="YRj-Ox-eKc">
|
||||
<connections>
|
||||
<action selector="editTunnelConfiguration:" destination="h8W-vj-IcI" id="f1k-Y6-4c3"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
|
||||
<connections>
|
||||
<outlet property="editButton" destination="YRj-Ox-eKc" id="nIf-WD-pml"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="cXx-q2-SBO" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="121" y="-263"/>
|
||||
</scene>
|
||||
<!--Scan Code-->
|
||||
<scene sceneID="gKN-k2-HoW">
|
||||
|
|
|
@ -261,6 +261,22 @@ class AppCoordinator: RootViewCoordinator {
|
|||
})
|
||||
}
|
||||
|
||||
func showTunnelInfoViewController(tunnel: Tunnel, context: NSManagedObjectContext) {
|
||||
let tunnelInfoViewController = storyboard.instantiateViewController(type: TunnelInfoTableViewController.self)
|
||||
|
||||
tunnelInfoViewController.configure(context: context, delegate: self, tunnel: tunnel)
|
||||
|
||||
self.navigationController.pushViewController(tunnelInfoViewController, animated: true)
|
||||
}
|
||||
|
||||
func showTunnelConfigurationViewController(tunnel: Tunnel?, context: NSManagedObjectContext) {
|
||||
let tunnelConfigurationViewController = storyboard.instantiateViewController(type: TunnelConfigurationTableViewController.self)
|
||||
|
||||
tunnelConfigurationViewController.configure(context: context, delegate: self, tunnel: tunnel)
|
||||
|
||||
self.navigationController.pushViewController(tunnelConfigurationViewController, animated: true)
|
||||
}
|
||||
|
||||
public func showError(_ error: Error) {
|
||||
showAlert(title: NSLocalizedString("Error", comment: "Error alert title"), message: error.localizedDescription)
|
||||
}
|
||||
|
@ -289,6 +305,20 @@ class AppCoordinator: RootViewCoordinator {
|
|||
}
|
||||
}
|
||||
|
||||
extension AppCoordinator: TunnelInfoTableViewControllerDelegate {
|
||||
func configure(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) {
|
||||
print("configure tunnel \(tunnel)")
|
||||
let editContext = persistentContainer.newBackgroundContext()
|
||||
var backgroundTunnel: Tunnel?
|
||||
editContext.performAndWait {
|
||||
backgroundTunnel = editContext.object(with: tunnel.objectID) as? Tunnel
|
||||
}
|
||||
|
||||
showTunnelConfigurationViewController(tunnel: backgroundTunnel, context: editContext)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension AppCoordinator: TunnelsTableViewControllerDelegate {
|
||||
func exportTunnels(tunnelsTableViewController: TunnelsTableViewController, barButtonItem: UIBarButtonItem) {
|
||||
self.exportConfigs(barButtonItem: barButtonItem)
|
||||
|
@ -401,23 +431,10 @@ extension AppCoordinator: TunnelsTableViewControllerDelegate {
|
|||
manager?.connection.stopVPNTunnel()
|
||||
}
|
||||
|
||||
func configure(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) {
|
||||
print("configure tunnel \(tunnel)")
|
||||
let editContext = persistentContainer.newBackgroundContext()
|
||||
var backgroundTunnel: Tunnel?
|
||||
editContext.performAndWait {
|
||||
backgroundTunnel = editContext.object(with: tunnel.objectID) as? Tunnel
|
||||
}
|
||||
func info(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) {
|
||||
print("info tunnel \(tunnel)")
|
||||
|
||||
showTunnelConfigurationViewController(tunnel: backgroundTunnel, context: editContext)
|
||||
}
|
||||
|
||||
func showTunnelConfigurationViewController(tunnel: Tunnel?, context: NSManagedObjectContext) {
|
||||
let tunnelConfigurationViewController = storyboard.instantiateViewController(type: TunnelConfigurationTableViewController.self)
|
||||
|
||||
tunnelConfigurationViewController.configure(context: context, delegate: self, tunnel: tunnel)
|
||||
|
||||
self.navigationController.pushViewController(tunnelConfigurationViewController, animated: true)
|
||||
showTunnelInfoViewController(tunnel: tunnel, context: self.persistentContainer.viewContext)
|
||||
}
|
||||
|
||||
func delete(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) {
|
||||
|
@ -476,7 +493,7 @@ extension AppCoordinator: TunnelsTableViewControllerDelegate {
|
|||
}
|
||||
|
||||
_ = refreshProviderManagers().then { () -> Promise<Void> in
|
||||
self.navigationController.popToRootViewController(animated: true)
|
||||
self.navigationController.popViewController(animated: true)
|
||||
return Promise.value(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
//
|
||||
// TunnelInfoTableViewController.swift
|
||||
// WireGuard
|
||||
//
|
||||
// Created by Jeroen Leenarts on 15-09-18.
|
||||
// Copyright © 2018 WireGuard LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreData
|
||||
import BNRCoreDataStack
|
||||
import PromiseKit
|
||||
|
||||
protocol TunnelInfoTableViewControllerDelegate: class {
|
||||
func configure(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController)
|
||||
}
|
||||
|
||||
class TunnelInfoTableViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var editButton: UIBarButtonItem!
|
||||
|
||||
private var viewContext: NSManagedObjectContext!
|
||||
private weak var delegate: TunnelInfoTableViewControllerDelegate?
|
||||
private var tunnel: Tunnel!
|
||||
|
||||
func configure(context: NSManagedObjectContext, delegate: TunnelInfoTableViewControllerDelegate? = nil, tunnel: Tunnel) {
|
||||
viewContext = context
|
||||
self.delegate = delegate
|
||||
self.tunnel = tunnel
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super .viewWillAppear(animated)
|
||||
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return 3
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
switch section {
|
||||
case 1:
|
||||
return tunnel?.peers?.count ?? 1
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
switch indexPath.section {
|
||||
case 0:
|
||||
let cell = tableView.dequeueReusableCell(type: InterfaceInfoTableViewCell.self, for: indexPath)
|
||||
cell.model = tunnel.interface
|
||||
return cell
|
||||
default:
|
||||
let cell = tableView.dequeueReusableCell(type: PeerInfoTableViewCell.self, for: indexPath)
|
||||
if let peer = tunnel.peers?.object(at: indexPath.row) as? Peer {
|
||||
cell.peer = peer
|
||||
} else {
|
||||
let peer = Peer(context: tunnel.managedObjectContext!)
|
||||
tunnel.addToPeers(peer)
|
||||
cell.peer = peer
|
||||
}
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func editTunnelConfiguration(_ sender: Any) {
|
||||
delegate?.configure(tunnel: self.tunnel, tunnelInfoTableViewController: self)
|
||||
}
|
||||
}
|
||||
|
||||
class InterfaceInfoTableViewCell: UITableViewCell {
|
||||
var model: Interface! {
|
||||
didSet {
|
||||
nameField.text = model.tunnel?.title
|
||||
addressesField.text = model.addresses
|
||||
privateKeyField.text = model.privateKey
|
||||
listenPortField.text = String(model.listenPort)
|
||||
dnsField.text = model.dns
|
||||
mtuField.text = String(model.mtu)
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var nameField: UILabel!
|
||||
@IBOutlet weak var addressesField: UILabel!
|
||||
@IBOutlet weak var privateKeyField: UILabel!
|
||||
@IBOutlet weak var listenPortField: UILabel!
|
||||
@IBOutlet weak var dnsField: UILabel!
|
||||
@IBOutlet weak var mtuField: UILabel!
|
||||
}
|
||||
|
||||
class PeerInfoTableViewCell: UITableViewCell {
|
||||
var peer: Peer! {
|
||||
didSet {
|
||||
publicKeyField.text = peer.publicKey
|
||||
preSharedKeyField.text = peer.presharedKey
|
||||
allowedIpsField.text = peer.allowedIPs
|
||||
endpointField.text = peer.endpoint
|
||||
persistentKeepaliveField.text = String(peer.persistentKeepalive)
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var publicKeyField: UILabel!
|
||||
@IBOutlet weak var preSharedKeyField: UILabel!
|
||||
@IBOutlet weak var allowedIpsField: UILabel!
|
||||
@IBOutlet weak var endpointField: UILabel!
|
||||
@IBOutlet weak var persistentKeepaliveField: UILabel!
|
||||
}
|
||||
|
||||
extension TunnelInfoTableViewController: Identifyable {}
|
||||
extension InterfaceInfoTableViewCell: Identifyable {}
|
||||
extension PeerInfoTableViewCell: Identifyable {}
|
|
@ -7,8 +7,9 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
import os.log
|
||||
import CoreData
|
||||
|
||||
import BNRCoreDataStack
|
||||
import NetworkExtension
|
||||
|
||||
|
@ -17,7 +18,7 @@ protocol TunnelsTableViewControllerDelegate: class {
|
|||
func addProvider(tunnelsTableViewController: TunnelsTableViewController)
|
||||
func connect(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController)
|
||||
func disconnect(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController)
|
||||
func configure(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController)
|
||||
func info(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController)
|
||||
func delete(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController)
|
||||
func status(for tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) -> NEVPNStatus
|
||||
}
|
||||
|
@ -39,12 +40,17 @@ class TunnelsTableViewController: UITableViewController {
|
|||
|
||||
public func updateStatus(for tunnelIdentifier: String) {
|
||||
viewContext.perform {
|
||||
let tunnel = try? Tunnel.findFirstInContext(self.viewContext, predicate: NSPredicate(format: "tunnelIdentifier == %@", tunnelIdentifier))
|
||||
do {
|
||||
let tunnel = try Tunnel.findFirstInContext(self.viewContext, predicate: NSPredicate(format: "tunnelIdentifier == %@", tunnelIdentifier))
|
||||
if let tunnel = tunnel {
|
||||
if let indexPath = self.fetchedResultsController.indexPathForObject(tunnel!) {
|
||||
if let indexPath = self.fetchedResultsController.indexPathForObject(tunnel) {
|
||||
self.tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.none)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
os_log("Unable to load tunnel for tunnel identifier: %{public}@", log: Log.general, type: .error, error.localizedDescription)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +110,7 @@ class TunnelsTableViewController: UITableViewController {
|
|||
let section = sections[indexPath.section]
|
||||
let tunnel = section.objects[indexPath.row]
|
||||
|
||||
delegate?.configure(tunnel: tunnel, tunnelsTableViewController: self)
|
||||
delegate?.info(tunnel: tunnel, tunnelsTableViewController: self)
|
||||
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
@ -117,7 +123,7 @@ class TunnelsTableViewController: UITableViewController {
|
|||
let section = sections[indexPath.section]
|
||||
let tunnel = section.objects[indexPath.row]
|
||||
|
||||
delegate?.configure(tunnel: tunnel, tunnelsTableViewController: self)
|
||||
delegate?.info(tunnel: tunnel, tunnelsTableViewController: self)
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue