mirror of
https://github.com/bitwarden/android.git
synced 2026-06-08 08:06:32 -05:00
BIT-462: Add UI for custom vault timeout (#576)
This commit is contained in:
committed by
Álison Fernandes
parent
ff9dd81c55
commit
7e0a14d3a0
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.platform.components.dialog
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -45,6 +46,7 @@ import com.x8bit.bitwarden.R
|
||||
* with AM/PM.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun BitwardenTimePickerDialog(
|
||||
initialHour: Int,
|
||||
@@ -99,10 +101,17 @@ fun BitwardenTimePickerDialog(
|
||||
}
|
||||
},
|
||||
) {
|
||||
val modifier = Modifier.weight(1f)
|
||||
if (showTimeInput) {
|
||||
TimeInput(state = timePickerState)
|
||||
TimeInput(
|
||||
state = timePickerState,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
TimePicker(state = timePickerState)
|
||||
TimePicker(
|
||||
state = timePickerState,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,7 +122,7 @@ private fun TimePickerDialog(
|
||||
inputToggleButton: @Composable () -> Unit,
|
||||
dismissButton: @Composable () -> Unit,
|
||||
confirmButton: @Composable () -> Unit,
|
||||
content: @Composable () -> Unit,
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
Dialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@@ -46,9 +47,14 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenTextRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTwoButtonDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenWideSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTimePickerDialog
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialColors
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialTypography
|
||||
import com.x8bit.bitwarden.ui.platform.util.displayLabel
|
||||
import com.x8bit.bitwarden.ui.platform.util.toFormattedPattern
|
||||
import java.time.LocalTime
|
||||
|
||||
private const val MINUTES_PER_HOUR = 60
|
||||
|
||||
/**
|
||||
* Displays the account security screen.
|
||||
@@ -195,12 +201,25 @@ fun AccountSecurityScreen(
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
SessionTimeoutRow(
|
||||
selectedVaultTimeoutType = state.vaultTimeoutType,
|
||||
selectedVaultTimeoutType = state.vaultTimeout.type,
|
||||
onVaultTimeoutTypeSelect = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AccountSecurityAction.VaultTimeoutTypeSelect(it)) }
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
(state.vaultTimeout as? VaultTimeout.Custom)?.let { customTimeout ->
|
||||
SessionCustomTimeoutRow(
|
||||
customVaultTimeout = customTimeout,
|
||||
onCustomVaultTimeoutSelect = remember(viewModel) {
|
||||
{
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.CustomVaultTimeoutSelect(it),
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
SessionTimeoutActionRow(
|
||||
selectedVaultTimeoutAction = state.vaultTimeoutAction,
|
||||
onVaultTimeoutActionSelect = remember(viewModel) {
|
||||
@@ -334,6 +353,50 @@ private fun SessionTimeoutRow(
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun SessionCustomTimeoutRow(
|
||||
customVaultTimeout: VaultTimeout.Custom,
|
||||
onCustomVaultTimeoutSelect: (VaultTimeout.Custom) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var shouldShowTimePickerDialog by rememberSaveable { mutableStateOf(false) }
|
||||
val vaultTimeoutInMinutes = customVaultTimeout.vaultTimeoutInMinutes
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.custom),
|
||||
onClick = { shouldShowTimePickerDialog = true },
|
||||
modifier = modifier,
|
||||
) {
|
||||
val formattedTime = LocalTime
|
||||
.ofSecondOfDay(
|
||||
vaultTimeoutInMinutes * MINUTES_PER_HOUR.toLong(),
|
||||
)
|
||||
.toFormattedPattern("HH:mm")
|
||||
Text(
|
||||
text = formattedTime,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
|
||||
if (shouldShowTimePickerDialog) {
|
||||
BitwardenTimePickerDialog(
|
||||
initialHour = vaultTimeoutInMinutes / MINUTES_PER_HOUR,
|
||||
initialMinute = vaultTimeoutInMinutes.mod(MINUTES_PER_HOUR),
|
||||
onTimeSelect = { hour, minute ->
|
||||
shouldShowTimePickerDialog = false
|
||||
onCustomVaultTimeoutSelect(
|
||||
VaultTimeout.Custom(
|
||||
vaultTimeoutInMinutes = hour * MINUTES_PER_HOUR + minute,
|
||||
),
|
||||
)
|
||||
},
|
||||
onDismissRequest = { shouldShowTimePickerDialog = false },
|
||||
is24Hour = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun SessionTimeoutActionRow(
|
||||
|
||||
@@ -39,7 +39,7 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
isApproveLoginRequestsEnabled = false,
|
||||
isUnlockWithBiometricsEnabled = false,
|
||||
isUnlockWithPinEnabled = false,
|
||||
vaultTimeoutType = settingsRepository.vaultTimeout.type,
|
||||
vaultTimeout = settingsRepository.vaultTimeout,
|
||||
vaultTimeoutAction = settingsRepository.vaultTimeoutAction,
|
||||
),
|
||||
) {
|
||||
@@ -63,6 +63,7 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
AccountSecurityAction.LogoutClick -> handleLogoutClick()
|
||||
AccountSecurityAction.PendingLoginRequestsClick -> handlePendingLoginRequestsClick()
|
||||
is AccountSecurityAction.VaultTimeoutTypeSelect -> handleVaultTimeoutTypeSelect(action)
|
||||
is AccountSecurityAction.CustomVaultTimeoutSelect -> handleCustomVaultTimeoutSelect(action)
|
||||
is AccountSecurityAction.VaultTimeoutActionSelect -> {
|
||||
handleVaultTimeoutActionSelect(action)
|
||||
}
|
||||
@@ -123,13 +124,8 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun handleVaultTimeoutTypeSelect(action: AccountSecurityAction.VaultTimeoutTypeSelect) {
|
||||
val vaultTimeoutType = action.vaultTimeoutType
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
vaultTimeoutType = action.vaultTimeoutType,
|
||||
)
|
||||
}
|
||||
val vaultTimeout = when (vaultTimeoutType) {
|
||||
val previousTimeout = state.vaultTimeout
|
||||
val vaultTimeout = when (action.vaultTimeoutType) {
|
||||
VaultTimeout.Type.IMMEDIATELY -> VaultTimeout.Immediately
|
||||
VaultTimeout.Type.ONE_MINUTE -> VaultTimeout.OneMinute
|
||||
VaultTimeout.Type.FIVE_MINUTES -> VaultTimeout.FiveMinutes
|
||||
@@ -139,7 +135,28 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
VaultTimeout.Type.FOUR_HOURS -> VaultTimeout.FourHours
|
||||
VaultTimeout.Type.ON_APP_RESTART -> VaultTimeout.OnAppRestart
|
||||
VaultTimeout.Type.NEVER -> VaultTimeout.Never
|
||||
VaultTimeout.Type.CUSTOM -> VaultTimeout.Custom(vaultTimeoutInMinutes = 0)
|
||||
VaultTimeout.Type.CUSTOM -> {
|
||||
if (previousTimeout is VaultTimeout.Custom) {
|
||||
previousTimeout
|
||||
} else {
|
||||
VaultTimeout.Custom(vaultTimeoutInMinutes = 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
handleVaultTimeoutSelect(vaultTimeout = vaultTimeout)
|
||||
}
|
||||
|
||||
private fun handleCustomVaultTimeoutSelect(
|
||||
action: AccountSecurityAction.CustomVaultTimeoutSelect,
|
||||
) {
|
||||
handleVaultTimeoutSelect(vaultTimeout = action.customVaultTimeout)
|
||||
}
|
||||
|
||||
private fun handleVaultTimeoutSelect(vaultTimeout: VaultTimeout) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
vaultTimeout = vaultTimeout,
|
||||
)
|
||||
}
|
||||
settingsRepository.vaultTimeout = vaultTimeout
|
||||
|
||||
@@ -192,7 +209,7 @@ data class AccountSecurityState(
|
||||
val isApproveLoginRequestsEnabled: Boolean,
|
||||
val isUnlockWithBiometricsEnabled: Boolean,
|
||||
val isUnlockWithPinEnabled: Boolean,
|
||||
val vaultTimeoutType: VaultTimeout.Type,
|
||||
val vaultTimeout: VaultTimeout,
|
||||
val vaultTimeoutAction: VaultTimeoutAction,
|
||||
) : Parcelable
|
||||
|
||||
@@ -317,6 +334,13 @@ sealed class AccountSecurityAction {
|
||||
val vaultTimeoutType: VaultTimeout.Type,
|
||||
) : AccountSecurityAction()
|
||||
|
||||
/**
|
||||
* User selected an updated [VaultTimeout.Custom].
|
||||
*/
|
||||
data class CustomVaultTimeoutSelect(
|
||||
val customVaultTimeout: VaultTimeout.Custom,
|
||||
) : AccountSecurityAction()
|
||||
|
||||
/**
|
||||
* User selected a [VaultTimeoutAction].
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user