Skip to content

Commit

Permalink
navigation above ChangePasswordDialog
Browse files Browse the repository at this point in the history
  • Loading branch information
babichev.a committed Oct 11, 2024
1 parent ec3c499 commit 8726fc0
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import notedelight.shared_compose_ui.generated.resources.create_note
import org.jetbrains.compose.resources.getString
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
Expand Down Expand Up @@ -50,6 +51,7 @@ class RotationTest {
IdlingRegistry.getInstance().unregister(IdlingRes.countingIdlingResource)
}

@Ignore("Unable to connect to Emulator gRPC port on CI")
@Test
fun rotationTest() = runTest {
composeTestRule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,7 @@ fun App(
ConfirmPasswordDialog(confirmViewModel = getViewModel())
}
dialog(route = AppNavGraph.ChangePasswordDialog.route) {
ChangePasswordDialog(
dismissDialog = navController::navigateUp,
changeViewModel = getViewModel()
)
ChangePasswordDialog(changeViewModel = getViewModel())
}
dialog(
route = AppNavGraph.ErrorDialog.route,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import org.jetbrains.compose.resources.getString
import org.jetbrains.compose.resources.stringResource

@Composable
fun ChangePasswordDialog(dismissDialog: () -> Unit, changeViewModel: ChangeViewModel) {
fun ChangePasswordDialog(changeViewModel: ChangeViewModel) {
val changeResultState: State<ChangeResult> = changeViewModel.resultStateFlow.collectAsState()
var oldLabelResource by remember { mutableStateOf(Res.string.enter_old_password) }
var oldError by remember { mutableStateOf(false) }
Expand All @@ -55,7 +55,6 @@ fun ChangePasswordDialog(dismissDialog: () -> Unit, changeViewModel: ChangeViewM
val coroutineScope = rememberCoroutineScope()
when (val changeResult: ChangeResult = changeResultState.value) {
is ChangeResult.InitState, is ChangeResult.Loading -> Unit
is ChangeResult.Success -> dismissDialog()
is ChangeResult.OldEmptyPasswordError -> {
oldLabelResource = Res.string.empty_password
oldError = true
Expand Down Expand Up @@ -90,7 +89,7 @@ fun ChangePasswordDialog(dismissDialog: () -> Unit, changeViewModel: ChangeViewM
repeatError = repeatError,
repeatPasswordState = repeatPasswordState,
snackbarHostState = snackbarHostState,
dismissDialog = dismissDialog
dismissDialog = changeViewModel::navigateUp,
) {
changeViewModel.checkChange(
oldPassword = oldPasswordState.value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.junit.Test
import org.mockito.Mockito
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.seconds

class SaveViewModelTest {

Expand All @@ -23,7 +24,7 @@ class SaveViewModelTest {
private val saveViewModel: SaveViewModel = SaveViewModel(mockRouter)

@Test
fun `Don't save and nav back`() = runTest {
fun `Don't save and nav back`() = runTest(timeout = 5.seconds) {
saveViewModel.doNotSaveAndNavBack()
advanceUntilIdle()
assertFalse(SaveNoteUseCase.saveChannel.receiveCatching().getOrThrow())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import app.cash.turbine.test
import com.softartdev.notedelight.shared.presentation.MainDispatcherRule
import com.softartdev.notedelight.shared.StubEditable
import com.softartdev.notedelight.shared.navigation.Router
import com.softartdev.notedelight.shared.usecase.crypt.ChangePasswordUseCase
import com.softartdev.notedelight.shared.usecase.crypt.CheckPasswordUseCase
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Rule
Expand All @@ -24,7 +26,8 @@ class ChangeViewModelTest {

private val checkPasswordUseCase = Mockito.mock(CheckPasswordUseCase::class.java)
private val changePasswordUseCase = Mockito.mock(ChangePasswordUseCase::class.java)
private val changeViewModel = ChangeViewModel(checkPasswordUseCase, changePasswordUseCase)
private val router = Mockito.mock(Router::class.java)
private val changeViewModel = ChangeViewModel(checkPasswordUseCase, changePasswordUseCase, router)

@Test
fun checkChangeOldEmptyPasswordError() = runTest {
Expand Down Expand Up @@ -81,8 +84,11 @@ class ChangeViewModelTest {
Mockito.`when`(checkPasswordUseCase(old)).thenReturn(true)
val new = StubEditable("new")
changeViewModel.checkChange(old, new, new)
advanceUntilIdle()
assertEquals(ChangeResult.Loading, awaitItem())
assertEquals(ChangeResult.Success, awaitItem())

Mockito.verify(router).popBackStack()
Mockito.verifyNoMoreInteractions(router)

cancelAndIgnoreRemainingEvents()
}
Expand All @@ -103,9 +109,4 @@ class ChangeViewModelTest {
cancelAndIgnoreRemainingEvents()
}
}

@Test
fun errorResult() {
assertEquals(ChangeResult.Error("err"), changeViewModel.errorResult(Throwable("err")))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ val viewModelModule: Module = module {
viewModelFactory { SettingsViewModel(get(), get(), get()) }
viewModelFactory { EnterViewModel(get(), get(), get()) }
viewModelFactory { ConfirmViewModel(get(), get()) }
viewModelFactory { ChangeViewModel(get(), get()) }
viewModelFactory { ChangeViewModel(get(), get(), get()) }
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.softartdev.notedelight.shared.presentation.settings.security.change

sealed class ChangeResult {
object InitState: ChangeResult()
object Loading: ChangeResult()
object Success: ChangeResult()
object OldEmptyPasswordError: ChangeResult()
object NewEmptyPasswordError: ChangeResult()
object PasswordsNoMatchError: ChangeResult()
object IncorrectPasswordError: ChangeResult()
data object InitState: ChangeResult()
data object Loading: ChangeResult()
data object OldEmptyPasswordError: ChangeResult()
data object NewEmptyPasswordError: ChangeResult()
data object PasswordsNoMatchError: ChangeResult()
data object IncorrectPasswordError: ChangeResult()
data class Error(val message: String?): ChangeResult()
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,59 @@
package com.softartdev.notedelight.shared.presentation.settings.security.change

import com.softartdev.notedelight.shared.base.BaseStateViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.softartdev.notedelight.shared.navigation.Router
import com.softartdev.notedelight.shared.usecase.crypt.ChangePasswordUseCase
import com.softartdev.notedelight.shared.usecase.crypt.CheckPasswordUseCase
import io.github.aakira.napier.Napier
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class ChangeViewModel(
private val checkPasswordUseCase: CheckPasswordUseCase,
private val changePasswordUseCase: ChangePasswordUseCase
) : BaseStateViewModel<ChangeResult>() {

override var initResult: ChangeResult? = ChangeResult.InitState
override val loadingResult: ChangeResult = ChangeResult.Loading
private val changePasswordUseCase: ChangePasswordUseCase,
private val router: Router,
) : ViewModel() {
private val mutableStateFlow: MutableStateFlow<ChangeResult> = MutableStateFlow(
value = ChangeResult.InitState
)
val resultStateFlow: StateFlow<ChangeResult> = mutableStateFlow

fun checkChange(
oldPassword: CharSequence,
newPassword: CharSequence,
repeatNewPassword: CharSequence
) = launch {
when {
oldPassword.isEmpty() -> ChangeResult.OldEmptyPasswordError
newPassword.isEmpty() -> ChangeResult.NewEmptyPasswordError
newPassword.toString() != repeatNewPassword.toString() -> ChangeResult.PasswordsNoMatchError
else -> when (checkPasswordUseCase(oldPassword)) {
true -> {
) = viewModelScope.launch(context = Dispatchers.IO) {
mutableStateFlow.value = ChangeResult.Loading
try {
when {
oldPassword.isEmpty() -> {
mutableStateFlow.value = ChangeResult.OldEmptyPasswordError
}
newPassword.isEmpty() -> {
mutableStateFlow.value = ChangeResult.NewEmptyPasswordError
}
newPassword.toString() != repeatNewPassword.toString() -> {
mutableStateFlow.value = ChangeResult.PasswordsNoMatchError
}
checkPasswordUseCase(oldPassword) -> {
changePasswordUseCase(oldPassword, newPassword)
ChangeResult.Success
navigateUp()
}
else -> {
mutableStateFlow.value = ChangeResult.IncorrectPasswordError
}
false -> ChangeResult.IncorrectPasswordError
}
} catch (e: Throwable) {
Napier.e("", e)
mutableStateFlow.value = ChangeResult.Error(e.message)
}
}

override fun errorResult(throwable: Throwable): ChangeResult =
ChangeResult.Error(throwable.message)
fun navigateUp() = viewModelScope.launch(context = Dispatchers.Main) {
router.popBackStack()
}
}

0 comments on commit 8726fc0

Please sign in to comment.