summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2020-02-26 12:38:36 +0100
committerAndrej Mihajlov <and@mullvad.net>2020-02-26 17:14:56 +0100
commit8922808f55a8458a1e7acd80959f84ce7a54bfe5 (patch)
tree37f4c1b98a222de16f57e284262bdc5c8c64af17
parent3ae8363e792b01307688ceea5f503e0b2cc9cadf (diff)
downloadmullvadvpn-8922808f55a8458a1e7acd80959f84ce7a54bfe5.tar.xz
mullvadvpn-8922808f55a8458a1e7acd80959f84ce7a54bfe5.zip
Add consent view controller and rework app button
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj12
-rw-r--r--ios/MullvadVPN/AppButton.swift251
-rw-r--r--ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/Contents.json15
-rw-r--r--ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/NewLogoIcon.pdfbin0 -> 2604 bytes
-rw-r--r--ios/MullvadVPN/Base.lproj/Main.storyboard203
-rw-r--r--ios/MullvadVPN/ConsentViewController.swift48
-rw-r--r--ios/MullvadVPN/CustomButton.swift68
-rw-r--r--ios/MullvadVPN/UIColor+Palette.swift6
-rw-r--r--ios/MullvadVPN/ViewControllerIdentifier.swift1
9 files changed, 498 insertions, 106 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index b7e147b85a..46c230a192 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -35,6 +35,7 @@
5860F1EB23AA4CF300CEA666 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5860F1EA23AA4CF300CEA666 /* Logging.swift */; };
5862805422428EF100F5A6E1 /* TranslucentButtonBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */; };
5867A51C2248F26A005513C0 /* SegueIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5867A51B2248F26A005513C0 /* SegueIdentifier.swift */; };
+ 5868585524054096000B8131 /* AppButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5868585424054096000B8131 /* AppButton.swift */; };
586AA296234B696B00502875 /* WireguardAssociatedAddresses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B8743122B25A7600015324 /* WireguardAssociatedAddresses.swift */; };
586BD68322B7BBD800BB7F9F /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 586BD68222B7BBD800BB7F9F /* NetworkExtension.framework */; };
586BD68422B7BBE400BB7F9F /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 586BD68222B7BBD800BB7F9F /* NetworkExtension.framework */; };
@@ -59,13 +60,13 @@
5888AD89227B18C40051EB06 /* RelayList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD88227B18C40051EB06 /* RelayList.swift */; };
588AE72F2362001F009F9F2E /* MutuallyExclusive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 588AE72E2362001F009F9F2E /* MutuallyExclusive.swift */; };
588AE730236200E2009F9F2E /* MutuallyExclusive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 588AE72E2362001F009F9F2E /* MutuallyExclusive.swift */; };
- 5894FC492296A8090017471D /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5894FC482296A8090017471D /* CustomButton.swift */; };
589AB4F7227B64450039131E /* BasicTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 589AB4F6227B64450039131E /* BasicTableViewCell.swift */; };
58A1AA8723F43901009F7EA6 /* GeoLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A1AA8623F43901009F7EA6 /* GeoLocation.swift */; };
58A1AA8823F43901009F7EA6 /* GeoLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A1AA8623F43901009F7EA6 /* GeoLocation.swift */; };
58A1AA8C23F5584C009F7EA6 /* ConnectionPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */; };
58A8BE81239FBE62006B74AC /* IPEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58561C98239A5D1500BD6B5E /* IPEndpoint.swift */; };
58A8BE8323A0F362006B74AC /* UIAlertController+Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A8BE8223A0F362006B74AC /* UIAlertController+Error.swift */; };
+ 58A99ED3240014A0006599E9 /* ConsentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A99ED2240014A0006599E9 /* ConsentViewController.swift */; };
58ADDB3C227B1BD200FAFEA7 /* JsonRpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58ADDB3B227B1BD200FAFEA7 /* JsonRpc.swift */; };
58ADDB3E227B1CD900FAFEA7 /* MullvadAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58ADDB3D227B1CD900FAFEA7 /* MullvadAPI.swift */; };
58AEEF652344A36000C9BBD5 /* KeychainError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AEEF642344A36000C9BBD5 /* KeychainError.swift */; };
@@ -184,6 +185,7 @@
5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslucentButtonBlurView.swift; sourceTree = "<group>"; };
5866F39B2243B82D00168AE5 /* MullvadVPN.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MullvadVPN.entitlements; sourceTree = "<group>"; };
5867A51B2248F26A005513C0 /* SegueIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegueIdentifier.swift; sourceTree = "<group>"; };
+ 5868585424054096000B8131 /* AppButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppButton.swift; sourceTree = "<group>"; };
586BD68222B7BBD800BB7F9F /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
58723E7422A54C63009837F5 /* libwg-go.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libwg-go.a"; sourceTree = BUILT_PRODUCTS_DIR; };
5873884C239E6D7E00E96C4E /* EmbeddedViewContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmbeddedViewContainerView.swift; sourceTree = "<group>"; };
@@ -203,11 +205,11 @@
5888AD88227B18C40051EB06 /* RelayList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayList.swift; sourceTree = "<group>"; };
588AE72E2362001F009F9F2E /* MutuallyExclusive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutuallyExclusive.swift; sourceTree = "<group>"; };
5894E725236B2801008A2793 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
- 5894FC482296A8090017471D /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = "<group>"; };
589AB4F6227B64450039131E /* BasicTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicTableViewCell.swift; sourceTree = "<group>"; };
58A1AA8623F43901009F7EA6 /* GeoLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoLocation.swift; sourceTree = "<group>"; };
58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionPanelView.swift; sourceTree = "<group>"; };
58A8BE8223A0F362006B74AC /* UIAlertController+Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Error.swift"; sourceTree = "<group>"; };
+ 58A99ED2240014A0006599E9 /* ConsentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentViewController.swift; sourceTree = "<group>"; };
58ADDB3B227B1BD200FAFEA7 /* JsonRpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JsonRpc.swift; sourceTree = "<group>"; };
58ADDB3D227B1CD900FAFEA7 /* MullvadAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MullvadAPI.swift; sourceTree = "<group>"; };
58AEEF642344A36000C9BBD5 /* KeychainError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainError.swift; sourceTree = "<group>"; };
@@ -341,6 +343,7 @@
58C3A4B122456F1A00340BDB /* AccountInputGroupView.swift */,
58CCA01D2242787B004F3011 /* AccountTextField.swift */,
58CCA01722426713004F3011 /* AccountViewController.swift */,
+ 5868585424054096000B8131 /* AppButton.swift */,
58CE5E63224146200008646E /* AppDelegate.swift */,
58BFA5CB22A7CE1F00A6173D /* ApplicationConfiguration.swift */,
58CE5E6A224146210008646E /* Assets.xcassets */,
@@ -349,7 +352,7 @@
58EC4E6B23915325003F5C5B /* Bundle+MullvadVersion.swift */,
58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */,
58CCA00F224249A1004F3011 /* ConnectViewController.swift */,
- 5894FC482296A8090017471D /* CustomButton.swift */,
+ 58A99ED2240014A0006599E9 /* ConsentViewController.swift */,
582BB1B0229569620055B6EF /* CustomNavigationBar.swift */,
58C6B35D22BBBFE3003C19AD /* Data+HexCoding.swift */,
5873884C239E6D7E00E96C4E /* EmbeddedViewContainerView.swift */,
@@ -713,6 +716,7 @@
58C6B35422BB87C4003C19AD /* WireguardPrivateKey.swift in Sources */,
5888AD87227B17950051EB06 /* SelectLocationController.swift in Sources */,
58F19E35228C15BA00C7710B /* SpinnerActivityIndicatorView.swift in Sources */,
+ 58A99ED3240014A0006599E9 /* ConsentViewController.swift in Sources */,
5845F838236C466400B2D93C /* TunnelControlViewController.swift in Sources */,
58CCA0162242560B004F3011 /* UIColor+Palette.swift in Sources */,
58AEEF6B2344A46200C9BBD5 /* TunnelConfigurationManager.swift in Sources */,
@@ -721,6 +725,7 @@
5845F83A236C6A7200B2D93C /* AutoDisposableSink.swift in Sources */,
5840250422B11AB700E4CFEC /* MullvadEndpoint.swift in Sources */,
58CCA01822426713004F3011 /* AccountViewController.swift in Sources */,
+ 5868585524054096000B8131 /* AppButton.swift in Sources */,
5845F842236CBACD00B2D93C /* PacketTunnelIpc.swift in Sources */,
58781CC922AE7CA8009B9D8E /* RelayConstraints.swift in Sources */,
58ADDB3E227B1CD900FAFEA7 /* MullvadAPI.swift in Sources */,
@@ -746,7 +751,6 @@
589AB4F7227B64450039131E /* BasicTableViewCell.swift in Sources */,
5888AD7F2279B6BF0051EB06 /* RelayStatusIndicatorView.swift in Sources */,
5867A51C2248F26A005513C0 /* SegueIdentifier.swift in Sources */,
- 5894FC492296A8090017471D /* CustomButton.swift in Sources */,
58CCA01E2242787B004F3011 /* AccountTextField.swift in Sources */,
587AD7CA2342283900E93A53 /* Account.swift in Sources */,
58A8BE8323A0F362006B74AC /* UIAlertController+Error.swift in Sources */,
diff --git a/ios/MullvadVPN/AppButton.swift b/ios/MullvadVPN/AppButton.swift
new file mode 100644
index 0000000000..f1f727b741
--- /dev/null
+++ b/ios/MullvadVPN/AppButton.swift
@@ -0,0 +1,251 @@
+//
+// AppButton.swift
+// MullvadVPN
+//
+// Created by pronebird on 23/05/2019.
+// Copyright © 2019 Mullvad VPN AB. All rights reserved.
+//
+
+import UIKit
+
+enum ButtonImageAlignment {
+ /// Align image at the left edge of the title label
+ case left
+
+ /// Align image at the right edge of the title label
+ case right
+
+ /// Align image at the leading edge of the title label
+ case leading
+
+ /// Align image at the trailing edge of the title label
+ case trailing
+
+ /// Align image at the leading edge of content area
+ case leadingFixed
+
+ /// Align image at the trailing edge of the content area
+ case trailingFixed
+
+ /// Align image at the left edge of the content area
+ case leftFixed
+
+ /// Align image at the right edge of the content area
+ case rightFixed
+}
+
+private extension UIControl.State {
+ var customButtonTitleColor: UIColor? {
+ switch self {
+ case .normal:
+ return UIColor.AppButton.normalTitleColor
+ case .disabled:
+ return UIColor.AppButton.disabledTitleColor
+ case .highlighted:
+ return UIColor.AppButton.highlightedTitleColor
+ default:
+ return nil
+ }
+ }
+}
+
+/// A subclass that implements the button that visually look like URL links on the web
+@IBDesignable class LinkButton: CustomButton {
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ commonInit()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ commonInit()
+ }
+
+ override func setTitle(_ title: String?, for state: UIControl.State) {
+ if let title = title {
+ setAttributedTitle(makeAttributedTitle(title, for: state), for: state)
+ } else {
+ setAttributedTitle(nil, for: state)
+ }
+ }
+
+ private func commonInit() {
+ imageAlignment = .trailing
+
+ let states: [UIControl.State] = [.normal, .highlighted, .disabled]
+ states.forEach { (state) in
+ if let title = self.title(for: state) {
+ let attributedTitle = makeAttributedTitle(title, for: state)
+ self.setAttributedTitle(attributedTitle, for: state)
+ }
+ }
+ }
+
+ private func makeAttributedTitle(_ title: String, for state: UIControl.State) -> NSAttributedString {
+ var attributes: [NSAttributedString.Key: Any] = [
+ .underlineStyle: NSUnderlineStyle.single.rawValue
+ ]
+
+ if let titleColor = state.customButtonTitleColor {
+ attributes[.foregroundColor] = titleColor
+ }
+
+ return NSAttributedString(string: title, attributes: attributes)
+ }
+}
+
+/// A subclass that implements action buttons used across the app
+@IBDesignable class AppButton: CustomButton {
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ commonInit()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ super.init(coder: aDecoder)
+ commonInit()
+ }
+
+ private func commonInit() {
+ var contentInsets = contentEdgeInsets
+
+ if contentInsets.top == 0 {
+ contentInsets.top = 10
+ }
+
+ if contentInsets.bottom == 0 {
+ contentInsets.bottom = 10
+ }
+
+ if contentInsets.right == 0 {
+ contentInsets.right = 10
+ }
+
+ if contentInsets.left == 0 {
+ contentInsets.left = 10
+ }
+
+ contentEdgeInsets = contentInsets
+ imageAlignment = .trailingFixed
+
+ titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
+
+ let states: [UIControl.State] = [.normal, .highlighted, .disabled]
+ states.forEach { (state) in
+ if let titleColor = state.customButtonTitleColor {
+ setTitleColor(titleColor, for: state)
+ }
+ }
+ }
+
+}
+
+/// A custom `UIButton` subclass that implements additional layouts for the image
+@IBDesignable class CustomButton: UIButton {
+
+ var imageAlignment: ButtonImageAlignment = .leading
+ var inlineImageSpacing: CGFloat = 4
+
+ var effectiveImageAlignment: ButtonImageAlignment {
+ switch (imageAlignment, effectiveUserInterfaceLayoutDirection) {
+ case (.left, _),
+ (.leading, .leftToRight),
+ (.trailing, .rightToLeft):
+ return .left
+
+ case (.right, _),
+ (.trailing, .leftToRight),
+ (.leading, .rightToLeft):
+ return .right
+
+ case (.leftFixed, _),
+ (.leadingFixed, .leftToRight),
+ (.trailingFixed, .rightToLeft):
+ return .leftFixed
+
+ case (.rightFixed, _),
+ (.trailingFixed, .leftToRight),
+ (.leadingFixed, .rightToLeft):
+ return .rightFixed
+
+ default:
+ fatalError()
+ }
+ }
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ commonInit()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ commonInit()
+ }
+
+ private func commonInit() {
+ // Align the text color with the tint color which is applied to the image view
+ if let imageTintColor = UIControl.State.normal.customButtonTitleColor {
+ tintColor = imageTintColor
+ }
+ }
+
+ private func computeLayout(forContentRect contentRect: CGRect) -> (CGRect, CGRect) {
+ var imageRect = super.imageRect(forContentRect: contentRect)
+ var titleRect = super.titleRect(forContentRect: contentRect)
+
+ switch (effectiveContentHorizontalAlignment, effectiveImageAlignment) {
+ case (.left, .left):
+ imageRect.origin.x = contentRect.minX
+ titleRect.origin.x = imageRect.width > 0
+ ? imageRect.maxX + inlineImageSpacing
+ : contentRect.minX
+
+ case (.left, .right):
+ titleRect.origin.x = contentRect.origin.x
+ imageRect.origin.x = titleRect.maxX + inlineImageSpacing
+
+ case (.left, .leftFixed):
+ imageRect.origin.x = contentRect.minX
+ titleRect.origin.x = imageRect.width > 0
+ ? imageRect.maxX + inlineImageSpacing
+ : contentRect.minX
+
+ case (.left, .rightFixed):
+ imageRect.origin.x = contentRect.maxX - imageRect.width
+ titleRect.origin.x = contentRect.minX
+
+ case (.center, .leftFixed):
+ imageRect.origin.x = contentRect.minX
+ titleRect.origin.x = contentRect.midX - titleRect.width * 0.5
+
+ case (.center, .rightFixed):
+ imageRect.origin.x = contentRect.maxX - imageRect.width
+ titleRect.origin.x = contentRect.midX - titleRect.width * 0.5
+
+ case (.center, .left):
+ titleRect.origin.x = contentRect.midX - titleRect.width * 0.5
+ imageRect.origin.x = titleRect.origin.x - inlineImageSpacing - imageRect.width
+
+ case (.center, .right):
+ titleRect.origin.x = contentRect.midX - titleRect.width * 0.5
+ imageRect.origin.x = titleRect.maxX + inlineImageSpacing
+
+ default:
+ fatalError()
+ }
+
+ return (titleRect, imageRect)
+ }
+
+ override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
+ return computeLayout(forContentRect: contentRect).1
+ }
+
+ override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
+ return computeLayout(forContentRect: contentRect).0
+ }
+
+}
diff --git a/ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/Contents.json b/ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/Contents.json
new file mode 100644
index 0000000000..9e9f4e465b
--- /dev/null
+++ b/ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "NewLogoIcon.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+} \ No newline at end of file
diff --git a/ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/NewLogoIcon.pdf b/ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/NewLogoIcon.pdf
new file mode 100644
index 0000000000..a3200ee169
--- /dev/null
+++ b/ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/NewLogoIcon.pdf
Binary files differ
diff --git a/ios/MullvadVPN/Base.lproj/Main.storyboard b/ios/MullvadVPN/Base.lproj/Main.storyboard
index 89d0918f7e..b467d421c9 100644
--- a/ios/MullvadVPN/Base.lproj/Main.storyboard
+++ b/ios/MullvadVPN/Base.lproj/Main.storyboard
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="ZwP-1v-DUg">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="ZwP-1v-DUg">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -183,7 +183,7 @@
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ire-2z-eJu" userLabel="Footer">
- <rect key="frame" x="0.0" y="554.5" width="375" height="112.5"/>
+ <rect key="frame" x="0.0" y="577.5" width="375" height="89.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Don't have an account number?" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QcG-Tf-YdQ">
<rect key="frame" x="24" y="16" width="327" height="20.5"/>
@@ -191,10 +191,8 @@
<color key="textColor" white="1" alpha="0.60327482876712324" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="osm-vd-aTb">
- <rect key="frame" x="24" y="44.5" width="327" height="44"/>
- <fontDescription key="fontDescription" type="system" pointSize="20"/>
- <inset key="contentEdgeInsets" minX="0.0" minY="10" maxX="0.0" maxY="10"/>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="osm-vd-aTb" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target">
+ <rect key="frame" x="24" y="44.5" width="327" height="21"/>
<state key="normal" title="Create account" backgroundImage="DefaultButton">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
@@ -369,20 +367,20 @@
<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="43.5"/>
+ <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="348" 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="21.5"/>
+ <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="259" y="11" width="81" height="21.5"/>
+ <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"/>
@@ -407,20 +405,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" width="375" height="43.5"/>
+ <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="21.5"/>
+ <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="21.5"/>
+ <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"/>
@@ -442,14 +440,14 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="BasicDisclosure" id="Ahs-gu-nTM" customClass="SettingsBasicCell" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="0.0" y="142.5" width="375" height="43.5"/>
+ <rect key="frame" x="0.0" y="141.5" width="375" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Ahs-gu-nTM" id="Drq-vk-8F2">
- <rect key="frame" x="0.0" y="0.0" width="348" 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="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Amw-A3-ePS">
- <rect key="frame" x="16" y="11" width="324" height="21.5"/>
+ <rect key="frame" x="16" y="11" width="324" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
@@ -593,30 +591,39 @@
<constraint firstItem="8f3-SD-t3K" firstAttribute="leading" secondItem="Bjs-D6-NVj" secondAttribute="leading" id="fvj-uI-LRp"/>
</constraints>
</view>
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Keg-iI-sK2">
+ <rect key="frame" x="0.0" y="115" width="327" height="24"/>
+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+ <constraints>
+ <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="24" id="Kph-MQ-fdV"/>
+ </constraints>
+ </view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ydQ-IP-KZb" userLabel="Buttons">
<rect key="frame" x="0.0" y="139" width="327" height="108"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="zF0-5W-t7M">
<rect key="frame" x="0.0" y="0.0" width="327" height="108"/>
<subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OCa-Jz-b7W" customClass="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OCa-Jz-b7W" customClass="AppButton" 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="IpC-KC-l52"/>
</constraints>
+ <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Regenerate key" backgroundImage="SuccessButton"/>
<connections>
<action selector="handleRegenerateKey:" destination="vAK-MJ-h3c" eventType="touchUpInside" id="s39-bg-vkG"/>
</connections>
</button>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qEF-8w-MdR" customClass="CustomButton" customModule="MullvadVPN" customModuleProvider="target">
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qEF-8w-MdR" customClass="AppButton" 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="299-Lu-yIB"/>
</constraints>
+ <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- <state key="normal" title="Verify key" backgroundImage="SuccessButton"/>
+ <state key="normal" title="Verify key" backgroundImage="DefaultButton"/>
<connections>
<action selector="handleVerifyKey:" destination="vAK-MJ-h3c" eventType="touchUpInside" id="wGf-5k-Zw2"/>
</connections>
@@ -634,6 +641,9 @@
</subviews>
<constraints>
<constraint firstItem="ydQ-IP-KZb" firstAttribute="top" secondItem="Bjs-D6-NVj" secondAttribute="bottom" constant="24" id="37w-fI-zi8"/>
+ <constraint firstItem="Keg-iI-sK2" firstAttribute="top" secondItem="Bjs-D6-NVj" secondAttribute="bottom" id="3Kf-Tj-Ofg"/>
+ <constraint firstItem="Keg-iI-sK2" firstAttribute="bottom" secondItem="ydQ-IP-KZb" secondAttribute="top" id="59A-sp-tTb"/>
+ <constraint firstItem="Keg-iI-sK2" firstAttribute="leading" secondItem="Lx5-tV-hNL" secondAttribute="leading" id="85d-cg-gGf"/>
<constraint firstItem="Bjs-D6-NVj" firstAttribute="top" secondItem="xch-VD-kOQ" secondAttribute="bottom" constant="24" id="8F9-gx-ngL"/>
<constraint firstAttribute="trailing" secondItem="xch-VD-kOQ" secondAttribute="trailing" id="GLB-vv-DDi"/>
<constraint firstAttribute="trailing" secondItem="Bjs-D6-NVj" secondAttribute="trailing" id="Hpo-go-tU4"/>
@@ -643,6 +653,7 @@
<constraint firstItem="xch-VD-kOQ" firstAttribute="leading" secondItem="Lx5-tV-hNL" secondAttribute="leading" id="Y3H-6z-JyF"/>
<constraint firstAttribute="bottom" secondItem="ydQ-IP-KZb" secondAttribute="bottom" id="aRW-Pg-yg6"/>
<constraint firstItem="xch-VD-kOQ" firstAttribute="top" secondItem="Lx5-tV-hNL" secondAttribute="top" id="i3j-2f-8vV"/>
+ <constraint firstAttribute="trailing" secondItem="Keg-iI-sK2" secondAttribute="trailing" id="oRh-Gz-ieh"/>
</constraints>
</view>
</subviews>
@@ -802,7 +813,7 @@
<constraint firstItem="NMg-f0-BTW" firstAttribute="leading" secondItem="459-0n-9V2" secondAttribute="leading" id="vqI-Vt-8V6"/>
</constraints>
</view>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" 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="AppButton" customModule="MullvadVPN" customModuleProvider="target">
<rect key="frame" x="0.0" y="139.5" width="327" height="42"/>
<accessibility key="accessibilityConfiguration" identifier="LogoutButton"/>
<constraints>
@@ -886,6 +897,128 @@
</objects>
<point key="canvasLocation" x="670" y="-832"/>
</scene>
+ <!--Consent View Controller-->
+ <scene sceneID="dxQ-uf-ugD">
+ <objects>
+ <viewController storyboardIdentifier="Consent" id="kLI-jR-tKo" customClass="ConsentViewController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController">
+ <view key="view" contentMode="scaleToFill" id="xQJ-oi-zn6">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <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="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="582"/>
+ <subviews>
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Wnl-L9-JqG" userLabel="Logo header">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="100"/>
+ <subviews>
+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="NewLogoIcon" translatesAutoresizingMaskIntoConstraints="NO" id="WSx-4V-zIk">
+ <rect key="frame" x="137.5" y="0.0" width="100" height="100"/>
+ <constraints>
+ <constraint firstAttribute="width" secondItem="WSx-4V-zIk" secondAttribute="height" multiplier="1:1" id="ZtE-hc-rs8"/>
+ <constraint firstAttribute="width" constant="100" id="qGt-Am-MHR"/>
+ </constraints>
+ </imageView>
+ </subviews>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ <constraints>
+ <constraint firstItem="WSx-4V-zIk" firstAttribute="centerX" secondItem="Wnl-L9-JqG" secondAttribute="centerX" id="30b-jz-Tpk"/>
+ <constraint firstAttribute="bottom" secondItem="WSx-4V-zIk" secondAttribute="bottom" id="3FY-d7-yKL"/>
+ <constraint firstItem="WSx-4V-zIk" firstAttribute="top" secondItem="Wnl-L9-JqG" secondAttribute="top" id="ekz-Kj-ng1"/>
+ </constraints>
+ </view>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Do you agree to remaining anonymous?" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KiF-h3-6a4">
+ <rect key="frame" x="20" y="100" width="335" height="57.5"/>
+ <fontDescription key="fontDescription" type="boldSystem" pointSize="24"/>
+ <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dZ1-yd-jbD">
+ <rect key="frame" x="20" y="181.5" width="335" height="358.5"/>
+ <string key="text">You have a right to privacy. That’s why we don’t store activity logs of any kind, don't ask for personal information when signing up, and encourage you to pay anonymously.
+
In some situations, as outlined in our privacy policy, we might process personal data that you choose to send, for example if you email us.
+
We strongly believe in retaining as little data as possible because we want you to remain anonymous.
+</string>
+ <fontDescription key="fontDescription" type="system" pointSize="20"/>
+ <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ <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="540" width="16" 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"/>
+ <connections>
+ <action selector="openPrivacyPolicy:" destination="kLI-jR-tKo" eventType="touchUpInside" id="Hm5-a0-LNm"/>
+ </connections>
+ </button>
+ </subviews>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="KiF-h3-6a4" secondAttribute="trailing" constant="20" symbolic="YES" id="CK8-X1-Nkb"/>
+ <constraint firstItem="Wnl-L9-JqG" firstAttribute="leading" secondItem="N9k-cQ-tlw" secondAttribute="leading" id="FKE-Uf-7uJ"/>
+ <constraint firstAttribute="bottom" secondItem="Cas-Tk-gcz" secondAttribute="bottom" constant="20" symbolic="YES" id="Kda-4m-cai"/>
+ <constraint firstAttribute="trailing" secondItem="Wnl-L9-JqG" secondAttribute="trailing" id="MKQ-ko-Avx"/>
+ <constraint firstItem="Cas-Tk-gcz" firstAttribute="top" secondItem="dZ1-yd-jbD" secondAttribute="bottom" id="N88-cS-Ver"/>
+ <constraint firstItem="KiF-h3-6a4" firstAttribute="leading" secondItem="N9k-cQ-tlw" secondAttribute="leading" constant="20" symbolic="YES" id="NFy-JV-jZg"/>
+ <constraint firstAttribute="trailing" secondItem="dZ1-yd-jbD" secondAttribute="trailing" constant="20" symbolic="YES" id="Yyj-6q-s67"/>
+ <constraint firstItem="Wnl-L9-JqG" firstAttribute="bottom" secondItem="KiF-h3-6a4" secondAttribute="top" id="bjr-qL-pMb"/>
+ <constraint firstItem="dZ1-yd-jbD" firstAttribute="top" secondItem="KiF-h3-6a4" secondAttribute="bottom" constant="24" id="btD-0h-bhJ"/>
+ <constraint firstItem="dZ1-yd-jbD" firstAttribute="leading" secondItem="N9k-cQ-tlw" secondAttribute="leading" constant="20" symbolic="YES" id="eQC-X5-D2r"/>
+ <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Cas-Tk-gcz" secondAttribute="trailing" constant="20" symbolic="YES" id="jYh-Qy-r3y"/>
+ <constraint firstItem="Cas-Tk-gcz" firstAttribute="leading" secondItem="N9k-cQ-tlw" secondAttribute="leading" constant="20" symbolic="YES" id="uFa-a3-PG6"/>
+ <constraint firstItem="Wnl-L9-JqG" firstAttribute="top" secondItem="N9k-cQ-tlw" secondAttribute="top" id="zHJ-3T-ddt"/>
+ </constraints>
+ </view>
+ </subviews>
+ <constraints>
+ <constraint firstAttribute="bottom" secondItem="N9k-cQ-tlw" secondAttribute="bottom" id="GDa-a8-iDt"/>
+ <constraint firstAttribute="trailing" secondItem="N9k-cQ-tlw" secondAttribute="trailing" id="H5A-HQ-KaS"/>
+ <constraint firstItem="N9k-cQ-tlw" firstAttribute="leading" secondItem="JYh-33-d0O" secondAttribute="leading" id="XuX-5s-2by"/>
+ <constraint firstItem="N9k-cQ-tlw" firstAttribute="width" secondItem="JYh-33-d0O" secondAttribute="width" id="idS-Wd-3MB"/>
+ <constraint firstItem="N9k-cQ-tlw" firstAttribute="top" secondItem="JYh-33-d0O" secondAttribute="top" id="oMo-Do-1Dj"/>
+ </constraints>
+ </scrollView>
+ <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="16P-Q0-ZO9" userLabel="Footer">
+ <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="21"/>
+ <state key="normal" title="Agree &amp; Continue" backgroundImage="DefaultButton">
+ <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ </state>
+ </button>
+ </subviews>
+ <color key="backgroundColor" name="Secondary"/>
+ <constraints>
+ <constraint firstItem="ttw-7B-1MM" firstAttribute="top" secondItem="16P-Q0-ZO9" secondAttribute="topMargin" id="lkM-QB-3cu"/>
+ <constraint firstItem="ttw-7B-1MM" firstAttribute="trailing" secondItem="16P-Q0-ZO9" secondAttribute="trailingMargin" id="ntK-fj-CmJ"/>
+ <constraint firstAttribute="bottomMargin" secondItem="ttw-7B-1MM" secondAttribute="bottom" id="sFa-XA-rpD"/>
+ <constraint firstItem="ttw-7B-1MM" firstAttribute="leading" secondItem="16P-Q0-ZO9" secondAttribute="leadingMargin" id="zcA-ed-V7o"/>
+ </constraints>
+ <edgeInsets key="layoutMargins" top="24" left="16" bottom="24" right="16"/>
+ </view>
+ </subviews>
+ <color key="backgroundColor" name="Primary"/>
+ <constraints>
+ <constraint firstItem="16P-Q0-ZO9" firstAttribute="top" secondItem="JYh-33-d0O" secondAttribute="bottom" id="74M-Ho-5CP"/>
+ <constraint firstAttribute="bottom" secondItem="16P-Q0-ZO9" secondAttribute="bottom" id="IFF-x2-PtX"/>
+ <constraint firstAttribute="trailing" secondItem="JYh-33-d0O" secondAttribute="trailing" id="J2w-ev-9cV"/>
+ <constraint firstAttribute="trailing" secondItem="16P-Q0-ZO9" secondAttribute="trailing" id="cyQ-2k-LQX"/>
+ <constraint firstItem="JYh-33-d0O" firstAttribute="top" secondItem="xQJ-oi-zn6" secondAttribute="top" id="uYC-FA-dma"/>
+ <constraint firstItem="JYh-33-d0O" firstAttribute="leading" secondItem="xQJ-oi-zn6" secondAttribute="leading" id="ulR-7a-F1P"/>
+ <constraint firstItem="16P-Q0-ZO9" firstAttribute="leading" secondItem="xQJ-oi-zn6" secondAttribute="leading" id="wxq-ir-0JY"/>
+ </constraints>
+ <viewLayoutGuide key="safeArea" id="OP4-4u-dhX"/>
+ </view>
+ <navigationItem key="navigationItem" id="1zW-Vd-PiW"/>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="87X-aX-U9x" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="-311.19999999999999" y="1747.3763118440781"/>
+ </scene>
<!--Navigation Controller-->
<scene sceneID="oT4-Ap-qrZ">
<objects>
@@ -937,31 +1070,31 @@
</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="43.5"/>
+ <rect key="frame" x="0.0" y="173" width="375" height="43"/>
<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"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5ag-N4-pUg" customClass="RelayStatusIndicatorView" customModule="MullvadVPN" customModuleProvider="target">
- <rect key="frame" x="16" y="14" width="16" height="16"/>
+ <rect key="frame" x="16" y="13.5" width="16" height="16"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="QWj-hh-I3P"/>
<constraint firstAttribute="width" constant="16" id="TFV-yi-LXG"/>
</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="21.5"/>
+ <rect key="frame" x="44" y="11" width="42" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IconTick" translatesAutoresizingMaskIntoConstraints="NO" id="e1o-Bl-zd5">
- <rect key="frame" x="12" y="10" width="24" height="24"/>
+ <rect key="frame" x="12" y="9.5" width="24" height="24"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KaW-bN-I51">
- <rect key="frame" x="311" y="0.0" width="64" height="43.5"/>
+ <rect key="frame" x="311" y="0.0" width="64" height="43"/>
<constraints>
<constraint firstAttribute="width" constant="64" id="UU3-Di-65E"/>
</constraints>
@@ -1050,7 +1183,7 @@
<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">
+ <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"/>
<inset key="contentEdgeInsets" minX="0.0" minY="0.0" maxX="0.0" maxY="10"/>
<state key="normal" title="Select location" backgroundImage="TranslucentNeutralButton">
@@ -1071,7 +1204,7 @@
</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">
+ <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">
@@ -1109,7 +1242,7 @@
<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">
+ <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"/>
<inset key="contentEdgeInsets" minX="0.0" minY="0.0" maxX="0.0" maxY="10"/>
<state key="normal" title="Switch location" backgroundImage="TranslucentNeutralButton">
@@ -1135,7 +1268,7 @@
<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">
+ <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"/>
@@ -1182,7 +1315,7 @@
<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">
+ <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"/>
<inset key="contentEdgeInsets" minX="0.0" minY="0.0" maxX="0.0" maxY="10"/>
<state key="normal" title="Switch location" backgroundImage="TranslucentNeutralButton">
@@ -1208,7 +1341,7 @@
<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">
+ <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">
@@ -1251,10 +1384,12 @@
<image name="DangerButton" width="9" height="9"/>
<image name="DefaultButton" width="9" height="9"/>
<image name="IconChevronDown" width="24" height="24"/>
+ <image name="IconExtlink" width="16" height="16"/>
<image name="IconSettings" width="24" height="24"/>
<image name="IconSuccess" width="60" height="60"/>
<image name="IconTick" width="24" height="24"/>
<image name="LogoIcon" width="49" height="50"/>
+ <image name="NewLogoIcon" width="400" height="400"/>
<image name="SuccessButton" width="9" height="9"/>
<image name="TranslucentDangerButton" width="9" height="9"/>
<image name="TranslucentNeutralButton" width="9" height="9"/>
diff --git a/ios/MullvadVPN/ConsentViewController.swift b/ios/MullvadVPN/ConsentViewController.swift
new file mode 100644
index 0000000000..9a4f9853e6
--- /dev/null
+++ b/ios/MullvadVPN/ConsentViewController.swift
@@ -0,0 +1,48 @@
+//
+// ConsentViewController.swift
+// MullvadVPN
+//
+// Created by pronebird on 21/02/2020.
+// Copyright © 2020 Mullvad VPN AB. All rights reserved.
+//
+
+import SafariServices
+import UIKit
+
+class ConsentViewController: UIViewController, RootContainment, SFSafariViewControllerDelegate {
+
+ override var preferredStatusBarStyle: UIStatusBarStyle {
+ return .lightContent
+ }
+
+ var preferredHeaderBarStyle: HeaderBarStyle {
+ return .transparent
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ self.rootContainerController?.headerBarSettingsButton.isHidden = true
+ }
+
+ // MARK: - IBActions
+
+ @IBAction func openPrivacyPolicy(_ sender: Any) {
+ let pageURL = URL(string: "https://mullvad.net/en/help/privacy-policy/?hide_nav")!
+
+ let safariController = SFSafariViewController(url: pageURL)
+ safariController.delegate = self
+
+ let navigationController = UINavigationController(rootViewController: safariController)
+ navigationController.setNavigationBarHidden(true, animated: false)
+
+ present(navigationController, animated: true)
+ }
+
+ // MARK: - SFSafariViewControllerDelegate
+
+ func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
+ controller.dismiss(animated: true)
+ }
+
+}
diff --git a/ios/MullvadVPN/CustomButton.swift b/ios/MullvadVPN/CustomButton.swift
deleted file mode 100644
index 1b5bcbece3..0000000000
--- a/ios/MullvadVPN/CustomButton.swift
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// CustomButton.swift
-// MullvadVPN
-//
-// Created by pronebird on 23/05/2019.
-// Copyright © 2019 Mullvad VPN AB. All rights reserved.
-//
-
-import UIKit
-
-@IBDesignable class CustomButton: UIButton {
-
- override init(frame: CGRect) {
- super.init(frame: frame)
-
- commonInit()
- }
-
- required init?(coder aDecoder: NSCoder) {
- super.init(coder: aDecoder)
-
- commonInit()
- }
-
- private func commonInit() {
- var contentInsets = contentEdgeInsets
-
- if contentInsets.top == 0 {
- contentInsets.top = 10
- }
-
- if contentInsets.bottom == 0 {
- contentInsets.bottom = 10
- }
-
- if contentInsets.right == 0 {
- contentInsets.right = 10
- }
-
- if contentInsets.left == 0 {
- contentInsets.left = 10
- }
-
- contentEdgeInsets = contentInsets
- titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
-
- setTitleColor(UIColor.white, for: .normal)
- setTitleColor(UIColor.lightGray, for: .highlighted)
- setTitleColor(UIColor.lightGray, for: .disabled)
- }
-
- override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
- var imageRect = super.imageRect(forContentRect: contentRect)
-
- imageRect.origin.x = contentRect.maxX - imageRect.size.width
-
- return imageRect
- }
-
- override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
- var titleRect = super.titleRect(forContentRect: contentRect)
-
- titleRect.origin.x = contentRect.midX - titleRect.width * 0.5
-
- return titleRect
- }
-
-}
diff --git a/ios/MullvadVPN/UIColor+Palette.swift b/ios/MullvadVPN/UIColor+Palette.swift
index 8f6d35c147..8235f857a3 100644
--- a/ios/MullvadVPN/UIColor+Palette.swift
+++ b/ios/MullvadVPN/UIColor+Palette.swift
@@ -30,6 +30,12 @@ extension UIColor {
}
}
+ enum AppButton {
+ static let normalTitleColor = UIColor.white
+ static let highlightedTitleColor = UIColor.lightGray
+ static let disabledTitleColor = UIColor.lightGray
+ }
+
// Relay availability indicator view
enum RelayStatusIndicator {
static let activeColor = successColor.withAlphaComponent(0.9)
diff --git a/ios/MullvadVPN/ViewControllerIdentifier.swift b/ios/MullvadVPN/ViewControllerIdentifier.swift
index 8c4c9b2691..7e2dcd4e03 100644
--- a/ios/MullvadVPN/ViewControllerIdentifier.swift
+++ b/ios/MullvadVPN/ViewControllerIdentifier.swift
@@ -9,6 +9,7 @@
import Foundation
enum ViewControllerIdentifier: String {
+ case consent = "Consent"
case root = "Root"
case login = "Login"
case main = "Main"