Update unlock screen (#70)

This commit is contained in:
Katherine Bertelsen 2024-04-27 10:57:16 -05:00 committed by GitHub
parent 13bf5ad143
commit c3510e2371
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 170 additions and 26 deletions

View File

@ -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"

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "authenticator-logo.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View 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"/>

View File

@ -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)")

View File

@ -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

View File

@ -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,
]
)
}
}
}

View File

@ -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.
///

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "authenticator-logo.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}