mirror of
https://github.com/bitwarden/android.git
synced 2025-03-15 10:48:47 +03:00
BIT-1094: Store default URI match detection type (#747)
This commit is contained in:
parent
45592a7369
commit
8a16672b4d
14 changed files with 283 additions and 39 deletions
|
@ -1,5 +1,6 @@
|
|||
package com.x8bit.bitwarden.data.platform.datasource.disk
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
|
@ -95,6 +96,16 @@ interface SettingsDiskSource {
|
|||
vaultTimeoutAction: VaultTimeoutAction?,
|
||||
)
|
||||
|
||||
/**
|
||||
* Gets the default [UriMatchType] for the given [userId].
|
||||
*/
|
||||
fun getDefaultUriMatchType(userId: String): UriMatchType?
|
||||
|
||||
/**
|
||||
* Stores the given default [uriMatchType] for the given [userId].
|
||||
*/
|
||||
fun storeDefaultUriMatchType(userId: String, uriMatchType: UriMatchType?)
|
||||
|
||||
/**
|
||||
* Gets the current state of the pull to refresh feature for the given [userId].
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.platform.datasource.disk
|
|||
|
||||
import android.content.SharedPreferences
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
|
@ -21,6 +22,7 @@ private const val BLOCKED_AUTOFILL_URIS_KEY = "$BASE_KEY:autofillBlacklistedUris
|
|||
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_ICON_LOADING_KEY = "$BASE_KEY:disableFavicon"
|
||||
private const val APPROVE_PASSWORDLESS_LOGINS_KEY = "$BASE_KEY:approvePasswordlessLogins"
|
||||
|
||||
|
@ -94,6 +96,7 @@ class SettingsDiskSourceImpl(
|
|||
override fun clearData(userId: String) {
|
||||
storeVaultTimeoutInMinutes(userId = userId, vaultTimeoutInMinutes = null)
|
||||
storeVaultTimeoutAction(userId = userId, vaultTimeoutAction = null)
|
||||
storeDefaultUriMatchType(userId = userId, uriMatchType = null)
|
||||
storePullToRefreshEnabled(userId = userId, isPullToRefreshEnabled = null)
|
||||
storeInlineAutofillEnabled(userId = userId, isInlineAutofillEnabled = null)
|
||||
storeBlockedAutofillUris(userId = userId, blockedAutofillUris = null)
|
||||
|
@ -157,6 +160,21 @@ class SettingsDiskSourceImpl(
|
|||
getMutableVaultTimeoutActionFlow(userId = userId).tryEmit(vaultTimeoutAction)
|
||||
}
|
||||
|
||||
override fun getDefaultUriMatchType(userId: String): UriMatchType? =
|
||||
getInt(key = "${DEFAULT_URI_MATCH_TYPE_KEY}_$userId")?.let { storedValue ->
|
||||
UriMatchType.entries.find { it.value == storedValue }
|
||||
}
|
||||
|
||||
override fun storeDefaultUriMatchType(
|
||||
userId: String,
|
||||
uriMatchType: UriMatchType?,
|
||||
) {
|
||||
putInt(
|
||||
key = "${DEFAULT_URI_MATCH_TYPE_KEY}_$userId",
|
||||
value = uriMatchType?.value,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getPullToRefreshEnabled(userId: String): Boolean? =
|
||||
getBoolean(key = "${PULL_TO_REFRESH_KEY}_$userId")
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.x8bit.bitwarden.data.platform.repository
|
||||
|
||||
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
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
|
@ -58,6 +59,12 @@ interface SettingsRepository {
|
|||
*/
|
||||
var vaultTimeoutAction: VaultTimeoutAction
|
||||
|
||||
/**
|
||||
* The default [UriMatchType] for the current user that should be used when matching URIs for
|
||||
* items that have "default" as their chosen type.
|
||||
*/
|
||||
var defaultUriMatchType: UriMatchType
|
||||
|
||||
/**
|
||||
* Whether or not PIN unlocking is enabled for the current user.
|
||||
*/
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
|||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
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
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
|
@ -127,6 +128,21 @@ class SettingsRepositoryImpl(
|
|||
vaultTimeoutAction = value,
|
||||
)
|
||||
}
|
||||
|
||||
override var defaultUriMatchType: UriMatchType
|
||||
get() = activeUserId
|
||||
?.let {
|
||||
settingsDiskSource.getDefaultUriMatchType(userId = it)
|
||||
}
|
||||
?: UriMatchType.DOMAIN
|
||||
set(value) {
|
||||
val userId = activeUserId ?: return
|
||||
settingsDiskSource.storeDefaultUriMatchType(
|
||||
userId = userId,
|
||||
uriMatchType = value,
|
||||
)
|
||||
}
|
||||
|
||||
override val isUnlockWithPinEnabled: Boolean
|
||||
get() = activeUserId
|
||||
?.let { authDiskSource.getEncryptedPin(userId = it) != null }
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package com.x8bit.bitwarden.data.platform.repository.model
|
||||
|
||||
/**
|
||||
* Represents a way to match a known URI against a "test" one.
|
||||
*
|
||||
* The [value] is used for consistent storage purposes.
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
enum class UriMatchType(
|
||||
val value: Int,
|
||||
) {
|
||||
/**
|
||||
* The URIs match if their top-level and second-level domains match.
|
||||
*/
|
||||
DOMAIN(0),
|
||||
|
||||
/**
|
||||
* The URIs match if their hostnames (and ports if specified) match.
|
||||
*/
|
||||
HOST(1),
|
||||
|
||||
/**
|
||||
* The URIs match if the "test" URI starts with the known URI.
|
||||
*/
|
||||
STARTS_WITH(2),
|
||||
|
||||
/**
|
||||
* The URIs match if the "test" URI matches the known URI according to a specified regular
|
||||
* expression for the item.
|
||||
*/
|
||||
REGULAR_EXPRESSION(3),
|
||||
|
||||
/**
|
||||
* The URIs match if they are exactly the same.
|
||||
*/
|
||||
EXACT(4),
|
||||
|
||||
/**
|
||||
* The URIs should never match.
|
||||
*/
|
||||
NEVER(5),
|
||||
}
|
|
@ -29,6 +29,7 @@ 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.UriMatchType
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
|
@ -40,6 +41,7 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenSelectionRow
|
|||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenWideSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.autofill.util.displayLabel
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalIntentManager
|
||||
|
||||
|
@ -193,8 +195,8 @@ fun AutoFillScreen(
|
|||
|
||||
@Composable
|
||||
private fun UriMatchDetectionDialog(
|
||||
selectedUriDetection: AutoFillState.UriDetectionMethod,
|
||||
onDetectionSelect: (AutoFillState.UriDetectionMethod) -> Unit,
|
||||
selectedUriDetection: UriMatchType,
|
||||
onDetectionSelect: (UriMatchType) -> Unit,
|
||||
) {
|
||||
var shouldShowDialog by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
|
@ -205,7 +207,7 @@ private fun UriMatchDetectionDialog(
|
|||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
text = selectedUriDetection.text(),
|
||||
text = selectedUriDetection.displayLabel(),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
@ -216,14 +218,15 @@ private fun UriMatchDetectionDialog(
|
|||
title = stringResource(id = R.string.default_uri_match_detection),
|
||||
onDismissRequest = { shouldShowDialog = false },
|
||||
) {
|
||||
AutoFillState.UriDetectionMethod.values().forEach { option ->
|
||||
val uriMatchTypes = UriMatchType.entries
|
||||
uriMatchTypes.forEach { option ->
|
||||
BitwardenSelectionRow(
|
||||
text = option.text,
|
||||
text = option.displayLabel,
|
||||
isSelected = option == selectedUriDetection,
|
||||
onClick = {
|
||||
shouldShowDialog = false
|
||||
onDetectionSelect(
|
||||
AutoFillState.UriDetectionMethod.values().first { it == option },
|
||||
uriMatchTypes.first { it == option },
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
|
@ -3,8 +3,8 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.autofill
|
|||
import android.os.Parcelable
|
||||
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.UriMatchType
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
|
@ -33,7 +33,7 @@ class AutoFillViewModel @Inject constructor(
|
|||
isAutoFillServicesEnabled = settingsRepository.isAutofillEnabledStateFlow.value,
|
||||
isCopyTotpAutomaticallyEnabled = false,
|
||||
isUseInlineAutoFillEnabled = settingsRepository.isInlineAutofillEnabled,
|
||||
uriDetectionMethod = AutoFillState.UriDetectionMethod.DEFAULT,
|
||||
uriDetectionMethod = settingsRepository.defaultUriMatchType,
|
||||
),
|
||||
) {
|
||||
|
||||
|
@ -96,8 +96,7 @@ class AutoFillViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleUriDetectionMethodSelect(action: AutoFillAction.UriDetectionMethodSelect) {
|
||||
// TODO BIT-1094: Persist selection
|
||||
sendEvent(AutoFillEvent.ShowToast("Not yet implemented.".asText()))
|
||||
settingsRepository.defaultUriMatchType = action.uriDetectionMethod
|
||||
mutableStateFlow.update {
|
||||
it.copy(uriDetectionMethod = action.uriDetectionMethod)
|
||||
}
|
||||
|
@ -125,7 +124,7 @@ data class AutoFillState(
|
|||
val isAutoFillServicesEnabled: Boolean,
|
||||
val isCopyTotpAutomaticallyEnabled: Boolean,
|
||||
val isUseInlineAutoFillEnabled: Boolean,
|
||||
val uriDetectionMethod: UriDetectionMethod,
|
||||
val uriDetectionMethod: UriMatchType,
|
||||
) : Parcelable {
|
||||
|
||||
/**
|
||||
|
@ -134,19 +133,6 @@ data class AutoFillState(
|
|||
*/
|
||||
val canInteractWithInlineAutofillToggle: Boolean
|
||||
get() = isAutoFillServicesEnabled
|
||||
|
||||
/**
|
||||
* A representation of the URI detection methods.
|
||||
*/
|
||||
enum class UriDetectionMethod(val text: Text) {
|
||||
DEFAULT(text = R.string.default_text.asText()),
|
||||
BASE_DOMAIN(text = R.string.base_domain.asText()),
|
||||
HOST(text = R.string.host.asText()),
|
||||
STARTS_WITH(text = R.string.starts_with.asText()),
|
||||
REGULAR_EXPRESSION(text = R.string.reg_ex.asText()),
|
||||
EXACT(text = R.string.exact.asText()),
|
||||
NEVER(text = R.string.never.asText()),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,10 +193,10 @@ sealed class AutoFillAction {
|
|||
) : AutoFillAction()
|
||||
|
||||
/**
|
||||
* User selected a [AutoFillState.UriDetectionMethod].
|
||||
* User selected a [UriMatchType].
|
||||
*/
|
||||
data class UriDetectionMethodSelect(
|
||||
val uriDetectionMethod: AutoFillState.UriDetectionMethod,
|
||||
val uriDetectionMethod: UriMatchType,
|
||||
) : AutoFillAction()
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package com.x8bit.bitwarden.ui.platform.feature.settings.autofill.util
|
||||
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
|
||||
/**
|
||||
* Returns a human-readable display label for the given [UriMatchType].
|
||||
*/
|
||||
val UriMatchType.displayLabel: Text
|
||||
get() = when (this) {
|
||||
UriMatchType.DOMAIN -> R.string.base_domain
|
||||
UriMatchType.HOST -> R.string.host
|
||||
UriMatchType.STARTS_WITH -> R.string.starts_with
|
||||
UriMatchType.REGULAR_EXPRESSION -> R.string.reg_ex
|
||||
UriMatchType.EXACT -> R.string.exact
|
||||
UriMatchType.NEVER -> R.string.never
|
||||
}
|
||||
.asText()
|
|
@ -4,6 +4,7 @@ import androidx.core.content.edit
|
|||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.platform.base.FakeSharedPreferences
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.di.PlatformNetworkModule
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
|
@ -74,6 +75,10 @@ class SettingsDiskSourceTest {
|
|||
userId = userId,
|
||||
vaultTimeoutAction = VaultTimeoutAction.LOCK,
|
||||
)
|
||||
settingsDiskSource.storeDefaultUriMatchType(
|
||||
userId = userId,
|
||||
uriMatchType = UriMatchType.REGULAR_EXPRESSION,
|
||||
)
|
||||
settingsDiskSource.storePullToRefreshEnabled(
|
||||
userId = userId,
|
||||
isPullToRefreshEnabled = true,
|
||||
|
@ -99,6 +104,7 @@ class SettingsDiskSourceTest {
|
|||
|
||||
assertNull(settingsDiskSource.getVaultTimeoutInMinutes(userId = userId))
|
||||
assertNull(settingsDiskSource.getVaultTimeoutAction(userId = userId))
|
||||
assertNull(settingsDiskSource.getDefaultUriMatchType(userId = userId))
|
||||
assertNull(settingsDiskSource.getPullToRefreshEnabled(userId = userId))
|
||||
assertNull(settingsDiskSource.getInlineAutofillEnabled(userId = userId))
|
||||
assertNull(settingsDiskSource.getBlockedAutofillUris(userId = userId))
|
||||
|
@ -379,6 +385,66 @@ class SettingsDiskSourceTest {
|
|||
assertNull(fakeSharedPreferences.getString(vaultTimeoutActionKey, null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDefaultUriMatchType when values are present should pull from SharedPreferences`() {
|
||||
val defaultUriMatchTypeBaseKey = "bwPreferencesStorage:defaultUriMatch"
|
||||
val mockUserId = "mockUserId"
|
||||
val uriMatchType = UriMatchType.REGULAR_EXPRESSION
|
||||
fakeSharedPreferences
|
||||
.edit {
|
||||
putInt(
|
||||
"${defaultUriMatchTypeBaseKey}_$mockUserId",
|
||||
3,
|
||||
)
|
||||
}
|
||||
val actual = settingsDiskSource.getDefaultUriMatchType(userId = mockUserId)
|
||||
assertEquals(
|
||||
uriMatchType,
|
||||
actual,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDefaultUriMatchType when values are absent should return null`() {
|
||||
val mockUserId = "mockUserId"
|
||||
assertNull(settingsDiskSource.getDefaultUriMatchType(userId = mockUserId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storeDefaultUriMatchType for non-null values should update SharedPreferences`() {
|
||||
val defaultUriMatchTypeBaseKey = "bwPreferencesStorage:defaultUriMatch"
|
||||
val mockUserId = "mockUserId"
|
||||
val uriMatchType = UriMatchType.REGULAR_EXPRESSION
|
||||
settingsDiskSource.storeDefaultUriMatchType(
|
||||
userId = mockUserId,
|
||||
uriMatchType = uriMatchType,
|
||||
)
|
||||
val actual = fakeSharedPreferences.getInt(
|
||||
"${defaultUriMatchTypeBaseKey}_$mockUserId",
|
||||
0,
|
||||
)
|
||||
assertEquals(
|
||||
3,
|
||||
actual,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storeDefaultUriMatchType for null values should clear SharedPreferences`() {
|
||||
val defaultUriMatchTypeBaseKey = "bwPreferencesStorage:defaultUriMatch"
|
||||
val mockUserId = "mockUserId"
|
||||
val defaultUriMatchTypeKey = "${defaultUriMatchTypeBaseKey}_$mockUserId"
|
||||
fakeSharedPreferences.edit {
|
||||
putInt(defaultUriMatchTypeKey, 3)
|
||||
}
|
||||
assertTrue(fakeSharedPreferences.contains(defaultUriMatchTypeKey))
|
||||
settingsDiskSource.storeDefaultUriMatchType(
|
||||
userId = mockUserId,
|
||||
uriMatchType = null,
|
||||
)
|
||||
assertFalse(fakeSharedPreferences.contains(defaultUriMatchTypeKey))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPullToRefreshEnabled when values are present should pull from SharedPreferences`() {
|
||||
val pullToRefreshBaseKey = "bwPreferencesStorage:syncOnRefresh"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden.data.platform.datasource.disk.util
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
|
@ -36,7 +37,7 @@ class FakeSettingsDiskSource : SettingsDiskSource {
|
|||
private val storedLastSyncTime = mutableMapOf<String, Instant?>()
|
||||
private val storedVaultTimeoutActions = mutableMapOf<String, VaultTimeoutAction?>()
|
||||
private val storedVaultTimeoutInMinutes = mutableMapOf<String, Int?>()
|
||||
|
||||
private val storedUriMatchTypes = mutableMapOf<String, UriMatchType?>()
|
||||
private val storedPullToRefreshEnabled = mutableMapOf<String, Boolean?>()
|
||||
private val storedInlineAutofillEnabled = mutableMapOf<String, Boolean?>()
|
||||
private val storedBlockedAutofillUris = mutableMapOf<String, List<String>?>()
|
||||
|
@ -74,6 +75,7 @@ class FakeSettingsDiskSource : SettingsDiskSource {
|
|||
override fun clearData(userId: String) {
|
||||
storedVaultTimeoutActions.remove(userId)
|
||||
storedVaultTimeoutInMinutes.remove(userId)
|
||||
storedUriMatchTypes.remove(userId)
|
||||
storedPullToRefreshEnabled.remove(userId)
|
||||
storedInlineAutofillEnabled.remove(userId)
|
||||
storedBlockedAutofillUris.remove(userId)
|
||||
|
@ -124,6 +126,16 @@ class FakeSettingsDiskSource : SettingsDiskSource {
|
|||
getMutableVaultTimeoutActionsFlow(userId = userId).tryEmit(vaultTimeoutAction)
|
||||
}
|
||||
|
||||
override fun getDefaultUriMatchType(userId: String): UriMatchType? =
|
||||
storedUriMatchTypes[userId]
|
||||
|
||||
override fun storeDefaultUriMatchType(
|
||||
userId: String,
|
||||
uriMatchType: UriMatchType?,
|
||||
) {
|
||||
storedUriMatchTypes[userId] = uriMatchType
|
||||
}
|
||||
|
||||
override fun getPullToRefreshEnabled(userId: String): Boolean? =
|
||||
storedPullToRefreshEnabled[userId]
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
|
|||
import com.x8bit.bitwarden.data.platform.datasource.disk.util.FakeSettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.AppForegroundState
|
||||
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
|
||||
import com.x8bit.bitwarden.data.platform.util.asSuccess
|
||||
|
@ -376,6 +377,39 @@ class SettingsRepositoryTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `defaultUriMatchType should pull from and update SettingsDiskSource`() {
|
||||
fakeAuthDiskSource.userState = null
|
||||
assertEquals(
|
||||
UriMatchType.DOMAIN,
|
||||
settingsRepository.defaultUriMatchType,
|
||||
)
|
||||
|
||||
val userId = "userId"
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
|
||||
// Updates to the disk source change the repository value
|
||||
UriMatchType.entries.forEach { uriMatchType ->
|
||||
fakeSettingsDiskSource.storeDefaultUriMatchType(
|
||||
userId = userId,
|
||||
uriMatchType = uriMatchType,
|
||||
)
|
||||
assertEquals(
|
||||
uriMatchType,
|
||||
settingsRepository.defaultUriMatchType,
|
||||
)
|
||||
}
|
||||
|
||||
// Updates to the repository value change the disk source
|
||||
UriMatchType.entries.forEach { uriMatchType ->
|
||||
settingsRepository.defaultUriMatchType = uriMatchType
|
||||
assertEquals(
|
||||
uriMatchType,
|
||||
fakeSettingsDiskSource.getDefaultUriMatchType(userId = userId),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `isUnlockWithPinEnabled should return a value that tracks the existence of an encrypted PIN for the current user`() {
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.compose.ui.test.onNodeWithContentDescription
|
|||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
|
@ -246,16 +247,16 @@ class AutoFillScreenTest : BaseComposeTest() {
|
|||
@Test
|
||||
fun `default URI match detection add login should be updated on or off according to state`() {
|
||||
composeTestRule
|
||||
.onNodeWithText("Default")
|
||||
.onNodeWithText("Base domain")
|
||||
.assertExists()
|
||||
composeTestRule
|
||||
.onNodeWithText("Starts with")
|
||||
.assertDoesNotExist()
|
||||
mutableStateFlow.update {
|
||||
it.copy(uriDetectionMethod = AutoFillState.UriDetectionMethod.STARTS_WITH)
|
||||
it.copy(uriDetectionMethod = UriMatchType.STARTS_WITH)
|
||||
}
|
||||
composeTestRule
|
||||
.onNodeWithText("Default")
|
||||
.onNodeWithText("Base domain")
|
||||
.assertDoesNotExist()
|
||||
composeTestRule
|
||||
.onNodeWithText("Starts with")
|
||||
|
@ -295,5 +296,5 @@ private val DEFAULT_STATE: AutoFillState = AutoFillState(
|
|||
isAutoFillServicesEnabled = false,
|
||||
isCopyTotpAutomaticallyEnabled = false,
|
||||
isUseInlineAutoFillEnabled = false,
|
||||
uriDetectionMethod = AutoFillState.UriDetectionMethod.DEFAULT,
|
||||
uriDetectionMethod = UriMatchType.DOMAIN,
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.autofill
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import io.mockk.every
|
||||
|
@ -21,6 +22,8 @@ class AutoFillViewModelTest : BaseViewModelTest() {
|
|||
private val settingsRepository: SettingsRepository = mockk() {
|
||||
every { isInlineAutofillEnabled } returns true
|
||||
every { isInlineAutofillEnabled = any() } just runs
|
||||
every { defaultUriMatchType } returns UriMatchType.DOMAIN
|
||||
every { defaultUriMatchType = any() } just runs
|
||||
every { isAutofillEnabledStateFlow } returns mutableIsAutofillEnabledStateFlow
|
||||
every { disableAutofill() } just runs
|
||||
}
|
||||
|
@ -36,7 +39,7 @@ class AutoFillViewModelTest : BaseViewModelTest() {
|
|||
mutableIsAutofillEnabledStateFlow.value = true
|
||||
val state = DEFAULT_STATE.copy(
|
||||
isAutoFillServicesEnabled = true,
|
||||
uriDetectionMethod = AutoFillState.UriDetectionMethod.REGULAR_EXPRESSION,
|
||||
uriDetectionMethod = UriMatchType.REGULAR_EXPRESSION,
|
||||
)
|
||||
val viewModel = createViewModel(state = state)
|
||||
assertEquals(state, viewModel.stateFlow.value)
|
||||
|
@ -140,17 +143,15 @@ class AutoFillViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `on UriDetectionMethodSelect should emit ShowToast`() = runTest {
|
||||
fun `on UriDetectionMethodSelect should update the state and save the new value to settings`() {
|
||||
val viewModel = createViewModel()
|
||||
val method = AutoFillState.UriDetectionMethod.EXACT
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AutoFillAction.UriDetectionMethodSelect(method))
|
||||
assertEquals(AutoFillEvent.ShowToast("Not yet implemented.".asText()), awaitItem())
|
||||
}
|
||||
val method = UriMatchType.EXACT
|
||||
viewModel.trySendAction(AutoFillAction.UriDetectionMethodSelect(method))
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(uriDetectionMethod = method),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify { settingsRepository.defaultUriMatchType = method }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -175,5 +176,5 @@ private val DEFAULT_STATE: AutoFillState = AutoFillState(
|
|||
isAutoFillServicesEnabled = false,
|
||||
isCopyTotpAutomaticallyEnabled = false,
|
||||
isUseInlineAutoFillEnabled = true,
|
||||
uriDetectionMethod = AutoFillState.UriDetectionMethod.DEFAULT,
|
||||
uriDetectionMethod = UriMatchType.DOMAIN,
|
||||
)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package com.x8bit.bitwarden.ui.platform.feature.settings.autofill.util
|
||||
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class UriMatchTypeExtensionsTest {
|
||||
@Test
|
||||
fun `displayLabel should return the correct value for each type`() {
|
||||
mapOf(
|
||||
UriMatchType.DOMAIN to R.string.base_domain.asText(),
|
||||
UriMatchType.HOST to R.string.host.asText(),
|
||||
UriMatchType.STARTS_WITH to R.string.starts_with.asText(),
|
||||
UriMatchType.REGULAR_EXPRESSION to R.string.reg_ex.asText(),
|
||||
UriMatchType.EXACT to R.string.exact.asText(),
|
||||
UriMatchType.NEVER to R.string.never.asText(),
|
||||
)
|
||||
.forEach { (type, label) ->
|
||||
assertEquals(
|
||||
label,
|
||||
type.displayLabel,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue