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 import im.vector.app.core.platform.VectorViewModelAction
sealed class RenameSessionAction : VectorViewModelAction { sealed class RenameSessionAction : VectorViewModelAction {
object InitWithLastEditedName : RenameSessionAction()
object SaveModifications : RenameSessionAction() object SaveModifications : RenameSessionAction()
data class EditLocally(val editedName: String) : RenameSessionAction() data class EditLocally(val editedName: String) : RenameSessionAction()
} }

View File

@ -40,8 +40,6 @@ class RenameSessionFragment :
@Inject lateinit var viewNavigator: RenameSessionViewNavigator @Inject lateinit var viewNavigator: RenameSessionViewNavigator
private var renameEditTextInitialized = false
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSessionRenameBinding { override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSessionRenameBinding {
return FragmentSessionRenameBinding.inflate(inflater, container, false) return FragmentSessionRenameBinding.inflate(inflater, container, false)
} }
@ -52,6 +50,7 @@ class RenameSessionFragment :
initToolbar() initToolbar()
initEditText() initEditText()
initSaveButton() initSaveButton()
initWithLastEditedName()
} }
private fun initToolbar() { private fun initToolbar() {
@ -72,9 +71,17 @@ class RenameSessionFragment :
} }
} }
private fun initWithLastEditedName() {
viewModel.handle(RenameSessionAction.InitWithLastEditedName)
}
private fun observeViewEvents() { private fun observeViewEvents() {
viewModel.observeViewEvents { viewModel.observeViewEvents {
when (it) { when (it) {
is RenameSessionViewEvent.Initialized -> {
views.renameSessionEditText.setText(it.deviceName)
views.renameSessionEditText.setSelection(views.renameSessionEditText.length())
}
is RenameSessionViewEvent.SessionRenamed -> { is RenameSessionViewEvent.SessionRenamed -> {
viewNavigator.goBack(requireActivity()) viewNavigator.goBack(requireActivity())
} }
@ -86,11 +93,6 @@ class RenameSessionFragment :
} }
override fun invalidate() = withState(viewModel) { state -> 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() 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 import im.vector.app.core.platform.VectorViewEvents
sealed class RenameSessionViewEvent : VectorViewEvents { sealed class RenameSessionViewEvent : VectorViewEvents {
data class Initialized(val deviceName: String) : RenameSessionViewEvent()
object SessionRenamed : RenameSessionViewEvent() object SessionRenamed : RenameSessionViewEvent()
data class Failure(val throwable: Throwable) : RenameSessionViewEvent() data class Failure(val throwable: Throwable) : RenameSessionViewEvent()
} }

View File

@ -16,6 +16,7 @@
package im.vector.app.features.settings.devices.v2.rename package im.vector.app.features.settings.devices.v2.rename
import androidx.annotation.VisibleForTesting
import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory 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.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.settings.devices.v2.overview.GetDeviceFullInfoUseCase import im.vector.app.features.settings.devices.v2.overview.GetDeviceFullInfoUseCase
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class RenameSessionViewModel @AssistedInject constructor( class RenameSessionViewModel @AssistedInject constructor(
@ -41,23 +41,41 @@ class RenameSessionViewModel @AssistedInject constructor(
override fun create(initialState: RenameSessionViewState): RenameSessionViewModel override fun create(initialState: RenameSessionViewState): RenameSessionViewModel
} }
init { @VisibleForTesting
observeSessionInfo(initialState.deviceId) var hasRetrievedOriginalDeviceName = false
}
private fun observeSessionInfo(deviceId: String) {
getDeviceFullInfoUseCase.execute(deviceId)
.onEach { setState { copy(editedDeviceName = it.deviceInfo.displayName.orEmpty()) } }
.launchIn(viewModelScope)
}
override fun handle(action: RenameSessionAction) { override fun handle(action: RenameSessionAction) {
when (action) { when (action) {
is RenameSessionAction.InitWithLastEditedName -> handleInitWithLastEditedName()
is RenameSessionAction.EditLocally -> handleEditLocally(action.editedName) is RenameSessionAction.EditLocally -> handleEditLocally(action.editedName)
is RenameSessionAction.SaveModifications -> handleSaveModifications() 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) { private fun handleEditLocally(editedName: String) {
setState { copy(editedDeviceName = editedName) } setState { copy(editedDeviceName = editedName) }
} }

View File

@ -51,38 +51,72 @@ class RenameSessionViewModelTest {
) )
@Test @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 // Given
givenSessionWithName(A_SESSION_NAME) givenSessionWithName(A_SESSION_NAME)
val action = RenameSessionAction.InitWithLastEditedName
val expectedState = RenameSessionViewState( val expectedState = RenameSessionViewState(
deviceId = A_SESSION_ID, deviceId = A_SESSION_ID,
editedDeviceName = A_SESSION_NAME, editedDeviceName = A_SESSION_NAME,
) )
val expectedEvent = RenameSessionViewEvent.Initialized(
deviceName = A_SESSION_NAME,
)
val viewModel = createViewModel()
viewModel.hasRetrievedOriginalDeviceName = false
// When // When
val viewModel = createViewModel() val viewModelTest = viewModel.test()
viewModel.handle(action)
// Then // Then
viewModel.test() viewModelTest.assertLatestState { state -> state == expectedState }
.assertLatestState { state -> state == expectedState } .assertEvent { event -> event == expectedEvent }
.finish() .finish()
verify { verify {
getDeviceFullInfoUseCase.execute(A_SESSION_ID) 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 @Test
fun `given a new edited name when handling edit name locally action then view state is updated accordingly`() { fun `given a new edited name when handling edit name locally action then view state is updated accordingly`() {
// Given // Given
givenSessionWithName(A_SESSION_NAME)
val action = RenameSessionAction.EditLocally(AN_EDITED_SESSION_NAME) val action = RenameSessionAction.EditLocally(AN_EDITED_SESSION_NAME)
val expectedState = RenameSessionViewState( val expectedState = RenameSessionViewState(
deviceId = A_SESSION_ID, deviceId = A_SESSION_ID,
editedDeviceName = AN_EDITED_SESSION_NAME, editedDeviceName = AN_EDITED_SESSION_NAME,
) )
val viewModel = createViewModel()
// When // When
val viewModel = createViewModel()
val viewModelTest = viewModel.test() val viewModelTest = viewModel.test()
viewModel.handle(action) viewModel.handle(action)
@ -95,12 +129,11 @@ class RenameSessionViewModelTest {
@Test @Test
fun `given current edited name when handling save modifications action with success then correct view event is posted`() { fun `given current edited name when handling save modifications action with success then correct view event is posted`() {
// Given // Given
givenSessionWithName(A_SESSION_NAME) coEvery { renameSessionUseCase.execute(A_SESSION_ID, any()) } returns Result.success(Unit)
coEvery { renameSessionUseCase.execute(A_SESSION_ID, A_SESSION_NAME) } returns Result.success(Unit)
val action = RenameSessionAction.SaveModifications val action = RenameSessionAction.SaveModifications
val viewModel = createViewModel()
// When // When
val viewModel = createViewModel()
val viewModelTest = viewModel.test() val viewModelTest = viewModel.test()
viewModel.handle(action) viewModel.handle(action)
@ -113,13 +146,12 @@ class RenameSessionViewModelTest {
@Test @Test
fun `given current edited name when handling save modifications action with error then correct view event is posted`() { fun `given current edited name when handling save modifications action with error then correct view event is posted`() {
// Given // Given
givenSessionWithName(A_SESSION_NAME)
val error = Exception() 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 action = RenameSessionAction.SaveModifications
val viewModel = createViewModel()
// When // When
val viewModel = createViewModel()
val viewModelTest = viewModel.test() val viewModelTest = viewModel.test()
viewModel.handle(action) viewModel.handle(action)