Save the clear clipboard frequency in settings. (#886)

This commit is contained in:
Oleg Semenenko
2024-01-30 23:44:21 -06:00
committed by Álison Fernandes
parent 526ab51a90
commit a985cfaccc
13 changed files with 224 additions and 45 deletions

View File

@@ -129,6 +129,16 @@ interface SettingsDiskSource {
vaultTimeoutAction: VaultTimeoutAction?,
)
/**
* Gets the clipboard clearing frequency in seconds for the given [userId].
*/
fun getClearClipboardFrequencySeconds(userId: String): Int?
/**
* Stores the clipboard clearing frequency in seconds for the given [userId].
*/
fun storeClearClipboardFrequencySeconds(userId: String, frequency: Int?)
/**
* Gets the default [UriMatchType] for the given [userId].
*/

View File

@@ -31,6 +31,7 @@ private const val SCREEN_CAPTURE_ALLOW_KEY = "$BASE_KEY:screenCaptureAllowed"
private const val SYSTEM_BIOMETRIC_INTEGRITY_SOURCE_KEY = "$BASE_KEY:biometricIntegritySource"
private const val ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY = "$BASE_KEY:accountBiometricIntegrityValid"
private const val CRASH_LOGGING_ENABLED_KEY = "$BASE_KEY:crashLoggingEnabled"
private const val CLEAR_CLIPBOARD_INTERVAL_KEY = "$BASE_KEY:clearClipboard"
/**
* Primary implementation of [SettingsDiskSource].
@@ -136,6 +137,7 @@ class SettingsDiskSourceImpl(
)
storeLastSyncTime(userId = userId, lastSyncTime = null)
storeScreenCaptureAllowed(userId = userId, isScreenCaptureAllowed = null)
storeClearClipboardFrequencySeconds(userId = userId, frequency = null)
removeWithPrefix(prefix = "${ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY}_$userId")
}
@@ -191,6 +193,16 @@ class SettingsDiskSourceImpl(
getMutableVaultTimeoutInMinutesFlow(userId = userId).tryEmit(vaultTimeoutInMinutes)
}
override fun getClearClipboardFrequencySeconds(userId: String): Int? =
getInt(key = "${CLEAR_CLIPBOARD_INTERVAL_KEY}_$userId")
override fun storeClearClipboardFrequencySeconds(userId: String, frequency: Int?) {
putInt(
key = "${CLEAR_CLIPBOARD_INTERVAL_KEY}_$userId",
value = frequency,
)
}
override fun getVaultTimeoutAction(userId: String): VaultTimeoutAction? =
getString(key = "${VAULT_TIMEOUT_ACTION_KEY}_$userId")?.let { storedValue ->
VaultTimeoutAction.entries.firstOrNull { storedValue == it.value }

View File

@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.platform.repository
import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult
import com.x8bit.bitwarden.data.platform.repository.model.BiometricsKeyResult
import com.x8bit.bitwarden.data.platform.repository.model.ClearClipboardFrequency
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
@@ -51,6 +52,11 @@ interface SettingsRepository {
*/
val isIconLoadingDisabledFlow: Flow<Boolean>
/**
* The frequency in seconds at which we clear the clipboard.
*/
var clearClipboardFrequency: ClearClipboardFrequency
/**
* The current setting for crash logging.
*/

View File

@@ -9,6 +9,7 @@ import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.platform.repository.model.BiometricsKeyResult
import com.x8bit.bitwarden.data.platform.repository.model.ClearClipboardFrequency
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
@@ -101,6 +102,18 @@ class SettingsRepositoryImpl(
.isIconLoadingDisabled
?: false,
)
override var clearClipboardFrequency: ClearClipboardFrequency
get() = activeUserId
?.let { userId ->
settingsDiskSource
.getClearClipboardFrequencySeconds(userId)
.toClearClipboardFrequency()
}
?: ClearClipboardFrequency.NEVER
set(value) {
val userId = activeUserId ?: return
settingsDiskSource.storeClearClipboardFrequencySeconds(userId, value.frequencySeconds)
}
override var isCrashLoggingEnabled: Boolean
get() = settingsDiskSource.isCrashLoggingEnabled ?: true
@@ -439,6 +452,13 @@ private fun Int?.toVaultTimeout(): VaultTimeout =
else -> VaultTimeout.Custom(vaultTimeoutInMinutes = this)
}
/**
* Converts the given Int into a [ClearClipboardFrequency] item.
*/
private fun Int?.toClearClipboardFrequency(): ClearClipboardFrequency =
ClearClipboardFrequency.entries.firstOrNull { it.frequencySeconds == this }
?: ClearClipboardFrequency.NEVER
/**
* Returns the given [VaultTimeoutAction] or a default value if `null`.
*/

View File

@@ -0,0 +1,17 @@
package com.x8bit.bitwarden.data.platform.repository.model
/**
* Represents the frequency for clearing the clipboard for the current user.
*/
@Suppress("MagicNumber")
enum class ClearClipboardFrequency(
val frequencySeconds: Int?,
) {
NEVER(null),
TEN_SECONDS(10),
TWENTY_SECONDS(20),
THIRTY_SECONDS(30),
ONE_MINUTE(60),
TWO_MINUTES(120),
FIVE_MINUTES(300),
}

View File

@@ -0,0 +1,21 @@
package com.x8bit.bitwarden.data.platform.repository.util
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.platform.repository.model.ClearClipboardFrequency
import com.x8bit.bitwarden.ui.platform.base.util.Text
import com.x8bit.bitwarden.ui.platform.base.util.asText
/**
* Provides a human-readable display label for the given [ClearClipboardFrequency].
*/
val ClearClipboardFrequency.displayLabel: Text
get() = when (this) {
ClearClipboardFrequency.NEVER -> R.string.never
ClearClipboardFrequency.TEN_SECONDS -> R.string.ten_seconds
ClearClipboardFrequency.TWENTY_SECONDS -> R.string.twenty_seconds
ClearClipboardFrequency.THIRTY_SECONDS -> R.string.thirty_seconds
ClearClipboardFrequency.ONE_MINUTE -> R.string.one_minute
ClearClipboardFrequency.TWO_MINUTES -> R.string.two_minutes
ClearClipboardFrequency.FIVE_MINUTES -> R.string.five_minutes
}
.asText()

View File

@@ -29,6 +29,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.platform.repository.model.ClearClipboardFrequency
import com.x8bit.bitwarden.data.platform.repository.util.displayLabel
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledTonalButton
import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingDialog
@@ -191,8 +193,8 @@ private fun ScreenCaptureRow(
@Composable
private fun ClearClipboardFrequencyRow(
currentSelection: OtherState.ClearClipboardFrequency,
onFrequencySelection: (OtherState.ClearClipboardFrequency) -> Unit,
currentSelection: ClearClipboardFrequency,
onFrequencySelection: (ClearClipboardFrequency) -> Unit,
modifier: Modifier = Modifier,
) {
var shouldShowClearClipboardDialog by remember { mutableStateOf(false) }
@@ -204,7 +206,7 @@ private fun ClearClipboardFrequencyRow(
modifier = modifier,
) {
Text(
text = currentSelection.text(),
text = currentSelection.displayLabel.invoke(),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
@@ -215,14 +217,14 @@ private fun ClearClipboardFrequencyRow(
title = stringResource(id = R.string.clear_clipboard),
onDismissRequest = { shouldShowClearClipboardDialog = false },
) {
OtherState.ClearClipboardFrequency.entries.forEach { option ->
ClearClipboardFrequency.entries.forEach { option ->
BitwardenSelectionRow(
text = option.text,
text = option.displayLabel,
isSelected = option == currentSelection,
onClick = {
shouldShowClearClipboardDialog = false
onFrequencySelection(
OtherState.ClearClipboardFrequency.entries.first { it == option },
ClearClipboardFrequency.entries.first { it == option },
)
},
)

View File

@@ -5,6 +5,7 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
import com.x8bit.bitwarden.data.platform.repository.model.ClearClipboardFrequency
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import com.x8bit.bitwarden.ui.platform.base.util.Text
@@ -38,7 +39,7 @@ class OtherViewModel @Inject constructor(
?: OtherState(
allowScreenCapture = settingsRepo.isScreenCaptureAllowed,
allowSyncOnRefresh = settingsRepo.getPullToRefreshEnabledFlow().value,
clearClipboardFrequency = OtherState.ClearClipboardFrequency.DEFAULT,
clearClipboardFrequency = settingsRepo.clearClipboardFrequency,
lastSyncTime = settingsRepo
.vaultLastSync
?.toFormattedPattern(VAULT_LAST_SYNC_TIME_PATTERN, clock.zone)
@@ -80,12 +81,10 @@ class OtherViewModel @Inject constructor(
private fun handleClearClipboardFrequencyChanged(
action: OtherAction.ClearClipboardFrequencyChange,
) {
// TODO BIT-1283 implement clear clipboard setting
mutableStateFlow.update {
it.copy(
clearClipboardFrequency = action.clearClipboardFrequency,
)
it.copy(clearClipboardFrequency = action.clearClipboardFrequency)
}
settingsRepo.clearClipboardFrequency = action.clearClipboardFrequency
}
private fun handleSyncNowButtonClicked() {
@@ -125,19 +124,6 @@ data class OtherState(
val lastSyncTime: String,
val dialogState: DialogState?,
) : Parcelable {
/**
* Represents the different frequencies with which the user clipboard can be cleared.
*/
enum class ClearClipboardFrequency(val text: Text) {
DEFAULT(text = R.string.never.asText()),
TEN_SECONDS(text = R.string.ten_seconds.asText()),
TWENTY_SECONDS(text = R.string.twenty_seconds.asText()),
THIRTY_SECONDS(text = R.string.thirty_seconds.asText()),
ONE_MINUTE(text = R.string.one_minute.asText()),
TWO_MINUTES(text = R.string.two_minutes.asText()),
FIVE_MINUTES(text = R.string.five_minutes.asText()),
}
/**
* Represents the current state of any dialogs on the screen.
*/
@@ -189,7 +175,7 @@ sealed class OtherAction {
* Indicates that the user changed the clear clipboard frequency.
*/
data class ClearClipboardFrequencyChange(
val clearClipboardFrequency: OtherState.ClearClipboardFrequency,
val clearClipboardFrequency: ClearClipboardFrequency,
) : OtherAction()
/**