summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2020-07-23 15:13:07 +0300
committerAndrej Mihajlov <and@mullvad.net>2020-07-30 09:50:25 +0300
commita2e4d8e3b39ccaea3ab00fc3caf13d86fbd3edb1 (patch)
tree85157be91e3fd2f2dbb28b8a51420d66398b7493
parentca590bb989cea195b67208dc49da9419da14e9a1 (diff)
downloadmullvadvpn-a2e4d8e3b39ccaea3ab00fc3caf13d86fbd3edb1.tar.xz
mullvadvpn-a2e4d8e3b39ccaea3ab00fc3caf13d86fbd3edb1.zip
Revamp Connect controller buttons
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj4
-rw-r--r--ios/MullvadVPN/AppButton.swift38
-rw-r--r--ios/MullvadVPN/Assets.xcassets/IconReload.imageset/Contents.json12
-rw-r--r--ios/MullvadVPN/Assets.xcassets/IconReload.imageset/IconReload.pdf71
-rw-r--r--ios/MullvadVPN/Base.lproj/Main.storyboard273
-rw-r--r--ios/MullvadVPN/ConnectViewController.swift118
-rw-r--r--ios/MullvadVPN/ConnectionPanelView.swift6
-rw-r--r--ios/MullvadVPN/LoginViewController.swift4
-rw-r--r--ios/MullvadVPN/SegueIdentifier.swift4
-rw-r--r--ios/MullvadVPN/SelectLocationCell.swift6
-rw-r--r--ios/MullvadVPN/TunnelControlViewController.swift104
-rwxr-xr-xios/convert-assets.rb1
12 files changed, 245 insertions, 396 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index dc01442a6d..a2f251bca4 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -54,7 +54,6 @@
5840250222B1124600E4CFEC /* IpAddress+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250022B1124600E4CFEC /* IpAddress+Codable.swift */; };
5840250422B11AB700E4CFEC /* MullvadEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */; };
5840250522B11AB700E4CFEC /* MullvadEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */; };
- 5845F838236C466400B2D93C /* TunnelControlViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5845F837236C466400B2D93C /* TunnelControlViewController.swift */; };
5845F842236CBACD00B2D93C /* PacketTunnelIpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */; };
5845F843236CBDAB00B2D93C /* PacketTunnelIpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */; };
584E96BC240FD4DA00D3334F /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A1AA8623F43901009F7EA6 /* Location.swift */; };
@@ -270,7 +269,6 @@
5835B7CB233B76CB0096D79F /* TunnelManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelManager.swift; sourceTree = "<group>"; };
5840250022B1124600E4CFEC /* IpAddress+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IpAddress+Codable.swift"; sourceTree = "<group>"; };
5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MullvadEndpoint.swift; sourceTree = "<group>"; };
- 5845F837236C466400B2D93C /* TunnelControlViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelControlViewController.swift; sourceTree = "<group>"; };
5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelIpc.swift; sourceTree = "<group>"; };
584B26F3237434D00073B10E /* RelaySelectorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySelectorTests.swift; sourceTree = "<group>"; };
58561C98239A5D1500BD6B5E /* IPEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPEndpoint.swift; sourceTree = "<group>"; };
@@ -560,7 +558,6 @@
581CBCED229826FD00727D7F /* StaticTableViewDataSource.swift */,
5807E2BF2432038B00F5FF30 /* String+Split.swift */,
5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */,
- 5845F837236C466400B2D93C /* TunnelControlViewController.swift */,
5835B7CB233B76CB0096D79F /* TunnelManager.swift */,
587AD7C523421D7000E93A53 /* TunnelSettings.swift */,
58AEEF6A2344A46200C9BBD5 /* TunnelSettingsManager.swift */,
@@ -938,7 +935,6 @@
58F19E35228C15BA00C7710B /* SpinnerActivityIndicatorView.swift in Sources */,
58A99ED3240014A0006599E9 /* ConsentViewController.swift in Sources */,
58FAEE0124533A9C00CB0F5B /* KeychainClass.swift in Sources */,
- 5845F838236C466400B2D93C /* TunnelControlViewController.swift in Sources */,
58CCA0162242560B004F3011 /* UIColor+Palette.swift in Sources */,
58AEEF6B2344A46200C9BBD5 /* TunnelSettingsManager.swift in Sources */,
587CBFE322807F530028DED3 /* UIColor+Helpers.swift in Sources */,
diff --git a/ios/MullvadVPN/AppButton.swift b/ios/MullvadVPN/AppButton.swift
index 25eed30cf8..e778f9c642 100644
--- a/ios/MullvadVPN/AppButton.swift
+++ b/ios/MullvadVPN/AppButton.swift
@@ -98,6 +98,35 @@ private extension UIControl.State {
/// A subclass that implements action buttons used across the app
@IBDesignable class AppButton: CustomButton {
+ enum Style {
+ case `default`
+ case danger
+ case success
+ case translucentDanger
+ case translucentNeutral
+
+ var backgroundImage: UIImage? {
+ switch self {
+ case .default:
+ return UIImage(named: "DefaultButton")
+ case .danger:
+ return UIImage(named: "DangerButton")
+ case .success:
+ return UIImage(named: "SuccessButton")
+ case .translucentDanger:
+ return UIImage(named: "TranslucentDangerButton")
+ case .translucentNeutral:
+ return UIImage(named: "TranslucentNeutralButton")
+ }
+ }
+ }
+
+ var style: Style = .default {
+ didSet {
+ updateButtonBackground()
+ }
+ }
+
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
@@ -138,6 +167,15 @@ private extension UIControl.State {
setTitleColor(titleColor, for: state)
}
}
+
+ // Avoid setting the background image if it's already set via Interface Builder
+ if backgroundImage(for: .normal) == nil {
+ updateButtonBackground()
+ }
+ }
+
+ private func updateButtonBackground() {
+ setBackgroundImage(style.backgroundImage, for: .normal)
}
}
diff --git a/ios/MullvadVPN/Assets.xcassets/IconReload.imageset/Contents.json b/ios/MullvadVPN/Assets.xcassets/IconReload.imageset/Contents.json
new file mode 100644
index 0000000000..de2a405693
--- /dev/null
+++ b/ios/MullvadVPN/Assets.xcassets/IconReload.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "IconReload.pdf",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/ios/MullvadVPN/Assets.xcassets/IconReload.imageset/IconReload.pdf b/ios/MullvadVPN/Assets.xcassets/IconReload.imageset/IconReload.pdf
new file mode 100644
index 0000000000..dd17312eec
--- /dev/null
+++ b/ios/MullvadVPN/Assets.xcassets/IconReload.imageset/IconReload.pdf
@@ -0,0 +1,71 @@
+%PDF-1.5
+%
+4 0 obj
+<< /Length 5 0 R
+ /Filter /FlateDecode
+>>
+stream
+xURKNE1wl@,p %9PxS(pI Q}1_' FEd3$Y)W kJ.^t#_S|rt'OdzW(t}.H܆"atk~kmۖyXMk7BqH)pjgH
+lBRT,hseXJ֙%P/y#\ͯ YR[<<4Ɓ(d>n3<q5M!V=)7Za
+h0ȵp? ~p{80
+i)M kdq!wma*lE!uqI A
+endstream
+endobj
+5 0 obj
+ 360
+endobj
+3 0 obj
+<<
+ /ExtGState <<
+ /a0 << /CA 1 /ca 1 >>
+ >>
+>>
+endobj
+2 0 obj
+<< /Type /Page % 1
+ /Parent 1 0 R
+ /MediaBox [ 0 0 512 512 ]
+ /Contents 4 0 R
+ /Group <<
+ /Type /Group
+ /S /Transparency
+ /I true
+ /CS /DeviceRGB
+ >>
+ /Resources 3 0 R
+>>
+endobj
+1 0 obj
+<< /Type /Pages
+ /Kids [ 2 0 R ]
+ /Count 1
+>>
+endobj
+6 0 obj
+<< /Producer (cairo 1.16.0 (https://cairographics.org))
+ /CreationDate (D:20200723135151+03'00)
+>>
+endobj
+7 0 obj
+<< /Type /Catalog
+ /Pages 1 0 R
+>>
+endobj
+xref
+0 8
+0000000000 65535 f
+0000000764 00000 n
+0000000546 00000 n
+0000000474 00000 n
+0000000015 00000 n
+0000000452 00000 n
+0000000829 00000 n
+0000000945 00000 n
+trailer
+<< /Size 8
+ /Root 7 0 R
+ /Info 6 0 R
+>>
+startxref
+997
+%%EOF
diff --git a/ios/MullvadVPN/Base.lproj/Main.storyboard b/ios/MullvadVPN/Base.lproj/Main.storyboard
index 9cf7ac24e6..7bb8bab957 100644
--- a/ios/MullvadVPN/Base.lproj/Main.storyboard
+++ b/ios/MullvadVPN/Base.lproj/Main.storyboard
@@ -206,7 +206,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="3rI-k6-N1S">
- <rect key="frame" x="24" y="245" width="327" height="212"/>
+ <rect key="frame" x="24" y="307" width="327" height="212"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SECURE CONNECTION" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HNy-mU-nui">
<rect key="frame" x="0.0" y="0.0" width="327" height="24"/>
@@ -253,29 +253,39 @@
</view>
</subviews>
</stackView>
- <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Dv1-XA-XQG" userLabel="Tunnel control buttons">
- <rect key="frame" x="24" y="481" width="327" height="162"/>
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kbg-vd-uS0">
+ <rect key="frame" x="24" y="543" width="327" height="100"/>
+ <subviews>
+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="oZQ-uX-qg5">
+ <rect key="frame" x="0.0" y="0.0" width="327" height="100"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="100" placeholder="YES" id="xyU-Ve-38D"/>
+ </constraints>
+ </stackView>
+ </subviews>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
- <constraint firstAttribute="height" constant="162" placeholder="YES" id="kLh-W4-WzX"/>
+ <constraint firstItem="oZQ-uX-qg5" firstAttribute="leading" secondItem="kbg-vd-uS0" secondAttribute="leading" id="CVK-s8-K47"/>
+ <constraint firstAttribute="trailing" secondItem="oZQ-uX-qg5" secondAttribute="trailing" id="IEd-jf-HBD"/>
+ <constraint firstAttribute="bottom" secondItem="oZQ-uX-qg5" secondAttribute="bottom" id="pAj-Dl-cfL"/>
+ <constraint firstItem="oZQ-uX-qg5" firstAttribute="top" secondItem="kbg-vd-uS0" secondAttribute="top" id="qfE-M4-Vqw"/>
</constraints>
- <connections>
- <segue destination="7We-1v-DIF" kind="embed" identifier="EmbedTunnelControls" id="SUp-a7-wNJ"/>
- </connections>
- </containerView>
+ </view>
</subviews>
<color key="backgroundColor" name="Primary"/>
<constraints>
<constraint firstItem="3rI-k6-N1S" firstAttribute="leading" secondItem="PNd-mm-N1B" secondAttribute="leadingMargin" id="5fs-z1-QKf"/>
<constraint firstAttribute="trailingMargin" secondItem="3rI-k6-N1S" secondAttribute="trailing" id="NFr-rI-7r3"/>
- <constraint firstItem="iBo-pG-OTz" firstAttribute="trailing" secondItem="Dv1-XA-XQG" secondAttribute="trailing" constant="24" id="OPf-p4-dPn"/>
- <constraint firstItem="Dv1-XA-XQG" firstAttribute="top" secondItem="3rI-k6-N1S" secondAttribute="bottom" constant="24" id="hRj-EJ-ls3"/>
- <constraint firstItem="iBo-pG-OTz" firstAttribute="bottom" secondItem="Dv1-XA-XQG" secondAttribute="bottom" constant="24" id="sjJ-M6-O74"/>
- <constraint firstItem="Dv1-XA-XQG" firstAttribute="leading" secondItem="iBo-pG-OTz" secondAttribute="leading" constant="24" id="ye6-tj-a0l"/>
+ <constraint firstItem="iBo-pG-OTz" firstAttribute="bottom" secondItem="kbg-vd-uS0" secondAttribute="bottom" constant="24" id="Und-F7-4LQ"/>
+ <constraint firstItem="kbg-vd-uS0" firstAttribute="leading" secondItem="iBo-pG-OTz" secondAttribute="leading" constant="24" id="WON-cN-WSC"/>
+ <constraint firstItem="kbg-vd-uS0" firstAttribute="top" secondItem="3rI-k6-N1S" secondAttribute="bottom" constant="24" id="Yrd-dM-tsp"/>
+ <constraint firstItem="iBo-pG-OTz" firstAttribute="trailing" secondItem="kbg-vd-uS0" secondAttribute="trailing" constant="24" id="cbX-QT-hOe"/>
</constraints>
<edgeInsets key="layoutMargins" top="0.0" left="24" bottom="24" right="24"/>
<viewLayoutGuide key="safeArea" id="iBo-pG-OTz"/>
</view>
<connections>
+ <outlet property="buttonsStackView" destination="oZQ-uX-qg5" id="dvm-AG-6HG"/>
<outlet property="cityLabel" destination="mfr-Ic-PYf" id="vut-Me-cdj"/>
<outlet property="connectionPanel" destination="ocV-9f-WDZ" id="Uad-bl-KFU"/>
<outlet property="countryLabel" destination="9Yf-sl-l3q" id="L3N-Jn-zlr"/>
@@ -895,7 +905,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JYh-33-d0O">
- <rect key="frame" x="0.0" y="0.0" width="375" height="597"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="598"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="N9k-cQ-tlw" userLabel="Content view">
<rect key="frame" x="0.0" y="0.0" width="375" height="558"/>
@@ -934,7 +944,7 @@
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Cas-Tk-gcz" customClass="LinkButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="20" y="516" width="128" height="22"/>
+ <rect key="frame" x="20" y="516" width="20" height="22"/>
<fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="18"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Privacy Policy" image="IconExtlink"/>
@@ -970,10 +980,10 @@
</constraints>
</scrollView>
<view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="16P-Q0-ZO9" userLabel="Footer">
- <rect key="frame" x="0.0" y="597" width="375" height="70"/>
+ <rect key="frame" x="0.0" y="598" width="375" height="69"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ttw-7B-1MM" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="16" y="24" width="343" height="22"/>
+ <rect key="frame" x="16" y="24" width="343" height="21"/>
<accessibility key="accessibilityConfiguration" identifier="AgreeButton"/>
<state key="normal" title="Agree and continue" backgroundImage="DefaultButton">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -1011,235 +1021,6 @@
</objects>
<point key="canvasLocation" x="-551" y="27"/>
</scene>
- <!--Tunnel Control View Controller-->
- <scene sceneID="Zzn-S1-fVu">
- <objects>
- <viewController id="7We-1v-DIF" customClass="TunnelControlViewController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController">
- <view key="view" contentMode="scaleToFill" id="Ayf-ZB-cCJ">
- <rect key="frame" x="0.0" y="0.0" width="327" height="162"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- <viewLayoutGuide key="safeArea" id="MPh-Rn-8Ad"/>
- </view>
- <connections>
- <outlet property="connectedView" destination="KX2-Pi-Myg" id="qSH-w0-rkV"/>
- <outlet property="connectingView" destination="ZYQ-G2-MXc" id="Hg7-Sg-PFl"/>
- <outlet property="disconnectedView" destination="7l6-on-fbR" id="UT0-9I-faY"/>
- </connections>
- </viewController>
- <placeholder placeholderIdentifier="IBFirstResponder" id="C3V-lo-QFw" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
- <view contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="7l6-on-fbR">
- <rect key="frame" x="0.0" y="0.0" width="261" height="121"/>
- <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <subviews>
- <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="shY-Lj-oYx">
- <rect key="frame" x="0.0" y="0.0" width="261" height="121"/>
- <subviews>
- <visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JHO-Ca-Zzd" customClass="TranslucentButtonBlurView" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52.5"/>
- <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="jVH-JP-pJo">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52.5"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hVz-q0-Xpd" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52.5"/>
- <accessibility key="accessibilityConfiguration" identifier="SelectLocationButton"/>
- <inset key="contentEdgeInsets" minX="0.0" minY="0.0" maxX="0.0" maxY="10"/>
- <state key="normal" title="Select location" backgroundImage="TranslucentNeutralButton">
- <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- </state>
- <connections>
- <action selector="handleSelectLocation:" destination="7We-1v-DIF" eventType="touchUpInside" id="P4j-WA-6kP"/>
- </connections>
- </button>
- </subviews>
- <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- <constraints>
- <constraint firstAttribute="bottom" secondItem="hVz-q0-Xpd" secondAttribute="bottom" id="4Q2-Zh-7fM"/>
- <constraint firstAttribute="trailing" secondItem="hVz-q0-Xpd" secondAttribute="trailing" id="AsY-cg-1fj"/>
- <constraint firstItem="hVz-q0-Xpd" firstAttribute="leading" secondItem="jVH-JP-pJo" secondAttribute="leading" id="Eya-ig-8On"/>
- <constraint firstItem="hVz-q0-Xpd" firstAttribute="top" secondItem="jVH-JP-pJo" secondAttribute="top" id="UY2-bK-i8s"/>
- </constraints>
- </view>
- <blurEffect style="light"/>
- </visualEffectView>
- <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vxU-Mt-fMo" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="68.5" width="261" height="52.5"/>
- <accessibility key="accessibilityConfiguration" identifier="ConnectButton"/>
- <state key="normal" title="Secure my connection" backgroundImage="SuccessButton">
- <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- </state>
- <connections>
- <action selector="handleSecureConnection:" destination="7We-1v-DIF" eventType="touchUpInside" id="XmB-3v-mds"/>
- </connections>
- </button>
- </subviews>
- </stackView>
- </subviews>
- <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- <constraints>
- <constraint firstItem="shY-Lj-oYx" firstAttribute="leading" secondItem="7l6-on-fbR" secondAttribute="leading" id="1th-7a-npG"/>
- <constraint firstItem="shY-Lj-oYx" firstAttribute="bottom" secondItem="7l6-on-fbR" secondAttribute="bottom" id="53Y-II-Op2"/>
- <constraint firstAttribute="trailing" secondItem="shY-Lj-oYx" secondAttribute="trailing" id="6QT-NE-4OX"/>
- <constraint firstItem="shY-Lj-oYx" firstAttribute="trailing" secondItem="7l6-on-fbR" secondAttribute="trailing" id="ORr-CI-hQE"/>
- <constraint firstItem="shY-Lj-oYx" firstAttribute="leading" secondItem="7l6-on-fbR" secondAttribute="leading" id="U5c-eT-w73"/>
- <constraint firstItem="shY-Lj-oYx" firstAttribute="top" secondItem="7l6-on-fbR" secondAttribute="top" id="cea-vh-q3j"/>
- <constraint firstAttribute="bottom" secondItem="shY-Lj-oYx" secondAttribute="bottom" id="isW-KM-CjB"/>
- <constraint firstItem="shY-Lj-oYx" firstAttribute="top" secondItem="7l6-on-fbR" secondAttribute="top" id="zkC-qT-d72"/>
- </constraints>
- </view>
- <view contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="ZYQ-G2-MXc">
- <rect key="frame" x="0.0" y="0.0" width="261" height="120"/>
- <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <subviews>
- <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="K2E-tQ-f7f">
- <rect key="frame" x="0.0" y="0.0" width="261" height="120"/>
- <subviews>
- <visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HGl-4o-WUZ" customClass="TranslucentButtonBlurView" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="tbu-8S-1Wk">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dbp-iY-d0K" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <accessibility key="accessibilityConfiguration" identifier="SwitchLocationButton"/>
- <inset key="contentEdgeInsets" minX="0.0" minY="0.0" maxX="0.0" maxY="10"/>
- <state key="normal" title="Switch location" backgroundImage="TranslucentNeutralButton">
- <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- </state>
- <connections>
- <action selector="handleSelectLocation:" destination="7We-1v-DIF" eventType="touchUpInside" id="8dc-Ta-6qx"/>
- </connections>
- </button>
- </subviews>
- <constraints>
- <constraint firstAttribute="bottom" secondItem="dbp-iY-d0K" secondAttribute="bottom" id="5LU-aU-B47"/>
- <constraint firstAttribute="trailing" secondItem="dbp-iY-d0K" secondAttribute="trailing" id="7PF-WL-1iS"/>
- <constraint firstItem="dbp-iY-d0K" firstAttribute="leading" secondItem="tbu-8S-1Wk" secondAttribute="leading" id="8h9-Dh-uGH"/>
- <constraint firstItem="dbp-iY-d0K" firstAttribute="top" secondItem="tbu-8S-1Wk" secondAttribute="top" id="Xop-Vl-s9E"/>
- </constraints>
- </view>
- <blurEffect style="light"/>
- </visualEffectView>
- <visualEffectView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" translatesAutoresizingMaskIntoConstraints="NO" id="wTZ-S5-pHI" customClass="TranslucentButtonBlurView" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="68" width="261" height="52"/>
- <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="hWm-jl-c2l">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PDP-HS-RB2" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <state key="normal" title="Cancel" backgroundImage="TranslucentDangerButton">
- <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- </state>
- <connections>
- <action selector="handleDisconnect:" destination="7We-1v-DIF" eventType="touchUpInside" id="lgN-mu-5IE"/>
- </connections>
- </button>
- </subviews>
- <constraints>
- <constraint firstItem="PDP-HS-RB2" firstAttribute="leading" secondItem="hWm-jl-c2l" secondAttribute="leading" id="0iK-cH-2T7"/>
- <constraint firstItem="PDP-HS-RB2" firstAttribute="top" secondItem="hWm-jl-c2l" secondAttribute="top" id="Q9r-wY-cgh"/>
- <constraint firstAttribute="bottom" secondItem="PDP-HS-RB2" secondAttribute="bottom" id="Rvj-jF-cwH"/>
- <constraint firstAttribute="trailing" secondItem="PDP-HS-RB2" secondAttribute="trailing" id="Thh-Vt-L4v"/>
- </constraints>
- </view>
- <blurEffect style="light"/>
- </visualEffectView>
- </subviews>
- </stackView>
- </subviews>
- <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- <constraints>
- <constraint firstItem="K2E-tQ-f7f" firstAttribute="trailing" secondItem="ZYQ-G2-MXc" secondAttribute="trailing" id="8jj-NR-Sva"/>
- <constraint firstItem="K2E-tQ-f7f" firstAttribute="bottom" secondItem="ZYQ-G2-MXc" secondAttribute="bottom" id="eza-7A-uNf"/>
- <constraint firstItem="K2E-tQ-f7f" firstAttribute="top" secondItem="ZYQ-G2-MXc" secondAttribute="top" id="ndG-qN-nvg"/>
- <constraint firstItem="K2E-tQ-f7f" firstAttribute="leading" secondItem="ZYQ-G2-MXc" secondAttribute="leading" id="phY-um-kkn"/>
- <constraint firstAttribute="bottom" secondItem="K2E-tQ-f7f" secondAttribute="bottom" id="qUI-AH-MDO"/>
- <constraint firstItem="K2E-tQ-f7f" firstAttribute="top" secondItem="ZYQ-G2-MXc" secondAttribute="top" id="s3u-gd-29a"/>
- <constraint firstAttribute="trailing" secondItem="K2E-tQ-f7f" secondAttribute="trailing" id="x5Q-Uy-6xz"/>
- <constraint firstItem="K2E-tQ-f7f" firstAttribute="leading" secondItem="ZYQ-G2-MXc" secondAttribute="leading" id="xkx-qv-Dcr"/>
- </constraints>
- </view>
- <view contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="KX2-Pi-Myg">
- <rect key="frame" x="0.0" y="0.0" width="261" height="120"/>
- <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <subviews>
- <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="J70-p3-IaC">
- <rect key="frame" x="0.0" y="0.0" width="261" height="120"/>
- <subviews>
- <visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fgw-rj-lK4" customClass="TranslucentButtonBlurView" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="dSR-qU-xgH">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZbQ-zA-ZS8" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <accessibility key="accessibilityConfiguration" identifier="SwitchLocationButton"/>
- <inset key="contentEdgeInsets" minX="0.0" minY="0.0" maxX="0.0" maxY="10"/>
- <state key="normal" title="Switch location" backgroundImage="TranslucentNeutralButton">
- <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- </state>
- <connections>
- <action selector="handleSelectLocation:" destination="7We-1v-DIF" eventType="touchUpInside" id="rZA-gs-2O6"/>
- </connections>
- </button>
- </subviews>
- <constraints>
- <constraint firstItem="ZbQ-zA-ZS8" firstAttribute="leading" secondItem="dSR-qU-xgH" secondAttribute="leading" id="c2Y-VY-hME"/>
- <constraint firstAttribute="bottom" secondItem="ZbQ-zA-ZS8" secondAttribute="bottom" id="eUE-C6-e9C"/>
- <constraint firstAttribute="trailing" secondItem="ZbQ-zA-ZS8" secondAttribute="trailing" id="ggD-w4-oQQ"/>
- <constraint firstItem="ZbQ-zA-ZS8" firstAttribute="top" secondItem="dSR-qU-xgH" secondAttribute="top" id="oMx-RW-wv9"/>
- </constraints>
- </view>
- <blurEffect style="light"/>
- </visualEffectView>
- <visualEffectView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" translatesAutoresizingMaskIntoConstraints="NO" id="sAx-Or-5Yn" customClass="TranslucentButtonBlurView" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="68" width="261" height="52"/>
- <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="ANR-Gb-KsI">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="d5t-ia-qxF" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
- <accessibility key="accessibilityConfiguration" identifier="DisconnectButton"/>
- <state key="normal" title="Disconnect" backgroundImage="TranslucentDangerButton">
- <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- </state>
- <connections>
- <action selector="handleDisconnect:" destination="7We-1v-DIF" eventType="touchUpInside" id="S6r-fB-gnj"/>
- </connections>
- </button>
- </subviews>
- <constraints>
- <constraint firstAttribute="trailing" secondItem="d5t-ia-qxF" secondAttribute="trailing" id="6AH-65-3Vh"/>
- <constraint firstAttribute="bottom" secondItem="d5t-ia-qxF" secondAttribute="bottom" id="7aQ-oK-5Yo"/>
- <constraint firstItem="d5t-ia-qxF" firstAttribute="leading" secondItem="ANR-Gb-KsI" secondAttribute="leading" id="EKV-6Y-UtV"/>
- <constraint firstItem="d5t-ia-qxF" firstAttribute="top" secondItem="ANR-Gb-KsI" secondAttribute="top" id="NKf-WN-rVa"/>
- </constraints>
- </view>
- <blurEffect style="light"/>
- </visualEffectView>
- </subviews>
- </stackView>
- </subviews>
- <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- <constraints>
- <constraint firstItem="J70-p3-IaC" firstAttribute="bottom" secondItem="KX2-Pi-Myg" secondAttribute="bottom" id="0FU-IO-L7p"/>
- <constraint firstItem="J70-p3-IaC" firstAttribute="top" secondItem="KX2-Pi-Myg" secondAttribute="top" id="KZn-7H-iDI"/>
- <constraint firstItem="J70-p3-IaC" firstAttribute="top" secondItem="KX2-Pi-Myg" secondAttribute="top" id="NnJ-v1-dtl"/>
- <constraint firstItem="J70-p3-IaC" firstAttribute="leading" secondItem="KX2-Pi-Myg" secondAttribute="leading" id="ZWy-eg-o1m"/>
- <constraint firstAttribute="trailing" secondItem="J70-p3-IaC" secondAttribute="trailing" id="cFk-ve-P9q"/>
- <constraint firstItem="J70-p3-IaC" firstAttribute="leading" secondItem="KX2-Pi-Myg" secondAttribute="leading" id="kjo-BJ-Odb"/>
- <constraint firstItem="J70-p3-IaC" firstAttribute="trailing" secondItem="KX2-Pi-Myg" secondAttribute="trailing" id="saI-Tt-ucW"/>
- <constraint firstAttribute="bottom" secondItem="J70-p3-IaC" secondAttribute="bottom" id="tBe-df-ho5"/>
- </constraints>
- </view>
- </objects>
- <point key="canvasLocation" x="2541" y="78"/>
- </scene>
</scenes>
<resources>
<image name="DangerButton" width="9" height="9"/>
@@ -1248,8 +1029,6 @@
<image name="IconSuccess" width="60" height="60"/>
<image name="LogoIcon" width="253" height="253"/>
<image name="SuccessButton" width="9" height="9"/>
- <image name="TranslucentDangerButton" width="9" height="9"/>
- <image name="TranslucentNeutralButton" width="9" height="9"/>
<namedColor name="Primary">
<color red="0.16078431372549021" green="0.30196078431372547" blue="0.45098039215686275" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
diff --git a/ios/MullvadVPN/ConnectViewController.swift b/ios/MullvadVPN/ConnectViewController.swift
index 52b8a87f8c..41797054e1 100644
--- a/ios/MullvadVPN/ConnectViewController.swift
+++ b/ios/MullvadVPN/ConnectViewController.swift
@@ -10,17 +10,19 @@ import UIKit
import NetworkExtension
import os
-class ConnectViewController: UIViewController,
- RootContainment,
- TunnelControlViewControllerDelegate,
- TunnelObserver,
+class ConnectViewController: UIViewController, RootContainment, TunnelObserver,
SelectLocationDelegate
{
-
@IBOutlet var secureLabel: UILabel!
@IBOutlet var countryLabel: UILabel!
@IBOutlet var cityLabel: UILabel!
@IBOutlet var connectionPanel: ConnectionPanelView!
+ @IBOutlet var buttonsStackView: UIStackView!
+
+ private let connectButton = makeButton(style: .success)
+ private let selectLocationButton = makeButton(style: .translucentNeutral)
+ private lazy var selectLocationBlurView = Self.makeBlurButton(button: selectLocationButton)
+ private let splitDisconnectButtonView = DisconnectSplitButton(bundle: nil)
private let alertPresenter = AlertPresenter()
@@ -47,15 +49,21 @@ class ConnectViewController: UIViewController,
setNeedsHeaderBarStyleAppearanceUpdate()
updateSecureLabel()
updateTunnelConnectionInfo()
+ updateButtons()
}
}
- private var showedAccountView = false
+ private var showedAccountView = true
override func viewDidLoad() {
super.viewDidLoad()
connectionPanel.collapseButton.addTarget(self, action: #selector(handleConnectionPanelButton(_:)), for: .touchUpInside)
+ connectButton.addTarget(self, action: #selector(handleConnect(_:)), for: .touchUpInside)
+ splitDisconnectButtonView.primaryButton.addTarget(self, action: #selector(handleDisconnect(_:)), for: .touchUpInside)
+ splitDisconnectButtonView.secondaryButton.addTarget(self, action: #selector(handleReconnect(_:)), for: .touchUpInside)
+
+ selectLocationButton.addTarget(self, action: #selector(handleSelectLocation(_:)), for: .touchUpInside)
TunnelManager.shared.addObserver(self)
self.tunnelState = TunnelManager.shared.tunnelState
@@ -67,14 +75,6 @@ class ConnectViewController: UIViewController,
showAccountViewForExpiredAccount()
}
- override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
- if case .embedTunnelControls = SegueIdentifier.Connect.from(segue: segue) {
- let tunnelControlController = segue.destination as! TunnelControlViewController
- tunnelControlController.view.translatesAutoresizingMaskIntoConstraints = false
- tunnelControlController.delegate = self
- }
- }
-
// MARK: - TunnelObserver
func tunnelStateDidChange(tunnelState: TunnelState) {
@@ -87,21 +87,6 @@ class ConnectViewController: UIViewController,
// no-op
}
- // MARK: - TunnelControlViewControllerDelegate
-
- func tunnelControlViewController(_ controller: TunnelControlViewController, handleAction action: TunnelControlAction) {
- switch action {
- case .connect:
- connectTunnel()
-
- case .disconnect:
- disconnectTunnel()
-
- case .selectLocation:
- showSelectLocation()
- }
- }
-
// MARK: - SelectLocationDelegate
func selectLocationController(_ controller: SelectLocationController, didSelectLocation location: RelayLocation) {
@@ -129,6 +114,63 @@ class ConnectViewController: UIViewController,
// MARK: - Private
+ private class func makeBlurButton(button: AppButton) -> UIView {
+ let effectView = TranslucentButtonBlurView(effect: UIBlurEffect(style: .light))
+ effectView.contentView.addSubview(button)
+
+ NSLayoutConstraint.activate([
+ button.topAnchor.constraint(equalTo: effectView.contentView.topAnchor),
+ button.leadingAnchor.constraint(equalTo: effectView.contentView.leadingAnchor),
+ button.trailingAnchor.constraint(equalTo: effectView.contentView.trailingAnchor),
+ button.bottomAnchor.constraint(equalTo: effectView.contentView.bottomAnchor)
+ ])
+
+ return effectView
+ }
+
+ private class func makeButton(style: AppButton.Style) -> AppButton {
+ let button = AppButton(type: .custom)
+ button.style = style
+ button.translatesAutoresizingMaskIntoConstraints = false
+ button.titleLabel?.font = UIFont.systemFont(ofSize: 18, weight: .semibold)
+ return button
+ }
+
+ private func updateButtons() {
+ switch tunnelState {
+ case .disconnected:
+ selectLocationButton.setTitle(NSLocalizedString("Select location", comment: ""), for: .normal)
+ connectButton.setTitle(NSLocalizedString("Secure connection", comment: ""), for: .normal)
+
+ setArrangedButtons([selectLocationBlurView, connectButton])
+
+ case .connecting:
+ selectLocationButton.setTitle(NSLocalizedString("Switch location", comment: ""), for: .normal)
+ splitDisconnectButtonView.primaryButton.setTitle(NSLocalizedString("Cancel", comment: ""), for: .normal)
+
+ setArrangedButtons([selectLocationBlurView, splitDisconnectButtonView])
+
+ case .connected, .reconnecting, .disconnecting:
+ selectLocationButton.setTitle(NSLocalizedString("Switch location", comment: ""), for: .normal)
+ splitDisconnectButtonView.primaryButton.setTitle(NSLocalizedString("Disconnect", comment: ""), for: .normal)
+
+ setArrangedButtons([selectLocationBlurView, splitDisconnectButtonView])
+ }
+ }
+
+ private func setArrangedButtons(_ newButtons: [UIView]) {
+ buttonsStackView.arrangedSubviews.forEach { (button) in
+ if !newButtons.contains(button) {
+ buttonsStackView.removeArrangedSubview(button)
+ button.removeFromSuperview()
+ }
+ }
+
+ newButtons.forEach { (button) in
+ buttonsStackView.addArrangedSubview(button)
+ }
+ }
+
private func updateSecureLabel() {
secureLabel.text = tunnelState.textForSecureLabel().uppercased()
secureLabel.textColor = tunnelState.textColorForSecureLabel()
@@ -239,6 +281,24 @@ class ConnectViewController: UIViewController,
connectionPanel.toggleConnectionInfoVisibility()
}
+ @objc func handleConnect(_ sender: Any) {
+ connectTunnel()
+ }
+
+ @objc func handleDisconnect(_ sender: Any) {
+ disconnectTunnel()
+ }
+
+ @objc func handleReconnect(_ sender: Any) {
+ TunnelManager.shared.reconnectTunnel {
+ // TODO:
+ }
+ }
+
+ @objc func handleSelectLocation(_ sender: Any) {
+ showSelectLocation()
+ }
+
}
private extension TunnelState {
diff --git a/ios/MullvadVPN/ConnectionPanelView.swift b/ios/MullvadVPN/ConnectionPanelView.swift
index fbf0ae44d3..325fc17bc2 100644
--- a/ios/MullvadVPN/ConnectionPanelView.swift
+++ b/ios/MullvadVPN/ConnectionPanelView.swift
@@ -182,12 +182,12 @@ class ConnectionPanelCollapseButton: CustomButton {
enum Style {
case up, down
- var image: UIImage {
+ var image: UIImage? {
switch self {
case .up:
- return UIImage(imageLiteralResourceName: "IconChevronUp")
+ return UIImage(named: "IconChevronUp")
case .down:
- return UIImage(imageLiteralResourceName: "IconChevronDown")
+ return UIImage(named: "IconChevronDown")
}
}
}
diff --git a/ios/MullvadVPN/LoginViewController.swift b/ios/MullvadVPN/LoginViewController.swift
index 20cb90d387..b6cb895389 100644
--- a/ios/MullvadVPN/LoginViewController.swift
+++ b/ios/MullvadVPN/LoginViewController.swift
@@ -220,11 +220,11 @@ class LoginViewController: UIViewController, RootContainment {
switch loginState {
case .failure:
let opacity: CGFloat = self.accountTextField.isEditing ? 0 : 1
- statusImageView.image = UIImage(imageLiteralResourceName: "IconFail")
+ statusImageView.image = UIImage(named: "IconFail")
animateStatusImage(to: opacity)
case .success:
- statusImageView.image = UIImage(imageLiteralResourceName: "IconSuccess")
+ statusImageView.image = UIImage(named: "IconSuccess")
animateStatusImage(to: 1)
case .default, .authenticating:
diff --git a/ios/MullvadVPN/SegueIdentifier.swift b/ios/MullvadVPN/SegueIdentifier.swift
index 3e9f2db97b..2edf12abeb 100644
--- a/ios/MullvadVPN/SegueIdentifier.swift
+++ b/ios/MullvadVPN/SegueIdentifier.swift
@@ -22,10 +22,6 @@ extension SegueIdentifier {
case showAccount = "ShowAccount"
}
- enum Connect: String, SegueConvertible {
- case embedTunnelControls = "EmbedTunnelControls"
- }
-
enum Account: String, SegueConvertible {
case logout = "Logout"
}
diff --git a/ios/MullvadVPN/SelectLocationCell.swift b/ios/MullvadVPN/SelectLocationCell.swift
index 8d29a1d960..0b5fa63dac 100644
--- a/ios/MullvadVPN/SelectLocationCell.swift
+++ b/ios/MullvadVPN/SelectLocationCell.swift
@@ -13,11 +13,11 @@ class SelectLocationCell: BasicTableViewCell {
let locationLabel = UILabel()
let statusIndicator = RelayStatusIndicatorView()
- let tickImageView = UIImageView(image: UIImage(imageLiteralResourceName: "IconTick"))
+ let tickImageView = UIImageView(image: UIImage(named: "IconTick"))
let collapseButton = UIButton(type: .custom)
- private let chevronDown = UIImage(imageLiteralResourceName: "IconChevronDown")
- private let chevronUp = UIImage(imageLiteralResourceName: "IconChevronUp")
+ private let chevronDown = UIImage(named: "IconChevronDown")
+ private let chevronUp = UIImage(named: "IconChevronUp")
var isDisabled = false {
didSet {
diff --git a/ios/MullvadVPN/TunnelControlViewController.swift b/ios/MullvadVPN/TunnelControlViewController.swift
deleted file mode 100644
index c380bafdd6..0000000000
--- a/ios/MullvadVPN/TunnelControlViewController.swift
+++ /dev/null
@@ -1,104 +0,0 @@
-//
-// TunnelControlView.swift
-// MullvadVPN
-//
-// Created by pronebird on 01/11/2019.
-// Copyright © 2019 Mullvad VPN AB. All rights reserved.
-//
-
-import UIKit
-
-enum TunnelControlAction {
- /// An action emitted only when the tunnel is down
- case connect
-
- /// An action emitted when user either selects to cancel the connection or disconnect when
- /// the tunnel is already connected
- case disconnect
-
- /// An action emitted when user requests to either select the location when the tunnel is down
- /// or change the location when the tunnel is connecting or connected.
- case selectLocation
-}
-
-protocol TunnelControlViewControllerDelegate: class {
- func tunnelControlViewController(_ controller: TunnelControlViewController, handleAction action: TunnelControlAction) -> Void
-}
-
-class TunnelControlViewController: UIViewController, TunnelObserver {
-
- @IBOutlet var disconnectedView: UIView!
- @IBOutlet var connectingView: UIView!
- @IBOutlet var connectedView: UIView!
-
- weak var delegate: TunnelControlViewControllerDelegate?
-
- private var controlsView: UIView?
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- TunnelManager.shared.addObserver(self)
- self.didReceiveTunnelState(TunnelManager.shared.tunnelState)
- }
-
- // MARK: - TunnelObserver
-
- func tunnelStateDidChange(tunnelState: TunnelState) {
- DispatchQueue.main.async {
- self.didReceiveTunnelState(tunnelState)
- }
- }
-
- func tunnelPublicKeyDidChange(publicKey: WireguardPublicKey?) {
- // no-op
- }
-
- /// MARK: - Private
-
- private func didReceiveTunnelState(_ tunnelState: TunnelState) {
- switch tunnelState {
- case .disconnected:
- addControlsView(disconnectedView)
-
- case .connecting:
- addControlsView(connectingView)
-
- case .connected, .reconnecting, .disconnecting:
- addControlsView(connectedView)
- }
- }
-
- private func addControlsView(_ nextControlsView: UIView) {
- guard controlsView != nextControlsView else { return }
-
- controlsView?.removeFromSuperview()
- controlsView = nextControlsView
-
- nextControlsView.translatesAutoresizingMaskIntoConstraints = false
-
- view.addSubview(nextControlsView)
-
- NSLayoutConstraint.activate([
- nextControlsView.topAnchor.constraint(equalTo: view.topAnchor),
- nextControlsView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- nextControlsView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- nextControlsView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- ])
- }
-
- // MARK: - Actions
-
- @IBAction func handleSecureConnection(_ sender: Any) {
- delegate?.tunnelControlViewController(self, handleAction: .connect)
- }
-
- @IBAction func handleDisconnect(_ sender: Any) {
- delegate?.tunnelControlViewController(self, handleAction: .disconnect)
- }
-
- @IBAction func handleSelectLocation(_ sender: Any) {
- delegate?.tunnelControlViewController(self, handleAction: .selectLocation)
- }
-
-}
diff --git a/ios/convert-assets.rb b/ios/convert-assets.rb
index a082667e04..8529b2e7d5 100755
--- a/ios/convert-assets.rb
+++ b/ios/convert-assets.rb
@@ -28,6 +28,7 @@ GRAPHICAL_ASSETS=[
"icon-fail.svg",
"icon-fastest.svg",
"icon-nearest.svg",
+ "icon-reload.svg",
"icon-settings.svg",
"icon-spinner.svg",
"icon-success.svg",