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 370fba6..4cc7e5d 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 @@ -103,6 +103,8 @@ import com.artemchep.keyguard.ui.theme.badgeContainer import com.artemchep.keyguard.ui.theme.isDark import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flow @@ -520,6 +522,17 @@ private fun buildItemsFlow( copyText = copyText, ) } + if (account != null && profile != null && !profile.twoFactorEnabled) { + val inactiveTfaItem = VaultViewItem.InactiveTotp( + id = "inactive_tfa", + chevron = true, + onClick = { + val intent = NavigationIntent.NavigateToBrowser(account.url) + scope.navigate(intent) + }, + ) + emit(inactiveTfaItem) + } if (meta != null) { val syncTimestamp = meta.lastSyncTimestamp if (syncTimestamp != null) { @@ -702,7 +715,7 @@ private fun buildItemsFlow( filter = DFilter.ById( id = accountId.id, what = DFilter.ById.What.ACCOUNT, - ) + ), ), ) val intent = NavigationIntent.NavigateToRoute(route) @@ -741,11 +754,6 @@ private fun buildItemsFlow( account = account, profile = profile, ) - emitTwoFactorAuth( - scope = scope, - account = account, - profile = profile, - ) val unofficialServer = profile.unofficialServer if (unofficialServer) { val unofficialServerText = scope.translate(Res.strings.bitwarden_unofficial_server) @@ -905,6 +913,29 @@ private suspend fun FlowCollector.emitEmail( .attempt() .bind() .getOrNull() + val badges = kotlin.run { + val list = mutableListOf>() + // Account email verification badge + list += if (profile.emailVerified) { + VaultViewItem.Value.Badge( + text = scope.translate(Res.strings.email_verified), + score = 1f, + ) + } else { + VaultViewItem.Value.Badge( + text = scope.translate(Res.strings.email_not_verified), + score = 0.5f, + ) + }.let(::MutableStateFlow) + // Account two-factor authentication badge + if (profile.twoFactorEnabled) { + list += VaultViewItem.Value.Badge( + text = scope.translate(Res.strings.account_action_tfa_title), + score = 1f, + ).let(::MutableStateFlow) + } + list + } val emailItem = VaultViewItem.Value( id = id, elevation = 1.dp, @@ -956,55 +987,12 @@ private suspend fun FlowCollector.emitEmail( ) } }, - badge = if (profile.emailVerified) { - VaultViewItem.Value.Badge( - text = scope.translate(Res.strings.email_verified), - score = 1f, - ) - } else { - VaultViewItem.Value.Badge( - text = scope.translate(Res.strings.email_not_verified), - score = 0.5f, - ) - }, + badge2 = badges, ) emit(emailItem) } } -private suspend fun FlowCollector.emitTwoFactorAuth( - scope: RememberStateFlowScope, - account: DAccount, - profile: DProfile, -) { - val id = "twofa" - val twoFactorEnabled = profile.twoFactorEnabled - val item = VaultViewItem.Action( - id = id, - title = scope.translate(Res.strings.account_action_tfa_title), - text = scope.translate(Res.strings.account_action_tfa_text), - leading = { - Icon(Icons.Outlined.KeyguardTwoFa, null) - }, - trailing = { - ChevronIcon() - }, - badge = if (twoFactorEnabled) { - VaultViewItem.Action.Badge( - text = scope.translate(Res.strings.account_action_tfa_active_status), - score = 1f, - ) - } else { - null - }, - onClick = { - val intent = NavigationIntent.NavigateToBrowser(account.url) - scope.navigate(intent) - }, - ) - emit(item) -} - private suspend fun FlowCollector.emitPremium( scope: RememberStateFlowScope, account: DAccount, diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/component/VaultViewInactiveTotpItem.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/component/VaultViewInactiveTotpItem.kt index b087396..2f2ae5f 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/component/VaultViewInactiveTotpItem.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/component/VaultViewInactiveTotpItem.kt @@ -15,6 +15,7 @@ import com.artemchep.keyguard.res.Res import com.artemchep.keyguard.ui.DisabledEmphasisAlpha import com.artemchep.keyguard.ui.FlatDropdown import com.artemchep.keyguard.ui.FlatItemTextContent +import com.artemchep.keyguard.ui.icons.ChevronIcon import com.artemchep.keyguard.ui.theme.combineAlpha import com.artemchep.keyguard.ui.theme.onWarningContainer import com.artemchep.keyguard.ui.theme.warning @@ -53,6 +54,14 @@ fun VaultViewInactiveTotpItem( ) } }, + trailing = if (item.chevron) { + // composable + { + ChevronIcon() + } + } else { + null + }, onClick = item.onClick, ) } diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/model/VaultViewItem.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/model/VaultViewItem.kt index 5fe2aac..f2b0740 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/model/VaultViewItem.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/feature/home/vault/model/VaultViewItem.kt @@ -246,7 +246,7 @@ sealed interface VaultViewItem { data class InactiveTotp( override val id: String, - val info: TwoFaServiceInfo, + val chevron: Boolean, val onClick: () -> Unit, ) : VaultViewItem { companion object 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 1c59327..d7338e2 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 @@ -1105,7 +1105,7 @@ private fun RememberStateFlowScope.oh( if (isUnsecure != null) { val model = VaultViewItem.InactiveTotp( id = "error2", - info = isUnsecure, + chevron = false, onClick = { val route = TwoFaServiceViewDialogRoute( args = TwoFaServiceViewDialogRoute.Args(isUnsecure),