Update unlock screen (#70)
@ -5,9 +5,9 @@
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xF7",
|
||||
"green" : "0xF2",
|
||||
"red" : "0xF2"
|
||||
"blue" : "0xDC",
|
||||
"green" : "0x5D",
|
||||
"red" : "0x17"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
||||
12
Authenticator/Application/Support/Assets.xcassets/logoAuthenticator.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "authenticator-logo.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Authenticator/Application/Support/Assets.xcassets/logoAuthenticator.imageset/authenticator-logo.pdf
vendored
Normal file
@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina5_9" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
||||
<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"/>
|
||||
@ -17,13 +17,13 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logoBitwarden" translatesAutoresizingMaskIntoConstraints="NO" id="BLO-Tb-egS">
|
||||
<rect key="frame" x="46.666666666666657" y="384" width="282" height="44"/>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logoAuthenticator" translatesAutoresizingMaskIntoConstraints="NO" id="BLO-Tb-egS">
|
||||
<rect key="frame" x="46.666666666666657" y="374.66666666666669" width="282" height="63"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="tintColor" name="tintSplash"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="282" id="bDQ-uQ-eee"/>
|
||||
<constraint firstAttribute="height" constant="44" id="ssv-dM-0pp"/>
|
||||
<constraint firstAttribute="height" constant="63" id="ssv-dM-0pp"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
@ -41,9 +41,9 @@
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="logoBitwarden" width="282" height="44"/>
|
||||
<image name="logoAuthenticator" width="696" height="188"/>
|
||||
<namedColor name="backgroundSplash">
|
||||
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.090196078431372548" green="0.36470588235294116" blue="0.86274509803921573" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="tintSplash">
|
||||
<color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
@ -91,7 +91,7 @@ class VaultUnlockProcessor: StateProcessor<
|
||||
}
|
||||
|
||||
do {
|
||||
let key = try await services.biometricsRepository.getUserAuthKey()
|
||||
_ = try await services.biometricsRepository.getUserAuthKey()
|
||||
await coordinator.handleEvent(.didCompleteAuth)
|
||||
} catch let error as BiometricsServiceError {
|
||||
Logger.processor.error("BiometricsServiceError unlocking vault with biometrics: \(error)")
|
||||
|
||||
@ -10,6 +10,8 @@ struct VaultUnlockView: View {
|
||||
/// The `Store` for this view.
|
||||
@ObservedObject var store: Store<VaultUnlockState, VaultUnlockAction, VaultUnlockEffect>
|
||||
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
var body: some View {
|
||||
content
|
||||
.task {
|
||||
@ -22,11 +24,22 @@ struct VaultUnlockView: View {
|
||||
}
|
||||
|
||||
private var content: some View {
|
||||
VStack(spacing: 48) {
|
||||
Image(decorative: Asset.Images.logo)
|
||||
ZStack {
|
||||
if colorScheme == .light {
|
||||
Asset.Colors.primaryBitwarden.swiftUIColor
|
||||
} else {
|
||||
Asset.Colors.backgroundSecondary.swiftUIColor
|
||||
}
|
||||
|
||||
Image(decorative: Asset.Images.authenticatorLogo)
|
||||
.resizable()
|
||||
.frame(width: 232, height: 63)
|
||||
|
||||
biometricAuthButton
|
||||
.offset(y: 63 + 48)
|
||||
.padding(16)
|
||||
}
|
||||
.padding(16)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
|
||||
/// A button to trigger a biometric auth unlock.
|
||||
@ -37,7 +50,14 @@ struct VaultUnlockView: View {
|
||||
} label: {
|
||||
biometricUnlockText(biometryType)
|
||||
}
|
||||
.buttonStyle(.primary(shouldFillWidth: true))
|
||||
.if(colorScheme == .light) { view in
|
||||
view.buttonStyle(.secondary(shouldFillWidth: true))
|
||||
.background(Asset.Colors.backgroundPrimary.swiftUIColor)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||
}
|
||||
.if(colorScheme == .dark) { view in
|
||||
view.buttonStyle(.primary(shouldFillWidth: true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,21 +74,55 @@ struct VaultUnlockView: View {
|
||||
// MARK: - Previews
|
||||
|
||||
#if DEBUG
|
||||
#Preview("Unlock") {
|
||||
NavigationView {
|
||||
VaultUnlockView(
|
||||
store: Store(
|
||||
processor: StateProcessor(
|
||||
state: VaultUnlockState(
|
||||
biometricUnlockStatus: .available(
|
||||
.faceID,
|
||||
enabled: true,
|
||||
hasValidIntegrity: true
|
||||
struct VaultUnlockView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
VaultUnlockView(
|
||||
store: Store(
|
||||
processor: StateProcessor(
|
||||
state: VaultUnlockState(
|
||||
biometricUnlockStatus: .available(
|
||||
.faceID,
|
||||
enabled: false,
|
||||
hasValidIntegrity: false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}.previewDisplayName("No Button")
|
||||
|
||||
NavigationView {
|
||||
VaultUnlockView(
|
||||
store: Store(
|
||||
processor: StateProcessor(
|
||||
state: VaultUnlockState(
|
||||
biometricUnlockStatus: .available(
|
||||
.faceID,
|
||||
enabled: true,
|
||||
hasValidIntegrity: true
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}.previewDisplayName("Face ID Button")
|
||||
|
||||
NavigationView {
|
||||
VaultUnlockView(
|
||||
store: Store(
|
||||
processor: StateProcessor(
|
||||
state: VaultUnlockState(
|
||||
biometricUnlockStatus: .available(
|
||||
.touchID,
|
||||
enabled: true,
|
||||
hasValidIntegrity: true
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}.previewDisplayName("Touch ID Button")
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
import SnapshotTesting
|
||||
import SwiftUI
|
||||
import ViewInspector
|
||||
import XCTest
|
||||
|
||||
@testable import AuthenticatorShared
|
||||
|
||||
// MARK: - VaultUnlockViewTests
|
||||
|
||||
class VaultUnlockViewTests: AuthenticatorTestCase {
|
||||
// MARK: Properties
|
||||
|
||||
var processor: MockProcessor<VaultUnlockState, VaultUnlockAction, VaultUnlockEffect>!
|
||||
var subject: VaultUnlockView!
|
||||
|
||||
// MARK: Setup & Teardown
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
let state = VaultUnlockState()
|
||||
processor = MockProcessor(state: state)
|
||||
subject = VaultUnlockView(
|
||||
store: Store(processor: processor)
|
||||
)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
super.tearDown()
|
||||
|
||||
processor = nil
|
||||
subject = nil
|
||||
}
|
||||
|
||||
// MARK: Tests
|
||||
|
||||
/// Test a snapshot of the ItemListView previews.
|
||||
func test_snapshot_VaultUnlockView_previews() {
|
||||
for preview in VaultUnlockView_Previews._allPreviews {
|
||||
assertSnapshots(
|
||||
of: preview.content,
|
||||
as: [
|
||||
.defaultPortrait,
|
||||
.defaultPortraitDark,
|
||||
.defaultPortraitAX5,
|
||||
.defaultLandscape,
|
||||
.defaultLandscapeAX5,
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 99 KiB |
@ -84,6 +84,20 @@ extension View {
|
||||
}
|
||||
}
|
||||
|
||||
/// Conditionally applies the given transform if the given condition evaluates to `true`.
|
||||
/// - Parameters:
|
||||
/// - condition: The condition to evaluate.
|
||||
/// - transform: The transform to apply to the source `View`.
|
||||
/// - Returns: Either the original `View` or the modified `View` if the condition is `true`.
|
||||
@ViewBuilder
|
||||
func `if`<Content: View>(_ condition: @autoclosure () -> Bool, transform: (Self) -> Content) -> some View {
|
||||
if condition() {
|
||||
transform(self)
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Conditionally adds an action to perform when this view recognizes a long press
|
||||
/// gesture.
|
||||
///
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "authenticator-logo.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||