BIT-713: Adding SimpleLogin service UI (#460)

This commit is contained in:
joshua-livefront 2023-12-29 16:07:09 -05:00 committed by Álison Fernandes
parent 3142a640ce
commit 17b50d96f1
4 changed files with 190 additions and 2 deletions

View file

@ -890,7 +890,14 @@ private fun ColumnScope.ForwardedEmailAliasTypeContent(
}
is ServiceType.SimpleLogin -> {
// TODO: SimpleLogin Service Implementation (BIT-713)
BitwardenPasswordField(
label = stringResource(id = R.string.api_key_required_parenthesis),
value = usernameTypeState.selectedServiceType.apiKey,
onValueChange = forwardedEmailAliasHandlers.onSimpleLoginApiKeyTextChange,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
}
null -> {
@ -1209,6 +1216,7 @@ private class PassphraseHandlers(
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
@Suppress("LongParameterList")
private class ForwardedEmailAliasHandlers(
val onServiceChange: (ServiceTypeOption) -> Unit,
val onAddyIoAccessTokenTextChange: (String) -> Unit,
@ -1216,6 +1224,7 @@ private class ForwardedEmailAliasHandlers(
val onDuckDuckGoApiKeyTextChange: (String) -> Unit,
val onFastMailApiKeyTextChange: (String) -> Unit,
val onFirefoxRelayAccessTokenTextChange: (String) -> Unit,
val onSimpleLoginApiKeyTextChange: (String) -> Unit,
) {
companion object {
@Suppress("LongMethod")
@ -1298,6 +1307,19 @@ private class ForwardedEmailAliasHandlers(
),
)
},
onSimpleLoginApiKeyTextChange = { newApiKey ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.SimpleLogin
.ApiKeyTextChange(
apiKey = newApiKey,
),
)
},
)
}
}

View file

@ -71,7 +71,7 @@ class GeneratorViewModel @Inject constructor(
}
}
@Suppress("MaxLineLength")
@Suppress("MaxLineLength", "LongMethod")
override fun handleAction(action: GeneratorAction) {
when (action) {
is GeneratorAction.PasswordHistoryClick -> {
@ -134,6 +134,10 @@ class GeneratorViewModel @Inject constructor(
handleFirefoxRelayTextInputChange(action)
}
is GeneratorAction.MainType.Username.UsernameType.ForwardedEmailAlias.SimpleLogin.ApiKeyTextChange -> {
handleSimpleLoginTextInputChange(action)
}
is GeneratorAction.MainType.Username.UsernameType.PlusAddressedEmail.EmailTextChange -> {
handlePlusAddressedEmailTextInputChange(action)
}
@ -734,6 +738,25 @@ class GeneratorViewModel @Inject constructor(
//endregion FirefoxRelay Service Specific Handlers
//region SimpleLogin Service Specific Handlers
private fun handleSimpleLoginTextInputChange(
action: GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.SimpleLogin
.ApiKeyTextChange,
) {
updateSimpleLoginServiceType { simpleLoginServiceType ->
val newApiKey = action.apiKey
simpleLoginServiceType.copy(apiKey = newApiKey)
}
}
//endregion SimpleLogin Service Specific Handlers
//region Plus Addressed Email Specific Handlers
private fun handlePlusAddressedEmailTextInputChange(
@ -988,6 +1011,30 @@ class GeneratorViewModel @Inject constructor(
}
}
private inline fun updateSimpleLoginServiceType(
crossinline block: (SimpleLogin) -> SimpleLogin,
) {
updateGeneratorMainTypeUsername { currentUsernameType ->
if (currentUsernameType.selectedType !is ForwardedEmailAlias) {
return@updateGeneratorMainTypeUsername currentUsernameType
}
val currentServiceType = (currentUsernameType.selectedType).selectedServiceType
if (currentServiceType !is SimpleLogin) {
return@updateGeneratorMainTypeUsername currentUsernameType
}
val updatedServiceType = block(currentServiceType)
currentUsernameType.copy(
selectedType = ForwardedEmailAlias(
selectedServiceType = updatedServiceType,
obfuscatedText = currentUsernameType.selectedType.obfuscatedText,
),
)
}
}
private inline fun updatePlusAddressedEmailType(
crossinline block: (PlusAddressedEmail) -> PlusAddressedEmail,
) {
@ -1696,6 +1743,19 @@ sealed class GeneratorAction {
*/
data class AccessTokenTextChange(val accessToken: String) : FirefoxRelay()
}
/**
* Represents actions specifically related to the SimpleLogin service.
*/
sealed class SimpleLogin : ForwardedEmailAlias() {
/**
* Fired when the api key input text is changed.
*
* @property apiKey The new api key text.
*/
data class ApiKeyTextChange(val apiKey: String) : SimpleLogin()
}
}
/**

View file

@ -1141,6 +1141,46 @@ class GeneratorScreenTest : BaseComposeTest() {
//endregion FirefoxRelay Service Type Tests
//region SimpleLogin Service Type Tests
@Suppress("MaxLineLength")
@Test
fun `in Username_ForwardedEmailAlias_SimpleLogin state, updating api key text input should send ApiKeyTextChange action`() {
updateState(
GeneratorState(
generatedText = "Placeholder",
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = GeneratorState
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceType
.SimpleLogin(),
),
),
),
)
val newApiKey = "apiKey"
composeTestRule
.onNodeWithText("API key (required)")
.performScrollTo()
.performTextInput(newApiKey)
verify {
viewModel.trySendAction(
GeneratorAction.MainType.Username.UsernameType.ForwardedEmailAlias.SimpleLogin.ApiKeyTextChange(
apiKey = newApiKey,
),
)
}
}
//endregion SimpleLogin Service Type Tests
//region Username Plus Addressed Email Tests
@Suppress("MaxLineLength")

View file

@ -43,6 +43,9 @@ class GeneratorViewModelTest : BaseViewModelTest() {
private val initialFirefoxRelay = createFirefoxRelayState()
private val firefoxRelaySavedStateHandle = createSavedStateHandleWithState(initialFirefoxRelay)
private val initialSimpleLogin = createSimpleLoginState()
private val simpleLoginSavedStateHandle = createSavedStateHandleWithState(initialSimpleLogin)
private val initialCatchAllEmailState = createCatchAllEmailState()
private val catchAllEmailSavedStateHandle =
createSavedStateHandleWithState(initialCatchAllEmailState)
@ -1175,6 +1178,51 @@ class GeneratorViewModelTest : BaseViewModelTest() {
}
}
@Nested
inner class SimpleLoginActions {
private val defaultSimpleLoginState = createSimpleLoginState()
private lateinit var viewModel: GeneratorViewModel
@BeforeEach
fun setup() {
viewModel = GeneratorViewModel(simpleLoginSavedStateHandle, fakeGeneratorRepository)
}
@Test
fun `ApiKeyTextChange should update api key text correctly`() = runTest {
val newApiKey = "newApiKey"
val action = GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.SimpleLogin
.ApiKeyTextChange(
apiKey = newApiKey,
)
viewModel.actionChannel.trySend(action)
val expectedState = defaultSimpleLoginState.copy(
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = GeneratorState
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceType
.SimpleLogin(
apiKey = newApiKey,
),
),
),
)
assertEquals(expectedState, viewModel.stateFlow.value)
}
}
@Nested
inner class PlusAddressedEmailActions {
private val defaultPlusAddressedEmailState = createPlusAddressedEmailState()
@ -1454,6 +1502,24 @@ class GeneratorViewModelTest : BaseViewModelTest() {
),
)
private fun createSimpleLoginState(
generatedText: String = "defaultSimpleLogin",
): GeneratorState =
GeneratorState(
generatedText = generatedText,
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = GeneratorState
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceType
.SimpleLogin(),
),
),
)
private fun createPlusAddressedEmailState(
generatedText: String = "defaultPlusAddressedEmail",
email: String = "defaultEmail",