ReadMarker: extract from ViewModel the jump to read marker visibility logic as it's easier to deal with.
This commit is contained in:
parent
05d09bf950
commit
c6d01fbcf4
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
* 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.riotx.features.home.room.detail
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import im.vector.riotx.core.di.ScreenScope
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ScreenScope
|
||||||
|
class ReadMarkerHelper @Inject constructor() {
|
||||||
|
|
||||||
|
lateinit var timelineEventController: TimelineEventController
|
||||||
|
lateinit var layoutManager: LinearLayoutManager
|
||||||
|
var callback: Callback? = null
|
||||||
|
|
||||||
|
private var state: RoomDetailViewState? = null
|
||||||
|
|
||||||
|
fun updateState(state: RoomDetailViewState) {
|
||||||
|
this.state = state
|
||||||
|
checkJumpToReadMarkerVisibility()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onTimelineScrolled() {
|
||||||
|
checkJumpToReadMarkerVisibility()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkJumpToReadMarkerVisibility() {
|
||||||
|
val nonNullState = this.state ?: return
|
||||||
|
val lastVisibleItem = layoutManager.findLastVisibleItemPosition()
|
||||||
|
val readMarkerId = nonNullState.asyncRoomSummary()?.readMarkerId
|
||||||
|
if (readMarkerId == null) {
|
||||||
|
callback?.onVisibilityUpdated(false, null)
|
||||||
|
}
|
||||||
|
val positionOfReadMarker = timelineEventController.searchPositionOfEvent(readMarkerId)
|
||||||
|
Timber.v("Position of readMarker: $positionOfReadMarker")
|
||||||
|
Timber.v("Position of lastVisibleItem: $lastVisibleItem")
|
||||||
|
if (positionOfReadMarker == null) {
|
||||||
|
if (nonNullState.timeline?.isLive == true && lastVisibleItem > 0) {
|
||||||
|
callback?.onVisibilityUpdated(true, readMarkerId)
|
||||||
|
} else {
|
||||||
|
callback?.onVisibilityUpdated(false, readMarkerId)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (positionOfReadMarker > lastVisibleItem) {
|
||||||
|
callback?.onVisibilityUpdated(true, readMarkerId)
|
||||||
|
} else {
|
||||||
|
callback?.onVisibilityUpdated(false, readMarkerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onVisibilityUpdated(show: Boolean, readMarkerId: String?)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -227,6 +227,7 @@ class RoomDetailFragment :
|
|||||||
@Inject lateinit var errorFormatter: ErrorFormatter
|
@Inject lateinit var errorFormatter: ErrorFormatter
|
||||||
@Inject lateinit var eventHtmlRenderer: EventHtmlRenderer
|
@Inject lateinit var eventHtmlRenderer: EventHtmlRenderer
|
||||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||||
|
@Inject lateinit var readMarkerHelper: ReadMarkerHelper
|
||||||
|
|
||||||
private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
|
private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
|
||||||
private lateinit var scrollOnHighlightedEventCallback: ScrollOnHighlightedEventCallback
|
private lateinit var scrollOnHighlightedEventCallback: ScrollOnHighlightedEventCallback
|
||||||
@ -398,22 +399,22 @@ class RoomDetailFragment :
|
|||||||
if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) {
|
if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) {
|
||||||
val parser = Parser.builder().build()
|
val parser = Parser.builder().build()
|
||||||
val document = parser.parse(messageContent.formattedBody
|
val document = parser.parse(messageContent.formattedBody
|
||||||
?: messageContent.body)
|
?: messageContent.body)
|
||||||
formattedBody = eventHtmlRenderer.render(document)
|
formattedBody = eventHtmlRenderer.render(document)
|
||||||
}
|
}
|
||||||
composerLayout.composerRelatedMessageContent.text = formattedBody
|
composerLayout.composerRelatedMessageContent.text = formattedBody
|
||||||
?: nonFormattedBody
|
?: nonFormattedBody
|
||||||
|
|
||||||
updateComposerText(defaultContent)
|
updateComposerText(defaultContent)
|
||||||
|
|
||||||
composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), iconRes))
|
composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), iconRes))
|
||||||
|
|
||||||
avatarRenderer.render(event.senderAvatar, event.root.senderId
|
avatarRenderer.render(event.senderAvatar, event.root.senderId
|
||||||
?: "", event.senderName, composerLayout.composerRelatedMessageAvatar)
|
?: "", event.senderName, composerLayout.composerRelatedMessageAvatar)
|
||||||
avatarRenderer.render(event.senderAvatar,
|
avatarRenderer.render(event.senderAvatar,
|
||||||
event.root.senderId ?: "",
|
event.root.senderId ?: "",
|
||||||
event.senderName,
|
event.senderName,
|
||||||
composerLayout.composerRelatedMessageAvatar)
|
composerLayout.composerRelatedMessageAvatar)
|
||||||
composerLayout.expand {
|
composerLayout.expand {
|
||||||
//need to do it here also when not using quick reply
|
//need to do it here also when not using quick reply
|
||||||
focusComposerAndShowKeyboard()
|
focusComposerAndShowKeyboard()
|
||||||
@ -451,9 +452,9 @@ class RoomDetailFragment :
|
|||||||
REQUEST_FILES_REQUEST_CODE, TAKE_IMAGE_REQUEST_CODE -> handleMediaIntent(data)
|
REQUEST_FILES_REQUEST_CODE, TAKE_IMAGE_REQUEST_CODE -> handleMediaIntent(data)
|
||||||
REACTION_SELECT_REQUEST_CODE -> {
|
REACTION_SELECT_REQUEST_CODE -> {
|
||||||
val eventId = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_EVENT_ID)
|
val eventId = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_EVENT_ID)
|
||||||
?: return
|
?: return
|
||||||
val reaction = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_REACTION_RESULT)
|
val reaction = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_REACTION_RESULT)
|
||||||
?: return
|
?: return
|
||||||
//TODO check if already reacted with that?
|
//TODO check if already reacted with that?
|
||||||
roomDetailViewModel.process(RoomDetailActions.SendReaction(reaction, eventId))
|
roomDetailViewModel.process(RoomDetailActions.SendReaction(reaction, eventId))
|
||||||
}
|
}
|
||||||
@ -479,6 +480,13 @@ class RoomDetailFragment :
|
|||||||
it.dispatchTo(scrollOnNewMessageCallback)
|
it.dispatchTo(scrollOnNewMessageCallback)
|
||||||
it.dispatchTo(scrollOnHighlightedEventCallback)
|
it.dispatchTo(scrollOnHighlightedEventCallback)
|
||||||
}
|
}
|
||||||
|
readMarkerHelper.timelineEventController = timelineEventController
|
||||||
|
readMarkerHelper.layoutManager = layoutManager
|
||||||
|
readMarkerHelper.callback = object : ReadMarkerHelper.Callback {
|
||||||
|
override fun onVisibilityUpdated(show: Boolean, readMarkerId: String?) {
|
||||||
|
jumpToReadMarkerView.render(show, readMarkerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
recyclerView.setController(timelineEventController)
|
recyclerView.setController(timelineEventController)
|
||||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
|
||||||
@ -486,6 +494,7 @@ class RoomDetailFragment :
|
|||||||
if (recyclerView.scrollState == RecyclerView.SCROLL_STATE_IDLE) {
|
if (recyclerView.scrollState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||||
updateJumpToBottomViewVisibility()
|
updateJumpToBottomViewVisibility()
|
||||||
}
|
}
|
||||||
|
readMarkerHelper.onTimelineScrolled()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
@ -504,26 +513,26 @@ class RoomDetailFragment :
|
|||||||
|
|
||||||
if (vectorPreferences.swipeToReplyIsEnabled()) {
|
if (vectorPreferences.swipeToReplyIsEnabled()) {
|
||||||
val swipeCallback = RoomMessageTouchHelperCallback(requireContext(),
|
val swipeCallback = RoomMessageTouchHelperCallback(requireContext(),
|
||||||
R.drawable.ic_reply,
|
R.drawable.ic_reply,
|
||||||
object : RoomMessageTouchHelperCallback.QuickReplayHandler {
|
object : RoomMessageTouchHelperCallback.QuickReplayHandler {
|
||||||
override fun performQuickReplyOnHolder(model: EpoxyModel<*>) {
|
override fun performQuickReplyOnHolder(model: EpoxyModel<*>) {
|
||||||
(model as? AbsMessageItem)?.attributes?.informationData?.let {
|
(model as? AbsMessageItem)?.attributes?.informationData?.let {
|
||||||
val eventId = it.eventId
|
val eventId = it.eventId
|
||||||
roomDetailViewModel.process(RoomDetailActions.EnterReplyMode(eventId, composerLayout.composerEditText.text.toString()))
|
roomDetailViewModel.process(RoomDetailActions.EnterReplyMode(eventId, composerLayout.composerEditText.text.toString()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun canSwipeModel(model: EpoxyModel<*>): Boolean {
|
override fun canSwipeModel(model: EpoxyModel<*>): Boolean {
|
||||||
return when (model) {
|
return when (model) {
|
||||||
is MessageFileItem,
|
is MessageFileItem,
|
||||||
is MessageImageVideoItem,
|
is MessageImageVideoItem,
|
||||||
is MessageTextItem -> {
|
is MessageTextItem -> {
|
||||||
return (model as AbsMessageItem).attributes.informationData.sendState == SendState.SYNCED
|
return (model as AbsMessageItem).attributes.informationData.sendState == SendState.SYNCED
|
||||||
}
|
}
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
val touchHelper = ItemTouchHelper(swipeCallback)
|
val touchHelper = ItemTouchHelper(swipeCallback)
|
||||||
touchHelper.attachToRecyclerView(recyclerView)
|
touchHelper.attachToRecyclerView(recyclerView)
|
||||||
}
|
}
|
||||||
@ -698,6 +707,7 @@ class RoomDetailFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun renderState(state: RoomDetailViewState) {
|
private fun renderState(state: RoomDetailViewState) {
|
||||||
|
readMarkerHelper.updateState(state)
|
||||||
renderRoomSummary(state)
|
renderRoomSummary(state)
|
||||||
val summary = state.asyncRoomSummary()
|
val summary = state.asyncRoomSummary()
|
||||||
val inviter = state.asyncInviter()
|
val inviter = state.asyncInviter()
|
||||||
@ -726,7 +736,6 @@ class RoomDetailFragment :
|
|||||||
composerLayout.visibility = View.GONE
|
composerLayout.visibility = View.GONE
|
||||||
notificationAreaView.render(NotificationAreaView.State.Tombstone(state.tombstoneEvent))
|
notificationAreaView.render(NotificationAreaView.State.Tombstone(state.tombstoneEvent))
|
||||||
}
|
}
|
||||||
jumpToReadMarkerView.render(state.showJumpToReadMarker, summary?.readMarkerId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderRoomSummary(state: RoomDetailViewState) {
|
private fun renderRoomSummary(state: RoomDetailViewState) {
|
||||||
@ -1151,7 +1160,7 @@ class RoomDetailFragment :
|
|||||||
roomDetailViewModel.process(RoomDetailActions.RejectInvite)
|
roomDetailViewModel.process(RoomDetailActions.RejectInvite)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JumpToReadMarkerView.Callback
|
// JumpToReadMarkerView.Callback
|
||||||
|
|
||||||
override fun onJumpToReadMarkerClicked(readMarkerId: String) {
|
override fun onJumpToReadMarkerClicked(readMarkerId: String) {
|
||||||
roomDetailViewModel.process(RoomDetailActions.NavigateToEvent(readMarkerId, false))
|
roomDetailViewModel.process(RoomDetailActions.NavigateToEvent(readMarkerId, false))
|
||||||
|
@ -119,7 +119,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||||||
observeRoomSummary()
|
observeRoomSummary()
|
||||||
observeEventDisplayedActions()
|
observeEventDisplayedActions()
|
||||||
observeSummaryState()
|
observeSummaryState()
|
||||||
observeJumpToReadMarkerViewVisibility()
|
|
||||||
observeReadMarkerVisibility()
|
observeReadMarkerVisibility()
|
||||||
observeDrafts()
|
observeDrafts()
|
||||||
room.rx().loadRoomMembersIfNeeded().subscribeLogError().disposeOnClear()
|
room.rx().loadRoomMembersIfNeeded().subscribeLogError().disposeOnClear()
|
||||||
@ -185,23 +184,23 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||||||
copy(
|
copy(
|
||||||
// Create a sendMode from a draft and retrieve the TimelineEvent
|
// Create a sendMode from a draft and retrieve the TimelineEvent
|
||||||
sendMode = when (draft) {
|
sendMode = when (draft) {
|
||||||
is UserDraft.REGULAR -> SendMode.REGULAR(draft.text)
|
is UserDraft.REGULAR -> SendMode.REGULAR(draft.text)
|
||||||
is UserDraft.QUOTE -> {
|
is UserDraft.QUOTE -> {
|
||||||
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
|
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
|
||||||
SendMode.QUOTE(timelineEvent, draft.text)
|
SendMode.QUOTE(timelineEvent, draft.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is UserDraft.REPLY -> {
|
is UserDraft.REPLY -> {
|
||||||
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
|
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
|
||||||
SendMode.REPLY(timelineEvent, draft.text)
|
SendMode.REPLY(timelineEvent, draft.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is UserDraft.EDIT -> {
|
is UserDraft.EDIT -> {
|
||||||
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
|
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
|
||||||
SendMode.EDIT(timelineEvent, draft.text)
|
SendMode.EDIT(timelineEvent, draft.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: SendMode.REGULAR("")
|
} ?: SendMode.REGULAR("")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,7 +209,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||||||
|
|
||||||
private fun handleTombstoneEvent(action: RoomDetailActions.HandleTombstoneEvent) {
|
private fun handleTombstoneEvent(action: RoomDetailActions.HandleTombstoneEvent) {
|
||||||
val tombstoneContent = action.event.getClearContent().toModel<RoomTombstoneContent>()
|
val tombstoneContent = action.event.getClearContent().toModel<RoomTombstoneContent>()
|
||||||
?: return
|
?: return
|
||||||
|
|
||||||
val roomId = tombstoneContent.replacementRoom ?: ""
|
val roomId = tombstoneContent.replacementRoom ?: ""
|
||||||
val isRoomJoined = session.getRoom(roomId)?.roomSummary()?.membership == Membership.JOIN
|
val isRoomJoined = session.getRoom(roomId)?.roomSummary()?.membership == Membership.JOIN
|
||||||
@ -345,7 +344,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||||||
is SendMode.EDIT -> {
|
is SendMode.EDIT -> {
|
||||||
//is original event a reply?
|
//is original event a reply?
|
||||||
val inReplyTo = state.sendMode.timelineEvent.root.getClearContent().toModel<MessageContent>()?.relatesTo?.inReplyTo?.eventId
|
val inReplyTo = state.sendMode.timelineEvent.root.getClearContent().toModel<MessageContent>()?.relatesTo?.inReplyTo?.eventId
|
||||||
?: state.sendMode.timelineEvent.root.content.toModel<EncryptedEventContent>()?.relatesTo?.inReplyTo?.eventId
|
?: state.sendMode.timelineEvent.root.content.toModel<EncryptedEventContent>()?.relatesTo?.inReplyTo?.eventId
|
||||||
if (inReplyTo != null) {
|
if (inReplyTo != null) {
|
||||||
//TODO check if same content?
|
//TODO check if same content?
|
||||||
room.getTimeLineEvent(inReplyTo)?.let {
|
room.getTimeLineEvent(inReplyTo)?.let {
|
||||||
@ -354,13 +353,13 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||||||
} else {
|
} else {
|
||||||
val messageContent: MessageContent? =
|
val messageContent: MessageContent? =
|
||||||
state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel()
|
state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel()
|
||||||
?: state.sendMode.timelineEvent.root.getClearContent().toModel()
|
?: state.sendMode.timelineEvent.root.getClearContent().toModel()
|
||||||
val existingBody = messageContent?.body ?: ""
|
val existingBody = messageContent?.body ?: ""
|
||||||
if (existingBody != action.text) {
|
if (existingBody != action.text) {
|
||||||
room.editTextMessage(state.sendMode.timelineEvent.root.eventId ?: "",
|
room.editTextMessage(state.sendMode.timelineEvent.root.eventId ?: "",
|
||||||
messageContent?.type ?: MessageType.MSGTYPE_TEXT,
|
messageContent?.type ?: MessageType.MSGTYPE_TEXT,
|
||||||
action.text,
|
action.text,
|
||||||
action.autoMarkdown)
|
action.autoMarkdown)
|
||||||
} else {
|
} else {
|
||||||
Timber.w("Same message content, do not send edition")
|
Timber.w("Same message content, do not send edition")
|
||||||
}
|
}
|
||||||
@ -371,7 +370,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||||||
is SendMode.QUOTE -> {
|
is SendMode.QUOTE -> {
|
||||||
val messageContent: MessageContent? =
|
val messageContent: MessageContent? =
|
||||||
state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel()
|
state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel()
|
||||||
?: state.sendMode.timelineEvent.root.getClearContent().toModel()
|
?: state.sendMode.timelineEvent.root.getClearContent().toModel()
|
||||||
val textMsg = messageContent?.body
|
val textMsg = messageContent?.body
|
||||||
|
|
||||||
val finalText = legacyRiotQuoteText(textMsg, action.text)
|
val finalText = legacyRiotQuoteText(textMsg, action.text)
|
||||||
@ -702,45 +701,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeJumpToReadMarkerViewVisibility() {
|
|
||||||
Observable.combineLatest(
|
|
||||||
room.rx().liveRoomSummary()
|
|
||||||
.map {
|
|
||||||
val readMarkerId = it.readMarkerId
|
|
||||||
if (readMarkerId == null) {
|
|
||||||
Option.empty()
|
|
||||||
} else {
|
|
||||||
val readMarkerIndex = room.getTimeLineEvent(readMarkerId)?.displayIndex
|
|
||||||
?: Int.MIN_VALUE
|
|
||||||
Option.just(readMarkerIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.distinctUntilChanged(),
|
|
||||||
visibleEventsObservable.distinctUntilChanged(),
|
|
||||||
isEventVisibleObservable { it.hasReadMarker }.startWith(false).takeUntil { it },
|
|
||||||
Function3<Option<Int>, RoomDetailActions.TimelineEventTurnsVisible, Boolean, Boolean> { readMarkerIndex, currentVisibleEvent, isReadMarkerViewVisible ->
|
|
||||||
if (readMarkerIndex.isEmpty() || isReadMarkerViewVisible) {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
val currentVisibleEventPosition = currentVisibleEvent.event.displayIndex
|
|
||||||
readMarkerIndex.getOrElse { Int.MIN_VALUE } < currentVisibleEventPosition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.distinctUntilChanged()
|
|
||||||
.subscribe {
|
|
||||||
setState { copy(showJumpToReadMarker = it) }
|
|
||||||
}
|
|
||||||
.disposeOnClear()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isEventVisibleObservable(filterEvent: (TimelineEvent) -> Boolean): Observable<Boolean> {
|
|
||||||
return Observable.merge(
|
|
||||||
visibleEventsObservable.filter { filterEvent(it.event) }.map { true },
|
|
||||||
invisibleEventsObservable.filter { filterEvent(it.event) }.map { false }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun observeRoomSummary() {
|
private fun observeRoomSummary() {
|
||||||
room.rx().liveRoomSummary()
|
room.rx().liveRoomSummary()
|
||||||
.execute { async ->
|
.execute { async ->
|
||||||
|
@ -52,7 +52,6 @@ data class RoomDetailViewState(
|
|||||||
val tombstoneEvent: Event? = null,
|
val tombstoneEvent: Event? = null,
|
||||||
val tombstoneEventHandling: Async<String> = Uninitialized,
|
val tombstoneEventHandling: Async<String> = Uninitialized,
|
||||||
val syncState: SyncState = SyncState.IDLE,
|
val syncState: SyncState = SyncState.IDLE,
|
||||||
val showJumpToReadMarker: Boolean = false,
|
|
||||||
val highlightedEventId: String? = null,
|
val highlightedEventId: String? = null,
|
||||||
val hideReadMarker: Boolean = false
|
val hideReadMarker: Boolean = false
|
||||||
) : MvRxState {
|
) : MvRxState {
|
||||||
|
@ -56,7 +56,6 @@ class ScrollOnHighlightedEventCallback(private val layoutManager: LinearLayoutMa
|
|||||||
// Do not scroll it item is already visible
|
// Do not scroll it item is already visible
|
||||||
if (positionToScroll !in firstVisibleItem..lastVisibleItem) {
|
if (positionToScroll !in firstVisibleItem..lastVisibleItem) {
|
||||||
Timber.v("Scroll to $positionToScroll")
|
Timber.v("Scroll to $positionToScroll")
|
||||||
// Note: Offset will be from the bottom, since the layoutManager is reversed
|
|
||||||
layoutManager.scrollToPosition(positionToScroll)
|
layoutManager.scrollToPosition(positionToScroll)
|
||||||
}
|
}
|
||||||
scheduledEventId.set(null)
|
scheduledEventId.set(null)
|
||||||
|
@ -158,7 +158,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
|||||||
synchronized(modelCache) {
|
synchronized(modelCache) {
|
||||||
for (i in 0 until modelCache.size) {
|
for (i in 0 until modelCache.size) {
|
||||||
if (modelCache[i]?.eventId == viewState.highlightedEventId
|
if (modelCache[i]?.eventId == viewState.highlightedEventId
|
||||||
|| modelCache[i]?.eventId == eventIdToHighlight) {
|
|| modelCache[i]?.eventId == eventIdToHighlight) {
|
||||||
modelCache[i] = null
|
modelCache[i] = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,8 +229,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
|||||||
// Should be build if not cached or if cached but contains mergedHeader or formattedDay
|
// Should be build if not cached or if cached but contains mergedHeader or formattedDay
|
||||||
// We then are sure we always have items up to date.
|
// We then are sure we always have items up to date.
|
||||||
if (modelCache[position] == null
|
if (modelCache[position] == null
|
||||||
|| modelCache[position]?.mergedHeaderModel != null
|
|| modelCache[position]?.mergedHeaderModel != null
|
||||||
|| modelCache[position]?.formattedDayModel != null) {
|
|| modelCache[position]?.formattedDayModel != null) {
|
||||||
modelCache[position] = buildItemModels(position, currentSnapshot)
|
modelCache[position] = buildItemModels(position, currentSnapshot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user