Add Init action + corresponding initialized event

This commit is contained in:
Maxime NATUREL 2022-09-22 15:06:23 +02:00
parent e437c9e131
commit fd85ad0f1b
5 changed files with 84 additions and 30 deletions

View File

@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2.rename
import im.vector.app.core.platform.VectorViewModelAction
sealed class RenameSessionAction : VectorViewModelAction {
object InitWithLastEditedName : RenameSessionAction()
object SaveModifications : RenameSessionAction()
data class EditLocally(val editedName: String) : RenameSessionAction()
}

View File

@ -40,8 +40,6 @@ class RenameSessionFragment :
@Inject lateinit var viewNavigator: RenameSessionViewNavigator
private var renameEditTextInitialized = false
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSessionRenameBinding {
return FragmentSessionRenameBinding.inflate(inflater, container, false)
}
@ -52,6 +50,7 @@ class RenameSessionFragment :
initToolbar()
initEditText()
initSaveButton()
initWithLastEditedName()
}
private fun initToolbar() {
@ -72,9 +71,17 @@ class RenameSessionFragment :
}
}
private fun initWithLastEditedName() {
viewModel.handle(RenameSessionAction.InitWithLastEditedName)
}
private fun observeViewEvents() {
viewModel.observeViewEvents {
when (it) {
is RenameSessionViewEvent.Initialized -> {
views.renameSessionEditText.setText(it.deviceName)
views.renameSessionEditText.setSelection(views.renameSessionEditText.length())
}
is RenameSessionViewEvent.SessionRenamed -> {
viewNavigator.goBack(requireActivity())
}
@ -86,11 +93,6 @@ class RenameSessionFragment :
}
override fun invalidate() = withState(viewModel) { state ->
if (renameEditTextInitialized.not()) {
views.renameSessionEditText.setText(state.editedDeviceName)
views.renameSessionEditText.setSelection(views.renameSessionEditText.length())
renameEditTextInitialized = true
}
views.renameSessionSave.isEnabled = state.editedDeviceName.isNotEmpty()
}
}

View File

@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2.rename
import im.vector.app.core.platform.VectorViewEvents
sealed class RenameSessionViewEvent : VectorViewEvents {
data class Initialized(val deviceName: String) : RenameSessionViewEvent()
object SessionRenamed : RenameSessionViewEvent()
data class Failure(val throwable: Throwable) : RenameSessionViewEvent()
}

View File

@ -16,6 +16,7 @@
package im.vector.app.features.settings.devices.v2.rename
import androidx.annotation.VisibleForTesting
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@ -24,8 +25,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.settings.devices.v2.overview.GetDeviceFullInfoUseCase
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
class RenameSessionViewModel @AssistedInject constructor(
@ -41,23 +41,41 @@ class RenameSessionViewModel @AssistedInject constructor(
override fun create(initialState: RenameSessionViewState): RenameSessionViewModel
}
init {
observeSessionInfo(initialState.deviceId)
}
private fun observeSessionInfo(deviceId: String) {
getDeviceFullInfoUseCase.execute(deviceId)
.onEach { setState { copy(editedDeviceName = it.deviceInfo.displayName.orEmpty()) } }
.launchIn(viewModelScope)
}
@VisibleForTesting
var hasRetrievedOriginalDeviceName = false
override fun handle(action: RenameSessionAction) {
when (action) {
is RenameSessionAction.InitWithLastEditedName -> handleInitWithLastEditedName()
is RenameSessionAction.EditLocally -> handleEditLocally(action.editedName)
is RenameSessionAction.SaveModifications -> handleSaveModifications()
}
}
private fun handleInitWithLastEditedName() = withState { state ->
if (hasRetrievedOriginalDeviceName) {
postInitEvent()
} else {
hasRetrievedOriginalDeviceName = true
viewModelScope.launch {
setStateWithOriginalDeviceName(state.deviceId)
postInitEvent()
}
}
}
private suspend fun setStateWithOriginalDeviceName(deviceId: String) {
getDeviceFullInfoUseCase.execute(deviceId)
.firstOrNull()
?.let { deviceFullInfo ->
setState { copy(editedDeviceName = deviceFullInfo.deviceInfo.displayName.orEmpty()) }
}
}
private fun postInitEvent() = withState { state ->
_viewEvents.post(RenameSessionViewEvent.Initialized(state.editedDeviceName))
}
private fun handleEditLocally(editedName: String) {
setState { copy(editedDeviceName = editedName) }
}

View File

@ -51,38 +51,72 @@ class RenameSessionViewModelTest {
)
@Test
fun `given the viewModel has been initialized then viewState is updated with current session name`() {
fun `given the original device name has not been retrieved when handling init with last edited name action then view state and view events are updated`() {
// Given
givenSessionWithName(A_SESSION_NAME)
val action = RenameSessionAction.InitWithLastEditedName
val expectedState = RenameSessionViewState(
deviceId = A_SESSION_ID,
editedDeviceName = A_SESSION_NAME,
)
val expectedEvent = RenameSessionViewEvent.Initialized(
deviceName = A_SESSION_NAME,
)
val viewModel = createViewModel()
viewModel.hasRetrievedOriginalDeviceName = false
// When
val viewModel = createViewModel()
val viewModelTest = viewModel.test()
viewModel.handle(action)
// Then
viewModel.test()
.assertLatestState { state -> state == expectedState }
viewModelTest.assertLatestState { state -> state == expectedState }
.assertEvent { event -> event == expectedEvent }
.finish()
verify {
getDeviceFullInfoUseCase.execute(A_SESSION_ID)
}
}
@Test
fun `given the original device name has been retrieved when handling init with last edited name action then view state and view events are updated`() {
// Given
val action = RenameSessionAction.InitWithLastEditedName
val expectedState = RenameSessionViewState(
deviceId = A_SESSION_ID,
editedDeviceName = AN_EDITED_SESSION_NAME,
)
val expectedEvent = RenameSessionViewEvent.Initialized(
deviceName = AN_EDITED_SESSION_NAME,
)
val viewModel = createViewModel()
viewModel.handle(RenameSessionAction.EditLocally(AN_EDITED_SESSION_NAME))
viewModel.hasRetrievedOriginalDeviceName = true
// When
val viewModelTest = viewModel.test()
viewModel.handle(action)
// Then
viewModelTest.assertLatestState { state -> state == expectedState }
.assertEvent { event -> event == expectedEvent }
.finish()
verify(inverse = true) {
getDeviceFullInfoUseCase.execute(A_SESSION_ID)
}
}
@Test
fun `given a new edited name when handling edit name locally action then view state is updated accordingly`() {
// Given
givenSessionWithName(A_SESSION_NAME)
val action = RenameSessionAction.EditLocally(AN_EDITED_SESSION_NAME)
val expectedState = RenameSessionViewState(
deviceId = A_SESSION_ID,
editedDeviceName = AN_EDITED_SESSION_NAME,
)
val viewModel = createViewModel()
// When
val viewModel = createViewModel()
val viewModelTest = viewModel.test()
viewModel.handle(action)
@ -95,12 +129,11 @@ class RenameSessionViewModelTest {
@Test
fun `given current edited name when handling save modifications action with success then correct view event is posted`() {
// Given
givenSessionWithName(A_SESSION_NAME)
coEvery { renameSessionUseCase.execute(A_SESSION_ID, A_SESSION_NAME) } returns Result.success(Unit)
coEvery { renameSessionUseCase.execute(A_SESSION_ID, any()) } returns Result.success(Unit)
val action = RenameSessionAction.SaveModifications
val viewModel = createViewModel()
// When
val viewModel = createViewModel()
val viewModelTest = viewModel.test()
viewModel.handle(action)
@ -113,13 +146,12 @@ class RenameSessionViewModelTest {
@Test
fun `given current edited name when handling save modifications action with error then correct view event is posted`() {
// Given
givenSessionWithName(A_SESSION_NAME)
val error = Exception()
coEvery { renameSessionUseCase.execute(A_SESSION_ID, A_SESSION_NAME) } returns Result.failure(error)
coEvery { renameSessionUseCase.execute(A_SESSION_ID, any()) } returns Result.failure(error)
val action = RenameSessionAction.SaveModifications
val viewModel = createViewModel()
// When
val viewModel = createViewModel()
val viewModelTest = viewModel.test()
viewModel.handle(action)