Adding confirmation dialog for all type of sessions

This commit is contained in:
Maxime NATUREL 2022-09-29 10:27:13 +02:00
parent e47bf2b200
commit 082fa1e69e
5 changed files with 41 additions and 41 deletions

View File

@ -20,7 +20,7 @@ import im.vector.app.core.platform.VectorViewModelAction
sealed class SessionOverviewAction : VectorViewModelAction { sealed class SessionOverviewAction : VectorViewModelAction {
object VerifySession : SessionOverviewAction() object VerifySession : SessionOverviewAction()
object SignoutSession : SessionOverviewAction() object SignoutOtherSession : SessionOverviewAction()
object SsoAuthDone : SessionOverviewAction() object SsoAuthDone : SessionOverviewAction()
data class PasswordAuthDone(val password: String) : SessionOverviewAction() data class PasswordAuthDone(val password: String) : SessionOverviewAction()
object ReAuthCancelled : SessionOverviewAction() object ReAuthCancelled : SessionOverviewAction()

View File

@ -28,6 +28,7 @@ import androidx.core.view.isVisible
import com.airbnb.mvrx.Success import com.airbnb.mvrx.Success
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.date.VectorDateFormatter
@ -42,6 +43,7 @@ import im.vector.app.features.crypto.recover.SetupMode
import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
import im.vector.app.features.workers.signout.SignOutUiWorker import im.vector.app.features.workers.signout.SignOutUiWorker
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.extensions.orFalse
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -87,17 +89,12 @@ class SessionOverviewFragment :
navigator.open4SSetup(requireActivity(), SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET) navigator.open4SSetup(requireActivity(), SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET)
} }
is SessionOverviewViewEvent.RequestReAuth -> askForReAuthentication(it) is SessionOverviewViewEvent.RequestReAuth -> askForReAuthentication(it)
SessionOverviewViewEvent.ConfirmSignoutCurrentSession -> confirmSignoutCurrentSession()
SessionOverviewViewEvent.SignoutSuccess -> viewNavigator.goBack(requireActivity()) SessionOverviewViewEvent.SignoutSuccess -> viewNavigator.goBack(requireActivity())
is SessionOverviewViewEvent.SignoutError -> showFailure(it.error) is SessionOverviewViewEvent.SignoutError -> showFailure(it.error)
} }
} }
} }
private fun confirmSignoutCurrentSession() {
activity?.let { SignOutUiWorker(it).perform() }
}
private fun initSessionInfoView() { private fun initSessionInfoView() {
views.sessionOverviewInfo.onLearnMoreClickListener = { views.sessionOverviewInfo.onLearnMoreClickListener = {
Toast.makeText(context, "Learn more verification status", Toast.LENGTH_LONG).show() Toast.makeText(context, "Learn more verification status", Toast.LENGTH_LONG).show()
@ -112,10 +109,39 @@ class SessionOverviewFragment :
private fun initSignoutButton() { private fun initSignoutButton() {
views.sessionOverviewSignout.debouncedClicks { views.sessionOverviewSignout.debouncedClicks {
viewModel.handle(SessionOverviewAction.SignoutSession) confirmSignoutSession()
} }
} }
private fun confirmSignoutSession() = withState(viewModel) { state ->
if (state.deviceInfo.invoke()?.isCurrentDevice.orFalse()) {
confirmSignoutCurrentSession()
} else {
confirmSignoutOtherSession()
}
}
private fun confirmSignoutCurrentSession() {
activity?.let { SignOutUiWorker(it).perform() }
}
private fun confirmSignoutOtherSession() {
activity?.let {
MaterialAlertDialogBuilder(it)
.setTitle(R.string.action_sign_out)
.setMessage(R.string.action_sign_out_confirmation_simple)
.setPositiveButton(R.string.action_sign_out) { _, _ ->
signoutSession()
}
.setNegativeButton(R.string.action_cancel, null)
.show()
}
}
private fun signoutSession() {
viewModel.handle(SessionOverviewAction.SignoutOtherSession)
}
override fun onDestroyView() { override fun onDestroyView() {
cleanUpSessionInfoView() cleanUpSessionInfoView()
super.onDestroyView() super.onDestroyView()

View File

@ -28,7 +28,6 @@ sealed class SessionOverviewViewEvent : VectorViewEvents {
val lastErrorCode: String? val lastErrorCode: String?
) : SessionOverviewViewEvent() ) : SessionOverviewViewEvent()
object ConfirmSignoutCurrentSession : SessionOverviewViewEvent()
object SignoutSuccess : SessionOverviewViewEvent() object SignoutSuccess : SessionOverviewViewEvent()
data class SignoutError(val error: Throwable) : SessionOverviewViewEvent() data class SignoutError(val error: Throwable) : SessionOverviewViewEvent()
} }

View File

@ -97,7 +97,7 @@ class SessionOverviewViewModel @AssistedInject constructor(
override fun handle(action: SessionOverviewAction) { override fun handle(action: SessionOverviewAction) {
when (action) { when (action) {
is SessionOverviewAction.VerifySession -> handleVerifySessionAction() is SessionOverviewAction.VerifySession -> handleVerifySessionAction()
SessionOverviewAction.SignoutSession -> handleSignoutSession() SessionOverviewAction.SignoutOtherSession -> handleSignoutOtherSession()
SessionOverviewAction.SsoAuthDone -> handleSsoAuthDone() SessionOverviewAction.SsoAuthDone -> handleSsoAuthDone()
is SessionOverviewAction.PasswordAuthDone -> handlePasswordAuthDone(action) is SessionOverviewAction.PasswordAuthDone -> handlePasswordAuthDone(action)
SessionOverviewAction.ReAuthCancelled -> handleReAuthCancelled() SessionOverviewAction.ReAuthCancelled -> handleReAuthCancelled()
@ -127,18 +127,13 @@ class SessionOverviewViewModel @AssistedInject constructor(
_viewEvents.post(SessionOverviewViewEvent.ShowVerifyOtherSession(deviceId)) _viewEvents.post(SessionOverviewViewEvent.ShowVerifyOtherSession(deviceId))
} }
private fun handleSignoutSession() = withState { state -> private fun handleSignoutOtherSession() = withState { state ->
if (state.deviceInfo.invoke()?.isCurrentDevice.orFalse()) { // signout process for current session is not handled here
handleSignoutCurrentSession() if (!state.deviceInfo.invoke()?.isCurrentDevice.orFalse()) {
} else {
handleSignoutOtherSession(state.deviceId) handleSignoutOtherSession(state.deviceId)
} }
} }
private fun handleSignoutCurrentSession() {
_viewEvents.post(SessionOverviewViewEvent.ConfirmSignoutCurrentSession)
}
private fun handleSignoutOtherSession(deviceId: String) { private fun handleSignoutOtherSession(deviceId: String) {
viewModelScope.launch { viewModelScope.launch {
setLoading(true) setLoading(true)

View File

@ -199,26 +199,6 @@ class SessionOverviewViewModelTest {
.finish() .finish()
} }
@Test
fun `given current session when handling signout action then confirmation event is posted`() {
// Given
val deviceFullInfo = mockk<DeviceFullInfo>()
every { deviceFullInfo.isCurrentDevice } returns true
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo)
val signoutAction = SessionOverviewAction.SignoutSession
givenCurrentSessionIsTrusted()
// When
val viewModel = createViewModel()
val viewModelTest = viewModel.test()
viewModel.handle(signoutAction)
// Then
viewModelTest
.assertEvent { it is SessionOverviewViewEvent.ConfirmSignoutCurrentSession }
.finish()
}
@Test @Test
fun `given another session and no reAuth is needed when handling signout action then signout process is performed`() { fun `given another session and no reAuth is needed when handling signout action then signout process is performed`() {
// Given // Given
@ -227,7 +207,7 @@ class SessionOverviewViewModelTest {
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo)
givenSignoutSuccess(A_SESSION_ID_1) givenSignoutSuccess(A_SESSION_ID_1)
every { refreshDevicesUseCase.execute() } just runs every { refreshDevicesUseCase.execute() } just runs
val signoutAction = SessionOverviewAction.SignoutSession val signoutAction = SessionOverviewAction.SignoutOtherSession
givenCurrentSessionIsTrusted() givenCurrentSessionIsTrusted()
val expectedViewState = SessionOverviewViewState( val expectedViewState = SessionOverviewViewState(
deviceId = A_SESSION_ID_1, deviceId = A_SESSION_ID_1,
@ -263,7 +243,7 @@ class SessionOverviewViewModelTest {
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo)
val serverError = Failure.OtherServerError(errorBody = "", httpCode = HttpsURLConnection.HTTP_UNAUTHORIZED) val serverError = Failure.OtherServerError(errorBody = "", httpCode = HttpsURLConnection.HTTP_UNAUTHORIZED)
givenSignoutError(A_SESSION_ID_1, serverError) givenSignoutError(A_SESSION_ID_1, serverError)
val signoutAction = SessionOverviewAction.SignoutSession val signoutAction = SessionOverviewAction.SignoutOtherSession
givenCurrentSessionIsTrusted() givenCurrentSessionIsTrusted()
val expectedViewState = SessionOverviewViewState( val expectedViewState = SessionOverviewViewState(
deviceId = A_SESSION_ID_1, deviceId = A_SESSION_ID_1,
@ -297,7 +277,7 @@ class SessionOverviewViewModelTest {
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo)
val error = Exception() val error = Exception()
givenSignoutError(A_SESSION_ID_1, error) givenSignoutError(A_SESSION_ID_1, error)
val signoutAction = SessionOverviewAction.SignoutSession val signoutAction = SessionOverviewAction.SignoutOtherSession
givenCurrentSessionIsTrusted() givenCurrentSessionIsTrusted()
val expectedViewState = SessionOverviewViewState( val expectedViewState = SessionOverviewViewState(
deviceId = A_SESSION_ID_1, deviceId = A_SESSION_ID_1,
@ -330,7 +310,7 @@ class SessionOverviewViewModelTest {
every { deviceFullInfo.isCurrentDevice } returns false every { deviceFullInfo.isCurrentDevice } returns false
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo)
val reAuthNeeded = givenSignoutReAuthNeeded(A_SESSION_ID_1) val reAuthNeeded = givenSignoutReAuthNeeded(A_SESSION_ID_1)
val signoutAction = SessionOverviewAction.SignoutSession val signoutAction = SessionOverviewAction.SignoutOtherSession
givenCurrentSessionIsTrusted() givenCurrentSessionIsTrusted()
val expectedPendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session) val expectedPendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session)
val expectedReAuthEvent = SessionOverviewViewEvent.RequestReAuth(reAuthNeeded.flowResponse, reAuthNeeded.errCode) val expectedReAuthEvent = SessionOverviewViewEvent.RequestReAuth(reAuthNeeded.flowResponse, reAuthNeeded.errCode)