mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-27 03:49:04 +03:00
WIP
This commit is contained in:
parent
0eff00ebee
commit
68512e475f
5 changed files with 152 additions and 46 deletions
|
@ -47,9 +47,9 @@ import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineEventVi
|
|||
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||
import im.vector.riotx.features.home.room.detail.timeline.helper.nextOrNull
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.BaseEventItem
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.BasedMergedItem
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.DaySeparatorItem
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.DaySeparatorItem_
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.MergedHeaderItem
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.ReadReceiptData
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.TimelineReadMarkerItem_
|
||||
|
@ -373,7 +373,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
|||
val localId: Long,
|
||||
val eventId: String?,
|
||||
val eventModel: EpoxyModel<*>? = null,
|
||||
val mergedHeaderModel: MergedHeaderItem? = null,
|
||||
val mergedHeaderModel: BasedMergedItem<*>? = null,
|
||||
val formattedDayModel: DaySeparatorItem? = null
|
||||
) {
|
||||
fun shouldTriggerBuild(): Boolean {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.riotx.features.home.room.detail.timeline.factory
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
|
@ -23,7 +24,10 @@ import im.vector.riotx.features.home.room.detail.timeline.TimelineEventControlle
|
|||
import im.vector.riotx.features.home.room.detail.timeline.helper.AvatarSizeProvider
|
||||
import im.vector.riotx.features.home.room.detail.timeline.helper.MergedTimelineEventVisibilityStateChangedListener
|
||||
import im.vector.riotx.features.home.room.detail.timeline.helper.canBeMerged
|
||||
import im.vector.riotx.features.home.room.detail.timeline.helper.isRoomConfiguration
|
||||
import im.vector.riotx.features.home.room.detail.timeline.helper.prevSameTypeEvents
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.BaseEventItem
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.BasedMergedItem
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.MergedHeaderItem
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.MergedHeaderItem_
|
||||
import javax.inject.Inject
|
||||
|
@ -43,8 +47,72 @@ class MergedHeaderItemFactory @Inject constructor(private val sessionHolder: Act
|
|||
eventIdToHighlight: String?,
|
||||
callback: TimelineEventController.Callback?,
|
||||
requestModelBuild: () -> Unit)
|
||||
: MergedHeaderItem? {
|
||||
return if (!event.canBeMerged() || (nextEvent?.root?.getClearType() == event.root.getClearType() && !addDaySeparator)) {
|
||||
: BasedMergedItem<*>? {
|
||||
return if (nextEvent?.root?.getClearType() == EventType.STATE_ROOM_CREATE && event.isRoomConfiguration()) {
|
||||
// It's the first item before room.create
|
||||
// Collapse all room configuration events
|
||||
var prevEvent = if (currentPosition > 0) items[currentPosition -1] else null
|
||||
var tmpPos = currentPosition -1
|
||||
val mergedEvents = ArrayList<TimelineEvent>().also { it.add(event) }
|
||||
while(prevEvent != null && prevEvent.isRoomConfiguration()) {
|
||||
mergedEvents.add(prevEvent)
|
||||
tmpPos--
|
||||
prevEvent = if (tmpPos >= 0) items[tmpPos] else null
|
||||
}
|
||||
if (mergedEvents.size > 2) {
|
||||
var highlighted = false
|
||||
val mergedData = ArrayList<BasedMergedItem.Data>(mergedEvents.size)
|
||||
mergedEvents.reversed()
|
||||
.forEach { mergedEvent ->
|
||||
if (!highlighted && mergedEvent.root.eventId == eventIdToHighlight) {
|
||||
highlighted = true
|
||||
}
|
||||
val senderAvatar = mergedEvent.senderAvatar
|
||||
val senderName = mergedEvent.getDisambiguatedDisplayName()
|
||||
val data = BasedMergedItem.Data(
|
||||
userId = mergedEvent.root.senderId ?: "",
|
||||
avatarUrl = senderAvatar,
|
||||
memberName = senderName,
|
||||
localId = mergedEvent.localId,
|
||||
eventId = mergedEvent.root.eventId ?: ""
|
||||
)
|
||||
mergedData.add(data)
|
||||
}
|
||||
val mergedEventIds = mergedEvents.map { it.localId }
|
||||
// We try to find if one of the item id were used as mergeItemCollapseStates key
|
||||
// => handle case where paginating from mergeable events and we get more
|
||||
val previousCollapseStateKey = mergedEventIds.intersect(mergeItemCollapseStates.keys).firstOrNull()
|
||||
val initialCollapseState = mergeItemCollapseStates.remove(previousCollapseStateKey)
|
||||
?: true
|
||||
val isCollapsed = mergeItemCollapseStates.getOrPut(event.localId) { initialCollapseState }
|
||||
if (isCollapsed) {
|
||||
collapsedEventIds.addAll(mergedEventIds)
|
||||
} else {
|
||||
collapsedEventIds.removeAll(mergedEventIds)
|
||||
}
|
||||
val mergeId = mergedEventIds.joinToString(separator = "_") { it.toString() }
|
||||
val attributes = BasedMergedItem.Attributes(
|
||||
isCollapsed = isCollapsed,
|
||||
mergeData = mergedData,
|
||||
avatarRenderer = avatarRenderer,
|
||||
onCollapsedStateChanged = {
|
||||
mergeItemCollapseStates[event.localId] = it
|
||||
requestModelBuild()
|
||||
},
|
||||
readReceiptsCallback = callback
|
||||
)
|
||||
MergedHeaderItem_()
|
||||
.id(mergeId)
|
||||
.leftGuideline(avatarSizeProvider.leftGuideline)
|
||||
.highlighted(isCollapsed && highlighted)
|
||||
.attributes(attributes)
|
||||
.also {
|
||||
it.setOnVisibilityStateChanged(MergedTimelineEventVisibilityStateChangedListener(callback, mergedEvents))
|
||||
}
|
||||
|
||||
} else null
|
||||
}
|
||||
else if (!event.canBeMerged() || (nextEvent?.root?.getClearType() == event.root.getClearType() && !addDaySeparator)) {
|
||||
null
|
||||
} else {
|
||||
val prevSameTypeEvents = items.prevSameTypeEvents(currentPosition, 2)
|
||||
|
@ -53,14 +121,14 @@ class MergedHeaderItemFactory @Inject constructor(private val sessionHolder: Act
|
|||
} else {
|
||||
var highlighted = false
|
||||
val mergedEvents = (prevSameTypeEvents + listOf(event)).asReversed()
|
||||
val mergedData = ArrayList<MergedHeaderItem.Data>(mergedEvents.size)
|
||||
val mergedData = ArrayList<BasedMergedItem.Data>(mergedEvents.size)
|
||||
mergedEvents.forEach { mergedEvent ->
|
||||
if (!highlighted && mergedEvent.root.eventId == eventIdToHighlight) {
|
||||
highlighted = true
|
||||
}
|
||||
val senderAvatar = mergedEvent.senderAvatar
|
||||
val senderName = mergedEvent.getDisambiguatedDisplayName()
|
||||
val data = MergedHeaderItem.Data(
|
||||
val data = BasedMergedItem.Data(
|
||||
userId = mergedEvent.root.senderId ?: "",
|
||||
avatarUrl = senderAvatar,
|
||||
memberName = senderName,
|
||||
|
@ -82,7 +150,7 @@ class MergedHeaderItemFactory @Inject constructor(private val sessionHolder: Act
|
|||
collapsedEventIds.removeAll(mergedEventIds)
|
||||
}
|
||||
val mergeId = mergedEventIds.joinToString(separator = "_") { it.toString() }
|
||||
val attributes = MergedHeaderItem.Attributes(
|
||||
val attributes = BasedMergedItem.Attributes(
|
||||
isCollapsed = isCollapsed,
|
||||
mergeData = mergedData,
|
||||
avatarRenderer = avatarRenderer,
|
||||
|
|
|
@ -50,6 +50,18 @@ fun TimelineEvent.canBeMerged(): Boolean {
|
|||
return root.getClearType() == EventType.STATE_ROOM_MEMBER
|
||||
}
|
||||
|
||||
fun TimelineEvent.isRoomConfiguration(): Boolean {
|
||||
return when (root.getClearType()) {
|
||||
EventType.STATE_ROOM_GUEST_ACCESS,
|
||||
EventType.STATE_ROOM_HISTORY_VISIBILITY,
|
||||
EventType.STATE_ROOM_JOIN_RULES,
|
||||
EventType.STATE_ROOM_MEMBER,
|
||||
EventType.STATE_ROOM_NAME,
|
||||
EventType.STATE_ROOM_ENCRYPTION -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun List<TimelineEvent>.nextSameTypeEvents(index: Int, minSize: Int): List<TimelineEvent> {
|
||||
if (index >= size - 1) {
|
||||
return emptyList()
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.riotx.features.home.room.detail.timeline.item
|
||||
|
||||
import androidx.annotation.IdRes
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||
|
||||
abstract class BasedMergedItem<H : BasedMergedItem.Holder> : BaseEventItem<H>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
lateinit var attributes: Attributes
|
||||
|
||||
protected val distinctMergeData by lazy {
|
||||
attributes.mergeData.distinctBy { it.userId }
|
||||
}
|
||||
|
||||
override fun getEventIds(): List<String> {
|
||||
return if (attributes.isCollapsed) {
|
||||
attributes.mergeData.map { it.eventId }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
data class Data(
|
||||
val localId: Long,
|
||||
val eventId: String,
|
||||
val userId: String,
|
||||
val memberName: String,
|
||||
val avatarUrl: String?
|
||||
)
|
||||
|
||||
fun Data.toMatrixItem() = MatrixItem.UserItem(userId, memberName, avatarUrl)
|
||||
|
||||
data class Attributes(
|
||||
val isCollapsed: Boolean,
|
||||
val mergeData: List<Data>,
|
||||
val avatarRenderer: AvatarRenderer,
|
||||
val readReceiptsCallback: TimelineEventController.ReadReceiptsCallback? = null,
|
||||
val onCollapsedStateChanged: (Boolean) -> Unit
|
||||
)
|
||||
|
||||
abstract class Holder(@IdRes stubId: Int) : BaseEventItem.BaseHolder(stubId) {
|
||||
//val reactionsContainer by bind<ViewGroup>(R.id.reactionsContainer)
|
||||
}
|
||||
}
|
|
@ -22,22 +22,11 @@ import android.widget.ImageView
|
|||
import android.widget.TextView
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_base_noinfo)
|
||||
abstract class MergedHeaderItem : BaseEventItem<MergedHeaderItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
lateinit var attributes: Attributes
|
||||
|
||||
private val distinctMergeData by lazy {
|
||||
attributes.mergeData.distinctBy { it.userId }
|
||||
}
|
||||
abstract class MergedHeaderItem : BasedMergedItem<MergedHeaderItem.Holder>() {
|
||||
|
||||
override fun getViewType() = STUB_ID
|
||||
|
||||
|
@ -72,33 +61,7 @@ abstract class MergedHeaderItem : BaseEventItem<MergedHeaderItem.Holder>() {
|
|||
holder.readReceiptsView.isVisible = false
|
||||
}
|
||||
|
||||
override fun getEventIds(): List<String> {
|
||||
return if (attributes.isCollapsed) {
|
||||
attributes.mergeData.map { it.eventId }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
data class Data(
|
||||
val localId: Long,
|
||||
val eventId: String,
|
||||
val userId: String,
|
||||
val memberName: String,
|
||||
val avatarUrl: String?
|
||||
)
|
||||
|
||||
fun Data.toMatrixItem() = MatrixItem.UserItem(userId, memberName, avatarUrl)
|
||||
|
||||
data class Attributes(
|
||||
val isCollapsed: Boolean,
|
||||
val mergeData: List<Data>,
|
||||
val avatarRenderer: AvatarRenderer,
|
||||
val readReceiptsCallback: TimelineEventController.ReadReceiptsCallback? = null,
|
||||
val onCollapsedStateChanged: (Boolean) -> Unit
|
||||
)
|
||||
|
||||
class Holder : BaseHolder(STUB_ID) {
|
||||
class Holder : BasedMergedItem.Holder(STUB_ID) {
|
||||
val expandView by bind<TextView>(R.id.itemMergedExpandTextView)
|
||||
val summaryView by bind<TextView>(R.id.itemMergedSummaryTextView)
|
||||
val separatorView by bind<View>(R.id.itemMergedSeparatorView)
|
||||
|
|
Loading…
Reference in a new issue