mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 21:48:50 +03:00
Read marker: final refact [WIP]
This commit is contained in:
parent
c6d01fbcf4
commit
63b43de4b8
17 changed files with 152 additions and 115 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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?)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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?) {
|
||||
|
|
|
@ -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<String>, Optional<String>, 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<String>, Optional<String>, Boolean> { readMarker, readReceipt ->
|
||||
readMarker.getOrNull() != readReceipt.getOrNull()
|
||||
}
|
||||
)
|
||||
.subscribe {
|
||||
setState { copy(readMarkerVisible = it) }
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
|
||||
override fun onCleared() {
|
||||
timeline.dispose()
|
||||
super.onCleared()
|
||||
|
|
|
@ -53,7 +53,7 @@ data class RoomDetailViewState(
|
|||
val tombstoneEventHandling: Async<String> = 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)
|
||||
|
|
|
@ -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<ReadReceiptData>)
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<TimelineEvent>,
|
||||
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()
|
||||
|
|
|
@ -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<EncryptedEventContent>()?.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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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_())
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -57,8 +57,8 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
|||
|
||||
private val _readMarkerCallback = object : ReadMarkerView.Callback {
|
||||
|
||||
override fun onReadMarkerLongBound() {
|
||||
attributes.readReceiptsCallback?.onReadMarkerLongDisplayed()
|
||||
override fun onReadMarkerLongBound(isDisplayed: Boolean) {
|
||||
attributes.readReceiptsCallback?.onReadMarkerLongBound(isDisplayed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ abstract class MergedHeaderItem : BaseEventItem<MergedHeaderItem.Holder>() {
|
|||
|
||||
private val _readMarkerCallback = object : ReadMarkerView.Callback {
|
||||
|
||||
override fun onReadMarkerLongBound() {
|
||||
attributes.readReceiptsCallback?.onReadMarkerLongDisplayed()
|
||||
override fun onReadMarkerLongBound(isDisplayed: Boolean) {
|
||||
attributes.readReceiptsCallback?.onReadMarkerLongBound(isDisplayed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,9 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
|||
})
|
||||
|
||||
private val _readMarkerCallback = object : ReadMarkerView.Callback {
|
||||
override fun onReadMarkerLongBound() {
|
||||
attributes.readReceiptsCallback?.onReadMarkerLongDisplayed()
|
||||
|
||||
override fun onReadMarkerLongBound(isDisplayed: Boolean) {
|
||||
attributes.readReceiptsCallback?.onReadMarkerLongBound(isDisplayed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue