diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2020-07-23 15:13:07 +0300 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2020-07-30 09:50:25 +0300 |
| commit | a2e4d8e3b39ccaea3ab00fc3caf13d86fbd3edb1 (patch) | |
| tree | 85157be91e3fd2f2dbb28b8a51420d66398b7493 | |
| parent | ca590bb989cea195b67208dc49da9419da14e9a1 (diff) | |
| download | mullvadvpn-a2e4d8e3b39ccaea3ab00fc3caf13d86fbd3edb1.tar.xz mullvadvpn-a2e4d8e3b39ccaea3ab00fc3caf13d86fbd3edb1.zip | |
Revamp Connect controller buttons
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN/AppButton.swift | 38 | ||||
| -rw-r--r-- | ios/MullvadVPN/Assets.xcassets/IconReload.imageset/Contents.json | 12 | ||||
| -rw-r--r-- | ios/MullvadVPN/Assets.xcassets/IconReload.imageset/IconReload.pdf | 71 | ||||
| -rw-r--r-- | ios/MullvadVPN/Base.lproj/Main.storyboard | 273 | ||||
| -rw-r--r-- | ios/MullvadVPN/ConnectViewController.swift | 118 | ||||
| -rw-r--r-- | ios/MullvadVPN/ConnectionPanelView.swift | 6 | ||||
| -rw-r--r-- | ios/MullvadVPN/LoginViewController.swift | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN/SegueIdentifier.swift | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN/SelectLocationCell.swift | 6 | ||||
| -rw-r--r-- | ios/MullvadVPN/TunnelControlViewController.swift | 104 | ||||
| -rwxr-xr-x | ios/convert-assets.rb | 1 |
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(pIQ}1_'FEd3$Y)WkJ.^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!uqIA +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", |
