mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 18:35:40 +03:00
Verify from RoomMember Profile
This commit is contained in:
parent
a758efc018
commit
d60351bcb7
14 changed files with 198 additions and 165 deletions
|
@ -17,6 +17,7 @@
|
|||
package im.vector.matrix.android.api.session.crypto.sas
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
||||
import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest
|
||||
|
||||
/**
|
||||
|
@ -51,7 +52,7 @@ interface VerificationService {
|
|||
/**
|
||||
* Request a key verification from another user using toDevice events.
|
||||
*/
|
||||
fun requestKeyVerificationInDMs(methods: List<VerificationMethod>, userId: String, roomId: String): PendingVerificationRequest
|
||||
fun requestKeyVerificationInDMs(methods: List<VerificationMethod>, userId: String, roomId: String, localId: String? = LocalEcho.createLocalEchoId()): PendingVerificationRequest
|
||||
|
||||
fun declineVerificationRequestInDMs(otherUserId: String, otherDeviceId: String, transactionId: String, roomId: String)
|
||||
|
||||
|
|
|
@ -715,7 +715,7 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun requestKeyVerificationInDMs(methods: List<VerificationMethod>, userId: String, roomId: String)
|
||||
override fun requestKeyVerificationInDMs(methods: List<VerificationMethod>, userId: String, roomId: String, localId: String?)
|
||||
: PendingVerificationRequest {
|
||||
Timber.i("## SAS Requesting verification to user: $userId in room $roomId")
|
||||
|
||||
|
@ -737,7 +737,7 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
val localID = LocalEcho.createLocalEchoId()
|
||||
val localID = localId ?: LocalEcho.createLocalEchoId()
|
||||
|
||||
val verificationRequest = PendingVerificationRequest(
|
||||
ageLocalTs = System.currentTimeMillis(),
|
||||
|
|
|
@ -22,6 +22,7 @@ import im.vector.matrix.android.api.MatrixCallback
|
|||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.room.RoomSummaryQueryParams
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.VersioningState
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
|
@ -36,6 +37,7 @@ import im.vector.matrix.android.internal.database.query.where
|
|||
import im.vector.matrix.android.internal.query.process
|
||||
import im.vector.matrix.android.internal.session.room.alias.GetRoomIdByAliasTask
|
||||
import im.vector.matrix.android.internal.session.room.create.CreateRoomTask
|
||||
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
|
||||
import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask
|
||||
import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask
|
||||
import im.vector.matrix.android.internal.session.user.accountdata.UpdateBreadcrumbsTask
|
||||
|
@ -76,15 +78,21 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona
|
|||
|
||||
override fun getExistingDirectRoomWithUser(otherUserId: String): Room? {
|
||||
Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||
val roomId = RoomSummaryEntity.where(realm)
|
||||
val candidates = RoomSummaryEntity.where(realm)
|
||||
.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
|
||||
.findAll()?.let { dms ->
|
||||
dms.firstOrNull {
|
||||
it.otherMemberIds.contains(otherUserId)
|
||||
}
|
||||
.findAll()?.filter { dm ->
|
||||
dm.otherMemberIds.contains(otherUserId)
|
||||
&& dm.membership == Membership.JOIN
|
||||
}?.map {
|
||||
it.roomId
|
||||
}
|
||||
?.roomId ?: return null
|
||||
return RoomEntity.where(realm, roomId).findFirst()?.let { roomFactory.create(roomId) }
|
||||
?: return null
|
||||
candidates.forEach { roomId ->
|
||||
if (RoomMemberHelper(realm, roomId).getActiveRoomMemberIds().any { it == otherUserId }) {
|
||||
return RoomEntity.where(realm, roomId).findFirst()?.let { roomFactory.create(roomId) }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ import im.vector.riotx.features.crypto.verification.choose.VerificationChooseMet
|
|||
import im.vector.riotx.features.crypto.verification.conclusion.VerificationConclusionFragment
|
||||
import im.vector.riotx.features.crypto.verification.emoji.VerificationEmojiCodeFragment
|
||||
import im.vector.riotx.features.crypto.verification.request.VerificationRequestFragment
|
||||
import im.vector.riotx.features.crypto.verification.request.VerificationRequestViewModel
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_verification.*
|
||||
|
@ -57,8 +56,6 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
val roomId: String? = null
|
||||
) : Parcelable
|
||||
|
||||
@Inject
|
||||
lateinit var verificationRequestViewModelFactory: VerificationRequestViewModel.Factory
|
||||
@Inject
|
||||
lateinit var verificationViewModelFactory: VerificationBottomSheetViewModel.Factory
|
||||
@Inject
|
||||
|
@ -133,7 +130,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
it.otherUserMxItem?.id ?: "",
|
||||
// If it was outgoing it.transaction id would be null, but the pending request
|
||||
// would be updated (from localID to txId)
|
||||
it.pendingRequest?.transactionId ?: it.transactionId))
|
||||
it.pendingRequest.invoke()?.transactionId ?: it.transactionId))
|
||||
})
|
||||
}
|
||||
VerificationTxState.Verified,
|
||||
|
@ -153,36 +150,36 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
// At this point there is no transaction for this request
|
||||
|
||||
// Transaction has not yet started
|
||||
if (it.pendingRequest?.cancelConclusion != null) {
|
||||
if (it.pendingRequest.invoke()?.cancelConclusion != null) {
|
||||
// The request has been declined, we should dismiss
|
||||
dismiss()
|
||||
}
|
||||
|
||||
// If it's an outgoing
|
||||
if (it.pendingRequest == null || !it.pendingRequest.isIncoming) {
|
||||
if (it.pendingRequest.invoke() == null || it.pendingRequest.invoke()?.isIncoming == false) {
|
||||
Timber.v("## SAS show bottom sheet for outgoing request")
|
||||
if (it.pendingRequest?.isReady == true) {
|
||||
if (it.pendingRequest.invoke()?.isReady == true) {
|
||||
Timber.v("## SAS show bottom sheet for outgoing and ready request")
|
||||
// Show choose method fragment with waiting
|
||||
showFragment(VerificationChooseMethodFragment::class, Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, VerificationArgs(it.otherUserMxItem?.id
|
||||
?: "", it.pendingRequest.transactionId))
|
||||
?: "", it.pendingRequest.invoke()?.transactionId))
|
||||
})
|
||||
} else {
|
||||
// Stay on the start fragment
|
||||
showFragment(VerificationRequestFragment::class, Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, VerificationArgs(
|
||||
it.otherUserMxItem?.id ?: "",
|
||||
it.pendingRequest?.transactionId,
|
||||
it.pendingRequest.invoke()?.transactionId,
|
||||
it.roomId))
|
||||
})
|
||||
}
|
||||
} else if (it.pendingRequest.isIncoming) {
|
||||
} else if (it.pendingRequest.invoke()?.isIncoming == true) {
|
||||
Timber.v("## SAS show bottom sheet for Incoming request")
|
||||
// For incoming we can switch to choose method because ready is being sent or already sent
|
||||
showFragment(VerificationChooseMethodFragment::class, Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, VerificationArgs(it.otherUserMxItem?.id
|
||||
?: "", it.pendingRequest.transactionId))
|
||||
?: "", it.pendingRequest.invoke()?.transactionId))
|
||||
})
|
||||
}
|
||||
super.invalidate()
|
||||
|
@ -209,7 +206,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
fun withArgs(roomId: String?, otherUserId: String, transactionId: String? = null): VerificationBottomSheet {
|
||||
return VerificationBottomSheet().apply {
|
||||
arguments = Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, VerificationBottomSheet.VerificationArgs(
|
||||
putParcelable(MvRx.KEY_ARG, VerificationArgs(
|
||||
otherUserId = otherUserId,
|
||||
roomId = roomId,
|
||||
verificationId = transactionId
|
||||
|
|
|
@ -18,21 +18,27 @@ package im.vector.riotx.features.crypto.verification
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
||||
import im.vector.matrix.android.api.session.crypto.sas.QRVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationService
|
||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationService
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationTxState
|
||||
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.matrix.android.api.util.toMatrixItem
|
||||
import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest
|
||||
|
@ -43,7 +49,8 @@ import im.vector.riotx.core.utils.LiveEvent
|
|||
data class VerificationBottomSheetViewState(
|
||||
val otherUserMxItem: MatrixItem? = null,
|
||||
val roomId: String? = null,
|
||||
val pendingRequest: PendingVerificationRequest? = null,
|
||||
val pendingRequest: Async<PendingVerificationRequest> = Uninitialized,
|
||||
val pendingLocalId: String? = null,
|
||||
val transactionState: VerificationTxState? = null,
|
||||
val transactionId: String? = null,
|
||||
val cancelCode: CancelCode? = null
|
||||
|
@ -93,7 +100,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
|||
otherUserMxItem = userItem?.toMatrixItem(),
|
||||
transactionState = sasTx?.state,
|
||||
transactionId = args.verificationId,
|
||||
pendingRequest = pr,
|
||||
pendingRequest = if (pr != null) Success(pr) else Uninitialized,
|
||||
roomId = args.roomId)
|
||||
)
|
||||
}
|
||||
|
@ -106,9 +113,40 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
|||
|
||||
when (action) {
|
||||
is VerificationAction.RequestVerificationByDM -> {
|
||||
if (roomId == null) return@withState
|
||||
setState {
|
||||
copy(pendingRequest = session.getSasVerificationService().requestKeyVerificationInDMs(supportedVerificationMethods, otherUserId, roomId))
|
||||
if (roomId == null) {
|
||||
val localID = LocalEcho.createLocalEchoId()
|
||||
setState {
|
||||
copy(
|
||||
pendingLocalId = localID,
|
||||
pendingRequest = Loading()
|
||||
)
|
||||
}
|
||||
val roomParams = CreateRoomParams().apply {
|
||||
invitedUserIds = listOf(otherUserId).toMutableList()
|
||||
setDirectMessage()
|
||||
}
|
||||
session.createRoom(roomParams, object : MatrixCallback<String> {
|
||||
override fun onSuccess(data: String) {
|
||||
setState {
|
||||
copy(
|
||||
roomId = data,
|
||||
pendingRequest = Success(
|
||||
session.getSasVerificationService().requestKeyVerificationInDMs(supportedVerificationMethods, otherUserId, data, pendingLocalId)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
setState {
|
||||
copy(pendingRequest = Fail(failure))
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
setState {
|
||||
copy(pendingRequest = Success(session.getSasVerificationService().requestKeyVerificationInDMs(supportedVerificationMethods, otherUserId, roomId)))
|
||||
}
|
||||
}
|
||||
}
|
||||
is VerificationAction.StartSASVerification -> {
|
||||
|
@ -154,7 +192,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
|||
}
|
||||
|
||||
override fun transactionUpdated(tx: VerificationTransaction) = withState { state ->
|
||||
if (tx.transactionId == (state.pendingRequest?.transactionId ?: state.transactionId)) {
|
||||
if (tx.transactionId == (state.pendingRequest.invoke()?.transactionId ?: state.transactionId)) {
|
||||
// A SAS tx has been started following this request
|
||||
setState {
|
||||
copy(
|
||||
|
@ -171,9 +209,11 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
|||
|
||||
override fun verificationRequestUpdated(pr: PendingVerificationRequest) = withState { state ->
|
||||
|
||||
if (pr.localID == state.pendingRequest?.localID || state.pendingRequest?.transactionId == pr.transactionId) {
|
||||
if (pr.localID == state.pendingLocalId
|
||||
|| pr.localID == state.pendingRequest.invoke()?.localID
|
||||
|| state.pendingRequest.invoke()?.transactionId == pr.transactionId) {
|
||||
setState {
|
||||
copy(pendingRequest = pr)
|
||||
copy(pendingRequest = Success(pr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ class VerificationChooseMethodFragment @Inject constructor(
|
|||
override fun doVerifyBySas() = withState(sharedViewModel) {
|
||||
sharedViewModel.handle(VerificationAction.StartSASVerification(
|
||||
it.otherUserMxItem?.id ?: "",
|
||||
it.pendingRequest?.transactionId ?: ""))
|
||||
it.pendingRequest.invoke()?.transactionId ?: ""))
|
||||
}
|
||||
|
||||
override fun openCamera() {
|
||||
|
@ -115,7 +115,7 @@ class VerificationChooseMethodFragment @Inject constructor(
|
|||
private fun onRemoteQrCodeScanned(remoteQrCode: String) = withState(sharedViewModel) {
|
||||
sharedViewModel.handle(VerificationAction.RemoteQrCodeScanned(
|
||||
it.otherUserMxItem?.id ?: "",
|
||||
it.pendingRequest?.transactionId ?: "",
|
||||
it.pendingRequest.invoke()?.transactionId ?: "",
|
||||
remoteQrCode
|
||||
))
|
||||
}
|
||||
|
|
|
@ -19,11 +19,14 @@ package im.vector.riotx.features.crypto.verification.request
|
|||
import androidx.core.text.toSpannable
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.dividerItem
|
||||
import im.vector.riotx.core.resources.ColorProvider
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.core.utils.colorizeMatchingText
|
||||
import im.vector.riotx.features.crypto.verification.VerificationBottomSheetViewState
|
||||
import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||
import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||
import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
|
||||
|
@ -36,17 +39,18 @@ class VerificationRequestController @Inject constructor(
|
|||
|
||||
var listener: Listener? = null
|
||||
|
||||
private var viewState: VerificationRequestViewState? = null
|
||||
private var viewState: VerificationBottomSheetViewState? = null
|
||||
|
||||
fun update(viewState: VerificationRequestViewState) {
|
||||
fun update(viewState: VerificationBottomSheetViewState) {
|
||||
this.viewState = viewState
|
||||
requestModelBuild()
|
||||
}
|
||||
|
||||
override fun buildModels() {
|
||||
val state = viewState ?: return
|
||||
val matrixItem = viewState?.otherUserMxItem ?: return
|
||||
|
||||
val styledText = state.matrixItem.let {
|
||||
val styledText = matrixItem.let {
|
||||
stringProvider.getString(R.string.verification_request_notice, it.id)
|
||||
.toSpannable()
|
||||
.colorizeMatchingText(it.id, colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color))
|
||||
|
@ -61,14 +65,8 @@ class VerificationRequestController @Inject constructor(
|
|||
id("sep")
|
||||
}
|
||||
|
||||
when (state.started) {
|
||||
is Loading -> {
|
||||
bottomSheetVerificationWaitingItem {
|
||||
id("waiting")
|
||||
title(stringProvider.getString(R.string.verification_request_waiting_for, state.matrixItem.getBestName()))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
when (val pr = state.pendingRequest) {
|
||||
is Uninitialized -> {
|
||||
bottomSheetVerificationActionItem {
|
||||
id("start")
|
||||
title(stringProvider.getString(R.string.start_verification))
|
||||
|
@ -79,6 +77,20 @@ class VerificationRequestController @Inject constructor(
|
|||
listener { listener?.onClickOnVerificationStart() }
|
||||
}
|
||||
}
|
||||
is Loading -> {
|
||||
bottomSheetVerificationWaitingItem {
|
||||
id("waiting")
|
||||
title(stringProvider.getString(R.string.verification_request_waiting_for, matrixItem.getBestName()))
|
||||
}
|
||||
}
|
||||
is Success -> {
|
||||
if (!pr.invoke().isReady) {
|
||||
bottomSheetVerificationWaitingItem {
|
||||
id("waiting")
|
||||
title(stringProvider.getString(R.string.verification_request_waiting_for, matrixItem.getBestName()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,22 +30,19 @@ import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
|||
import javax.inject.Inject
|
||||
|
||||
class VerificationRequestFragment @Inject constructor(
|
||||
val verificationRequestViewModelFactory: VerificationRequestViewModel.Factory,
|
||||
val controller: VerificationRequestController
|
||||
) : VectorBaseFragment(), VerificationRequestController.Listener {
|
||||
|
||||
private val viewModel by fragmentViewModel(VerificationRequestViewModel::class)
|
||||
|
||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setupRecyclerView()
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.listener = null
|
||||
|
@ -61,7 +58,9 @@ class VerificationRequestFragment @Inject constructor(
|
|||
controller.update(state)
|
||||
}
|
||||
|
||||
override fun onClickOnVerificationStart() = withState(viewModel) { state ->
|
||||
sharedViewModel.handle(VerificationAction.RequestVerificationByDM(state.matrixItem.id, state.roomId))
|
||||
override fun onClickOnVerificationStart(): Unit = withState(viewModel) { state ->
|
||||
state.otherUserMxItem?.id?.let { otherUserId ->
|
||||
viewModel.handle(VerificationAction.RequestVerificationByDM(otherUserId, state.roomId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.crypto.verification.request
|
||||
|
||||
import com.airbnb.mvrx.*
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationService
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationTransaction
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.matrix.android.api.util.toMatrixItem
|
||||
import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest
|
||||
import im.vector.riotx.core.di.HasScreenInjector
|
||||
import im.vector.riotx.core.platform.EmptyAction
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
||||
|
||||
data class VerificationRequestViewState(
|
||||
val roomId: String? = null,
|
||||
val matrixItem: MatrixItem,
|
||||
val started: Async<Boolean> = Success(false)
|
||||
) : MvRxState
|
||||
|
||||
class VerificationRequestViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: VerificationRequestViewState,
|
||||
private val session: Session
|
||||
) : VectorViewModel<VerificationRequestViewState, EmptyAction>(initialState), VerificationService.VerificationListener {
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(initialState: VerificationRequestViewState): VerificationRequestViewModel
|
||||
}
|
||||
|
||||
init {
|
||||
session.getSasVerificationService().addListener(this)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
session.getSasVerificationService().removeListener(this)
|
||||
super.onCleared()
|
||||
}
|
||||
|
||||
companion object : MvRxViewModelFactory<VerificationRequestViewModel, VerificationRequestViewState> {
|
||||
override fun create(viewModelContext: ViewModelContext, state: VerificationRequestViewState): VerificationRequestViewModel? {
|
||||
val fragment: VerificationRequestFragment = (viewModelContext as FragmentViewModelContext).fragment()
|
||||
return fragment.verificationRequestViewModelFactory.create(state)
|
||||
}
|
||||
|
||||
override fun initialState(viewModelContext: ViewModelContext): VerificationRequestViewState? {
|
||||
val args = viewModelContext.args<VerificationBottomSheet.VerificationArgs>()
|
||||
val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
|
||||
|
||||
val pr = session.getSasVerificationService()
|
||||
.getExistingVerificationRequest(args.otherUserId, args.verificationId)
|
||||
return session.getUser(args.otherUserId)?.let {
|
||||
VerificationRequestViewState(
|
||||
started = Success(false).takeIf { pr == null }
|
||||
?: Success(true).takeIf { pr?.isReady == true }
|
||||
?: Loading(),
|
||||
matrixItem = it.toMatrixItem()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(action: EmptyAction) {}
|
||||
|
||||
override fun transactionCreated(tx: VerificationTransaction) {}
|
||||
|
||||
override fun transactionUpdated(tx: VerificationTransaction) {}
|
||||
|
||||
override fun verificationRequestCreated(pr: PendingVerificationRequest) {
|
||||
verificationRequestUpdated(pr)
|
||||
}
|
||||
|
||||
override fun verificationRequestUpdated(pr: PendingVerificationRequest) = withState { state ->
|
||||
if (pr.otherUserId == state.matrixItem.id) {
|
||||
if (pr.isReady) {
|
||||
setState {
|
||||
copy(started = Success(true))
|
||||
}
|
||||
} else {
|
||||
setState {
|
||||
copy(started = Loading())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1027,6 +1027,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onAvatarClicked(informationData: MessageInformationData) {
|
||||
//roomDetailViewModel.handle(RoomDetailAction.RequestVerification(informationData.senderId))
|
||||
openRoomMemberProfile(informationData.senderId)
|
||||
}
|
||||
|
||||
|
|
|
@ -23,4 +23,5 @@ sealed class RoomMemberProfileAction : VectorViewModelAction {
|
|||
|
||||
object RetryFetchingInfo: RoomMemberProfileAction()
|
||||
object IgnoreUser: RoomMemberProfileAction()
|
||||
data class VerifyUser(val userId: String? = null, val roomId: String? = null): RoomMemberProfileAction()
|
||||
}
|
||||
|
|
|
@ -37,7 +37,9 @@ class RoomMemberProfileController @Inject constructor(
|
|||
|
||||
interface Callback {
|
||||
fun onIgnoreClicked()
|
||||
fun onLearnMoreClicked()
|
||||
fun onTapVerify()
|
||||
fun onShowDeviceList()
|
||||
fun onShowDeviceListNoCrossSigning()
|
||||
fun onJumpToReadReceiptClicked()
|
||||
fun onMentionClicked()
|
||||
}
|
||||
|
@ -90,7 +92,7 @@ class RoomMemberProfileController @Inject constructor(
|
|||
editable = true,
|
||||
icon = icon,
|
||||
divider = false,
|
||||
action = { callback?.onLearnMoreClicked() }
|
||||
action = { callback?.onShowDeviceList() }
|
||||
)
|
||||
} else {
|
||||
//Not trusted, propose to verify
|
||||
|
@ -102,7 +104,7 @@ class RoomMemberProfileController @Inject constructor(
|
|||
editable = true,
|
||||
icon = R.drawable.ic_shield_black,
|
||||
divider = false,
|
||||
action = { callback?.onLearnMoreClicked() }
|
||||
action = { callback?.onTapVerify() }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -120,7 +122,7 @@ class RoomMemberProfileController @Inject constructor(
|
|||
editable = false,
|
||||
divider = false,
|
||||
subtitle = stringProvider.getString(R.string.room_profile_encrypted_subtitle),
|
||||
action = { callback?.onLearnMoreClicked() }
|
||||
action = { callback?.onShowDeviceListNoCrossSigning() }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -20,16 +20,23 @@ package im.vector.riotx.features.roommemberprofile
|
|||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import com.airbnb.mvrx.*
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.animations.AppBarStateChangeListener
|
||||
import im.vector.riotx.core.animations.MatrixItemAppBarStateChangeListener
|
||||
import im.vector.riotx.core.extensions.cleanup
|
||||
import im.vector.riotx.core.extensions.configureWith
|
||||
import im.vector.riotx.core.extensions.observeEvent
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
import im.vector.riotx.core.platform.StateView
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
||||
|
@ -83,6 +90,21 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
viewModel.actionResultLiveData.observeEvent(this) { async ->
|
||||
when (async) {
|
||||
is Success -> {
|
||||
when (val action = async.invoke()) {
|
||||
is RoomMemberProfileAction.VerifyUser -> {
|
||||
VerificationBottomSheet
|
||||
.withArgs(roomId = null, otherUserId = action.userId!!)
|
||||
.show(parentFragmentManager, "VERIF")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -126,8 +148,39 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
viewModel.handle(RoomMemberProfileAction.IgnoreUser)
|
||||
}
|
||||
|
||||
override fun onLearnMoreClicked() {
|
||||
vectorBaseActivity.notImplemented("Learn more")
|
||||
override fun onTapVerify() {
|
||||
viewModel.handle(RoomMemberProfileAction.VerifyUser())
|
||||
// if (state.isRoomEncrypted) {
|
||||
// if( !state.isMine && state.userMXCrossSigningInfo?.isTrusted == false) {
|
||||
// // we want to verify
|
||||
// // TODO do not use current room, find or create DM
|
||||
// VerificationBottomSheet.withArgs(
|
||||
// state.roomId,
|
||||
// state.userId
|
||||
// ).show(parentFragmentManager, "REQ")
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// override fun onTapVerify() = withState(viewModel) { state ->
|
||||
// if (state.isRoomEncrypted) {
|
||||
// if( !state.isMine && state.userMXCrossSigningInfo?.isTrusted == false) {
|
||||
// // we want to verify
|
||||
// // TODO do not use current room, find or create DM
|
||||
// VerificationBottomSheet.withArgs(
|
||||
// state.roomId,
|
||||
// state.userId
|
||||
// ).show(parentFragmentManager, "REQ")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
override fun onShowDeviceList() {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun onShowDeviceListNoCrossSigning() {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun onJumpToReadReceiptClicked() {
|
||||
|
|
|
@ -17,9 +17,13 @@
|
|||
|
||||
package im.vector.riotx.features.roommemberprofile
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
|
@ -46,6 +50,7 @@ import im.vector.riotx.core.di.HasScreenInjector
|
|||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.core.utils.DataSource
|
||||
import im.vector.riotx.core.utils.LiveEvent
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
|
@ -86,6 +91,10 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
|||
private val _viewEvents = PublishDataSource<RoomMemberProfileViewEvents>()
|
||||
val viewEvents: DataSource<RoomMemberProfileViewEvents> = _viewEvents
|
||||
|
||||
private val _actionResultLiveData = MutableLiveData<LiveEvent<Async<RoomMemberProfileAction>>>()
|
||||
val actionResultLiveData: LiveData<LiveEvent<Async<RoomMemberProfileAction>>>
|
||||
get() = _actionResultLiveData
|
||||
|
||||
private val room = if (initialState.roomId != null) {
|
||||
session.getRoom(initialState.roomId)
|
||||
} else {
|
||||
|
@ -112,7 +121,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
|||
|
||||
session.rx().liveUserCryptoDevices(initialState.userId)
|
||||
.map {
|
||||
it.fold(true, { prev, dev -> prev && dev.isVerified})
|
||||
it.fold(true, { prev, dev -> prev && dev.isVerified })
|
||||
}
|
||||
.execute {
|
||||
copy(allDevicesAreTrusted = it)
|
||||
|
@ -134,11 +143,25 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
|||
|
||||
override fun handle(action: RoomMemberProfileAction) {
|
||||
when (action) {
|
||||
RoomMemberProfileAction.RetryFetchingInfo -> fetchProfileInfo()
|
||||
is RoomMemberProfileAction.IgnoreUser -> handleIgnoreAction()
|
||||
is RoomMemberProfileAction.RetryFetchingInfo -> fetchProfileInfo()
|
||||
is RoomMemberProfileAction.IgnoreUser -> handleIgnoreAction()
|
||||
is RoomMemberProfileAction.VerifyUser -> prepareVerification(action)
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareVerification(action: RoomMemberProfileAction.VerifyUser) = withState { state ->
|
||||
// Sanity
|
||||
if (state.isRoomEncrypted) {
|
||||
if (!state.isMine && state.userMXCrossSigningInfo?.isTrusted == false) {
|
||||
// ok, let's find or create the DM room
|
||||
_actionResultLiveData.postValue(
|
||||
LiveEvent(Success(action.copy(userId = state.userId)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun observeRoomMemberSummary(room: Room) {
|
||||
val queryParams = roomMemberQueryParams {
|
||||
this.userId = QueryStringValue.Equals(initialState.userId, QueryStringValue.Case.SENSITIVE)
|
||||
|
@ -163,7 +186,6 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
|||
.execute {
|
||||
copy(userMatrixItem = it)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun observeRoomSummaryAndPowerLevels(room: Room) {
|
||||
|
|
Loading…
Reference in a new issue