BIT-1092: Store and expose value for disabling autofill save prompt (#763)

This commit is contained in:
Brian Yencho 2024-01-24 16:46:53 -06:00 committed by Álison Fernandes
parent d8ceedd90b
commit 7a416de9c9
9 changed files with 134 additions and 8 deletions

View file

@ -106,6 +106,20 @@ interface SettingsDiskSource {
*/
fun storeDefaultUriMatchType(userId: String, uriMatchType: UriMatchType?)
/**
* Gets the value for whether or not the autofill save prompt should be disabled for the
* given [userId].
*/
fun getAutofillSavePromptDisabled(userId: String): Boolean?
/**
* Stores the given [isAutofillSavePromptDisabled] for the given [userId].
*/
fun storeAutofillSavePromptDisabled(
userId: String,
isAutofillSavePromptDisabled: Boolean?,
)
/**
* Gets the current state of the pull to refresh feature for the given [userId].
*/

View file

@ -23,6 +23,7 @@ private const val VAULT_LAST_SYNC_TIME = "$BASE_KEY:vaultLastSyncTime"
private const val VAULT_TIMEOUT_ACTION_KEY = "$BASE_KEY:vaultTimeoutAction"
private const val VAULT_TIME_IN_MINUTES_KEY = "$BASE_KEY:vaultTimeout"
private const val DEFAULT_URI_MATCH_TYPE_KEY = "$BASE_KEY:defaultUriMatch"
private const val DISABLE_AUTOFILL_SAVE_PROMPT_KEY = "$BASE_KEY:autofillDisableSavePrompt"
private const val DISABLE_ICON_LOADING_KEY = "$BASE_KEY:disableFavicon"
private const val APPROVE_PASSWORDLESS_LOGINS_KEY = "$BASE_KEY:approvePasswordlessLogins"
@ -97,6 +98,7 @@ class SettingsDiskSourceImpl(
storeVaultTimeoutInMinutes(userId = userId, vaultTimeoutInMinutes = null)
storeVaultTimeoutAction(userId = userId, vaultTimeoutAction = null)
storeDefaultUriMatchType(userId = userId, uriMatchType = null)
storeAutofillSavePromptDisabled(userId = userId, isAutofillSavePromptDisabled = null)
storePullToRefreshEnabled(userId = userId, isPullToRefreshEnabled = null)
storeInlineAutofillEnabled(userId = userId, isInlineAutofillEnabled = null)
storeBlockedAutofillUris(userId = userId, blockedAutofillUris = null)
@ -175,6 +177,19 @@ class SettingsDiskSourceImpl(
)
}
override fun getAutofillSavePromptDisabled(userId: String): Boolean? =
getBoolean(key = "${DISABLE_AUTOFILL_SAVE_PROMPT_KEY}_$userId")
override fun storeAutofillSavePromptDisabled(
userId: String,
isAutofillSavePromptDisabled: Boolean?,
) {
putBoolean(
key = "${DISABLE_AUTOFILL_SAVE_PROMPT_KEY}_$userId",
value = isAutofillSavePromptDisabled,
)
}
override fun getPullToRefreshEnabled(userId: String): Boolean? =
getBoolean(key = "${PULL_TO_REFRESH_KEY}_$userId")

View file

@ -75,6 +75,11 @@ interface SettingsRepository {
*/
var isInlineAutofillEnabled: Boolean
/**
* Whether or not the autofill save prompt is disabled for the current user.
*/
var isAutofillSavePromptDisabled: Boolean
/**
* A list of blocked autofill URI's for the current user.
*/

View file

@ -163,6 +163,18 @@ class SettingsRepositoryImpl(
)
}
override var isAutofillSavePromptDisabled: Boolean
get() = activeUserId
?.let { settingsDiskSource.getAutofillSavePromptDisabled(userId = it) }
?: false
set(value) {
val userId = activeUserId ?: return
settingsDiskSource.storeAutofillSavePromptDisabled(
userId = userId,
isAutofillSavePromptDisabled = value,
)
}
override var blockedAutofillUris: List<String>
get() = activeUserId
?.let { settingsDiskSource.getBlockedAutofillUris(userId = it) }

View file

@ -29,7 +29,7 @@ class AutoFillViewModel @Inject constructor(
) : BaseViewModel<AutoFillState, AutoFillEvent, AutoFillAction>(
initialState = savedStateHandle[KEY_STATE]
?: AutoFillState(
isAskToAddLoginEnabled = false,
isAskToAddLoginEnabled = !settingsRepository.isAutofillSavePromptDisabled,
isAutoFillServicesEnabled = settingsRepository.isAutofillEnabledStateFlow.value,
isCopyTotpAutomaticallyEnabled = false,
isUseInlineAutoFillEnabled = settingsRepository.isInlineAutofillEnabled,
@ -65,8 +65,7 @@ class AutoFillViewModel @Inject constructor(
}
private fun handleAskToAddLoginClick(action: AutoFillAction.AskToAddLoginClick) {
// TODO BIT-1092: Persist selection
sendEvent(AutoFillEvent.ShowToast("Not yet implemented.".asText()))
settingsRepository.isAutofillSavePromptDisabled = !action.isEnabled
mutableStateFlow.update { it.copy(isAskToAddLoginEnabled = action.isEnabled) }
}

View file

@ -16,6 +16,7 @@ import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.time.Instant
@Suppress("LargeClass")
class SettingsDiskSourceTest {
private val fakeSharedPreferences = FakeSharedPreferences()
private val json = PlatformNetworkModule.providesJson()
@ -79,6 +80,10 @@ class SettingsDiskSourceTest {
userId = userId,
uriMatchType = UriMatchType.REGULAR_EXPRESSION,
)
settingsDiskSource.storeAutofillSavePromptDisabled(
userId = userId,
isAutofillSavePromptDisabled = true,
)
settingsDiskSource.storePullToRefreshEnabled(
userId = userId,
isPullToRefreshEnabled = true,
@ -105,6 +110,7 @@ class SettingsDiskSourceTest {
assertNull(settingsDiskSource.getVaultTimeoutInMinutes(userId = userId))
assertNull(settingsDiskSource.getVaultTimeoutAction(userId = userId))
assertNull(settingsDiskSource.getDefaultUriMatchType(userId = userId))
assertNull(settingsDiskSource.getAutofillSavePromptDisabled(userId = userId))
assertNull(settingsDiskSource.getPullToRefreshEnabled(userId = userId))
assertNull(settingsDiskSource.getInlineAutofillEnabled(userId = userId))
assertNull(settingsDiskSource.getBlockedAutofillUris(userId = userId))
@ -445,6 +451,50 @@ class SettingsDiskSourceTest {
assertFalse(fakeSharedPreferences.contains(defaultUriMatchTypeKey))
}
@Suppress("MaxLineLength")
@Test
fun `getAutofillSavePromptDisabled when values are present should pull from SharedPreferences`() {
val disableAutofillSavePromptBaseKey = "bwPreferencesStorage:autofillDisableSavePrompt"
val mockUserId = "mockUserId"
val disableAutofillSavePromptKey = "${disableAutofillSavePromptBaseKey}_$mockUserId"
fakeSharedPreferences
.edit {
putBoolean(disableAutofillSavePromptKey, true)
}
assertEquals(true, settingsDiskSource.getAutofillSavePromptDisabled(userId = mockUserId))
}
@Test
fun `getAutofillSavePromptDisabled when values are absent should return null`() {
val mockUserId = "mockUserId"
assertNull(settingsDiskSource.getAutofillSavePromptDisabled(userId = mockUserId))
}
@Test
fun `storeAutofillSavePromptDisabled for non-null values should update SharedPreferences`() {
val disableAutofillSavePromptBaseKey = "bwPreferencesStorage:autofillDisableSavePrompt"
val mockUserId = "mockUserId"
val disableAutofillSavePromptKey = "${disableAutofillSavePromptBaseKey}_$mockUserId"
settingsDiskSource.storeAutofillSavePromptDisabled(
userId = mockUserId,
isAutofillSavePromptDisabled = true,
)
assertTrue(fakeSharedPreferences.getBoolean(disableAutofillSavePromptKey, false))
}
@Test
fun `storeAutofillSavePromptDisabled for null values should clear SharedPreferences`() {
val disableAutofillSavePromptBaseKey = "bwPreferencesStorage:autofillDisableSavePrompt"
val mockUserId = "mockUserId"
val disableAutofillSavePromptKey = "${disableAutofillSavePromptBaseKey}_$mockUserId"
fakeSharedPreferences.edit { putBoolean(disableAutofillSavePromptKey, false) }
settingsDiskSource.storeAutofillSavePromptDisabled(
userId = mockUserId,
isAutofillSavePromptDisabled = null,
)
assertFalse(fakeSharedPreferences.contains(disableAutofillSavePromptKey))
}
@Test
fun `getPullToRefreshEnabled when values are present should pull from SharedPreferences`() {
val pullToRefreshBaseKey = "bwPreferencesStorage:syncOnRefresh"

View file

@ -38,6 +38,7 @@ class FakeSettingsDiskSource : SettingsDiskSource {
private val storedVaultTimeoutActions = mutableMapOf<String, VaultTimeoutAction?>()
private val storedVaultTimeoutInMinutes = mutableMapOf<String, Int?>()
private val storedUriMatchTypes = mutableMapOf<String, UriMatchType?>()
private val storedDisableAutofillSavePrompt = mutableMapOf<String, Boolean?>()
private val storedPullToRefreshEnabled = mutableMapOf<String, Boolean?>()
private val storedInlineAutofillEnabled = mutableMapOf<String, Boolean?>()
private val storedBlockedAutofillUris = mutableMapOf<String, List<String>?>()
@ -76,6 +77,7 @@ class FakeSettingsDiskSource : SettingsDiskSource {
storedVaultTimeoutActions.remove(userId)
storedVaultTimeoutInMinutes.remove(userId)
storedUriMatchTypes.remove(userId)
storedDisableAutofillSavePrompt.remove(userId)
storedPullToRefreshEnabled.remove(userId)
storedInlineAutofillEnabled.remove(userId)
storedBlockedAutofillUris.remove(userId)
@ -136,6 +138,16 @@ class FakeSettingsDiskSource : SettingsDiskSource {
storedUriMatchTypes[userId] = uriMatchType
}
override fun getAutofillSavePromptDisabled(userId: String): Boolean? =
storedDisableAutofillSavePrompt[userId]
override fun storeAutofillSavePromptDisabled(
userId: String,
isAutofillSavePromptDisabled: Boolean?,
) {
storedDisableAutofillSavePrompt[userId] = isAutofillSavePromptDisabled
}
override fun getPullToRefreshEnabled(userId: String): Boolean? =
storedPullToRefreshEnabled[userId]

View file

@ -443,6 +443,24 @@ class SettingsRepositoryTest {
assertTrue(fakeSettingsDiskSource.getInlineAutofillEnabled(userId = userId)!!)
}
@Test
fun `isAutofillSavePromptDisabled should pull from and update SettingsDiskSource`() {
val userId = "userId"
fakeAuthDiskSource.userState = MOCK_USER_STATE
assertFalse(settingsRepository.isAutofillSavePromptDisabled)
// Updates to the disk source change the repository value.
fakeSettingsDiskSource.storeAutofillSavePromptDisabled(
userId = userId,
isAutofillSavePromptDisabled = true,
)
assertTrue(settingsRepository.isAutofillSavePromptDisabled)
// Updates to the repository change the disk source value
settingsRepository.isAutofillSavePromptDisabled = false
assertFalse(fakeSettingsDiskSource.getAutofillSavePromptDisabled(userId = userId)!!)
}
@Test
fun `blockedAutofillUris should pull from and update SettingsDiskSource`() {
val userId = "userId"

View file

@ -22,6 +22,8 @@ class AutoFillViewModelTest : BaseViewModelTest() {
private val settingsRepository: SettingsRepository = mockk() {
every { isInlineAutofillEnabled } returns true
every { isInlineAutofillEnabled = any() } just runs
every { isAutofillSavePromptDisabled } returns true
every { isAutofillSavePromptDisabled = any() } just runs
every { defaultUriMatchType } returns UriMatchType.DOMAIN
every { defaultUriMatchType = any() } just runs
every { isAutofillEnabledStateFlow } returns mutableIsAutofillEnabledStateFlow
@ -66,16 +68,15 @@ class AutoFillViewModelTest : BaseViewModelTest() {
}
@Test
fun `on AskToAddLoginClick should emit ShowToast`() = runTest {
fun `on AskToAddLoginClick should update the state and save the new value to settings`() {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(AutoFillAction.AskToAddLoginClick(true))
assertEquals(AutoFillEvent.ShowToast("Not yet implemented.".asText()), awaitItem())
}
viewModel.trySendAction(AutoFillAction.AskToAddLoginClick(true))
assertEquals(
DEFAULT_STATE.copy(isAskToAddLoginEnabled = true),
viewModel.stateFlow.value,
)
// The UI enables the value, so the value gets flipped to save it as a "disabled" value.
verify { settingsRepository.isAutofillSavePromptDisabled = false }
}
@Test