mirror of
https://github.com/vector-im/riotX-android
synced 2025-10-06 00:02:48 +02:00
Compare commits
2 Commits
v1.6.46
...
feature/fg
Author | SHA1 | Date | |
---|---|---|---|
|
dc7b424324 | ||
|
5dec4797dd |
@@ -16,6 +16,7 @@
|
||||
|
||||
package im.vector.app.core.epoxy
|
||||
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
@@ -25,6 +26,14 @@ import im.vector.app.features.home.room.detail.timeline.item.ItemWithEvents
|
||||
abstract class TimelineEmptyItem : VectorEpoxyModel<TimelineEmptyItem.Holder>(), ItemWithEvents {
|
||||
|
||||
@EpoxyAttribute lateinit var eventId: String
|
||||
@EpoxyAttribute var hidden: Boolean = true
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.view.updateLayoutParams {
|
||||
this.height = if (hidden) 0 else 1
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEventIds(): List<String> {
|
||||
return listOf(eventId)
|
||||
|
@@ -66,7 +66,7 @@ class JumpToBottomViewVisibilityManager(
|
||||
}
|
||||
|
||||
private fun maybeShowJumpToBottomViewVisibility() {
|
||||
if (layoutManager.findFirstVisibleItemPosition() != 0) {
|
||||
if (layoutManager.findFirstVisibleItemPosition() > 1) {
|
||||
jumpToBottomView.show()
|
||||
} else {
|
||||
jumpToBottomView.hide()
|
||||
|
@@ -24,7 +24,6 @@ import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.Timeline
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
@@ -34,8 +33,8 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
||||
data class SendSticker(val stickerContent: MessageStickerContent) : RoomDetailAction()
|
||||
data class SendMessage(val text: CharSequence, val autoMarkdown: Boolean) : RoomDetailAction()
|
||||
data class SendMedia(val attachments: List<ContentAttachmentData>, val compressBeforeSending: Boolean) : RoomDetailAction()
|
||||
data class TimelineEventTurnsVisible(val event: TimelineEvent) : RoomDetailAction()
|
||||
data class TimelineEventTurnsInvisible(val event: TimelineEvent) : RoomDetailAction()
|
||||
data class TimelineEventTurnsVisible(val eventId: String) : RoomDetailAction()
|
||||
data class TimelineEventTurnsInvisible(val eventId: String) : RoomDetailAction()
|
||||
data class LoadMoreTimelineEvents(val direction: Timeline.Direction) : RoomDetailAction()
|
||||
data class SendReaction(val targetEventId: String, val reaction: String) : RoomDetailAction()
|
||||
data class UndoReaction(val targetEventId: String, val reaction: String, val reason: String? = "") : RoomDetailAction()
|
||||
|
@@ -1454,12 +1454,12 @@ class RoomDetailFragment @Inject constructor(
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onEventVisible(event: TimelineEvent) {
|
||||
roomDetailViewModel.handle(RoomDetailAction.TimelineEventTurnsVisible(event))
|
||||
override fun onEventVisible(eventId: String) {
|
||||
roomDetailViewModel.handle(RoomDetailAction.TimelineEventTurnsVisible(eventId))
|
||||
}
|
||||
|
||||
override fun onEventInvisible(event: TimelineEvent) {
|
||||
roomDetailViewModel.handle(RoomDetailAction.TimelineEventTurnsInvisible(event))
|
||||
override fun onEventInvisible(eventId: String) {
|
||||
roomDetailViewModel.handle(RoomDetailAction.TimelineEventTurnsInvisible(eventId))
|
||||
}
|
||||
|
||||
override fun onEncryptedMessageClicked(informationData: MessageInformationData, view: View) {
|
||||
|
@@ -1022,19 +1022,19 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||
|
||||
private fun handleEventVisible(action: RoomDetailAction.TimelineEventTurnsVisible) {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
if (action.event.root.sendState.isSent()) { // ignore pending/local events
|
||||
val event = timeline.getTimelineEventWithId(action.eventId) ?: return@launch
|
||||
if (event.root.sendState.isSent()) { // ignore pending/local events
|
||||
visibleEventsObservable.accept(action)
|
||||
}
|
||||
// We need to update this with the related m.replace also (to move read receipt)
|
||||
action.event.annotations?.editSummary?.sourceEvents?.forEach {
|
||||
event.annotations?.editSummary?.sourceEvents?.forEach {
|
||||
room.getTimeLineEvent(it)?.let { event ->
|
||||
visibleEventsObservable.accept(RoomDetailAction.TimelineEventTurnsVisible(event))
|
||||
visibleEventsObservable.accept(RoomDetailAction.TimelineEventTurnsVisible(event.eventId))
|
||||
}
|
||||
}
|
||||
|
||||
// handle chat effects here
|
||||
if (vectorPreferences.chatEffectsEnabled()) {
|
||||
chatEffectManager.checkForEffect(action.event)
|
||||
chatEffectManager.checkForEffect(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1194,7 +1194,9 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||
.buffer(1, TimeUnit.SECONDS)
|
||||
.filter { it.isNotEmpty() }
|
||||
.subscribeBy(onNext = { actions ->
|
||||
val bufferedMostRecentDisplayedEvent = actions.maxByOrNull { it.event.displayIndex }?.event ?: return@subscribeBy
|
||||
val bufferedMostRecentDisplayedEvent = actions
|
||||
.mapNotNull { timeline.getTimelineEventWithId(it.eventId) }
|
||||
.maxByOrNull { it.displayIndex } ?: return@subscribeBy
|
||||
val globalMostRecentDisplayedEvent = mostRecentDisplayedEvent
|
||||
if (trackUnreadMessages.get()) {
|
||||
if (globalMostRecentDisplayedEvent == null) {
|
||||
|
@@ -43,7 +43,6 @@ class ScrollOnNewMessageCallback(private val layoutManager: LinearLayoutManager,
|
||||
layoutManager.scrollToPosition(position)
|
||||
return
|
||||
}
|
||||
Timber.v("On inserted $count count at position: $position")
|
||||
if (layoutManager.findFirstVisibleItemPosition() != position) {
|
||||
return
|
||||
}
|
||||
@@ -51,11 +50,10 @@ class ScrollOnNewMessageCallback(private val layoutManager: LinearLayoutManager,
|
||||
val firstNewItemIds = firstNewItem.getEventIds().firstOrNull() ?: return
|
||||
val indexOfFirstNewItem = newTimelineEventIds.indexOf(firstNewItemIds)
|
||||
if (indexOfFirstNewItem != -1) {
|
||||
Timber.v("Should scroll to position: $position")
|
||||
repeat(newTimelineEventIds.size - indexOfFirstNewItem) {
|
||||
newTimelineEventIds.removeAt(indexOfFirstNewItem)
|
||||
}
|
||||
layoutManager.scrollToPosition(position)
|
||||
layoutManager.scrollToPosition(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -85,8 +85,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||
ReadReceiptsCallback,
|
||||
PreviewUrlCallback {
|
||||
fun onLoadMore(direction: Timeline.Direction)
|
||||
fun onEventInvisible(event: TimelineEvent)
|
||||
fun onEventVisible(event: TimelineEvent)
|
||||
fun onEventInvisible(eventId: String)
|
||||
fun onEventVisible(eventId: String)
|
||||
fun onRoomCreateLinkClicked(url: String)
|
||||
fun onEncryptedMessageClicked(informationData: MessageInformationData, view: View)
|
||||
fun onImageMessageClicked(messageImageContent: MessageImageInfoContent, mediaData: ImageContentRenderer.Data, view: View)
|
||||
@@ -144,7 +144,6 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||
private var unreadState: UnreadState = UnreadState.Unknown
|
||||
private var positionOfReadMarker: Int? = null
|
||||
private var eventIdToHighlight: String? = null
|
||||
private var previousModelsSize = 0
|
||||
|
||||
var callback: Callback? = null
|
||||
var timeline: Timeline? = null
|
||||
@@ -341,7 +340,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||
updateUTDStates(event, nextEvent)
|
||||
val eventModel = timelineItemFactory.create(event, nextEvent, eventIdToHighlight, callback).also {
|
||||
it.id(event.localId)
|
||||
it.setOnVisibilityStateChanged(TimelineEventVisibilityStateChangedListener(callback, event))
|
||||
it.setOnVisibilityStateChanged(TimelineEventVisibilityStateChangedListener(callback, event.eventId))
|
||||
}
|
||||
val addDaySeparator = if (hasReachedInvite && hasUTD) {
|
||||
true
|
||||
|
@@ -19,6 +19,7 @@ package im.vector.app.features.home.room.detail.timeline.helper
|
||||
import com.airbnb.epoxy.EpoxyModel
|
||||
import com.airbnb.epoxy.VisibilityState
|
||||
import im.vector.app.core.epoxy.LoadingItem_
|
||||
import im.vector.app.core.epoxy.TimelineEmptyItem
|
||||
import im.vector.app.core.epoxy.TimelineEmptyItem_
|
||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||
import im.vector.app.features.home.room.detail.UnreadState
|
||||
@@ -59,12 +60,27 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
|
||||
val showHiddenEvents = vectorPreferences.shouldShowHiddenEvents()
|
||||
var index = 0
|
||||
val firstUnreadEventId = (unreadState as? UnreadState.HasUnread)?.firstUnreadEventId
|
||||
var prevWasHidden = false
|
||||
var onlyHidden = true
|
||||
// Then iterate on models so we have the exact positions in the adapter
|
||||
modelsIterator.forEach { epoxyModel ->
|
||||
if (epoxyModel is TimelineEmptyItem && !prevWasHidden) {
|
||||
prevWasHidden = true
|
||||
modelsIterator.remove()
|
||||
val emptyItem = TimelineEmptyItem_()
|
||||
.id("not_hidden_${epoxyModel.id()}")
|
||||
.eventId(epoxyModel.eventId)
|
||||
.hidden(false)
|
||||
.setOnVisibilityStateChanged(TimelineEventVisibilityStateChangedListener(callback, epoxyModel.eventId))
|
||||
modelsIterator.add(emptyItem)
|
||||
} else if (epoxyModel !is TimelineEmptyItem) {
|
||||
onlyHidden = false
|
||||
prevWasHidden = false
|
||||
}
|
||||
if (epoxyModel is ItemWithEvents) {
|
||||
epoxyModel.getEventIds().forEach { eventId ->
|
||||
adapterPositionMapping[eventId] = index
|
||||
if (eventId == firstUnreadEventId) {
|
||||
if (eventId == firstUnreadEventId && !onlyHidden) {
|
||||
modelsIterator.addReadMarkerItem(callback)
|
||||
index++
|
||||
positionOfReadMarker.set(index)
|
||||
@@ -88,6 +104,7 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
|
||||
add(readMarker)
|
||||
// Use next as we still have some process to do before the next iterator loop
|
||||
next()
|
||||
previous()
|
||||
}
|
||||
|
||||
private fun MutableListIterator<EpoxyModel<*>>.removeCallItemIfNeeded(
|
||||
@@ -105,6 +122,7 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
|
||||
val emptyItem = TimelineEmptyItem_()
|
||||
.id(epoxyModel.id())
|
||||
.eventId(epoxyModel.attributes.informationData.eventId)
|
||||
.hidden(false)
|
||||
add(emptyItem)
|
||||
}
|
||||
callIds.add(callId)
|
||||
|
@@ -32,14 +32,14 @@ class ReadMarkerVisibilityStateChangedListener(private val callback: TimelineEve
|
||||
}
|
||||
|
||||
class TimelineEventVisibilityStateChangedListener(private val callback: TimelineEventController.Callback?,
|
||||
private val event: TimelineEvent)
|
||||
private val eventId: String)
|
||||
: VectorEpoxyModel.OnVisibilityStateChangedListener {
|
||||
|
||||
override fun onVisibilityStateChanged(visibilityState: Int) {
|
||||
if (visibilityState == VisibilityState.VISIBLE) {
|
||||
callback?.onEventVisible(event)
|
||||
callback?.onEventVisible(eventId)
|
||||
} else if (visibilityState == VisibilityState.INVISIBLE) {
|
||||
callback?.onEventInvisible(event)
|
||||
callback?.onEventInvisible(eventId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,9 +50,9 @@ class MergedTimelineEventVisibilityStateChangedListener(private val callback: Ti
|
||||
|
||||
override fun onVisibilityStateChanged(visibilityState: Int) {
|
||||
if (visibilityState == VisibilityState.VISIBLE) {
|
||||
events.forEach { callback?.onEventVisible(it) }
|
||||
events.forEach { callback?.onEventVisible(it.eventId) }
|
||||
} else if (visibilityState == VisibilityState.INVISIBLE) {
|
||||
events.forEach { callback?.onEventInvisible(it) }
|
||||
events.forEach { callback?.onEventInvisible(it.eventId) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.app.features.home.room.detail.timeline.item
|
||||
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_blank_stub)
|
||||
abstract class BlankItem : VectorEpoxyModel<BlankItem.BlankHolder>() {
|
||||
class BlankHolder : VectorEpoxyHolder()
|
||||
}
|
@@ -3,7 +3,6 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:padding="8dp">
|
||||
|
||||
<View
|
||||
@@ -12,16 +11,15 @@
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?riotx_header_panel_background" />
|
||||
android:background="?riotx_list_bottom_sheet_divider_color" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemDayTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:background="?riotx_background"
|
||||
android:paddingStart="32dp"
|
||||
android:paddingEnd="32dp"
|
||||
android:background="?android:attr/windowBackground"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:textColor="?riotx_header_panel_text_secondary"
|
||||
android:textSize="15sp"
|
||||
tools:text="@tools:sample/date/day_of_week" />
|
||||
|
@@ -2,7 +2,6 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:padding="8dp">
|
||||
|
||||
<View
|
||||
@@ -17,10 +16,9 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:background="?riotx_background"
|
||||
android:background="?android:attr/windowBackground"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:text="@string/timeline_unread_messages"
|
||||
android:textColor="@color/notification_accent_color"
|
||||
android:textSize="15sp" />
|
||||
|
Reference in New Issue
Block a user