From d0bda2fe97ed1821b16edbc258dbf1ceeb669a7b Mon Sep 17 00:00:00 2001 From: David Perez Date: Fri, 12 Apr 2024 13:59:23 -0500 Subject: [PATCH] Apply some minor clean up to the AuthRepo (#1263) --- .../auth/repository/AuthRepositoryImpl.kt | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt index f50ca9a40d..9d30363790 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt @@ -91,7 +91,7 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.filterNot import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn @@ -127,7 +127,25 @@ class AuthRepositoryImpl( private val elapsedRealtimeMillisProvider: () -> Long = { SystemClock.elapsedRealtime() }, ) : AuthRepository, AuthRequestManager by authRequestManager { + /** + * A scope intended for use when simply collecting multiple flows in order to combine them. The + * use of [Dispatchers.Unconfined] allows for this to happen synchronously whenever any of + * these flows changes. + */ + private val unconfinedScope = CoroutineScope(dispatcherManager.unconfined) + + /** + * A scope intended for use when operating asynchronously. + */ + private val ioScope = CoroutineScope(dispatcherManager.io) + private val mutableHasPendingAccountAdditionStateFlow = MutableStateFlow(false) + + /** + * If there is a pending account deletion, continue showing the original UserState until it + * is confirmed. This is accomplished by blocking the emissions of the [userStateFlow] + * whenever set to `true`. + */ private val mutableHasPendingAccountDeletionStateFlow = MutableStateFlow(false) /** @@ -155,15 +173,6 @@ class AuthRepositoryImpl( */ private var passwordToCheck: String? = null - /** - * A scope intended for use when simply collecting multiple flows in order to combine them. The - * use of [Dispatchers.Unconfined] allows for this to happen synchronously whenever any of - * these flows changes. - */ - private val unconfinedScope = CoroutineScope(dispatcherManager.unconfined) - - private val ioScope = CoroutineScope(dispatcherManager.io) - override var twoFactorResponse: GetTokenResponseJson.TwoFactorRequired? = null override val ssoOrganizationIdentifier: String? get() = organizationIdentifier @@ -216,11 +225,7 @@ class AuthRepositoryImpl( isDeviceTrustedProvider = ::isDeviceTrusted, ) } - .filter { - // If there is a pending account deletion, continue showing - // the original UserState until it is confirmed. - !mutableHasPendingAccountDeletionStateFlow.value - } + .filterNot { mutableHasPendingAccountDeletionStateFlow.value } .stateIn( scope = unconfinedScope, started = SharingStarted.Eagerly, @@ -242,8 +247,7 @@ class AuthRepositoryImpl( captchaTokenChannel.receiveAsFlow() private val duoTokenChannel = Channel(capacity = Int.MAX_VALUE) - override val duoTokenResultFlow: Flow = - duoTokenChannel.receiveAsFlow() + override val duoTokenResultFlow: Flow = duoTokenChannel.receiveAsFlow() private val yubiKeyResultChannel = Channel(capacity = Int.MAX_VALUE) override val yubiKeyResultFlow: Flow = yubiKeyResultChannel.receiveAsFlow() @@ -279,6 +283,8 @@ class AuthRepositoryImpl( refreshAccessTokenSynchronously(userId) vaultRepository.sync() } + // This requires the ioScope to ensure that refreshAccessTokenSynchronously + // happens on a background thread .launchIn(ioScope) pushManager @@ -638,9 +644,9 @@ class AuthRepositoryImpl( onSuccess = { when (it) { is RegisterResponseJson.CaptchaRequired -> { - it.validationErrors.captchaKeys.firstOrNull()?.let { key -> - RegisterResult.CaptchaRequired(captchaId = key) - } ?: RegisterResult.Error(errorMessage = null) + it.validationErrors.captchaKeys.firstOrNull() + ?.let { key -> RegisterResult.CaptchaRequired(captchaId = key) } + ?: RegisterResult.Error(errorMessage = null) } is RegisterResponseJson.Success -> {