diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2020-02-26 12:38:36 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2020-02-26 17:14:56 +0100 |
| commit | 8922808f55a8458a1e7acd80959f84ce7a54bfe5 (patch) | |
| tree | 37f4c1b98a222de16f57e284262bdc5c8c64af17 | |
| parent | 3ae8363e792b01307688ceea5f503e0b2cc9cadf (diff) | |
| download | mullvadvpn-8922808f55a8458a1e7acd80959f84ce7a54bfe5.tar.xz mullvadvpn-8922808f55a8458a1e7acd80959f84ce7a54bfe5.zip | |
Add consent view controller and rework app button
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 12 | ||||
| -rw-r--r-- | ios/MullvadVPN/AppButton.swift | 251 | ||||
| -rw-r--r-- | ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/Contents.json | 15 | ||||
| -rw-r--r-- | ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/NewLogoIcon.pdf | bin | 0 -> 2604 bytes | |||
| -rw-r--r-- | ios/MullvadVPN/Base.lproj/Main.storyboard | 203 | ||||
| -rw-r--r-- | ios/MullvadVPN/ConsentViewController.swift | 48 | ||||
| -rw-r--r-- | ios/MullvadVPN/CustomButton.swift | 68 | ||||
| -rw-r--r-- | ios/MullvadVPN/UIColor+Palette.swift | 6 | ||||
| -rw-r--r-- | ios/MullvadVPN/ViewControllerIdentifier.swift | 1 |
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 Binary files differnew file mode 100644 index 0000000000..a3200ee169 --- /dev/null +++ b/ios/MullvadVPN/Assets.xcassets/NewLogoIcon.imageset/NewLogoIcon.pdf 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 & 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" |
