Timeline: fix membership filtering

This commit is contained in:
ganfra 2021-03-30 19:59:25 +02:00
parent 13cb81b92f
commit 5d19cfff13
7 changed files with 53 additions and 25 deletions

View file

@ -41,7 +41,14 @@ class UserPreferencesProvider @Inject constructor(private val vectorPreferences:
vectorPreferences.neverShowLongClickOnRoomHelpAgain() vectorPreferences.neverShowLongClickOnRoomHelpAgain()
} }
fun shouldShowRoomMemberStateEvents(): Boolean { fun shouldShowJoinLeaves(): Boolean {
return vectorPreferences.showRoomMemberStateEvents() return vectorPreferences.showJoinLeaveMessages()
} }
fun shouldShowAvatarDisplayNameChanges(): Boolean {
return vectorPreferences.showAvatarDisplayNameChangeMessages()
}
} }

View file

@ -318,7 +318,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
cacheItemData.eventModel cacheItemData.eventModel
} }
listOf( listOf(
cacheItemData?.readReceiptsItem?.takeIf { cacheItemData.mergedHeaderModel == null }, cacheItemData?.readReceiptsItem?.takeUnless { mergedHeaderItemFactory.isCollapsed(cacheItemData.localId) },
eventModel, eventModel,
cacheItemData?.mergedHeaderModel, cacheItemData?.mergedHeaderModel,
cacheItemData?.formattedDayModel?.takeIf { eventModel != null || cacheItemData.mergedHeaderModel != null } cacheItemData?.formattedDayModel?.takeIf { eventModel != null || cacheItemData.mergedHeaderModel != null }
@ -428,6 +428,9 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
private fun getReadReceiptsByShownEvent(): Map<String, List<ReadReceipt>> { private fun getReadReceiptsByShownEvent(): Map<String, List<ReadReceipt>> {
val receiptsByEvent = HashMap<String, MutableList<ReadReceipt>>() val receiptsByEvent = HashMap<String, MutableList<ReadReceipt>>()
if(!userPreferencesProvider.shouldShowReadReceipts()){
return receiptsByEvent
}
var lastShownEventId: String? = null var lastShownEventId: String? = null
val itr = currentSnapshot.listIterator(currentSnapshot.size) val itr = currentSnapshot.listIterator(currentSnapshot.size)
while (itr.hasPrevious()) { while (itr.hasPrevious()) {

View file

@ -86,12 +86,11 @@ private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper) {
eventIdToHighlight: String?, eventIdToHighlight: String?,
requestModelBuild: () -> Unit, requestModelBuild: () -> Unit,
callback: TimelineEventController.Callback?): MergedMembershipEventsItem_? { callback: TimelineEventController.Callback?): MergedMembershipEventsItem_? {
val prevSameTypeEvents = timelineEventVisibilityHelper.prevSameTypeEvents(items, currentPosition, 2, eventIdToHighlight) val mergedEvents = timelineEventVisibilityHelper.prevSameTypeEvents(items, currentPosition, 2, eventIdToHighlight)
return if (prevSameTypeEvents.isEmpty()) { return if (mergedEvents.isEmpty()) {
null null
} else { } else {
var highlighted = false var highlighted = false
val mergedEvents = (prevSameTypeEvents + listOf(event)).asReversed()
val mergedData = ArrayList<BasedMergedItem.Data>(mergedEvents.size) val mergedData = ArrayList<BasedMergedItem.Data>(mergedEvents.size)
mergedEvents.forEach { mergedEvent -> mergedEvents.forEach { mergedEvent ->
if (!highlighted && mergedEvent.root.eventId == eventIdToHighlight) { if (!highlighted && mergedEvent.root.eventId == eventIdToHighlight) {

View file

@ -72,7 +72,7 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
} }
epoxyModel.getEventIds().forEach { eventId -> epoxyModel.getEventIds().forEach { eventId ->
adapterPositionMapping[eventId] = index adapterPositionMapping[eventId] = index
if (eventId == firstUnreadEventId && atLeastOneVisibleItemsBeforeReadMarker && epoxyModel.canAppendReadMarker()) { if (epoxyModel.canAppendReadMarker() && eventId == firstUnreadEventId && atLeastOneVisibleItemsBeforeReadMarker) {
modelsIterator.addReadMarkerItem(callback) modelsIterator.addReadMarkerItem(callback)
index++ index++
positionOfReadMarker.set(index) positionOfReadMarker.set(index)

View file

@ -29,12 +29,21 @@ import javax.inject.Inject
class TimelineEventVisibilityHelper @Inject constructor(private val userPreferencesProvider: UserPreferencesProvider) { class TimelineEventVisibilityHelper @Inject constructor(private val userPreferencesProvider: UserPreferencesProvider) {
/**
* @param timelineEvents the events to search in
* @param index the index to start computing (inclusive)
* @param minSize the minimum number of same type events to have sequentially, otherwise will return an empty list
* @param eventIdToHighlight used to compute visibility
*
* @return a list of timeline events which have sequentially the same type following the next direction.
*/
fun nextSameTypeEvents(timelineEvents: List<TimelineEvent>, index: Int, minSize: Int, eventIdToHighlight: String?): List<TimelineEvent> { fun nextSameTypeEvents(timelineEvents: List<TimelineEvent>, index: Int, minSize: Int, eventIdToHighlight: String?): List<TimelineEvent> {
if (index >= timelineEvents.size - 1) { if (index >= timelineEvents.size - 1) {
return emptyList() return emptyList()
} }
val timelineEvent = timelineEvents[index] val timelineEvent = timelineEvents[index]
val nextSubList = timelineEvents.subList(index + 1, timelineEvents.size) val nextSubList = timelineEvents.subList(index, timelineEvents.size)
val indexOfNextDay = nextSubList.indexOfFirst { val indexOfNextDay = nextSubList.indexOfFirst {
val date = it.root.localDateTime() val date = it.root.localDateTime()
val nextDate = timelineEvent.root.localDateTime() val nextDate = timelineEvent.root.localDateTime()
@ -58,6 +67,14 @@ class TimelineEventVisibilityHelper @Inject constructor(private val userPreferen
return filteredSameTypeEvents return filteredSameTypeEvents
} }
/**
* @param timelineEvents the events to search in
* @param index the index to start computing (inclusive)
* @param minSize the minimum number of same type events to have sequentially, otherwise will return an empty list
* @param eventIdToHighlight used to compute visibility
*
* @return a list of timeline events which have sequentially the same type following the prev direction.
*/
fun prevSameTypeEvents(timelineEvents: List<TimelineEvent>, index: Int, minSize: Int, eventIdToHighlight: String?): List<TimelineEvent> { fun prevSameTypeEvents(timelineEvents: List<TimelineEvent>, index: Int, minSize: Int, eventIdToHighlight: String?): List<TimelineEvent> {
val prevSub = timelineEvents.subList(0, index + 1) val prevSub = timelineEvents.subList(0, index + 1)
return prevSub return prevSub
@ -65,9 +82,13 @@ class TimelineEventVisibilityHelper @Inject constructor(private val userPreferen
.let { .let {
nextSameTypeEvents(it, 0, minSize, eventIdToHighlight) nextSameTypeEvents(it, 0, minSize, eventIdToHighlight)
} }
.reversed()
} }
/**
* @param timelineEvent the event to check for visibility
* @param highlightedEventId can be checked to force visibility to true
* @return true if the event should be shown in the timeline.
*/
fun shouldShowEvent(timelineEvent: TimelineEvent, highlightedEventId: String?): Boolean { fun shouldShowEvent(timelineEvent: TimelineEvent, highlightedEventId: String?): Boolean {
// If show hidden events is true we should always display something // If show hidden events is true we should always display something
if (userPreferencesProvider.shouldShowHiddenEvents()) { if (userPreferencesProvider.shouldShowHiddenEvents()) {
@ -97,7 +118,8 @@ class TimelineEventVisibilityHelper @Inject constructor(private val userPreferen
} }
if (root.getClearType() == EventType.STATE_ROOM_MEMBER) { if (root.getClearType() == EventType.STATE_ROOM_MEMBER) {
val diff = computeMembershipDiff() val diff = computeMembershipDiff()
if ((diff.isJoin || diff.isPart) && !userPreferencesProvider.shouldShowRoomMemberStateEvents()) return true if ((diff.isJoin || diff.isPart) && !userPreferencesProvider.shouldShowJoinLeaves()) return true
if ((diff.isAvatarChange || diff.isDisplaynameChange) && !userPreferencesProvider.shouldShowAvatarDisplayNameChanges()) return true
} }
return false return false
} }
@ -110,9 +132,9 @@ class TimelineEventVisibilityHelper @Inject constructor(private val userPreferen
val isJoin = isMembershipChanged && content?.membership == Membership.JOIN val isJoin = isMembershipChanged && content?.membership == Membership.JOIN
val isPart = isMembershipChanged && content?.membership == Membership.LEAVE && root.stateKey == root.senderId val isPart = isMembershipChanged && content?.membership == Membership.LEAVE && root.stateKey == root.senderId
val isJoinToJoin = !isMembershipChanged && content?.membership == Membership.JOIN val isProfileChanged = !isMembershipChanged && content?.membership == Membership.JOIN
val isDisplaynameChange = isJoinToJoin && content?.displayName != prevContent?.displayName; val isDisplaynameChange = isProfileChanged && content?.displayName != prevContent?.displayName;
val isAvatarChange = isJoinToJoin && content?.avatarUrl !== prevContent?.avatarUrl val isAvatarChange = isProfileChanged && content?.avatarUrl !== prevContent?.avatarUrl
return MembershipDiff( return MembershipDiff(
isJoin = isJoin, isJoin = isJoin,

View file

@ -357,15 +357,6 @@ class VectorPreferences @Inject constructor(private val context: Context) {
return defaultPrefs.getBoolean(SETTINGS_12_24_TIMESTAMPS_KEY, false) return defaultPrefs.getBoolean(SETTINGS_12_24_TIMESTAMPS_KEY, false)
} }
/**
* Tells if all room member state events should be shown in the messages list.
*
* @return true all room member state events should be shown in the messages list.
*/
fun showRoomMemberStateEvents(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY, true)
}
/** /**
* Tells if the join and leave membership events should be shown in the messages list. * Tells if the join and leave membership events should be shown in the messages list.
* *

View file

@ -88,9 +88,15 @@
<im.vector.app.core.preference.VectorSwitchPreference <im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="true" android:defaultValue="true"
android:key="SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY" android:key="SETTINGS_SHOW_JOIN_LEAVE_MESSAGES_KEY"
android:summary="@string/settings_show_room_member_state_events_summary" android:summary="@string/settings_show_join_leave_messages_summary"
android:title="@string/settings_show_room_member_state_events" /> android:title="@string/settings_show_join_leave_messages" />
<im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="true"
android:key="SETTINGS_SHOW_AVATAR_DISPLAY_NAME_CHANGES_MESSAGES_KEY"
android:summary="@string/settings_show_avatar_display_name_changes_messages_summary"
android:title="@string/settings_show_avatar_display_name_changes_messages" />
<im.vector.app.core.preference.VectorSwitchPreference <im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="true" android:defaultValue="true"