summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2019-12-10 11:15:31 +0100
committerAndrej Mihajlov <and@mullvad.net>2019-12-10 11:15:31 +0100
commit2aacf8fb21ff13905a338bd373aa365adec0ae7c (patch)
tree05f13f79a233186e7db92176f0afbb75e771864c
parent87eeab54df529f6129da48eba32fbbc4c196649d (diff)
parenta75d471cfea6068c6ff059b4a75e328796e94621 (diff)
downloadmullvadvpn-2aacf8fb21ff13905a338bd373aa365adec0ae7c.tar.xz
mullvadvpn-2aacf8fb21ff13905a338bd373aa365adec0ae7c.zip
Merge branch 'wireup-connect-controller-ios'
-rw-r--r--ios/MullvadVPN/Base.lproj/Main.storyboard395
-rw-r--r--ios/MullvadVPN/ConnectViewController.swift138
-rw-r--r--ios/MullvadVPN/CustomButton.swift4
-rw-r--r--ios/MullvadVPN/RootContainerViewController.swift24
-rw-r--r--ios/MullvadVPN/SegueIdentifier.swift5
-rw-r--r--ios/MullvadVPN/TunnelControlViewController.swift96
-rw-r--r--ios/MullvadVPN/UIColor+Palette.swift34
7 files changed, 580 insertions, 116 deletions
diff --git a/ios/MullvadVPN/Base.lproj/Main.storyboard b/ios/MullvadVPN/Base.lproj/Main.storyboard
index 118282aaa9..389973eab7 100644
--- a/ios/MullvadVPN/Base.lproj/Main.storyboard
+++ b/ios/MullvadVPN/Base.lproj/Main.storyboard
@@ -39,19 +39,19 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="93"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LogoIcon" translatesAutoresizingMaskIntoConstraints="NO" id="cKg-hE-JsS">
- <rect key="frame" x="12" y="48.5" width="16" height="16"/>
+ <rect key="frame" x="12" y="6.5" width="98" height="100"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uXv-Tf-PET">
- <rect key="frame" x="343" y="45.5" width="16" height="22"/>
+ <rect key="frame" x="311" y="32.5" width="48" height="48"/>
<state key="normal" image="IconSettings"/>
<connections>
<segue destination="Kqv-qu-mfF" kind="presentation" identifier="ShowSettings" id="cxu-NC-VeP"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MULLVAD VPN" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dqy-A0-TdV">
- <rect key="frame" x="36" y="42" width="168" height="29"/>
+ <rect key="frame" x="118" y="42" width="168" height="29"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="24"/>
- <color key="textColor" white="1" alpha="0.80" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ <color key="textColor" white="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
@@ -100,10 +100,10 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0ZY-Kh-JiM" userLabel="Container">
- <rect key="frame" x="0.0" y="20" width="375" height="647"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pID-oa-Rrg" customClass="SpinnerActivityIndicatorView" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="163.5" y="162.5" width="48" height="48"/>
+ <rect key="frame" x="163.5" y="172.5" width="48" height="48"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="48" id="2J4-Qc-ctc"/>
@@ -111,10 +111,10 @@
</constraints>
</view>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IconSuccess" translatesAutoresizingMaskIntoConstraints="NO" id="7ux-Tb-Fzq">
- <rect key="frame" x="157.5" y="156.5" width="60" height="60"/>
+ <rect key="frame" x="157.5" y="166.5" width="60" height="60"/>
</imageView>
<view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="V3j-Lb-fSQ" userLabel="Form">
- <rect key="frame" x="0.0" y="240.5" width="375" height="126"/>
+ <rect key="frame" x="0.0" y="250.5" width="375" height="126"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Login" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Nxn-Fc-EGe">
<rect key="frame" x="24" y="0.0" width="327" height="39"/>
@@ -133,7 +133,6 @@
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="0000 0000 0000 0000" textAlignment="natural" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="XOB-ct-yLU" userLabel="Account Text Field" customClass="AccountTextField" customModule="MullvadVPN" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="327" height="48"/>
- <nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="numberPad" enablesReturnKeyAutomatically="YES" smartDashesType="no" smartInsertDeleteType="no" smartQuotesType="no" textContentType="username"/>
<connections>
@@ -270,98 +269,81 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
- <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="MapBackground" translatesAutoresizingMaskIntoConstraints="NO" id="3Ck-JT-ogd">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
- </imageView>
- <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="shY-Lj-oYx">
- <rect key="frame" x="24" y="543" width="327" height="100"/>
+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="3rI-k6-N1S">
+ <rect key="frame" x="24" y="304" width="327" height="59"/>
<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="327" height="42"/>
- <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="327" height="42"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hVz-q0-Xpd" customClass="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="0.0" width="327" height="42"/>
- <fontDescription key="fontDescription" type="system" pointSize="20"/>
- <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>
- <segue destination="hOC-Ab-N3D" kind="presentation" id="LlL-R9-hNI"/>
- </connections>
- </button>
- </subviews>
- <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>
- <constraints>
- <constraint firstAttribute="height" constant="42" id="Doo-X5-rCc"/>
- </constraints>
- <blurEffect style="light"/>
- </visualEffectView>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vxU-Mt-fMo" customClass="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="58" width="327" height="42"/>
- <constraints>
- <constraint firstAttribute="height" constant="42" placeholder="YES" id="C9s-Bs-hA5"/>
- </constraints>
- <fontDescription key="fontDescription" type="system" pointSize="20"/>
- <state key="normal" title="Secure my connection" backgroundImage="SuccessButton">
- <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- </state>
- </button>
+ <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="26.5"/>
+ <fontDescription key="fontDescription" type="system" pointSize="22"/>
+ <color key="textColor" red="0.26666666666666666" green="0.67843137254901964" blue="0.30196078431372547" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sweden" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Yf-sl-l3q">
+ <rect key="frame" x="0.0" y="32.5" width="327" height="26.5"/>
+ <fontDescription key="fontDescription" type="system" pointSize="22"/>
+ <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ <nil key="highlightedColor"/>
+ </label>
</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"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="162" placeholder="YES" id="kLh-W4-WzX"/>
+ </constraints>
+ <connections>
+ <segue destination="7We-1v-DIF" kind="embed" identifier="EmbedTunnelControls" id="SUp-a7-wNJ"/>
+ </connections>
+ </containerView>
</subviews>
<color key="backgroundColor" red="0.16078431369999999" green="0.30196078430000001" blue="0.45098039220000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
- <constraint firstAttribute="trailingMargin" secondItem="shY-Lj-oYx" secondAttribute="trailing" id="2y6-PR-9e3"/>
- <constraint firstItem="3Ck-JT-ogd" firstAttribute="top" secondItem="PNd-mm-N1B" secondAttribute="top" id="EBE-j1-lqr"/>
- <constraint firstItem="3Ck-JT-ogd" firstAttribute="leading" secondItem="PNd-mm-N1B" secondAttribute="leading" id="OEK-r4-gE7"/>
- <constraint firstAttribute="bottom" secondItem="3Ck-JT-ogd" secondAttribute="bottom" id="e75-bI-sYJ"/>
- <constraint firstAttribute="trailing" secondItem="3Ck-JT-ogd" secondAttribute="trailing" id="fXi-Cn-1bF"/>
- <constraint firstAttribute="bottomMargin" secondItem="shY-Lj-oYx" secondAttribute="bottom" id="rYu-al-UqH"/>
- <constraint firstItem="shY-Lj-oYx" firstAttribute="leading" secondItem="PNd-mm-N1B" secondAttribute="leadingMargin" id="v5s-FD-Iaw"/>
+ <constraint firstItem="3rI-k6-N1S" firstAttribute="leading" secondItem="PNd-mm-N1B" secondAttribute="leadingMargin" id="5fs-z1-QKf"/>
+ <constraint firstItem="3rI-k6-N1S" firstAttribute="centerY" secondItem="PNd-mm-N1B" secondAttribute="centerY" id="MU7-g1-1QL"/>
+ <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="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"/>
</constraints>
<edgeInsets key="layoutMargins" top="0.0" left="24" bottom="24" right="24"/>
<viewLayoutGuide key="safeArea" id="iBo-pG-OTz"/>
</view>
+ <connections>
+ <outlet property="countryLabel" destination="9Yf-sl-l3q" id="TZY-gM-Qr8"/>
+ <outlet property="secureLabel" destination="HNy-mU-nui" id="QBg-mR-Z6g"/>
+ <segue destination="hOC-Ab-N3D" kind="presentation" identifier="ShowRelaySelector" id="mui-V1-CK4"/>
+ </connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="gkg-dm-hcG" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
- <point key="canvasLocation" x="1690" y="27"/>
+ <point key="canvasLocation" x="1688.8" y="26.53673163418291"/>
</scene>
<!--Settings-->
<scene sceneID="3oF-uu-3Bk">
<objects>
<tableViewController id="SHd-a4-ewi" customClass="SettingsViewController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="6Gz-UM-orK">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.098039215690000001" green="0.18039215689999999" blue="0.27058823529999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="separatorColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Account" id="ghE-jC-RWf" customClass="SettingsAccountCell" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+ <rect key="frame" x="0.0" y="55.5" width="375" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ghE-jC-RWf" id="sTl-gI-g2a">
- <rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
+ <rect key="frame" x="0.0" y="0.0" width="348" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Account" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lve-Kd-qTr">
- <rect key="frame" x="16" y="11" width="63.5" height="22"/>
+ <rect key="frame" x="16" y="11" width="63.5" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" text="A YEAR LEFT" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QeD-EQ-Ruo">
- <rect key="frame" x="252" y="11" width="81" height="22"/>
+ <rect key="frame" x="259" y="11" width="81" height="21"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="13"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
@@ -385,20 +367,20 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="AppVersion" id="pbd-iC-Emm" customClass="SettingsAppVersionCell" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
+ <rect key="frame" x="0.0" y="98.5" width="375" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pbd-iC-Emm" id="lYp-Z8-1sN">
- <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="App version" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pYC-Zb-8N9">
- <rect key="frame" x="16" y="11" width="91" height="22"/>
+ <rect key="frame" x="16" y="11" width="91" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" text="2018.3" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sOr-vj-cg7">
- <rect key="frame" x="316.5" y="11" width="42.5" height="22"/>
+ <rect key="frame" x="316.5" y="11" width="42.5" height="21"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="13"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
@@ -451,16 +433,16 @@
<objects>
<viewController id="ruh-Q2-P39" customClass="AccountViewController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Qpl-bL-ZGl">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
- <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" alwaysBounceVertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="saE-dV-AgF">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="saE-dV-AgF">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<subviews>
- <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rkG-Xa-pEO" userLabel="Container">
- <rect key="frame" x="0.0" y="0.0" width="375" height="279"/>
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rkG-Xa-pEO" userLabel="Container">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="295"/>
<subviews>
- <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="nkx-Eb-7le" userLabel="Content">
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nkx-Eb-7le" userLabel="Content">
<rect key="frame" x="24" y="24" width="327" height="247"/>
<subviews>
<view contentMode="scaleToFill" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="HzF-8Z-UBs" userLabel="Account number">
@@ -525,7 +507,7 @@
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="wNk-FP-mVD">
<rect key="frame" x="0.0" y="0.0" width="327" height="108"/>
<subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2Ia-Dz-pE6" customClass="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2Ia-Dz-pE6" customClass="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="327" height="42"/>
<constraints>
<constraint firstAttribute="height" constant="42" placeholder="YES" id="9Ss-ab-obH"/>
@@ -536,7 +518,7 @@
<action selector="doBuyCredits" destination="ruh-Q2-P39" eventType="touchUpInside" id="BAj-cb-ENq"/>
</connections>
</button>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QHr-Lz-v6t" customClass="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QHr-Lz-v6t" customClass="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
<rect key="frame" x="0.0" y="66" width="327" height="42"/>
<constraints>
<constraint firstAttribute="height" constant="42" placeholder="YES" id="VYx-GQ-CIz"/>
@@ -574,10 +556,10 @@
</view>
</subviews>
<constraints>
- <constraint firstAttribute="bottomMargin" secondItem="nkx-Eb-7le" secondAttribute="bottom" id="28V-SW-noS"/>
- <constraint firstAttribute="trailingMargin" secondItem="nkx-Eb-7le" secondAttribute="trailing" id="KQB-PO-stg"/>
- <constraint firstItem="nkx-Eb-7le" firstAttribute="leading" secondItem="rkG-Xa-pEO" secondAttribute="leadingMargin" id="L4C-cS-yzC"/>
- <constraint firstItem="nkx-Eb-7le" firstAttribute="top" secondItem="rkG-Xa-pEO" secondAttribute="topMargin" id="eea-1e-zMf"/>
+ <constraint firstAttribute="bottom" secondItem="nkx-Eb-7le" secondAttribute="bottom" constant="24" id="28V-SW-noS"/>
+ <constraint firstAttribute="trailing" secondItem="nkx-Eb-7le" secondAttribute="trailing" constant="24" id="KQB-PO-stg"/>
+ <constraint firstItem="nkx-Eb-7le" firstAttribute="leading" secondItem="rkG-Xa-pEO" secondAttribute="leading" constant="24" id="L4C-cS-yzC"/>
+ <constraint firstItem="nkx-Eb-7le" firstAttribute="top" secondItem="rkG-Xa-pEO" secondAttribute="top" constant="24" id="eea-1e-zMf"/>
</constraints>
</view>
</subviews>
@@ -597,7 +579,6 @@
<constraint firstItem="saE-dV-AgF" firstAttribute="top" secondItem="Qpl-bL-ZGl" secondAttribute="top" id="sZ0-CC-Onn"/>
<constraint firstItem="saE-dV-AgF" firstAttribute="leading" secondItem="Qpl-bL-ZGl" secondAttribute="leading" id="xba-Jt-Ulk"/>
</constraints>
- <edgeInsets key="layoutMargins" top="24" left="24" bottom="24" right="24"/>
<viewLayoutGuide key="safeArea" id="jrJ-di-3DV"/>
</view>
<navigationItem key="navigationItem" title="Account" id="rL3-Y8-3g8"/>
@@ -616,8 +597,9 @@
<scene sceneID="er3-W2-NkS">
<objects>
<navigationController id="Kqv-qu-mfF" sceneMemberID="viewController">
+ <navigationItem key="navigationItem" id="7IR-NQ-qLb"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" largeTitles="YES" id="7PK-0x-byW" customClass="CustomNavigationBar" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="20" width="375" height="96"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="108"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</navigationBar>
@@ -634,7 +616,7 @@
<objects>
<navigationController id="hOC-Ab-N3D" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" largeTitles="YES" id="kmu-Ab-x1c" customClass="CustomNavigationBar" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="20" width="375" height="96"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="108"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<textAttributes key="largeTitleTextAttributes">
@@ -654,7 +636,7 @@
<objects>
<tableViewController id="FxZ-7F-3yi" customClass="SelectLocationController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="56" sectionHeaderHeight="28" sectionFooterHeight="28" id="LKX-4h-vIx">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.098039215690000001" green="0.18039215689999999" blue="0.27058823529999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="separatorColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -663,7 +645,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="While connected, your real location is masked with a private and secure location in the selected region" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="X0P-N8-lda">
- <rect key="frame" x="24" y="44" width="327" height="77"/>
+ <rect key="frame" x="24" y="24" width="327" height="97"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.60217786815068497" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
@@ -680,7 +662,7 @@
</view>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="aFz-H5-sPu" customClass="SelectLocationCell" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="173" width="375" height="44"/>
+ <rect key="frame" x="0.0" y="173" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="aFz-H5-sPu" id="6nQ-gT-vzf">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
@@ -694,7 +676,7 @@
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y7o-0b-MUV">
- <rect key="frame" x="44" y="11" width="42" height="22"/>
+ <rect key="frame" x="44" y="11" width="42" height="21.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
@@ -748,14 +730,245 @@
</barButtonItem>
</navigationItem>
<connections>
+ <outlet property="activityIndicator" destination="Mdw-ey-b8l" id="w7b-yv-Q39"/>
<segue destination="6Lc-ZQ-E4P" kind="unwind" identifier="ReturnToConnectWithNewRelay" unwindAction="unwindFromSelectLocationWithSegue:" id="SPT-Ay-Cy3"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="EvX-LH-gOg" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ <view contentMode="scaleToFill" id="Mdw-ey-b8l" customClass="SpinnerActivityIndicatorView" customModule="MullvadVPN" customModuleProvider="target">
+ <rect key="frame" x="0.0" y="0.0" width="48" height="48"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ <viewLayoutGuide key="safeArea" id="gNQ-Ao-v6S"/>
+ </view>
<exit id="6Lc-ZQ-E4P" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="2649" y="841"/>
</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="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
+ <rect key="frame" x="0.0" y="0.0" width="261" height="52.5"/>
+ <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>
+ <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="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
+ <rect key="frame" x="0.0" y="68.5" width="261" height="52.5"/>
+ <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="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
+ <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
+ <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="CustomButton" 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="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
+ <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
+ <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="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
+ <rect key="frame" x="0.0" y="0.0" width="261" height="52"/>
+ <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"/>
@@ -766,8 +979,8 @@
<image name="IconSuccess" width="60" height="60"/>
<image name="IconTick" width="24" height="24"/>
<image name="LogoIcon" width="49" height="50"/>
- <image name="MapBackground" width="637" height="982"/>
<image name="SuccessButton" width="9" height="9"/>
+ <image name="TranslucentDangerButton" width="9" height="9"/>
<image name="TranslucentNeutralButton" width="9" height="9"/>
</resources>
</document>
diff --git a/ios/MullvadVPN/ConnectViewController.swift b/ios/MullvadVPN/ConnectViewController.swift
index d7b615b3fb..8e9c4f09b7 100644
--- a/ios/MullvadVPN/ConnectViewController.swift
+++ b/ios/MullvadVPN/ConnectViewController.swift
@@ -6,27 +6,159 @@
// Copyright © 2019 Amagicom AB. All rights reserved.
//
+import Combine
import UIKit
+import NetworkExtension
+import os
-class ConnectViewController: UIViewController, RootContainment {
+class ConnectViewController: UIViewController, RootContainment, TunnelControlViewControllerDelegate {
+
+ @IBOutlet var secureLabel: UILabel!
+ @IBOutlet var countryLabel: UILabel!
+
+ private var setRelaysSubscriber: AnyCancellable?
+ private var startStopTunnelSubscriber: AnyCancellable?
+ private var tunnelStateSubscriber: AnyCancellable?
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
var preferredHeaderBarStyle: HeaderBarStyle {
- return .unsecured
+ switch tunnelState {
+ case .connecting, .reconnecting, .connected:
+ return .secured
+
+ case .disconnecting, .disconnected:
+ return .unsecured
+ }
+ }
+
+ private var tunnelState: TunnelState = .disconnected {
+ didSet {
+ setNeedsHeaderBarStyleAppearanceUpdate()
+ updateSecureLabel()
+ updateTunnelConnectionInfo()
+ }
}
override func viewDidLoad() {
super.viewDidLoad()
- // Do any additional setup after loading the view, typically from a nib.
+
+ tunnelStateSubscriber = TunnelManager.shared.$tunnelState
+ .receive(on: DispatchQueue.main)
+ .assign(to: \.tunnelState, on: self)
+ }
+
+ 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: - TunnelControlViewControllerDelegate
+
+ func tunnelControlViewController(_ controller: TunnelControlViewController, handleAction action: TunnelControlAction) {
+ switch action {
+ case .connect:
+ connectTunnel()
+
+ case .disconnect:
+ disconnectTunnel()
+
+ case .selectLocation:
+ performSegue(withIdentifier: SegueIdentifier.Connect.showRelaySelector.rawValue, sender: self)
+ }
+ }
+
+ // MARK: - Private
+
+ private func updateSecureLabel() {
+ secureLabel.text = tunnelState.textForSecureLabel()
+ secureLabel.textColor = tunnelState.textColorForSecureLabel()
+ }
+
+ private func updateTunnelConnectionInfo() {
+ switch tunnelState {
+ case .connected(let connectionInfo),
+ .reconnecting(let connectionInfo):
+ countryLabel.text = "\(connectionInfo.hostname)\nIn: \(connectionInfo.ipv4Relay)"
+
+ case .connecting, .disconnected, .disconnecting:
+ countryLabel.text = ""
+ }
+ }
+
+ private func connectTunnel() {
+ startStopTunnelSubscriber = TunnelManager.shared.startTunnel()
+ .receive(on: DispatchQueue.main)
+ .sink(receiveCompletion: { (completion) in
+ if case .failure(let error) = completion {
+ os_log(.error, "Failed to start the tunnel: %{public}s", error.localizedDescription)
+ }
+ })
+ }
+
+ private func disconnectTunnel() {
+ startStopTunnelSubscriber = TunnelManager.shared.stopTunnel()
+ .receive(on: DispatchQueue.main)
+ .sink(receiveCompletion: { (_) in
+ // no-op
+ })
}
// MARK: - Actions
@IBAction func unwindFromSelectLocation(segue: UIStoryboardSegue) {
+ guard let selectLocationController = segue.source as? SelectLocationController else { return }
+ guard let selectedItem = selectLocationController.selectedItem else { return }
+
+ let relayConstraints = RelayConstraints(location: .only(selectedItem.relayLocation))
+
+ setRelaysSubscriber = TunnelManager.shared.setRelayConstraints(relayConstraints)
+ .receive(on: DispatchQueue.main)
+ .sink(receiveCompletion: { (completion) in
+ switch completion {
+ case .finished:
+ os_log(.debug, "Updated relay constraints: %{public}s", String(reflecting: relayConstraints))
+ self.connectTunnel()
+
+ case .failure(let error):
+ os_log(.error, "Failed to update relay constraints: %{public}s", error.localizedDescription)
+ }
+ })
+ }
+
+}
+
+private extension TunnelState {
+
+ func textColorForSecureLabel() -> UIColor {
+ switch self {
+ case .connecting, .reconnecting:
+ return .white
+
+ case .connected:
+ return .successColor
+
+ case .disconnecting, .disconnected:
+ return .dangerColor
+ }
+ }
+
+ func textForSecureLabel() -> String {
+ switch self {
+ case .connecting, .reconnecting:
+ return NSLocalizedString("Creating secure connection", tableName: "Connect", comment: "")
+
+ case .connected:
+ return NSLocalizedString("Secure connection", tableName: "Connect", comment: "")
+ case .disconnecting, .disconnected:
+ return NSLocalizedString("Unsecured connection", tableName: "Connect", comment: "")
+ }
}
}
diff --git a/ios/MullvadVPN/CustomButton.swift b/ios/MullvadVPN/CustomButton.swift
index 119403c91c..fa4c867cc9 100644
--- a/ios/MullvadVPN/CustomButton.swift
+++ b/ios/MullvadVPN/CustomButton.swift
@@ -43,7 +43,9 @@ import UIKit
contentEdgeInsets = contentInsets
titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
- titleLabel?.textColor = UIColor.white
+
+ setTitleColor(UIColor.white, for: .normal)
+ setTitleColor(UIColor.lightGray, for: .highlighted)
}
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
diff --git a/ios/MullvadVPN/RootContainerViewController.swift b/ios/MullvadVPN/RootContainerViewController.swift
index 7d1990e507..0ca4588232 100644
--- a/ios/MullvadVPN/RootContainerViewController.swift
+++ b/ios/MullvadVPN/RootContainerViewController.swift
@@ -114,6 +114,9 @@ class RootContainerViewController: UIViewController {
// MARK: - Storyboard segue handling
override func unwind(for unwindSegue: UIStoryboardSegue, towards subsequentVC: UIViewController) {
+ // Make sure there is no attempt to unwind to the top view controller
+ guard subsequentVC != topViewController else { return }
+
let index = viewControllers.firstIndex(of: subsequentVC)!
let newViewControllers = Array(viewControllers.prefix(through: index))
@@ -246,7 +249,7 @@ class RootContainerViewController: UIViewController {
}
/// Request the root container to query the top controller for the new header bar style
- func setNeedsHeaderBarStyleAppearance() {
+ func updateHeaderBarAppearance() {
updateHeaderBarStyleFromChildPreferences(animated: UIView.areAnimationsEnabled)
}
@@ -324,20 +327,21 @@ class RootContainerPushSegue: UIStoryboardSegue {
}
}
+/// A UIViewController extension that gives view controllers an access to root container
extension UIViewController {
var rootContainerController: RootContainerViewController? {
- var viewController: UIViewController? = parent
-
- while viewController != nil {
- if let container = viewController as? RootContainerViewController {
- return container
- }
-
- viewController = viewController?.parent
+ var current: UIViewController? = self
+ let iterator = AnyIterator { () -> UIViewController? in
+ current = current?.parent
+ return current
}
- return nil
+ return iterator.first { $0 is RootContainerViewController } as? RootContainerViewController
+ }
+
+ func setNeedsHeaderBarStyleAppearanceUpdate() {
+ rootContainerController?.updateHeaderBarAppearance()
}
}
diff --git a/ios/MullvadVPN/SegueIdentifier.swift b/ios/MullvadVPN/SegueIdentifier.swift
index f1d9c0c71b..eaa8a10cbb 100644
--- a/ios/MullvadVPN/SegueIdentifier.swift
+++ b/ios/MullvadVPN/SegueIdentifier.swift
@@ -21,6 +21,11 @@ extension SegueIdentifier {
case showConnect = "ShowConnect"
}
+ enum Connect: String, SegueConvertible {
+ case embedTunnelControls = "EmbedTunnelControls"
+ case showRelaySelector = "ShowRelaySelector"
+ }
+
enum SelectLocation: String, SegueConvertible {
case returnToConnectWithNewRelay = "ReturnToConnectWithNewRelay"
}
diff --git a/ios/MullvadVPN/TunnelControlViewController.swift b/ios/MullvadVPN/TunnelControlViewController.swift
new file mode 100644
index 0000000000..2f9bc0eae4
--- /dev/null
+++ b/ios/MullvadVPN/TunnelControlViewController.swift
@@ -0,0 +1,96 @@
+//
+// TunnelControlView.swift
+// MullvadVPN
+//
+// Created by pronebird on 01/11/2019.
+// Copyright © 2019 Amagicom AB. All rights reserved.
+//
+
+import Combine
+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 {
+
+ @IBOutlet var disconnectedView: UIView!
+ @IBOutlet var connectingView: UIView!
+ @IBOutlet var connectedView: UIView!
+
+ weak var delegate: TunnelControlViewControllerDelegate?
+
+ private var tunnelStateSubscriber: AnyCancellable?
+ private var controlsView: UIView?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ tunnelStateSubscriber = TunnelManager.shared.$tunnelState
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] (tunnelState) in
+ self?.didReceiveTunnelState(tunnelState)
+ }
+ }
+
+ 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/MullvadVPN/UIColor+Palette.swift b/ios/MullvadVPN/UIColor+Palette.swift
index 72a1b4ace8..0298502fef 100644
--- a/ios/MullvadVPN/UIColor+Palette.swift
+++ b/ios/MullvadVPN/UIColor+Palette.swift
@@ -10,20 +10,20 @@ import UIKit
extension UIColor {
- struct AccountTextField {
- struct NormalState {
+ enum AccountTextField {
+ enum NormalState {
static let borderColor = UIColor(red: 0.10, green: 0.18, blue: 0.27, alpha: 1.0)
static let textColor = UIColor(red: 0.16, green: 0.30, blue: 0.45, alpha: 1.0)
static let backgroundColor = UIColor.white
}
- struct ErrorState {
+ enum ErrorState {
static let borderColor = dangerColor.withAlphaComponent(0.4)
static let textColor = dangerColor
static let backgroundColor = UIColor.white
}
- struct AuthenticatingState {
+ enum AuthenticatingState {
static let borderColor = UIColor.clear
static let textColor = UIColor.white
static let backgroundColor = UIColor.white.withAlphaComponent(0.2)
@@ -31,27 +31,39 @@ extension UIColor {
}
// Relay availability indicator view
- struct RelayStatusIndicator {
+ enum RelayStatusIndicator {
static let activeColor = successColor.withAlphaComponent(0.9)
static let inactiveColor = dangerColor.withAlphaComponent(0.95)
}
// Cells
- struct Cell {
+ enum Cell {
static let backgroundColor = UIColor(red: 0.16, green: 0.30, blue: 0.45, alpha: 1.0)
- static let selectedAltBackgroundColor = backgroundColor.darkened(by: 0.2)
+ static let disabledBackgroundColor = backgroundColor.darkened(by: 0.3)!
+
static let selectedBackgroundColor = successColor
- static let subCellBackgroundColor = UIColor(red: 0.15, green: 0.23, blue: 0.33, alpha: 1.0)
- static let subSubCellBackgroundColor = UIColor(red: 0.13, green: 0.20, blue: 0.30, alpha: 1.0)
+ static let disabledSelectedBackgroundColor = selectedBackgroundColor.darkened(by: 0.3)!
+
+ static let selectedAltBackgroundColor = backgroundColor.darkened(by: 0.2)!
+ }
+
+ enum SubCell {
+ static let backgroundColor = UIColor(red: 0.15, green: 0.23, blue: 0.33, alpha: 1.0)
+ static let disabledBackgroundColor = backgroundColor.darkened(by: 0.3)!
+ }
+
+ enum SubSubCell {
+ static let backgroundColor = UIColor(red: 0.13, green: 0.20, blue: 0.30, alpha: 1.0)
+ static let disabledBackgroundColor = backgroundColor.darkened(by: 0.3)!
}
- struct HeaderBar {
+ enum HeaderBar {
static let defaultBackgroundColor = UIColor(red: 0.16, green: 0.30, blue: 0.45, alpha: 1.0)
static let unsecuredBackgroundColor = dangerColor
static let securedBackgroundColor = successColor
}
// Common colors
- static let dangerColor = UIColor(red: 0.82, green: 0.01, blue: 0.11, alpha: 1.0)
+ static let dangerColor = UIColor(red: 0.89, green: 0.25, blue: 0.22, alpha: 1.0)
static let successColor = UIColor(red: 0.27, green: 0.68, blue: 0.30, alpha: 1.0)
}