diff --git a/vector/src/main/java/im/vector/riotx/core/ui/views/ReadMarkerView.kt b/vector/src/main/java/im/vector/riotx/core/ui/views/ReadMarkerView.kt index 55665ca27f..19dad458a5 100644 --- a/vector/src/main/java/im/vector/riotx/core/ui/views/ReadMarkerView.kt +++ b/vector/src/main/java/im/vector/riotx/core/ui/views/ReadMarkerView.kt @@ -37,7 +37,7 @@ class ReadMarkerView @JvmOverloads constructor( ) : View(context, attrs, defStyleAttr) { interface Callback { - fun onReadMarkerLongBound() + fun onReadMarkerLongBound(isDisplayed: Boolean) } private var eventId: String? = null @@ -57,7 +57,7 @@ class ReadMarkerView @JvmOverloads constructor( if (hasReadMarker) { callbackDispatcherJob = GlobalScope.launch(Dispatchers.Main) { delay(DELAY_IN_MS) - callback?.onReadMarkerLongBound() + callback?.onReadMarkerLongBound(displayReadMarker) } } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/ReadMarkerHelper.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/ReadMarkerHelper.kt index c162098cff..85ad6201d3 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/ReadMarkerHelper.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/ReadMarkerHelper.kt @@ -30,10 +30,25 @@ class ReadMarkerHelper @Inject constructor() { lateinit var layoutManager: LinearLayoutManager var callback: Callback? = null + private var onReadMarkerLongDisplayed = false + private var readMarkerVisible: Boolean = true private var state: RoomDetailViewState? = null - fun updateState(state: RoomDetailViewState) { - this.state = state + fun readMarkerVisible(): Boolean { + return readMarkerVisible + } + + fun onResume() { + onReadMarkerLongDisplayed = false + } + + fun onReadMarkerLongDisplayed() { + onReadMarkerLongDisplayed = true + } + + fun updateWith(newState: RoomDetailViewState) { + state = newState + checkReadMarkerVisibility() checkJumpToReadMarkerVisibility() } @@ -41,34 +56,47 @@ class ReadMarkerHelper @Inject constructor() { checkJumpToReadMarkerVisibility() } + private fun checkReadMarkerVisibility() { + val nonNullState = this.state ?: return + val firstVisibleItem = layoutManager.findFirstVisibleItemPosition() + val lastVisibleItem = layoutManager.findLastVisibleItemPosition() + readMarkerVisible = if (!onReadMarkerLongDisplayed) { + true + } else { + if (nonNullState.timeline?.isLive == false) { + true + } else { + !(firstVisibleItem == 0 && lastVisibleItem > 0) + } + } + } + private fun checkJumpToReadMarkerVisibility() { val nonNullState = this.state ?: return val lastVisibleItem = layoutManager.findLastVisibleItemPosition() val readMarkerId = nonNullState.asyncRoomSummary()?.readMarkerId if (readMarkerId == null) { - callback?.onVisibilityUpdated(false, null) + callback?.onJumpToReadMarkerVisibilityUpdate(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) + callback?.onJumpToReadMarkerVisibilityUpdate(true, readMarkerId) } else { - callback?.onVisibilityUpdated(false, readMarkerId) + callback?.onJumpToReadMarkerVisibilityUpdate(false, readMarkerId) } } else { if (positionOfReadMarker > lastVisibleItem) { - callback?.onVisibilityUpdated(true, readMarkerId) + callback?.onJumpToReadMarkerVisibilityUpdate(true, readMarkerId) } else { - callback?.onVisibilityUpdated(false, readMarkerId) + callback?.onJumpToReadMarkerVisibilityUpdate(false, readMarkerId) } } } interface Callback { - fun onVisibilityUpdated(show: Boolean, readMarkerId: String?) + fun onJumpToReadMarkerVisibilityUpdate(show: Boolean, readMarkerId: String?) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index a94e1941a1..aadfbb9fcb 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -28,12 +28,7 @@ import android.os.Parcelable import android.text.Editable import android.text.Spannable import android.text.TextUtils -import android.view.HapticFeedbackConstants -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuItem -import android.view.View -import android.view.Window +import android.view.* import android.view.inputmethod.InputMethodManager import android.widget.TextView import android.widget.Toast @@ -51,13 +46,7 @@ import androidx.recyclerview.widget.RecyclerView import butterknife.BindView import com.airbnb.epoxy.EpoxyModel import com.airbnb.epoxy.EpoxyVisibilityTracker -import com.airbnb.mvrx.Async -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.args -import com.airbnb.mvrx.fragmentViewModel -import com.airbnb.mvrx.withState +import com.airbnb.mvrx.* import com.github.piasy.biv.BigImageViewer import com.github.piasy.biv.loader.ImageLoader import com.google.android.material.snackbar.Snackbar @@ -71,13 +60,7 @@ import im.vector.matrix.android.api.permalinks.PermalinkFactory import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.model.Membership -import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent -import im.vector.matrix.android.api.session.room.model.message.MessageContent -import im.vector.matrix.android.api.session.room.model.message.MessageFileContent -import im.vector.matrix.android.api.session.room.model.message.MessageImageContent -import im.vector.matrix.android.api.session.room.model.message.MessageTextContent -import im.vector.matrix.android.api.session.room.model.message.MessageType -import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent +import im.vector.matrix.android.api.session.room.model.message.* import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent @@ -124,17 +107,8 @@ import im.vector.riotx.features.home.room.detail.composer.TextComposerViewModel import im.vector.riotx.features.home.room.detail.composer.TextComposerViewState import im.vector.riotx.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController -import im.vector.riotx.features.home.room.detail.timeline.action.ActionsHandler -import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsBottomSheet -import im.vector.riotx.features.home.room.detail.timeline.action.SimpleAction -import im.vector.riotx.features.home.room.detail.timeline.action.ViewEditHistoryBottomSheet -import im.vector.riotx.features.home.room.detail.timeline.action.ViewReactionBottomSheet -import im.vector.riotx.features.home.room.detail.timeline.item.AbsMessageItem -import im.vector.riotx.features.home.room.detail.timeline.item.MessageFileItem -import im.vector.riotx.features.home.room.detail.timeline.item.MessageImageVideoItem -import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData -import im.vector.riotx.features.home.room.detail.timeline.item.MessageTextItem -import im.vector.riotx.features.home.room.detail.timeline.item.ReadReceiptData +import im.vector.riotx.features.home.room.detail.timeline.action.* +import im.vector.riotx.features.home.room.detail.timeline.item.* import im.vector.riotx.features.html.EventHtmlRenderer import im.vector.riotx.features.html.PillImageSpan import im.vector.riotx.features.invite.VectorInviteView @@ -432,8 +406,8 @@ class RoomDetailFragment : } override fun onResume() { + readMarkerHelper.onResume() super.onResume() - notificationDrawerManager.setCurrentRoom(roomDetailArgs.roomId) } @@ -483,7 +457,7 @@ class RoomDetailFragment : readMarkerHelper.timelineEventController = timelineEventController readMarkerHelper.layoutManager = layoutManager readMarkerHelper.callback = object : ReadMarkerHelper.Callback { - override fun onVisibilityUpdated(show: Boolean, readMarkerId: String?) { + override fun onJumpToReadMarkerVisibilityUpdate(show: Boolean, readMarkerId: String?) { jumpToReadMarkerView.render(show, readMarkerId) } } @@ -707,13 +681,13 @@ class RoomDetailFragment : } private fun renderState(state: RoomDetailViewState) { - readMarkerHelper.updateState(state) + readMarkerHelper.updateWith(state) renderRoomSummary(state) val summary = state.asyncRoomSummary() val inviter = state.asyncInviter() if (summary?.membership == Membership.JOIN) { scrollOnHighlightedEventCallback.timeline = state.timeline - timelineEventController.update(state) + timelineEventController.update(state, readMarkerHelper.readMarkerVisible()) inviteView.visibility = View.GONE val uid = session.myUserId val meMember = session.getRoom(state.roomId)?.getRoomMember(uid) @@ -974,7 +948,10 @@ class RoomDetailFragment : .show(requireActivity().supportFragmentManager, "DISPLAY_READ_RECEIPTS") } - override fun onReadMarkerLongDisplayed() = withState(roomDetailViewModel) { state -> + override fun onReadMarkerLongBound(isDisplayed: Boolean) { + if (isDisplayed) { + readMarkerHelper.onReadMarkerLongDisplayed() + } val firstVisibleItem = layoutManager.findFirstVisibleItemPosition() val nextReadMarkerId = timelineEventController.searchEventIdAtPosition(firstVisibleItem) if (nextReadMarkerId != null) { @@ -982,6 +959,7 @@ class RoomDetailFragment : } } + // AutocompleteUserPresenter.Callback override fun onQueryUsers(query: CharSequence?) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 22850a96f0..72c6d67a7d 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -21,8 +21,6 @@ import android.text.TextUtils import androidx.annotation.IdRes import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import arrow.core.Option -import arrow.core.getOrElse import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success @@ -43,13 +41,11 @@ import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.matrix.android.api.session.room.model.message.MessageType import im.vector.matrix.android.api.session.room.model.message.getFileUrl -import im.vector.matrix.android.api.session.room.model.relation.ReactionContent import im.vector.matrix.android.api.session.room.model.tombstone.RoomTombstoneContent import im.vector.matrix.android.api.session.room.send.UserDraft -import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.TimelineSettings -import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.api.session.room.timeline.getTextEditableContent +import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent import im.vector.matrix.rx.rx @@ -62,11 +58,11 @@ import im.vector.riotx.core.utils.LiveEvent import im.vector.riotx.core.utils.subscribeLogError import im.vector.riotx.features.command.CommandParser import im.vector.riotx.features.command.ParsedCommand +import im.vector.riotx.features.home.room.detail.timeline.TimelineLayoutManagerHolder import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDisplayableEvents import im.vector.riotx.features.settings.VectorPreferences import io.reactivex.Observable import io.reactivex.functions.BiFunction -import io.reactivex.functions.Function3 import io.reactivex.rxkotlin.subscribeBy import org.commonmark.parser.Parser import org.commonmark.renderer.html.HtmlRenderer @@ -76,6 +72,7 @@ import java.util.concurrent.TimeUnit class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: RoomDetailViewState, + private val timelineLayoutManagerHolder: TimelineLayoutManagerHolder, private val userPreferencesProvider: UserPreferencesProvider, private val vectorPreferences: VectorPreferences, private val session: Session @@ -119,8 +116,9 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro observeRoomSummary() observeEventDisplayedActions() observeSummaryState() - observeReadMarkerVisibility() observeDrafts() + observeReadMarkerVisibility() + observeOwnState() room.rx().loadRoomMembersIfNeeded().subscribeLogError().disposeOnClear() timeline.start() setState { copy(timeline = this@RoomDetailViewModel.timeline) } @@ -711,23 +709,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } } - private fun observeReadMarkerVisibility() { - Observable - .combineLatest( - room.rx().liveReadMarker(), - room.rx().liveReadReceipt(), - BiFunction, Optional, Boolean> { readMarker, readReceipt -> - readMarker.getOrNull() == readReceipt.getOrNull() - } - ) - .startWith(false) - .subscribe { - setState { copy(hideReadMarker = it) } - } - .disposeOnClear() - } - - private fun observeSummaryState() { asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary -> if (summary.membership == Membership.INVITE) { @@ -743,6 +724,22 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } } + private fun observeReadMarkerVisibility() { + Observable + .combineLatest( + room.rx().liveReadMarker(), + room.rx().liveReadReceipt(), + BiFunction, Optional, Boolean> { readMarker, readReceipt -> + readMarker.getOrNull() != readReceipt.getOrNull() + } + ) + .subscribe { + setState { copy(readMarkerVisible = it) } + } + .disposeOnClear() + } + + override fun onCleared() { timeline.dispose() super.onCleared() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt index 2be78506a0..2609aed2e3 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt @@ -53,7 +53,7 @@ data class RoomDetailViewState( val tombstoneEventHandling: Async = Uninitialized, val syncState: SyncState = SyncState.IDLE, val highlightedEventId: String? = null, - val hideReadMarker: Boolean = false + val readMarkerVisible: Boolean = false ) : MvRxState { constructor(args: RoomDetailArgs) : this(roomId = args.roomId, eventId = args.eventId) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt index fdc37a7f35..525fb6cd6a 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt @@ -34,7 +34,10 @@ import im.vector.riotx.core.extensions.localDateTime import im.vector.riotx.features.home.room.detail.RoomDetailViewState import im.vector.riotx.features.home.room.detail.timeline.factory.MergedHeaderItemFactory import im.vector.riotx.features.home.room.detail.timeline.factory.TimelineItemFactory -import im.vector.riotx.features.home.room.detail.timeline.helper.* +import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineEventDiffUtilCallback +import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineEventVisibilityStateChangedListener +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.* import im.vector.riotx.features.media.ImageContentRenderer import im.vector.riotx.features.media.VideoContentRenderer @@ -79,7 +82,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec interface ReadReceiptsCallback { fun onReadReceiptsClicked(readReceipts: List) - fun onReadMarkerLongDisplayed() + fun onReadMarkerLongBound(isDisplayed: Boolean) } interface UrlClickCallback { @@ -141,7 +144,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec requestModelBuild() } - fun update(viewState: RoomDetailViewState) { + fun update(viewState: RoomDetailViewState, readMarkerVisible: Boolean) { if (timeline != viewState.timeline) { timeline = viewState.timeline timeline?.listener = this @@ -166,8 +169,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec eventIdToHighlight = viewState.highlightedEventId requestModelBuild = true } - if (hideReadMarker != viewState.hideReadMarker) { - hideReadMarker = viewState.hideReadMarker + if (this.readMarkerVisible != readMarkerVisible) { + this.readMarkerVisible = readMarkerVisible requestModelBuild = true } if (requestModelBuild) { @@ -175,7 +178,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec } } - private var hideReadMarker: Boolean = false + private var readMarkerVisible: Boolean = false private var eventIdToHighlight: String? = null override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { @@ -255,11 +258,19 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec val date = event.root.localDateTime() val nextDate = nextEvent?.root?.localDateTime() val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate() - val eventModel = timelineItemFactory.create(event, nextEvent, eventIdToHighlight, hideReadMarker, callback).also { + val eventModel = timelineItemFactory.create(event, nextEvent, eventIdToHighlight, readMarkerVisible, callback).also { it.id(event.localId) it.setOnVisibilityStateChanged(TimelineEventVisibilityStateChangedListener(callback, event)) } - val mergedHeaderModel = mergedHeaderItemFactory.create(event, nextEvent, items, addDaySeparator, currentPosition, eventIdToHighlight, callback) { + val mergedHeaderModel = mergedHeaderItemFactory.create(event, + nextEvent = nextEvent, + items = items, + addDaySeparator = addDaySeparator, + readMarkerVisible = readMarkerVisible, + currentPosition = currentPosition, + eventIdToHighlight = eventIdToHighlight, + callback = callback + ) { requestModelBuild() } val daySeparatorItem = buildDaySeparatorItem(addDaySeparator, date) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineLayoutManagerHolder.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineLayoutManagerHolder.kt new file mode 100644 index 0000000000..429515798a --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineLayoutManagerHolder.kt @@ -0,0 +1,29 @@ +/* + + * 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.timeline + +import androidx.recyclerview.widget.LinearLayoutManager +import im.vector.riotx.core.di.ScreenScope +import javax.inject.Inject + +@ScreenScope +class TimelineLayoutManagerHolder @Inject constructor() { + + lateinit var layoutManager: LinearLayoutManager + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/DefaultItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/DefaultItemFactory.kt index a387f3f496..959079bf8b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/DefaultItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/DefaultItemFactory.kt @@ -31,7 +31,7 @@ class DefaultItemFactory @Inject constructor(private val avatarSizeProvider: Ava fun create(event: TimelineEvent, highlight: Boolean, - hideReadMarker: Boolean, + readMarkerVisible: Boolean, callback: TimelineEventController.Callback?, exception: Exception? = null): DefaultItem? { val text = if (exception == null) { @@ -40,7 +40,7 @@ class DefaultItemFactory @Inject constructor(private val avatarSizeProvider: Ava "an exception occurred when rendering the event ${event.root.eventId}" } - val informationData = informationDataFactory.create(event, null, hideReadMarker) + val informationData = informationDataFactory.create(event, null, readMarkerVisible) return DefaultItem_() .leftGuideline(avatarSizeProvider.leftGuideline) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt index 663762850a..e67507d7bb 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt @@ -41,7 +41,7 @@ class EncryptedItemFactory @Inject constructor(private val messageInformationDat fun create(event: TimelineEvent, nextEvent: TimelineEvent?, highlight: Boolean, - hideReadMarker: Boolean, + readMarkerVisible: Boolean, callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? { event.root.eventId ?: return null @@ -65,7 +65,7 @@ class EncryptedItemFactory @Inject constructor(private val messageInformationDat // TODO This is not correct format for error, change it - val informationData = messageInformationDataFactory.create(event, nextEvent, hideReadMarker) + val informationData = messageInformationDataFactory.create(event, nextEvent, readMarkerVisible) val attributes = attributesFactory.create(null, informationData, callback) return MessageTextItem_() .leftGuideline(avatarSizeProvider.leftGuideline) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt index 80b3aa261b..ddf93410a1 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt @@ -18,15 +18,9 @@ package im.vector.riotx.features.home.room.detail.timeline.factory import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotx.core.di.ActiveSessionHolder -import im.vector.riotx.core.extensions.displayReadMarker import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController -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.prevSameTypeEvents -import im.vector.riotx.features.home.room.detail.timeline.helper.senderAvatar -import im.vector.riotx.features.home.room.detail.timeline.helper.senderName +import im.vector.riotx.features.home.room.detail.timeline.helper.* 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 @@ -42,6 +36,7 @@ class MergedHeaderItemFactory @Inject constructor(private val sessionHolder: Act nextEvent: TimelineEvent?, items: List, addDaySeparator: Boolean, + readMarkerVisible: Boolean, currentPosition: Int, eventIdToHighlight: String?, callback: TimelineEventController.Callback?, @@ -67,7 +62,7 @@ class MergedHeaderItemFactory @Inject constructor(private val sessionHolder: Act if (readMarkerId == null && mergedEvent.hasReadMarker) { readMarkerId = mergedEvent.root.eventId } - if (!showReadMarker && mergedEvent.displayReadMarker(sessionHolder.getActiveSession().myUserId)) { + if (!showReadMarker && mergedEvent.hasReadMarker && readMarkerVisible) { showReadMarker = true } val senderAvatar = mergedEvent.senderAvatar() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 2cf5a60c44..747ae483c9 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -76,12 +76,12 @@ class MessageItemFactory @Inject constructor( fun create(event: TimelineEvent, nextEvent: TimelineEvent?, highlight: Boolean, - hideReadMarker: Boolean, + readMarkerVisible: Boolean, callback: TimelineEventController.Callback? ): VectorEpoxyModel<*>? { event.root.eventId ?: return null - val informationData = messageInformationDataFactory.create(event, nextEvent, hideReadMarker) + val informationData = messageInformationDataFactory.create(event, nextEvent, readMarkerVisible) if (event.root.isRedacted()) { //message is redacted @@ -98,7 +98,7 @@ class MessageItemFactory @Inject constructor( || event.isEncrypted() && event.root.content.toModel()?.relatesTo?.type == RelationType.REPLACE ) { // This is an edit event, we should it when debugging as a notice event - return noticeItemFactory.create(event, highlight, hideReadMarker, callback) + return noticeItemFactory.create(event, highlight, readMarkerVisible, callback) } val attributes = messageItemAttributesFactory.create(messageContent, informationData, callback) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt index f251a70905..ff7af61fbe 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt @@ -34,11 +34,11 @@ class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEv fun create(event: TimelineEvent, highlight: Boolean, - hideReadMarker: Boolean, + readMarkerVisible: Boolean, callback: TimelineEventController.Callback?): NoticeItem? { val formattedText = eventFormatter.format(event) ?: return null - val informationData = informationDataFactory.create(event, null, hideReadMarker) + val informationData = informationDataFactory.create(event, null, readMarkerVisible) val attributes = NoticeItem.Attributes( avatarRenderer = avatarRenderer, informationData = informationData, diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/TimelineItemFactory.kt index 18254120af..eda00fff95 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/TimelineItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/TimelineItemFactory.kt @@ -33,14 +33,14 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me fun create(event: TimelineEvent, nextEvent: TimelineEvent?, eventIdToHighlight: String?, - hideReadMarker: Boolean, + readMarkerVisible: Boolean, callback: TimelineEventController.Callback?): VectorEpoxyModel<*> { val highlight = event.root.eventId == eventIdToHighlight val computedModel = try { when (event.root.getClearType()) { - EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, highlight, hideReadMarker, callback) + EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, highlight, readMarkerVisible, callback) // State and call EventType.STATE_ROOM_TOMBSTONE, EventType.STATE_ROOM_NAME, @@ -52,22 +52,22 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me EventType.CALL_ANSWER, EventType.REACTION, EventType.REDACTION, - EventType.ENCRYPTION -> noticeItemFactory.create(event, highlight, hideReadMarker, callback) + EventType.ENCRYPTION -> noticeItemFactory.create(event, highlight, readMarkerVisible, callback) // State room create EventType.STATE_ROOM_CREATE -> roomCreateItemFactory.create(event, callback) // Crypto EventType.ENCRYPTED -> { if (event.root.isRedacted()) { // Redacted event, let the MessageItemFactory handle it - messageItemFactory.create(event, nextEvent, highlight, hideReadMarker, callback) + messageItemFactory.create(event, nextEvent, highlight, readMarkerVisible, callback) } else { - encryptedItemFactory.create(event, nextEvent, highlight, hideReadMarker, callback) + encryptedItemFactory.create(event, nextEvent, highlight, readMarkerVisible, callback) } } // Unhandled event types (yet) EventType.STATE_ROOM_THIRD_PARTY_INVITE, - EventType.STICKER -> defaultItemFactory.create(event, highlight, hideReadMarker, callback) + EventType.STICKER -> defaultItemFactory.create(event, highlight, readMarkerVisible, callback) else -> { Timber.v("Type ${event.root.getClearType()} not handled") null @@ -75,7 +75,7 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me } } catch (e: Exception) { Timber.e(e, "failed to create message item") - defaultItemFactory.create(event, highlight, hideReadMarker, callback, e) + defaultItemFactory.create(event, highlight, readMarkerVisible, callback, e) } return (computedModel ?: EmptyItem_()) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 453f7e4cd9..8448ddc059 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -24,10 +24,8 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.hasBeenEdited import im.vector.riotx.core.extensions.localDateTime import im.vector.riotx.core.resources.ColorProvider -import im.vector.riotx.core.utils.isSingleEmoji import im.vector.riotx.features.home.getColorFromUserId import im.vector.riotx.core.date.VectorDateFormatter -import im.vector.riotx.core.extensions.displayReadMarker import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotx.features.home.room.detail.timeline.item.ReactionInfoData import im.vector.riotx.features.home.room.detail.timeline.item.ReadReceiptData @@ -41,7 +39,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses private val dateFormatter: VectorDateFormatter, private val colorProvider: ColorProvider) { - fun create(event: TimelineEvent, nextEvent: TimelineEvent?, hideReadMarker: Boolean): MessageInformationData { + fun create(event: TimelineEvent, nextEvent: TimelineEvent?, readMarkerVisible: Boolean): MessageInformationData { // Non nullability has been tested before val eventId = event.root.eventId!! @@ -65,7 +63,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses textColor = colorProvider.getColor(getColorFromUserId(event.root.senderId ?: "")) } - val displayReadMarker = !hideReadMarker && event.displayReadMarker(session.myUserId) + val displayReadMarker = readMarkerVisible && event.hasReadMarker return MessageInformationData( eventId = eventId, diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt index 408a997efd..5bf8ba6e06 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt @@ -57,8 +57,8 @@ abstract class AbsMessageItem : BaseEventItem() { private val _readMarkerCallback = object : ReadMarkerView.Callback { - override fun onReadMarkerLongBound() { - attributes.readReceiptsCallback?.onReadMarkerLongDisplayed() + override fun onReadMarkerLongBound(isDisplayed: Boolean) { + attributes.readReceiptsCallback?.onReadMarkerLongBound(isDisplayed) } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedHeaderItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedHeaderItem.kt index de105b2261..da19a88133 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedHeaderItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedHeaderItem.kt @@ -41,8 +41,8 @@ abstract class MergedHeaderItem : BaseEventItem() { private val _readMarkerCallback = object : ReadMarkerView.Callback { - override fun onReadMarkerLongBound() { - attributes.readReceiptsCallback?.onReadMarkerLongDisplayed() + override fun onReadMarkerLongBound(isDisplayed: Boolean) { + attributes.readReceiptsCallback?.onReadMarkerLongBound(isDisplayed) } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/NoticeItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/NoticeItem.kt index 89270ce026..559b02aa61 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/NoticeItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/NoticeItem.kt @@ -38,8 +38,9 @@ abstract class NoticeItem : BaseEventItem() { }) private val _readMarkerCallback = object : ReadMarkerView.Callback { - override fun onReadMarkerLongBound() { - attributes.readReceiptsCallback?.onReadMarkerLongDisplayed() + + override fun onReadMarkerLongBound(isDisplayed: Boolean) { + attributes.readReceiptsCallback?.onReadMarkerLongBound(isDisplayed) } }