diff options
26 files changed, 1222 insertions, 1238 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 8f3cfbd48d..acb84d969c 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -50,8 +50,6 @@ 581503A424D6F1EC00C9C50E /* ChainedError+Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581503A224D6F1EC00C9C50E /* ChainedError+Logger.swift */; }; 581503A624D6F4AE00C9C50E /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581503A524D6F4AE00C9C50E /* Logging.swift */; }; 581503A724D6F4AE00C9C50E /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581503A524D6F4AE00C9C50E /* Logging.swift */; }; - 581CBCE62296B97300727D7F /* ViewControllerIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581CBCE52296B97300727D7F /* ViewControllerIdentifier.swift */; }; - 581CBCEC2298041B00727D7F /* SettingsAppVersionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581CBCEB2298041B00727D7F /* SettingsAppVersionCell.swift */; }; 581CBCEE229826FD00727D7F /* StaticTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581CBCED229826FD00727D7F /* StaticTableViewDataSource.swift */; }; 582AE3102440A6CA00E6733A /* AccountTokenInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582AE30F2440A6CA00E6733A /* AccountTokenInput.swift */; }; 582AE3122440CA0D00E6733A /* AccountTokenInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582AE3112440CA0D00E6733A /* AccountTokenInputTests.swift */; }; @@ -96,7 +94,6 @@ 5860F1C223A785C600CEA666 /* WireguardDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5860F1C123A785C600CEA666 /* WireguardDevice.swift */; }; 5860F1C423A8D25F00CEA666 /* WireguardConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5860F1C323A8D25F00CEA666 /* WireguardConfiguration.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 */; }; @@ -104,7 +101,6 @@ 58723E7522A54CB2009837F5 /* libwg-go.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58723E7422A54C63009837F5 /* libwg-go.a */; }; 5873884D239E6D7E00E96C4E /* EmbeddedViewContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5873884C239E6D7E00E96C4E /* EmbeddedViewContainerView.swift */; }; 587425C12299833500CA2045 /* RootContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587425C02299833500CA2045 /* RootContainerViewController.swift */; }; - 5877152E23981C5B001F8237 /* SettingsBasicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5877152D23981C5B001F8237 /* SettingsBasicCell.swift */; }; 5877153023981F7B001F8237 /* WireguardKeysViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5877152F23981F7B001F8237 /* WireguardKeysViewController.swift */; }; 58781CC922AE7CA8009B9D8E /* RelayConstraints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58781CC822AE7CA8009B9D8E /* RelayConstraints.swift */; }; 58781CCE22AE8918009B9D8E /* RelayConstraints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58781CC822AE7CA8009B9D8E /* RelayConstraints.swift */; }; @@ -117,7 +113,7 @@ 588534BF246193D90018B744 /* AutomaticKeyRotationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 588534BD246193C00018B744 /* AutomaticKeyRotationManager.swift */; }; 5888AD7F2279B6BF0051EB06 /* RelayStatusIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD7E2279B6BF0051EB06 /* RelayStatusIndicatorView.swift */; }; 5888AD83227B11080051EB06 /* SelectLocationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD82227B11080051EB06 /* SelectLocationCell.swift */; }; - 5888AD87227B17950051EB06 /* SelectLocationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD86227B17950051EB06 /* SelectLocationController.swift */; }; + 5888AD87227B17950051EB06 /* SelectLocationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD86227B17950051EB06 /* SelectLocationViewController.swift */; }; 588D2FE3248AC27F00E313F7 /* AsyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E973DD24850EB600096F90 /* AsyncOperation.swift */; }; 58906DE02445C7A5002F0673 /* NEProviderStopReason+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58906DDF2445C7A5002F0673 /* NEProviderStopReason+Debug.swift */; }; 58907D9524D17B4E00CFC3F5 /* DisconnectSplitButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58907D9424D17B4E00CFC3F5 /* DisconnectSplitButton.swift */; }; @@ -133,6 +129,8 @@ 58A1AA8C23F5584C009F7EA6 /* ConnectionPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */; }; 58A8BE81239FBE62006B74AC /* IPEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58561C98239A5D1500BD6B5E /* IPEndpoint.swift */; }; 58A99ED3240014A0006599E9 /* ConsentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A99ED2240014A0006599E9 /* ConsentViewController.swift */; }; + 58AB9DEC2501040C006C5526 /* ConsentViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 58AB9DEB2501040C006C5526 /* ConsentViewController.xib */; }; + 58AB9DEE25010636006C5526 /* LoginViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 58AB9DED25010636006C5526 /* LoginViewController.xib */; }; 58AEEF652344A36000C9BBD5 /* KeychainError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AEEF642344A36000C9BBD5 /* KeychainError.swift */; }; 58AEEF662344A37400C9BBD5 /* KeychainError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AEEF642344A36000C9BBD5 /* KeychainError.swift */; }; 58AEEF6B2344A46200C9BBD5 /* TunnelSettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AEEF6A2344A46200C9BBD5 /* TunnelSettingsManager.swift */; }; @@ -144,6 +142,7 @@ 58B0A2AD238EE6EC00BC001D /* MullvadEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */; }; 58B8743222B25A7600015324 /* WireguardAssociatedAddresses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B8743122B25A7600015324 /* WireguardAssociatedAddresses.swift */; }; 58B8743B22B788D200015324 /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B8743722B25EAB00015324 /* PacketTunnelSettingsGenerator.swift */; }; + 58B9814E24FEA70D00C0D59E /* WireguardKeysViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 58B9814D24FEA70D00C0D59E /* WireguardKeysViewController.xib */; }; 58B9EB132488ED2100095626 /* AlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B9EB122488ED2100095626 /* AlertPresenter.swift */; }; 58B9EB152489139B00095626 /* DisplayChainedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B9EB142489139B00095626 /* DisplayChainedError.swift */; }; 58BA692E23E99EFF009DC256 /* Locking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BA692D23E99EFF009DC256 /* Locking.swift */; }; @@ -185,7 +184,9 @@ 58CE5E81224146470008646E /* PacketTunnel.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 58CE5E79224146470008646E /* PacketTunnel.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 58D0C79E23F1CEBA00FE9BA7 /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D0C79D23F1CEBA00FE9BA7 /* SnapshotHelper.swift */; }; 58D0C7A223F1CECF00FE9BA7 /* MullvadVPNScreenshots.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D0C7A023F1CECF00FE9BA7 /* MullvadVPNScreenshots.swift */; }; + 58D9AF6B2501111800B6FAB5 /* ConnectViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 58D9AF6A2501111800B6FAB5 /* ConnectViewController.xib */; }; 58DF28A52417CB4B00E836B0 /* AppStorePaymentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DF28A42417CB4B00E836B0 /* AppStorePaymentManager.swift */; }; + 58E5BC2624FEB6DB00A53A76 /* AccountViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 58E5BC2524FEB6DB00A53A76 /* AccountViewController.xib */; }; 58E6771F24ADFE7800AA26E7 /* SettingsNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E6771E24ADFE7800AA26E7 /* SettingsNavigationController.swift */; }; 58F19E35228C15BA00C7710B /* SpinnerActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F19E34228C15BA00C7710B /* SpinnerActivityIndicatorView.swift */; }; 58F3C0962492617E003E76BE /* AsyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E973DD24850EB600096F90 /* AsyncOperation.swift */; }; @@ -280,8 +281,6 @@ 5815039C24D6ECE600C9C50E /* TextFileOutputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFileOutputStream.swift; sourceTree = "<group>"; }; 581503A224D6F1EC00C9C50E /* ChainedError+Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChainedError+Logger.swift"; sourceTree = "<group>"; }; 581503A524D6F4AE00C9C50E /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; }; - 581CBCE52296B97300727D7F /* ViewControllerIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerIdentifier.swift; sourceTree = "<group>"; }; - 581CBCEB2298041B00727D7F /* SettingsAppVersionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsAppVersionCell.swift; sourceTree = "<group>"; }; 581CBCED229826FD00727D7F /* StaticTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticTableViewDataSource.swift; sourceTree = "<group>"; }; 582AE30F2440A6CA00E6733A /* AccountTokenInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountTokenInput.swift; sourceTree = "<group>"; }; 582AE3112440CA0D00E6733A /* AccountTokenInputTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTokenInputTests.swift; sourceTree = "<group>"; }; @@ -303,13 +302,11 @@ 5860F1C323A8D25F00CEA666 /* WireguardConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireguardConfiguration.swift; sourceTree = "<group>"; }; 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>"; }; 587425C02299833500CA2045 /* RootContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootContainerViewController.swift; sourceTree = "<group>"; }; - 5877152D23981C5B001F8237 /* SettingsBasicCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsBasicCell.swift; sourceTree = "<group>"; }; 5877152F23981F7B001F8237 /* WireguardKeysViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireguardKeysViewController.swift; sourceTree = "<group>"; }; 58781CC822AE7CA8009B9D8E /* RelayConstraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConstraints.swift; sourceTree = "<group>"; }; 58781CD422AFBA39009B9D8E /* RelaySelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySelector.swift; sourceTree = "<group>"; }; @@ -320,7 +317,7 @@ 588534BD246193C00018B744 /* AutomaticKeyRotationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomaticKeyRotationManager.swift; sourceTree = "<group>"; }; 5888AD7E2279B6BF0051EB06 /* RelayStatusIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayStatusIndicatorView.swift; sourceTree = "<group>"; }; 5888AD82227B11080051EB06 /* SelectLocationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationCell.swift; sourceTree = "<group>"; }; - 5888AD86227B17950051EB06 /* SelectLocationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationController.swift; sourceTree = "<group>"; }; + 5888AD86227B17950051EB06 /* SelectLocationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationViewController.swift; sourceTree = "<group>"; }; 58906DDF2445C7A5002F0673 /* NEProviderStopReason+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEProviderStopReason+Debug.swift"; sourceTree = "<group>"; }; 58907D9424D17B4E00CFC3F5 /* DisconnectSplitButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisconnectSplitButton.swift; sourceTree = "<group>"; }; 5894E725236B2801008A2793 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; @@ -330,12 +327,15 @@ 58A1AA8623F43901009F7EA6 /* Location.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Location.swift; sourceTree = "<group>"; }; 58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionPanelView.swift; sourceTree = "<group>"; }; 58A99ED2240014A0006599E9 /* ConsentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentViewController.swift; sourceTree = "<group>"; }; + 58AB9DEB2501040C006C5526 /* ConsentViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConsentViewController.xib; sourceTree = "<group>"; }; + 58AB9DED25010636006C5526 /* LoginViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LoginViewController.xib; sourceTree = "<group>"; }; 58AEEF642344A36000C9BBD5 /* KeychainError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainError.swift; sourceTree = "<group>"; }; 58AEEF6A2344A46200C9BBD5 /* TunnelSettingsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsManager.swift; sourceTree = "<group>"; }; 58B0A2A0238EE67E00BC001D /* MullvadVPNTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MullvadVPNTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58B0A2A4238EE67E00BC001D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 58B8743122B25A7600015324 /* WireguardAssociatedAddresses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireguardAssociatedAddresses.swift; sourceTree = "<group>"; }; 58B8743722B25EAB00015324 /* PacketTunnelSettingsGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelSettingsGenerator.swift; sourceTree = "<group>"; }; + 58B9814D24FEA70D00C0D59E /* WireguardKeysViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WireguardKeysViewController.xib; sourceTree = "<group>"; }; 58B9EB122488ED2100095626 /* AlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresenter.swift; sourceTree = "<group>"; }; 58B9EB142489139B00095626 /* DisplayChainedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayChainedError.swift; sourceTree = "<group>"; }; 58BA692D23E99EFF009DC256 /* Locking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Locking.swift; sourceTree = "<group>"; }; @@ -374,7 +374,9 @@ 58D0C79D23F1CEBA00FE9BA7 /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotHelper.swift; sourceTree = "<group>"; }; 58D0C79F23F1CECF00FE9BA7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 58D0C7A023F1CECF00FE9BA7 /* MullvadVPNScreenshots.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MullvadVPNScreenshots.swift; sourceTree = "<group>"; }; + 58D9AF6A2501111800B6FAB5 /* ConnectViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConnectViewController.xib; sourceTree = "<group>"; }; 58DF28A42417CB4B00E836B0 /* AppStorePaymentManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStorePaymentManager.swift; sourceTree = "<group>"; }; + 58E5BC2524FEB6DB00A53A76 /* AccountViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountViewController.xib; sourceTree = "<group>"; }; 58E6771E24ADFE7800AA26E7 /* SettingsNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsNavigationController.swift; sourceTree = "<group>"; }; 58E973DD24850EB600096F90 /* AsyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncOperation.swift; sourceTree = "<group>"; }; 58ECD29123F178FD004298B6 /* Screenshots.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Screenshots.xcconfig; sourceTree = "<group>"; }; @@ -531,6 +533,7 @@ 58CCA01D2242787B004F3011 /* AccountTextField.swift */, 582AE30F2440A6CA00E6733A /* AccountTokenInput.swift */, 58CCA01722426713004F3011 /* AccountViewController.swift */, + 58E5BC2524FEB6DB00A53A76 /* AccountViewController.xib */, 58B9EB122488ED2100095626 /* AlertPresenter.swift */, 5868585424054096000B8131 /* AppButton.swift */, 58CE5E63224146200008646E /* AppDelegate.swift */, @@ -544,6 +547,7 @@ 58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */, 58CCA00F224249A1004F3011 /* ConnectViewController.swift */, 58A99ED2240014A0006599E9 /* ConsentViewController.swift */, + 58AB9DEB2501040C006C5526 /* ConsentViewController.xib */, 58F3C09B249B99DD003E76BE /* Curve25519.swift */, 5896AE83246D5889005B36CB /* CustomDateComponentsFormatting.swift */, 582BB1B0229569620055B6EF /* CustomNavigationBar.swift */, @@ -579,20 +583,18 @@ 5811DE4F239014550011EB53 /* NEVPNStatus+Debug.swift */, 58CC40EE24A601900019D96E /* ObserverList.swift */, 580EE1FF24B3218800F9D8A1 /* Operations */, + 583BC70624FE4DC400C9DE04 /* Optional+DispatchQueue.swift */, 5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */, 58BFA5C522A7C97F00A6173D /* RelayCache.swift */, 58781CC822AE7CA8009B9D8E /* RelayConstraints.swift */, 58781CD422AFBA39009B9D8E /* RelaySelector.swift */, 5888AD7E2279B6BF0051EB06 /* RelayStatusIndicatorView.swift */, 587425C02299833500CA2045 /* RootContainerViewController.swift */, - 5867A51B2248F26A005513C0 /* SegueIdentifier.swift */, 5888AD82227B11080051EB06 /* SelectLocationCell.swift */, - 5888AD86227B17950051EB06 /* SelectLocationController.swift */, + 5888AD86227B17950051EB06 /* SelectLocationViewController.swift */, 5857F24224C8662600CF6F47 /* SelectLocationHeaderView.swift */, 5857F24624C882D700CF6F47 /* SelectLocationNavigationController.swift */, 582BB1B2229574F40055B6EF /* SettingsAccountCell.swift */, - 581CBCEB2298041B00727D7F /* SettingsAppVersionCell.swift */, - 5877152D23981C5B001F8237 /* SettingsBasicCell.swift */, 582BB1AE229566420055B6EF /* SettingsCell.swift */, 58E6771E24ADFE7800AA26E7 /* SettingsNavigationController.swift */, 58CCA01122424D11004F3011 /* SettingsViewController.swift */, @@ -609,13 +611,14 @@ 587CBFE222807F530028DED3 /* UIColor+Helpers.swift */, 58CCA0152242560B004F3011 /* UIColor+Palette.swift */, 58FD5BF12424F7D700112C88 /* UserInterfaceInteractionRestriction.swift */, - 581CBCE52296B97300727D7F /* ViewControllerIdentifier.swift */, 58B8743122B25A7600015324 /* WireguardAssociatedAddresses.swift */, 5877152F23981F7B001F8237 /* WireguardKeysViewController.swift */, + 58B9814D24FEA70D00C0D59E /* WireguardKeysViewController.xib */, 58C6B35322BB87C4003C19AD /* WireguardPrivateKey.swift */, 58F3C098249B978C003E76BE /* x25519.c */, 58F3C097249B978C003E76BE /* x25519.h */, - 583BC70624FE4DC400C9DE04 /* Optional+DispatchQueue.swift */, + 58AB9DED25010636006C5526 /* LoginViewController.xib */, + 58D9AF6A2501111800B6FAB5 /* ConnectViewController.xib */, ); path = MullvadVPN; sourceTree = "<group>"; @@ -845,10 +848,15 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 58D9AF6B2501111800B6FAB5 /* ConnectViewController.xib in Resources */, + 58AB9DEE25010636006C5526 /* LoginViewController.xib in Resources */, 58F3C0A624A50157003E76BE /* relays.json in Resources */, 58CE5E6E224146210008646E /* LaunchScreen.storyboard in Resources */, 58CE5E6B224146210008646E /* Assets.xcassets in Resources */, + 58AB9DEC2501040C006C5526 /* ConsentViewController.xib in Resources */, 58CE5E69224146200008646E /* Main.storyboard in Resources */, + 58E5BC2624FEB6DB00A53A76 /* AccountViewController.xib in Resources */, + 58B9814E24FEA70D00C0D59E /* WireguardKeysViewController.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -966,7 +974,6 @@ 582BB1B52295780F0055B6EF /* AccountExpiry.swift in Sources */, 582BB1B3229574F40055B6EF /* SettingsAccountCell.swift in Sources */, 58CCA010224249A1004F3011 /* ConnectViewController.swift in Sources */, - 581CBCE62296B97300727D7F /* ViewControllerIdentifier.swift in Sources */, 580EE21524B3231200F9D8A1 /* OperationBlockObserver.swift in Sources */, 58BFA5C622A7C97F00A6173D /* RelayCache.swift in Sources */, 582BB1B1229569620055B6EF /* CustomNavigationBar.swift in Sources */, @@ -979,7 +986,7 @@ 582AE3102440A6CA00E6733A /* AccountTokenInput.swift in Sources */, 58FAEDF7245088E100CB0F5B /* Keychain.swift in Sources */, 58907D9524D17B4E00CFC3F5 /* DisconnectSplitButton.swift in Sources */, - 5888AD87227B17950051EB06 /* SelectLocationController.swift in Sources */, + 5888AD87227B17950051EB06 /* SelectLocationViewController.swift in Sources */, 580EE20424B321EC00F9D8A1 /* OperationObserver.swift in Sources */, 58F19E35228C15BA00C7710B /* SpinnerActivityIndicatorView.swift in Sources */, 58A99ED3240014A0006599E9 /* ConsentViewController.swift in Sources */, @@ -987,7 +994,6 @@ 58CCA0162242560B004F3011 /* UIColor+Palette.swift in Sources */, 58AEEF6B2344A46200C9BBD5 /* TunnelSettingsManager.swift in Sources */, 587CBFE322807F530028DED3 /* UIColor+Helpers.swift in Sources */, - 581CBCEC2298041B00727D7F /* SettingsAppVersionCell.swift in Sources */, 58FAEDFD24533A5500CB0F5B /* KeychainMatchLimit.swift in Sources */, 5840250422B11AB700E4CFEC /* MullvadEndpoint.swift in Sources */, 58CC40EF24A601900019D96E /* ObserverList.swift in Sources */, @@ -1017,7 +1023,6 @@ 5807E2C02432038B00F5FF30 /* String+Split.swift in Sources */, 58CE5E66224146200008646E /* LoginViewController.swift in Sources */, 580EE21B24B3236900F9D8A1 /* InputOperation.swift in Sources */, - 5877152E23981C5B001F8237 /* SettingsBasicCell.swift in Sources */, 58FD5BE724192A2C00112C88 /* AppStoreReceipt.swift in Sources */, 5835B7CC233B76CB0096D79F /* TunnelManager.swift in Sources */, 5815039724D6ECAE00C9C50E /* CustomFormatLogHandler.swift in Sources */, @@ -1036,7 +1041,6 @@ 589AB4F7227B64450039131E /* BasicTableViewCell.swift in Sources */, 58B9EB152489139B00095626 /* DisplayChainedError.swift in Sources */, 5888AD7F2279B6BF0051EB06 /* RelayStatusIndicatorView.swift in Sources */, - 5867A51C2248F26A005513C0 /* SegueIdentifier.swift in Sources */, 58CCA01E2242787B004F3011 /* AccountTextField.swift in Sources */, 587AD7CA2342283900E93A53 /* Account.swift in Sources */, 58F840AF2464382C0044E708 /* KeychainItemRevision.swift in Sources */, diff --git a/ios/MullvadVPN/AccountViewController.swift b/ios/MullvadVPN/AccountViewController.swift index 5c81d561d4..03263ff6f1 100644 --- a/ios/MullvadVPN/AccountViewController.swift +++ b/ios/MullvadVPN/AccountViewController.swift @@ -10,6 +10,10 @@ import StoreKit import UIKit import Logging +protocol AccountViewControllerDelegate: class { + func accountViewControllerDidLogout(_ controller: AccountViewController) +} + class AccountViewController: UIViewController, AppStorePaymentObserver { @IBOutlet var accountTokenButton: UIButton! @@ -26,6 +30,8 @@ class AccountViewController: UIViewController, AppStorePaymentObserver { private let alertPresenter = AlertPresenter() private let logger = Logger(label: "AccountViewController") + weak var delegate: AccountViewControllerDelegate? + private lazy var purchaseButtonInteractionRestriction = UserInterfaceInteractionRestriction { [weak self] (enableUserInteraction, _) in // Make sure to disable the button if the product is not loaded @@ -50,6 +56,8 @@ class AccountViewController: UIViewController, AppStorePaymentObserver { override func viewDidLoad() { super.viewDidLoad() + navigationItem.title = NSLocalizedString("Account", comment: "Navigation title") + AppStorePaymentManager.shared.addPaymentObserver(self) accountExpiryObserver = NotificationCenter.default.addObserver( @@ -250,10 +258,7 @@ class AccountViewController: UIViewController, AppStorePaymentObserver { self.alertPresenter.enqueue(errorAlertController, presentingController: self) case .success: - self.performSegue( - withIdentifier: SegueIdentifier.Account.logout.rawValue, - sender: self - ) + self.delegate?.accountViewControllerDidLogout(self) } } } diff --git a/ios/MullvadVPN/AccountViewController.xib b/ios/MullvadVPN/AccountViewController.xib new file mode 100644 index 0000000000..7094f3fdd4 --- /dev/null +++ b/ios/MullvadVPN/AccountViewController.xib @@ -0,0 +1,222 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> + <device id="retina6_1" orientation="portrait" appearance="light"/> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <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"/> + </dependencies> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AccountViewController" customModule="MullvadVPN" customModuleProvider="target"> + <connections> + <outlet property="accountTokenButton" destination="lCa-aa-Pm3" id="R2W-4z-06o"/> + <outlet property="activityIndicator" destination="eGi-ok-x76" id="Lq5-Ry-ec8"/> + <outlet property="expiryLabel" destination="2i5-GK-hJb" id="0yg-To-nL7"/> + <outlet property="logoutButton" destination="hLF-CV-4mn" id="Tae-qy-70n"/> + <outlet property="purchaseButton" destination="Jll-2f-Pkg" id="Qbx-89-bCu"/> + <outlet property="restoreButton" destination="Of2-bz-zp8" id="P8L-j9-7m7"/> + <outlet property="view" destination="N94-2G-eN0" id="dAC-wQ-aYn"/> + </connections> + </placeholder> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view contentMode="scaleToFill" id="N94-2G-eN0"> + <rect key="frame" x="0.0" y="0.0" width="414" height="896"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0Lz-bX-FzY"> + <rect key="frame" x="0.0" y="0.0" width="414" height="896"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="A7Y-7l-t1J" userLabel="Container"> + <rect key="frame" x="0.0" y="0.0" width="414" height="349.5"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cUt-HL-Is8" userLabel="Content"> + <rect key="frame" x="24" y="24" width="366" height="301.5"/> + <subviews> + <view contentMode="scaleToFill" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="NgY-qI-yOq" userLabel="Account number"> + <rect key="frame" x="0.0" y="0.0" width="366" height="46"/> + <subviews> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="vAg-UO-s90"> + <rect key="frame" x="0.0" y="0.0" width="366" height="46"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Account number" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wYg-Sx-sht"> + <rect key="frame" x="0.0" y="0.0" width="366" height="17"/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lCa-aa-Pm3"> + <rect key="frame" x="0.0" y="25" width="366" height="21"/> + <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/> + <inset key="contentEdgeInsets" minX="0.01" minY="0.0" maxX="1" maxY="0.0"/> + <state key="normal" title="123456789"> + <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </state> + <connections> + <action selector="copyAccountToken" destination="-1" eventType="touchUpInside" id="hU3-zX-gvR"/> + </connections> + </button> + </subviews> + </stackView> + </subviews> + <constraints> + <constraint firstItem="vAg-UO-s90" firstAttribute="leading" secondItem="NgY-qI-yOq" secondAttribute="leading" id="03w-uO-dTN"/> + <constraint firstAttribute="trailing" secondItem="vAg-UO-s90" secondAttribute="trailing" id="Lfo-go-G45"/> + <constraint firstItem="vAg-UO-s90" firstAttribute="top" secondItem="NgY-qI-yOq" secondAttribute="top" id="VxJ-9R-Z8g"/> + <constraint firstAttribute="bottom" secondItem="vAg-UO-s90" secondAttribute="bottom" id="b7b-Im-8Ei"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="C4H-CM-EXc" userLabel="Expiry"> + <rect key="frame" x="0.0" y="70" width="366" height="45.5"/> + <subviews> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="t98-46-zC2"> + <rect key="frame" x="0.0" y="0.0" width="366" height="45.5"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oeO-Xm-rOB"> + <rect key="frame" x="0.0" y="0.0" width="366" height="17"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="751" text="Paid until" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="k3W-5i-Dbf"> + <rect key="frame" x="0.0" y="0.0" width="59.5" height="17"/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eGi-ok-x76" customClass="SpinnerActivityIndicatorView" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="350" y="0.5" width="16" height="16"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="width" constant="16" id="W8Y-gT-Qgm"/> + <constraint firstAttribute="height" constant="16" id="atJ-sI-Bp0"/> + </constraints> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="thickness"> + <real key="value" value="2"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + </view> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="bottom" secondItem="k3W-5i-Dbf" secondAttribute="bottom" id="4J3-AE-5Hy"/> + <constraint firstAttribute="trailing" secondItem="eGi-ok-x76" secondAttribute="trailing" id="5gP-Vc-aP2"/> + <constraint firstItem="k3W-5i-Dbf" firstAttribute="top" secondItem="oeO-Xm-rOB" secondAttribute="top" id="VZh-En-ucb"/> + <constraint firstItem="eGi-ok-x76" firstAttribute="centerY" secondItem="oeO-Xm-rOB" secondAttribute="centerY" id="Vlb-z0-sSB"/> + <constraint firstItem="eGi-ok-x76" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="k3W-5i-Dbf" secondAttribute="trailing" constant="8" symbolic="YES" id="h3f-p3-TI0"/> + <constraint firstItem="k3W-5i-Dbf" firstAttribute="leading" secondItem="oeO-Xm-rOB" secondAttribute="leading" id="z5j-jP-WPE"/> + </constraints> + </view> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="May 16, 2019" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2i5-GK-hJb"> + <rect key="frame" x="0.0" y="25" width="366" height="20.5"/> + <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/> + <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + </subviews> + </stackView> + </subviews> + <constraints> + <constraint firstItem="t98-46-zC2" firstAttribute="leading" secondItem="C4H-CM-EXc" secondAttribute="leading" id="TZN-lX-Cfd"/> + <constraint firstAttribute="bottom" secondItem="t98-46-zC2" secondAttribute="bottom" id="dzU-41-4Ce"/> + <constraint firstAttribute="trailing" secondItem="t98-46-zC2" secondAttribute="trailing" id="gUN-YB-Dub"/> + <constraint firstItem="t98-46-zC2" firstAttribute="top" secondItem="C4H-CM-EXc" secondAttribute="top" id="ycA-QZ-paj"/> + </constraints> + </view> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="9TF-RQ-EIQ"> + <rect key="frame" x="0.0" y="139.5" width="366" height="96"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Jll-2f-Pkg" customClass="InAppPurchaseButton" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="0.0" y="0.0" width="366" height="42"/> + <constraints> + <constraint firstAttribute="height" constant="42" placeholder="YES" id="T0e-dF-aO3"/> + </constraints> + <state key="normal" title="Display name for in-app purchase" backgroundImage="SuccessButton"> + <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </state> + <connections> + <action selector="doPurchase" destination="-1" eventType="touchUpInside" id="cOe-fB-cnj"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Of2-bz-zp8" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="0.0" y="54" width="366" height="42"/> + <constraints> + <constraint firstAttribute="height" constant="42" placeholder="YES" id="akv-uD-R7b"/> + </constraints> + <state key="normal" title="Restore purchases" backgroundImage="DefaultButton"> + <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </state> + <connections> + <action selector="restorePurchases" destination="-1" eventType="touchUpInside" id="G4r-zv-oE7"/> + </connections> + </button> + </subviews> + </stackView> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hLF-CV-4mn" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="0.0" y="259.5" width="366" height="42"/> + <accessibility key="accessibilityConfiguration" identifier="LogoutButton"/> + <constraints> + <constraint firstAttribute="height" constant="42" placeholder="YES" id="96p-fe-pCW"/> + </constraints> + <state key="normal" title="Log out" backgroundImage="DangerButton"> + <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </state> + <connections> + <action selector="doLogout" destination="-1" eventType="touchUpInside" id="cQP-IQ-YXH"/> + </connections> + </button> + </subviews> + <constraints> + <constraint firstAttribute="bottom" secondItem="hLF-CV-4mn" secondAttribute="bottom" id="8Q9-HL-ots"/> + <constraint firstItem="C4H-CM-EXc" firstAttribute="top" secondItem="NgY-qI-yOq" secondAttribute="bottom" constant="24" id="BXu-aw-iGR"/> + <constraint firstItem="9TF-RQ-EIQ" firstAttribute="top" secondItem="C4H-CM-EXc" secondAttribute="bottom" constant="24" id="DAE-90-Mp8"/> + <constraint firstAttribute="trailing" secondItem="hLF-CV-4mn" secondAttribute="trailing" id="Dsn-hU-tIY"/> + <constraint firstAttribute="trailing" secondItem="NgY-qI-yOq" secondAttribute="trailing" id="HqF-A7-TVI"/> + <constraint firstAttribute="trailing" secondItem="9TF-RQ-EIQ" secondAttribute="trailing" id="Ige-HU-iDn"/> + <constraint firstItem="hLF-CV-4mn" firstAttribute="leading" secondItem="cUt-HL-Is8" secondAttribute="leading" id="L7D-2u-m46"/> + <constraint firstItem="NgY-qI-yOq" firstAttribute="top" secondItem="cUt-HL-Is8" secondAttribute="top" id="UBb-Ur-xTn"/> + <constraint firstItem="C4H-CM-EXc" firstAttribute="leading" secondItem="cUt-HL-Is8" secondAttribute="leading" id="aLA-Ny-ns1"/> + <constraint firstItem="hLF-CV-4mn" firstAttribute="top" secondItem="9TF-RQ-EIQ" secondAttribute="bottom" constant="24" id="ebA-OO-a9k"/> + <constraint firstItem="NgY-qI-yOq" firstAttribute="leading" secondItem="cUt-HL-Is8" secondAttribute="leading" id="poq-lk-quh"/> + <constraint firstAttribute="trailing" secondItem="C4H-CM-EXc" secondAttribute="trailing" id="rCO-oS-vUH"/> + <constraint firstItem="9TF-RQ-EIQ" firstAttribute="leading" secondItem="cUt-HL-Is8" secondAttribute="leading" id="z6r-P0-UIz"/> + </constraints> + </view> + </subviews> + <constraints> + <constraint firstAttribute="trailing" secondItem="cUt-HL-Is8" secondAttribute="trailing" constant="24" id="6ID-oY-lMo"/> + <constraint firstItem="cUt-HL-Is8" firstAttribute="top" secondItem="A7Y-7l-t1J" secondAttribute="top" constant="24" id="gIs-Jy-3Wt"/> + <constraint firstItem="cUt-HL-Is8" firstAttribute="leading" secondItem="A7Y-7l-t1J" secondAttribute="leading" constant="24" id="mYu-Hf-PyO"/> + <constraint firstAttribute="bottom" secondItem="cUt-HL-Is8" secondAttribute="bottom" constant="24" id="tvu-dy-eUg"/> + </constraints> + </view> + </subviews> + <constraints> + <constraint firstItem="A7Y-7l-t1J" firstAttribute="top" secondItem="0Lz-bX-FzY" secondAttribute="top" id="1cN-aK-hFF"/> + <constraint firstItem="A7Y-7l-t1J" firstAttribute="width" secondItem="0Lz-bX-FzY" secondAttribute="width" id="FZh-X9-Ucr"/> + <constraint firstAttribute="trailing" secondItem="A7Y-7l-t1J" secondAttribute="trailing" id="hSK-e2-Hvk"/> + <constraint firstAttribute="bottom" secondItem="A7Y-7l-t1J" secondAttribute="bottom" id="mVG-9l-3sw"/> + <constraint firstItem="A7Y-7l-t1J" firstAttribute="leading" secondItem="0Lz-bX-FzY" secondAttribute="leading" id="nYy-Ub-bKV"/> + </constraints> + </scrollView> + </subviews> + <color key="backgroundColor" name="Secondary"/> + <constraints> + <constraint firstAttribute="bottom" secondItem="0Lz-bX-FzY" secondAttribute="bottom" id="Vmc-qV-8ql"/> + <constraint firstItem="0Lz-bX-FzY" firstAttribute="top" secondItem="N94-2G-eN0" secondAttribute="top" id="lLv-TR-i3s"/> + <constraint firstAttribute="trailing" secondItem="0Lz-bX-FzY" secondAttribute="trailing" id="vLz-OO-5Fk"/> + <constraint firstItem="0Lz-bX-FzY" firstAttribute="leading" secondItem="N94-2G-eN0" secondAttribute="leading" id="vQL-ZY-loY"/> + </constraints> + <viewLayoutGuide key="safeArea" id="qcy-9H-fTo"/> + <point key="canvasLocation" x="139" y="153"/> + </view> + </objects> + <resources> + <image name="DangerButton" width="9" height="9"/> + <image name="DefaultButton" width="9" height="9"/> + <image name="SuccessButton" width="9" height="9"/> + <namedColor name="Secondary"> + <color red="0.098039215686274508" green="0.1803921568627451" blue="0.27058823529411763" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> + </resources> +</document> diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index d54ac731fc..07b20b7d36 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -14,8 +14,7 @@ import Logging class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - - let mainStoryboard = UIStoryboard(name: "Main", bundle: nil) + var rootContainer: RootContainerViewController? #if targetEnvironment(simulator) let simulatorTunnelProvider = SimulatorTunnelProviderHost() @@ -26,6 +25,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { #endif func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Setup logging initLoggingSystem(bundleIdentifier: Bundle.main.bundleIdentifier!) #if DEBUG @@ -36,13 +36,23 @@ class AppDelegate: UIResponder, UIApplicationDelegate { #endif #if targetEnvironment(simulator) + // Configure mock tunnel provider on simulator SimulatorTunnelProvider.shared.delegate = simulatorTunnelProvider #endif - let accountToken = Account.shared.token + // Create an app window + self.window = UIWindow(frame: UIScreen.main.bounds) + // Set an empty view controller while loading tunnels + let launchController = UIViewController() + launchController.view.backgroundColor = .primaryColor + self.window?.rootViewController = launchController + + // Update relays RelayCache.shared.updateRelays() + // Load tunnels + let accountToken = Account.shared.token TunnelManager.shared.loadTunnel(accountToken: accountToken) { (result) in DispatchQueue.main.async { if case .failure(let error) = result { @@ -50,9 +60,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } let rootViewController = RootContainerViewController() + rootViewController.delegate = self let showMainController = { (_ animated: Bool) in - self.showMainController(in: rootViewController, animated: animated) { + self.showConnectController(in: rootViewController, animated: animated) { self.didPresentTheMainController() } } @@ -68,9 +79,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } self.window?.rootViewController = rootViewController + self.rootContainer = rootViewController } } + // Show the window + self.window?.makeKeyAndVisible() + return true } @@ -87,26 +102,24 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } private func showTermsOfService(in rootViewController: RootContainerViewController, completionHandler: @escaping () -> Void) { - let consentViewController = self.mainStoryboard.instantiateViewController(withIdentifier: ViewControllerIdentifier.consent.rawValue) as! ConsentViewController - + let consentViewController = ConsentViewController() consentViewController.completionHandler = completionHandler rootViewController.setViewControllers([consentViewController], animated: false) } - private func showMainController( + private func showConnectController( in rootViewController: RootContainerViewController, animated: Bool, completionHandler: @escaping () -> Void) { - let loginViewController = self.mainStoryboard.instantiateViewController(withIdentifier: ViewControllerIdentifier.login.rawValue) + let loginViewController = LoginViewController() + loginViewController.delegate = self - var viewControllers = [loginViewController] + var viewControllers: [UIViewController] = [loginViewController] if Account.shared.isLoggedIn { - let mainViewController = self.mainStoryboard.instantiateViewController(withIdentifier: ViewControllerIdentifier.main.rawValue) - - viewControllers.append(mainViewController) + viewControllers.append(ConnectViewController()) } rootViewController.setViewControllers(viewControllers, animated: animated, completion: completionHandler) @@ -114,6 +127,46 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } +extension AppDelegate: RootContainerViewControllerDelegate { + + func rootContainerViewControllerShouldShowSettings(_ controller: RootContainerViewController, navigateTo route: SettingsNavigationRoute?, animated: Bool) { + let settingsController = SettingsViewController(style: .grouped) + settingsController.settingsDelegate = self + + let navController = SettingsNavigationController(navigationBarClass: CustomNavigationBar.self, toolbarClass: nil) + navController.pushViewController(settingsController, animated: false) + + if let route = route { + settingsController.navigate(to: route) + } + + controller.present(navController, animated: animated) + } +} + +extension AppDelegate: LoginViewControllerDelegate { + + func loginViewControllerDidLogin(_ controller: LoginViewController) { + rootContainer?.pushViewController(ConnectViewController(), animated: true) + } + +} + +extension AppDelegate: SettingsViewControllerDelegate { + + func settingsViewController(_ controller: SettingsViewController, didFinishWithReason reason: SettingsDismissReason) { + if case .userLoggedOut = reason { + rootContainer?.popToRootViewController(animated: false) + + let loginController = rootContainer?.topViewController as? LoginViewController + + loginController?.reset() + } + controller.dismiss(animated: true) + } + +} + extension AppDelegate: AppStorePaymentManagerDelegate { func appStorePaymentManager(_ manager: AppStorePaymentManager, diff --git a/ios/MullvadVPN/Base.lproj/Main.storyboard b/ios/MullvadVPN/Base.lproj/Main.storyboard index f2ce083c98..4503b4021e 100644 --- a/ios/MullvadVPN/Base.lproj/Main.storyboard +++ b/ios/MullvadVPN/Base.lproj/Main.storyboard @@ -22,1047 +22,12 @@ </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="2sf-Y1-Ntj" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/> </objects> - <point key="canvasLocation" x="-1306" y="27"/> - </scene> - <!--Login View Controller--> - <scene sceneID="tne-QT-ifu"> - <objects> - <viewController storyboardIdentifier="Login" id="BYZ-38-t0r" customClass="LoginViewController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController"> - <view key="view" contentMode="scaleToFill" id="xpu-Q8-m8b"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <subviews> - <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0ZY-Kh-JiM" userLabel="Container"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pID-oa-Rrg" customClass="SpinnerActivityIndicatorView" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="163.5" y="173" width="48" height="48"/> - <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstAttribute="height" constant="48" id="2J4-Qc-ctc"/> - <constraint firstAttribute="width" constant="48" id="ohE-fk-mg9"/> - </constraints> - </view> - <imageView clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IconSuccess" translatesAutoresizingMaskIntoConstraints="NO" id="7ux-Tb-Fzq"> - <rect key="frame" x="157.5" y="167" width="60" height="60"/> - </imageView> - <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="V3j-Lb-fSQ" userLabel="Form"> - <rect key="frame" x="0.0" y="251" width="375" height="125.5"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Login" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Nxn-Fc-EGe"> - <rect key="frame" x="24" y="0.0" width="327" height="39"/> - <fontDescription key="fontDescription" type="system" pointSize="32"/> - <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" text="Enter your account number" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XSV-Lk-dj4"> - <rect key="frame" x="24" y="47" width="327" height="20.5"/> - <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" white="1" alpha="0.60359589041095896" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="VmT-ya-ufe" customClass="AccountInputGroupView" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="24" y="77.5" width="327" height="48"/> - <subviews> - <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="0000 0000 0000 0000" textAlignment="natural" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="XOB-ct-yLU" userLabel="Account Text Field" customClass="AccountTextField" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="0.0" y="0.0" width="327" height="48"/> - <accessibility key="accessibilityConfiguration" identifier="LoginTextField"/> - <fontDescription key="fontDescription" type="system" pointSize="20"/> - <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="numberPad" enablesReturnKeyAutomatically="YES" smartDashesType="no" smartInsertDeleteType="no" smartQuotesType="no" textContentType="username"/> - </textField> - </subviews> - <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstItem="XOB-ct-yLU" firstAttribute="top" secondItem="VmT-ya-ufe" secondAttribute="top" id="6gC-g8-WvR"/> - <constraint firstAttribute="trailing" secondItem="XOB-ct-yLU" secondAttribute="trailing" id="8oc-Rn-csw"/> - <constraint firstAttribute="height" constant="48" placeholder="YES" id="Str-4H-10Q"/> - <constraint firstItem="XOB-ct-yLU" firstAttribute="leading" secondItem="VmT-ya-ufe" secondAttribute="leading" id="dLW-t4-NiY"/> - <constraint firstAttribute="bottom" secondItem="XOB-ct-yLU" secondAttribute="bottom" id="ykb-mC-noi"/> - </constraints> - <connections> - <outlet property="textField" destination="XOB-ct-yLU" id="7VW-eF-gMr"/> - </connections> - </view> - </subviews> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstAttribute="trailingMargin" secondItem="Nxn-Fc-EGe" secondAttribute="trailing" id="1ea-k3-78I"/> - <constraint firstItem="XSV-Lk-dj4" firstAttribute="leading" secondItem="Nxn-Fc-EGe" secondAttribute="leading" id="2Yu-kr-QsE"/> - <constraint firstItem="VmT-ya-ufe" firstAttribute="leading" secondItem="Nxn-Fc-EGe" secondAttribute="leading" id="8FN-nm-t0F"/> - <constraint firstItem="VmT-ya-ufe" firstAttribute="top" secondItem="XSV-Lk-dj4" secondAttribute="bottom" constant="10" id="9pH-T3-2jW"/> - <constraint firstItem="Nxn-Fc-EGe" firstAttribute="leading" secondItem="V3j-Lb-fSQ" secondAttribute="leadingMargin" id="Ce0-1J-FJc"/> - <constraint firstItem="XSV-Lk-dj4" firstAttribute="trailing" secondItem="Nxn-Fc-EGe" secondAttribute="trailing" id="OLs-m1-xHT"/> - <constraint firstAttribute="bottom" secondItem="VmT-ya-ufe" secondAttribute="bottom" id="OhO-fH-gIS"/> - <constraint firstItem="VmT-ya-ufe" firstAttribute="trailing" secondItem="Nxn-Fc-EGe" secondAttribute="trailing" id="RMD-VJ-u4j"/> - <constraint firstItem="XSV-Lk-dj4" firstAttribute="top" secondItem="Nxn-Fc-EGe" secondAttribute="bottom" constant="8" id="aBF-3y-LX5"/> - <constraint firstItem="Nxn-Fc-EGe" firstAttribute="top" secondItem="V3j-Lb-fSQ" secondAttribute="top" id="nCa-l7-I8c"/> - </constraints> - </view> - </subviews> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstItem="7ux-Tb-Fzq" firstAttribute="centerX" secondItem="pID-oa-Rrg" secondAttribute="centerX" id="0pe-6n-wrA"/> - <constraint firstItem="V3j-Lb-fSQ" firstAttribute="top" secondItem="pID-oa-Rrg" secondAttribute="bottom" constant="30" id="2Sy-bS-AZZ"/> - <constraint firstItem="V3j-Lb-fSQ" firstAttribute="centerY" secondItem="0ZY-Kh-JiM" secondAttribute="centerY" constant="-20" id="3Uk-YZ-4C3"/> - <constraint firstItem="7ux-Tb-Fzq" firstAttribute="centerY" secondItem="pID-oa-Rrg" secondAttribute="centerY" id="BRH-Bd-Pe8"/> - <constraint firstAttribute="trailing" secondItem="V3j-Lb-fSQ" secondAttribute="trailing" id="EHy-Cx-cGj"/> - <constraint firstItem="pID-oa-Rrg" firstAttribute="centerX" secondItem="0ZY-Kh-JiM" secondAttribute="centerX" id="Ojm-D5-HnO"/> - <constraint firstItem="V3j-Lb-fSQ" firstAttribute="leading" secondItem="0ZY-Kh-JiM" secondAttribute="leading" id="alr-G1-L4w"/> - </constraints> - </view> - <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ire-2z-eJu" userLabel="Footer"> - <rect key="frame" x="0.0" y="556.5" width="375" height="110.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"/> - <fontDescription key="fontDescription" type="system" pointSize="17"/> - <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" 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="42"/> - <constraints> - <constraint firstAttribute="height" constant="42" placeholder="YES" id="NNo-Ki-ThF"/> - </constraints> - <state key="normal" title="Create account" backgroundImage="DefaultButton"> - <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - </state> - <connections> - <action selector="createNewAccount" destination="BYZ-38-t0r" eventType="touchUpInside" id="d7p-Uy-6Wc"/> - </connections> - </button> - </subviews> - <color key="backgroundColor" name="Secondary"/> - <constraints> - <constraint firstAttribute="trailingMargin" secondItem="osm-vd-aTb" secondAttribute="trailing" id="MCf-FB-2AL"/> - <constraint firstAttribute="bottomMargin" secondItem="osm-vd-aTb" secondAttribute="bottom" id="g0d-lW-N4P"/> - <constraint firstItem="QcG-Tf-YdQ" firstAttribute="leading" secondItem="Ire-2z-eJu" secondAttribute="leadingMargin" id="hLO-0a-7p0"/> - <constraint firstItem="QcG-Tf-YdQ" firstAttribute="top" secondItem="Ire-2z-eJu" secondAttribute="topMargin" id="pOc-kU-kNJ"/> - <constraint firstAttribute="trailingMargin" secondItem="QcG-Tf-YdQ" secondAttribute="trailing" id="rEw-4o-orE"/> - <constraint firstItem="osm-vd-aTb" firstAttribute="leading" secondItem="Ire-2z-eJu" secondAttribute="leadingMargin" id="sLm-Ug-jLY"/> - <constraint firstItem="osm-vd-aTb" firstAttribute="top" secondItem="QcG-Tf-YdQ" secondAttribute="bottom" constant="8" id="yAE-m3-6y0"/> - </constraints> - <edgeInsets key="layoutMargins" top="16" left="0.0" bottom="24" right="0.0"/> - </view> - </subviews> - <color key="backgroundColor" name="Primary"/> - <constraints> - <constraint firstAttribute="bottom" secondItem="0ZY-Kh-JiM" secondAttribute="bottom" id="09L-EV-qfI"/> - <constraint firstItem="0ZY-Kh-JiM" firstAttribute="leading" secondItem="xpu-Q8-m8b" secondAttribute="leading" id="5T5-Un-Bbw"/> - <constraint firstItem="Ire-2z-eJu" firstAttribute="leading" secondItem="xpu-Q8-m8b" secondAttribute="leading" id="8MY-2T-1p9"/> - <constraint firstItem="0ZY-Kh-JiM" firstAttribute="top" secondItem="RSb-dJ-fKl" secondAttribute="top" id="XTe-ZF-Txi"/> - <constraint firstAttribute="trailing" secondItem="0ZY-Kh-JiM" secondAttribute="trailing" id="ZCl-FF-h79"/> - <constraint firstAttribute="bottom" secondItem="Ire-2z-eJu" secondAttribute="bottom" id="okj-M8-3PQ"/> - <constraint firstAttribute="trailing" secondItem="Ire-2z-eJu" secondAttribute="trailing" id="uZQ-0R-5JT"/> - </constraints> - <edgeInsets key="layoutMargins" top="0.0" left="24" bottom="0.0" right="24"/> - <viewLayoutGuide key="safeArea" id="RSb-dJ-fKl"/> - </view> - <connections> - <outlet property="accountInputGroup" destination="VmT-ya-ufe" id="ku3-qa-yfV"/> - <outlet property="accountTextField" destination="XOB-ct-yLU" id="mXd-SV-E16"/> - <outlet property="activityIndicator" destination="pID-oa-Rrg" id="GG2-Hv-FWl"/> - <outlet property="createAccountButton" destination="osm-vd-aTb" id="2Gr-84-Sg5"/> - <outlet property="keyboardToolbar" destination="waX-JF-VTG" id="kav-5t-mkA"/> - <outlet property="keyboardToolbarLoginButton" destination="0VH-wf-oEs" id="fsM-6o-9nL"/> - <outlet property="loginForm" destination="V3j-Lb-fSQ" id="tYu-S8-ylm"/> - <outlet property="loginFormWrapperBottomConstraint" destination="09L-EV-qfI" id="fYF-OK-trh"/> - <outlet property="messageLabel" destination="XSV-Lk-dj4" id="8bd-TU-yhD"/> - <outlet property="statusImageView" destination="7ux-Tb-Fzq" id="UhU-kS-PKR"/> - <outlet property="titleLabel" destination="Nxn-Fc-EGe" id="lOm-uS-4Ff"/> - <segue destination="Ki6-Mt-b6R" kind="custom" identifier="ShowConnect" customClass="RootContainerPushSegue" customModule="MullvadVPN" customModuleProvider="target" id="ccw-Nc-l0Q"/> - </connections> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> - <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="waX-JF-VTG"> - <rect key="frame" x="0.0" y="0.0" width="375" height="44"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> - <items> - <barButtonItem style="plain" systemItem="cancel" id="hYv-Qq-TND"> - <connections> - <action selector="cancelLogin" destination="BYZ-38-t0r" id="5UA-Vf-AE0"/> - </connections> - </barButtonItem> - <barButtonItem style="plain" systemItem="flexibleSpace" id="Llz-4U-rOT"/> - <barButtonItem title="Log in" style="done" id="0VH-wf-oEs"> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="LoginBarButtonItem"/> - </userDefinedRuntimeAttributes> - <connections> - <action selector="doLogin" destination="BYZ-38-t0r" id="8Mv-Di-I6Y"/> - </connections> - </barButtonItem> - </items> - </toolbar> - </objects> - <point key="canvasLocation" x="669.60000000000002" y="27.436281859070466"/> - </scene> - <!--Connect View Controller--> - <scene sceneID="Fnf-X9-B7i"> - <objects> - <viewController storyboardIdentifier="Main" id="Ki6-Mt-b6R" customClass="ConnectViewController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController"> - <view key="view" contentMode="scaleToFill" id="PNd-mm-N1B"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <subviews> - <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="3rI-k6-N1S"> - <rect key="frame" x="24" y="307" width="327" height="212"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SECURE CONNECTION" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HNy-mU-nui"> - <rect key="frame" x="0.0" y="0.0" width="327" height="24"/> - <accessibility key="accessibilityConfiguration" identifier="SecureConnectionLabel"/> - <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/> - <color key="textColor" name="Success"/> - <nil key="highlightedColor"/> - </label> - <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="PBy-k6-ijS"> - <rect key="frame" x="0.0" y="32" width="327" height="82"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stockholm" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mfr-Ic-PYf"> - <rect key="frame" x="0.0" y="0.0" width="327" height="41"/> - <fontDescription key="fontDescription" type="boldSystem" pointSize="34"/> - <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" text="Sweden" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Yf-sl-l3q"> - <rect key="frame" x="0.0" y="41" width="327" height="41"/> - <fontDescription key="fontDescription" type="boldSystem" pointSize="34"/> - <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - </subviews> - </stackView> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hCl-ph-fhs"> - <rect key="frame" x="0.0" y="122" width="327" height="90"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ocV-9f-WDZ" customClass="ConnectionPanelView" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="0.0" y="0.0" width="327" height="90"/> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstAttribute="height" constant="90" placeholder="YES" id="z9Q-OD-1co"/> - </constraints> - </view> - </subviews> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstItem="ocV-9f-WDZ" firstAttribute="top" secondItem="hCl-ph-fhs" secondAttribute="top" id="S3C-dT-RKK"/> - <constraint firstItem="ocV-9f-WDZ" firstAttribute="leading" secondItem="hCl-ph-fhs" secondAttribute="leading" id="e8V-PF-ISy"/> - <constraint firstAttribute="bottom" secondItem="ocV-9f-WDZ" secondAttribute="bottom" id="ehS-MG-cf7"/> - <constraint firstAttribute="trailing" secondItem="ocV-9f-WDZ" secondAttribute="trailing" id="jIg-r7-5mz"/> - </constraints> - </view> - </subviews> - </stackView> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kbg-vd-uS0"> - <rect key="frame" x="24" y="543" width="327" height="100"/> - <subviews> - <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="oZQ-uX-qg5"> - <rect key="frame" x="0.0" y="0.0" width="327" height="100"/> - <constraints> - <constraint firstAttribute="height" constant="100" placeholder="YES" id="xyU-Ve-38D"/> - </constraints> - </stackView> - </subviews> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstItem="oZQ-uX-qg5" firstAttribute="leading" secondItem="kbg-vd-uS0" secondAttribute="leading" id="CVK-s8-K47"/> - <constraint firstAttribute="trailing" secondItem="oZQ-uX-qg5" secondAttribute="trailing" id="IEd-jf-HBD"/> - <constraint firstAttribute="bottom" secondItem="oZQ-uX-qg5" secondAttribute="bottom" id="pAj-Dl-cfL"/> - <constraint firstItem="oZQ-uX-qg5" firstAttribute="top" secondItem="kbg-vd-uS0" secondAttribute="top" id="qfE-M4-Vqw"/> - </constraints> - </view> - </subviews> - <color key="backgroundColor" name="Primary"/> - <constraints> - <constraint firstItem="3rI-k6-N1S" firstAttribute="leading" secondItem="PNd-mm-N1B" secondAttribute="leadingMargin" id="5fs-z1-QKf"/> - <constraint firstAttribute="trailingMargin" secondItem="3rI-k6-N1S" secondAttribute="trailing" id="NFr-rI-7r3"/> - <constraint firstItem="iBo-pG-OTz" firstAttribute="bottom" secondItem="kbg-vd-uS0" secondAttribute="bottom" constant="24" id="Und-F7-4LQ"/> - <constraint firstItem="kbg-vd-uS0" firstAttribute="leading" secondItem="iBo-pG-OTz" secondAttribute="leading" constant="24" id="WON-cN-WSC"/> - <constraint firstItem="kbg-vd-uS0" firstAttribute="top" secondItem="3rI-k6-N1S" secondAttribute="bottom" constant="24" id="Yrd-dM-tsp"/> - <constraint firstItem="iBo-pG-OTz" firstAttribute="trailing" secondItem="kbg-vd-uS0" secondAttribute="trailing" constant="24" id="cbX-QT-hOe"/> - </constraints> - <edgeInsets key="layoutMargins" top="0.0" left="24" bottom="24" right="24"/> - <viewLayoutGuide key="safeArea" id="iBo-pG-OTz"/> - </view> - <connections> - <outlet property="buttonsStackView" destination="oZQ-uX-qg5" id="dvm-AG-6HG"/> - <outlet property="cityLabel" destination="mfr-Ic-PYf" id="vut-Me-cdj"/> - <outlet property="connectionPanel" destination="ocV-9f-WDZ" id="Uad-bl-KFU"/> - <outlet property="countryLabel" destination="9Yf-sl-l3q" id="L3N-Jn-zlr"/> - <outlet property="secureLabel" destination="HNy-mU-nui" id="QBg-mR-Z6g"/> - </connections> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="gkg-dm-hcG" userLabel="First Responder" sceneMemberID="firstResponder"/> - </objects> - <point key="canvasLocation" x="1688.8" y="26.53673163418291"/> - </scene> - <!--Settings--> - <scene sceneID="3oF-uu-3Bk"> - <objects> - <tableViewController id="SHd-a4-ewi" customClass="SettingsViewController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController"> - <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="6Gz-UM-orK"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <color key="backgroundColor" name="Secondary"/> - <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <color key="separatorColor" name="Secondary"/> - <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"/> - <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"/> - <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"/> - <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"/> - <fontDescription key="fontDescription" type="system" weight="medium" pointSize="13"/> - <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - </subviews> - <constraints> - <constraint firstItem="Lve-Kd-qTr" firstAttribute="bottom" secondItem="sTl-gI-g2a" secondAttribute="bottomMargin" id="2nF-fr-JAQ"/> - <constraint firstItem="Lve-Kd-qTr" firstAttribute="top" secondItem="sTl-gI-g2a" secondAttribute="topMargin" id="2se-fh-l9F"/> - <constraint firstItem="QeD-EQ-Ruo" firstAttribute="top" secondItem="sTl-gI-g2a" secondAttribute="topMargin" id="6Cf-jR-RQ2"/> - <constraint firstItem="QeD-EQ-Ruo" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Lve-Kd-qTr" secondAttribute="trailing" id="Axr-Q2-gFq"/> - <constraint firstAttribute="bottomMargin" secondItem="QeD-EQ-Ruo" secondAttribute="bottom" id="VES-Yv-Ull"/> - <constraint firstItem="QeD-EQ-Ruo" firstAttribute="trailing" secondItem="sTl-gI-g2a" secondAttribute="trailingMargin" id="bMl-dk-MoO"/> - <constraint firstItem="Lve-Kd-qTr" firstAttribute="leading" secondItem="sTl-gI-g2a" secondAttribute="leadingMargin" id="yrm-Np-m0P"/> - </constraints> - </tableViewCellContentView> - <color key="backgroundColor" name="Primary"/> - <accessibility key="accessibilityConfiguration" identifier="AccountCell"/> - <connections> - <outlet property="expiryLabel" destination="QeD-EQ-Ruo" id="sr0-cQ-JV1"/> - <outlet property="titleLabel" destination="Lve-Kd-qTr" id="psd-kM-u1u"/> - <segue destination="ruh-Q2-P39" kind="show" identifier="ShowAccount" id="Oei-D9-z6L"/> - </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"/> - <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"/> - <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"/> - <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"/> - <fontDescription key="fontDescription" type="system" weight="medium" pointSize="13"/> - <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - </subviews> - <constraints> - <constraint firstItem="pYC-Zb-8N9" firstAttribute="top" secondItem="lYp-Z8-1sN" secondAttribute="topMargin" id="6Ih-SA-8o0"/> - <constraint firstAttribute="bottomMargin" secondItem="sOr-vj-cg7" secondAttribute="bottom" id="8Gv-HC-Rxo"/> - <constraint firstItem="sOr-vj-cg7" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="pYC-Zb-8N9" secondAttribute="trailing" constant="8" symbolic="YES" id="IYX-rX-a2Q"/> - <constraint firstAttribute="trailingMargin" secondItem="sOr-vj-cg7" secondAttribute="trailing" id="Is4-dU-mbu"/> - <constraint firstAttribute="bottomMargin" secondItem="pYC-Zb-8N9" secondAttribute="bottom" id="NpP-d6-M0T"/> - <constraint firstItem="pYC-Zb-8N9" firstAttribute="leading" secondItem="lYp-Z8-1sN" secondAttribute="leadingMargin" id="Ove-uA-2Fw"/> - <constraint firstItem="sOr-vj-cg7" firstAttribute="top" secondItem="lYp-Z8-1sN" secondAttribute="topMargin" id="qeA-c2-OxT"/> - </constraints> - </tableViewCellContentView> - <color key="backgroundColor" name="Primary"/> - <connections> - <outlet property="versionLabel" destination="sOr-vj-cg7" id="xgH-No-26f"/> - </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"/> - <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"/> - <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"/> - <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - </subviews> - <constraints> - <constraint firstItem="Amw-A3-ePS" firstAttribute="leading" secondItem="Drq-vk-8F2" secondAttribute="leadingMargin" id="4Ug-US-l8D"/> - <constraint firstItem="Amw-A3-ePS" firstAttribute="top" secondItem="Drq-vk-8F2" secondAttribute="topMargin" id="6ID-BF-Jsp"/> - <constraint firstAttribute="bottomMargin" secondItem="Amw-A3-ePS" secondAttribute="bottom" id="JPQ-S7-zHO"/> - <constraint firstAttribute="trailingMargin" secondItem="Amw-A3-ePS" secondAttribute="trailing" id="lhc-g5-1mb"/> - </constraints> - </tableViewCellContentView> - <color key="backgroundColor" name="Primary"/> - <connections> - <outlet property="titleLabel" destination="Amw-A3-ePS" id="cGS-cX-LXr"/> - </connections> - </tableViewCell> - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Basic" id="kzz-4X-xg1" customClass="SettingsBasicCell" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="0.0" y="186" width="375" height="43.5"/> - <autoresizingMask key="autoresizingMask"/> - <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="kzz-4X-xg1" id="KpJ-UC-PyV"> - <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/> - <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="PWF-Y6-mDf"> - <rect key="frame" x="16" y="11" width="343" height="21.5"/> - <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - </subviews> - <constraints> - <constraint firstItem="PWF-Y6-mDf" firstAttribute="top" secondItem="KpJ-UC-PyV" secondAttribute="topMargin" id="7c8-Np-uyI"/> - <constraint firstAttribute="trailingMargin" secondItem="PWF-Y6-mDf" secondAttribute="trailing" id="G6s-Z9-acp"/> - <constraint firstAttribute="bottomMargin" secondItem="PWF-Y6-mDf" secondAttribute="bottom" id="ICb-f1-Zux"/> - <constraint firstItem="PWF-Y6-mDf" firstAttribute="leading" secondItem="KpJ-UC-PyV" secondAttribute="leadingMargin" id="teH-t2-aJn"/> - </constraints> - </tableViewCellContentView> - <color key="backgroundColor" name="Primary"/> - <connections> - <outlet property="titleLabel" destination="PWF-Y6-mDf" id="G5i-Wm-WZN"/> - </connections> - </tableViewCell> - </prototypes> - <sections/> - <connections> - <outlet property="dataSource" destination="9xf-6a-8vR" id="DSW-6u-Rhl"/> - <outlet property="delegate" destination="9xf-6a-8vR" id="HBx-xF-dDg"/> - </connections> - </tableView> - <navigationItem key="navigationItem" title="Settings" id="Xxl-r7-Sbm"> - <barButtonItem key="rightBarButtonItem" style="done" systemItem="done" id="AnV-sJ-aya"> - <connections> - <action selector="handleDismiss" destination="SHd-a4-ewi" id="eE7-bB-mer"/> - </connections> - </barButtonItem> - </navigationItem> - <connections> - <outlet property="staticDataSource" destination="9xf-6a-8vR" id="E8j-Z4-Ljk"/> - <segue destination="vAK-MJ-h3c" kind="show" identifier="ShowWireguardKeys" id="eDY-gl-kvu"/> - </connections> - </tableViewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="sR5-ix-4x7" userLabel="First Responder" sceneMemberID="firstResponder"/> - <customObject id="9xf-6a-8vR" customClass="SettingsTableViewDataSource" customModule="MullvadVPN" customModuleProvider="target"> - <connections> - <outlet property="tableView" destination="6Gz-UM-orK" id="Ipk-3P-ycO"/> - </connections> - </customObject> - </objects> - <point key="canvasLocation" x="1690" y="-832"/> - </scene> - <!--WireGuard key--> - <scene sceneID="fcg-jd-GmS"> - <objects> - <viewController id="vAK-MJ-h3c" customClass="WireguardKeysViewController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController"> - <view key="view" contentMode="scaleToFill" id="NHk-FR-Mwy"> - <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="fa2-zl-Fc4"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5VO-oQ-4jM" userLabel="Container"> - <rect key="frame" x="0.0" y="0.0" width="375" height="295.5"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Lx5-tV-hNL" userLabel="Content"> - <rect key="frame" x="24" y="24" width="327" height="247.5"/> - <subviews> - <view contentMode="scaleToFill" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="xch-VD-kOQ" userLabel="Account number"> - <rect key="frame" x="0.0" y="0.0" width="327" height="46"/> - <subviews> - <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="CtE-XF-2uJ"> - <rect key="frame" x="0.0" y="0.0" width="327" height="46"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="29J-lm-A4D"> - <rect key="frame" x="0.0" y="0.0" width="327" height="17"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="751" text="Public key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="riQ-cz-0de"> - <rect key="frame" x="0.0" y="0.0" width="66" height="17"/> - <fontDescription key="fontDescription" type="system" pointSize="14"/> - <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Z76-2G-dkn" customClass="EmbeddedViewContainerView" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="185" y="0.0" width="142" height="17"/> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstAttribute="width" constant="142" placeholder="YES" id="v4m-dU-J71"/> - </constraints> - <connections> - <outlet property="embeddedView" destination="1Ue-pb-GCu" id="uUI-08-4yA"/> - </connections> - </view> - </subviews> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstAttribute="bottom" secondItem="Z76-2G-dkn" secondAttribute="bottom" id="I4r-uc-kgH"/> - <constraint firstItem="riQ-cz-0de" firstAttribute="leading" secondItem="29J-lm-A4D" secondAttribute="leading" id="TZy-KN-DUR"/> - <constraint firstAttribute="trailing" secondItem="Z76-2G-dkn" secondAttribute="trailing" id="cto-xJ-P12"/> - <constraint firstItem="Z76-2G-dkn" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="riQ-cz-0de" secondAttribute="trailing" constant="8" id="kUO-SM-ut1"/> - <constraint firstItem="riQ-cz-0de" firstAttribute="top" secondItem="29J-lm-A4D" secondAttribute="top" id="pef-9R-fZa"/> - <constraint firstAttribute="bottom" secondItem="riQ-cz-0de" secondAttribute="bottom" id="sTe-ay-g1z"/> - <constraint firstItem="Z76-2G-dkn" firstAttribute="top" secondItem="29J-lm-A4D" secondAttribute="top" id="w1K-nl-2QW"/> - </constraints> - </view> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="F0p-ra-1bv"> - <rect key="frame" x="0.0" y="25" width="327" height="21"/> - <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/> - <inset key="contentEdgeInsets" minX="0.01" minY="0.0" maxX="1" maxY="0.0"/> - <state key="normal" title="123456789"> - <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - </state> - <connections> - <action selector="copyPublicKey:" destination="vAK-MJ-h3c" eventType="touchUpInside" id="xqz-Xp-I45"/> - </connections> - </button> - </subviews> - </stackView> - </subviews> - <constraints> - <constraint firstItem="CtE-XF-2uJ" firstAttribute="top" secondItem="xch-VD-kOQ" secondAttribute="top" id="9pN-dP-gTH"/> - <constraint firstAttribute="trailing" secondItem="CtE-XF-2uJ" secondAttribute="trailing" id="Kjq-dh-nxS"/> - <constraint firstAttribute="bottom" secondItem="CtE-XF-2uJ" secondAttribute="bottom" id="coJ-q9-t0B"/> - <constraint firstItem="CtE-XF-2uJ" firstAttribute="leading" secondItem="xch-VD-kOQ" secondAttribute="leading" id="wHk-cr-fV2"/> - </constraints> - </view> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Bjs-D6-NVj" userLabel="Expiry"> - <rect key="frame" x="0.0" y="70" width="327" height="45.5"/> - <subviews> - <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="8f3-SD-t3K"> - <rect key="frame" x="0.0" y="0.0" width="327" height="45.5"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Key generated" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FMt-bt-4gy"> - <rect key="frame" x="0.0" y="0.0" width="327" height="17"/> - <fontDescription key="fontDescription" type="system" pointSize="14"/> - <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="6 days ago" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CvU-pV-ixr"> - <rect key="frame" x="0.0" y="25" width="327" height="20.5"/> - <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/> - <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - </subviews> - </stackView> - </subviews> - <constraints> - <constraint firstAttribute="bottom" secondItem="8f3-SD-t3K" secondAttribute="bottom" id="Lou-NI-gF9"/> - <constraint firstAttribute="trailing" secondItem="8f3-SD-t3K" secondAttribute="trailing" id="Xok-g3-2S0"/> - <constraint firstItem="8f3-SD-t3K" firstAttribute="top" secondItem="Bjs-D6-NVj" secondAttribute="top" id="asr-RD-H6w"/> - <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="ydQ-IP-KZb" userLabel="Buttons"> - <rect key="frame" x="0.0" y="139.5" 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="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="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="DefaultButton"/> - <connections> - <action selector="handleVerifyKey:" destination="vAK-MJ-h3c" eventType="touchUpInside" id="wGf-5k-Zw2"/> - </connections> - </button> - </subviews> - </stackView> - </subviews> - <constraints> - <constraint firstAttribute="bottom" secondItem="zF0-5W-t7M" secondAttribute="bottom" id="Hb8-OT-rIo"/> - <constraint firstAttribute="trailing" secondItem="zF0-5W-t7M" secondAttribute="trailing" id="bO9-9j-LGw"/> - <constraint firstItem="zF0-5W-t7M" firstAttribute="leading" secondItem="ydQ-IP-KZb" secondAttribute="leading" id="d8z-bR-Gjl"/> - <constraint firstItem="zF0-5W-t7M" firstAttribute="top" secondItem="ydQ-IP-KZb" secondAttribute="top" id="ylb-xz-fnV"/> - </constraints> - </view> - </subviews> - <constraints> - <constraint firstItem="ydQ-IP-KZb" firstAttribute="top" secondItem="Bjs-D6-NVj" secondAttribute="bottom" constant="24" id="37w-fI-zi8"/> - <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"/> - <constraint firstAttribute="trailing" secondItem="ydQ-IP-KZb" secondAttribute="trailing" id="OwJ-Xb-q8O"/> - <constraint firstItem="ydQ-IP-KZb" firstAttribute="leading" secondItem="Lx5-tV-hNL" secondAttribute="leading" id="P69-3O-u0S"/> - <constraint firstItem="Bjs-D6-NVj" firstAttribute="leading" secondItem="Lx5-tV-hNL" secondAttribute="leading" id="Qj6-44-14Q"/> - <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"/> - </constraints> - </view> - </subviews> - <constraints> - <constraint firstAttribute="bottom" secondItem="Lx5-tV-hNL" secondAttribute="bottom" constant="24" id="1sW-Lm-fPs"/> - <constraint firstItem="Lx5-tV-hNL" firstAttribute="top" secondItem="5VO-oQ-4jM" secondAttribute="top" constant="24" id="6F1-G5-kJW"/> - <constraint firstAttribute="trailing" secondItem="Lx5-tV-hNL" secondAttribute="trailing" constant="24" id="YZH-zj-zvM"/> - <constraint firstItem="Lx5-tV-hNL" firstAttribute="leading" secondItem="5VO-oQ-4jM" secondAttribute="leading" constant="24" id="rHz-2D-i6n"/> - </constraints> - </view> - </subviews> - <constraints> - <constraint firstItem="5VO-oQ-4jM" firstAttribute="width" secondItem="fa2-zl-Fc4" secondAttribute="width" id="86a-VC-VLn"/> - <constraint firstAttribute="bottom" secondItem="5VO-oQ-4jM" secondAttribute="bottom" id="ERb-9i-nFf"/> - <constraint firstItem="5VO-oQ-4jM" firstAttribute="leading" secondItem="fa2-zl-Fc4" secondAttribute="leading" id="KdL-EB-Idq"/> - <constraint firstItem="5VO-oQ-4jM" firstAttribute="top" secondItem="fa2-zl-Fc4" secondAttribute="top" id="avu-mu-m90"/> - <constraint firstAttribute="trailing" secondItem="5VO-oQ-4jM" secondAttribute="trailing" id="sUD-Wq-7oa"/> - </constraints> - </scrollView> - </subviews> - <color key="backgroundColor" name="Secondary"/> - <constraints> - <constraint firstItem="fa2-zl-Fc4" firstAttribute="top" secondItem="NHk-FR-Mwy" secondAttribute="top" id="0XS-W3-vV4"/> - <constraint firstItem="fa2-zl-Fc4" firstAttribute="bottom" secondItem="uHO-zG-HAA" secondAttribute="bottom" id="3Uo-OT-Y0q"/> - <constraint firstItem="fa2-zl-Fc4" firstAttribute="leading" secondItem="uHO-zG-HAA" secondAttribute="leading" id="4rW-4C-pRs"/> - <constraint firstItem="fa2-zl-Fc4" firstAttribute="trailing" secondItem="uHO-zG-HAA" secondAttribute="trailing" id="VuC-Wb-6U4"/> - </constraints> - <viewLayoutGuide key="safeArea" id="uHO-zG-HAA"/> - </view> - <navigationItem key="navigationItem" title="WireGuard key" id="6ve-v7-tYQ"/> - <connections> - <outlet property="creationDateLabel" destination="CvU-pV-ixr" id="qSg-Be-sO0"/> - <outlet property="publicKeyButton" destination="F0p-ra-1bv" id="pZV-nS-lIs"/> - <outlet property="regenerateKeyButton" destination="OCa-Jz-b7W" id="BZD-Qc-8lO"/> - <outlet property="verifyKeyButton" destination="qEF-8w-MdR" id="zuU-Ts-QNG"/> - <outlet property="wireguardKeyStatusView" destination="1Ue-pb-GCu" id="VV8-bG-SgD"/> - </connections> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="WDa-g6-tXg" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/> - <view contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="1Ue-pb-GCu" customClass="WireguardKeyStatusView" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="0.0" y="0.0" width="240" height="16"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="751" text="Key is valid" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ocb-Gs-xuo"> - <rect key="frame" x="0.0" y="0.0" width="240" height="16"/> - <fontDescription key="fontDescription" type="system" pointSize="14"/> - <color key="textColor" name="Success"/> - <nil key="highlightedColor"/> - </label> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ZN9-r7-vKB" customClass="SpinnerActivityIndicatorView" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="224" y="0.0" width="16" height="16"/> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstAttribute="width" secondItem="ZN9-r7-vKB" secondAttribute="height" multiplier="1:1" id="7dm-3X-rB1"/> - </constraints> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="thickness"> - <real key="value" value="2"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </view> - </subviews> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstItem="ZN9-r7-vKB" firstAttribute="height" secondItem="Ocb-Gs-xuo" secondAttribute="height" id="0GM-ky-aMe"/> - <constraint firstAttribute="trailing" secondItem="Ocb-Gs-xuo" secondAttribute="trailing" id="C6Q-Ie-omp"/> - <constraint firstItem="Ocb-Gs-xuo" firstAttribute="leading" secondItem="1Ue-pb-GCu" secondAttribute="leading" id="M7j-bw-5Ye"/> - <constraint firstAttribute="trailing" secondItem="ZN9-r7-vKB" secondAttribute="trailing" id="YRs-9L-5CY"/> - <constraint firstItem="ZN9-r7-vKB" firstAttribute="centerY" secondItem="Ocb-Gs-xuo" secondAttribute="centerY" id="d43-KC-IK5"/> - <constraint firstAttribute="bottom" secondItem="Ocb-Gs-xuo" secondAttribute="bottom" id="ivo-8C-Rj8"/> - <constraint firstItem="Ocb-Gs-xuo" firstAttribute="top" secondItem="1Ue-pb-GCu" secondAttribute="top" id="kgV-z9-gxp"/> - </constraints> - <connections> - <outlet property="activityIndicator" destination="ZN9-r7-vKB" id="lj5-xB-7Ra"/> - <outlet property="textLabel" destination="Ocb-Gs-xuo" id="LoV-ls-1BU"/> - </connections> - </view> - </objects> - <point key="canvasLocation" x="2576.8000000000002" y="-513.19340329835086"/> - </scene> - <!--Account--> - <scene sceneID="Ca0-W1-eLb"> - <objects> - <viewController id="ruh-Q2-P39" customClass="AccountViewController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController"> - <view key="view" contentMode="scaleToFill" id="Qpl-bL-ZGl"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <subviews> - <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="saE-dV-AgF"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rkG-Xa-pEO" userLabel="Container"> - <rect key="frame" x="0.0" y="0.0" width="375" height="349.5"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nkx-Eb-7le" userLabel="Content"> - <rect key="frame" x="24" y="24" width="327" height="301.5"/> - <subviews> - <view contentMode="scaleToFill" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="HzF-8Z-UBs" userLabel="Account number"> - <rect key="frame" x="0.0" y="0.0" width="327" height="46"/> - <subviews> - <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="5ux-jY-AC5"> - <rect key="frame" x="0.0" y="0.0" width="327" height="46"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Account number" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0L8-AT-A51"> - <rect key="frame" x="0.0" y="0.0" width="327" height="17"/> - <fontDescription key="fontDescription" type="system" pointSize="14"/> - <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XNH-JJ-9gR"> - <rect key="frame" x="0.0" y="25" width="327" height="21"/> - <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/> - <inset key="contentEdgeInsets" minX="0.01" minY="0.0" maxX="1" maxY="0.0"/> - <state key="normal" title="123456789"> - <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - </state> - <connections> - <action selector="copyAccountToken" destination="ruh-Q2-P39" eventType="touchUpInside" id="jox-eA-A3D"/> - </connections> - </button> - </subviews> - </stackView> - </subviews> - <constraints> - <constraint firstAttribute="trailing" secondItem="5ux-jY-AC5" secondAttribute="trailing" id="PJ0-He-QSB"/> - <constraint firstAttribute="bottom" secondItem="5ux-jY-AC5" secondAttribute="bottom" id="Uxx-Cj-ONf"/> - <constraint firstItem="5ux-jY-AC5" firstAttribute="top" secondItem="HzF-8Z-UBs" secondAttribute="top" id="gnz-tE-Rri"/> - <constraint firstItem="5ux-jY-AC5" firstAttribute="leading" secondItem="HzF-8Z-UBs" secondAttribute="leading" id="n4M-ed-uC3"/> - </constraints> - </view> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="459-0n-9V2" userLabel="Expiry"> - <rect key="frame" x="0.0" y="70" width="327" height="45.5"/> - <subviews> - <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="NMg-f0-BTW"> - <rect key="frame" x="0.0" y="0.0" width="327" height="45.5"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fyk-lv-ggt"> - <rect key="frame" x="0.0" y="0.0" width="327" height="17"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="751" text="Paid until" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nrG-9Q-lWI"> - <rect key="frame" x="0.0" y="0.0" width="59.5" height="17"/> - <fontDescription key="fontDescription" type="system" pointSize="14"/> - <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="20K-WW-5v6" customClass="SpinnerActivityIndicatorView" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="311" y="0.5" width="16" height="16"/> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstAttribute="width" constant="16" id="Hym-zs-PN7"/> - <constraint firstAttribute="height" constant="16" id="uys-o5-CZJ"/> - </constraints> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="thickness"> - <real key="value" value="2"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </view> - </subviews> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <constraints> - <constraint firstItem="20K-WW-5v6" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="nrG-9Q-lWI" secondAttribute="trailing" constant="8" symbolic="YES" id="3uR-Ln-ICn"/> - <constraint firstItem="nrG-9Q-lWI" firstAttribute="top" secondItem="fyk-lv-ggt" secondAttribute="top" id="a1L-QD-n7C"/> - <constraint firstAttribute="bottom" secondItem="nrG-9Q-lWI" secondAttribute="bottom" id="cbS-5z-9b7"/> - <constraint firstItem="nrG-9Q-lWI" firstAttribute="leading" secondItem="fyk-lv-ggt" secondAttribute="leading" id="ii0-xx-bNC"/> - <constraint firstAttribute="trailing" secondItem="20K-WW-5v6" secondAttribute="trailing" id="wwh-w9-ngZ"/> - <constraint firstItem="20K-WW-5v6" firstAttribute="centerY" secondItem="fyk-lv-ggt" secondAttribute="centerY" id="z8g-E3-YGZ"/> - </constraints> - </view> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="May 16, 2019" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8Vg-dd-ZpW"> - <rect key="frame" x="0.0" y="25" width="327" height="20.5"/> - <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/> - <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <nil key="highlightedColor"/> - </label> - </subviews> - </stackView> - </subviews> - <constraints> - <constraint firstItem="NMg-f0-BTW" firstAttribute="top" secondItem="459-0n-9V2" secondAttribute="top" id="JQm-gX-yM4"/> - <constraint firstAttribute="trailing" secondItem="NMg-f0-BTW" secondAttribute="trailing" id="VtX-r0-IfB"/> - <constraint firstAttribute="bottom" secondItem="NMg-f0-BTW" secondAttribute="bottom" id="XJw-2J-qBl"/> - <constraint firstItem="NMg-f0-BTW" firstAttribute="leading" secondItem="459-0n-9V2" secondAttribute="leading" id="vqI-Vt-8V6"/> - </constraints> - </view> - <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="J7Z-sf-Cjx"> - <rect key="frame" x="0.0" y="139.5" width="327" height="96"/> - <subviews> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ja8-Zt-rQX" customClass="InAppPurchaseButton" 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="h63-ia-ihB"/> - </constraints> - <state key="normal" title="Display name for in-app purchase" backgroundImage="SuccessButton"> - <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - </state> - <connections> - <action selector="doPurchase" destination="ruh-Q2-P39" eventType="touchUpInside" id="PHS-Qd-y9J"/> - </connections> - </button> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="h5f-yH-jeE" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="0.0" y="54" width="327" height="42"/> - <constraints> - <constraint firstAttribute="height" constant="42" placeholder="YES" id="Zuv-DV-LSL"/> - </constraints> - <state key="normal" title="Restore purchases" backgroundImage="DefaultButton"> - <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - </state> - <connections> - <action selector="restorePurchases" destination="ruh-Q2-P39" eventType="touchUpInside" id="ILp-fL-Ab5"/> - </connections> - </button> - </subviews> - </stackView> - <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="259.5" width="327" height="42"/> - <accessibility key="accessibilityConfiguration" identifier="LogoutButton"/> - <constraints> - <constraint firstAttribute="height" constant="42" placeholder="YES" id="VYx-GQ-CIz"/> - </constraints> - <state key="normal" title="Log out" backgroundImage="DangerButton"> - <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - </state> - <connections> - <action selector="doLogout" destination="ruh-Q2-P39" eventType="touchUpInside" id="CVm-Qx-5Et"/> - </connections> - </button> - </subviews> - <constraints> - <constraint firstItem="QHr-Lz-v6t" firstAttribute="leading" secondItem="nkx-Eb-7le" secondAttribute="leading" id="EEA-bt-bSx"/> - <constraint firstItem="459-0n-9V2" firstAttribute="leading" secondItem="nkx-Eb-7le" secondAttribute="leading" id="G86-ck-dqe"/> - <constraint firstAttribute="trailing" secondItem="459-0n-9V2" secondAttribute="trailing" id="HUb-T5-Wkk"/> - <constraint firstItem="J7Z-sf-Cjx" firstAttribute="top" secondItem="459-0n-9V2" secondAttribute="bottom" constant="24" id="LFm-ye-Fog"/> - <constraint firstItem="459-0n-9V2" firstAttribute="top" secondItem="HzF-8Z-UBs" secondAttribute="bottom" constant="24" id="Ttn-aK-Cj0"/> - <constraint firstItem="QHr-Lz-v6t" firstAttribute="top" secondItem="J7Z-sf-Cjx" secondAttribute="bottom" constant="24" id="Zfk-OU-5Ka"/> - <constraint firstItem="HzF-8Z-UBs" firstAttribute="leading" secondItem="nkx-Eb-7le" secondAttribute="leading" id="bCL-Z9-nk4"/> - <constraint firstAttribute="trailing" secondItem="QHr-Lz-v6t" secondAttribute="trailing" id="eBz-Is-dHp"/> - <constraint firstAttribute="bottom" secondItem="QHr-Lz-v6t" secondAttribute="bottom" id="fRA-bC-3eO"/> - <constraint firstItem="J7Z-sf-Cjx" firstAttribute="leading" secondItem="nkx-Eb-7le" secondAttribute="leading" id="nNI-7C-xEi"/> - <constraint firstAttribute="trailing" secondItem="HzF-8Z-UBs" secondAttribute="trailing" id="pVC-Ci-c98"/> - <constraint firstAttribute="trailing" secondItem="J7Z-sf-Cjx" secondAttribute="trailing" id="tgl-YH-hLZ"/> - <constraint firstItem="HzF-8Z-UBs" firstAttribute="top" secondItem="nkx-Eb-7le" secondAttribute="top" id="vsH-Ee-fch"/> - </constraints> - </view> - </subviews> - <constraints> - <constraint firstAttribute="bottom" secondItem="nkx-Eb-7le" secondAttribute="bottom" constant="24" id="28V-SW-noS"/> - <constraint firstAttribute="trailing" secondItem="nkx-Eb-7le" secondAttribute="trailing" constant="24" id="KQB-PO-stg"/> - <constraint firstItem="nkx-Eb-7le" firstAttribute="leading" secondItem="rkG-Xa-pEO" secondAttribute="leading" constant="24" id="L4C-cS-yzC"/> - <constraint firstItem="nkx-Eb-7le" firstAttribute="top" secondItem="rkG-Xa-pEO" secondAttribute="top" constant="24" id="eea-1e-zMf"/> - </constraints> - </view> - </subviews> - <constraints> - <constraint firstAttribute="bottom" secondItem="rkG-Xa-pEO" secondAttribute="bottom" id="B6s-Tv-NQF"/> - <constraint firstItem="rkG-Xa-pEO" firstAttribute="leading" secondItem="saE-dV-AgF" secondAttribute="leading" id="FeG-FO-jRU"/> - <constraint firstItem="rkG-Xa-pEO" firstAttribute="width" secondItem="saE-dV-AgF" secondAttribute="width" id="Vai-Jc-iRg"/> - <constraint firstItem="rkG-Xa-pEO" firstAttribute="top" secondItem="saE-dV-AgF" secondAttribute="top" id="guJ-dt-tsQ"/> - <constraint firstAttribute="trailing" secondItem="rkG-Xa-pEO" secondAttribute="trailing" id="xas-S1-tKp"/> - </constraints> - </scrollView> - </subviews> - <color key="backgroundColor" name="Secondary"/> - <constraints> - <constraint firstAttribute="bottom" secondItem="saE-dV-AgF" secondAttribute="bottom" id="Ldq-tX-ami"/> - <constraint firstAttribute="trailing" secondItem="saE-dV-AgF" secondAttribute="trailing" id="jaQ-Ns-Hja"/> - <constraint firstItem="saE-dV-AgF" firstAttribute="top" secondItem="Qpl-bL-ZGl" secondAttribute="top" id="sZ0-CC-Onn"/> - <constraint firstItem="saE-dV-AgF" firstAttribute="leading" secondItem="Qpl-bL-ZGl" secondAttribute="leading" id="xba-Jt-Ulk"/> - </constraints> - <viewLayoutGuide key="safeArea" id="jrJ-di-3DV"/> - </view> - <navigationItem key="navigationItem" title="Account" id="rL3-Y8-3g8"/> - <connections> - <outlet property="accountTokenButton" destination="XNH-JJ-9gR" id="yCU-t3-ayW"/> - <outlet property="activityIndicator" destination="20K-WW-5v6" id="DKS-1x-8oF"/> - <outlet property="expiryLabel" destination="8Vg-dd-ZpW" id="3n5-2Z-J8y"/> - <outlet property="logoutButton" destination="QHr-Lz-v6t" id="K7y-9z-xdj"/> - <outlet property="purchaseButton" destination="Ja8-Zt-rQX" id="fbk-aY-fj5"/> - <outlet property="restoreButton" destination="h5f-yH-jeE" id="jAy-mR-DEN"/> - <segue destination="P2i-eG-jQx" kind="unwind" identifier="Logout" unwindAction="unwindFromAccountWithSegue:" id="5li-wk-yRM"/> - </connections> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="3tt-67-nI8" userLabel="First Responder" sceneMemberID="firstResponder"/> - <exit id="P2i-eG-jQx" userLabel="Exit" sceneMemberID="exit"/> - </objects> - <point key="canvasLocation" x="2576.8000000000002" y="-1258.0209895052474"/> - </scene> - <!--Settings Navigation Controller--> - <scene sceneID="er3-W2-NkS"> - <objects> - <navigationController storyboardIdentifier="Settings" id="Kqv-qu-mfF" customClass="SettingsNavigationController" customModule="MullvadVPN" customModuleProvider="target" sceneMemberID="viewController"> - <navigationItem key="navigationItem" id="7IR-NQ-qLb"/> - <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" largeTitles="YES" id="7PK-0x-byW" customClass="CustomNavigationBar" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="0.0" y="0.0" width="375" height="96"/> - <autoresizingMask key="autoresizingMask"/> - <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - </navigationBar> - <connections> - <segue destination="SHd-a4-ewi" kind="relationship" relationship="rootViewController" id="5n8-Yk-l4C"/> - </connections> - </navigationController> - <placeholder placeholderIdentifier="IBFirstResponder" id="bHt-Id-Zc4" userLabel="First Responder" sceneMemberID="firstResponder"/> - </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="597"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="N9k-cQ-tlw" userLabel="Content view"> - <rect key="frame" x="0.0" y="0.0" width="375" height="558"/> - <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="LogoIcon" translatesAutoresizingMaskIntoConstraints="NO" id="WSx-4V-zIk"> - <rect key="frame" x="157.5" y="20" width="60" height="60"/> - <constraints> - <constraint firstAttribute="width" secondItem="WSx-4V-zIk" secondAttribute="height" multiplier="1:1" id="ZtE-hc-rs8"/> - <constraint firstAttribute="width" constant="60" 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" constant="20" id="3FY-d7-yKL"/> - <constraint firstItem="WSx-4V-zIk" firstAttribute="top" secondItem="Wnl-L9-JqG" secondAttribute="top" constant="20" 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="334.5"/> - <string key="text">You have a right to privacy. That’s why we never store activity logs, don't ask for personal information, and encourage anonymous payments.
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="516" width="128" 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="handlePrivacyPolicyButton:" 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="597" width="375" height="70"/> - <subviews> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ttw-7B-1MM" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target"> - <rect key="frame" x="16" y="24" width="343" height="22"/> - <accessibility key="accessibilityConfiguration" identifier="AgreeButton"/> - <state key="normal" title="Agree and continue" backgroundImage="DefaultButton"> - <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - </state> - <connections> - <action selector="handleAgreeAndContinueButton:" destination="kLI-jR-tKo" eventType="touchUpInside" id="wBI-Iz-pUM"/> - </connections> - </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="-551" y="27"/> + <point key="canvasLocation" x="670" y="-57"/> </scene> </scenes> <resources> - <image name="DangerButton" width="9" height="9"/> - <image name="DefaultButton" width="9" height="9"/> - <image name="IconExtlink" width="16" height="16"/> - <image name="IconSuccess" width="60" height="60"/> - <image name="LogoIcon" width="253" height="253"/> - <image name="SuccessButton" width="9" height="9"/> <namedColor name="Primary"> <color red="0.16078431372549021" green="0.30196078431372547" blue="0.45098039215686275" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> </namedColor> - <namedColor name="Secondary"> - <color red="0.098039215686274508" green="0.1803921568627451" blue="0.27058823529411763" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - </namedColor> - <namedColor name="Success"> - <color red="0.26666666666666666" green="0.67843137254901964" blue="0.30196078431372547" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - </namedColor> </resources> </document> diff --git a/ios/MullvadVPN/BasicTableViewCell.swift b/ios/MullvadVPN/BasicTableViewCell.swift index 68158801db..fd506d309d 100644 --- a/ios/MullvadVPN/BasicTableViewCell.swift +++ b/ios/MullvadVPN/BasicTableViewCell.swift @@ -10,8 +10,8 @@ import UIKit class BasicTableViewCell: UITableViewCell { - override func awakeFromNib() { - super.awakeFromNib() + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) let backgroundView = UIView() backgroundView.backgroundColor = UIColor.Cell.backgroundColor @@ -25,4 +25,8 @@ class BasicTableViewCell: UITableViewCell { contentView.backgroundColor = UIColor.clear } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + } diff --git a/ios/MullvadVPN/ConnectViewController.swift b/ios/MullvadVPN/ConnectViewController.swift index a3dfdb7b05..725b2472da 100644 --- a/ios/MullvadVPN/ConnectViewController.swift +++ b/ios/MullvadVPN/ConnectViewController.swift @@ -94,7 +94,7 @@ class ConnectViewController: UIViewController, RootContainment, TunnelObserver, // MARK: - SelectLocationDelegate - func selectLocationController(_ controller: SelectLocationController, didSelectLocation location: RelayLocation) { + func selectLocationViewController(_ controller: SelectLocationViewController, didSelectLocation location: RelayLocation) { controller.dismiss(animated: true) { let relayConstraints = RelayConstraints(location: .only(location)) @@ -115,7 +115,7 @@ class ConnectViewController: UIViewController, RootContainment, TunnelObserver, } } - func selectLocationControllerDidCancel(_ controller: SelectLocationController) { + func selectLocationViewControllerDidCancel(_ controller: SelectLocationViewController) { controller.dismiss(animated: true) } diff --git a/ios/MullvadVPN/ConnectViewController.xib b/ios/MullvadVPN/ConnectViewController.xib new file mode 100644 index 0000000000..2cf50c7cef --- /dev/null +++ b/ios/MullvadVPN/ConnectViewController.xib @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> + <device id="retina6_1" orientation="portrait" appearance="light"/> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <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"/> + </dependencies> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ConnectViewController" customModule="MullvadVPN" customModuleProvider="target"> + <connections> + <outlet property="buttonsStackView" destination="tVZ-jT-d0h" id="IRm-TE-iJs"/> + <outlet property="cityLabel" destination="8Qe-Us-gxU" id="qAs-MJ-Quv"/> + <outlet property="connectionPanel" destination="h6t-ky-9gm" id="hOY-G9-IVQ"/> + <outlet property="countryLabel" destination="neK-xr-40H" id="tNC-OD-PTx"/> + <outlet property="secureLabel" destination="dus-AY-JC0" id="PMW-GI-4ga"/> + <outlet property="view" destination="bFH-8p-vRl" id="jVw-4H-ccF"/> + </connections> + </placeholder> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view contentMode="scaleToFill" id="bFH-8p-vRl"> + <rect key="frame" x="0.0" y="0.0" width="414" height="896"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="SON-pD-ZGn"> + <rect key="frame" x="24" y="502" width="366" height="212"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SECURE CONNECTION" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dus-AY-JC0"> + <rect key="frame" x="0.0" y="0.0" width="366" height="24"/> + <accessibility key="accessibilityConfiguration" identifier="SecureConnectionLabel"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/> + <color key="textColor" name="Success"/> + <nil key="highlightedColor"/> + </label> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="daZ-9L-RFn"> + <rect key="frame" x="0.0" y="32" width="366" height="82"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stockholm" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8Qe-Us-gxU"> + <rect key="frame" x="0.0" y="0.0" width="366" height="41"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="34"/> + <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" text="Sweden" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="neK-xr-40H"> + <rect key="frame" x="0.0" y="41" width="366" height="41"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="34"/> + <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + </subviews> + </stackView> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mAs-zy-aF9"> + <rect key="frame" x="0.0" y="122" width="366" height="90"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="h6t-ky-9gm" customClass="ConnectionPanelView" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="0.0" y="0.0" width="366" height="90"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="height" constant="90" placeholder="YES" id="sqc-lF-rCp"/> + </constraints> + </view> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="bottom" secondItem="h6t-ky-9gm" secondAttribute="bottom" id="gde-uU-FXR"/> + <constraint firstAttribute="trailing" secondItem="h6t-ky-9gm" secondAttribute="trailing" id="hyx-Rc-2zS"/> + <constraint firstItem="h6t-ky-9gm" firstAttribute="leading" secondItem="mAs-zy-aF9" secondAttribute="leading" id="ivP-qV-nIn"/> + <constraint firstItem="h6t-ky-9gm" firstAttribute="top" secondItem="mAs-zy-aF9" secondAttribute="top" id="zG4-Um-x5m"/> + </constraints> + </view> + </subviews> + </stackView> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="82Y-rR-Igf"> + <rect key="frame" x="24" y="738" width="366" height="100"/> + <subviews> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="tVZ-jT-d0h"> + <rect key="frame" x="0.0" y="0.0" width="366" height="100"/> + <constraints> + <constraint firstAttribute="height" constant="100" placeholder="YES" id="VS7-pq-Idz"/> + </constraints> + </stackView> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstItem="tVZ-jT-d0h" firstAttribute="top" secondItem="82Y-rR-Igf" secondAttribute="top" id="1YE-mx-7t7"/> + <constraint firstItem="tVZ-jT-d0h" firstAttribute="leading" secondItem="82Y-rR-Igf" secondAttribute="leading" id="Dab-DT-04W"/> + <constraint firstAttribute="bottom" secondItem="tVZ-jT-d0h" secondAttribute="bottom" id="Sjj-UF-9Xr"/> + <constraint firstAttribute="trailing" secondItem="tVZ-jT-d0h" secondAttribute="trailing" id="cOe-Ju-VcI"/> + </constraints> + </view> + </subviews> + <color key="backgroundColor" name="Primary"/> + <constraints> + <constraint firstItem="Rzj-xL-crv" firstAttribute="bottom" secondItem="82Y-rR-Igf" secondAttribute="bottom" constant="24" id="D4A-Ij-Eip"/> + <constraint firstItem="Rzj-xL-crv" firstAttribute="trailing" secondItem="82Y-rR-Igf" secondAttribute="trailing" constant="24" id="DPX-JT-0Bx"/> + <constraint firstItem="SON-pD-ZGn" firstAttribute="leading" secondItem="bFH-8p-vRl" secondAttribute="leadingMargin" id="LSL-Go-oXb"/> + <constraint firstItem="82Y-rR-Igf" firstAttribute="leading" secondItem="Rzj-xL-crv" secondAttribute="leading" constant="24" id="UWY-XY-Njv"/> + <constraint firstAttribute="trailingMargin" secondItem="SON-pD-ZGn" secondAttribute="trailing" id="Vhs-Sr-QUI"/> + <constraint firstItem="82Y-rR-Igf" firstAttribute="top" secondItem="SON-pD-ZGn" secondAttribute="bottom" constant="24" id="WhU-py-uqj"/> + </constraints> + <edgeInsets key="layoutMargins" top="0.0" left="24" bottom="24" right="24"/> + <viewLayoutGuide key="safeArea" id="Rzj-xL-crv"/> + <point key="canvasLocation" x="139" y="153"/> + </view> + </objects> + <resources> + <namedColor name="Primary"> + <color red="0.16078431372549021" green="0.30196078431372547" blue="0.45098039215686275" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> + <namedColor name="Success"> + <color red="0.26666666666666666" green="0.67843137254901964" blue="0.30196078431372547" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> + </resources> +</document> diff --git a/ios/MullvadVPN/ConsentViewController.xib b/ios/MullvadVPN/ConsentViewController.xib new file mode 100644 index 0000000000..331483b9ae --- /dev/null +++ b/ios/MullvadVPN/ConsentViewController.xib @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> + <device id="retina6_1" orientation="portrait" appearance="light"/> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <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"/> + </dependencies> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ConsentViewController" customModule="MullvadVPN" customModuleProvider="target"> + <connections> + <outlet property="view" destination="okw-Tg-2ad" id="WQ8-79-AH6"/> + </connections> + </placeholder> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view contentMode="scaleToFill" id="okw-Tg-2ad"> + <rect key="frame" x="0.0" y="0.0" width="414" height="896"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fbX-Lo-tij"> + <rect key="frame" x="0.0" y="0.0" width="414" height="793"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="11q-bQ-xwY" userLabel="Content view"> + <rect key="frame" x="0.0" y="0.0" width="414" height="558"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5Ub-SU-zLG" userLabel="Logo header"> + <rect key="frame" x="0.0" y="0.0" width="414" height="100"/> + <subviews> + <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LogoIcon" translatesAutoresizingMaskIntoConstraints="NO" id="4vX-y0-HN4"> + <rect key="frame" x="177" y="20" width="60" height="60"/> + <constraints> + <constraint firstAttribute="width" secondItem="4vX-y0-HN4" secondAttribute="height" multiplier="1:1" id="4h0-Vu-yGp"/> + <constraint firstAttribute="width" constant="60" id="DiU-Y2-Isy"/> + </constraints> + </imageView> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstItem="4vX-y0-HN4" firstAttribute="top" secondItem="5Ub-SU-zLG" secondAttribute="top" constant="20" id="0Bk-LL-D0w"/> + <constraint firstItem="4vX-y0-HN4" firstAttribute="centerX" secondItem="5Ub-SU-zLG" secondAttribute="centerX" id="G7a-zH-1ff"/> + <constraint firstAttribute="bottom" secondItem="4vX-y0-HN4" secondAttribute="bottom" constant="20" id="iv9-ph-I49"/> + </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="64r-KN-ooC"> + <rect key="frame" x="20" y="100" width="374" 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="wh8-zG-jJA"> + <rect key="frame" x="20" y="181.5" width="374" height="334.5"/> + <string key="text">You have a right to privacy. That’s why we never store activity logs, don't ask for personal information, and encourage anonymous payments.
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="DsZ-mb-iQe" customClass="LinkButton" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="20" y="516" width="20" height="22"/> + <fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="18"/> + <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <state key="normal" title="Privacy Policy" image="IconExtlink"/> + <connections> + <action selector="handlePrivacyPolicyButton:" destination="-1" eventType="touchUpInside" id="Vid-Bc-rEi"/> + </connections> + </button> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="DsZ-mb-iQe" secondAttribute="trailing" constant="20" symbolic="YES" id="4tG-3r-ao8"/> + <constraint firstItem="wh8-zG-jJA" firstAttribute="top" secondItem="64r-KN-ooC" secondAttribute="bottom" constant="24" id="FLZ-Ye-Tpi"/> + <constraint firstItem="DsZ-mb-iQe" firstAttribute="top" secondItem="wh8-zG-jJA" secondAttribute="bottom" id="I7w-FT-B6x"/> + <constraint firstAttribute="trailing" secondItem="5Ub-SU-zLG" secondAttribute="trailing" id="Laz-Cj-wzQ"/> + <constraint firstAttribute="trailing" secondItem="64r-KN-ooC" secondAttribute="trailing" constant="20" symbolic="YES" id="NEy-kj-Xa9"/> + <constraint firstAttribute="bottom" secondItem="DsZ-mb-iQe" secondAttribute="bottom" constant="20" symbolic="YES" id="VEw-Go-ZgL"/> + <constraint firstItem="DsZ-mb-iQe" firstAttribute="leading" secondItem="11q-bQ-xwY" secondAttribute="leading" constant="20" symbolic="YES" id="WZO-4C-eJL"/> + <constraint firstItem="5Ub-SU-zLG" firstAttribute="leading" secondItem="11q-bQ-xwY" secondAttribute="leading" id="hVR-xg-zsg"/> + <constraint firstAttribute="trailing" secondItem="wh8-zG-jJA" secondAttribute="trailing" constant="20" symbolic="YES" id="mKX-Gy-ThJ"/> + <constraint firstItem="5Ub-SU-zLG" firstAttribute="top" secondItem="11q-bQ-xwY" secondAttribute="top" id="p0M-NJ-XvJ"/> + <constraint firstItem="5Ub-SU-zLG" firstAttribute="bottom" secondItem="64r-KN-ooC" secondAttribute="top" id="qr7-pk-goS"/> + <constraint firstItem="wh8-zG-jJA" firstAttribute="leading" secondItem="11q-bQ-xwY" secondAttribute="leading" constant="20" symbolic="YES" id="ugv-Jw-Z2N"/> + <constraint firstItem="64r-KN-ooC" firstAttribute="leading" secondItem="11q-bQ-xwY" secondAttribute="leading" constant="20" symbolic="YES" id="yXI-Im-8ZF"/> + </constraints> + </view> + </subviews> + <constraints> + <constraint firstAttribute="trailing" secondItem="11q-bQ-xwY" secondAttribute="trailing" id="2iy-GE-faC"/> + <constraint firstAttribute="bottom" secondItem="11q-bQ-xwY" secondAttribute="bottom" id="NJz-kz-ei6"/> + <constraint firstItem="11q-bQ-xwY" firstAttribute="width" secondItem="fbX-Lo-tij" secondAttribute="width" id="dPZ-ie-kV8"/> + <constraint firstItem="11q-bQ-xwY" firstAttribute="top" secondItem="fbX-Lo-tij" secondAttribute="top" id="po9-I5-cIU"/> + <constraint firstItem="11q-bQ-xwY" firstAttribute="leading" secondItem="fbX-Lo-tij" secondAttribute="leading" id="sin-cl-oOj"/> + </constraints> + </scrollView> + <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FYK-e4-iEm" userLabel="Footer"> + <rect key="frame" x="0.0" y="793" width="414" height="103"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7rE-vW-Iff" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="20" y="24" width="374" height="21"/> + <accessibility key="accessibilityConfiguration" identifier="AgreeButton"/> + <state key="normal" title="Agree and continue" backgroundImage="DefaultButton"> + <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </state> + <connections> + <action selector="handleAgreeAndContinueButton:" destination="-1" eventType="touchUpInside" id="GH7-Ie-FcB"/> + </connections> + </button> + </subviews> + <color key="backgroundColor" name="Secondary"/> + <constraints> + <constraint firstItem="7rE-vW-Iff" firstAttribute="trailing" secondItem="FYK-e4-iEm" secondAttribute="trailingMargin" id="1rH-JL-16T"/> + <constraint firstItem="7rE-vW-Iff" firstAttribute="leading" secondItem="FYK-e4-iEm" secondAttribute="leadingMargin" id="StR-Pw-jiq"/> + <constraint firstAttribute="bottomMargin" secondItem="7rE-vW-Iff" secondAttribute="bottom" id="r5T-I7-veu"/> + <constraint firstItem="7rE-vW-Iff" firstAttribute="top" secondItem="FYK-e4-iEm" secondAttribute="topMargin" id="zpa-Wp-alT"/> + </constraints> + <edgeInsets key="layoutMargins" top="24" left="16" bottom="24" right="16"/> + </view> + </subviews> + <color key="backgroundColor" name="Primary"/> + <constraints> + <constraint firstItem="fbX-Lo-tij" firstAttribute="leading" secondItem="okw-Tg-2ad" secondAttribute="leading" id="Dnd-7Z-TMw"/> + <constraint firstAttribute="bottom" secondItem="FYK-e4-iEm" secondAttribute="bottom" id="R7i-8R-6DV"/> + <constraint firstAttribute="trailing" secondItem="fbX-Lo-tij" secondAttribute="trailing" id="RYg-1F-lLB"/> + <constraint firstItem="FYK-e4-iEm" firstAttribute="leading" secondItem="okw-Tg-2ad" secondAttribute="leading" id="agm-y6-aMX"/> + <constraint firstItem="fbX-Lo-tij" firstAttribute="top" secondItem="okw-Tg-2ad" secondAttribute="top" id="cU9-ui-8N7"/> + <constraint firstAttribute="trailing" secondItem="FYK-e4-iEm" secondAttribute="trailing" id="dVg-eg-gFM"/> + <constraint firstItem="FYK-e4-iEm" firstAttribute="top" secondItem="fbX-Lo-tij" secondAttribute="bottom" id="dhh-eu-XGv"/> + </constraints> + <viewLayoutGuide key="safeArea" id="AcR-u0-2Ll"/> + <point key="canvasLocation" x="139" y="153"/> + </view> + </objects> + <resources> + <image name="DefaultButton" width="9" height="9"/> + <image name="IconExtlink" width="16" height="16"/> + <image name="LogoIcon" width="253" height="253"/> + <namedColor name="Primary"> + <color red="0.16078431372549021" green="0.30196078431372547" blue="0.45098039215686275" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> + <namedColor name="Secondary"> + <color red="0.098039215686274508" green="0.1803921568627451" blue="0.27058823529411763" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> + </resources> +</document> diff --git a/ios/MullvadVPN/Info.plist b/ios/MullvadVPN/Info.plist index b4fc95ec26..169f726c0f 100644 --- a/ios/MullvadVPN/Info.plist +++ b/ios/MullvadVPN/Info.plist @@ -26,8 +26,6 @@ <true/> <key>UILaunchStoryboardName</key> <string>LaunchScreen</string> - <key>UIMainStoryboardFile</key> - <string>Main</string> <key>UIRequiredDeviceCapabilities</key> <array> <string>armv7</string> diff --git a/ios/MullvadVPN/LoginViewController.swift b/ios/MullvadVPN/LoginViewController.swift index 9138e15bbb..e92186f502 100644 --- a/ios/MullvadVPN/LoginViewController.swift +++ b/ios/MullvadVPN/LoginViewController.swift @@ -22,6 +22,10 @@ enum LoginState { case success(AuthenticationMethod) } +protocol LoginViewControllerDelegate: class { + func loginViewControllerDidLogin(_ controller: LoginViewController) +} + class LoginViewController: UIViewController, RootContainment { @IBOutlet var keyboardToolbar: UIToolbar! @@ -44,6 +48,8 @@ class LoginViewController: UIViewController, RootContainment { } } + weak var delegate: LoginViewControllerDelegate? + override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } @@ -99,6 +105,14 @@ class LoginViewController: UIViewController, RootContainment { object: accountTextField) } + // MARK: - Public + + func reset() { + loginState = .default + accountTextField.autoformattingText = "" + updateKeyboardToolbar() + } + // MARK: - Keyboard notifications @objc private func keyboardWillShow(_ notification: Notification) { @@ -140,12 +154,6 @@ class LoginViewController: UIViewController, RootContainment { // MARK: - Actions - @IBAction func unwindFromAccount(segue: UIStoryboardSegue) { - loginState = .default - accountTextField.autoformattingText = "" - updateKeyboardToolbar() - } - @IBAction func cancelLogin() { view.endEditing(true) } @@ -259,8 +267,7 @@ class LoginViewController: UIViewController, RootContainment { DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { self.rootContainerController?.setEnableSettingsButton(true) - self.performSegue(withIdentifier: SegueIdentifier.Login.showConnect.rawValue, - sender: self) + self.delegate?.loginViewControllerDidLogin(self) } } } diff --git a/ios/MullvadVPN/LoginViewController.xib b/ios/MullvadVPN/LoginViewController.xib new file mode 100644 index 0000000000..44055f78f6 --- /dev/null +++ b/ios/MullvadVPN/LoginViewController.xib @@ -0,0 +1,192 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> + <device id="retina6_1" orientation="portrait" appearance="light"/> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <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"/> + </dependencies> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="LoginViewController" customModule="MullvadVPN" customModuleProvider="target"> + <connections> + <outlet property="accountInputGroup" destination="fmY-Fe-bhX" id="lRy-3H-p77"/> + <outlet property="accountTextField" destination="M05-uw-Xgl" id="d7E-mT-gts"/> + <outlet property="activityIndicator" destination="kcs-fP-UuB" id="nTJ-wH-MFm"/> + <outlet property="createAccountButton" destination="yyj-Bk-eOB" id="A6e-QQ-2Hz"/> + <outlet property="keyboardToolbar" destination="eMY-ag-aGA" id="MXd-lD-jRp"/> + <outlet property="keyboardToolbarLoginButton" destination="vJz-hf-rNV" id="IcH-iY-AI6"/> + <outlet property="loginForm" destination="h09-lb-ltN" id="4pC-oh-SiV"/> + <outlet property="loginFormWrapperBottomConstraint" destination="a30-Jy-fnc" id="LXy-zf-zOf"/> + <outlet property="messageLabel" destination="BPK-kZ-9lL" id="eKD-KS-aq8"/> + <outlet property="statusImageView" destination="L2c-40-K8a" id="6xq-lK-xjr"/> + <outlet property="titleLabel" destination="edY-81-swW" id="7HS-3s-d6L"/> + <outlet property="view" destination="mbj-X6-VW9" id="7jT-Iq-dEp"/> + </connections> + </placeholder> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view contentMode="scaleToFill" id="mbj-X6-VW9"> + <rect key="frame" x="0.0" y="0.0" width="414" height="896"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Hlu-LB-fs2" userLabel="Container"> + <rect key="frame" x="0.0" y="44" width="414" height="852"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kcs-fP-UuB" customClass="SpinnerActivityIndicatorView" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="183" y="265.5" width="48" height="48"/> + <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="width" constant="48" id="ayU-NN-NND"/> + <constraint firstAttribute="height" constant="48" id="tdi-f8-eAx"/> + </constraints> + </view> + <imageView clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IconSuccess" translatesAutoresizingMaskIntoConstraints="NO" id="L2c-40-K8a"> + <rect key="frame" x="177" y="259.5" width="60" height="60"/> + </imageView> + <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="h09-lb-ltN" userLabel="Form"> + <rect key="frame" x="0.0" y="343.5" width="414" height="125.5"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Login" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="edY-81-swW"> + <rect key="frame" x="24" y="0.0" width="366" height="39"/> + <fontDescription key="fontDescription" type="system" pointSize="32"/> + <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" text="Enter your account number" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BPK-kZ-9lL"> + <rect key="frame" x="24" y="47" width="366" height="20.5"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" white="1" alpha="0.60359589039999995" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fmY-Fe-bhX" customClass="AccountInputGroupView" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="24" y="77.5" width="366" height="48"/> + <subviews> + <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="0000 0000 0000 0000" textAlignment="natural" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="M05-uw-Xgl" userLabel="Account Text Field" customClass="AccountTextField" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="0.0" y="0.0" width="366" height="48"/> + <accessibility key="accessibilityConfiguration" identifier="LoginTextField"/> + <fontDescription key="fontDescription" type="system" pointSize="20"/> + <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="numberPad" enablesReturnKeyAutomatically="YES" smartDashesType="no" smartInsertDeleteType="no" smartQuotesType="no" textContentType="username"/> + </textField> + </subviews> + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstItem="M05-uw-Xgl" firstAttribute="top" secondItem="fmY-Fe-bhX" secondAttribute="top" id="9ld-io-34b"/> + <constraint firstAttribute="height" constant="48" placeholder="YES" id="QKg-Me-fbd"/> + <constraint firstAttribute="trailing" secondItem="M05-uw-Xgl" secondAttribute="trailing" id="XbY-CL-4DV"/> + <constraint firstAttribute="bottom" secondItem="M05-uw-Xgl" secondAttribute="bottom" id="qle-Bq-Gwu"/> + <constraint firstItem="M05-uw-Xgl" firstAttribute="leading" secondItem="fmY-Fe-bhX" secondAttribute="leading" id="ti3-Jt-gIj"/> + </constraints> + <connections> + <outlet property="textField" destination="M05-uw-Xgl" id="Stn-EF-XKw"/> + </connections> + </view> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="trailingMargin" secondItem="edY-81-swW" secondAttribute="trailing" id="1OY-3d-amx"/> + <constraint firstItem="edY-81-swW" firstAttribute="leading" secondItem="h09-lb-ltN" secondAttribute="leadingMargin" id="2EO-AX-dOa"/> + <constraint firstItem="fmY-Fe-bhX" firstAttribute="leading" secondItem="edY-81-swW" secondAttribute="leading" id="6Yg-wS-lQA"/> + <constraint firstItem="edY-81-swW" firstAttribute="top" secondItem="h09-lb-ltN" secondAttribute="top" id="L7R-pW-kDT"/> + <constraint firstItem="BPK-kZ-9lL" firstAttribute="leading" secondItem="edY-81-swW" secondAttribute="leading" id="Luz-tR-dyN"/> + <constraint firstItem="BPK-kZ-9lL" firstAttribute="top" secondItem="edY-81-swW" secondAttribute="bottom" constant="8" id="RQ5-p6-Tcp"/> + <constraint firstItem="fmY-Fe-bhX" firstAttribute="top" secondItem="BPK-kZ-9lL" secondAttribute="bottom" constant="10" id="T6H-O9-mQp"/> + <constraint firstItem="fmY-Fe-bhX" firstAttribute="trailing" secondItem="edY-81-swW" secondAttribute="trailing" id="lqk-t6-mkw"/> + <constraint firstItem="BPK-kZ-9lL" firstAttribute="trailing" secondItem="edY-81-swW" secondAttribute="trailing" id="mit-be-kUU"/> + <constraint firstAttribute="bottom" secondItem="fmY-Fe-bhX" secondAttribute="bottom" id="r57-ni-R5Y"/> + </constraints> + </view> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstItem="h09-lb-ltN" firstAttribute="leading" secondItem="Hlu-LB-fs2" secondAttribute="leading" id="6ui-Qt-KHA"/> + <constraint firstItem="L2c-40-K8a" firstAttribute="centerX" secondItem="kcs-fP-UuB" secondAttribute="centerX" id="Bn8-0h-4u1"/> + <constraint firstItem="L2c-40-K8a" firstAttribute="centerY" secondItem="kcs-fP-UuB" secondAttribute="centerY" id="EmV-jB-7A5"/> + <constraint firstItem="kcs-fP-UuB" firstAttribute="centerX" secondItem="Hlu-LB-fs2" secondAttribute="centerX" id="aHt-jx-l4c"/> + <constraint firstItem="h09-lb-ltN" firstAttribute="top" secondItem="kcs-fP-UuB" secondAttribute="bottom" constant="30" id="b9G-Ra-uTL"/> + <constraint firstItem="h09-lb-ltN" firstAttribute="centerY" secondItem="Hlu-LB-fs2" secondAttribute="centerY" constant="-20" id="d3Q-mn-gqk"/> + <constraint firstAttribute="trailing" secondItem="h09-lb-ltN" secondAttribute="trailing" id="hkn-ig-VGd"/> + </constraints> + </view> + <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OWx-up-Gr3" userLabel="Footer"> + <rect key="frame" x="0.0" y="751.5" width="414" height="144.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="Kmh-Zz-WX7"> + <rect key="frame" x="24" y="16" width="366" height="20.5"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" white="1" alpha="0.60327482880000005" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yyj-Bk-eOB" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="24" y="44.5" width="366" height="42"/> + <constraints> + <constraint firstAttribute="height" constant="42" placeholder="YES" id="aLH-Os-Yhl"/> + </constraints> + <state key="normal" title="Create account" backgroundImage="DefaultButton"> + <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </state> + <connections> + <action selector="createNewAccount" destination="-1" eventType="touchUpInside" id="Sat-eK-Sfr"/> + </connections> + </button> + </subviews> + <color key="backgroundColor" name="Secondary"/> + <constraints> + <constraint firstItem="Kmh-Zz-WX7" firstAttribute="top" secondItem="OWx-up-Gr3" secondAttribute="topMargin" id="2gd-XW-al2"/> + <constraint firstAttribute="bottomMargin" secondItem="yyj-Bk-eOB" secondAttribute="bottom" id="5sc-Gk-BLo"/> + <constraint firstItem="yyj-Bk-eOB" firstAttribute="top" secondItem="Kmh-Zz-WX7" secondAttribute="bottom" constant="8" id="6ep-aF-S3v"/> + <constraint firstAttribute="trailingMargin" secondItem="yyj-Bk-eOB" secondAttribute="trailing" id="JZr-eV-Ptz"/> + <constraint firstItem="yyj-Bk-eOB" firstAttribute="leading" secondItem="OWx-up-Gr3" secondAttribute="leadingMargin" id="aF1-ha-Rup"/> + <constraint firstItem="Kmh-Zz-WX7" firstAttribute="leading" secondItem="OWx-up-Gr3" secondAttribute="leadingMargin" id="joi-NK-b3p"/> + <constraint firstAttribute="trailingMargin" secondItem="Kmh-Zz-WX7" secondAttribute="trailing" id="pJv-fq-yMY"/> + </constraints> + <edgeInsets key="layoutMargins" top="16" left="0.0" bottom="24" right="0.0"/> + </view> + </subviews> + <color key="backgroundColor" name="Primary"/> + <constraints> + <constraint firstItem="Hlu-LB-fs2" firstAttribute="top" secondItem="nNG-OH-fpp" secondAttribute="top" id="9Wj-KC-bOY"/> + <constraint firstAttribute="bottom" secondItem="OWx-up-Gr3" secondAttribute="bottom" id="Gtb-JS-xnU"/> + <constraint firstItem="OWx-up-Gr3" firstAttribute="leading" secondItem="mbj-X6-VW9" secondAttribute="leading" id="HGZ-UR-R1R"/> + <constraint firstItem="Hlu-LB-fs2" firstAttribute="leading" secondItem="mbj-X6-VW9" secondAttribute="leading" id="Psd-xu-SF5"/> + <constraint firstAttribute="bottom" secondItem="Hlu-LB-fs2" secondAttribute="bottom" id="a30-Jy-fnc"/> + <constraint firstAttribute="trailing" secondItem="Hlu-LB-fs2" secondAttribute="trailing" id="eE0-5M-Lr5"/> + <constraint firstAttribute="trailing" secondItem="OWx-up-Gr3" secondAttribute="trailing" id="jUk-Gq-dMy"/> + </constraints> + <edgeInsets key="layoutMargins" top="0.0" left="24" bottom="0.0" right="24"/> + <viewLayoutGuide key="safeArea" id="nNG-OH-fpp"/> + <point key="canvasLocation" x="139" y="153"/> + </view> + <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="eMY-ag-aGA"> + <rect key="frame" x="0.0" y="0.0" width="375" height="44"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> + <items> + <barButtonItem style="plain" systemItem="cancel" id="JeF-aH-YXy"> + <connections> + <action selector="cancelLogin" destination="-1" id="Bil-lr-11g"/> + </connections> + </barButtonItem> + <barButtonItem style="plain" systemItem="flexibleSpace" id="VXP-Mz-kgj"/> + <barButtonItem title="Log in" style="done" id="vJz-hf-rNV"> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="LoginBarButtonItem"/> + </userDefinedRuntimeAttributes> + <connections> + <action selector="doLogin" destination="-1" id="Tif-Kp-Pkt"/> + </connections> + </barButtonItem> + </items> + <point key="canvasLocation" x="138" y="517"/> + </toolbar> + </objects> + <resources> + <image name="DefaultButton" width="9" height="9"/> + <image name="IconSuccess" width="60" height="60"/> + <namedColor name="Primary"> + <color red="0.16078431372549021" green="0.30196078431372547" blue="0.45098039215686275" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> + <namedColor name="Secondary"> + <color red="0.098039215686274508" green="0.1803921568627451" blue="0.27058823529411763" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> + </resources> +</document> diff --git a/ios/MullvadVPN/RootContainerViewController.swift b/ios/MullvadVPN/RootContainerViewController.swift index 51229183a6..9ddc903af5 100644 --- a/ios/MullvadVPN/RootContainerViewController.swift +++ b/ios/MullvadVPN/RootContainerViewController.swift @@ -36,23 +36,29 @@ protocol RootContainment { } -/// A root container class that primarily handles the unwind storyboard segues on log out +protocol RootContainerViewControllerDelegate: class { + func rootContainerViewControllerShouldShowSettings(_ controller: RootContainerViewController, navigateTo route: SettingsNavigationRoute?, animated: Bool) +} + +/// A root container view controller class RootContainerViewController: UIViewController { typealias CompletionHandler = () -> Void - private var viewControllers = [UIViewController]() - - private var topViewController: UIViewController? { - return viewControllers.last - } - private let headerBarView = HeaderBarView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) private let transitionContainer = UIView(frame: UIScreen.main.bounds) private(set) var headerBarStyle = HeaderBarStyle.default private(set) var headerBarHidden = false + private(set) var viewControllers = [UIViewController]() + + var topViewController: UIViewController? { + return viewControllers.last + } + + weak var delegate: RootContainerViewControllerDelegate? + override var childForStatusBarStyle: UIViewController? { return topViewController } @@ -151,6 +157,12 @@ class RootContainerViewController: UIViewController { setViewControllersInternal(newViewControllers, isUnwinding: false, animated: animated) } + func popToRootViewController(animated: Bool) { + if let rootController = self.viewControllers.first, self.viewControllers.count > 1 { + setViewControllersInternal([rootController], isUnwinding: true, animated: animated) + } + } + /// Request the root container to query the top controller for the new header bar style func updateHeaderBarAppearance() { updateHeaderBarStyleFromChildPreferences(animated: UIView.areAnimationsEnabled) @@ -158,18 +170,7 @@ class RootContainerViewController: UIViewController { /// Request to display settings controller func showSettings(navigateTo route: SettingsNavigationRoute? = nil, animated: Bool) { - let mainStoryboard = UIStoryboard(name: "Main", bundle: nil) - - guard let navController = mainStoryboard - .instantiateViewController(withIdentifier: ViewControllerIdentifier.settings.rawValue) - as? UINavigationController else { return } - - if let route = route { - let settingsController = navController.topViewController as? SettingsViewController - settingsController?.navigate(to: route) - } - - present(navController, animated: animated) + delegate?.rootContainerViewControllerShouldShowSettings(self, navigateTo: route, animated: animated) } /// Enable or disable the settings bar button displayed in the header bar diff --git a/ios/MullvadVPN/SegueIdentifier.swift b/ios/MullvadVPN/SegueIdentifier.swift deleted file mode 100644 index 2edf12abeb..0000000000 --- a/ios/MullvadVPN/SegueIdentifier.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// SegueIdentifier.swift -// MullvadVPN -// -// Created by pronebird on 25/03/2019. -// Copyright © 2019 Mullvad VPN AB. All rights reserved. -// - -import UIKit - -// A phantom struct holding the storyboard segue identifiers for each view controller -enum SegueIdentifier {} - -extension SegueIdentifier { - - enum Login: String, SegueConvertible { - case showConnect = "ShowConnect" - } - - enum Settings: String, SegueConvertible { - case showWireguardKeys = "ShowWireguardKeys" - case showAccount = "ShowAccount" - } - - enum Account: String, SegueConvertible { - case logout = "Logout" - } -} - -protocol SegueConvertible: RawRepresentable { - static func from(segue: UIStoryboardSegue) -> Self? -} - -extension SegueConvertible where RawValue == String { - static func from(segue: UIStoryboardSegue) -> Self? { - if let identifier = segue.identifier { - return self.init(rawValue: identifier) - } else { - return nil - } - } -} diff --git a/ios/MullvadVPN/SelectLocationCell.swift b/ios/MullvadVPN/SelectLocationCell.swift index 0b5fa63dac..d7f3c4c1ba 100644 --- a/ios/MullvadVPN/SelectLocationCell.swift +++ b/ios/MullvadVPN/SelectLocationCell.swift @@ -80,8 +80,6 @@ class SelectLocationCell: BasicTableViewCell { private func setupCell() { indentationWidth = 16 - backgroundView = UIView() - selectedBackgroundView = UIView() backgroundColor = .clear contentView.layoutMargins = preferredMargins diff --git a/ios/MullvadVPN/SelectLocationNavigationController.swift b/ios/MullvadVPN/SelectLocationNavigationController.swift index 08c3b3b7e8..be5c3098d3 100644 --- a/ios/MullvadVPN/SelectLocationNavigationController.swift +++ b/ios/MullvadVPN/SelectLocationNavigationController.swift @@ -10,12 +10,12 @@ import Foundation import UIKit protocol SelectLocationDelegate: class { - func selectLocationController(_ controller: SelectLocationController, didSelectLocation location: RelayLocation) - func selectLocationControllerDidCancel(_ controller: SelectLocationController) + func selectLocationViewController(_ controller: SelectLocationViewController, didSelectLocation location: RelayLocation) + func selectLocationViewControllerDidCancel(_ controller: SelectLocationViewController) } class SelectLocationNavigationController: UINavigationController { - private weak var contentController: SelectLocationController? + private weak var contentController: SelectLocationViewController? weak var selectLocationDelegate: SelectLocationDelegate? @@ -26,15 +26,15 @@ class SelectLocationNavigationController: UINavigationController { navigationBar.barStyle = .black navigationBar.tintColor = .white - let contentController = SelectLocationController() - contentController.navigationItem.title = NSLocalizedString("Select location", comment: "") + let contentController = SelectLocationViewController() + contentController.navigationItem.title = NSLocalizedString("Select location", comment: "Navigation title") contentController.navigationItem.largeTitleDisplayMode = .always contentController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(handleDone(_:))) contentController.didSelectLocationHandler = { [weak self] (location) in guard let self = self, let contentController = self.contentController else { return } - self.selectLocationDelegate?.selectLocationController(contentController, didSelectLocation: location) + self.selectLocationDelegate?.selectLocationViewController(contentController, didSelectLocation: location) } self.contentController = contentController @@ -57,7 +57,7 @@ class SelectLocationNavigationController: UINavigationController { @objc func handleDone(_ sender: AnyObject) { if let contentController = contentController { - selectLocationDelegate?.selectLocationControllerDidCancel(contentController) + selectLocationDelegate?.selectLocationViewControllerDidCancel(contentController) } } } diff --git a/ios/MullvadVPN/SelectLocationController.swift b/ios/MullvadVPN/SelectLocationViewController.swift index 44e8751919..47a6dab663 100644 --- a/ios/MullvadVPN/SelectLocationController.swift +++ b/ios/MullvadVPN/SelectLocationViewController.swift @@ -1,5 +1,5 @@ // -// SelectLocationController.swift +// SelectLocationViewController.swift // MullvadVPN // // Created by pronebird on 02/05/2019. @@ -12,7 +12,7 @@ import Logging private let kCellIdentifier = "Cell" -class SelectLocationController: UITableViewController, RelayCacheObserver { +class SelectLocationViewController: UITableViewController, RelayCacheObserver { private enum Error: ChainedError { case loadRelayList(RelayCacheError) diff --git a/ios/MullvadVPN/SettingsAccountCell.swift b/ios/MullvadVPN/SettingsAccountCell.swift index 7167efb709..1dbbee3198 100644 --- a/ios/MullvadVPN/SettingsAccountCell.swift +++ b/ios/MullvadVPN/SettingsAccountCell.swift @@ -10,9 +10,6 @@ import UIKit class SettingsAccountCell: SettingsCell { - @IBOutlet var titleLabel: UILabel! - @IBOutlet var expiryLabel: UILabel! - var accountExpiryDate: Date? { didSet { didUpdateAccountExpiry() @@ -24,22 +21,22 @@ class SettingsAccountCell: SettingsCell { let accountExpiry = AccountExpiry(date: accountExpiryDate) if accountExpiry.isExpired { - expiryLabel.text = NSLocalizedString("OUT OF TIME", comment: "") - expiryLabel.textColor = .dangerColor + detailTitleLabel.text = NSLocalizedString("OUT OF TIME", comment: "") + detailTitleLabel.textColor = .dangerColor } else { if let remainingTime = accountExpiry.formattedRemainingTime { let localizedString = NSLocalizedString("%@ left", comment: "") let formattedString = String(format: localizedString, remainingTime) - expiryLabel.text = formattedString.uppercased() + detailTitleLabel.text = formattedString.uppercased() } else { - expiryLabel.text = "" + detailTitleLabel.text = "" } - expiryLabel.textColor = .white + detailTitleLabel.textColor = .white } } else { - expiryLabel.text = "" - expiryLabel.textColor = .white + detailTitleLabel.text = "" + detailTitleLabel.textColor = .white } } diff --git a/ios/MullvadVPN/SettingsAppVersionCell.swift b/ios/MullvadVPN/SettingsAppVersionCell.swift deleted file mode 100644 index 8639687bd7..0000000000 --- a/ios/MullvadVPN/SettingsAppVersionCell.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// SettingsAppVersionCell.swift -// MullvadVPN -// -// Created by pronebird on 24/05/2019. -// Copyright © 2019 Mullvad VPN AB. All rights reserved. -// - -import UIKit - -class SettingsAppVersionCell: SettingsCell { - @IBOutlet var versionLabel: UILabel! -} diff --git a/ios/MullvadVPN/SettingsBasicCell.swift b/ios/MullvadVPN/SettingsBasicCell.swift deleted file mode 100644 index 8755dcdc69..0000000000 --- a/ios/MullvadVPN/SettingsBasicCell.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// SettingsBasicCell.swift -// MullvadVPN -// -// Created by pronebird on 04/12/2019. -// Copyright © 2019 Mullvad VPN AB. All rights reserved. -// - -import UIKit - -class SettingsBasicCell: SettingsCell { - @IBOutlet var titleLabel: UILabel! -} diff --git a/ios/MullvadVPN/SettingsCell.swift b/ios/MullvadVPN/SettingsCell.swift index 84967b9a1d..b8d46fe148 100644 --- a/ios/MullvadVPN/SettingsCell.swift +++ b/ios/MullvadVPN/SettingsCell.swift @@ -10,21 +10,66 @@ import UIKit class SettingsCell: BasicTableViewCell { + let titleLabel = UILabel() + let detailTitleLabel = UILabel() + private let preferredMargins = UIEdgeInsets(top: 16, left: 24, bottom: 16, right: 12) private var appDidBecomeActiveObserver: NSObjectProtocol? - override func awakeFromNib() { - super.awakeFromNib() + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + tintColor = .white backgroundView?.backgroundColor = UIColor.Cell.backgroundColor selectedBackgroundView?.backgroundColor = UIColor.Cell.selectedAltBackgroundColor contentView.layoutMargins = preferredMargins separatorInset = .zero + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.font = UIFont.systemFont(ofSize: 17) + titleLabel.textColor = .white + + detailTitleLabel.translatesAutoresizingMaskIntoConstraints = false + detailTitleLabel.font = UIFont.systemFont(ofSize: 13) + detailTitleLabel.textColor = .white + + titleLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal) + detailTitleLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) + + titleLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) + detailTitleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + + contentView.addSubview(titleLabel) + contentView.addSubview(detailTitleLabel) + + NSLayoutConstraint.activate([ + titleLabel.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + titleLabel.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor), + titleLabel.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor), + + detailTitleLabel.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: titleLabel.trailingAnchor, multiplier: 1), + + detailTitleLabel.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), + detailTitleLabel.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor), + detailTitleLabel.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor), + ]) + enableDisclosureViewTintColorFix() } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func didAddSubview(_ subview: UIView) { + super.didAddSubview(subview) + + if let button = subview as? UIButton { + updateDisclosureButtonBackgroundImageRenderingMode(button) + } + } + /// `UITableViewCell` resets the disclosure view image when the app goes in background /// This fix ensures that the image is tinted when the app becomes active again. private func enableDisclosureViewTintColorFix() { @@ -42,9 +87,13 @@ class SettingsCell: BasicTableViewCell { /// Fix this by looking for the accessory button and changing the image rendering mode private func updateDisclosureViewTintColor() { for case let button as UIButton in subviews { - if let image = button.backgroundImage(for: .normal)?.withRenderingMode(.alwaysTemplate) { - button.setBackgroundImage(image, for: .normal) - } + updateDisclosureButtonBackgroundImageRenderingMode(button) + } + } + + private func updateDisclosureButtonBackgroundImageRenderingMode(_ button: UIButton) { + if let image = button.backgroundImage(for: .normal)?.withRenderingMode(.alwaysTemplate) { + button.setBackgroundImage(image, for: .normal) } } } diff --git a/ios/MullvadVPN/SettingsNavigationController.swift b/ios/MullvadVPN/SettingsNavigationController.swift index 326c2047bd..87527b77cb 100644 --- a/ios/MullvadVPN/SettingsNavigationController.swift +++ b/ios/MullvadVPN/SettingsNavigationController.swift @@ -10,10 +10,16 @@ import Foundation import UIKit class SettingsNavigationController: UINavigationController { + override func viewDidLoad() { super.viewDidLoad() + navigationBar.barStyle = .black + navigationBar.tintColor = .white + navigationBar.prefersLargeTitles = true + // Update account expiry Account.shared.updateAccountExpiry() } + } diff --git a/ios/MullvadVPN/SettingsViewController.swift b/ios/MullvadVPN/SettingsViewController.swift index 6991202afc..201451c09e 100644 --- a/ios/MullvadVPN/SettingsViewController.swift +++ b/ios/MullvadVPN/SettingsViewController.swift @@ -11,25 +11,52 @@ import UIKit enum SettingsNavigationRoute { case account + case wireguardKeys } -class SettingsViewController: UITableViewController { +enum SettingsDismissReason { + case none + case userLoggedOut +} + +protocol SettingsViewControllerDelegate: class { + func settingsViewController(_ controller: SettingsViewController, didFinishWithReason reason: SettingsDismissReason) +} - @IBOutlet var staticDataSource: SettingsTableViewDataSource! +class SettingsViewController: UITableViewController, AccountViewControllerDelegate { private enum CellIdentifier: String { - case account = "Account" - case appVersion = "AppVersion" - case basicDisclosure = "BasicDisclosure" - case basic = "Basic" + case accountCell = "AccountCell" + case basicCell = "BasicCell" } + private let staticDataSource = SettingsTableViewDataSource() + private weak var accountRow: StaticTableViewRow? private var accountExpiryObserver: NSObjectProtocol? + weak var settingsDelegate: SettingsViewControllerDelegate? + override func viewDidLoad() { super.viewDidLoad() + tableView.backgroundColor = .secondaryColor + tableView.separatorColor = .secondaryColor + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 60 + tableView.sectionHeaderHeight = 18 + tableView.sectionFooterHeight = 18 + + tableView.dataSource = staticDataSource + tableView.delegate = staticDataSource + + tableView.register(SettingsAccountCell.self, forCellReuseIdentifier: CellIdentifier.accountCell.rawValue) + tableView.register(SettingsCell.self, forCellReuseIdentifier: CellIdentifier.basicCell.rawValue) + + navigationItem.title = NSLocalizedString("Settings", comment: "Navigation title") + navigationItem.largeTitleDisplayMode = .always + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(handleDismiss)) + accountExpiryObserver = NotificationCenter.default.addObserver( forName: Account.didUpdateAccountExpiryNotification, object: Account.shared, @@ -45,7 +72,7 @@ class SettingsViewController: UITableViewController { // MARK: - IBActions @IBAction func handleDismiss() { - dismiss(animated: true) + settingsDelegate?.settingsViewController(self, didFinishWithReason: .none) } // MARK: - Navigation @@ -53,34 +80,51 @@ class SettingsViewController: UITableViewController { func navigate(to route: SettingsNavigationRoute) { switch route { case .account: - self.performSegue( - withIdentifier: SegueIdentifier.Settings.showAccount.rawValue, - sender: nil) + let controller = AccountViewController() + controller.delegate = self + + navigationController?.pushViewController(controller, animated: true) + + case .wireguardKeys: + let controller = WireguardKeysViewController() + + navigationController?.pushViewController(controller, animated: true) } } + // MARK: - AccountViewControllerDelegate + + func accountViewControllerDidLogout(_ controller: AccountViewController) { + settingsDelegate?.settingsViewController(self, didFinishWithReason: .userLoggedOut) + } + // MARK: - Private private func setupDataSource() { if Account.shared.isLoggedIn { let topSection = StaticTableViewSection() - let accountRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.account.rawValue) { (_, cell) in + let accountRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.accountCell.rawValue) { (_, cell) in let cell = cell as! SettingsAccountCell + cell.titleLabel.text = NSLocalizedString("Account", comment: "") cell.accountExpiryDate = Account.shared.expiry + cell.accessoryType = .disclosureIndicator + } + + accountRow.actionBlock = { [weak self] (indexPath) in + self?.navigate(to: .account) } - let wireguardKeyRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.basicDisclosure.rawValue) { (_, cell) in - let cell = cell as! SettingsBasicCell + let wireguardKeyRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.basicCell.rawValue) { (_, cell) in + let cell = cell as! SettingsCell cell.titleLabel.text = NSLocalizedString("WireGuard key", comment: "") cell.accessibilityIdentifier = "WireGuardKeyCell" + cell.accessoryType = .disclosureIndicator } wireguardKeyRow.actionBlock = { [weak self] (indexPath) in - self?.performSegue( - withIdentifier: SegueIdentifier.Settings.showWireguardKeys.rawValue, - sender: nil) + self?.navigate(to: .wireguardKeys) } self.accountRow = accountRow @@ -90,11 +134,12 @@ class SettingsViewController: UITableViewController { } let middleSection = StaticTableViewSection() - let versionRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.appVersion.rawValue) { (_, cell) in - let cell = cell as! SettingsAppVersionCell + let versionRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.basicCell.rawValue) { (_, cell) in + let cell = cell as! SettingsCell let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String - cell.versionLabel.text = version + cell.titleLabel.text = NSLocalizedString("App version", comment: "") + cell.detailTitleLabel.text = version } versionRow.isSelectable = false @@ -102,8 +147,8 @@ class SettingsViewController: UITableViewController { staticDataSource.addSections([middleSection]) #if DEBUG - let logStreamerRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.basic.rawValue) { (_, cell) in - let cell = cell as! SettingsBasicCell + let logStreamerRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.basicCell.rawValue) { (_, cell) in + let cell = cell as! SettingsCell cell.titleLabel.text = NSLocalizedString("App logs", comment: "") } diff --git a/ios/MullvadVPN/ViewControllerIdentifier.swift b/ios/MullvadVPN/ViewControllerIdentifier.swift deleted file mode 100644 index d2eaad74bb..0000000000 --- a/ios/MullvadVPN/ViewControllerIdentifier.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// ViewControllerIdentifier.swift -// MullvadVPN -// -// Created by pronebird on 23/05/2019. -// Copyright © 2019 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -enum ViewControllerIdentifier: String { - case consent = "Consent" - case login = "Login" - case main = "Main" - case settings = "Settings" - case selectLocation = "SelectLocation" -} diff --git a/ios/MullvadVPN/WireguardKeysViewController.swift b/ios/MullvadVPN/WireguardKeysViewController.swift index 66cd8abf33..8c0ab1f486 100644 --- a/ios/MullvadVPN/WireguardKeysViewController.swift +++ b/ios/MullvadVPN/WireguardKeysViewController.swift @@ -46,6 +46,8 @@ class WireguardKeysViewController: UIViewController, TunnelObserver { override func viewDidLoad() { super.viewDidLoad() + navigationItem.title = NSLocalizedString("WireGuard key", comment: "Navigation title") + TunnelManager.shared.addObserver(self) updatePublicKey(publicKey: TunnelManager.shared.publicKey, animated: false) diff --git a/ios/MullvadVPN/WireguardKeysViewController.xib b/ios/MullvadVPN/WireguardKeysViewController.xib new file mode 100644 index 0000000000..46e0084a49 --- /dev/null +++ b/ios/MullvadVPN/WireguardKeysViewController.xib @@ -0,0 +1,259 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> + <device id="retina6_1" orientation="portrait" appearance="light"/> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <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"/> + </dependencies> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="WireguardKeysViewController" customModule="MullvadVPN" customModuleProvider="target"> + <connections> + <outlet property="creationDateLabel" destination="lzi-4c-l9v" id="0Z2-ew-RhM"/> + <outlet property="publicKeyButton" destination="bD5-xv-y6Z" id="C0z-zj-s1r"/> + <outlet property="regenerateKeyButton" destination="moM-8X-Qyw" id="Lk5-iu-49e"/> + <outlet property="verifyKeyButton" destination="aB5-uU-WIR" id="KXV-vp-x6x"/> + <outlet property="view" destination="0KT-g1-t9r" id="QAy-jD-drf"/> + <outlet property="wireguardKeyStatusView" destination="UWn-xd-nij" id="det-Vn-9ID"/> + </connections> + </placeholder> + <view contentMode="scaleToFill" id="0KT-g1-t9r"> + <rect key="frame" x="0.0" y="0.0" width="414" height="896"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ef2-EJ-GbD"> + <rect key="frame" x="0.0" y="0.0" width="414" height="862"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8RA-l5-l5o" userLabel="Container"> + <rect key="frame" x="0.0" y="0.0" width="414" height="295.5"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nm3-Kj-ONm" userLabel="Content"> + <rect key="frame" x="24" y="24" width="366" height="247.5"/> + <subviews> + <view contentMode="scaleToFill" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TQT-yd-nbI" userLabel="Account number"> + <rect key="frame" x="0.0" y="0.0" width="366" height="46"/> + <subviews> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="vMc-wW-ggf"> + <rect key="frame" x="0.0" y="0.0" width="366" height="46"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OrE-dl-8bW"> + <rect key="frame" x="0.0" y="0.0" width="366" height="17"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="751" text="Public key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="g23-nO-ste"> + <rect key="frame" x="0.0" y="0.0" width="66" height="17"/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UgW-XB-q8E" customClass="EmbeddedViewContainerView" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="224" y="0.0" width="142" height="17"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="width" constant="142" placeholder="YES" id="tdi-3g-eCH"/> + </constraints> + <connections> + <outlet property="embeddedView" destination="UWn-xd-nij" id="DCV-o7-ddF"/> + </connections> + </view> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstItem="UgW-XB-q8E" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="g23-nO-ste" secondAttribute="trailing" constant="8" id="L13-rB-Uy0"/> + <constraint firstAttribute="trailing" secondItem="UgW-XB-q8E" secondAttribute="trailing" id="YCs-71-hye"/> + <constraint firstItem="g23-nO-ste" firstAttribute="leading" secondItem="OrE-dl-8bW" secondAttribute="leading" id="YI1-PR-QX4"/> + <constraint firstItem="UgW-XB-q8E" firstAttribute="top" secondItem="OrE-dl-8bW" secondAttribute="top" id="aUr-hg-Omr"/> + <constraint firstAttribute="bottom" secondItem="g23-nO-ste" secondAttribute="bottom" id="cPa-1N-3xG"/> + <constraint firstAttribute="bottom" secondItem="UgW-XB-q8E" secondAttribute="bottom" id="dEW-6v-kNP"/> + <constraint firstItem="g23-nO-ste" firstAttribute="top" secondItem="OrE-dl-8bW" secondAttribute="top" id="r9d-Wb-cDT"/> + </constraints> + </view> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bD5-xv-y6Z"> + <rect key="frame" x="0.0" y="25" width="366" height="21"/> + <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/> + <inset key="contentEdgeInsets" minX="0.01" minY="0.0" maxX="1" maxY="0.0"/> + <state key="normal" title="123456789"> + <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </state> + <connections> + <action selector="copyPublicKey:" destination="-1" eventType="touchUpInside" id="lcS-i9-vnc"/> + </connections> + </button> + </subviews> + </stackView> + </subviews> + <constraints> + <constraint firstItem="vMc-wW-ggf" firstAttribute="top" secondItem="TQT-yd-nbI" secondAttribute="top" id="0h8-eE-6HJ"/> + <constraint firstAttribute="bottom" secondItem="vMc-wW-ggf" secondAttribute="bottom" id="Biu-i4-kLE"/> + <constraint firstItem="vMc-wW-ggf" firstAttribute="leading" secondItem="TQT-yd-nbI" secondAttribute="leading" id="aLi-aW-dRS"/> + <constraint firstAttribute="trailing" secondItem="vMc-wW-ggf" secondAttribute="trailing" id="j8I-aY-laA"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WE4-cD-dXV" userLabel="Expiry"> + <rect key="frame" x="0.0" y="70" width="366" height="45.5"/> + <subviews> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="qQz-cx-MJT"> + <rect key="frame" x="0.0" y="0.0" width="366" height="45.5"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Key generated" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="017-qu-nUG"> + <rect key="frame" x="0.0" y="0.0" width="366" height="17"/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="6 days ago" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lzi-4c-l9v"> + <rect key="frame" x="0.0" y="25" width="366" height="20.5"/> + <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/> + <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + </subviews> + </stackView> + </subviews> + <constraints> + <constraint firstAttribute="bottom" secondItem="qQz-cx-MJT" secondAttribute="bottom" id="7CP-kA-aNk"/> + <constraint firstItem="qQz-cx-MJT" firstAttribute="leading" secondItem="WE4-cD-dXV" secondAttribute="leading" id="Cdg-Vz-UPX"/> + <constraint firstAttribute="trailing" secondItem="qQz-cx-MJT" secondAttribute="trailing" id="aYR-XF-Fm4"/> + <constraint firstItem="qQz-cx-MJT" firstAttribute="top" secondItem="WE4-cD-dXV" secondAttribute="top" id="vC6-tk-rlS"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Rnk-UH-rRP" userLabel="Buttons"> + <rect key="frame" x="0.0" y="139.5" width="366" height="108"/> + <subviews> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="hTO-tb-TtE"> + <rect key="frame" x="0.0" y="0.0" width="366" height="108"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="moM-8X-Qyw" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="0.0" y="0.0" width="366" height="42"/> + <constraints> + <constraint firstAttribute="height" constant="42" placeholder="YES" id="hcH-5Y-7hH"/> + </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="-1" eventType="touchUpInside" id="MPC-g8-z3f"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aB5-uU-WIR" customClass="AppButton" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="0.0" y="66" width="366" height="42"/> + <constraints> + <constraint firstAttribute="height" constant="42" placeholder="YES" id="lzN-hG-dmz"/> + </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="DefaultButton"/> + <connections> + <action selector="handleVerifyKey:" destination="-1" eventType="touchUpInside" id="tkx-8o-gGK"/> + </connections> + </button> + </subviews> + </stackView> + </subviews> + <constraints> + <constraint firstAttribute="bottom" secondItem="hTO-tb-TtE" secondAttribute="bottom" id="XYT-Mh-nOc"/> + <constraint firstItem="hTO-tb-TtE" firstAttribute="top" secondItem="Rnk-UH-rRP" secondAttribute="top" id="eLy-gb-ayb"/> + <constraint firstItem="hTO-tb-TtE" firstAttribute="leading" secondItem="Rnk-UH-rRP" secondAttribute="leading" id="lBy-5I-ndg"/> + <constraint firstAttribute="trailing" secondItem="hTO-tb-TtE" secondAttribute="trailing" id="m07-nv-nWj"/> + </constraints> + </view> + </subviews> + <constraints> + <constraint firstItem="Rnk-UH-rRP" firstAttribute="top" secondItem="WE4-cD-dXV" secondAttribute="bottom" constant="24" id="2sI-jI-10o"/> + <constraint firstAttribute="trailing" secondItem="Rnk-UH-rRP" secondAttribute="trailing" id="7kY-ED-xKR"/> + <constraint firstItem="TQT-yd-nbI" firstAttribute="leading" secondItem="nm3-Kj-ONm" secondAttribute="leading" id="9ok-6a-WGz"/> + <constraint firstItem="Rnk-UH-rRP" firstAttribute="leading" secondItem="nm3-Kj-ONm" secondAttribute="leading" id="DIF-4p-U9a"/> + <constraint firstAttribute="trailing" secondItem="TQT-yd-nbI" secondAttribute="trailing" id="Msk-pE-y04"/> + <constraint firstItem="WE4-cD-dXV" firstAttribute="top" secondItem="TQT-yd-nbI" secondAttribute="bottom" constant="24" id="XYW-Zd-IB6"/> + <constraint firstAttribute="bottom" secondItem="Rnk-UH-rRP" secondAttribute="bottom" id="amK-et-wSg"/> + <constraint firstAttribute="trailing" secondItem="WE4-cD-dXV" secondAttribute="trailing" id="c5R-u5-ncH"/> + <constraint firstItem="TQT-yd-nbI" firstAttribute="top" secondItem="nm3-Kj-ONm" secondAttribute="top" id="yWj-DN-anI"/> + <constraint firstItem="WE4-cD-dXV" firstAttribute="leading" secondItem="nm3-Kj-ONm" secondAttribute="leading" id="zcQ-MS-Mkz"/> + </constraints> + </view> + </subviews> + <constraints> + <constraint firstItem="nm3-Kj-ONm" firstAttribute="leading" secondItem="8RA-l5-l5o" secondAttribute="leading" constant="24" id="6xO-Yz-LyP"/> + <constraint firstAttribute="trailing" secondItem="nm3-Kj-ONm" secondAttribute="trailing" constant="24" id="8ps-I8-JZz"/> + <constraint firstAttribute="bottom" secondItem="nm3-Kj-ONm" secondAttribute="bottom" constant="24" id="SNO-Jm-cFh"/> + <constraint firstItem="nm3-Kj-ONm" firstAttribute="top" secondItem="8RA-l5-l5o" secondAttribute="top" constant="24" id="xhA-R2-TRH"/> + </constraints> + </view> + </subviews> + <constraints> + <constraint firstItem="8RA-l5-l5o" firstAttribute="width" secondItem="Ef2-EJ-GbD" secondAttribute="width" id="2wa-Gf-kAz"/> + <constraint firstItem="8RA-l5-l5o" firstAttribute="top" secondItem="Ef2-EJ-GbD" secondAttribute="top" id="5US-02-mPv"/> + <constraint firstAttribute="trailing" secondItem="8RA-l5-l5o" secondAttribute="trailing" id="Woy-WL-LaP"/> + <constraint firstAttribute="bottom" secondItem="8RA-l5-l5o" secondAttribute="bottom" id="weK-v1-ewb"/> + <constraint firstItem="8RA-l5-l5o" firstAttribute="leading" secondItem="Ef2-EJ-GbD" secondAttribute="leading" id="xbl-T4-0ym"/> + </constraints> + </scrollView> + </subviews> + <color key="backgroundColor" name="Secondary"/> + <constraints> + <constraint firstItem="Ef2-EJ-GbD" firstAttribute="trailing" secondItem="BeY-Zt-zoO" secondAttribute="trailing" id="AVa-p6-gnL"/> + <constraint firstItem="Ef2-EJ-GbD" firstAttribute="top" secondItem="0KT-g1-t9r" secondAttribute="top" id="DUA-7u-Tpr"/> + <constraint firstItem="Ef2-EJ-GbD" firstAttribute="bottom" secondItem="BeY-Zt-zoO" secondAttribute="bottom" id="Xqi-8g-wIh"/> + <constraint firstItem="Ef2-EJ-GbD" firstAttribute="leading" secondItem="BeY-Zt-zoO" secondAttribute="leading" id="sST-q5-QMi"/> + </constraints> + <viewLayoutGuide key="safeArea" id="BeY-Zt-zoO"/> + <point key="canvasLocation" x="3274" y="-451"/> + </view> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="UWn-xd-nij" customClass="WireguardKeyStatusView" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="0.0" y="0.0" width="332" height="30"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="751" text="Key is valid" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hfe-qt-Bfg"> + <rect key="frame" x="0.0" y="0.0" width="332" height="30"/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <color key="textColor" name="Success"/> + <nil key="highlightedColor"/> + </label> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="izE-NT-b2X" customClass="SpinnerActivityIndicatorView" customModule="MullvadVPN" customModuleProvider="target"> + <rect key="frame" x="302" y="0.0" width="30" height="30"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="width" secondItem="izE-NT-b2X" secondAttribute="height" multiplier="1:1" id="Hb3-oO-ph9"/> + </constraints> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="thickness"> + <real key="value" value="2"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + </view> + </subviews> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstItem="izE-NT-b2X" firstAttribute="height" secondItem="Hfe-qt-Bfg" secondAttribute="height" id="5CX-7Y-dTK"/> + <constraint firstItem="Hfe-qt-Bfg" firstAttribute="top" secondItem="UWn-xd-nij" secondAttribute="top" id="8c7-fU-nCj"/> + <constraint firstAttribute="bottom" secondItem="Hfe-qt-Bfg" secondAttribute="bottom" id="FdG-Wt-XTb"/> + <constraint firstItem="Hfe-qt-Bfg" firstAttribute="leading" secondItem="UWn-xd-nij" secondAttribute="leading" id="Rwl-nz-b8C"/> + <constraint firstAttribute="trailing" secondItem="Hfe-qt-Bfg" secondAttribute="trailing" id="dhs-MG-8Va"/> + <constraint firstAttribute="trailing" secondItem="izE-NT-b2X" secondAttribute="trailing" id="iIb-6W-Xx6"/> + <constraint firstItem="izE-NT-b2X" firstAttribute="centerY" secondItem="Hfe-qt-Bfg" secondAttribute="centerY" id="iiN-wu-4SO"/> + </constraints> + <nil key="simulatedTopBarMetrics"/> + <nil key="simulatedBottomBarMetrics"/> + <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> + <viewLayoutGuide key="safeArea" id="4Jg-lh-k5T"/> + <connections> + <outlet property="activityIndicator" destination="izE-NT-b2X" id="BrH-U3-uZU"/> + <outlet property="textLabel" destination="Hfe-qt-Bfg" id="An4-Wb-wtv"/> + </connections> + <point key="canvasLocation" x="2561" y="-159"/> + </view> + </objects> + <resources> + <image name="DefaultButton" width="9" height="9"/> + <image name="SuccessButton" width="9" height="9"/> + <namedColor name="Secondary"> + <color red="0.098039215686274508" green="0.1803921568627451" blue="0.27058823529411763" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> + <namedColor name="Success"> + <color red="0.26666666666666666" green="0.67843137254901964" blue="0.30196078431372547" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> + </resources> +</document> |
