Architecture: get rid of RoomSummariesHolder as it can lead to errors

This commit is contained in:
ganfra 2021-08-18 15:25:58 +02:00
parent 799cd99176
commit 50a042683b
14 changed files with 93 additions and 147 deletions

View File

@ -40,7 +40,6 @@ import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.CurrentSpaceSuggestedRoomListDataSource import im.vector.app.features.home.CurrentSpaceSuggestedRoomListDataSource
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
import im.vector.app.features.home.room.detail.timeline.helper.RoomSummariesHolder
import im.vector.app.features.html.EventHtmlRenderer import im.vector.app.features.html.EventHtmlRenderer
import im.vector.app.features.html.VectorHtmlCompressor import im.vector.app.features.html.VectorHtmlCompressor
import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.AutoAcceptInvites
@ -66,7 +65,6 @@ import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.HomeServerHistoryService import org.matrix.android.sdk.api.auth.HomeServerHistoryService
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.widgets.model.WidgetType
import javax.inject.Singleton import javax.inject.Singleton
@Component(modules = [VectorModule::class]) @Component(modules = [VectorModule::class])
@ -167,8 +165,6 @@ interface VectorComponent {
fun webRtcCallManager(): WebRtcCallManager fun webRtcCallManager(): WebRtcCallManager
fun roomSummaryHolder(): RoomSummariesHolder
fun jitsiActiveConferenceHolder(): JitsiActiveConferenceHolder fun jitsiActiveConferenceHolder(): JitsiActiveConferenceHolder
@Component.Factory @Component.Factory

View File

@ -52,7 +52,6 @@ import im.vector.app.features.home.room.detail.composer.VoiceMessageHelper
import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator
import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler
import im.vector.app.features.home.room.detail.timeline.factory.TimelineFactory import im.vector.app.features.home.room.detail.timeline.factory.TimelineFactory
import im.vector.app.features.home.room.detail.timeline.helper.RoomSummariesHolder
import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever
import im.vector.app.features.home.room.typing.TypingHelper import im.vector.app.features.home.room.typing.TypingHelper
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
@ -117,7 +116,6 @@ class RoomDetailViewModel @AssistedInject constructor(
private val session: Session, private val session: Session,
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider, private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider,
private val stickerPickerActionHandler: StickerPickerActionHandler, private val stickerPickerActionHandler: StickerPickerActionHandler,
private val roomSummariesHolder: RoomSummariesHolder,
private val typingHelper: TypingHelper, private val typingHelper: TypingHelper,
private val callManager: WebRtcCallManager, private val callManager: WebRtcCallManager,
private val chatEffectManager: ChatEffectManager, private val chatEffectManager: ChatEffectManager,
@ -1576,7 +1574,6 @@ class RoomDetailViewModel @AssistedInject constructor(
private fun observeSummaryState() { private fun observeSummaryState() {
asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary -> asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary ->
roomSummariesHolder.set(summary)
setState { setState {
val typingMessage = typingHelper.getTypingMessage(summary.typingUsers) val typingMessage = typingHelper.getTypingMessage(summary.typingUsers)
copy( copy(
@ -1624,7 +1621,6 @@ class RoomDetailViewModel @AssistedInject constructor(
} }
override fun onCleared() { override fun onCleared() {
roomSummariesHolder.remove(room.roomId)
timeline.dispose() timeline.dispose()
timeline.removeAllListeners() timeline.removeAllListeners()
if (vectorPreferences.sendTypingNotifs()) { if (vectorPreferences.sendTypingNotifs()) {

View File

@ -64,6 +64,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
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.model.ReadReceipt import org.matrix.android.sdk.api.session.room.model.ReadReceipt
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
import org.matrix.android.sdk.api.session.room.model.message.MessageImageInfoContent import org.matrix.android.sdk.api.session.room.model.message.MessageImageInfoContent
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
@ -91,13 +92,15 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
data class PartialState( data class PartialState(
val unreadState: UnreadState = UnreadState.Unknown, val unreadState: UnreadState = UnreadState.Unknown,
val highlightedEventId: String? = null, val highlightedEventId: String? = null,
val jitsiState: JitsiState = JitsiState() val jitsiState: JitsiState = JitsiState(),
val roomSummary: RoomSummary? = null
) { ) {
constructor(state: RoomDetailViewState) : this( constructor(state: RoomDetailViewState) : this(
unreadState = state.unreadState, unreadState = state.unreadState,
highlightedEventId = state.highlightedEventId, highlightedEventId = state.highlightedEventId,
jitsiState = state.jitsiState jitsiState = state.jitsiState,
roomSummary = state.asyncRoomSummary()
) )
} }
@ -407,6 +410,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
val wantsDateSeparator = wantsDateSeparator(event, nextEvent) val wantsDateSeparator = wantsDateSeparator(event, nextEvent)
val mergedHeaderModel = mergedHeaderItemFactory.create(event, val mergedHeaderModel = mergedHeaderItemFactory.create(event,
nextEvent = nextEvent, nextEvent = nextEvent,
partialState = partialState,
items = this@TimelineEventController.currentSnapshot, items = this@TimelineEventController.currentSnapshot,
addDaySeparator = wantsDateSeparator, addDaySeparator = wantsDateSeparator,
currentPosition = position, currentPosition = position,

View File

@ -36,6 +36,7 @@ import im.vector.app.features.html.VectorHtmlCompressor
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
import im.vector.app.features.reactions.data.EmojiDataSource import im.vector.app.features.reactions.data.EmojiDataSource
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
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.keysbackup.KeysBackupState import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
@ -207,7 +208,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
EventType.CALL_CANDIDATES, EventType.CALL_CANDIDATES,
EventType.CALL_HANGUP, EventType.CALL_HANGUP,
EventType.CALL_ANSWER -> { EventType.CALL_ANSWER -> {
noticeEventFormatter.format(timelineEvent) noticeEventFormatter.format(timelineEvent, room?.roomSummary()?.isDirect.orFalse())
} }
else -> null else -> null
} }

View File

@ -17,19 +17,18 @@ package im.vector.app.features.home.room.detail.timeline.factory
import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.resources.UserPreferencesProvider import im.vector.app.core.resources.UserPreferencesProvider
import im.vector.app.features.call.vectorCallService
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
import im.vector.app.features.home.room.detail.timeline.helper.CallSignalingEventsGroup import im.vector.app.features.home.room.detail.timeline.helper.CallSignalingEventsGroup
import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory
import im.vector.app.features.home.room.detail.timeline.helper.MessageItemAttributesFactory import im.vector.app.features.home.room.detail.timeline.helper.MessageItemAttributesFactory
import im.vector.app.features.home.room.detail.timeline.helper.RoomSummariesHolder
import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem
import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem_ import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem_
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject import javax.inject.Inject
@ -40,22 +39,21 @@ class CallItemFactory @Inject constructor(
private val messageInformationDataFactory: MessageInformationDataFactory, private val messageInformationDataFactory: MessageInformationDataFactory,
private val messageItemAttributesFactory: MessageItemAttributesFactory, private val messageItemAttributesFactory: MessageItemAttributesFactory,
private val avatarSizeProvider: AvatarSizeProvider, private val avatarSizeProvider: AvatarSizeProvider,
private val noticeItemFactory: NoticeItemFactory, private val noticeItemFactory: NoticeItemFactory) {
private val roomSummariesHolder: RoomSummariesHolder) {
fun create(params: TimelineItemFactoryParams): VectorEpoxyModel<*>? { fun create(params: TimelineItemFactoryParams): VectorEpoxyModel<*>? {
val event = params.event val event = params.event
if (event.root.eventId == null) return null if (event.root.eventId == null) return null
val showHiddenEvents = userPreferencesProvider.shouldShowHiddenEvents() val showHiddenEvents = userPreferencesProvider.shouldShowHiddenEvents()
val callEventGrouper = params.eventsGroup?.let { CallSignalingEventsGroup(it) } ?: return null val callEventGrouper = params.eventsGroup?.let { CallSignalingEventsGroup(it) } ?: return null
val roomId = event.roomId val roomSummary = params.partialState.roomSummary ?: return null
val informationData = messageInformationDataFactory.create(params) val informationData = messageInformationDataFactory.create(params)
val callKind = if (callEventGrouper.isVideo()) CallTileTimelineItem.CallKind.VIDEO else CallTileTimelineItem.CallKind.AUDIO val callKind = if (callEventGrouper.isVideo()) CallTileTimelineItem.CallKind.VIDEO else CallTileTimelineItem.CallKind.AUDIO
val callItem = when (event.root.getClearType()) { val callItem = when (event.root.getClearType()) {
EventType.CALL_ANSWER -> { EventType.CALL_ANSWER -> {
if (callEventGrouper.isInCall()) { if (callEventGrouper.isInCall()) {
createCallTileTimelineItem( createCallTileTimelineItem(
roomId = roomId, roomSummary = roomSummary,
callId = callEventGrouper.callId, callId = callEventGrouper.callId,
callStatus = CallTileTimelineItem.CallStatus.IN_CALL, callStatus = CallTileTimelineItem.CallStatus.IN_CALL,
callKind = callKind, callKind = callKind,
@ -72,7 +70,7 @@ class CallItemFactory @Inject constructor(
EventType.CALL_INVITE -> { EventType.CALL_INVITE -> {
if (callEventGrouper.isRinging()) { if (callEventGrouper.isRinging()) {
createCallTileTimelineItem( createCallTileTimelineItem(
roomId = roomId, roomSummary = roomSummary,
callId = callEventGrouper.callId, callId = callEventGrouper.callId,
callStatus = CallTileTimelineItem.CallStatus.INVITED, callStatus = CallTileTimelineItem.CallStatus.INVITED,
callKind = callKind, callKind = callKind,
@ -88,7 +86,7 @@ class CallItemFactory @Inject constructor(
} }
EventType.CALL_REJECT -> { EventType.CALL_REJECT -> {
createCallTileTimelineItem( createCallTileTimelineItem(
roomId = roomId, roomSummary = roomSummary,
callId = callEventGrouper.callId, callId = callEventGrouper.callId,
callStatus = CallTileTimelineItem.CallStatus.REJECTED, callStatus = CallTileTimelineItem.CallStatus.REJECTED,
callKind = callKind, callKind = callKind,
@ -101,7 +99,7 @@ class CallItemFactory @Inject constructor(
} }
EventType.CALL_HANGUP -> { EventType.CALL_HANGUP -> {
createCallTileTimelineItem( createCallTileTimelineItem(
roomId = roomId, roomSummary = roomSummary,
callId = callEventGrouper.callId, callId = callEventGrouper.callId,
callStatus = if (callEventGrouper.callWasMissed()) CallTileTimelineItem.CallStatus.MISSED else CallTileTimelineItem.CallStatus.ENDED, callStatus = if (callEventGrouper.callWasMissed()) CallTileTimelineItem.CallStatus.MISSED else CallTileTimelineItem.CallStatus.ENDED,
callKind = callKind, callKind = callKind,
@ -123,7 +121,7 @@ class CallItemFactory @Inject constructor(
} }
private fun createCallTileTimelineItem( private fun createCallTileTimelineItem(
roomId: String, roomSummary: RoomSummary,
callId: String, callId: String,
callKind: CallTileTimelineItem.CallKind, callKind: CallTileTimelineItem.CallKind,
callStatus: CallTileTimelineItem.CallStatus, callStatus: CallTileTimelineItem.CallStatus,
@ -133,8 +131,7 @@ class CallItemFactory @Inject constructor(
formattedDuration: String, formattedDuration: String,
callback: TimelineEventController.Callback? callback: TimelineEventController.Callback?
): CallTileTimelineItem? { ): CallTileTimelineItem? {
val correctedRoomId = session.vectorCallService.userMapper.nativeRoomForVirtualRoom(roomId) ?: roomId val userOfInterest = roomSummary.toMatrixItem()
val userOfInterest = roomSummariesHolder.get(correctedRoomId)?.toMatrixItem() ?: return null
val attributes = messageItemAttributesFactory.create(null, informationData, callback).let { val attributes = messageItemAttributesFactory.create(null, informationData, callback).let {
CallTileTimelineItem.Attributes( CallTileTimelineItem.Attributes(
callId = callId, callId = callId,

View File

@ -22,7 +22,6 @@ import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
import im.vector.app.features.home.room.detail.timeline.helper.MergedTimelineEventVisibilityStateChangedListener import im.vector.app.features.home.room.detail.timeline.helper.MergedTimelineEventVisibilityStateChangedListener
import im.vector.app.features.home.room.detail.timeline.helper.RoomSummariesHolder
import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityHelper import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityHelper
import im.vector.app.features.home.room.detail.timeline.helper.canBeMerged import im.vector.app.features.home.room.detail.timeline.helper.canBeMerged
import im.vector.app.features.home.room.detail.timeline.helper.isRoomConfiguration import im.vector.app.features.home.room.detail.timeline.helper.isRoomConfiguration
@ -47,8 +46,7 @@ import javax.inject.Inject
class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolder: ActiveSessionHolder, class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
private val avatarRenderer: AvatarRenderer, private val avatarRenderer: AvatarRenderer,
private val avatarSizeProvider: AvatarSizeProvider, private val avatarSizeProvider: AvatarSizeProvider,
private val roomSummariesHolder: RoomSummariesHolder, private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
private val collapsedEventIds = linkedSetOf<Long>() private val collapsedEventIds = linkedSetOf<Long>()
private val mergeItemCollapseStates = HashMap<Long, Boolean>() private val mergeItemCollapseStates = HashMap<Long, Boolean>()
@ -60,6 +58,7 @@ private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
fun create(event: TimelineEvent, fun create(event: TimelineEvent,
nextEvent: TimelineEvent?, nextEvent: TimelineEvent?,
items: List<TimelineEvent>, items: List<TimelineEvent>,
partialState: TimelineEventController.PartialState,
addDaySeparator: Boolean, addDaySeparator: Boolean,
currentPosition: Int, currentPosition: Int,
eventIdToHighlight: String?, eventIdToHighlight: String?,
@ -70,18 +69,17 @@ private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
&& event.isRoomConfiguration(nextEvent.root.getClearContent()?.toModel<RoomCreateContent>()?.creator)) { && event.isRoomConfiguration(nextEvent.root.getClearContent()?.toModel<RoomCreateContent>()?.creator)) {
// It's the first item before room.create // It's the first item before room.create
// Collapse all room configuration events // Collapse all room configuration events
buildRoomCreationMergedSummary(currentPosition, items, event, eventIdToHighlight, requestModelBuild, callback) buildRoomCreationMergedSummary(currentPosition, items, partialState, event, eventIdToHighlight, requestModelBuild, callback)
} else if (!event.canBeMerged() || (nextEvent?.root?.getClearType() == event.root.getClearType() && !addDaySeparator)) { } else if (!event.canBeMerged() || (nextEvent?.root?.getClearType() == event.root.getClearType() && !addDaySeparator)) {
null null
} else { } else {
buildMembershipEventsMergedSummary(currentPosition, items, event, eventIdToHighlight, requestModelBuild, callback) buildMembershipEventsMergedSummary(currentPosition, items,partialState, event, eventIdToHighlight, requestModelBuild, callback)
} }
} }
private fun isDirectRoom(roomId: String) = roomSummariesHolder.get(roomId)?.isDirect.orFalse()
private fun buildMembershipEventsMergedSummary(currentPosition: Int, private fun buildMembershipEventsMergedSummary(currentPosition: Int,
items: List<TimelineEvent>, items: List<TimelineEvent>,
partialState: TimelineEventController.PartialState,
event: TimelineEvent, event: TimelineEvent,
eventIdToHighlight: String?, eventIdToHighlight: String?,
requestModelBuild: () -> Unit, requestModelBuild: () -> Unit,
@ -102,7 +100,7 @@ private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
memberName = mergedEvent.senderInfo.disambiguatedDisplayName, memberName = mergedEvent.senderInfo.disambiguatedDisplayName,
localId = mergedEvent.localId, localId = mergedEvent.localId,
eventId = mergedEvent.root.eventId ?: "", eventId = mergedEvent.root.eventId ?: "",
isDirectRoom = isDirectRoom(event.roomId) isDirectRoom = partialState.isDirectRoom()
) )
mergedData.add(data) mergedData.add(data)
} }
@ -141,6 +139,7 @@ private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
private fun buildRoomCreationMergedSummary(currentPosition: Int, private fun buildRoomCreationMergedSummary(currentPosition: Int,
items: List<TimelineEvent>, items: List<TimelineEvent>,
partialState: TimelineEventController.PartialState,
event: TimelineEvent, event: TimelineEvent,
eventIdToHighlight: String?, eventIdToHighlight: String?,
requestModelBuild: () -> Unit, requestModelBuild: () -> Unit,
@ -173,7 +172,7 @@ private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
memberName = mergedEvent.senderInfo.disambiguatedDisplayName, memberName = mergedEvent.senderInfo.disambiguatedDisplayName,
localId = mergedEvent.localId, localId = mergedEvent.localId,
eventId = mergedEvent.root.eventId ?: "", eventId = mergedEvent.root.eventId ?: "",
isDirectRoom = isDirectRoom(event.roomId) isDirectRoom = partialState.isDirectRoom()
) )
mergedData.add(data) mergedData.add(data)
} }
@ -206,7 +205,7 @@ private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
isEncryptionAlgorithmSecure = encryptionAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM, isEncryptionAlgorithmSecure = encryptionAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM,
callback = callback, callback = callback,
currentUserId = currentUserId, currentUserId = currentUserId,
roomSummary = roomSummariesHolder.get(event.roomId), roomSummary = partialState.roomSummary,
canChangeAvatar = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_AVATAR) ?: false, canChangeAvatar = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_AVATAR) ?: false,
canChangeTopic = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_TOPIC) ?: false, canChangeTopic = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_TOPIC) ?: false,
canChangeName = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_NAME) ?: false canChangeName = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_NAME) ?: false
@ -223,6 +222,10 @@ private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
} else null } else null
} }
private fun TimelineEventController.PartialState.isDirectRoom(): Boolean {
return roomSummary?.isDirect.orFalse()
}
fun isCollapsed(localId: Long): Boolean { fun isCollapsed(localId: Long): Boolean {
return collapsedEventIds.contains(localId) return collapsedEventIds.contains(localId)
} }

View File

@ -22,6 +22,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvide
import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory
import im.vector.app.features.home.room.detail.timeline.item.NoticeItem import im.vector.app.features.home.room.detail.timeline.item.NoticeItem
import im.vector.app.features.home.room.detail.timeline.item.NoticeItem_ import im.vector.app.features.home.room.detail.timeline.item.NoticeItem_
import org.matrix.android.sdk.api.extensions.orFalse
import javax.inject.Inject import javax.inject.Inject
class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEventFormatter, class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEventFormatter,
@ -31,7 +32,7 @@ class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEv
fun create(params: TimelineItemFactoryParams): NoticeItem? { fun create(params: TimelineItemFactoryParams): NoticeItem? {
val event = params.event val event = params.event
val formattedText = eventFormatter.format(event) ?: return null val formattedText = eventFormatter.format(event, isDm = params.partialState.roomSummary?.isDirect.orFalse()) ?: return null
val informationData = informationDataFactory.create(params) val informationData = informationDataFactory.create(params)
val attributes = NoticeItem.Attributes( val attributes = NoticeItem.Attributes(
avatarRenderer = avatarRenderer, avatarRenderer = avatarRenderer,

View File

@ -23,7 +23,6 @@ import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
import im.vector.app.features.home.room.detail.timeline.helper.JitsiWidgetEventsGroup import im.vector.app.features.home.room.detail.timeline.helper.JitsiWidgetEventsGroup
import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory
import im.vector.app.features.home.room.detail.timeline.helper.RoomSummariesHolder
import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem
import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem_ import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem_
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
@ -38,9 +37,7 @@ class WidgetItemFactory @Inject constructor(
private val avatarSizeProvider: AvatarSizeProvider, private val avatarSizeProvider: AvatarSizeProvider,
private val messageColorProvider: MessageColorProvider, private val messageColorProvider: MessageColorProvider,
private val avatarRenderer: AvatarRenderer, private val avatarRenderer: AvatarRenderer,
private val userPreferencesProvider: UserPreferencesProvider, private val userPreferencesProvider: UserPreferencesProvider) {
private val roomSummariesHolder: RoomSummariesHolder
) {
fun create(params: TimelineItemFactoryParams): VectorEpoxyModel<*>? { fun create(params: TimelineItemFactoryParams): VectorEpoxyModel<*>? {
val event = params.event val event = params.event
@ -56,9 +53,7 @@ class WidgetItemFactory @Inject constructor(
private fun createJitsiItem(params: TimelineItemFactoryParams, widgetContent: WidgetContent): VectorEpoxyModel<*>? { private fun createJitsiItem(params: TimelineItemFactoryParams, widgetContent: WidgetContent): VectorEpoxyModel<*>? {
val informationData = informationDataFactory.create(params) val informationData = informationDataFactory.create(params)
val event = params.event val userOfInterest = params.partialState.roomSummary?.toMatrixItem() ?: return null
val roomId = event.roomId
val userOfInterest = roomSummariesHolder.get(roomId)?.toMatrixItem() ?: return null
val isActiveTile = widgetContent.isActive() val isActiveTile = widgetContent.isActive()
val jitsiWidgetEventsGroup = params.eventsGroup?.let { JitsiWidgetEventsGroup(it) } ?: return null val jitsiWidgetEventsGroup = params.eventsGroup?.let { JitsiWidgetEventsGroup(it) } ?: return null
val isCallStillActive = jitsiWidgetEventsGroup.isStillActive() val isCallStillActive = jitsiWidgetEventsGroup.isStillActive()

View File

@ -23,6 +23,7 @@ import im.vector.app.core.resources.StringProvider
import me.gujun.android.span.span import me.gujun.android.span.span
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
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.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
import org.matrix.android.sdk.api.session.room.model.message.MessageOptionsContent import org.matrix.android.sdk.api.session.room.model.message.MessageOptionsContent
import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.model.message.MessageType
@ -41,7 +42,7 @@ class DisplayableEventFormatter @Inject constructor(
private val noticeEventFormatter: NoticeEventFormatter private val noticeEventFormatter: NoticeEventFormatter
) { ) {
fun format(timelineEvent: TimelineEvent, appendAuthor: Boolean): CharSequence { fun format(timelineEvent: TimelineEvent, isDm: Boolean, appendAuthor: Boolean): CharSequence {
if (timelineEvent.root.isRedacted()) { if (timelineEvent.root.isRedacted()) {
return noticeEventFormatter.formatRedactedEvent(timelineEvent.root) return noticeEventFormatter.formatRedactedEvent(timelineEvent.root)
} }
@ -135,7 +136,7 @@ class DisplayableEventFormatter @Inject constructor(
} }
else -> { else -> {
return span { return span {
text = noticeEventFormatter.format(timelineEvent) ?: "" text = noticeEventFormatter.format(timelineEvent, isDm) ?: ""
textStyle = "italic" textStyle = "italic"
} }
} }

View File

@ -19,7 +19,6 @@ package im.vector.app.features.home.room.detail.timeline.format
import im.vector.app.ActiveSessionDataSource import im.vector.app.ActiveSessionDataSource
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.room.detail.timeline.helper.RoomSummariesHolder
import im.vector.app.features.roomprofile.permissions.RoleFormatter import im.vector.app.features.roomprofile.permissions.RoleFormatter
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import org.matrix.android.sdk.api.extensions.appendNl import org.matrix.android.sdk.api.extensions.appendNl
@ -40,7 +39,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.RoomNameContent import org.matrix.android.sdk.api.session.room.model.RoomNameContent
import org.matrix.android.sdk.api.session.room.model.RoomServerAclContent import org.matrix.android.sdk.api.session.room.model.RoomServerAclContent
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
import org.matrix.android.sdk.api.session.room.model.RoomTopicContent import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
@ -58,7 +56,6 @@ class NoticeEventFormatter @Inject constructor(
private val roomHistoryVisibilityFormatter: RoomHistoryVisibilityFormatter, private val roomHistoryVisibilityFormatter: RoomHistoryVisibilityFormatter,
private val roleFormatter: RoleFormatter, private val roleFormatter: RoleFormatter,
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,
private val roomSummariesHolder: RoomSummariesHolder,
private val sp: StringProvider private val sp: StringProvider
) { ) {
@ -67,28 +64,25 @@ class NoticeEventFormatter @Inject constructor(
private fun Event.isSentByCurrentUser() = senderId != null && senderId == currentUserId private fun Event.isSentByCurrentUser() = senderId != null && senderId == currentUserId
private fun RoomSummary?.isDm() = this?.isDirect.orFalse() fun format(timelineEvent: TimelineEvent, isDm: Boolean): CharSequence? {
fun format(timelineEvent: TimelineEvent): CharSequence? {
val rs = roomSummariesHolder.get(timelineEvent.roomId)
return when (val type = timelineEvent.root.getClearType()) { return when (val type = timelineEvent.root.getClearType()) {
EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs) EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, isDm)
EventType.STATE_ROOM_CREATE -> formatRoomCreateEvent(timelineEvent.root, rs) EventType.STATE_ROOM_CREATE -> formatRoomCreateEvent(timelineEvent.root, isDm)
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_NAME -> formatRoomNameEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_AVATAR -> formatRoomAvatarEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_AVATAR -> formatRoomAvatarEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs) EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, isDm)
EventType.STATE_ROOM_THIRD_PARTY_INVITE -> formatRoomThirdPartyInvite(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs) EventType.STATE_ROOM_THIRD_PARTY_INVITE -> formatRoomThirdPartyInvite(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, isDm)
EventType.STATE_ROOM_ALIASES -> formatRoomAliasesEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_ALIASES -> formatRoomAliasesEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_CANONICAL_ALIAS -> formatRoomCanonicalAliasEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_CANONICAL_ALIAS -> formatRoomCanonicalAliasEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_HISTORY_VISIBILITY -> EventType.STATE_ROOM_HISTORY_VISIBILITY ->
formatRoomHistoryVisibilityEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs) formatRoomHistoryVisibilityEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, isDm)
EventType.STATE_ROOM_SERVER_ACL -> formatRoomServerAclEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_SERVER_ACL -> formatRoomServerAclEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_GUEST_ACCESS -> formatRoomGuestAccessEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs) EventType.STATE_ROOM_GUEST_ACCESS -> formatRoomGuestAccessEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, isDm)
EventType.STATE_ROOM_ENCRYPTION -> formatRoomEncryptionEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_ENCRYPTION -> formatRoomEncryptionEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_WIDGET, EventType.STATE_ROOM_WIDGET,
EventType.STATE_ROOM_WIDGET_LEGACY -> formatWidgetEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_WIDGET_LEGACY -> formatWidgetEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs) EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, isDm)
EventType.STATE_ROOM_POWER_LEVELS -> formatRoomPowerLevels(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_POWER_LEVELS -> formatRoomPowerLevels(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.CALL_INVITE, EventType.CALL_INVITE,
EventType.CALL_CANDIDATES, EventType.CALL_CANDIDATES,
@ -176,20 +170,20 @@ class NoticeEventFormatter @Inject constructor(
} }
} }
fun format(event: Event, senderName: String?, rs: RoomSummary?): CharSequence? { fun format(event: Event, senderName: String?, isDm: Boolean): CharSequence? {
return when (val type = event.getClearType()) { return when (val type = event.getClearType()) {
EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(event, senderName, rs) EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(event, senderName, isDm)
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(event, senderName) EventType.STATE_ROOM_NAME -> formatRoomNameEvent(event, senderName)
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(event, senderName) EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(event, senderName)
EventType.STATE_ROOM_AVATAR -> formatRoomAvatarEvent(event, senderName) EventType.STATE_ROOM_AVATAR -> formatRoomAvatarEvent(event, senderName)
EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(event, senderName, rs) EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(event, senderName, isDm)
EventType.STATE_ROOM_THIRD_PARTY_INVITE -> formatRoomThirdPartyInvite(event, senderName, rs) EventType.STATE_ROOM_THIRD_PARTY_INVITE -> formatRoomThirdPartyInvite(event, senderName, isDm)
EventType.STATE_ROOM_HISTORY_VISIBILITY -> formatRoomHistoryVisibilityEvent(event, senderName, rs) EventType.STATE_ROOM_HISTORY_VISIBILITY -> formatRoomHistoryVisibilityEvent(event, senderName, isDm)
EventType.CALL_INVITE, EventType.CALL_INVITE,
EventType.CALL_HANGUP, EventType.CALL_HANGUP,
EventType.CALL_REJECT, EventType.CALL_REJECT,
EventType.CALL_ANSWER -> formatCallEvent(type, event, senderName) EventType.CALL_ANSWER -> formatCallEvent(type, event, senderName)
EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(event, senderName, rs) EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(event, senderName, isDm)
else -> { else -> {
Timber.v("Type $type not handled by this formatter") Timber.v("Type $type not handled by this formatter")
null null
@ -201,14 +195,14 @@ class NoticeEventFormatter @Inject constructor(
return "Debug: event type \"${event.getClearType()}\"" return "Debug: event type \"${event.getClearType()}\""
} }
private fun formatRoomCreateEvent(event: Event, rs: RoomSummary?): CharSequence? { private fun formatRoomCreateEvent(event: Event, isDm: Boolean): CharSequence? {
return event.getClearContent().toModel<RoomCreateContent>() return event.getClearContent().toModel<RoomCreateContent>()
?.takeIf { it.creator.isNullOrBlank().not() } ?.takeIf { it.creator.isNullOrBlank().not() }
?.let { ?.let {
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_created_by_you else R.string.notice_room_created_by_you) sp.getString(if (isDm) R.string.notice_direct_room_created_by_you else R.string.notice_room_created_by_you)
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_created else R.string.notice_room_created, it.creator) sp.getString(if (isDm) R.string.notice_direct_room_created else R.string.notice_room_created, it.creator)
} }
} }
} }
@ -230,11 +224,11 @@ class NoticeEventFormatter @Inject constructor(
} }
} }
private fun formatRoomTombstoneEvent(event: Event, senderName: String?, rs: RoomSummary?): CharSequence? { private fun formatRoomTombstoneEvent(event: Event, senderName: String?, isDm: Boolean): CharSequence? {
return if (event.isSentByCurrentUser()) { return if (event.isSentByCurrentUser()) {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_update_by_you else R.string.notice_room_update_by_you) sp.getString(if (isDm) R.string.notice_direct_room_update_by_you else R.string.notice_room_update_by_you)
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_update else R.string.notice_room_update, senderName) sp.getString(if (isDm) R.string.notice_direct_room_update else R.string.notice_room_update, senderName)
} }
} }
@ -272,20 +266,20 @@ class NoticeEventFormatter @Inject constructor(
} }
} }
private fun formatRoomHistoryVisibilityEvent(event: Event, senderName: String?, rs: RoomSummary?): CharSequence? { private fun formatRoomHistoryVisibilityEvent(event: Event, senderName: String?, isDm: Boolean): CharSequence? {
val historyVisibility = event.getClearContent().toModel<RoomHistoryVisibilityContent>()?.historyVisibility ?: return null val historyVisibility = event.getClearContent().toModel<RoomHistoryVisibilityContent>()?.historyVisibility ?: return null
val historyVisibilitySuffix = roomHistoryVisibilityFormatter.getNoticeSuffix(historyVisibility) val historyVisibilitySuffix = roomHistoryVisibilityFormatter.getNoticeSuffix(historyVisibility)
return if (event.isSentByCurrentUser()) { return if (event.isSentByCurrentUser()) {
sp.getString(if (rs.isDm()) R.string.notice_made_future_direct_room_visibility_by_you else R.string.notice_made_future_room_visibility_by_you, sp.getString(if (isDm) R.string.notice_made_future_direct_room_visibility_by_you else R.string.notice_made_future_room_visibility_by_you,
historyVisibilitySuffix) historyVisibilitySuffix)
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_made_future_direct_room_visibility else R.string.notice_made_future_room_visibility, sp.getString(if (isDm) R.string.notice_made_future_direct_room_visibility else R.string.notice_made_future_room_visibility,
senderName, historyVisibilitySuffix) senderName, historyVisibilitySuffix)
} }
} }
private fun formatRoomThirdPartyInvite(event: Event, senderName: String?, rs: RoomSummary?): CharSequence? { private fun formatRoomThirdPartyInvite(event: Event, senderName: String?, isDm: Boolean): CharSequence? {
val content = event.getClearContent().toModel<RoomThirdPartyInviteContent>() val content = event.getClearContent().toModel<RoomThirdPartyInviteContent>()
val prevContent = event.resolvedPrevContent()?.toModel<RoomThirdPartyInviteContent>() val prevContent = event.resolvedPrevContent()?.toModel<RoomThirdPartyInviteContent>()
@ -294,24 +288,24 @@ class NoticeEventFormatter @Inject constructor(
// Revoke case // Revoke case
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString( sp.getString(
if (rs.isDm()) { if (isDm) {
R.string.notice_direct_room_third_party_revoked_invite_by_you R.string.notice_direct_room_third_party_revoked_invite_by_you
} else { } else {
R.string.notice_room_third_party_revoked_invite_by_you R.string.notice_room_third_party_revoked_invite_by_you
}, },
prevContent.displayName) prevContent.displayName)
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_third_party_revoked_invite else R.string.notice_room_third_party_revoked_invite, sp.getString(if (isDm) R.string.notice_direct_room_third_party_revoked_invite else R.string.notice_room_third_party_revoked_invite,
senderName, prevContent.displayName) senderName, prevContent.displayName)
} }
} }
content != null -> { content != null -> {
// Invitation case // Invitation case
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_third_party_invite_by_you else R.string.notice_room_third_party_invite_by_you, sp.getString(if (isDm) R.string.notice_direct_room_third_party_invite_by_you else R.string.notice_room_third_party_invite_by_you,
content.displayName) content.displayName)
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_third_party_invite else R.string.notice_room_third_party_invite, sp.getString(if (isDm) R.string.notice_direct_room_third_party_invite else R.string.notice_room_third_party_invite,
senderName, content.displayName) senderName, content.displayName)
} }
} }
@ -366,13 +360,13 @@ class NoticeEventFormatter @Inject constructor(
} }
} }
private fun formatRoomMemberEvent(event: Event, senderName: String?, rs: RoomSummary?): String? { private fun formatRoomMemberEvent(event: Event, senderName: String?, isDm: Boolean): String? {
val eventContent: RoomMemberContent? = event.getClearContent().toModel() val eventContent: RoomMemberContent? = event.getClearContent().toModel()
val prevEventContent: RoomMemberContent? = event.resolvedPrevContent().toModel() val prevEventContent: RoomMemberContent? = event.resolvedPrevContent().toModel()
val isMembershipEvent = prevEventContent?.membership != eventContent?.membership val isMembershipEvent = prevEventContent?.membership != eventContent?.membership
|| eventContent?.membership == Membership.LEAVE || eventContent?.membership == Membership.LEAVE
return if (isMembershipEvent) { return if (isMembershipEvent) {
buildMembershipNotice(event, senderName, eventContent, prevEventContent, rs) buildMembershipNotice(event, senderName, eventContent, prevEventContent, isDm)
} else { } else {
buildProfileNotice(event, senderName, eventContent, prevEventContent) buildProfileNotice(event, senderName, eventContent, prevEventContent)
} }
@ -554,25 +548,25 @@ class NoticeEventFormatter @Inject constructor(
} }
} }
private fun formatRoomGuestAccessEvent(event: Event, senderName: String?, rs: RoomSummary?): String? { private fun formatRoomGuestAccessEvent(event: Event, senderName: String?, isDm: Boolean): String? {
val eventContent: RoomGuestAccessContent? = event.getClearContent().toModel() val eventContent: RoomGuestAccessContent? = event.getClearContent().toModel()
return when (eventContent?.guestAccess) { return when (eventContent?.guestAccess) {
GuestAccess.CanJoin -> GuestAccess.CanJoin ->
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString( sp.getString(
if (rs.isDm()) R.string.notice_direct_room_guest_access_can_join_by_you else R.string.notice_room_guest_access_can_join_by_you if (isDm) R.string.notice_direct_room_guest_access_can_join_by_you else R.string.notice_room_guest_access_can_join_by_you
) )
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_guest_access_can_join else R.string.notice_room_guest_access_can_join, sp.getString(if (isDm) R.string.notice_direct_room_guest_access_can_join else R.string.notice_room_guest_access_can_join,
senderName) senderName)
} }
GuestAccess.Forbidden -> GuestAccess.Forbidden ->
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString( sp.getString(
if (rs.isDm()) R.string.notice_direct_room_guest_access_forbidden_by_you else R.string.notice_room_guest_access_forbidden_by_you if (isDm) R.string.notice_direct_room_guest_access_forbidden_by_you else R.string.notice_room_guest_access_forbidden_by_you
) )
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_guest_access_forbidden else R.string.notice_room_guest_access_forbidden, sp.getString(if (isDm) R.string.notice_direct_room_guest_access_forbidden else R.string.notice_room_guest_access_forbidden,
senderName) senderName)
} }
else -> null else -> null
@ -656,7 +650,7 @@ class NoticeEventFormatter @Inject constructor(
senderName: String?, senderName: String?,
eventContent: RoomMemberContent?, eventContent: RoomMemberContent?,
prevEventContent: RoomMemberContent?, prevEventContent: RoomMemberContent?,
rs: RoomSummary?): String? { isDm: Boolean): String? {
val senderDisplayName = senderName ?: event.senderId ?: "" val senderDisplayName = senderName ?: event.senderId ?: ""
val targetDisplayName = eventContent?.displayName ?: prevEventContent?.displayName ?: event.stateKey ?: "" val targetDisplayName = eventContent?.displayName ?: prevEventContent?.displayName ?: event.stateKey ?: ""
return when (eventContent?.membership) { return when (eventContent?.membership) {
@ -706,17 +700,17 @@ class NoticeEventFormatter @Inject constructor(
Membership.JOIN -> Membership.JOIN ->
eventContent.safeReason?.let { reason -> eventContent.safeReason?.let { reason ->
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_join_with_reason_by_you else R.string.notice_room_join_with_reason_by_you, sp.getString(if (isDm) R.string.notice_direct_room_join_with_reason_by_you else R.string.notice_room_join_with_reason_by_you,
reason) reason)
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_join_with_reason else R.string.notice_room_join_with_reason, sp.getString(if (isDm) R.string.notice_direct_room_join_with_reason else R.string.notice_room_join_with_reason,
senderDisplayName, reason) senderDisplayName, reason)
} }
} ?: run { } ?: run {
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_join_by_you else R.string.notice_room_join_by_you) sp.getString(if (isDm) R.string.notice_direct_room_join_by_you else R.string.notice_room_join_by_you)
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_join else R.string.notice_room_join, sp.getString(if (isDm) R.string.notice_direct_room_join else R.string.notice_room_join,
senderDisplayName) senderDisplayName)
} }
} }
@ -738,7 +732,7 @@ class NoticeEventFormatter @Inject constructor(
eventContent.safeReason?.let { reason -> eventContent.safeReason?.let { reason ->
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString( sp.getString(
if (rs.isDm()) { if (isDm) {
R.string.notice_direct_room_leave_with_reason_by_you R.string.notice_direct_room_leave_with_reason_by_you
} else { } else {
R.string.notice_room_leave_with_reason_by_you R.string.notice_room_leave_with_reason_by_you
@ -746,14 +740,14 @@ class NoticeEventFormatter @Inject constructor(
reason reason
) )
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_leave_with_reason else R.string.notice_room_leave_with_reason, sp.getString(if (isDm) R.string.notice_direct_room_leave_with_reason else R.string.notice_room_leave_with_reason,
senderDisplayName, reason) senderDisplayName, reason)
} }
} ?: run { } ?: run {
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_leave_by_you else R.string.notice_room_leave_by_you) sp.getString(if (isDm) R.string.notice_direct_room_leave_by_you else R.string.notice_room_leave_by_you)
} else { } else {
sp.getString(if (rs.isDm()) R.string.notice_direct_room_leave else R.string.notice_room_leave, sp.getString(if (isDm) R.string.notice_direct_room_leave else R.string.notice_room_leave,
senderDisplayName) senderDisplayName)
} }
} }
@ -818,14 +812,14 @@ class NoticeEventFormatter @Inject constructor(
} }
} }
private fun formatJoinRulesEvent(event: Event, senderName: String?, rs: RoomSummary?): CharSequence? { private fun formatJoinRulesEvent(event: Event, senderName: String?, isDm: Boolean): CharSequence? {
val content = event.getClearContent().toModel<RoomJoinRulesContent>() ?: return null val content = event.getClearContent().toModel<RoomJoinRulesContent>() ?: return null
return when (content.joinRules) { return when (content.joinRules) {
RoomJoinRules.INVITE -> RoomJoinRules.INVITE ->
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString(if (rs.isDm()) R.string.direct_room_join_rules_invite_by_you else R.string.room_join_rules_invite_by_you) sp.getString(if (isDm) R.string.direct_room_join_rules_invite_by_you else R.string.room_join_rules_invite_by_you)
} else { } else {
sp.getString(if (rs.isDm()) R.string.direct_room_join_rules_invite else R.string.room_join_rules_invite, sp.getString(if (isDm) R.string.direct_room_join_rules_invite else R.string.room_join_rules_invite,
senderName) senderName)
} }
RoomJoinRules.PUBLIC -> RoomJoinRules.PUBLIC ->

View File

@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage
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.room.model.ReferencesAggregatedContent import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
@ -48,7 +49,6 @@ import javax.inject.Inject
* This class compute if data of an event (such has avatar, display name, ...) should be displayed, depending on the previous event in the timeline * This class compute if data of an event (such has avatar, display name, ...) should be displayed, depending on the previous event in the timeline
*/ */
class MessageInformationDataFactory @Inject constructor(private val session: Session, class MessageInformationDataFactory @Inject constructor(private val session: Session,
private val roomSummariesHolder: RoomSummariesHolder,
private val dateFormatter: VectorDateFormatter, private val dateFormatter: VectorDateFormatter,
private val visibilityHelper: TimelineEventVisibilityHelper, private val visibilityHelper: TimelineEventVisibilityHelper,
private val vectorPreferences: VectorPreferences) { private val vectorPreferences: VectorPreferences) {
@ -74,7 +74,8 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
|| nextDisplayableEvent.isEdition() || nextDisplayableEvent.isEdition()
val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE) val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE)
val e2eDecoration = getE2EDecoration(event) val roomSummary = params.partialState.roomSummary
val e2eDecoration = getE2EDecoration(roomSummary, event)
// SendState Decoration // SendState Decoration
val isSentByMe = event.root.senderId == session.myUserId val isSentByMe = event.root.senderId == session.myUserId
@ -140,8 +141,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
} }
} }
private fun getE2EDecoration(event: TimelineEvent): E2EDecoration { private fun getE2EDecoration(roomSummary: RoomSummary? , event: TimelineEvent): E2EDecoration {
val roomSummary = roomSummariesHolder.get(event.roomId)
return if ( return if (
event.root.sendState == SendState.SYNCED event.root.sendState == SendState.SYNCED
&& roomSummary?.isEncrypted.orFalse() && roomSummary?.isEncrypted.orFalse()

View File

@ -1,43 +0,0 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.home.room.detail.timeline.helper
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import javax.inject.Inject
import javax.inject.Singleton
/*
You can use this to share room summary instances within the app.
You should probably use this only in the context of the timeline
*/
@Singleton
class RoomSummariesHolder @Inject constructor() {
private var roomSummaries = HashMap<String, RoomSummary>()
fun set(roomSummary: RoomSummary) {
roomSummaries[roomSummary.roomId] = roomSummary
}
fun get(roomId: String) = roomSummaries[roomId]
fun remove(roomId: String) = roomSummaries.remove(roomId)
fun clear() {
roomSummaries.clear()
}
}

View File

@ -114,7 +114,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
var latestEventTime: CharSequence = "" var latestEventTime: CharSequence = ""
val latestEvent = roomSummary.latestPreviewableEvent val latestEvent = roomSummary.latestPreviewableEvent
if (latestEvent != null) { if (latestEvent != null) {
latestFormattedEvent = displayableEventFormatter.format(latestEvent, roomSummary.isDirect.not()) latestFormattedEvent = displayableEventFormatter.format(latestEvent, roomSummary.isDirect, roomSummary.isDirect.not())
latestEventTime = dateFormatter.format(latestEvent.root.originServerTs, DateFormatKind.ROOM_LIST) latestEventTime = dateFormatter.format(latestEvent.root.originServerTs, DateFormatKind.ROOM_LIST)
} }
val typingMessage = typingHelper.getTypingMessage(roomSummary.typingUsers) val typingMessage = typingHelper.getTypingMessage(roomSummary.typingUsers)

View File

@ -21,6 +21,7 @@ import im.vector.app.R
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
import im.vector.app.features.home.room.detail.timeline.format.NoticeEventFormatter import im.vector.app.features.home.room.detail.timeline.format.NoticeEventFormatter
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.content.ContentUrlResolver import org.matrix.android.sdk.api.session.content.ContentUrlResolver
import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.MXCryptoError
@ -135,7 +136,7 @@ class NotifiableEventResolver @Inject constructor(
if (room == null) { if (room == null) {
Timber.e("## Unable to resolve room for eventId [$event]") Timber.e("## Unable to resolve room for eventId [$event]")
// Ok room is not known in store, but we can still display something // Ok room is not known in store, but we can still display something
val body = displayableEventFormatter.format(event, false) val body = displayableEventFormatter.format(event, isDm = false, appendAuthor = false)
val roomName = stringProvider.getString(R.string.notification_unknown_room_name) val roomName = stringProvider.getString(R.string.notification_unknown_room_name)
val senderDisplayName = event.senderInfo.disambiguatedDisplayName val senderDisplayName = event.senderInfo.disambiguatedDisplayName
@ -168,7 +169,7 @@ class NotifiableEventResolver @Inject constructor(
} }
} }
val body = displayableEventFormatter.format(event, false).toString() val body = displayableEventFormatter.format(event, isDm = room.roomSummary()?.isDirect.orFalse(), appendAuthor = false).toString()
val roomName = room.roomSummary()?.displayName ?: "" val roomName = room.roomSummary()?.displayName ?: ""
val senderDisplayName = event.senderInfo.disambiguatedDisplayName val senderDisplayName = event.senderInfo.disambiguatedDisplayName
@ -209,7 +210,7 @@ class NotifiableEventResolver @Inject constructor(
val roomId = event.roomId ?: return null val roomId = event.roomId ?: return null
val dName = event.senderId?.let { session.getRoomMember(it, roomId)?.displayName } val dName = event.senderId?.let { session.getRoomMember(it, roomId)?.displayName }
if (Membership.INVITE == content.membership) { if (Membership.INVITE == content.membership) {
val body = noticeEventFormatter.format(event, dName, session.getRoomSummary(roomId)) val body = noticeEventFormatter.format(event, dName, isDm = session.getRoomSummary(roomId)?.isDirect.orFalse())
?: stringProvider.getString(R.string.notification_new_invitation) ?: stringProvider.getString(R.string.notification_new_invitation)
return InviteNotifiableEvent( return InviteNotifiableEvent(
session.myUserId, session.myUserId,