mirror of
https://github.com/bitwarden/android.git
synced 2026-05-27 15:15:33 -05:00
Add support for the pull-to-refresh in settings (#615)
This commit is contained in:
@@ -232,4 +232,65 @@ class SettingsDiskSourceTest {
|
||||
)
|
||||
assertNull(fakeSharedPreferences.getString(vaultTimeoutActionKey, null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storePullToRefreshEnabled when values are present should pull from SharedPreferences`() {
|
||||
val pullToRefreshBaseKey = "bwPreferencesStorage:syncOnRefresh"
|
||||
val mockUserId = "mockUserId"
|
||||
val pullToRefreshKey = "${pullToRefreshBaseKey}_$mockUserId"
|
||||
fakeSharedPreferences
|
||||
.edit()
|
||||
.putBoolean(pullToRefreshKey, true)
|
||||
.apply()
|
||||
assertEquals(true, settingsDiskSource.getPullToRefreshEnabled(userId = mockUserId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storePullToRefreshEnabled when values are absent should return null`() {
|
||||
val mockUserId = "mockUserId"
|
||||
assertNull(settingsDiskSource.getPullToRefreshEnabled(userId = mockUserId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPullToRefreshEnabledFlow should react to changes in getPullToRefreshEnabled`() =
|
||||
runTest {
|
||||
val mockUserId = "mockUserId"
|
||||
settingsDiskSource.getPullToRefreshEnabledFlow(userId = mockUserId).test {
|
||||
// The initial values of the Flow and the property are in sync
|
||||
assertNull(settingsDiskSource.getPullToRefreshEnabled(userId = mockUserId))
|
||||
assertNull(awaitItem())
|
||||
|
||||
// Updating the disk source updates shared preferences
|
||||
settingsDiskSource.storePullToRefreshEnabled(
|
||||
userId = mockUserId,
|
||||
isPullToRefreshEnabled = true,
|
||||
)
|
||||
assertEquals(true, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storePullToRefreshEnabled for non-null values should update SharedPreferences`() {
|
||||
val pullToRefreshBaseKey = "bwPreferencesStorage:syncOnRefresh"
|
||||
val mockUserId = "mockUserId"
|
||||
val pullToRefreshKey = "${pullToRefreshBaseKey}_$mockUserId"
|
||||
settingsDiskSource.storePullToRefreshEnabled(
|
||||
userId = mockUserId,
|
||||
isPullToRefreshEnabled = true,
|
||||
)
|
||||
assertTrue(fakeSharedPreferences.getBoolean(pullToRefreshKey, false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storePullToRefreshEnabled for null values should clear SharedPreferences`() {
|
||||
val pullToRefreshBaseKey = "bwPreferencesStorage:syncOnRefresh"
|
||||
val mockUserId = "mockUserId"
|
||||
val pullToRefreshKey = "${pullToRefreshBaseKey}_$mockUserId"
|
||||
fakeSharedPreferences.edit { putBoolean(pullToRefreshKey, false) }
|
||||
settingsDiskSource.storePullToRefreshEnabled(
|
||||
userId = mockUserId,
|
||||
isPullToRefreshEnabled = null,
|
||||
)
|
||||
assertFalse(fakeSharedPreferences.contains(pullToRefreshKey))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,14 @@ class FakeSettingsDiskSource : SettingsDiskSource {
|
||||
private val mutableVaultTimeoutInMinutesFlowMap =
|
||||
mutableMapOf<String, MutableSharedFlow<Int?>>()
|
||||
|
||||
private val mutablePullToRefreshEnabledFlowMap =
|
||||
mutableMapOf<String, MutableSharedFlow<Boolean?>>()
|
||||
|
||||
private val storedVaultTimeoutActions = mutableMapOf<String, VaultTimeoutAction?>()
|
||||
private val storedVaultTimeoutInMinutes = mutableMapOf<String, Int?>()
|
||||
|
||||
private val storedPullToRefreshEnabled = mutableMapOf<String, Boolean?>()
|
||||
|
||||
override var appLanguage: AppLanguage? = null
|
||||
|
||||
override fun clearData(userId: String) {
|
||||
@@ -62,6 +67,18 @@ class FakeSettingsDiskSource : SettingsDiskSource {
|
||||
getMutableVaultTimeoutActionsFlow(userId = userId).tryEmit(vaultTimeoutAction)
|
||||
}
|
||||
|
||||
override fun getPullToRefreshEnabled(userId: String): Boolean? =
|
||||
storedPullToRefreshEnabled[userId]
|
||||
|
||||
override fun getPullToRefreshEnabledFlow(userId: String): Flow<Boolean?> =
|
||||
getMutablePullToRefreshEnabledFlow(userId = userId)
|
||||
.onSubscription { emit(getPullToRefreshEnabled(userId = userId)) }
|
||||
|
||||
override fun storePullToRefreshEnabled(userId: String, isPullToRefreshEnabled: Boolean?) {
|
||||
storedPullToRefreshEnabled[userId] = isPullToRefreshEnabled
|
||||
getMutablePullToRefreshEnabledFlow(userId = userId).tryEmit(isPullToRefreshEnabled)
|
||||
}
|
||||
|
||||
//region Private helper functions
|
||||
|
||||
private fun getMutableVaultTimeoutActionsFlow(
|
||||
@@ -78,5 +95,12 @@ class FakeSettingsDiskSource : SettingsDiskSource {
|
||||
bufferedMutableSharedFlow(replay = 1)
|
||||
}
|
||||
|
||||
private fun getMutablePullToRefreshEnabledFlow(
|
||||
userId: String,
|
||||
): MutableSharedFlow<Boolean?> =
|
||||
mutablePullToRefreshEnabledFlowMap.getOrPut(userId) {
|
||||
bufferedMutableSharedFlow(replay = 1)
|
||||
}
|
||||
|
||||
//endregion Private helper functions
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ package com.x8bit.bitwarden.data.platform.repository
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
|
||||
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 com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.runTest
|
||||
@@ -271,6 +273,38 @@ class SettingsRepositoryTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPullToRefreshEnabledFlow should react to changes in SettingsDiskSource`() = runTest {
|
||||
val userId = "userId"
|
||||
val userState = mockk<UserStateJson> {
|
||||
every { activeUserId } returns userId
|
||||
}
|
||||
coEvery { authDiskSource.userState } returns userState
|
||||
settingsRepository
|
||||
.getPullToRefreshEnabledFlow()
|
||||
.test {
|
||||
assertFalse(awaitItem())
|
||||
fakeSettingsDiskSource.storePullToRefreshEnabled(
|
||||
userId = userId,
|
||||
isPullToRefreshEnabled = true,
|
||||
)
|
||||
assertTrue(awaitItem())
|
||||
fakeSettingsDiskSource.storePullToRefreshEnabled(
|
||||
userId = userId,
|
||||
isPullToRefreshEnabled = false,
|
||||
)
|
||||
assertFalse(awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storePullToRefreshEnabled should properly update SettingsDiskSource`() {
|
||||
val userId = "userId"
|
||||
every { authDiskSource.userState?.activeUserId } returns userId
|
||||
settingsRepository.storePullToRefreshEnabled(true)
|
||||
assertEquals(true, fakeSettingsDiskSource.getPullToRefreshEnabled(userId = userId))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.other
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import io.mockk.every
|
||||
@@ -9,12 +10,17 @@ import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class OtherViewModelTest : BaseViewModelTest() {
|
||||
val vaultRepository = mockk<VaultRepository>()
|
||||
private val mutablePullToRefreshStateFlow = MutableStateFlow(false)
|
||||
private val settingsRepository = mockk<SettingsRepository> {
|
||||
every { getPullToRefreshEnabledFlow() } returns mutablePullToRefreshStateFlow
|
||||
}
|
||||
private val vaultRepository = mockk<VaultRepository>()
|
||||
|
||||
@Test
|
||||
fun `initial state should be correct when not set`() {
|
||||
@@ -51,21 +57,18 @@ class OtherViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on AllowSyncToggled should update value in state`() = runTest {
|
||||
fun `on AllowSyncToggled should update value in state`() {
|
||||
every {
|
||||
settingsRepository.storePullToRefreshEnabled(isPullToRefreshEnabled = true)
|
||||
} just runs
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
expectNoEvents()
|
||||
}
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(
|
||||
DEFAULT_STATE,
|
||||
awaitItem(),
|
||||
)
|
||||
viewModel.trySendAction(OtherAction.AllowSyncToggle(true))
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(allowSyncOnRefresh = true),
|
||||
awaitItem(),
|
||||
)
|
||||
viewModel.trySendAction(OtherAction.AllowSyncToggle(true))
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(allowSyncOnRefresh = true),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
settingsRepository.storePullToRefreshEnabled(isPullToRefreshEnabled = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +117,7 @@ class OtherViewModelTest : BaseViewModelTest() {
|
||||
private fun createViewModel(
|
||||
state: OtherState? = null,
|
||||
) = OtherViewModel(
|
||||
settingsRepo = settingsRepository,
|
||||
vaultRepo = vaultRepository,
|
||||
savedStateHandle = SavedStateHandle().apply {
|
||||
set("state", state)
|
||||
|
||||
Reference in New Issue
Block a user