From 7c2f73649dd4e9ae83895406e2d06667f8004a7c Mon Sep 17 00:00:00 2001 From: Artem Chepurnoy Date: Tue, 13 Feb 2024 16:44:02 +0200 Subject: [PATCH] feat: Auto-close Cipher/Account/Wordlist screens when the model disappears --- .../feature/auth/AccountViewStateProducer.kt | 3 ++- .../view/WordlistViewStateProducer.kt | 18 ++----------- .../vault/screen/VaultViewStateProducer.kt | 3 +++ .../keyguard/ui/autoclose/AutoCloseWatcher.kt | 26 +++++++++++++++++++ 4 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 common/src/commonMain/kotlin/com/artemchep/keyguard/ui/autoclose/AutoCloseWatcher.kt diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/auth/AccountViewStateProducer.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/auth/AccountViewStateProducer.kt index ed0461d7..9a8781c7 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/auth/AccountViewStateProducer.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/auth/AccountViewStateProducer.kt @@ -77,6 +77,7 @@ import com.artemchep.keyguard.feature.navigation.state.produceScreenState import com.artemchep.keyguard.provider.bitwarden.ServerEnv import com.artemchep.keyguard.res.Res import com.artemchep.keyguard.ui.FlatItemAction +import com.artemchep.keyguard.ui.autoclose.launchAutoPopSelfHandler import com.artemchep.keyguard.ui.buildContextItems import com.artemchep.keyguard.ui.icons.ChevronIcon import com.artemchep.keyguard.ui.icons.EmailIcon @@ -90,7 +91,6 @@ import com.artemchep.keyguard.ui.icons.icon import com.artemchep.keyguard.ui.icons.iconSmall import com.artemchep.keyguard.ui.theme.badgeContainer import com.artemchep.keyguard.ui.theme.isDark -import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.combine @@ -205,6 +205,7 @@ fun accountState( val accountFlow = getAccounts() .map { it.firstOrNull(accountId) } + launchAutoPopSelfHandler(accountFlow) val metaFlow = getMetas() .map { it.firstOrNull(accountId) } val profileFlow = getProfiles() diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/generator/wordlist/view/WordlistViewStateProducer.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/generator/wordlist/view/WordlistViewStateProducer.kt index f140d750..5fd28957 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/generator/wordlist/view/WordlistViewStateProducer.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/generator/wordlist/view/WordlistViewStateProducer.kt @@ -14,7 +14,6 @@ import com.artemchep.keyguard.common.usecase.RemoveWordlistById import com.artemchep.keyguard.feature.crashlytics.crashlyticsAttempt import com.artemchep.keyguard.feature.generator.wordlist.util.WordlistUtil import com.artemchep.keyguard.feature.home.vault.search.IndexedText -import com.artemchep.keyguard.feature.navigation.state.navigatePopSelf import com.artemchep.keyguard.feature.navigation.state.produceScreenState import com.artemchep.keyguard.feature.search.search.IndexedModel import com.artemchep.keyguard.feature.search.search.mapSearch @@ -22,12 +21,9 @@ import com.artemchep.keyguard.feature.search.search.searchFilter import com.artemchep.keyguard.feature.search.search.searchQueryHandle import com.artemchep.keyguard.res.Res import com.artemchep.keyguard.ui.FlatItemAction +import com.artemchep.keyguard.ui.autoclose.launchAutoPopSelfHandler import com.artemchep.keyguard.ui.buildContextItems -import kotlinx.coroutines.flow.drop -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import org.kodein.di.compose.localDI import org.kodein.di.direct @@ -110,17 +106,7 @@ fun produceWordlistViewState( } } .stateIn(screenScope) - // Auto-close the screen if a model - // disappears - wordlistFlow - // We drop the first event, because we don't want to never let - // the user open the screen if the model doesn't exist, we want to - // close it if the model existed before and a user has seen it. - .drop(1) - .filter { it == null } - // Pop the screen. - .onEach { navigatePopSelf() } - .launchIn(screenScope) + launchAutoPopSelfHandler(wordlistFlow) fun onClick(model: String) { } diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/screen/VaultViewStateProducer.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/screen/VaultViewStateProducer.kt index 674cea74..f3758837 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/screen/VaultViewStateProducer.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/screen/VaultViewStateProducer.kt @@ -177,6 +177,7 @@ import com.artemchep.keyguard.res.Res import com.artemchep.keyguard.ui.ContextItem import com.artemchep.keyguard.ui.FlatItemAction import com.artemchep.keyguard.ui.MediumEmphasisAlpha +import com.artemchep.keyguard.ui.autoclose.launchAutoPopSelfHandler import com.artemchep.keyguard.ui.buildContextItems import com.artemchep.keyguard.ui.colorizePassword import com.artemchep.keyguard.ui.icons.ChevronIcon @@ -398,6 +399,8 @@ fun vaultViewScreenState( .firstOrNull { it.id == itemId && it.accountId == accountId } } .distinctUntilChanged() + launchAutoPopSelfHandler(secretFlow) + val ciphersFlow = getCiphers() .map { secrets -> secrets diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/ui/autoclose/AutoCloseWatcher.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/ui/autoclose/AutoCloseWatcher.kt new file mode 100644 index 00000000..df40c653 --- /dev/null +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/ui/autoclose/AutoCloseWatcher.kt @@ -0,0 +1,26 @@ +package com.artemchep.keyguard.ui.autoclose + +import com.artemchep.keyguard.feature.navigation.state.RememberStateFlowScope +import com.artemchep.keyguard.feature.navigation.state.navigatePopSelf +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +fun RememberStateFlowScope.launchAutoPopSelfHandler( + contentFlow: Flow, +) { + // Auto-close the screen if a model disappears. + // This happens if a user deletes the + // cipher, for example. + contentFlow + // We drop the first event, because we don't want to never let + // the user open the screen if the model doesn't exist, we want to + // close it if the model existed before and a user has seen it. + .drop(1) + .filter { it == null } + // Pop the screen. + .onEach { navigatePopSelf() } + .launchIn(screenScope) +}