BIT-1196: Adding ui for FirefoxRelay service (#449)

This commit is contained in:
joshua-livefront 2023-12-28 17:26:17 -05:00 committed by Álison Fernandes
parent 5ac493fa89
commit 3c29dccf62
4 changed files with 200 additions and 1 deletions

View file

@ -853,7 +853,14 @@ private fun ColumnScope.ForwardedEmailAliasTypeContent(
}
is ServiceType.FirefoxRelay -> {
// TODO: FirefoxRelay Service Implementation (BIT-1196)
BitwardenPasswordField(
label = stringResource(id = R.string.api_access_token),
value = usernameTypeState.selectedServiceType.apiAccessToken,
onValueChange = forwardedEmailAliasHandlers.onFirefoxRelayAccessTokenTextChange,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
}
is ServiceType.SimpleLogin -> {
@ -1179,6 +1186,7 @@ private class PassphraseHandlers(
private class ForwardedEmailAliasHandlers(
val onServiceChange: (ServiceTypeOption) -> Unit,
val onDuckDuckGoApiKeyTextChange: (String) -> Unit,
val onFirefoxRelayAccessTokenTextChange: (String) -> Unit,
) {
companion object {
fun create(viewModel: GeneratorViewModel): ForwardedEmailAliasHandlers {
@ -1208,6 +1216,20 @@ private class ForwardedEmailAliasHandlers(
),
)
},
onFirefoxRelayAccessTokenTextChange = { newAccessToken ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.FirefoxRelay
.AccessTokenTextChange(
accessToken = newAccessToken,
),
)
},
)
}
}

View file

@ -23,6 +23,7 @@ import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Us
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.CatchAllEmail
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceType.DuckDuckGo
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceType.FirefoxRelay
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceType
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.PlusAddressedEmail
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.RandomWord
@ -118,6 +119,10 @@ class GeneratorViewModel @Inject constructor(
handleDuckDuckGoTextInputChange(action)
}
is GeneratorAction.MainType.Username.UsernameType.ForwardedEmailAlias.FirefoxRelay.AccessTokenTextChange -> {
handleFirefoxRelayTextInputChange(action)
}
is GeneratorAction.MainType.Username.UsernameType.PlusAddressedEmail.EmailTextChange -> {
handlePlusAddressedEmailTextInputChange(action)
}
@ -599,6 +604,8 @@ class GeneratorViewModel @Inject constructor(
//endregion Forwarded Email Alias Specific Handlers
//region DuckDuckGo Service Specific Handlers
private fun handleDuckDuckGoTextInputChange(
action: GeneratorAction
.MainType
@ -614,6 +621,27 @@ class GeneratorViewModel @Inject constructor(
}
}
//endregion DuckDuckGo Service Specific Handlers
//region FirefoxRelay Service Specific Handlers
private fun handleFirefoxRelayTextInputChange(
action: GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.FirefoxRelay
.AccessTokenTextChange,
) {
updateFirefoxRelayServiceType { firefoxRelayServiceType ->
val newAccessToken = action.accessToken
firefoxRelayServiceType.copy(apiAccessToken = newAccessToken)
}
}
//endregion FirefoxRelay Service Specific Handlers
//region Plus Addressed Email Specific Handlers
private fun handlePlusAddressedEmailTextInputChange(
@ -796,6 +824,30 @@ class GeneratorViewModel @Inject constructor(
}
}
private inline fun updateFirefoxRelayServiceType(
crossinline block: (FirefoxRelay) -> FirefoxRelay,
) {
updateGeneratorMainTypeUsername { currentUsernameType ->
if (currentUsernameType.selectedType !is ForwardedEmailAlias) {
return@updateGeneratorMainTypeUsername currentUsernameType
}
val currentServiceType = (currentUsernameType.selectedType).selectedServiceType
if (currentServiceType !is FirefoxRelay) {
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,
) {
@ -1458,6 +1510,19 @@ sealed class GeneratorAction {
*/
data class ApiKeyTextChange(val apiKey: String) : DuckDuckGo()
}
/**
* Represents actions specifically related to the FirefoxRelay service.
*/
sealed class FirefoxRelay : ForwardedEmailAlias() {
/**
* Fired when the access token input text is changed.
*
* @property accessToken The new access token text.
*/
data class AccessTokenTextChange(val accessToken: String) : FirefoxRelay()
}
}
/**

View file

@ -967,6 +967,52 @@ class GeneratorScreenTest : BaseComposeTest() {
//endregion DuckDuckGo Service Type Tests
//region FirefoxRelay Service Type Tests
@Suppress("MaxLineLength")
@Test
fun `in Username_ForwardedEmailAlias_FirefoxRelay state, updating access token text input should send AccessTokenTextChange action`() {
updateState(
GeneratorState(
generatedText = "Placeholder",
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = GeneratorState
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceType
.FirefoxRelay(),
),
),
),
)
val newAccessToken = "accessToken"
composeTestRule
.onNodeWithText("API access token")
.performScrollTo()
.performTextInput(newAccessToken)
verify {
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.FirefoxRelay
.AccessTokenTextChange(
accessToken = newAccessToken,
),
)
}
}
//endregion FirefoxRelay Service Type Tests
//region Username Plus Addressed Email Tests
@Suppress("MaxLineLength")

View file

@ -34,6 +34,9 @@ class GeneratorViewModelTest : BaseViewModelTest() {
private val initialDuckDuckGoState = createDuckDuckGoState()
private val duckDuckGoSavedStateHandle = createSavedStateHandleWithState(initialDuckDuckGoState)
private val initialFirefoxRelay = createFirefoxRelayState()
private val firefoxRelaySavedStateHandle = createSavedStateHandleWithState(initialFirefoxRelay)
private val initialCatchAllEmailState = createCatchAllEmailState()
private val catchAllEmailSavedStateHandle =
createSavedStateHandleWithState(initialCatchAllEmailState)
@ -998,6 +1001,51 @@ class GeneratorViewModelTest : BaseViewModelTest() {
}
}
@Nested
inner class FirefoxRelayActions {
private val defaultFirefoxRelayState = createFirefoxRelayState()
private lateinit var viewModel: GeneratorViewModel
@BeforeEach
fun setup() {
viewModel = GeneratorViewModel(firefoxRelaySavedStateHandle, fakeGeneratorRepository)
}
@Test
fun `AccessTokenTextChange should update access token text correctly`() = runTest {
val newAccessToken = "newAccessToken"
val action = GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.FirefoxRelay
.AccessTokenTextChange(
accessToken = newAccessToken,
)
viewModel.actionChannel.trySend(action)
val expectedState = defaultFirefoxRelayState.copy(
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = GeneratorState
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceType
.FirefoxRelay(
apiAccessToken = newAccessToken,
),
),
),
)
assertEquals(expectedState, viewModel.stateFlow.value)
}
}
@Nested
inner class PlusAddressedEmailActions {
private val defaultPlusAddressedEmailState = createPlusAddressedEmailState()
@ -1223,6 +1271,24 @@ class GeneratorViewModelTest : BaseViewModelTest() {
),
)
private fun createFirefoxRelayState(
generatedText: String = "defaultFirefoxRelay",
): GeneratorState =
GeneratorState(
generatedText = generatedText,
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = GeneratorState
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceType
.FirefoxRelay(),
),
),
)
private fun createPlusAddressedEmailState(
generatedText: String = "defaultPlusAddressedEmail",
email: String = "defaultEmail",