Skip to content
This repository has been archived by the owner on Dec 14, 2021. It is now read-only.

Commit

Permalink
Add privacy screen (#887)
Browse files Browse the repository at this point in the history
  • Loading branch information
joeyg authored and devinreams committed Mar 11, 2019
1 parent 3995f1e commit 0ac8a84
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 9 deletions.
8 changes: 8 additions & 0 deletions Lockbox.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@
D80D41BF21FD67A2008A7B11 /* BaseItemDetailStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA54E126924935F1ADF4E8E /* BaseItemDetailStore.swift */; };
D80D41C121FD6856008A7B11 /* ItemDetailStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D80D41C021FD6856008A7B11 /* ItemDetailStore.swift */; };
D80D41C321FD6D48008A7B11 /* CredentialItemDetailStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D80D41C221FD6D48008A7B11 /* CredentialItemDetailStore.swift */; };
D81526352230CDE10056EC54 /* PrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81526342230CDE10056EC54 /* PrivacyView.swift */; };
D81526372230CF180056EC54 /* PrivacyScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D81526362230CF180056EC54 /* PrivacyScreen.storyboard */; };
D81F9A4E2184ED7900B1E157 /* AdjustManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81F9A4D2184ED7900B1E157 /* AdjustManager.swift */; };
D81F9A502184F30700B1E157 /* AdjustManagerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81F9A4F2184F30700B1E157 /* AdjustManagerSpec.swift */; };
D82FF5162172DAC600018346 /* FakeProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D82FF5152172DAC600018346 /* FakeProfile.swift */; };
Expand Down Expand Up @@ -576,6 +578,8 @@
D80D41BD21F67E95008A7B11 /* SizeClassStoreSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizeClassStoreSpec.swift; sourceTree = "<group>"; };
D80D41C021FD6856008A7B11 /* ItemDetailStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDetailStore.swift; sourceTree = "<group>"; };
D80D41C221FD6D48008A7B11 /* CredentialItemDetailStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialItemDetailStore.swift; sourceTree = "<group>"; };
D81526342230CDE10056EC54 /* PrivacyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyView.swift; sourceTree = "<group>"; };
D81526362230CF180056EC54 /* PrivacyScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PrivacyScreen.storyboard; sourceTree = "<group>"; };
D81F9A4D2184ED7900B1E157 /* AdjustManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdjustManager.swift; sourceTree = "<group>"; };
D81F9A4F2184F30700B1E157 /* AdjustManagerSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdjustManagerSpec.swift; sourceTree = "<group>"; };
D82FF5152172DAC600018346 /* FakeProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeProfile.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -825,6 +829,7 @@
D8DD9303213F863700F8041D /* AutofillOnboarding.storyboard */,
D8DA03D5215B29C300656455 /* SetupAutofill.storyboard */,
D85CB82421E0295900E19118 /* LaunchScreen~ipad.storyboard */,
D81526362230CF180056EC54 /* PrivacyScreen.storyboard */,
);
path = Storyboard;
sourceTree = "<group>";
Expand Down Expand Up @@ -871,6 +876,7 @@
7DB9DEA02140CC0300239D31 /* ItemListView.swift */,
D8DA03D7215B34AA00656455 /* AutofillInstructionsView.swift */,
D85CB81B21D437AB00E19118 /* SplitView.swift */,
D81526342230CDE10056EC54 /* PrivacyView.swift */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -1423,6 +1429,7 @@
D8DD9304213F863700F8041D /* AutofillOnboarding.storyboard in Resources */,
7AA547E098053DFF64A3C0F9 /* Assets.xcassets in Resources */,
7D2D2F0B20C5A8B300339D9B /* OnboardingConfirmation.storyboard in Resources */,
D81526372230CF180056EC54 /* PrivacyScreen.storyboard in Resources */,
D5E2930A207D59050039A0AC /* FiraSans-Bold.ttf in Resources */,
7D7AD94B204EFBA4002D35EE /* StatusAlert.xib in Resources */,
7DC3899C20B600820057929D /* ItemDetail.storyboard in Resources */,
Expand Down Expand Up @@ -1654,6 +1661,7 @@
224A6C7D212C8C2B008C7A3F /* UIFont+.swift in Sources */,
D86A307620829B7F00589CA8 /* UIApplication+.swift in Sources */,
7B50F371215A52B900ADC28D /* ScrollAction.swift in Sources */,
D81526352230CDE10056EC54 /* PrivacyView.swift in Sources */,
7AA548BBE384D40397D26E9B /* RootView.swift in Sources */,
7D9722C62134622F0071D82B /* BaseWelcomePresenter.swift in Sources */,
7D1B22062033C5880098C3A3 /* ItemDetailPresenter.swift in Sources */,
Expand Down
30 changes: 28 additions & 2 deletions lockbox-ios/Presenter/RootPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ protocol RootViewProtocol: class {
func sidebarViewIs<T: UIViewController>(_ type: T.Type) -> Bool
func detailViewIs<T: UIViewController>(_ type: T.Type) -> Bool
func mainStackIs<T: UIViewController>(_ type: T.Type) -> Bool
func modalStackIs<T: UINavigationController>(_ type: T.Type) -> Bool
func modalStackIs<T: UIViewController>(_ type: T.Type) -> Bool
var modalStackPresented: Bool { get }

func startMainStack<T: UIViewController>(_ viewController: T)
func startModalStack<T: UINavigationController>(_ navigationController: T)
func startModalStack<T: UIViewController>(_ viewController: T)
func dismissModals()

func push(view: UIViewController)
Expand Down Expand Up @@ -137,6 +137,19 @@ class RootPresenter {
})
.disposed(by: self.disposeBag)

self.lifecycleStore.lifecycleFilter
.subscribe(onNext: { lifecycleAction in
switch lifecycleAction {
case .foreground:
self.hidePrivacyView()
case .background:
self.showPrivacyView()
default:
return
}
})
.disposed(by: self.disposeBag)

self.dispatcher.dispatch(action: OnboardingStatusAction(onboardingInProgress: false))
self.startTelemetry()
self.startAdjust()
Expand Down Expand Up @@ -337,6 +350,19 @@ extension RootPresenter {
self.sentryManager.setup(sendUsageData: enabled)
}).disposed(by: self.disposeBag)
}

private func hidePrivacyView() {
guard let view = self.view else { return }

if view.modalStackIs(PrivacyView.self) {
view.dismissModals()
}
}

private func showPrivacyView() {
let vc = self.viewFactory.make(storyboardName: "PrivacyScreen", identifier: "privacyview")
self.view?.startModalStack(vc)
}
}

extension RootPresenter: UISplitViewControllerDelegate {
Expand Down
50 changes: 50 additions & 0 deletions lockbox-ios/Storyboard/PrivacyScreen.storyboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--PrivacyScreen-->
<scene sceneID="6CU-Uj-tKT">
<objects>
<viewController storyboardIdentifier="privacyview" id="u26-pk-ELb" userLabel="PrivacyScreen" customClass="PrivacyView" customModule="Lockbox" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="QLr-Nd-0UP">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" image="nessie" translatesAutoresizingMaskIntoConstraints="NO" id="9rs-kq-AZt">
<rect key="frame" x="-288.5" y="0.0" width="952" height="388"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" image="lockbox-title" translatesAutoresizingMaskIntoConstraints="NO" id="XxX-uc-Qbs" userLabel="Lockbox">
<rect key="frame" x="73" y="267" width="230" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="230" id="PY6-Gi-aDY"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" red="0.0" green="0.37647058820000001" blue="0.87450980389999999" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="9rs-kq-AZt" firstAttribute="centerX" secondItem="QLr-Nd-0UP" secondAttribute="centerX" id="K6v-a9-byp"/>
<constraint firstItem="XxX-uc-Qbs" firstAttribute="centerX" secondItem="QLr-Nd-0UP" secondAttribute="centerX" id="MAF-gk-6h8"/>
<constraint firstItem="XxX-uc-Qbs" firstAttribute="top" secondItem="9rs-kq-AZt" secondAttribute="bottom" constant="73" id="iVX-bx-UoE"/>
<constraint firstItem="9rs-kq-AZt" firstAttribute="top" secondItem="QLr-Nd-0UP" secondAttribute="top" id="pAl-a4-ruj"/>
</constraints>
<viewLayoutGuide key="safeArea" id="XOp-uo-qiX"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="NJw-1a-ZvA" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="lockbox-title" width="448" height="56"/>
<image name="nessie" width="952" height="388"/>
</resources>
</document>
9 changes: 9 additions & 0 deletions lockbox-ios/View/PrivacyView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import UIKit

class PrivacyView: UIViewController {

}
6 changes: 3 additions & 3 deletions lockbox-ios/View/RootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class RootView: UIViewController, RootViewProtocol {
return currentViewController is T
}

func modalStackIs<T: UINavigationController>(_ type: T.Type) -> Bool {
func modalStackIs<T: UIViewController>(_ type: T.Type) -> Bool {
return self.currentViewController?.presentedViewController is T
}

Expand All @@ -112,8 +112,8 @@ class RootView: UIViewController, RootViewProtocol {
self.currentViewController = viewController
}

func startModalStack<T: UINavigationController>(_ navigationController: T) {
self.currentViewController?.present(navigationController, animated: !isRunningTest, completion: nil)
func startModalStack<T: UIViewController>(_ viewController: T) {
self.currentViewController?.present(viewController, animated: !isRunningTest, completion: nil)
}

func dismissModals() {
Expand Down
42 changes: 38 additions & 4 deletions lockbox-iosTests/RootPresenterSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class RootPresenterSpec: QuickSpec {
var mainStackIsArgument: UIViewController.Type?
var mainStackIsVar: Bool!

var modalStackIsArgument: UINavigationController.Type?
var modalStackIsArgument: UIViewController.Type?
var modalStackIsVar: Bool!

var startMainStackArgument: UIViewController?
Expand Down Expand Up @@ -70,7 +70,7 @@ class RootPresenterSpec: QuickSpec {
return self.mainStackIsVar
}

func modalStackIs<T: UINavigationController>(_ type: T.Type) -> Bool {
func modalStackIs<T: UIViewController>(_ type: T.Type) -> Bool {
self.modalStackIsArgument = type
return self.modalStackIsVar
}
Expand All @@ -81,8 +81,8 @@ class RootPresenterSpec: QuickSpec {
self.startMainStackArgument = viewController
}

func startModalStack<T: UINavigationController>(_ navigationController: T) {
self.startModalStackArgument = navigationController
func startModalStack<T: UIViewController>(_ viewController: T) {
self.startModalStackArgument = viewController
}

func dismissModals() {
Expand Down Expand Up @@ -233,6 +233,14 @@ class RootPresenterSpec: QuickSpec {
}
}

class FakeLifecycleStore: LifecycleStore {
var filterStub = PublishSubject<LifecycleAction>()

override var lifecycleFilter: Observable<LifecycleAction> {
return self.filterStub.asObservable()
}
}

private var view: FakeRootView!
private var dispatcher: FakeDispatcher!
private var routeStore: FakeRouteStore!
Expand All @@ -245,6 +253,7 @@ class RootPresenterSpec: QuickSpec {
private var sentryManager: FakeSentryManager!
private var adjustManager: FakeAdjustManager!
private var sizeClassStore: FakeSizeClassStore!
private var lifecycleStore: FakeLifecycleStore!
private let scheduler = TestScheduler(initialClock: 0)
var subject: RootPresenter!

Expand All @@ -265,6 +274,7 @@ class RootPresenterSpec: QuickSpec {
self.telemetryActionHandler.telemetryListener = self.scheduler.createObserver(TelemetryAction.self)
self.biometryManager.deviceAuthAvailableStub = true
self.sizeClassStore = FakeSizeClassStore()
self.lifecycleStore = FakeLifecycleStore()

self.subject = RootPresenter(
view: self.view,
Expand All @@ -274,6 +284,7 @@ class RootPresenterSpec: QuickSpec {
telemetryStore: self.telemetryStore,
accountStore: self.accountStore,
userDefaultStore: self.userDefaultStore,
lifecycleStore: self.lifecycleStore,
telemetryActionHandler: self.telemetryActionHandler,
biometryManager: self.biometryManager,
adjustManager: self.adjustManager,
Expand Down Expand Up @@ -1351,6 +1362,29 @@ class RootPresenterSpec: QuickSpec {
}
}
}

describe("life cycle actions") {
describe("enters background") {
beforeEach {
self.lifecycleStore.filterStub.onNext(LifecycleAction.background)
}

it("sets privacy screen") {
expect(self.view.startModalStackArgument is PrivacyView).to(beTrue())
}
}

describe("enters foreground") {
beforeEach {
self.view.modalStackIsVar = true
self.lifecycleStore.filterStub.onNext(LifecycleAction.foreground)
}

it("sets privacy screen") {
expect(self.view.dismissModalCalled).to(beTrue())
}
}
}
}
}
}
Expand Down

0 comments on commit 0ac8a84

Please sign in to comment.