From 1ccb96207ab6401a9aede584b3a75884776b65b4 Mon Sep 17 00:00:00 2001 From: Michael Scoff Date: Sun, 4 Feb 2018 15:37:05 -0800 Subject: [PATCH] Improve protection window (#273) * Improve protection window Move splash screen into separate window and lock screen. In this case you won't see transactions screen and splash screen always works if you even have face id disabled. * Revert provision settings * Update of the unit tests. --- Trust.xcodeproj/project.pbxproj | 20 +++++++++++--- Trust/AppDelegate.swift | 5 ++++ .../LockEnterPasscodeCoordinator.swift | 6 ++--- .../Coordinators/ProtectionCoordinator.swift | 26 ++++++++++++------- .../Coordinators/SplashCoordinator.swift | 14 ++-------- .../SplashViewController.swift | 23 ++++++++++++++++ .../LockEnterPasscodeCoordinatorTest.swift | 11 +++----- .../Coordinators/SplashCoordinatorTests.swift | 3 +-- 8 files changed, 70 insertions(+), 38 deletions(-) create mode 100644 Trust/Protection/ViewControllers/SplashViewController.swift diff --git a/Trust.xcodeproj/project.pbxproj b/Trust.xcodeproj/project.pbxproj index 218ab1e46..033a6594d 100644 --- a/Trust.xcodeproj/project.pbxproj +++ b/Trust.xcodeproj/project.pbxproj @@ -312,6 +312,7 @@ 77872D292025116E0032D687 /* EnterPasswordCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77872D282025116E0032D687 /* EnterPasswordCoordinator.swift */; }; 77872D2D202514AD0032D687 /* EnterPasswordCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77872D2C202514AD0032D687 /* EnterPasswordCoordinatorTests.swift */; }; 77872D322027AA4A0032D687 /* SliderTextFieldRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77872D312027AA4A0032D687 /* SliderTextFieldRow.swift */; }; + 77872D302026DC570032D687 /* SplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77872D2F2026DC570032D687 /* SplashViewController.swift */; }; 778EAF7D1FF10AF400C8E2AB /* SettingsCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 778EAF7C1FF10AF400C8E2AB /* SettingsCoordinatorTests.swift */; }; 77B3BF352017D0D000EEC15A /* MarketplaceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77B3BF342017D0D000EEC15A /* MarketplaceViewModel.swift */; }; 77B3BF3C201908ED00EEC15A /* ConfirmCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77B3BF3B201908ED00EEC15A /* ConfirmCoordinator.swift */; }; @@ -664,6 +665,7 @@ 77872D282025116E0032D687 /* EnterPasswordCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterPasswordCoordinator.swift; sourceTree = ""; }; 77872D2C202514AD0032D687 /* EnterPasswordCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterPasswordCoordinatorTests.swift; sourceTree = ""; }; 77872D312027AA4A0032D687 /* SliderTextFieldRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderTextFieldRow.swift; sourceTree = ""; }; + 77872D2F2026DC570032D687 /* SplashViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashViewController.swift; sourceTree = ""; }; 778EAF7C1FF10AF400C8E2AB /* SettingsCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCoordinatorTests.swift; sourceTree = ""; }; 77B3BF342017D0D000EEC15A /* MarketplaceViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketplaceViewModel.swift; sourceTree = ""; }; 77B3BF3B201908ED00EEC15A /* ConfirmCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmCoordinator.swift; sourceTree = ""; }; @@ -1783,6 +1785,7 @@ 732086B2201506AA0047F605 /* Protection */ = { isa = PBXGroup; children = ( + 77872D2E2026DC4E0032D687 /* ViewControllers */, 732086B3201507220047F605 /* Coordinators */, 732086B5201507220047F605 /* Views */, ); @@ -1896,6 +1899,14 @@ path = Coordinators; sourceTree = ""; }; + 77872D2E2026DC4E0032D687 /* ViewControllers */ = { + isa = PBXGroup; + children = ( + 77872D2F2026DC570032D687 /* SplashViewController.swift */, + ); + path = ViewControllers; + sourceTree = ""; + }; 778EAF7B1FF10AE000C8E2AB /* Coordinators */ = { isa = PBXGroup; children = ( @@ -2523,6 +2534,7 @@ 29BE3FD01F7071A200F6BFC2 /* UIColor.swift in Sources */, 73ACEEFB20163C94003DD71D /* LockView.swift in Sources */, 771AA964200D5EDB00D25403 /* WordCollectionViewCell.swift in Sources */, + 77872D302026DC570032D687 /* SplashViewController.swift in Sources */, 2996F1481F6C9AE5005C33AE /* SettingsCoordinator.swift in Sources */, 29C80D4D1FB5202C0037B1E0 /* BalanceBaseViewModel.swift in Sources */, 29E14FD11F7F457D00185568 /* TransactionsStorage.swift in Sources */, @@ -2880,7 +2892,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = Trust/Trust.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 141; DEVELOPMENT_TEAM = 9873B38DWV; @@ -2890,8 +2902,8 @@ OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = com.sixdays.trust; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "09b158f8-8b12-4ed4-8489-9514fc5e69aa"; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.sixdays.trust"; + PROVISIONING_PROFILE = "7edbff9c-3e3f-4ba3-b84f-19ac095b8e95"; + PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.sixdays.trust"; TARGETED_DEVICE_FAMILY = "1,2"; VALID_ARCHS = "arm64 armv7 armv7s"; VERSIONING_SYSTEM = "apple-generic"; @@ -2913,7 +2925,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.sixdays.trust; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "36d4af79-beee-452d-a1eb-76d840b41c13"; + PROVISIONING_PROFILE = "7edbff9c-3e3f-4ba3-b84f-19ac095b8e95"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.sixdays.trust"; TARGETED_DEVICE_FAMILY = "1,2"; VALID_ARCHS = "arm64 armv7 armv7s"; diff --git a/Trust/AppDelegate.swift b/Trust/AppDelegate.swift index 27ea09e17..cd7f71c6d 100644 --- a/Trust/AppDelegate.swift +++ b/Trust/AppDelegate.swift @@ -20,6 +20,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele } catch { print("EtherKeystore init issue.") } + protectionCoordinator.didFinishLaunchingWithOptions() return true } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { @@ -32,6 +33,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele Lokalise.shared.checkForUpdates { _, _ in } protectionCoordinator.applicationDidBecomeActive() } + + func applicationDidEnterBackground(_ application: UIApplication) { + protectionCoordinator.applicationDidEnterBackground() + } func application(_ application: UIApplication, shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplicationExtensionPointIdentifier) -> Bool { if extensionPointIdentifier == UIApplicationExtensionPointIdentifier.keyboard { return false diff --git a/Trust/Lock/Coordinators/LockEnterPasscodeCoordinator.swift b/Trust/Lock/Coordinators/LockEnterPasscodeCoordinator.swift index 2503715b2..a0dcf5035 100644 --- a/Trust/Lock/Coordinators/LockEnterPasscodeCoordinator.swift +++ b/Trust/Lock/Coordinators/LockEnterPasscodeCoordinator.swift @@ -5,14 +5,14 @@ import UIKit class LockEnterPasscodeCoordinator: Coordinator { var coordinators: [Coordinator] = [] var protectionWasShown = false - private let window: UIWindow + private let window: UIWindow = UIWindow() private let model: LockEnterPasscodeViewModel private let lock: LockInterface private lazy var lockEnterPasscodeViewController: LockEnterPasscodeViewController = { return LockEnterPasscodeViewController(model: model) }() - init(window: UIWindow, model: LockEnterPasscodeViewModel, lock: LockInterface = Lock()) { - self.window = window + init(model: LockEnterPasscodeViewModel, lock: LockInterface = Lock()) { + self.window.windowLevel = UIWindowLevelStatusBar + 1.0 self.model = model self.lock = lock lockEnterPasscodeViewController.unlockWithResult = { [weak self] (state, bioUnlock) in diff --git a/Trust/Protection/Coordinators/ProtectionCoordinator.swift b/Trust/Protection/Coordinators/ProtectionCoordinator.swift index 35f7b1a7a..96582f3f3 100644 --- a/Trust/Protection/Coordinators/ProtectionCoordinator.swift +++ b/Trust/Protection/Coordinators/ProtectionCoordinator.swift @@ -8,27 +8,35 @@ class ProtectionCoordinator: Coordinator { return SplashCoordinator(window: self.protectionWindow) }() lazy var lockEnterPasscodeCoordinator: LockEnterPasscodeCoordinator = { - return LockEnterPasscodeCoordinator(window: self.protectionWindow, model: LockEnterPasscodeViewModel()) + return LockEnterPasscodeCoordinator(model: LockEnterPasscodeViewModel()) }() let protectionWindow = UIWindow() init() { - protectionWindow.windowLevel = UIWindowLevelStatusBar + 1.0 + protectionWindow.windowLevel = UIWindowLevelStatusBar + 2.0 } + + func didFinishLaunchingWithOptions() { + splashCoordinator.start() + lockEnterPasscodeCoordinator.start() + } + func applicationWillResignActive() { - //We should show spalsh screen when protection is on. And app is susepndet. - guard Lock().isPasscodeSet() else { - return - } splashCoordinator.start() } + func applicationDidBecomeActive() { - //We should dismiss spalsh screen when app become active. - splashCoordinator.stop() - //We track protectionWasShown becouse of the TouchId that will trigger applicationDidBecomeActive method after valdiation. + //We track protectionWasShown because of the Touch ID that will trigger applicationDidBecomeActive method after valdiation. if !lockEnterPasscodeCoordinator.protectionWasShown { lockEnterPasscodeCoordinator.start() } else { lockEnterPasscodeCoordinator.protectionWasShown = false } + + //We should dismiss spalsh screen when app become active. + splashCoordinator.stop() + } + + func applicationDidEnterBackground() { + splashCoordinator.start() } } diff --git a/Trust/Protection/Coordinators/SplashCoordinator.swift b/Trust/Protection/Coordinators/SplashCoordinator.swift index 5611af864..4c476093a 100644 --- a/Trust/Protection/Coordinators/SplashCoordinator.swift +++ b/Trust/Protection/Coordinators/SplashCoordinator.swift @@ -5,24 +5,14 @@ import UIKit class SplashCoordinator: Coordinator { var coordinators: [Coordinator] = [] private let window: UIWindow - private var splashView: SplashView init(window: UIWindow) { self.window = window - self.splashView = SplashView() } func start() { + window.rootViewController = SplashViewController() window.isHidden = false - window.addSubview(splashView) - window.bringSubview(toFront: splashView) - splashView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - splashView.topAnchor.constraint(equalTo: window.topAnchor), - splashView.leadingAnchor.constraint(equalTo: window.leadingAnchor), - splashView.bottomAnchor.constraint(equalTo: window.bottomAnchor), - splashView.trailingAnchor.constraint(equalTo: window.trailingAnchor), - ]) } func stop() { - splashView.removeFromSuperview() + window.isHidden = true } } diff --git a/Trust/Protection/ViewControllers/SplashViewController.swift b/Trust/Protection/ViewControllers/SplashViewController.swift new file mode 100644 index 000000000..f612b149f --- /dev/null +++ b/Trust/Protection/ViewControllers/SplashViewController.swift @@ -0,0 +1,23 @@ +// Copyright SIX DAY LLC. All rights reserved. + +import Foundation +import UIKit + +class SplashViewController: UIViewController { + private var splashView = SplashView() + init() { + super.init(nibName: nil, bundle: nil) + splashView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(splashView) + NSLayoutConstraint.activate([ + splashView.topAnchor.constraint(equalTo: view.topAnchor), + splashView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + splashView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + splashView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + ]) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/TrustTests/Coordinators/LockEnterPasscodeCoordinatorTest.swift b/TrustTests/Coordinators/LockEnterPasscodeCoordinatorTest.swift index 7a65778b5..38fe5db85 100644 --- a/TrustTests/Coordinators/LockEnterPasscodeCoordinatorTest.swift +++ b/TrustTests/Coordinators/LockEnterPasscodeCoordinatorTest.swift @@ -5,32 +5,27 @@ import XCTest class LockEnterPasscodeCoordinatorTest: XCTestCase { func testStart() { - let window = UIWindow() let viewModel = LockEnterPasscodeViewModel() let fakeLock = FakeLockProtocol() - let coordinator = LockEnterPasscodeCoordinator(window: window, model: viewModel, lock: fakeLock) + let coordinator = LockEnterPasscodeCoordinator(model: viewModel, lock: fakeLock) XCTAssertFalse(coordinator.protectionWasShown) coordinator.start() XCTAssertTrue(coordinator.protectionWasShown) - XCTAssertTrue(window.rootViewController is LockEnterPasscodeViewController) } func testStop() { - let window = UIWindow() let viewModel = LockEnterPasscodeViewModel() let fakeLock = FakeLockProtocol() - let coordinator = LockEnterPasscodeCoordinator(window: window, model: viewModel, lock: fakeLock) + let coordinator = LockEnterPasscodeCoordinator(model: viewModel, lock: fakeLock) XCTAssertFalse(coordinator.protectionWasShown) coordinator.start() XCTAssertTrue(coordinator.protectionWasShown) coordinator.stop() - XCTAssertTrue(window.isHidden) } func testDisableLock() { - let window = UIWindow() let viewModel = LockEnterPasscodeViewModel() let fakeLock = FakeLockProtocol() fakeLock.passcodeSet = false - let coordinator = LockEnterPasscodeCoordinator(window: window, model: viewModel, lock: fakeLock) + let coordinator = LockEnterPasscodeCoordinator(model: viewModel, lock: fakeLock) XCTAssertFalse(coordinator.protectionWasShown) coordinator.start() XCTAssertFalse(coordinator.protectionWasShown) diff --git a/TrustTests/Coordinators/SplashCoordinatorTests.swift b/TrustTests/Coordinators/SplashCoordinatorTests.swift index 056a93701..2f7cf7ffd 100644 --- a/TrustTests/Coordinators/SplashCoordinatorTests.swift +++ b/TrustTests/Coordinators/SplashCoordinatorTests.swift @@ -10,13 +10,12 @@ class SplashCoordinatorTests: XCTestCase { let coordinator = SplashCoordinator(window: window) coordinator.start() XCTAssertFalse(window.isHidden) - XCTAssertNotNil(window.subviews.first) } func testStop() { let window = UIWindow() let coordinator = SplashCoordinator(window: window) coordinator.start() coordinator.stop() - XCTAssertNil(window.subviews.first) + XCTAssertTrue(window.isHidden) } }