Merge pull request #7130 from vector-im/feature/bma/fix_verification

Fix empty verification bottom sheet
This commit is contained in:
Benoit Marty 2022-09-16 19:00:39 +02:00 committed by GitHub
commit 73e061e472
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 134 additions and 101 deletions

1
changelog.d/7130.bugfix Normal file
View file

@ -0,0 +1 @@
Fix empty verification bottom sheet.

View file

@ -32,5 +32,13 @@ fun Session.getRoomSummary(roomIdOrAlias: String): RoomSummary? = roomService().
/** /**
* Get a user using the UserService of a Session. * Get a user using the UserService of a Session.
* @param userId the userId to look for.
* @return a user with userId or null if the User is not known yet by the SDK.
* See [org.matrix.android.sdk.api.session.user.UserService.resolveUser] to ensure that a User is retrieved.
*/ */
fun Session.getUser(userId: String): User? = userService().getUser(userId) fun Session.getUser(userId: String): User? = userService().getUser(userId)
/**
* Similar to [getUser], but fallback to a User without details if the User is not known by the SDK, or if Session is null.
*/
fun Session?.getUserOrDefault(userId: String): User = this?.userService()?.getUser(userId) ?: User(userId)

View file

@ -29,7 +29,7 @@ interface UserService {
/** /**
* Get a user from a userId. * Get a user from a userId.
* @param userId the userId to look for. * @param userId the userId to look for.
* @return a user with userId or null * @return a user with userId or null if the User is not known yet by the SDK. See [resolveUser] to ensure that a User is retrieved.
*/ */
fun getUser(userId: String): User? fun getUser(userId: String): User?

View file

@ -37,11 +37,10 @@ import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.session.getUserOrDefault
import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkData
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.user.model.User
class CreateDirectRoomViewModel @AssistedInject constructor( class CreateDirectRoomViewModel @AssistedInject constructor(
@Assisted initialState: CreateDirectRoomViewState, @Assisted initialState: CreateDirectRoomViewState,
@ -78,11 +77,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(
_viewEvents.post(CreateDirectRoomViewEvents.DmSelf) _viewEvents.post(CreateDirectRoomViewEvents.DmSelf)
} else { } else {
// Try to get user from known users and fall back to creating a User object from MXID // Try to get user from known users and fall back to creating a User object from MXID
val qrInvitee = if (session.getUser(mxid) != null) { val qrInvitee = session.getUserOrDefault(mxid)
session.getUser(mxid)!!
} else {
User(mxid, null, null)
}
onSubmitInvitees(setOf(PendingSelection.UserPendingSelection(qrInvitee))) onSubmitInvitees(setOf(PendingSelection.UserPendingSelection(qrInvitee)))
} }
} }

View file

@ -31,6 +31,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificatio
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
import org.matrix.android.sdk.api.session.getUserOrDefault
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -67,8 +68,8 @@ class IncomingVerificationRequestHandler @Inject constructor(
when (tx.state) { when (tx.state) {
is VerificationTxState.OnStarted -> { is VerificationTxState.OnStarted -> {
// Add a notification for every incoming request // Add a notification for every incoming request
val user = session?.userService()?.getUser(tx.otherUserId) val user = session.getUserOrDefault(tx.otherUserId).toMatrixItem()
val name = user?.toMatrixItem()?.getBestName() ?: tx.otherUserId val name = user.getBestName()
val alert = VerificationVectorAlert( val alert = VerificationVectorAlert(
uid, uid,
context.getString(R.string.sas_incoming_request_notif_title), context.getString(R.string.sas_incoming_request_notif_title),
@ -86,7 +87,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
} }
) )
.apply { .apply {
viewBinder = VerificationVectorAlert.ViewBinder(user?.toMatrixItem(), avatarRenderer.get()) viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer.get())
contentAction = Runnable { contentAction = Runnable {
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId) it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
@ -131,8 +132,8 @@ class IncomingVerificationRequestHandler @Inject constructor(
// XXX this is a bit hard coded :/ // XXX this is a bit hard coded :/
popupAlertManager.cancelAlert("review_login") popupAlertManager.cancelAlert("review_login")
} }
val user = session?.userService()?.getUser(pr.otherUserId)?.toMatrixItem() val user = session.getUserOrDefault(pr.otherUserId).toMatrixItem()
val name = user?.getBestName() ?: pr.otherUserId val name = user.getBestName()
val description = if (name == pr.otherUserId) { val description = if (name == pr.otherUserId) {
name name
} else { } else {

View file

@ -152,29 +152,25 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
} }
override fun invalidate() = withState(viewModel) { state -> override fun invalidate() = withState(viewModel) { state ->
state.otherUserMxItem?.let { matrixItem -> avatarRenderer.render(state.otherUserMxItem, views.otherUserAvatarImageView)
if (state.isMe) { if (state.isMe) {
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView) if (state.sasTransactionState == VerificationTxState.Verified ||
if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified ||
state.qrTransactionState == VerificationTxState.Verified || state.verifiedFromPrivateKeys) {
state.verifiedFromPrivateKeys) { views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
} else {
views.otherUserShield.render(RoomEncryptionTrustLevel.Warning)
}
views.otherUserNameText.text = getString(
if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session
)
} else { } else {
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView) views.otherUserShield.render(RoomEncryptionTrustLevel.Warning)
}
if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) { views.otherUserNameText.text = getString(
views.otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName()) if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session
views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted) )
} else { } else {
views.otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName()) if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) {
views.otherUserShield.render(null) views.otherUserNameText.text = getString(R.string.verification_verified_user, state.otherUserMxItem.getBestName())
} views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
} else {
views.otherUserNameText.text = getString(R.string.verification_verify_user, state.otherUserMxItem.getBestName())
views.otherUserShield.render(null)
} }
} }
@ -235,7 +231,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
showFragment( showFragment(
VerificationEmojiCodeFragment::class, VerificationEmojiCodeFragment::class,
VerificationArgs( VerificationArgs(
state.otherUserMxItem?.id ?: "", state.otherUserId,
// If it was outgoing it.transaction id would be null, but the pending request // If it was outgoing it.transaction id would be null, but the pending request
// would be updated (from localId to txId) // would be updated (from localId to txId)
state.pendingRequest.invoke()?.transactionId ?: state.transactionId state.pendingRequest.invoke()?.transactionId ?: state.transactionId
@ -271,7 +267,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
VerificationQRWaitingFragment::class, VerificationQRWaitingFragment::class,
VerificationQRWaitingFragment.Args( VerificationQRWaitingFragment.Args(
isMe = state.isMe, isMe = state.isMe,
otherUserName = state.otherUserMxItem?.getBestName() ?: "" otherUserName = state.otherUserMxItem.getBestName()
) )
) )
return@withState return@withState
@ -319,7 +315,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
showFragment( showFragment(
VerificationChooseMethodFragment::class, VerificationChooseMethodFragment::class,
VerificationArgs( VerificationArgs(
otherUserId = state.otherUserMxItem?.id ?: "", otherUserId = state.otherUserId,
verificationId = state.pendingRequest.invoke()?.transactionId verificationId = state.pendingRequest.invoke()?.transactionId
) )
) )
@ -328,7 +324,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
showFragment( showFragment(
VerificationRequestFragment::class, VerificationRequestFragment::class,
VerificationArgs( VerificationArgs(
otherUserId = state.otherUserMxItem?.id ?: "", otherUserId = state.otherUserId,
verificationId = state.pendingRequest.invoke()?.transactionId, verificationId = state.pendingRequest.invoke()?.transactionId,
verificationLocalId = state.roomId verificationLocalId = state.roomId
) )
@ -340,7 +336,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
showFragment( showFragment(
VerificationChooseMethodFragment::class, VerificationChooseMethodFragment::class,
VerificationArgs( VerificationArgs(
otherUserId = state.otherUserMxItem?.id ?: "", otherUserId = state.otherUserId,
verificationId = state.pendingRequest.invoke()?.transactionId verificationId = state.pendingRequest.invoke()?.transactionId
) )
) )

View file

@ -37,6 +37,7 @@ import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
@ -70,7 +71,7 @@ data class VerificationBottomSheetViewState(
val roomId: String?, val roomId: String?,
// true when we display the loading and we wait for the other (incoming request) // true when we display the loading and we wait for the other (incoming request)
val selfVerificationMode: Boolean, val selfVerificationMode: Boolean,
val otherUserMxItem: MatrixItem? = null, val otherUserMxItem: MatrixItem,
val pendingRequest: Async<PendingVerificationRequest> = Uninitialized, val pendingRequest: Async<PendingVerificationRequest> = Uninitialized,
val pendingLocalId: String? = null, val pendingLocalId: String? = null,
val sasTransactionState: VerificationTxState? = null, val sasTransactionState: VerificationTxState? = null,
@ -92,7 +93,8 @@ data class VerificationBottomSheetViewState(
otherUserId = args.otherUserId, otherUserId = args.otherUserId,
verificationId = args.verificationId, verificationId = args.verificationId,
roomId = args.roomId, roomId = args.roomId,
selfVerificationMode = args.selfVerificationMode selfVerificationMode = args.selfVerificationMode,
otherUserMxItem = MatrixItem.UserItem(args.otherUserId),
) )
} }
@ -126,7 +128,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
} }
} }
val userItem = session.getUser(initialState.otherUserId) fetchOtherUserProfile(initialState.otherUserId)
var autoReady = false var autoReady = false
val pr = if (initialState.selfVerificationMode) { val pr = if (initialState.selfVerificationMode) {
@ -160,7 +162,6 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
setState { setState {
copy( copy(
otherUserMxItem = userItem?.toMatrixItem(),
sasTransactionState = sasTx?.state, sasTransactionState = sasTx?.state,
qrTransactionState = qrTx?.state, qrTransactionState = qrTx?.state,
transactionId = pr?.transactionId ?: initialState.verificationId, transactionId = pr?.transactionId ?: initialState.verificationId,
@ -183,6 +184,28 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
} }
} }
private fun fetchOtherUserProfile(otherUserId: String) {
session.getUser(otherUserId)?.toMatrixItem()?.let {
setState {
copy(
otherUserMxItem = it
)
}
}
// Always fetch the latest User data
viewModelScope.launch {
tryOrNull { session.userService().resolveUser(otherUserId) }
?.toMatrixItem()
?.let {
setState {
copy(
otherUserMxItem = it
)
}
}
}
}
override fun onCleared() { override fun onCleared() {
session.cryptoService().verificationService().removeListener(this) session.cryptoService().verificationService().removeListener(this)
super.onCleared() super.onCleared()
@ -216,12 +239,12 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
private fun cancelAllPendingVerifications(state: VerificationBottomSheetViewState) { private fun cancelAllPendingVerifications(state: VerificationBottomSheetViewState) {
session.cryptoService() session.cryptoService()
.verificationService().getExistingVerificationRequest(state.otherUserMxItem?.id ?: "", state.transactionId)?.let { .verificationService().getExistingVerificationRequest(state.otherUserId, state.transactionId)?.let {
session.cryptoService().verificationService().cancelVerificationRequest(it) session.cryptoService().verificationService().cancelVerificationRequest(it)
} }
session.cryptoService() session.cryptoService()
.verificationService() .verificationService()
.getExistingTransaction(state.otherUserMxItem?.id ?: "", state.transactionId ?: "") .getExistingTransaction(state.otherUserId, state.transactionId ?: "")
?.cancel(CancelCode.User) ?.cancel(CancelCode.User)
} }
@ -249,7 +272,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
} }
override fun handle(action: VerificationAction) = withState { state -> override fun handle(action: VerificationAction) = withState { state ->
val otherUserId = state.otherUserMxItem?.id ?: return@withState val otherUserId = state.otherUserId
val roomId = state.roomId val roomId = state.roomId
?: session.roomService().getExistingDirectRoomWithUser(otherUserId) ?: session.roomService().getExistingDirectRoomWithUser(otherUserId)
@ -514,7 +537,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
override fun transactionUpdated(tx: VerificationTransaction) = withState { state -> override fun transactionUpdated(tx: VerificationTransaction) = withState { state ->
if (state.selfVerificationMode && state.transactionId == null) { if (state.selfVerificationMode && state.transactionId == null) {
// is this an incoming with that user // is this an incoming with that user
if (tx.isIncoming && tx.otherUserId == state.otherUserMxItem?.id) { if (tx.isIncoming && tx.otherUserId == state.otherUserId) {
// Also auto accept incoming if needed! // Also auto accept incoming if needed!
if (tx is IncomingSasVerificationTransaction) { if (tx is IncomingSasVerificationTransaction) {
if (tx.uxState == IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT) { if (tx.uxState == IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT) {
@ -564,7 +587,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
if (state.selfVerificationMode && state.pendingRequest.invoke() == null && state.transactionId == null) { if (state.selfVerificationMode && state.pendingRequest.invoke() == null && state.transactionId == null) {
// is this an incoming with that user // is this an incoming with that user
if (pr.isIncoming && pr.otherUserId == state.otherUserMxItem?.id) { if (pr.isIncoming && pr.otherUserId == state.otherUserId) {
if (!pr.isReady) { if (!pr.isReady) {
// auto ready in this case, as we are waiting // auto ready in this case, as we are waiting
// TODO, can I be here in DM mode? in this case should test if roomID is null? // TODO, can I be here in DM mode? in this case should test if roomID is null?

View file

@ -26,6 +26,7 @@ import im.vector.app.core.utils.colorizeMatchingText
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
import im.vector.app.features.displayname.getBestName
import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
import javax.inject.Inject import javax.inject.Inject
@ -60,8 +61,8 @@ class VerificationCancelController @Inject constructor(
} }
} }
} else { } else {
val otherUserID = state.otherUserMxItem?.id ?: "" val otherUserID = state.otherUserId
val otherDisplayName = state.otherUserMxItem?.displayName ?: "" val otherDisplayName = state.otherUserMxItem.getBestName()
bottomSheetVerificationNoticeItem { bottomSheetVerificationNoticeItem {
id("notice") id("notice")
notice( notice(

View file

@ -78,7 +78,7 @@ class VerificationChooseMethodFragment :
override fun doVerifyBySas() = withState(sharedViewModel) { state -> override fun doVerifyBySas() = withState(sharedViewModel) { state ->
sharedViewModel.handle( sharedViewModel.handle(
VerificationAction.StartSASVerification( VerificationAction.StartSASVerification(
state.otherUserMxItem?.id ?: "", state.otherUserId,
state.pendingRequest.invoke()?.transactionId ?: "" state.pendingRequest.invoke()?.transactionId ?: ""
) )
) )
@ -130,7 +130,7 @@ class VerificationChooseMethodFragment :
private fun onRemoteQrCodeScanned(remoteQrCode: String) = withState(sharedViewModel) { state -> private fun onRemoteQrCodeScanned(remoteQrCode: String) = withState(sharedViewModel) { state ->
sharedViewModel.handle( sharedViewModel.handle(
VerificationAction.RemoteQrCodeScanned( VerificationAction.RemoteQrCodeScanned(
state.otherUserMxItem?.id ?: "", state.otherUserId,
state.pendingRequest.invoke()?.transactionId ?: "", state.pendingRequest.invoke()?.transactionId ?: "",
remoteQrCode remoteQrCode
) )

View file

@ -136,7 +136,7 @@ class VerificationEmojiCodeController @Inject constructor(
if (state.isWaitingFromOther) { if (state.isWaitingFromOther) {
bottomSheetVerificationWaitingItem { bottomSheetVerificationWaitingItem {
id("waiting") id("waiting")
title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUser?.getBestName() ?: "")) title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUser.getBestName()))
} }
} else { } else {
bottomSheetVerificationActionItem { bottomSheetVerificationActionItem {

View file

@ -68,13 +68,13 @@ class VerificationEmojiCodeFragment :
} }
override fun onMatchButtonTapped() = withState(viewModel) { state -> override fun onMatchButtonTapped() = withState(viewModel) { state ->
val otherUserId = state.otherUser?.id ?: return@withState val otherUserId = state.otherUser.id
val txId = state.transactionId ?: return@withState val txId = state.transactionId ?: return@withState
sharedViewModel.handle(VerificationAction.SASMatchAction(otherUserId, txId)) sharedViewModel.handle(VerificationAction.SASMatchAction(otherUserId, txId))
} }
override fun onDoNotMatchButtonTapped() = withState(viewModel) { state -> override fun onDoNotMatchButtonTapped() = withState(viewModel) { state ->
val otherUserId = state.otherUser?.id ?: return@withState val otherUserId = state.otherUser.id
val txId = state.transactionId ?: return@withState val txId = state.transactionId ?: return@withState
sharedViewModel.handle(VerificationAction.SASDoNotMatchAction(otherUserId, txId)) sharedViewModel.handle(VerificationAction.SASDoNotMatchAction(otherUserId, txId))
} }

View file

@ -40,13 +40,13 @@ import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTra
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.session.getUserOrDefault
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
data class VerificationEmojiCodeViewState( data class VerificationEmojiCodeViewState(
val transactionId: String?, val transactionId: String?,
val otherUser: MatrixItem? = null, val otherUser: MatrixItem,
val supportsEmoji: Boolean = true, val supportsEmoji: Boolean = true,
val emojiDescription: Async<List<EmojiRepresentation>> = Uninitialized, val emojiDescription: Async<List<EmojiRepresentation>> = Uninitialized,
val decimalDescription: Async<String> = Uninitialized, val decimalDescription: Async<String> = Uninitialized,
@ -59,15 +59,13 @@ class VerificationEmojiCodeViewModel @AssistedInject constructor(
) : VectorViewModel<VerificationEmojiCodeViewState, EmptyAction, EmptyViewEvents>(initialState), VerificationService.Listener { ) : VectorViewModel<VerificationEmojiCodeViewState, EmptyAction, EmptyViewEvents>(initialState), VerificationService.Listener {
init { init {
withState { state -> refreshStateFromTx(
refreshStateFromTx( session.cryptoService().verificationService()
session.cryptoService().verificationService() .getExistingTransaction(
.getExistingTransaction( otherUserId = initialState.otherUser.id,
state.otherUser?.id ?: "", state.transactionId tid = initialState.transactionId ?: ""
?: "" ) as? SasVerificationTransaction
) as? SasVerificationTransaction )
)
}
session.cryptoService().verificationService().addListener(this) session.cryptoService().verificationService().addListener(this)
} }
@ -165,10 +163,10 @@ class VerificationEmojiCodeViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory<VerificationEmojiCodeViewModel, VerificationEmojiCodeViewState> by hiltMavericksViewModelFactory() { companion object : MavericksViewModelFactory<VerificationEmojiCodeViewModel, VerificationEmojiCodeViewState> by hiltMavericksViewModelFactory() {
override fun initialState(viewModelContext: ViewModelContext): VerificationEmojiCodeViewState? { override fun initialState(viewModelContext: ViewModelContext): VerificationEmojiCodeViewState {
val args = viewModelContext.args<VerificationBottomSheet.VerificationArgs>() val args = viewModelContext.args<VerificationBottomSheet.VerificationArgs>()
val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession() val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
val matrixItem = session.getUser(args.otherUserId)?.toMatrixItem() val matrixItem = session.getUserOrDefault(args.otherUserId).toMatrixItem()
return VerificationEmojiCodeViewState( return VerificationEmojiCodeViewState(
transactionId = args.verificationId, transactionId = args.verificationId,

View file

@ -54,7 +54,7 @@ class VerificationQrScannedByOtherController @Inject constructor(
if (state.isMe) { if (state.isMe) {
notice(host.stringProvider.getString(R.string.qr_code_scanned_self_verif_notice).toEpoxyCharSequence()) notice(host.stringProvider.getString(R.string.qr_code_scanned_self_verif_notice).toEpoxyCharSequence())
} else { } else {
val name = state.otherUserMxItem?.getBestName() ?: "" val name = state.otherUserMxItem.getBestName()
notice(host.stringProvider.getString(R.string.qr_code_scanned_by_other_notice, name).toEpoxyCharSequence()) notice(host.stringProvider.getString(R.string.qr_code_scanned_by_other_notice, name).toEpoxyCharSequence())
} }
} }

View file

@ -52,7 +52,6 @@ class VerificationRequestController @Inject constructor(
override fun buildModels() { override fun buildModels() {
val state = viewState ?: return val state = viewState ?: return
val matrixItem = viewState?.otherUserMxItem ?: return
val host = this val host = this
if (state.selfVerificationMode) { if (state.selfVerificationMode) {
@ -107,11 +106,9 @@ class VerificationRequestController @Inject constructor(
if (state.isMe) { if (state.isMe) {
stringProvider.getString(R.string.verify_new_session_notice) stringProvider.getString(R.string.verify_new_session_notice)
} else { } else {
matrixItem.let { stringProvider.getString(R.string.verification_request_notice, state.otherUserId)
stringProvider.getString(R.string.verification_request_notice, it.id) .toSpannable()
.toSpannable() .colorizeMatchingText(state.otherUserId, colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color))
.colorizeMatchingText(it.id, colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color))
}
} }
bottomSheetVerificationNoticeItem { bottomSheetVerificationNoticeItem {
@ -138,7 +135,7 @@ class VerificationRequestController @Inject constructor(
is Loading -> { is Loading -> {
bottomSheetVerificationWaitingItem { bottomSheetVerificationWaitingItem {
id("waiting") id("waiting")
title(host.stringProvider.getString(R.string.verification_request_waiting_for, matrixItem.getBestName())) title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUserMxItem.getBestName()))
} }
} }
is Success -> { is Success -> {
@ -151,7 +148,7 @@ class VerificationRequestController @Inject constructor(
} else { } else {
bottomSheetVerificationWaitingItem { bottomSheetVerificationWaitingItem {
id("waiting") id("waiting")
title(host.stringProvider.getString(R.string.verification_request_waiting_for, matrixItem.getBestName())) title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUserMxItem.getBestName()))
} }
} }
} }

View file

@ -64,9 +64,7 @@ class VerificationRequestFragment :
} }
override fun onClickOnVerificationStart(): Unit = withState(viewModel) { state -> override fun onClickOnVerificationStart(): Unit = withState(viewModel) { state ->
state.otherUserMxItem?.id?.let { otherUserId -> viewModel.handle(VerificationAction.RequestVerificationByDM(state.otherUserId, state.roomId))
viewModel.handle(VerificationAction.RequestVerificationByDM(otherUserId, state.roomId))
}
} }
override fun onClickRecoverFromPassphrase() { override fun onClickRecoverFromPassphrase() {

View file

@ -514,7 +514,7 @@ class HomeActivity :
) )
} }
private fun promptSecurityEvent(userItem: MatrixItem.UserItem?, titleRes: Int, descRes: Int, action: ((VectorBaseActivity<*>) -> Unit)) { private fun promptSecurityEvent(userItem: MatrixItem.UserItem, titleRes: Int, descRes: Int, action: ((VectorBaseActivity<*>) -> Unit)) {
popupAlertManager.postVectorAlert( popupAlertManager.postVectorAlert(
VerificationVectorAlert( VerificationVectorAlert(
uid = "upgradeSecurity", uid = "upgradeSecurity",

View file

@ -20,13 +20,13 @@ import im.vector.app.core.platform.VectorViewEvents
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
sealed interface HomeActivityViewEvents : VectorViewEvents { sealed interface HomeActivityViewEvents : VectorViewEvents {
data class AskPasswordToInitCrossSigning(val userItem: MatrixItem.UserItem?) : HomeActivityViewEvents data class AskPasswordToInitCrossSigning(val userItem: MatrixItem.UserItem) : HomeActivityViewEvents
data class CurrentSessionNotVerified( data class CurrentSessionNotVerified(
val userItem: MatrixItem.UserItem?, val userItem: MatrixItem.UserItem,
val waitForIncomingRequest: Boolean = true, val waitForIncomingRequest: Boolean = true,
) : HomeActivityViewEvents ) : HomeActivityViewEvents
data class CurrentSessionCannotBeVerified( data class CurrentSessionCannotBeVerified(
val userItem: MatrixItem.UserItem?, val userItem: MatrixItem.UserItem,
) : HomeActivityViewEvents ) : HomeActivityViewEvents
data class OnCrossSignedInvalidated(val userItem: MatrixItem.UserItem) : HomeActivityViewEvents data class OnCrossSignedInvalidated(val userItem: MatrixItem.UserItem) : HomeActivityViewEvents
object PromptToEnableSessionPush : HomeActivityViewEvents object PromptToEnableSessionPush : HomeActivityViewEvents

View file

@ -60,7 +60,7 @@ import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.session.getUserOrDefault
import org.matrix.android.sdk.api.session.pushrules.RuleIds import org.matrix.android.sdk.api.session.pushrules.RuleIds
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
@ -312,10 +312,10 @@ class HomeActivityViewModel @AssistedInject constructor(
} else { } else {
// cross signing keys have been reset // cross signing keys have been reset
// Trigger a popup to re-verify // Trigger a popup to re-verify
// Note: user can be null in case of logout // Note: user can be unknown in case of logout
session.getUser(session.myUserId) session.getUserOrDefault(session.myUserId)
?.toMatrixItem() .toMatrixItem()
?.let { user -> .let { user ->
_viewEvents.post(HomeActivityViewEvents.OnCrossSignedInvalidated(user)) _viewEvents.post(HomeActivityViewEvents.OnCrossSignedInvalidated(user))
} }
} }
@ -396,7 +396,7 @@ class HomeActivityViewModel @AssistedInject constructor(
// New session // New session
_viewEvents.post( _viewEvents.post(
HomeActivityViewEvents.CurrentSessionNotVerified( HomeActivityViewEvents.CurrentSessionNotVerified(
session.getUser(session.myUserId)?.toMatrixItem(), session.getUserOrDefault(session.myUserId).toMatrixItem(),
// Always send request instead of waiting for an incoming as per recent EW changes // Always send request instead of waiting for an incoming as per recent EW changes
false false
) )
@ -404,7 +404,7 @@ class HomeActivityViewModel @AssistedInject constructor(
} else { } else {
_viewEvents.post( _viewEvents.post(
HomeActivityViewEvents.CurrentSessionCannotBeVerified( HomeActivityViewEvents.CurrentSessionCannotBeVerified(
session.getUser(session.myUserId)?.toMatrixItem(), session.getUserOrDefault(session.myUserId).toMatrixItem(),
) )
) )
} }
@ -424,7 +424,7 @@ class HomeActivityViewModel @AssistedInject constructor(
// Check this is not an SSO account // Check this is not an SSO account
if (session.homeServerCapabilitiesService().getHomeServerCapabilities().canChangePassword) { if (session.homeServerCapabilitiesService().getHomeServerCapabilities().canChangePassword) {
// Ask password to the user: Upgrade security // Ask password to the user: Upgrade security
_viewEvents.post(HomeActivityViewEvents.AskPasswordToInitCrossSigning(session.getUser(session.myUserId)?.toMatrixItem())) _viewEvents.post(HomeActivityViewEvents.AskPasswordToInitCrossSigning(session.getUserOrDefault(session.myUserId).toMatrixItem()))
} }
// Else (SSO) just ignore for the moment // Else (SSO) just ignore for the moment
} else { } else {

View file

@ -21,10 +21,13 @@ import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Success import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
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 dagger.hilt.EntryPoints
import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.SingletonEntryPoint
import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
@ -40,14 +43,14 @@ import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.session.getUserOrDefault
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import timber.log.Timber import timber.log.Timber
data class UnknownDevicesState( data class UnknownDevicesState(
val myMatrixItem: MatrixItem.UserItem? = null, val myMatrixItem: MatrixItem.UserItem,
val unknownSessions: Async<List<DeviceDetectionInfo>> = Uninitialized val unknownSessions: Async<List<DeviceDetectionInfo>> = Uninitialized
) : MavericksState ) : MavericksState
@ -73,7 +76,15 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(
override fun create(initialState: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel override fun create(initialState: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel
} }
companion object : MavericksViewModelFactory<UnknownDeviceDetectorSharedViewModel, UnknownDevicesState> by hiltMavericksViewModelFactory() companion object : MavericksViewModelFactory<UnknownDeviceDetectorSharedViewModel, UnknownDevicesState> by hiltMavericksViewModelFactory() {
override fun initialState(viewModelContext: ViewModelContext): UnknownDevicesState {
val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
return UnknownDevicesState(
myMatrixItem = session.getUserOrDefault(session.myUserId).toMatrixItem()
)
}
}
private val ignoredDeviceList = ArrayList<String>() private val ignoredDeviceList = ArrayList<String>()
@ -118,7 +129,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(
.execute { async -> .execute { async ->
// Timber.v("## Detector trigger passed distinct") // Timber.v("## Detector trigger passed distinct")
copy( copy(
myMatrixItem = session.getUser(session.myUserId)?.toMatrixItem(), myMatrixItem = session.getUserOrDefault(session.myUserId).toMatrixItem(),
unknownSessions = async unknownSessions = async
) )
} }

View file

@ -32,6 +32,7 @@ import im.vector.app.core.platform.StateView
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.DrawableProvider import im.vector.app.core.resources.DrawableProvider
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.displayname.getBestName
import im.vector.app.features.home.room.list.home.header.HomeRoomFilter import im.vector.app.features.home.room.list.home.header.HomeRoomFilter
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -53,6 +54,7 @@ import org.matrix.android.sdk.api.query.RoomTagQueryFilter
import org.matrix.android.sdk.api.query.toActiveSpaceOrNoFilter import org.matrix.android.sdk.api.query.toActiveSpaceOrNoFilter
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.getUserOrDefault
import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
@ -62,6 +64,7 @@ import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.state.isPublic import org.matrix.android.sdk.api.session.room.state.isPublic
import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
class HomeRoomListViewModel @AssistedInject constructor( class HomeRoomListViewModel @AssistedInject constructor(
@ -298,7 +301,7 @@ class HomeRoomListViewModel @AssistedInject constructor(
isBigImage = true isBigImage = true
) )
} else { } else {
val userName = session.userService().getUser(session.myUserId)?.displayName ?: "" val userName = session.getUserOrDefault(session.myUserId).toMatrixItem().getBestName()
StateView.State.Empty( StateView.State.Empty(
title = stringProvider.getString(R.string.home_empty_no_rooms_title, userName), title = stringProvider.getString(R.string.home_empty_no_rooms_title, userName),
message = stringProvider.getString(R.string.home_empty_no_rooms_message), message = stringProvider.getString(R.string.home_empty_no_rooms_message),

View file

@ -38,13 +38,13 @@ class VerificationVectorAlert(
override val layoutRes = R.layout.alerter_verification_layout override val layoutRes = R.layout.alerter_verification_layout
class ViewBinder( class ViewBinder(
private val matrixItem: MatrixItem?, private val matrixItem: MatrixItem,
private val avatarRenderer: AvatarRenderer private val avatarRenderer: AvatarRenderer
) : VectorAlert.ViewBinder { ) : VectorAlert.ViewBinder {
override fun bind(view: View) { override fun bind(view: View) {
val views = AlerterVerificationLayoutBinding.bind(view) val views = AlerterVerificationLayoutBinding.bind(view)
matrixItem?.let { avatarRenderer.render(it, views.ivUserAvatar, GlideApp.with(view.context.applicationContext)) } avatarRenderer.render(matrixItem, views.ivUserAvatar, GlideApp.with(view.context.applicationContext))
} }
} }
} }

View file

@ -47,6 +47,7 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.getUserOrDefault
import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
@ -272,7 +273,7 @@ class SpaceListViewModel @AssistedInject constructor(
?.safeOrder() ?.safeOrder()
} }
val inviterIds = spaces.mapNotNull { it.inviterId } val inviterIds = spaces.mapNotNull { it.inviterId }
val inviters = inviterIds.mapNotNull { session.userService().getUser(it) } val inviters = inviterIds.map { session.getUserOrDefault(it) }
copy( copy(
asyncSpaces = asyncSpaces, asyncSpaces = asyncSpaces,
spaces = spaces, spaces = spaces,