Adding button to trigger sign out

This commit is contained in:
Maxime NATUREL 2022-09-23 16:11:55 +02:00
parent 7e81aa6193
commit b2b3ee1fe5
7 changed files with 89 additions and 22 deletions

View file

@ -3290,6 +3290,7 @@
<string name="device_manager_other_sessions_no_unverified_sessions_found">No unverified sessions found.</string>
<string name="device_manager_other_sessions_no_inactive_sessions_found">No inactive sessions found.</string>
<string name="device_manager_other_sessions_clear_filter">Clear Filter</string>
<string name="device_manager_session_overview_signout">Sign out of this session</string>
<string name="device_manager_session_details_title">Session details</string>
<string name="device_manager_session_details_description">Application, device, and activity information.</string>
<string name="device_manager_session_details_session_name">Session name</string>

View file

@ -41,6 +41,10 @@
<item name="lineHeight">24sp</item>
</style>
<style name="Widget.Vector.Button.Text.Destructive">
<item name="materialThemeOverlay">@style/VectorMaterialThemeOverlayDestructive</item>
</style>
<style name="Widget.Vector.Button.Text.OnPrimary">
<item name="colorControlHighlight">?colorOnPrimary</item>
<item name="materialThemeOverlay">@style/VectorMaterialThemeOverlayOnPrimary</item>

View file

@ -70,18 +70,7 @@ class SessionOverviewFragment :
observeViewEvents()
initSessionInfoView()
initVerifyButton()
}
private fun initSessionInfoView() {
views.sessionOverviewInfo.onLearnMoreClickListener = {
Toast.makeText(context, "Learn more verification status", Toast.LENGTH_LONG).show()
}
}
private fun initVerifyButton() {
views.sessionOverviewInfo.viewVerifyButton.debouncedClicks {
viewModel.handle(SessionOverviewAction.VerifySession)
}
initSignoutButton()
}
private fun observeViewEvents() {
@ -97,10 +86,30 @@ class SessionOverviewFragment :
navigator.open4SSetup(requireActivity(), SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET)
}
is SessionOverviewViewEvent.RequestReAuth -> askForReAuthentication(it)
SessionOverviewViewEvent.SignoutSuccess -> viewNavigator.goBack(requireActivity())
is SessionOverviewViewEvent.SignoutError -> showFailure(it.error)
}
}
}
private fun initSessionInfoView() {
views.sessionOverviewInfo.onLearnMoreClickListener = {
Toast.makeText(context, "Learn more verification status", Toast.LENGTH_LONG).show()
}
}
private fun initVerifyButton() {
views.sessionOverviewInfo.viewVerifyButton.debouncedClicks {
viewModel.handle(SessionOverviewAction.VerifySession)
}
}
private fun initSignoutButton() {
views.sessionOverviewSignout.debouncedClicks {
viewModel.handle(SessionOverviewAction.SignoutSession)
}
}
override fun onDestroyView() {
cleanUpSessionInfoView()
super.onDestroyView()

View file

@ -27,4 +27,7 @@ sealed class SessionOverviewViewEvent : VectorViewEvents {
val registrationFlowResponse: RegistrationFlowResponse,
val lastErrorCode: String?
) : SessionOverviewViewEvent()
object SignoutSuccess : SessionOverviewViewEvent()
data class SignoutError(val error: Throwable) : SessionOverviewViewEvent()
}

View file

@ -21,12 +21,15 @@ import com.airbnb.mvrx.Success
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
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.core.resources.StringProvider
import im.vector.app.features.auth.PendingAuthHandler
import im.vector.app.features.settings.devices.v2.IsCurrentSessionUseCase
import im.vector.app.features.settings.devices.v2.RefreshDevicesUseCase
import im.vector.app.features.settings.devices.v2.VectorSessionsListViewModel
import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionResult
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionUseCase
@ -39,21 +42,27 @@ import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
import timber.log.Timber
import javax.net.ssl.HttpsURLConnection
import kotlin.coroutines.Continuation
class SessionOverviewViewModel @AssistedInject constructor(
@Assisted val initialState: SessionOverviewViewState,
private val activeSessionHolder: ActiveSessionHolder,
private val isCurrentSessionUseCase: IsCurrentSessionUseCase,
private val stringProvider: StringProvider,
private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase,
private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase,
private val signoutSessionUseCase: SignoutSessionUseCase,
private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
private val pendingAuthHandler: PendingAuthHandler,
) : VectorViewModel<SessionOverviewViewState, SessionOverviewAction, SessionOverviewViewEvent>(initialState) {
activeSessionHolder: ActiveSessionHolder,
refreshDevicesUseCase: RefreshDevicesUseCase,
) : VectorSessionsListViewModel<SessionOverviewViewState, SessionOverviewAction, SessionOverviewViewEvent>(
initialState, activeSessionHolder, refreshDevicesUseCase
) {
companion object : MavericksViewModelFactory<SessionOverviewViewModel, SessionOverviewViewState> by hiltMavericksViewModelFactory()
@ -129,20 +138,26 @@ class SessionOverviewViewModel @AssistedInject constructor(
// TODO add unit tests
private fun handleSignoutSession() = withState { state ->
// TODO should we do something different when it is current session?
// TODO for current session: do the same process as sign out button in the general settings
// TODO add a loading viewState or ViewEvent
viewModelScope.launch {
signoutSessionUseCase.execute(state.deviceId, object : UserInteractiveAuthInterceptor {
val signoutResult = signoutSessionUseCase.execute(state.deviceId, object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
when (val result = interceptSignoutFlowResponseUseCase.execute(flowResponse, errCode, promise)) {
is SignoutSessionResult.ReAuthNeeded -> onReAuthNeeded(result)
is SignoutSessionResult.Completed -> {
Timber.d("signout completed")
// TODO check if it is called after a reAuth
// TODO refresh devices list? + post event to close the associated screen
}
is SignoutSessionResult.Completed -> Unit
}
}
})
if (signoutResult.isSuccess) {
onSignoutSuccess()
} else {
when (val failure = signoutResult.exceptionOrNull()) {
null -> onSignoutSuccess()
else -> onSignoutFailure(failure)
}
}
}
}
@ -153,6 +168,22 @@ class SessionOverviewViewModel @AssistedInject constructor(
_viewEvents.post(SessionOverviewViewEvent.RequestReAuth(reAuthNeeded.flowResponse, reAuthNeeded.errCode))
}
private fun onSignoutSuccess() {
Timber.d("signout success")
refreshDeviceList()
_viewEvents.post(SessionOverviewViewEvent.SignoutSuccess)
}
private fun onSignoutFailure(failure: Throwable) {
Timber.e("signout failure", failure)
val failureMessage = if (failure is Failure.OtherServerError && failure.httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED) {
stringProvider.getString(R.string.authentication_error)
} else {
stringProvider.getString(R.string.matrix_error)
}
_viewEvents.post(SessionOverviewViewEvent.SignoutError(Exception(failureMessage)))
}
private fun handleSsoAuthDone() {
pendingAuthHandler.ssoAuthDone()
}

View file

@ -17,6 +17,7 @@
package im.vector.app.features.settings.devices.v2.overview
import android.content.Context
import androidx.fragment.app.FragmentActivity
import im.vector.app.features.settings.devices.v2.details.SessionDetailsActivity
import im.vector.app.features.settings.devices.v2.rename.RenameSessionActivity
import javax.inject.Inject
@ -30,4 +31,9 @@ class SessionOverviewViewNavigator @Inject constructor() {
fun goToRenameSession(context: Context, deviceId: String) {
context.startActivity(RenameSessionActivity.newIntent(context, deviceId))
}
// TODO add unit test
fun goBack(fragmentActivity: FragmentActivity) {
fragmentActivity.finish()
}
}

View file

@ -31,6 +31,19 @@
app:sessionOverviewEntryDescription="@string/device_manager_session_details_description"
app:sessionOverviewEntryTitle="@string/device_manager_session_details_title" />
<Button
android:id="@+id/sessionOverviewSignout"
style="@style/Widget.Vector.Button.Text.Destructive"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:text="@string/device_manager_session_overview_signout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/sessionOverviewEntryDetails"
app:layout_constraintWidth="wrap_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>