diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 1a0c0f91..3fda5a63 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -48,7 +48,7 @@ android { buildConfigField "boolean", "LOG_PRIVATE_DATA", "false" // Set to BODY instead of NONE to enable logging - buildConfigField "okhttp3.logging.HttpLoggingInterceptor.Level", "OKHTTP_LOGGING_LEVEL", "okhttp3.logging.HttpLoggingInterceptor.Level.BASIC" + buildConfigField "okhttp3.logging.HttpLoggingInterceptor.Level", "OKHTTP_LOGGING_LEVEL", "okhttp3.logging.HttpLoggingInterceptor.Level.NONE" } release { @@ -91,7 +91,7 @@ dependencies { def moshi_version = '1.8.0' def lifecycle_version = '2.0.0' def coroutines_version = "1.0.1" - def markwon_version = '3.0.0-SNAPSHOT' + def markwon_version = '3.0.0' implementation fileTree(dir: 'libs', include: ['*.aar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt index 3c21437e..34b29187 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt @@ -16,6 +16,7 @@ package im.vector.matrix.android.internal.database.mapper +import com.squareup.moshi.JsonDataException import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.UnsignedData import im.vector.matrix.android.internal.database.model.EventEntity @@ -46,8 +47,16 @@ internal object EventMapper { fun map(eventEntity: EventEntity): Event { //TODO proxy the event to only parse unsigned data when accessed? - var ud = if (eventEntity.unsignedData.isNullOrBlank()) null - else MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).fromJson(eventEntity.unsignedData) + val ud = if (eventEntity.unsignedData.isNullOrBlank()) { + null + } else { + try { + MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).fromJson(eventEntity.unsignedData) + } catch (t: JsonDataException) { + null + } + + } return Event( type = eventEntity.type, eventId = eventEntity.eventId, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt index e5fb5493..3b024942 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt @@ -27,7 +27,6 @@ import im.vector.matrix.android.internal.database.model.* import im.vector.matrix.android.internal.database.query.create import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.task.Task -import im.vector.matrix.android.internal.util.tryTransactionAsync import im.vector.matrix.android.internal.util.tryTransactionSync import io.realm.Realm import timber.log.Timber @@ -49,60 +48,75 @@ internal class DefaultEventRelationsAggregationTask(private val monarchy: Monarc private val SHOULD_HANDLE_SERVER_AGREGGATION = false override fun execute(params: EventRelationsAggregationTask.Params): Try { + val events = params.events + val userId = params.userId return monarchy.tryTransactionSync { realm -> - update(realm, params.events, params.userId) + Timber.v(">>> DefaultEventRelationsAggregationTask[${params.hashCode()}] called with ${events.size} events") + update(realm, events, userId) + Timber.v("<<< DefaultEventRelationsAggregationTask[${params.hashCode()}] finished") } } private fun update(realm: Realm, events: List>, userId: String) { events.forEach { pair -> - val roomId = pair.first.roomId ?: return@forEach - val event = pair.first - val sendState = pair.second - val isLocalEcho = sendState == SendState.UNSENT - when (event.type) { - EventType.REACTION -> { - //we got a reaction!! - Timber.v("###REACTION in room $roomId") - handleReaction(event, roomId, realm, userId, isLocalEcho) + try { //Temporary catch, should be removed + val roomId = pair.first.roomId + if (roomId == null) { + Timber.w("Event has no room id ${pair.first.eventId}") + return@forEach } - EventType.MESSAGE -> { - if (event.unsignedData?.relations?.annotations != null) { - Timber.v("###REACTION Agreggation in room $roomId for event ${event.eventId}") - handleInitialAggregatedRelations(event, roomId, event.unsignedData.relations.annotations, realm) - } else { - val content: MessageContent? = event.content.toModel() - if (content?.relatesTo?.type == RelationType.REPLACE) { - Timber.v("###REPLACE in room $roomId for event ${event.eventId}") - //A replace! - handleReplace(realm, event, content, roomId, isLocalEcho) - } + val event = pair.first + val sendState = pair.second + val isLocalEcho = sendState == SendState.UNSENT + when (event.type) { + EventType.REACTION -> { + //we got a reaction!! + Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}") + handleReaction(event, roomId, realm, userId, isLocalEcho) } - - } - EventType.REDACTION -> { - val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() } - ?: return - when (eventToPrune.type) { - EventType.MESSAGE -> { - Timber.d("REDACTION for message ${eventToPrune.eventId}") - val unsignedData = EventMapper.map(eventToPrune).unsignedData - ?: UnsignedData(null, null) - - //was this event a m.replace - val contentModel = ContentMapper.map(eventToPrune.content)?.toModel() - if (RelationType.REPLACE == contentModel?.relatesTo?.type && contentModel.relatesTo?.eventId != null) { - handleRedactionOfReplace(eventToPrune, contentModel.relatesTo!!.eventId!!, realm) + EventType.MESSAGE -> { + if (event.unsignedData?.relations?.annotations != null) { + Timber.v("###REACTION Agreggation in room $roomId for event ${event.eventId}") + handleInitialAggregatedRelations(event, roomId, event.unsignedData.relations.annotations, realm) + } else { + val content: MessageContent? = event.content.toModel() + if (content?.relatesTo?.type == RelationType.REPLACE) { + Timber.v("###REPLACE in room $roomId for event ${event.eventId}") + //A replace! + handleReplace(realm, event, content, roomId, isLocalEcho) } - } - EventType.REACTION -> { - handleReactionRedact(eventToPrune, realm, userId) + + } + EventType.REDACTION -> { + val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() } + ?: return@forEach + when (eventToPrune.type) { + EventType.MESSAGE -> { + Timber.d("REDACTION for message ${eventToPrune.eventId}") + val unsignedData = EventMapper.map(eventToPrune).unsignedData + ?: UnsignedData(null, null) + + //was this event a m.replace + val contentModel = ContentMapper.map(eventToPrune.content)?.toModel() + if (RelationType.REPLACE == contentModel?.relatesTo?.type && contentModel.relatesTo?.eventId != null) { + handleRedactionOfReplace(eventToPrune, contentModel.relatesTo!!.eventId!!, realm) + } + + } + EventType.REACTION -> { + handleReactionRedact(eventToPrune, realm, userId) + } } } + else -> Timber.v("UnHandled event ${event.eventId}") } + + } catch (t: Throwable) { + Timber.e(t, "## Should not happen ") } } + } private fun handleReplace(realm: Realm, event: Event, content: MessageContent, roomId: String, isLocalEcho: Boolean) { @@ -112,7 +126,7 @@ internal class DefaultEventRelationsAggregationTask(private val monarchy: Monarc //ok, this is a replace var existing = EventAnnotationsSummaryEntity.where(realm, targetEventId).findFirst() if (existing == null) { - Timber.v("###REPLACE creating no relation summary for ${targetEventId}") + Timber.v("###REPLACE creating new relation summary for ${targetEventId}") existing = EventAnnotationsSummaryEntity.create(realm, targetEventId) existing.roomId = roomId } @@ -120,7 +134,7 @@ internal class DefaultEventRelationsAggregationTask(private val monarchy: Monarc //we have it val existingSummary = existing.editSummary if (existingSummary == null) { - Timber.v("###REPLACE no edit summary for ${targetEventId}, creating one (localEcho:$isLocalEcho)") + Timber.v("###REPLACE new edit summary for ${targetEventId}, creating one (localEcho:$isLocalEcho)") //create the edit summary val editSummary = realm.createObject(EditAggregatedSummaryEntity::class.java) editSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis() @@ -181,62 +195,70 @@ internal class DefaultEventRelationsAggregationTask(private val monarchy: Monarc } private fun handleReaction(event: Event, roomId: String, realm: Realm, userId: String, isLocalEcho: Boolean) { - event.content.toModel()?.let { content -> - //rel_type must be m.annotation - if (RelationType.ANNOTATION == content.relatesTo?.type) { - val reaction = content.relatesTo.key - val eventId = content.relatesTo.eventId - val eventSummary = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() - ?: EventAnnotationsSummaryEntity.create(realm, eventId).apply { this.roomId = roomId } + val content = event.content.toModel() + if (content == null) { + Timber.e("Malformed reaction content ${event.content}") + return + } + //rel_type must be m.annotation + if (RelationType.ANNOTATION == content.relatesTo?.type) { + val reaction = content.relatesTo.key + val relatedEventID = content.relatesTo.eventId + val reactionEventId = event.eventId + Timber.v("Reaction $reactionEventId relates to $relatedEventID") + val eventSummary = EventAnnotationsSummaryEntity.where(realm, relatedEventID).findFirst() + ?: EventAnnotationsSummaryEntity.create(realm, relatedEventID).apply { this.roomId = roomId } - var sum = eventSummary.reactionsSummary.find { it.key == reaction } - val txId = event.unsignedData?.transactionId - if (isLocalEcho && txId.isNullOrBlank()) { - Timber.w("Received a local echo with no transaction ID") - } - if (sum == null) { - sum = realm.createObject(ReactionAggregatedSummaryEntity::class.java) - sum.key = reaction - sum.firstTimestamp = event.originServerTs ?: 0 - if (isLocalEcho) { - Timber.v("Adding local echo reaction $reaction") - sum.sourceLocalEcho.add(txId) - sum.count = 1 - } else { - Timber.v("Adding synced reaction $reaction") - sum.count = 1 - sum.sourceEvents.add(event.eventId) - } - sum.addedByMe = sum.addedByMe || (userId == event.sender) - eventSummary.reactionsSummary.add(sum) + var sum = eventSummary.reactionsSummary.find { it.key == reaction } + val txId = event.unsignedData?.transactionId + if (isLocalEcho && txId.isNullOrBlank()) { + Timber.w("Received a local echo with no transaction ID") + } + if (sum == null) { + sum = realm.createObject(ReactionAggregatedSummaryEntity::class.java) + sum.key = reaction + sum.firstTimestamp = event.originServerTs ?: 0 + if (isLocalEcho) { + Timber.v("Adding local echo reaction $reaction") + sum.sourceLocalEcho.add(txId) + sum.count = 1 } else { - //is this a known event (is possible? pagination?) - if (!sum.sourceEvents.contains(eventId)) { + Timber.v("Adding synced reaction $reaction") + sum.count = 1 + sum.sourceEvents.add(reactionEventId) + } + sum.addedByMe = sum.addedByMe || (userId == event.sender) + eventSummary.reactionsSummary.add(sum) + } else { + //is this a known event (is possible? pagination?) + if (!sum.sourceEvents.contains(reactionEventId)) { - //check if it's not the sync of a local echo - if (!isLocalEcho && sum.sourceLocalEcho.contains(txId)) { - //ok it has already been counted, just sync the list, do not touch count - Timber.v("Ignoring synced of local echo for reaction $reaction") - sum.sourceLocalEcho.remove(txId) - sum.sourceEvents.add(event.eventId) + //check if it's not the sync of a local echo + if (!isLocalEcho && sum.sourceLocalEcho.contains(txId)) { + //ok it has already been counted, just sync the list, do not touch count + Timber.v("Ignoring synced of local echo for reaction $reaction") + sum.sourceLocalEcho.remove(txId) + sum.sourceEvents.add(reactionEventId) + } else { + sum.count += 1 + if (isLocalEcho) { + Timber.v("Adding local echo reaction $reaction") + sum.sourceLocalEcho.add(txId) } else { - sum.count += 1 - if (isLocalEcho) { - Timber.v("Adding local echo reaction $reaction") - sum.sourceLocalEcho.add(txId) - } else { - Timber.v("Adding synced reaction $reaction") - sum.sourceEvents.add(event.eventId) - } - - sum.addedByMe = sum.addedByMe || (userId == event.sender) + Timber.v("Adding synced reaction $reaction") + sum.sourceEvents.add(reactionEventId) } + sum.addedByMe = sum.addedByMe || (userId == event.sender) } - } + } } + + } else { + Timber.e("Unknwon relation type ${content.relatesTo?.type} for event ${event.eventId}") } + } /** diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt index 0b29064c..a04ed216 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt @@ -46,11 +46,11 @@ internal class EventRelationsAggregationUpdater(monarchy: Monarchy, override fun processChanges(inserted: List, updated: List, deleted: List) { Timber.v("EventRelationsAggregationUpdater called with ${inserted.size} insertions") - val inserted = inserted - .mapNotNull { it.asDomain() to it.sendState } + val domainInserted = inserted + .map { it.asDomain() to it.sendState } val params = EventRelationsAggregationTask.Params( - inserted, + domainInserted, credentials.userId ) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt index a6855817..caf75bd7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt @@ -38,7 +38,12 @@ internal class TaskExecutor(private val coroutineDispatchers: MatrixCoroutineDis task.execute(task.params) } } - resultOrFailure.fold({ task.callback.onFailure(it) }, { task.callback.onSuccess(it) }) + resultOrFailure.fold({ + Timber.d(it, "Task failed") + task.callback.onFailure(it) + }, { + task.callback.onSuccess(it) + }) } return CancelableCoroutine(job) } diff --git a/vector/build.gradle b/vector/build.gradle index 4cec152f..263df78e 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -84,13 +84,15 @@ android { debug { resValue "bool", "debug_mode", "true" buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false" - + buildConfigField "boolean", "SHOW_HIDDEN_TIMELINE_EVENTS", "false" + signingConfig signingConfigs.debug } release { resValue "bool", "debug_mode", "false" buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false" + buildConfigField "boolean", "SHOW_HIDDEN_TIMELINE_EVENTS", "false" minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' @@ -132,7 +134,7 @@ dependencies { def epoxy_version = "3.3.0" def arrow_version = "0.8.2" def coroutines_version = "1.0.1" - def markwon_version = '3.0.0-SNAPSHOT' + def markwon_version = '3.0.0' def big_image_viewer_version = '1.5.6' def glide_version = '4.9.0' def moshi_version = '1.8.0' diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt index 1da6ed9d..55284325 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt @@ -563,11 +563,11 @@ class RoomDetailFragment : vectorBaseActivity.notImplemented() } - override fun onEventCellClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View) { + override fun onEventCellClicked(informationData: MessageInformationData, messageContent: MessageContent?, view: View) { } - override fun onEventLongClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View): Boolean { + override fun onEventLongClicked(informationData: MessageInformationData, messageContent: MessageContent?, view: View): Boolean { view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) val roomId = roomDetailArgs.roomId diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt index 351129a2..346d21c3 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt @@ -55,7 +55,8 @@ class RoomDetailViewModel(initialState: RoomDetailViewState, private val roomId = initialState.roomId private val eventId = initialState.eventId private val displayedEventsObservable = BehaviorRelay.create() - private val timeline = room.createTimeline(eventId, TimelineDisplayableEvents.DISPLAYABLE_TYPES) + private val timeline = room.createTimeline(eventId, + if (TimelineDisplayableEvents.DEBUG_HIDDEN_EVENT) TimelineDisplayableEvents.DEBUG_DISPLAYABLE_TYPES else TimelineDisplayableEvents.DISPLAYABLE_TYPES) companion object : MvRxViewModelFactory { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt index 2861ae6a..2a436a19 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt @@ -46,15 +46,13 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter, private val backgroundHandler: Handler = TimelineAsyncHelper.getBackgroundHandler() ) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener { - interface Callback : ReactionPillCallback, AvatarCallback { + interface Callback : ReactionPillCallback, AvatarCallback, BaseCallback { fun onEventVisible(event: TimelineEvent) fun onUrlClicked(url: String) fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: VideoContentRenderer.Data, view: View) fun onFileMessageClicked(messageFileContent: MessageFileContent) fun onAudioMessageClicked(messageAudioContent: MessageAudioContent) - fun onEventCellClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View) - fun onEventLongClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View): Boolean fun onEditedDecorationClicked(informationData: MessageInformationData, editAggregatedSummary: EditAggregatedSummary?) } @@ -63,6 +61,11 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter, fun onLongClickOnReactionPill(informationData: MessageInformationData, reaction: String) } + interface BaseCallback { + fun onEventCellClicked(informationData: MessageInformationData, messageContent: MessageContent?, view: View) + fun onEventLongClicked(informationData: MessageInformationData, messageContent: MessageContent?, view: View): Boolean + } + interface AvatarCallback { fun onAvatarClicked(informationData: MessageInformationData) fun onMemberNameClicked(informationData: MessageInformationData) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt index ca422f72..6d99d41a 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt @@ -34,7 +34,7 @@ import org.koin.android.ext.android.get data class SimpleAction(val uid: String, val titleRes: Int, val iconResId: Int?, val data: Any? = null) -data class MessageMenuState(val actions: List) : MvRxState +data class MessageMenuState(val actions: List = emptyList()) : MvRxState /** * Manages list actions for a given message (copy / paste / forward...) @@ -50,9 +50,9 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel noticeItemFactory.create(event) + EventType.CALL_ANSWER -> noticeItemFactory.create(event, callback) // Unhandled event types (yet) EventType.ENCRYPTED, @@ -51,9 +57,32 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, EventType.STATE_ROOM_THIRD_PARTY_INVITE, EventType.STICKER, EventType.STATE_ROOM_CREATE -> defaultItemFactory.create(event) + else -> { - Timber.w("Ignored event (type: ${event.root.type}") - null + //These are just for debug to display hidden event, they should be filtered out in normal mode + if (TimelineDisplayableEvents.DEBUG_HIDDEN_EVENT) { + val informationData = MessageInformationData(eventId = event.root.eventId + ?: "?", + senderId = event.root.sender ?: "", + sendState = event.sendState, + time = "", + avatarUrl = null, + memberName = "", + showInformation = false + ) + val messageContent = event.root.content.toModel() + ?: MessageDefaultContent("", "", null, null) + MessageTextItem_() + .informationData(informationData) + .message("{ \"type\": ${event.root.type} }") + .longClickListener { view -> + return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) + ?: false + } + } else { + Timber.w("Ignored event (type: ${event.root.type}") + null + } } } } catch (e: Exception) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt index 657d9e03..711b870e 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt @@ -22,10 +22,14 @@ import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.riotredesign.BuildConfig import im.vector.riotredesign.core.extensions.localDateTime object TimelineDisplayableEvents { + //Debug helper, to show invisible items in time line (reaction, redacts) + val DEBUG_HIDDEN_EVENT = BuildConfig.SHOW_HIDDEN_TIMELINE_EVENTS + val DISPLAYABLE_TYPES = listOf( EventType.MESSAGE, EventType.STATE_ROOM_NAME, @@ -41,6 +45,11 @@ object TimelineDisplayableEvents { EventType.STICKER, EventType.STATE_ROOM_CREATE ) + + val DEBUG_DISPLAYABLE_TYPES = DISPLAYABLE_TYPES + listOf( + EventType.REDACTION, + EventType.REACTION + ) } fun TimelineEvent.isDisplayable(): Boolean { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt index dcb0bdf4..914cb232 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt @@ -23,27 +23,37 @@ import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.riotredesign.R import im.vector.riotredesign.features.home.AvatarRenderer +import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController @EpoxyModelClass(layout = R.layout.item_timeline_event_base_noinfo) abstract class NoticeItem : BaseEventItem() { @EpoxyAttribute var noticeText: CharSequence? = null - @EpoxyAttribute - var avatarUrl: String? = null - @EpoxyAttribute - var userId: String = "" - @EpoxyAttribute - var memberName: CharSequence? = null - @EpoxyAttribute - var longClickListener: View.OnLongClickListener? = null + lateinit var informationData: MessageInformationData + + @EpoxyAttribute + var baseCallback: TimelineEventController.BaseCallback? = null + + + private var longClickListener = View.OnLongClickListener { + baseCallback?.onEventLongClicked(informationData, null, it) + baseCallback != null + } + override fun bind(holder: Holder) { super.bind(holder) holder.noticeTextView.text = noticeText - AvatarRenderer.render(avatarUrl, userId, memberName?.toString(), holder.avatarImageView) + AvatarRenderer.render( + informationData.avatarUrl, + informationData.senderId, + informationData.memberName?.toString() + ?: informationData.senderId, + holder.avatarImageView + ) holder.view.setOnLongClickListener(longClickListener) } @@ -51,7 +61,6 @@ abstract class NoticeItem : BaseEventItem() { class Holder : BaseHolder() { override fun getStubId(): Int = STUB_ID - val avatarImageView by bind(R.id.itemNoticeAvatarView) val noticeTextView by bind(R.id.itemNoticeTextView) } diff --git a/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml b/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml index 07b43f7b..8163b3ac 100644 --- a/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml +++ b/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml @@ -4,6 +4,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:addStatesFromChildren="true" + android:background="?attr/selectableItemBackground" android:paddingLeft="8dp" android:paddingRight="8dp"> @@ -31,9 +32,9 @@