Calling signout multi sessions use case in other sessions screen
This commit is contained in:
parent
bb262f0c41
commit
1bda54323a
@ -20,6 +20,12 @@ import im.vector.app.core.platform.VectorViewModelAction
|
|||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
|
|
||||||
sealed class OtherSessionsAction : VectorViewModelAction {
|
sealed class OtherSessionsAction : VectorViewModelAction {
|
||||||
|
// ReAuth
|
||||||
|
object SsoAuthDone : OtherSessionsAction()
|
||||||
|
data class PasswordAuthDone(val password: String) : OtherSessionsAction()
|
||||||
|
object ReAuthCancelled : OtherSessionsAction()
|
||||||
|
|
||||||
|
// Others
|
||||||
data class FilterDevices(val filterType: DeviceManagerFilterType) : OtherSessionsAction()
|
data class FilterDevices(val filterType: DeviceManagerFilterType) : OtherSessionsAction()
|
||||||
data class EnableSelectMode(val deviceId: String?) : OtherSessionsAction()
|
data class EnableSelectMode(val deviceId: String?) : OtherSessionsAction()
|
||||||
object DisableSelectMode : OtherSessionsAction()
|
object DisableSelectMode : OtherSessionsAction()
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.app.features.settings.devices.v2.othersessions
|
package im.vector.app.features.settings.devices.v2.othersessions
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
@ -32,6 +33,7 @@ import com.airbnb.mvrx.fragmentViewModel
|
|||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
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.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.extensions.setTextColor
|
import im.vector.app.core.extensions.setTextColor
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment.ResultListener.Companion.RESULT_OK
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment.ResultListener.Companion.RESULT_OK
|
||||||
@ -40,6 +42,7 @@ import im.vector.app.core.platform.VectorMenuProvider
|
|||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.databinding.FragmentOtherSessionsBinding
|
import im.vector.app.databinding.FragmentOtherSessionsBinding
|
||||||
|
import im.vector.app.features.auth.ReAuthActivity
|
||||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterBottomSheet
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterBottomSheet
|
||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
@ -47,6 +50,7 @@ import im.vector.app.features.settings.devices.v2.list.OtherSessionsView
|
|||||||
import im.vector.app.features.settings.devices.v2.list.SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS
|
import im.vector.app.features.settings.devices.v2.list.SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS
|
||||||
import im.vector.app.features.settings.devices.v2.more.SessionLearnMoreBottomSheet
|
import im.vector.app.features.settings.devices.v2.more.SessionLearnMoreBottomSheet
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -158,8 +162,9 @@ class OtherSessionsFragment :
|
|||||||
private fun observeViewEvents() {
|
private fun observeViewEvents() {
|
||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is OtherSessionsViewEvents.Loading -> showLoading(it.message)
|
is OtherSessionsViewEvents.SignoutError -> showFailure(it.error)
|
||||||
is OtherSessionsViewEvents.Failure -> showFailure(it.throwable)
|
is OtherSessionsViewEvents.RequestReAuth -> askForReAuthentication(it)
|
||||||
|
OtherSessionsViewEvents.SignoutSuccess -> enableSelectMode(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,6 +196,7 @@ class OtherSessionsFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
|
updateLoading(state.isLoading)
|
||||||
if (state.devices is Success) {
|
if (state.devices is Success) {
|
||||||
val devices = state.devices.invoke()
|
val devices = state.devices.invoke()
|
||||||
renderDevices(devices, state.currentFilter)
|
renderDevices(devices, state.currentFilter)
|
||||||
@ -198,6 +204,14 @@ class OtherSessionsFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateLoading(isLoading: Boolean) {
|
||||||
|
if (isLoading) {
|
||||||
|
showLoading(null)
|
||||||
|
} else {
|
||||||
|
dismissLoadingDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateToolbar(devices: List<DeviceFullInfo>, isSelectModeEnabled: Boolean) {
|
private fun updateToolbar(devices: List<DeviceFullInfo>, isSelectModeEnabled: Boolean) {
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
val title = if (isSelectModeEnabled) {
|
val title = if (isSelectModeEnabled) {
|
||||||
@ -312,4 +326,37 @@ class OtherSessionsFragment :
|
|||||||
override fun onViewAllOtherSessionsClicked() {
|
override fun onViewAllOtherSessionsClicked() {
|
||||||
// NOOP. We don't have this button in this screen
|
// NOOP. We don't have this button in this screen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val reAuthActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||||
|
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||||
|
when (activityResult.data?.extras?.getString(ReAuthActivity.RESULT_FLOW_TYPE)) {
|
||||||
|
LoginFlowTypes.SSO -> {
|
||||||
|
viewModel.handle(OtherSessionsAction.SsoAuthDone)
|
||||||
|
}
|
||||||
|
LoginFlowTypes.PASSWORD -> {
|
||||||
|
val password = activityResult.data?.extras?.getString(ReAuthActivity.RESULT_VALUE) ?: ""
|
||||||
|
viewModel.handle(OtherSessionsAction.PasswordAuthDone(password))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
viewModel.handle(OtherSessionsAction.ReAuthCancelled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viewModel.handle(OtherSessionsAction.ReAuthCancelled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch the re auth activity to get credentials.
|
||||||
|
*/
|
||||||
|
private fun askForReAuthentication(reAuthReq: OtherSessionsViewEvents.RequestReAuth) {
|
||||||
|
ReAuthActivity.newIntent(
|
||||||
|
requireContext(),
|
||||||
|
reAuthReq.registrationFlowResponse,
|
||||||
|
reAuthReq.lastErrorCode,
|
||||||
|
getString(R.string.devices_delete_dialog_title)
|
||||||
|
).let { intent ->
|
||||||
|
reAuthActivityResultLauncher.launch(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,14 @@
|
|||||||
package im.vector.app.features.settings.devices.v2.othersessions
|
package im.vector.app.features.settings.devices.v2.othersessions
|
||||||
|
|
||||||
import im.vector.app.core.platform.VectorViewEvents
|
import im.vector.app.core.platform.VectorViewEvents
|
||||||
|
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||||
|
|
||||||
sealed class OtherSessionsViewEvents : VectorViewEvents {
|
sealed class OtherSessionsViewEvents : VectorViewEvents {
|
||||||
data class Loading(val message: CharSequence? = null) : OtherSessionsViewEvents()
|
data class RequestReAuth(
|
||||||
data class Failure(val throwable: Throwable) : OtherSessionsViewEvents()
|
val registrationFlowResponse: RegistrationFlowResponse,
|
||||||
|
val lastErrorCode: String?
|
||||||
|
) : OtherSessionsViewEvents()
|
||||||
|
|
||||||
|
object SignoutSuccess : OtherSessionsViewEvents()
|
||||||
|
data class SignoutError(val error: Throwable) : OtherSessionsViewEvents()
|
||||||
}
|
}
|
||||||
|
@ -21,19 +21,38 @@ import com.airbnb.mvrx.Success
|
|||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
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.resources.StringProvider
|
||||||
|
import im.vector.app.features.auth.PendingAuthHandler
|
||||||
import im.vector.app.features.settings.devices.v2.GetDeviceFullInfoListUseCase
|
import im.vector.app.features.settings.devices.v2.GetDeviceFullInfoListUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.RefreshDevicesUseCase
|
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.VectorSessionsListViewModel
|
||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
|
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.SignoutSessionsUseCase
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
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.uia.DefaultBaseAuth
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.net.ssl.HttpsURLConnection
|
||||||
|
import kotlin.coroutines.Continuation
|
||||||
|
|
||||||
class OtherSessionsViewModel @AssistedInject constructor(
|
class OtherSessionsViewModel @AssistedInject constructor(
|
||||||
@Assisted private val initialState: OtherSessionsViewState,
|
@Assisted private val initialState: OtherSessionsViewState,
|
||||||
activeSessionHolder: ActiveSessionHolder,
|
activeSessionHolder: ActiveSessionHolder,
|
||||||
|
private val stringProvider: StringProvider,
|
||||||
private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase,
|
private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase,
|
||||||
|
private val signoutSessionsUseCase: SignoutSessionsUseCase,
|
||||||
|
private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
|
||||||
|
private val pendingAuthHandler: PendingAuthHandler,
|
||||||
refreshDevicesUseCase: RefreshDevicesUseCase
|
refreshDevicesUseCase: RefreshDevicesUseCase
|
||||||
) : VectorSessionsListViewModel<OtherSessionsViewState, OtherSessionsAction, OtherSessionsViewEvents>(
|
) : VectorSessionsListViewModel<OtherSessionsViewState, OtherSessionsAction, OtherSessionsViewEvents>(
|
||||||
initialState, activeSessionHolder, refreshDevicesUseCase
|
initialState, activeSessionHolder, refreshDevicesUseCase
|
||||||
@ -68,6 +87,9 @@ class OtherSessionsViewModel @AssistedInject constructor(
|
|||||||
// TODO update unit tests
|
// TODO update unit tests
|
||||||
override fun handle(action: OtherSessionsAction) {
|
override fun handle(action: OtherSessionsAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
|
is OtherSessionsAction.PasswordAuthDone -> handlePasswordAuthDone(action)
|
||||||
|
OtherSessionsAction.ReAuthCancelled -> handleReAuthCancelled()
|
||||||
|
OtherSessionsAction.SsoAuthDone -> handleSsoAuthDone()
|
||||||
is OtherSessionsAction.FilterDevices -> handleFilterDevices(action)
|
is OtherSessionsAction.FilterDevices -> handleFilterDevices(action)
|
||||||
OtherSessionsAction.DisableSelectMode -> handleDisableSelectMode()
|
OtherSessionsAction.DisableSelectMode -> handleDisableSelectMode()
|
||||||
is OtherSessionsAction.EnableSelectMode -> handleEnableSelectMode(action.deviceId)
|
is OtherSessionsAction.EnableSelectMode -> handleEnableSelectMode(action.deviceId)
|
||||||
@ -145,7 +167,80 @@ class OtherSessionsViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleMultiSignout() {
|
private fun handleMultiSignout() = withState { state ->
|
||||||
// TODO call multi signout use case with all or only selected devices depending on the ViewState
|
viewModelScope.launch {
|
||||||
|
setLoading(true)
|
||||||
|
val deviceIds = getDeviceIdsToSignout(state)
|
||||||
|
if (deviceIds.isEmpty()) {
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
val signoutResult = signout(deviceIds)
|
||||||
|
setLoading(false)
|
||||||
|
|
||||||
|
if (signoutResult.isSuccess) {
|
||||||
|
onSignoutSuccess()
|
||||||
|
} else {
|
||||||
|
when (val failure = signoutResult.exceptionOrNull()) {
|
||||||
|
null -> onSignoutSuccess()
|
||||||
|
else -> onSignoutFailure(failure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDeviceIdsToSignout(state: OtherSessionsViewState): List<String> {
|
||||||
|
return if (state.isSelectModeEnabled) {
|
||||||
|
state.devices()?.filter { it.isSelected }.orEmpty()
|
||||||
|
} else {
|
||||||
|
state.devices().orEmpty()
|
||||||
|
}.mapNotNull { it.deviceInfo.deviceId }
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun signout(deviceIds: List<String>) = signoutSessionsUseCase.execute(deviceIds, 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 -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
private fun onReAuthNeeded(reAuthNeeded: SignoutSessionResult.ReAuthNeeded) {
|
||||||
|
Timber.d("onReAuthNeeded")
|
||||||
|
pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session)
|
||||||
|
pendingAuthHandler.uiaContinuation = reAuthNeeded.uiaContinuation
|
||||||
|
_viewEvents.post(OtherSessionsViewEvents.RequestReAuth(reAuthNeeded.flowResponse, reAuthNeeded.errCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setLoading(isLoading: Boolean) {
|
||||||
|
setState { copy(isLoading = isLoading) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onSignoutSuccess() {
|
||||||
|
Timber.d("signout success")
|
||||||
|
refreshDeviceList()
|
||||||
|
_viewEvents.post(OtherSessionsViewEvents.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(OtherSessionsViewEvents.SignoutError(Exception(failureMessage)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSsoAuthDone() {
|
||||||
|
pendingAuthHandler.ssoAuthDone()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handlePasswordAuthDone(action: OtherSessionsAction.PasswordAuthDone) {
|
||||||
|
pendingAuthHandler.passwordAuthDone(action.password)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleReAuthCancelled() {
|
||||||
|
pendingAuthHandler.reAuthCancelled()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ data class OtherSessionsViewState(
|
|||||||
val currentFilter: DeviceManagerFilterType = DeviceManagerFilterType.ALL_SESSIONS,
|
val currentFilter: DeviceManagerFilterType = DeviceManagerFilterType.ALL_SESSIONS,
|
||||||
val excludeCurrentDevice: Boolean = false,
|
val excludeCurrentDevice: Boolean = false,
|
||||||
val isSelectModeEnabled: Boolean = false,
|
val isSelectModeEnabled: Boolean = false,
|
||||||
|
val isLoading: Boolean = false,
|
||||||
) : MavericksState {
|
) : MavericksState {
|
||||||
|
|
||||||
constructor(args: OtherSessionsArgs) : this(excludeCurrentDevice = args.excludeCurrentDevice)
|
constructor(args: OtherSessionsArgs) : this(excludeCurrentDevice = args.excludeCurrentDevice)
|
||||||
|
@ -21,6 +21,9 @@ import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
|||||||
import org.matrix.android.sdk.api.util.awaitCallback
|
import org.matrix.android.sdk.api.util.awaitCallback
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use case to signout a single session.
|
||||||
|
*/
|
||||||
class SignoutSessionUseCase @Inject constructor(
|
class SignoutSessionUseCase @Inject constructor(
|
||||||
private val activeSessionHolder: ActiveSessionHolder,
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
) {
|
) {
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.settings.devices.v2.signout
|
||||||
|
|
||||||
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
|
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||||
|
import org.matrix.android.sdk.api.util.awaitCallback
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use case to signout several sessions.
|
||||||
|
*/
|
||||||
|
class SignoutSessionsUseCase @Inject constructor(
|
||||||
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
|
) {
|
||||||
|
|
||||||
|
// TODO add unit tests
|
||||||
|
suspend fun execute(deviceIds: List<String>, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor): Result<Unit> {
|
||||||
|
return deleteDevices(deviceIds, userInteractiveAuthInterceptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun deleteDevices(deviceIds: List<String>, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) = runCatching {
|
||||||
|
awaitCallback { matrixCallback ->
|
||||||
|
activeSessionHolder.getActiveSession()
|
||||||
|
.cryptoService()
|
||||||
|
.deleteDevices(deviceIds, userInteractiveAuthInterceptor, matrixCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user