mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
BIT-810: Implement resend notification (#803)
This commit is contained in:
parent
a7e393e325
commit
e5bfdd0fa7
4 changed files with 61 additions and 18 deletions
|
@ -4,12 +4,14 @@ import android.widget.Toast
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.defaultMinSize
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.imePadding
|
import androidx.compose.foundation.layout.imePadding
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
@ -198,14 +200,28 @@ private fun LoginWithDeviceScreenContent(
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
BitwardenClickableText(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp)
|
.defaultMinSize(minHeight = 32.dp)
|
||||||
.semantics { testTag = "ResendNotificationButton" }
|
.align(Alignment.Start),
|
||||||
.fillMaxWidth(),
|
) {
|
||||||
label = stringResource(id = R.string.resend_notification),
|
if (state.isResendNotificationLoading) {
|
||||||
onClick = onResendNotificationClick,
|
CircularProgressIndicator(
|
||||||
)
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 64.dp)
|
||||||
|
.size(size = 16.dp),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
BitwardenClickableText(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.semantics { testTag = "ResendNotificationButton" }
|
||||||
|
.fillMaxWidth(),
|
||||||
|
label = stringResource(id = R.string.resend_notification),
|
||||||
|
onClick = onResendNotificationClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,7 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleResendNotificationClicked() {
|
private fun handleResendNotificationClicked() {
|
||||||
// TODO BIT-810: implement Resend Notification button
|
sendNewAuthRequest()
|
||||||
sendEvent(LoginWithDeviceEvent.ShowToast("Not yet implemented."))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleViewAllLogInOptionsClicked() {
|
private fun handleViewAllLogInOptionsClicked() {
|
||||||
|
@ -69,6 +68,7 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||||
it.copy(
|
it.copy(
|
||||||
viewState = LoginWithDeviceState.ViewState.Content(
|
viewState = LoginWithDeviceState.ViewState.Content(
|
||||||
fingerprintPhrase = action.result.authRequest.fingerprint,
|
fingerprintPhrase = action.result.authRequest.fingerprint,
|
||||||
|
isResendNotificationLoading = false,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,7 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendNewAuthRequest() {
|
private fun sendNewAuthRequest() {
|
||||||
|
setIsResendNotificationLoading(true)
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
trySendAction(
|
trySendAction(
|
||||||
LoginWithDeviceAction.Internal.NewAuthRequestResultReceive(
|
LoginWithDeviceAction.Internal.NewAuthRequestResultReceive(
|
||||||
|
@ -98,6 +99,21 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setIsResendNotificationLoading(isLoading: Boolean) {
|
||||||
|
when (val viewState = mutableStateFlow.value.viewState) {
|
||||||
|
is LoginWithDeviceState.ViewState.Content -> {
|
||||||
|
mutableStateFlow.update {
|
||||||
|
it.copy(
|
||||||
|
viewState = viewState.copy(
|
||||||
|
isResendNotificationLoading = isLoading,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,6 +155,7 @@ data class LoginWithDeviceState(
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Content(
|
data class Content(
|
||||||
val fingerprintPhrase: String,
|
val fingerprintPhrase: String,
|
||||||
|
val isResendNotificationLoading: Boolean,
|
||||||
) : ViewState()
|
) : ViewState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,7 @@ class LoginWithDeviceScreenTest : BaseComposeTest() {
|
||||||
emailAddress = EMAIL,
|
emailAddress = EMAIL,
|
||||||
viewState = LoginWithDeviceState.ViewState.Content(
|
viewState = LoginWithDeviceState.ViewState.Content(
|
||||||
fingerprintPhrase = "alabster-drinkable-mystified-rapping-irrigate",
|
fingerprintPhrase = "alabster-drinkable-mystified-rapping-irrigate",
|
||||||
|
isResendNotificationLoading = false,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
|
||||||
emailAddress = newEmail,
|
emailAddress = newEmail,
|
||||||
viewState = LoginWithDeviceState.ViewState.Content(
|
viewState = LoginWithDeviceState.ViewState.Content(
|
||||||
fingerprintPhrase = FINGERPRINT,
|
fingerprintPhrase = FINGERPRINT,
|
||||||
|
isResendNotificationLoading = false,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
val viewModel = createViewModel(state)
|
val viewModel = createViewModel(state)
|
||||||
|
@ -69,16 +70,22 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ResendNotificationClick should emit ShowToast`() = runTest {
|
fun `ResendNotificationClick should create new auth request and update state`() = runTest {
|
||||||
|
val newFingerprint = "newFingerprint"
|
||||||
|
coEvery {
|
||||||
|
authRepository.createAuthRequest(EMAIL)
|
||||||
|
} returns AuthRequestResult.Success(AUTH_REQUEST.copy(fingerprint = newFingerprint))
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.actionChannel.trySend(LoginWithDeviceAction.ResendNotificationClick)
|
||||||
viewModel.actionChannel.trySend(LoginWithDeviceAction.ResendNotificationClick)
|
assertEquals(
|
||||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
DEFAULT_STATE.copy(
|
||||||
assertEquals(
|
viewState = LoginWithDeviceState.ViewState.Content(
|
||||||
LoginWithDeviceEvent.ShowToast("Not yet implemented."),
|
fingerprintPhrase = newFingerprint,
|
||||||
awaitItem(),
|
isResendNotificationLoading = false,
|
||||||
)
|
),
|
||||||
}
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -112,6 +119,7 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
viewState = LoginWithDeviceState.ViewState.Content(
|
viewState = LoginWithDeviceState.ViewState.Content(
|
||||||
fingerprintPhrase = newFingerprint,
|
fingerprintPhrase = newFingerprint,
|
||||||
|
isResendNotificationLoading = false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
|
@ -152,6 +160,7 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
|
||||||
emailAddress = EMAIL,
|
emailAddress = EMAIL,
|
||||||
viewState = LoginWithDeviceState.ViewState.Content(
|
viewState = LoginWithDeviceState.ViewState.Content(
|
||||||
fingerprintPhrase = FINGERPRINT,
|
fingerprintPhrase = FINGERPRINT,
|
||||||
|
isResendNotificationLoading = false,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
private val AUTH_REQUEST = AuthRequest(
|
private val AUTH_REQUEST = AuthRequest(
|
||||||
|
|
Loading…
Reference in a new issue