forked from GitHub-Mirror/riotX-android
Merge pull request #188 from vector-im/feature/disambiguation
Disambiguation of display names
This commit is contained in:
commit
1eb374fa49
@ -59,7 +59,7 @@ object RoomDataHelper {
|
|||||||
eventId = Random.nextLong().toString(),
|
eventId = Random.nextLong().toString(),
|
||||||
content = content,
|
content = content,
|
||||||
prevContent = prevContent,
|
prevContent = prevContent,
|
||||||
sender = sender,
|
senderId = sender,
|
||||||
stateKey = stateKey
|
stateKey = stateKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -71,12 +71,11 @@ data class Event(
|
|||||||
@Json(name = "content") val content: Content? = null,
|
@Json(name = "content") val content: Content? = null,
|
||||||
@Json(name = "prev_content") val prevContent: Content? = null,
|
@Json(name = "prev_content") val prevContent: Content? = null,
|
||||||
@Json(name = "origin_server_ts") val originServerTs: Long? = null,
|
@Json(name = "origin_server_ts") val originServerTs: Long? = null,
|
||||||
@Json(name = "sender") val sender: String? = null,
|
@Json(name = "sender") val senderId: String? = null,
|
||||||
@Json(name = "state_key") val stateKey: String? = null,
|
@Json(name = "state_key") val stateKey: String? = null,
|
||||||
@Json(name = "room_id") val roomId: String? = null,
|
@Json(name = "room_id") val roomId: String? = null,
|
||||||
@Json(name = "unsigned") val unsignedData: UnsignedData? = null,
|
@Json(name = "unsigned") val unsignedData: UnsignedData? = null,
|
||||||
@Json(name = "redacts") val redacts: String? = null
|
@Json(name = "redacts") val redacts: String? = null
|
||||||
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,6 +31,7 @@ data class TimelineEvent(
|
|||||||
val localId: String,
|
val localId: String,
|
||||||
val displayIndex: Int,
|
val displayIndex: Int,
|
||||||
val senderName: String?,
|
val senderName: String?,
|
||||||
|
val isUniqueDisplayName: Boolean,
|
||||||
val senderAvatar: String?,
|
val senderAvatar: String?,
|
||||||
val sendState: SendState,
|
val sendState: SendState,
|
||||||
val annotations: EventAnnotationsSummary? = null
|
val annotations: EventAnnotationsSummary? = null
|
||||||
@ -53,6 +54,18 @@ data class TimelineEvent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDisambiguatedDisplayName(): String {
|
||||||
|
return if (isUniqueDisplayName) {
|
||||||
|
senderName
|
||||||
|
} else {
|
||||||
|
senderName?.let { name ->
|
||||||
|
"$name (${root.senderId})"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?: root.senderId
|
||||||
|
?: ""
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the metadata associated with a key.
|
* Get the metadata associated with a key.
|
||||||
* @param key the key to get the metadata
|
* @param key the key to get the metadata
|
||||||
|
@ -65,7 +65,7 @@ open class IncomingRoomKeyRequest {
|
|||||||
* @param event the event
|
* @param event the event
|
||||||
*/
|
*/
|
||||||
constructor(event: Event) {
|
constructor(event: Event) {
|
||||||
userId = event.sender
|
userId = event.senderId
|
||||||
val roomKeyShareRequest = event.getClearContent().toModel<RoomKeyShareRequest>()!!
|
val roomKeyShareRequest = event.getClearContent().toModel<RoomKeyShareRequest>()!!
|
||||||
deviceId = roomKeyShareRequest.requestingDeviceId
|
deviceId = roomKeyShareRequest.requestingDeviceId
|
||||||
requestId = roomKeyShareRequest.requestId
|
requestId = roomKeyShareRequest.requestId
|
||||||
|
@ -131,7 +131,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
|||||||
* @param event the event
|
* @param event the event
|
||||||
*/
|
*/
|
||||||
private fun requestKeysForEvent(event: Event) {
|
private fun requestKeysForEvent(event: Event) {
|
||||||
val sender = event.sender!!
|
val sender = event.senderId!!
|
||||||
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()!!
|
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()!!
|
||||||
|
|
||||||
val recipients = ArrayList<Map<String, String>>()
|
val recipients = ArrayList<Map<String, String>>()
|
||||||
|
@ -121,9 +121,9 @@ internal class MXOlmDecryption(
|
|||||||
MXCryptoError.UNABLE_TO_DECRYPT, String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "sender")))
|
MXCryptoError.UNABLE_TO_DECRYPT, String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "sender")))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TextUtils.equals(olmPayloadContent.sender, event.sender)) {
|
if (!TextUtils.equals(olmPayloadContent.sender, event.senderId)) {
|
||||||
Timber.e("Event " + event.eventId + ": original sender " + olmPayloadContent.sender
|
Timber.e("Event " + event.eventId + ": original sender " + olmPayloadContent.sender
|
||||||
+ " does not match reported sender " + event.sender)
|
+ " does not match reported sender " + event.senderId)
|
||||||
throw MXDecryptionException(MXCryptoError(MXCryptoError.FORWARDED_MESSAGE_ERROR_CODE,
|
throw MXDecryptionException(MXCryptoError(MXCryptoError.FORWARDED_MESSAGE_ERROR_CODE,
|
||||||
MXCryptoError.UNABLE_TO_DECRYPT, String.format(MXCryptoError.FORWARDED_MESSAGE_REASON, olmPayloadContent.sender)))
|
MXCryptoError.UNABLE_TO_DECRYPT, String.format(MXCryptoError.FORWARDED_MESSAGE_REASON, olmPayloadContent.sender)))
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ internal class DefaultSasVerificationService(private val credentials: Credential
|
|||||||
private suspend fun onStartRequestReceived(event: Event) {
|
private suspend fun onStartRequestReceived(event: Event) {
|
||||||
val startReq = event.getClearContent().toModel<KeyVerificationStart>()!!
|
val startReq = event.getClearContent().toModel<KeyVerificationStart>()!!
|
||||||
|
|
||||||
val otherUserId = event.sender
|
val otherUserId = event.senderId
|
||||||
if (!startReq.isValid()) {
|
if (!startReq.isValid()) {
|
||||||
Timber.e("## received invalid verification request")
|
Timber.e("## received invalid verification request")
|
||||||
if (startReq.transactionID != null) {
|
if (startReq.transactionID != null) {
|
||||||
@ -236,7 +236,7 @@ internal class DefaultSasVerificationService(private val credentials: Credential
|
|||||||
Timber.e("## Received invalid accept request")
|
Timber.e("## Received invalid accept request")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val otherUserId = event.sender!!
|
val otherUserId = event.senderId!!
|
||||||
|
|
||||||
Timber.v("## SAS onCancelReceived otherUser:$otherUserId reason:${cancelReq.reason}")
|
Timber.v("## SAS onCancelReceived otherUser:$otherUserId reason:${cancelReq.reason}")
|
||||||
val existing = getExistingTransaction(otherUserId, cancelReq.transactionID!!)
|
val existing = getExistingTransaction(otherUserId, cancelReq.transactionID!!)
|
||||||
@ -258,7 +258,7 @@ internal class DefaultSasVerificationService(private val credentials: Credential
|
|||||||
Timber.e("## Received invalid accept request")
|
Timber.e("## Received invalid accept request")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val otherUserId = event.sender!!
|
val otherUserId = event.senderId!!
|
||||||
val existing = getExistingTransaction(otherUserId, acceptReq.transactionID!!)
|
val existing = getExistingTransaction(otherUserId, acceptReq.transactionID!!)
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
Timber.e("## Received invalid accept request")
|
Timber.e("## Received invalid accept request")
|
||||||
@ -282,7 +282,7 @@ internal class DefaultSasVerificationService(private val credentials: Credential
|
|||||||
Timber.e("## Received invalid key request")
|
Timber.e("## Received invalid key request")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val otherUserId = event.sender!!
|
val otherUserId = event.senderId!!
|
||||||
val existing = getExistingTransaction(otherUserId, keyReq.transactionID!!)
|
val existing = getExistingTransaction(otherUserId, keyReq.transactionID!!)
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
Timber.e("## Received invalid accept request")
|
Timber.e("## Received invalid accept request")
|
||||||
@ -303,7 +303,7 @@ internal class DefaultSasVerificationService(private val credentials: Credential
|
|||||||
Timber.e("## Received invalid key request")
|
Timber.e("## Received invalid key request")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val otherUserId = event.sender!!
|
val otherUserId = event.senderId!!
|
||||||
val existing = getExistingTransaction(otherUserId, macReq.transactionID!!)
|
val existing = getExistingTransaction(otherUserId, macReq.transactionID!!)
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
Timber.e("## Received invalid accept request")
|
Timber.e("## Received invalid accept request")
|
||||||
|
@ -37,7 +37,7 @@ internal object EventMapper {
|
|||||||
eventEntity.prevContent = ContentMapper.map(resolvedPrevContent)
|
eventEntity.prevContent = ContentMapper.map(resolvedPrevContent)
|
||||||
eventEntity.stateKey = event.stateKey
|
eventEntity.stateKey = event.stateKey
|
||||||
eventEntity.type = event.getClearType()
|
eventEntity.type = event.getClearType()
|
||||||
eventEntity.sender = event.sender
|
eventEntity.sender = event.senderId
|
||||||
eventEntity.originServerTs = event.originServerTs
|
eventEntity.originServerTs = event.originServerTs
|
||||||
eventEntity.redacts = event.redacts
|
eventEntity.redacts = event.redacts
|
||||||
eventEntity.age = event.unsignedData?.age ?: event.originServerTs
|
eventEntity.age = event.unsignedData?.age ?: event.originServerTs
|
||||||
@ -63,7 +63,7 @@ internal object EventMapper {
|
|||||||
content = ContentMapper.map(eventEntity.content),
|
content = ContentMapper.map(eventEntity.content),
|
||||||
prevContent = ContentMapper.map(eventEntity.prevContent),
|
prevContent = ContentMapper.map(eventEntity.prevContent),
|
||||||
originServerTs = eventEntity.originServerTs,
|
originServerTs = eventEntity.originServerTs,
|
||||||
sender = eventEntity.sender,
|
senderId = eventEntity.sender,
|
||||||
stateKey = eventEntity.stateKey,
|
stateKey = eventEntity.stateKey,
|
||||||
roomId = eventEntity.roomId,
|
roomId = eventEntity.roomId,
|
||||||
unsignedData = ud,
|
unsignedData = ud,
|
||||||
|
@ -227,7 +227,7 @@ internal class DefaultEventRelationsAggregationTask(private val monarchy: Monarc
|
|||||||
sum.count = 1
|
sum.count = 1
|
||||||
sum.sourceEvents.add(reactionEventId)
|
sum.sourceEvents.add(reactionEventId)
|
||||||
}
|
}
|
||||||
sum.addedByMe = sum.addedByMe || (userId == event.sender)
|
sum.addedByMe = sum.addedByMe || (userId == event.senderId)
|
||||||
eventSummary.reactionsSummary.add(sum)
|
eventSummary.reactionsSummary.add(sum)
|
||||||
} else {
|
} else {
|
||||||
//is this a known event (is possible? pagination?)
|
//is this a known event (is possible? pagination?)
|
||||||
@ -249,7 +249,7 @@ internal class DefaultEventRelationsAggregationTask(private val monarchy: Monarc
|
|||||||
sum.sourceEvents.add(reactionEventId)
|
sum.sourceEvents.add(reactionEventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
sum.addedByMe = sum.addedByMe || (userId == event.sender)
|
sum.addedByMe = sum.addedByMe || (userId == event.senderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ internal class RoomMembers(private val realm: Realm,
|
|||||||
}
|
}
|
||||||
return EventEntity
|
return EventEntity
|
||||||
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
||||||
.contains(EventEntityFields.CONTENT, displayName)
|
.contains(EventEntityFields.CONTENT, "\"displayname\":\"$displayName\"")
|
||||||
.distinct(EventEntityFields.STATE_KEY)
|
.distinct(EventEntityFields.STATE_KEY)
|
||||||
.findAll()
|
.findAll()
|
||||||
.size == 1
|
.size == 1
|
||||||
|
@ -1,59 +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.matrix.android.internal.session.room.send
|
|
||||||
|
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
|
||||||
import im.vector.matrix.android.api.session.events.model.Content
|
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
|
||||||
|
|
||||||
internal class EventFactory(private val credentials: Credentials) {
|
|
||||||
|
|
||||||
private val moshi = MoshiProvider.providesMoshi()
|
|
||||||
|
|
||||||
fun createTextEvent(roomId: String, msgType: String, text: String): Event {
|
|
||||||
val content = MessageTextContent(type = msgType, body = text)
|
|
||||||
|
|
||||||
return Event(
|
|
||||||
roomId = roomId,
|
|
||||||
originServerTs = dummyOriginServerTs(),
|
|
||||||
sender = credentials.userId,
|
|
||||||
eventId = dummyEventId(roomId),
|
|
||||||
type = EventType.MESSAGE,
|
|
||||||
content = toContent(content)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dummyOriginServerTs(): Long {
|
|
||||||
return System.currentTimeMillis()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dummyEventId(roomId: String): String {
|
|
||||||
return roomId + "-" + dummyOriginServerTs()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
private inline fun <reified T> toContent(data: T?): Content? {
|
|
||||||
val moshiAdapter = moshi.adapter(T::class.java)
|
|
||||||
val jsonValue = moshiAdapter.toJsonValue(data)
|
|
||||||
return jsonValue as? Content?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -130,7 +130,7 @@ internal class LocalEchoEventFactory(private val credentials: Credentials, priva
|
|||||||
return Event(
|
return Event(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
||||||
sender = credentials.userId,
|
senderId = credentials.userId,
|
||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.REACTION,
|
type = EventType.REACTION,
|
||||||
content = content.toContent(),
|
content = content.toContent(),
|
||||||
@ -221,7 +221,7 @@ internal class LocalEchoEventFactory(private val credentials: Credentials, priva
|
|||||||
return Event(
|
return Event(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
||||||
sender = credentials.userId,
|
senderId = credentials.userId,
|
||||||
eventId = localID,
|
eventId = localID,
|
||||||
type = EventType.MESSAGE,
|
type = EventType.MESSAGE,
|
||||||
content = content.toContent(),
|
content = content.toContent(),
|
||||||
@ -241,7 +241,7 @@ internal class LocalEchoEventFactory(private val credentials: Credentials, priva
|
|||||||
//Fallbacks and event representation
|
//Fallbacks and event representation
|
||||||
//TODO Add error/warning logs when any of this is null
|
//TODO Add error/warning logs when any of this is null
|
||||||
val permalink = PermalinkFactory.createPermalink(eventReplied) ?: return null
|
val permalink = PermalinkFactory.createPermalink(eventReplied) ?: return null
|
||||||
val userId = eventReplied.sender ?: return null
|
val userId = eventReplied.senderId ?: return null
|
||||||
val userLink = PermalinkFactory.createPermalink(userId) ?: return null
|
val userLink = PermalinkFactory.createPermalink(userId) ?: return null
|
||||||
// <mx-reply>
|
// <mx-reply>
|
||||||
// <blockquote>
|
// <blockquote>
|
||||||
@ -330,7 +330,7 @@ internal class LocalEchoEventFactory(private val credentials: Credentials, priva
|
|||||||
return Event(
|
return Event(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
||||||
sender = credentials.userId,
|
senderId = credentials.userId,
|
||||||
eventId = localID,
|
eventId = localID,
|
||||||
type = EventType.REDACTION,
|
type = EventType.REDACTION,
|
||||||
redacts = eventId,
|
redacts = eventId,
|
||||||
|
@ -26,6 +26,7 @@ import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
|
|||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||||
import im.vector.matrix.android.internal.session.room.EventRelationExtractor
|
import im.vector.matrix.android.internal.session.room.EventRelationExtractor
|
||||||
|
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||||
import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor
|
import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -49,7 +50,11 @@ internal class TimelineEventFactory(
|
|||||||
val cacheKey = sender + eventEntity.localId
|
val cacheKey = sender + eventEntity.localId
|
||||||
val senderData = senderCache.getOrPut(cacheKey) {
|
val senderData = senderCache.getOrPut(cacheKey) {
|
||||||
val senderRoomMember = roomMemberExtractor.extractFrom(eventEntity, realm)
|
val senderRoomMember = roomMemberExtractor.extractFrom(eventEntity, realm)
|
||||||
SenderData(senderRoomMember?.displayName, senderRoomMember?.avatarUrl)
|
val isUniqueDisplayName = RoomMembers(realm, eventEntity.roomId).isUniqueDisplayName(senderRoomMember?.displayName)
|
||||||
|
|
||||||
|
SenderData(senderRoomMember?.displayName,
|
||||||
|
isUniqueDisplayName,
|
||||||
|
senderRoomMember?.avatarUrl)
|
||||||
}
|
}
|
||||||
val event = eventEntity.asDomain()
|
val event = eventEntity.asDomain()
|
||||||
if (event.getClearType() == EventType.ENCRYPTED) {
|
if (event.getClearType() == EventType.ENCRYPTED) {
|
||||||
@ -62,6 +67,7 @@ internal class TimelineEventFactory(
|
|||||||
eventEntity.localId,
|
eventEntity.localId,
|
||||||
eventEntity.displayIndex,
|
eventEntity.displayIndex,
|
||||||
senderData.senderName,
|
senderData.senderName,
|
||||||
|
senderData.isUniqueDisplayName,
|
||||||
senderData.senderAvatar,
|
senderData.senderAvatar,
|
||||||
eventEntity.sendState,
|
eventEntity.sendState,
|
||||||
relations
|
relations
|
||||||
@ -96,7 +102,7 @@ internal class TimelineEventFactory(
|
|||||||
|
|
||||||
private data class SenderData(
|
private data class SenderData(
|
||||||
val senderName: String?,
|
val senderName: String?,
|
||||||
|
val isUniqueDisplayName: Boolean,
|
||||||
val senderAvatar: String?
|
val senderAvatar: String?
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
@ -257,7 +257,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return Event(eventId = data["event_id"],
|
return Event(eventId = data["event_id"],
|
||||||
sender = data["sender"],
|
senderId = data["sender"],
|
||||||
roomId = data["room_id"],
|
roomId = data["room_id"],
|
||||||
type = data.getValue("type"),
|
type = data.getValue("type"),
|
||||||
// TODO content = data.getValue("content"),
|
// TODO content = data.getValue("content"),
|
||||||
|
@ -222,8 +222,8 @@ class RoomDetailFragment :
|
|||||||
}
|
}
|
||||||
//switch to expanded bar
|
//switch to expanded bar
|
||||||
composerLayout.composerRelatedMessageTitle.apply {
|
composerLayout.composerRelatedMessageTitle.apply {
|
||||||
text = event.senderName
|
text = event.getDisambiguatedDisplayName()
|
||||||
setTextColor(ContextCompat.getColor(requireContext(), getColorFromUserId(event.root.sender)))
|
setTextColor(ContextCompat.getColor(requireContext(), getColorFromUserId(event.root.senderId)))
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO this is used at several places, find way to refactor?
|
//TODO this is used at several places, find way to refactor?
|
||||||
@ -255,7 +255,7 @@ class RoomDetailFragment :
|
|||||||
composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_reply))
|
composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_reply))
|
||||||
}
|
}
|
||||||
|
|
||||||
AvatarRenderer.render(event.senderAvatar, event.root.sender
|
AvatarRenderer.render(event.senderAvatar, event.root.senderId
|
||||||
?: "", event.senderName, composerLayout.composerRelatedMessageAvatar)
|
?: "", event.senderName, composerLayout.composerRelatedMessageAvatar)
|
||||||
|
|
||||||
composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length)
|
composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length)
|
||||||
|
@ -282,7 +282,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||||||
val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault())
|
val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault())
|
||||||
_nonBlockingPopAlert.postValue(LiveEvent(
|
_nonBlockingPopAlert.postValue(LiveEvent(
|
||||||
Pair(R.string.last_edited_info_message, listOf(
|
Pair(R.string.last_edited_info_message, listOf(
|
||||||
lastReplace.senderName ?: "?",
|
lastReplace.getDisambiguatedDisplayName(),
|
||||||
dateFormat.format(Date(lastReplace.root.originServerTs ?: 0)))
|
dateFormat.format(Date(lastReplace.root.originServerTs ?: 0)))
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
@ -429,7 +429,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||||||
private fun observeInvitationState() {
|
private fun observeInvitationState() {
|
||||||
asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary ->
|
asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary ->
|
||||||
if (summary.membership == Membership.INVITE) {
|
if (summary.membership == Membership.INVITE) {
|
||||||
summary.lastMessage?.sender?.let { senderId ->
|
summary.lastMessage?.senderId?.let { senderId ->
|
||||||
session.getUser(senderId)
|
session.getUser(senderId)
|
||||||
}?.also {
|
}?.also {
|
||||||
setState { copy(asyncInviter = Success(it)) }
|
setState { copy(asyncInviter = Success(it)) }
|
||||||
|
@ -238,7 +238,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
|
|||||||
val senderAvatar = mergedEvent.senderAvatar()
|
val senderAvatar = mergedEvent.senderAvatar()
|
||||||
val senderName = mergedEvent.senderName()
|
val senderName = mergedEvent.senderName()
|
||||||
MergedHeaderItem.Data(
|
MergedHeaderItem.Data(
|
||||||
userId = mergedEvent.root.sender ?: "",
|
userId = mergedEvent.root.senderId ?: "",
|
||||||
avatarUrl = senderAvatar,
|
avatarUrl = senderAvatar,
|
||||||
memberName = senderName ?: "",
|
memberName = senderName ?: "",
|
||||||
eventId = mergedEvent.localId
|
eventId = mergedEvent.localId
|
||||||
|
@ -90,7 +90,7 @@ class MessageActionsViewModel(initialState: MessageActionState) : VectorViewMode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
MessageActionState(
|
MessageActionState(
|
||||||
userId = event.root.sender ?: "",
|
userId = event.root.senderId ?: "",
|
||||||
senderName = parcel.informationData.memberName?.toString() ?: "",
|
senderName = parcel.informationData.memberName?.toString() ?: "",
|
||||||
messageBody = body,
|
messageBody = body,
|
||||||
ts = dateFormat.format(Date(originTs ?: 0)),
|
ts = dateFormat.format(Date(originTs ?: 0)),
|
||||||
|
@ -131,7 +131,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
|
|||||||
}
|
}
|
||||||
this.add(SimpleAction(ACTION_COPY_PERMALINK, R.string.permalink, R.drawable.ic_permalink, parcel.eventId))
|
this.add(SimpleAction(ACTION_COPY_PERMALINK, R.string.permalink, R.drawable.ic_permalink, parcel.eventId))
|
||||||
|
|
||||||
if (currentSession.sessionParams.credentials.userId != event.root.sender && event.root.getClearType() == EventType.MESSAGE) {
|
if (currentSession.sessionParams.credentials.userId != event.root.senderId && event.root.getClearType() == EventType.MESSAGE) {
|
||||||
//not sent by me
|
//not sent by me
|
||||||
this.add(SimpleAction(ACTION_FLAG, R.string.report_content, R.drawable.ic_flag, parcel.eventId))
|
this.add(SimpleAction(ACTION_FLAG, R.string.report_content, R.drawable.ic_flag, parcel.eventId))
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
|
|||||||
//Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment
|
//Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment
|
||||||
if (event.root.getClearType() != EventType.MESSAGE) return false
|
if (event.root.getClearType() != EventType.MESSAGE) return false
|
||||||
//TODO if user is admin or moderator
|
//TODO if user is admin or moderator
|
||||||
return event.root.sender == myUserId
|
return event.root.senderId == myUserId
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canViewReactions(event: TimelineEvent): Boolean {
|
private fun canViewReactions(event: TimelineEvent): Boolean {
|
||||||
@ -194,7 +194,7 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
|
|||||||
if (event.root.getClearType() != EventType.MESSAGE) return false
|
if (event.root.getClearType() != EventType.MESSAGE) return false
|
||||||
//TODO if user is admin or moderator
|
//TODO if user is admin or moderator
|
||||||
val messageContent = event.root.content.toModel<MessageContent>()
|
val messageContent = event.root.content.toModel<MessageContent>()
|
||||||
return event.root.sender == myUserId && (
|
return event.root.senderId == myUserId && (
|
||||||
messageContent?.type == MessageType.MSGTYPE_TEXT
|
messageContent?.type == MessageType.MSGTYPE_TEXT
|
||||||
|| messageContent?.type == MessageType.MSGTYPE_EMOTE
|
|| messageContent?.type == MessageType.MSGTYPE_EMOTE
|
||||||
)
|
)
|
||||||
|
@ -49,8 +49,8 @@ class ViewReactionViewModel(private val session: Session,
|
|||||||
|
|
||||||
sum.sourceEvents.mapNotNull { room.getTimeLineEvent(it) }.forEach {
|
sum.sourceEvents.mapNotNull { room.getTimeLineEvent(it) }.forEach {
|
||||||
val localDate = it.root.localDateTime()
|
val localDate = it.root.localDateTime()
|
||||||
results.add(ReactionInfo(it.root.eventId!!, sum.key, it.root.sender
|
results.add(ReactionInfo(it.root.eventId!!, sum.key, it.root.senderId
|
||||||
?: "", it.senderName, timelineDateFormatter.formatMessageHour(localDate)))
|
?: "", it.getDisambiguatedDisplayName(), timelineDateFormatter.formatMessageHour(localDate)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setState {
|
setState {
|
||||||
|
@ -37,7 +37,7 @@ class EncryptionItemFactory(private val stringProvider: StringProvider) {
|
|||||||
val text = buildNoticeText(event.root, event.senderName) ?: return null
|
val text = buildNoticeText(event.root, event.senderName) ?: return null
|
||||||
val informationData = MessageInformationData(
|
val informationData = MessageInformationData(
|
||||||
eventId = event.root.eventId ?: "?",
|
eventId = event.root.eventId ?: "?",
|
||||||
senderId = event.root.sender ?: "",
|
senderId = event.root.senderId ?: "",
|
||||||
sendState = event.sendState,
|
sendState = event.sendState,
|
||||||
avatarUrl = event.senderAvatar(),
|
avatarUrl = event.senderAvatar(),
|
||||||
memberName = event.senderName(),
|
memberName = event.senderName(),
|
||||||
|
@ -32,7 +32,7 @@ class NoticeItemFactory(private val eventFormatter: NoticeEventFormatter) {
|
|||||||
val formattedText = eventFormatter.format(event) ?: return null
|
val formattedText = eventFormatter.format(event) ?: return null
|
||||||
val informationData = MessageInformationData(
|
val informationData = MessageInformationData(
|
||||||
eventId = event.root.eventId ?: "?",
|
eventId = event.root.eventId ?: "?",
|
||||||
senderId = event.root.sender ?: "",
|
senderId = event.root.senderId ?: "",
|
||||||
sendState = event.sendState,
|
sendState = event.sendState,
|
||||||
avatarUrl = event.senderAvatar(),
|
avatarUrl = event.senderAvatar(),
|
||||||
memberName = event.senderName(),
|
memberName = event.senderName(),
|
||||||
|
@ -65,7 +65,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
|||||||
if (TimelineDisplayableEvents.DEBUG_HIDDEN_EVENT) {
|
if (TimelineDisplayableEvents.DEBUG_HIDDEN_EVENT) {
|
||||||
val informationData = MessageInformationData(eventId = event.root.eventId
|
val informationData = MessageInformationData(eventId = event.root.eventId
|
||||||
?: "?",
|
?: "?",
|
||||||
senderId = event.root.sender ?: "",
|
senderId = event.root.senderId ?: "",
|
||||||
sendState = event.sendState,
|
sendState = event.sendState,
|
||||||
time = "",
|
time = "",
|
||||||
avatarUrl = null,
|
avatarUrl = null,
|
||||||
|
@ -32,13 +32,13 @@ class NoticeEventFormatter(private val stringProvider: StringProvider) {
|
|||||||
|
|
||||||
fun format(timelineEvent: TimelineEvent): CharSequence? {
|
fun format(timelineEvent: TimelineEvent): CharSequence? {
|
||||||
return when (val type = timelineEvent.root.getClearType()) {
|
return when (val type = timelineEvent.root.getClearType()) {
|
||||||
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(timelineEvent.root, timelineEvent.senderName)
|
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
||||||
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(timelineEvent.root, timelineEvent.senderName)
|
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
||||||
EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.senderName())
|
EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.senderName())
|
||||||
EventType.STATE_HISTORY_VISIBILITY -> formatRoomHistoryVisibilityEvent(timelineEvent.root, timelineEvent.senderName)
|
EventType.STATE_HISTORY_VISIBILITY -> formatRoomHistoryVisibilityEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
||||||
EventType.CALL_INVITE,
|
EventType.CALL_INVITE,
|
||||||
EventType.CALL_HANGUP,
|
EventType.CALL_HANGUP,
|
||||||
EventType.CALL_ANSWER -> formatCallEvent(timelineEvent.root, timelineEvent.senderName)
|
EventType.CALL_ANSWER -> formatCallEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
||||||
else -> {
|
else -> {
|
||||||
Timber.v("Type $type not handled by this formatter")
|
Timber.v("Type $type not handled by this formatter")
|
||||||
null
|
null
|
||||||
@ -111,12 +111,12 @@ class NoticeEventFormatter(private val stringProvider: StringProvider) {
|
|||||||
if (!TextUtils.equals(eventContent?.displayName, prevEventContent?.displayName)) {
|
if (!TextUtils.equals(eventContent?.displayName, prevEventContent?.displayName)) {
|
||||||
val displayNameText = when {
|
val displayNameText = when {
|
||||||
prevEventContent?.displayName.isNullOrEmpty() ->
|
prevEventContent?.displayName.isNullOrEmpty() ->
|
||||||
stringProvider.getString(R.string.notice_display_name_set, event.sender, eventContent?.displayName)
|
stringProvider.getString(R.string.notice_display_name_set, event.senderId, eventContent?.displayName)
|
||||||
eventContent?.displayName.isNullOrEmpty() ->
|
eventContent?.displayName.isNullOrEmpty() ->
|
||||||
stringProvider.getString(R.string.notice_display_name_removed, event.sender, prevEventContent?.displayName)
|
stringProvider.getString(R.string.notice_display_name_removed, event.senderId, prevEventContent?.displayName)
|
||||||
else ->
|
else ->
|
||||||
stringProvider.getString(R.string.notice_display_name_changed_from,
|
stringProvider.getString(R.string.notice_display_name_changed_from,
|
||||||
event.sender, prevEventContent?.displayName, eventContent?.displayName)
|
event.senderId, prevEventContent?.displayName, eventContent?.displayName)
|
||||||
}
|
}
|
||||||
displayText.append(displayNameText)
|
displayText.append(displayNameText)
|
||||||
}
|
}
|
||||||
@ -134,8 +134,8 @@ class NoticeEventFormatter(private val stringProvider: StringProvider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildMembershipNotice(event: Event, senderName: String?, eventContent: RoomMember?, prevEventContent: RoomMember?): String? {
|
private fun buildMembershipNotice(event: Event, senderName: String?, eventContent: RoomMember?, prevEventContent: RoomMember?): String? {
|
||||||
val senderDisplayName = senderName ?: event.sender
|
val senderDisplayName = senderName ?: event.senderId
|
||||||
val targetDisplayName = eventContent?.displayName ?: event.sender
|
val targetDisplayName = eventContent?.displayName ?: event.senderId
|
||||||
return when {
|
return when {
|
||||||
Membership.INVITE == eventContent?.membership -> {
|
Membership.INVITE == eventContent?.membership -> {
|
||||||
// TODO get userId
|
// TODO get userId
|
||||||
@ -156,7 +156,7 @@ class NoticeEventFormatter(private val stringProvider: StringProvider) {
|
|||||||
stringProvider.getString(R.string.notice_room_join, senderDisplayName)
|
stringProvider.getString(R.string.notice_room_join, senderDisplayName)
|
||||||
Membership.LEAVE == eventContent?.membership ->
|
Membership.LEAVE == eventContent?.membership ->
|
||||||
// 2 cases here: this member may have left voluntarily or they may have been "left" by someone else ie. kicked
|
// 2 cases here: this member may have left voluntarily or they may have been "left" by someone else ie. kicked
|
||||||
return if (TextUtils.equals(event.sender, event.stateKey)) {
|
return if (TextUtils.equals(event.senderId, event.stateKey)) {
|
||||||
if (prevEventContent?.membership == Membership.INVITE) {
|
if (prevEventContent?.membership == Membership.INVITE) {
|
||||||
stringProvider.getString(R.string.notice_room_reject, senderDisplayName)
|
stringProvider.getString(R.string.notice_room_reject, senderDisplayName)
|
||||||
} else {
|
} else {
|
||||||
|
@ -85,12 +85,11 @@ fun TimelineEvent.senderAvatar(): String? {
|
|||||||
|
|
||||||
fun TimelineEvent.senderName(): String? {
|
fun TimelineEvent.senderName(): String? {
|
||||||
// We might have no senderName when user leave, so we try to get it from prevContent
|
// We might have no senderName when user leave, so we try to get it from prevContent
|
||||||
return senderName
|
return when {
|
||||||
?: if (root.type == EventType.STATE_ROOM_MEMBER) {
|
senderName != null -> getDisambiguatedDisplayName()
|
||||||
root.prevContent.toModel<RoomMember>()?.displayName
|
root.type == EventType.STATE_ROOM_MEMBER -> root.prevContent.toModel<RoomMember>()?.displayName
|
||||||
} else {
|
else -> null
|
||||||
null
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TimelineEvent.canBeMerged(): Boolean {
|
fun TimelineEvent.canBeMerged(): Boolean {
|
||||||
|
@ -83,7 +83,6 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
|||||||
override fun bind(holder: H) {
|
override fun bind(holder: H) {
|
||||||
super.bind(holder)
|
super.bind(holder)
|
||||||
if (informationData.showInformation) {
|
if (informationData.showInformation) {
|
||||||
|
|
||||||
holder.avatarImageView.layoutParams = holder.avatarImageView.layoutParams?.apply {
|
holder.avatarImageView.layoutParams = holder.avatarImageView.layoutParams?.apply {
|
||||||
val size = dpToPx(avatarStyle.avatarSizeDP, holder.view.context)
|
val size = dpToPx(avatarStyle.avatarSizeDP, holder.view.context)
|
||||||
height = size
|
height = size
|
||||||
|
@ -22,7 +22,6 @@ import im.vector.riotredesign.core.extensions.localDateTime
|
|||||||
import im.vector.riotredesign.core.resources.ColorProvider
|
import im.vector.riotredesign.core.resources.ColorProvider
|
||||||
import im.vector.riotredesign.features.home.getColorFromUserId
|
import im.vector.riotredesign.features.home.getColorFromUserId
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar
|
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.ReactionInfoData
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.ReactionInfoData
|
||||||
import me.gujun.android.span.span
|
import me.gujun.android.span.span
|
||||||
@ -38,23 +37,23 @@ class MessageInformationDataFactory(private val timelineDateFormatter: TimelineD
|
|||||||
val eventId = event.root.eventId!!
|
val eventId = event.root.eventId!!
|
||||||
|
|
||||||
val date = event.root.localDateTime()
|
val date = event.root.localDateTime()
|
||||||
|
|
||||||
val nextDate = nextEvent?.root?.localDateTime()
|
val nextDate = nextEvent?.root?.localDateTime()
|
||||||
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
||||||
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
||||||
?: false
|
?: false
|
||||||
|
|
||||||
val showInformation =
|
val showInformation =
|
||||||
addDaySeparator
|
addDaySeparator
|
||||||
|| event.senderAvatar != nextEvent?.senderAvatar
|
|| event.senderAvatar != nextEvent?.senderAvatar
|
||||||
|| event.senderName != nextEvent?.senderName
|
|| event.getDisambiguatedDisplayName() != nextEvent?.getDisambiguatedDisplayName()
|
||||||
|| (nextEvent?.root?.getClearType() != EventType.MESSAGE && nextEvent?.root?.getClearType() != EventType.ENCRYPTED)
|
|| (nextEvent?.root?.getClearType() != EventType.MESSAGE && nextEvent?.root?.getClearType() != EventType.ENCRYPTED)
|
||||||
|| isNextMessageReceivedMoreThanOneHourAgo
|
|| isNextMessageReceivedMoreThanOneHourAgo
|
||||||
|
|
||||||
val time = timelineDateFormatter.formatMessageHour(date)
|
val time = timelineDateFormatter.formatMessageHour(date)
|
||||||
val avatarUrl = event.senderAvatar()
|
val avatarUrl = event.senderAvatar
|
||||||
val memberName = event.senderName ?: event.root.sender ?: ""
|
val memberName = event.getDisambiguatedDisplayName()
|
||||||
val formattedMemberName = span(memberName) {
|
val formattedMemberName = span(memberName) {
|
||||||
textColor = colorProvider.getColor(getColorFromUserId(event.root.sender
|
textColor = colorProvider.getColor(getColorFromUserId(event.root.senderId
|
||||||
?: ""))
|
?: ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +61,7 @@ class MessageInformationDataFactory(private val timelineDateFormatter: TimelineD
|
|||||||
|
|
||||||
return MessageInformationData(
|
return MessageInformationData(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
senderId = event.root.sender ?: "",
|
senderId = event.root.senderId ?: "",
|
||||||
sendState = event.sendState,
|
sendState = event.sendState,
|
||||||
time = time,
|
time = time,
|
||||||
avatarUrl = avatarUrl,
|
avatarUrl = avatarUrl,
|
||||||
|
Loading…
Reference in New Issue
Block a user