Fix a regression where the forced logout indicator was presented on the hidden overlay window. (#2063)
This commit is contained in:
@@ -49,13 +49,6 @@ class AppLockFlowCoordinator: CoordinatorProtocol {
|
||||
// Set the initial background state.
|
||||
showPlaceholder()
|
||||
|
||||
appLockService.disabledPublisher
|
||||
.sink {
|
||||
// When the service is disabled via a force logout, we need to remove the activity indicator.
|
||||
ServiceLocator.shared.userIndicatorController.retractAllIndicators()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
notificationCenter.publisher(for: UIApplication.didEnterBackgroundNotification)
|
||||
.sink { [weak self] _ in
|
||||
self?.applicationDidEnterBackground()
|
||||
@@ -131,7 +124,6 @@ class AppLockFlowCoordinator: CoordinatorProtocol {
|
||||
case .appUnlocked:
|
||||
actionsSubject.send(.unlockApp)
|
||||
case .forceLogout:
|
||||
ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(type: .modal, title: L10n.commonSigningOut, persistent: true))
|
||||
actionsSubject.send(.forceLogout)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ struct AppLockScreenViewState: BindableState {
|
||||
|
||||
/// The number of times the user attempted to enter their PIN.
|
||||
var numberOfPINAttempts = 0
|
||||
/// An overlay indicator shown when the user is being logged out.
|
||||
var forcedLogoutIndicator: UserIndicator?
|
||||
|
||||
var bindings: AppLockScreenViewStateBindings
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ class AppLockScreenViewModel: AppLockScreenViewModelType, AppLockScreenViewModel
|
||||
state.bindings.alertInfo = .init(id: .confirmResetPIN,
|
||||
title: L10n.screenAppLockSignoutAlertTitle,
|
||||
message: L10n.screenAppLockSignoutAlertMessage,
|
||||
primaryButton: .init(title: L10n.actionOk) { self.actionsSubject.send(.forceLogout) },
|
||||
primaryButton: .init(title: L10n.actionOk) { self.forceLogout() },
|
||||
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
|
||||
}
|
||||
|
||||
@@ -90,7 +90,12 @@ class AppLockScreenViewModel: AppLockScreenViewModelType, AppLockScreenViewModel
|
||||
state.bindings.alertInfo = .init(id: .forcedLogout,
|
||||
title: L10n.screenAppLockSignoutAlertTitle,
|
||||
message: L10n.screenAppLockSignoutAlertMessage,
|
||||
primaryButton: .init(title: L10n.actionOk) { self.actionsSubject.send(.forceLogout) })
|
||||
primaryButton: .init(title: L10n.actionOk) { self.forceLogout() })
|
||||
}
|
||||
}
|
||||
|
||||
private func forceLogout() {
|
||||
state.forcedLogoutIndicator = UserIndicator(type: .modal, title: L10n.commonSigningOut, persistent: true)
|
||||
actionsSubject.send(.forceLogout)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,11 @@ struct AppLockScreen: View {
|
||||
}
|
||||
.background()
|
||||
.environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgCanvasDefault))
|
||||
.disabled(context.viewState.forcedLogoutIndicator != nil)
|
||||
.overlay {
|
||||
context.viewState.forcedLogoutIndicator.map(UserIndicatorModalView.init)
|
||||
.animation(.elementDefault, value: context.viewState.forcedLogoutIndicator)
|
||||
}
|
||||
.alert(item: $context.alertInfo)
|
||||
}
|
||||
|
||||
|
||||
@@ -56,9 +56,6 @@ class AppLockService: AppLockServiceProtocol {
|
||||
|
||||
var numberOfPINAttempts: AnyPublisher<Int, Never> { appSettings.$appLockNumberOfPINAttempts }
|
||||
|
||||
private var disabledSubject: PassthroughSubject<Void, Never> = .init()
|
||||
var disabledPublisher: AnyPublisher<Void, Never> { disabledSubject.eraseToAnyPublisher() }
|
||||
|
||||
init(keychainController: KeychainControllerProtocol, appSettings: AppSettings, context: LAContext = .init()) {
|
||||
self.keychainController = keychainController
|
||||
self.appSettings = appSettings
|
||||
@@ -108,7 +105,6 @@ class AppLockService: AppLockServiceProtocol {
|
||||
keychainController.removePINCode()
|
||||
keychainController.removePINCodeBiometricState()
|
||||
appSettings.appLockNumberOfPINAttempts = 0
|
||||
disabledSubject.send()
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground() {
|
||||
|
||||
@@ -45,9 +45,6 @@ protocol AppLockServiceProtocol: AnyObject {
|
||||
/// to re-enter their PIN code to re-enable the feature (i.e. to accept a new face or fingerprint).
|
||||
var biometricUnlockTrusted: Bool { get }
|
||||
|
||||
/// A publisher that advertises when the service has been disabled.
|
||||
var disabledPublisher: AnyPublisher<Void, Never> { get }
|
||||
|
||||
/// Sets the user's PIN code used to unlock the app.
|
||||
func setupPINCode(_ pinCode: String) -> Result<Void, AppLockServiceError>
|
||||
/// Validates the supplied PIN code is long enough, only contains digits and isn't a weak choice.
|
||||
|
||||
@@ -23,6 +23,9 @@ class AppLockUITests: XCTestCase {
|
||||
enum Step {
|
||||
static let placeholder = 0
|
||||
static let lockScreen = 1
|
||||
static let failedUnlock = 2
|
||||
static let logoutAlert = 3
|
||||
static let forcedLogout = 4
|
||||
static let unlocked = 99
|
||||
}
|
||||
|
||||
@@ -76,6 +79,33 @@ class AppLockUITests: XCTestCase {
|
||||
try await app.assertScreenshot(.appLockFlow, step: Step.unlocked)
|
||||
}
|
||||
|
||||
func testWrongPIN() async throws {
|
||||
// Given an app with screen lock enabled that is ready to unlock.
|
||||
let client = try UITestsSignalling.Client(mode: .tests)
|
||||
app = Application.launch(.appLockFlow)
|
||||
await client.waitForApp()
|
||||
|
||||
try await app.assertScreenshot(.appLockFlow, step: Step.unlocked)
|
||||
try client.send(.notification(name: UIApplication.didEnterBackgroundNotification))
|
||||
try client.send(.notification(name: UIApplication.willEnterForegroundNotification))
|
||||
try await app.assertScreenshot(.appLockFlow, step: Step.lockScreen)
|
||||
|
||||
// When entering an incorrect PIN
|
||||
enterWrongPIN()
|
||||
|
||||
// Then the app should remain locked with a warning.
|
||||
try await app.assertScreenshot(.appLockFlow, step: Step.failedUnlock)
|
||||
|
||||
// When entering it incorrectly twice more.
|
||||
enterWrongPIN()
|
||||
enterWrongPIN()
|
||||
|
||||
// Then then the app should sign the user out.
|
||||
try await app.assertScreenshot(.appLockFlow, step: Step.logoutAlert)
|
||||
app.alerts.element.buttons[A11yIdentifiers.alertInfo.primaryButton].tap()
|
||||
try await app.assertScreenshot(.appLockFlow, step: Step.forcedLogout)
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
func enterPIN() {
|
||||
@@ -84,4 +114,11 @@ class AppLockUITests: XCTestCase {
|
||||
app.buttons[A11yIdentifiers.appLockScreen.numpad(2)].tap()
|
||||
app.buttons[A11yIdentifiers.appLockScreen.numpad(3)].tap()
|
||||
}
|
||||
|
||||
func enterWrongPIN() {
|
||||
app.buttons[A11yIdentifiers.appLockScreen.numpad(0)].tap()
|
||||
app.buttons[A11yIdentifiers.appLockScreen.numpad(0)].tap()
|
||||
app.buttons[A11yIdentifiers.appLockScreen.numpad(0)].tap()
|
||||
app.buttons[A11yIdentifiers.appLockScreen.numpad(0)].tap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f4b9b5472f7c7405f57edc584676201fbcd47ad065ec76e793a9ab62686485d7
|
||||
size 101990
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8d58a22f5e6181851fb781fa3adc0b8c0cace95485cd1a0ad4c44ce0b443bc36
|
||||
size 243400
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:837433d70e1a6ce95d3ca397ebc62d6cc16ce75e40ed2500a71f4dc23bf6ea63
|
||||
size 112869
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ef32e70559dffc81857e5f45fcb6a19340dac24f053d17ac35ee9dba079bd5d8
|
||||
size 119421
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1360bca0f412008082064d36fe3e21f06050e18f7086c6ae6ec3e8b338d86e0e
|
||||
size 383427
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e9327687e1dbf64c1f1a10bfb90180fe440d2eb577955830cda186bc6fafc6ca
|
||||
size 137089
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c3520c84239be1f3ec57a402661b3470de1b411035386b80173eb27f318ead21
|
||||
size 109005
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:02fb11ea0d6ae4ca5c2c274100872aca790e1319e80f2d9c5e28491391fa5120
|
||||
size 300086
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e7dba3b14bee44e309ce7bb4df3e5b909dca683c7f3c1ed87640dfab49bdf6d0
|
||||
size 117251
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4df8f45fc81a28c27fe326162cf5a86660a28fc2a76ef8215cb9563a5e23a766
|
||||
size 127605
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:596d65ea705c802888e29e42094961cb2d3fc480a8fab8d6e8cea105fc233f1c
|
||||
size 499030
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a6b6f2d9135a6994cf1fc719c5ac8a54f7aaeaa50807e6045bf44ad40d3438a5
|
||||
size 142119
|
||||
1
changelog.d/pr-2063.bugfix
Normal file
1
changelog.d/pr-2063.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Fix a regression where the forced logout indicator was presented on the hidden overlay window.
|
||||
Reference in New Issue
Block a user