mirror of
https://github.com/bitwarden/android.git
synced 2025-03-15 18:58:59 +03:00
Add SettingsRepository and VaultTimeout (#519)
This commit is contained in:
parent
54c288cb25
commit
5469874c95
4 changed files with 263 additions and 0 deletions
|
@ -0,0 +1,19 @@
|
|||
package com.x8bit.bitwarden.data.platform.repository
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* Provides an API for observing and modifying settings state.
|
||||
*/
|
||||
interface SettingsRepository {
|
||||
/**
|
||||
* Gets updates for the [VaultTimeout] associated with the given [userId].
|
||||
*/
|
||||
fun getVaultTimeoutStateFlow(userId: String): StateFlow<VaultTimeout>
|
||||
|
||||
/**
|
||||
* Stores the given [vaultTimeout] for the given [userId].
|
||||
*/
|
||||
fun storeVaultTimeout(userId: String, vaultTimeout: VaultTimeout)
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.x8bit.bitwarden.data.platform.repository
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
/**
|
||||
* Primary implementation of [SettingsRepository].
|
||||
*/
|
||||
class SettingsRepositoryImpl(
|
||||
private val settingsDiskSource: SettingsDiskSource,
|
||||
private val dispatcherManager: DispatcherManager,
|
||||
) : SettingsRepository {
|
||||
private val unconfinedScope = CoroutineScope(dispatcherManager.unconfined)
|
||||
|
||||
override fun getVaultTimeoutStateFlow(userId: String): StateFlow<VaultTimeout> =
|
||||
settingsDiskSource
|
||||
.getVaultTimeoutInMinutesFlow(userId = userId)
|
||||
.map { it.toVaultTimeout() }
|
||||
.stateIn(
|
||||
scope = unconfinedScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = settingsDiskSource
|
||||
.getVaultTimeoutInMinutes(userId = userId)
|
||||
.toVaultTimeout(),
|
||||
)
|
||||
|
||||
override fun storeVaultTimeout(userId: String, vaultTimeout: VaultTimeout) {
|
||||
settingsDiskSource.storeVaultTimeoutInMinutes(
|
||||
userId = userId,
|
||||
vaultTimeoutInMinutes = vaultTimeout.vaultTimeoutInMinutes,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a stored [Int] representing a vault timeout in minutes to a [VaultTimeout].
|
||||
*/
|
||||
private fun Int?.toVaultTimeout(): VaultTimeout =
|
||||
when (this) {
|
||||
VaultTimeout.Immediately.vaultTimeoutInMinutes -> VaultTimeout.Immediately
|
||||
VaultTimeout.OneMinute.vaultTimeoutInMinutes -> VaultTimeout.OneMinute
|
||||
VaultTimeout.FiveMinutes.vaultTimeoutInMinutes -> VaultTimeout.FiveMinutes
|
||||
VaultTimeout.ThirtyMinutes.vaultTimeoutInMinutes -> VaultTimeout.ThirtyMinutes
|
||||
VaultTimeout.OneHour.vaultTimeoutInMinutes -> VaultTimeout.OneHour
|
||||
VaultTimeout.FourHours.vaultTimeoutInMinutes -> VaultTimeout.FourHours
|
||||
VaultTimeout.OnAppRestart.vaultTimeoutInMinutes -> VaultTimeout.OnAppRestart
|
||||
null -> VaultTimeout.Never
|
||||
else -> VaultTimeout.Custom(vaultTimeoutInMinutes = this)
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
package com.x8bit.bitwarden.data.platform.repository.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
/**
|
||||
* Represents the timeout period for a user's vault.
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
sealed class VaultTimeout : Parcelable {
|
||||
/**
|
||||
* The type of timeout.
|
||||
*/
|
||||
abstract val type: Type
|
||||
|
||||
/**
|
||||
* The time (in minutes) that the vault can stay unlocked before it will automatically lock
|
||||
* itself (or `null` to allow for vault that never locks).
|
||||
*/
|
||||
abstract val vaultTimeoutInMinutes: Int?
|
||||
|
||||
/**
|
||||
* The vault should be considered timed-out immediately.
|
||||
*/
|
||||
@Parcelize
|
||||
data object Immediately : VaultTimeout() {
|
||||
override val type: Type get() = Type.IMMEDIATELY
|
||||
override val vaultTimeoutInMinutes: Int get() = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* The vault should time out after one minute.
|
||||
*/
|
||||
@Parcelize
|
||||
data object OneMinute : VaultTimeout() {
|
||||
override val type: Type get() = Type.ONE_MINUTE
|
||||
override val vaultTimeoutInMinutes: Int get() = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* The vault should time out after five minutes.
|
||||
*/
|
||||
@Parcelize
|
||||
data object FiveMinutes : VaultTimeout() {
|
||||
override val type: Type get() = Type.FIVE_MINUTES
|
||||
override val vaultTimeoutInMinutes: Int get() = 5
|
||||
}
|
||||
|
||||
/**
|
||||
* The vault should time out after thirty minutes.
|
||||
*/
|
||||
@Parcelize
|
||||
data object ThirtyMinutes : VaultTimeout() {
|
||||
override val type: Type get() = Type.THIRTY_MINUTES
|
||||
override val vaultTimeoutInMinutes: Int get() = 30
|
||||
}
|
||||
|
||||
/**
|
||||
* The vault should time out after one hour.
|
||||
*/
|
||||
@Parcelize
|
||||
data object OneHour : VaultTimeout() {
|
||||
override val type: Type get() = Type.ONE_HOUR
|
||||
override val vaultTimeoutInMinutes: Int get() = 60
|
||||
}
|
||||
|
||||
/**
|
||||
* The vault should time out after four hours.
|
||||
*/
|
||||
@Parcelize
|
||||
data object FourHours : VaultTimeout() {
|
||||
override val type: Type get() = Type.FOUR_HOURS
|
||||
override val vaultTimeoutInMinutes: Int get() = 240
|
||||
}
|
||||
|
||||
/**
|
||||
* The vault should time out after an app restart.
|
||||
*/
|
||||
@Parcelize
|
||||
data object OnAppRestart : VaultTimeout() {
|
||||
override val type: Type get() = Type.ON_APP_RESTART
|
||||
override val vaultTimeoutInMinutes: Int get() = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* The vault should never automatically timeout.
|
||||
*/
|
||||
@Parcelize
|
||||
data object Never : VaultTimeout() {
|
||||
override val type: Type get() = Type.NEVER
|
||||
override val vaultTimeoutInMinutes: Int? get() = null
|
||||
}
|
||||
|
||||
/**
|
||||
* The timeout period is a custom value given by the dynamic [vaultTimeoutInMinutes].
|
||||
*/
|
||||
@Parcelize
|
||||
data class Custom(
|
||||
override val vaultTimeoutInMinutes: Int,
|
||||
) : VaultTimeout() {
|
||||
override val type: Type get() = Type.CUSTOM
|
||||
}
|
||||
|
||||
/**
|
||||
* The specific type of timeout.
|
||||
*/
|
||||
enum class Type {
|
||||
IMMEDIATELY,
|
||||
ONE_MINUTE,
|
||||
FIVE_MINUTES,
|
||||
THIRTY_MINUTES,
|
||||
ONE_HOUR,
|
||||
FOUR_HOURS,
|
||||
ON_APP_RESTART,
|
||||
NEVER,
|
||||
CUSTOM,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.x8bit.bitwarden.data.platform.repository
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.util.FakeSettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class SettingsRepositoryTest {
|
||||
private val fakeSettingsDiskSource = FakeSettingsDiskSource()
|
||||
|
||||
private val settingsRepository = SettingsRepositoryImpl(
|
||||
settingsDiskSource = fakeSettingsDiskSource,
|
||||
dispatcherManager = FakeDispatcherManager(),
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `getVaultTimeoutStateFlow should react to changes in SettingsDiskSource`() = runTest {
|
||||
val userId = "userId"
|
||||
settingsRepository
|
||||
.getVaultTimeoutStateFlow(userId = userId)
|
||||
.test {
|
||||
assertEquals(
|
||||
VaultTimeout.Never,
|
||||
awaitItem(),
|
||||
)
|
||||
VAULT_TIMEOUT_MAP.forEach { (vaultTimeout, vaultTimeoutInMinutes) ->
|
||||
fakeSettingsDiskSource.storeVaultTimeoutInMinutes(
|
||||
userId = userId,
|
||||
vaultTimeoutInMinutes = vaultTimeoutInMinutes,
|
||||
)
|
||||
assertEquals(
|
||||
vaultTimeout,
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storeVaultTimeout should properly update SettingsDiskSource`() {
|
||||
val userId = "userId"
|
||||
VAULT_TIMEOUT_MAP.forEach { (vaultTimeout, vaultTimeoutInMinutes) ->
|
||||
settingsRepository.storeVaultTimeout(
|
||||
userId = userId,
|
||||
vaultTimeout = vaultTimeout,
|
||||
)
|
||||
assertEquals(
|
||||
vaultTimeoutInMinutes,
|
||||
fakeSettingsDiskSource.getVaultTimeoutInMinutes(userId = userId),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a VaultTimeout to its expected vaultTimeoutInMinutes value.
|
||||
*/
|
||||
private val VAULT_TIMEOUT_MAP =
|
||||
mapOf(
|
||||
VaultTimeout.OneMinute to 1,
|
||||
VaultTimeout.FiveMinutes to 5,
|
||||
VaultTimeout.ThirtyMinutes to 30,
|
||||
VaultTimeout.OneHour to 60,
|
||||
VaultTimeout.FourHours to 240,
|
||||
VaultTimeout.OnAppRestart to -1,
|
||||
VaultTimeout.Never to null,
|
||||
VaultTimeout.Custom(vaultTimeoutInMinutes = 123) to 123,
|
||||
)
|
Loading…
Add table
Reference in a new issue