Work on timeline

This commit is contained in:
ganfra 2020-01-06 18:44:04 +01:00
parent 99c523b710
commit f9487f8995
10 changed files with 112 additions and 109 deletions

View file

@ -41,7 +41,8 @@ data class RoomSummary(
val membership: Membership = Membership.NONE,
val versioningState: VersioningState = VersioningState.NONE,
val readMarkerId: String? = null,
val userDrafts: List<UserDraft> = emptyList()
val userDrafts: List<UserDraft> = emptyList(),
var isEncrypted: Boolean
) {
val isVersioned: Boolean

View file

@ -92,7 +92,7 @@ internal fun ChunkEntity.add(roomId: String,
}
}
val isUnlinked = isUnlinked
val isChunkUnlinked = isUnlinked
val localId = TimelineEventEntity.nextId(realm)
val eventId = event.eventId ?: ""
val senderId = event.senderId ?: ""
@ -121,7 +121,7 @@ internal fun ChunkEntity.add(roomId: String,
this.stateIndex = currentStateIndex
this.displayIndex = currentDisplayIndex
this.sendState = SendState.SYNCED
this.isUnlinked = isUnlinked
this.isUnlinked = isChunkUnlinked
}
val eventEntity = realm.createObject<TimelineEventEntity>().also {
it.localId = localId

View file

@ -70,7 +70,8 @@ internal class RoomSummaryMapper @Inject constructor(
readMarkerId = roomSummaryEntity.readMarkerId,
userDrafts = roomSummaryEntity.userDrafts?.userDrafts?.map { DraftMapper.map(it) } ?: emptyList(),
canonicalAlias = roomSummaryEntity.canonicalAlias,
aliases = roomSummaryEntity.aliases.toList()
aliases = roomSummaryEntity.aliases.toList(),
isEncrypted = roomSummaryEntity.isEncrypted
)
}
}

View file

@ -43,7 +43,8 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
var canonicalAlias: String? = null,
var aliases: RealmList<String> = RealmList(),
// this is required for querying
var flatAliases: String = ""
var flatAliases: String = "",
var isEncrypted: Boolean = false
) : RealmObject() {
private var membershipStr: String = Membership.NONE.name

View file

@ -93,10 +93,12 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()
val lastCanonicalAliasEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_CANONICAL_ALIAS).prev()
val lastAliasesEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_ALIASES).prev()
val encryptionEvent = EventEntity.where(realm, roomId, EventType.ENCRYPTION).prev()
roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0
// avoid this call if we are sure there are unread events
|| !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId)
// avoid this call if we are sure there are unread events
|| !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId)
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString()
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
@ -105,10 +107,12 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
roomSummaryEntity.canonicalAlias = ContentMapper.map(lastCanonicalAliasEvent?.content).toModel<RoomCanonicalAliasContent>()
?.canonicalAlias
val roomAliases = ContentMapper.map(lastAliasesEvent?.content).toModel<RoomAliasesContent>()?.aliases ?: emptyList()
val roomAliases = ContentMapper.map(lastAliasesEvent?.content).toModel<RoomAliasesContent>()?.aliases
?: emptyList()
roomSummaryEntity.aliases.clear()
roomSummaryEntity.aliases.addAll(roomAliases)
roomSummaryEntity.flatAliases = roomAliases.joinToString(separator = "|", prefix = "|")
roomSummaryEntity.isEncrypted = encryptionEvent != null
if (updateMembers) {
val otherRoomMembers = RoomMembers(realm, roomId)

View file

@ -52,8 +52,8 @@ import io.realm.RealmQuery
import io.realm.RealmResults
import io.realm.Sort
import timber.log.Timber
import java.util.Collections
import java.util.UUID
import java.util.*
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
import kotlin.collections.ArrayList
@ -77,11 +77,9 @@ internal class DefaultTimeline(
private val hiddenReadReceipts: TimelineHiddenReadReceipts
) : Timeline, TimelineHiddenReadReceipts.Delegate {
private companion object {
val BACKGROUND_HANDLER = createBackgroundHandler("TIMELINE_DB_THREAD")
}
val backgroundHandler = createBackgroundHandler("TIMELINE_DB_THREAD_${System.currentTimeMillis()}")
private val listeners = ArrayList<Timeline.Listener>()
private val listeners = CopyOnWriteArrayList<Timeline.Listener>()
private val isStarted = AtomicBoolean(false)
private val isReady = AtomicBoolean(false)
private val mainHandler = createUIHandler()
@ -137,7 +135,7 @@ internal class DefaultTimeline(
// Public methods ******************************************************************************
override fun paginate(direction: Timeline.Direction, count: Int) {
BACKGROUND_HANDLER.post {
backgroundHandler.post {
if (!canPaginate(direction)) {
return@post
}
@ -165,7 +163,7 @@ internal class DefaultTimeline(
override fun start() {
if (isStarted.compareAndSet(false, true)) {
Timber.v("Start timeline for roomId: $roomId and eventId: $initialEventId")
BACKGROUND_HANDLER.post {
backgroundHandler.post {
eventDecryptor.start()
val realm = Realm.getInstance(realmConfiguration)
backgroundRealm.set(realm)
@ -199,8 +197,8 @@ internal class DefaultTimeline(
isReady.set(false)
Timber.v("Dispose timeline for roomId: $roomId and eventId: $initialEventId")
cancelableBag.cancel()
BACKGROUND_HANDLER.removeCallbacksAndMessages(null)
BACKGROUND_HANDLER.post {
backgroundHandler.removeCallbacksAndMessages(null)
backgroundHandler.post {
roomEntity?.sendingTimelineEvents?.removeAllChangeListeners()
if (this::eventRelations.isInitialized) {
eventRelations.removeAllChangeListeners()
@ -288,20 +286,20 @@ internal class DefaultTimeline(
return hasMoreInCache(direction) || !hasReachedEnd(direction)
}
override fun addListener(listener: Timeline.Listener) = synchronized(listeners) {
override fun addListener(listener: Timeline.Listener): Boolean {
if (listeners.contains(listener)) {
return false
}
listeners.add(listener).also {
return listeners.add(listener).also {
postSnapshot()
}
}
override fun removeListener(listener: Timeline.Listener) = synchronized(listeners) {
listeners.remove(listener)
override fun removeListener(listener: Timeline.Listener): Boolean {
return listeners.remove(listener)
}
override fun removeAllListeners() = synchronized(listeners) {
override fun removeAllListeners() {
listeners.clear()
}
@ -497,9 +495,9 @@ internal class DefaultTimeline(
return
}
val params = PaginationTask.Params(roomId = roomId,
from = token,
direction = direction.toPaginationDirection(),
limit = limit)
from = token,
direction = direction.toPaginationDirection(),
limit = limit)
Timber.v("Should fetch $limit items $direction")
cancelableBag += paginationTask
@ -516,7 +514,7 @@ internal class DefaultTimeline(
}
TokenChunkEventPersistor.Result.SHOULD_FETCH_MORE ->
// Database won't be updated, so we force pagination request
BACKGROUND_HANDLER.post {
backgroundHandler.post {
executePaginationTask(direction, limit)
}
}
@ -575,7 +573,7 @@ internal class DefaultTimeline(
val timelineEvent = buildTimelineEvent(eventEntity)
if (timelineEvent.isEncrypted()
&& timelineEvent.root.mxDecryptionResult == null) {
&& timelineEvent.root.mxDecryptionResult == null) {
timelineEvent.root.eventId?.let { eventDecryptor.requestDecryption(it) }
}
@ -649,17 +647,15 @@ internal class DefaultTimeline(
}
private fun postSnapshot() {
BACKGROUND_HANDLER.post {
backgroundHandler.post {
if (isReady.get().not()) {
return@post
}
updateLoadingStates(filteredEvents)
val snapshot = createSnapshot()
val runnable = Runnable {
synchronized(listeners) {
listeners.forEach {
it.onTimelineUpdated(snapshot)
}
listeners.forEach {
it.onTimelineUpdated(snapshot)
}
}
debouncer.debounce("post_snapshot", runnable, 50)
@ -671,10 +667,8 @@ internal class DefaultTimeline(
return
}
val runnable = Runnable {
synchronized(listeners) {
listeners.forEach {
it.onTimelineFailure(throwable)
}
listeners.forEach {
it.onTimelineFailure(throwable)
}
}
mainHandler.post(runnable)

View file

@ -40,6 +40,7 @@ import androidx.core.util.Pair
import androidx.core.view.ViewCompat
import androidx.core.view.forEach
import androidx.core.view.isVisible
import androidx.lifecycle.observe
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -71,6 +72,7 @@ import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
import im.vector.matrix.android.api.util.MatrixItem
import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.matrix.android.api.util.toRoomAliasMatrixItem
import im.vector.matrix.rx.rx
import im.vector.riotx.R
import im.vector.riotx.core.dialogs.withColoredButton
import im.vector.riotx.core.epoxy.LayoutManagerStateRestorer
@ -225,6 +227,8 @@ class RoomDetailFragment @Inject constructor(
setupNotificationView()
setupJumpToReadMarkerView()
setupJumpToBottomView()
roomDetailViewModel.subscribe { renderState(it) }
textComposerViewModel.subscribe { renderTextComposerState(it) }
roomDetailViewModel.sendMessageResultLiveData.observeEvent(this) { renderSendMessageResult(it) }
@ -325,12 +329,10 @@ class RoomDetailFragment @Inject constructor(
jumpToBottomView.setOnClickListener {
roomDetailViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState)
jumpToBottomView.visibility = View.INVISIBLE
withState(roomDetailViewModel) { state ->
if (state.timeline?.isLive == false) {
state.timeline.restartWithEventId(null)
} else {
layoutManager.scrollToPosition(0)
}
if (!roomDetailViewModel.timeline.isLive) {
roomDetailViewModel.timeline.restartWithEventId(null)
} else {
layoutManager.scrollToPosition(0)
}
}
}
@ -343,9 +345,9 @@ class RoomDetailFragment @Inject constructor(
AlertDialog.Builder(requireActivity())
.setTitle(R.string.dialog_title_error)
.setMessage(getString(R.string.error_file_too_big,
error.filename,
TextUtils.formatFileSize(requireContext(), error.fileSizeInBytes),
TextUtils.formatFileSize(requireContext(), error.homeServerLimitInBytes)
error.filename,
TextUtils.formatFileSize(requireContext(), error.fileSizeInBytes),
TextUtils.formatFileSize(requireContext(), error.homeServerLimitInBytes)
))
.setPositiveButton(R.string.ok, null)
.show()
@ -431,7 +433,8 @@ class RoomDetailFragment @Inject constructor(
composerLayout.sendButton.setContentDescription(getString(descriptionRes))
avatarRenderer.render(
MatrixItem.UserItem(event.root.senderId ?: "", event.getDisambiguatedDisplayName(), event.senderAvatar),
MatrixItem.UserItem(event.root.senderId
?: "", event.getDisambiguatedDisplayName(), event.senderAvatar),
composerLayout.composerRelatedMessageAvatar
)
composerLayout.expand {
@ -449,7 +452,7 @@ class RoomDetailFragment @Inject constructor(
// Ignore update to avoid saving a draft
composerLayout.composerEditText.setText(text)
composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text?.length
?: 0)
?: 0)
}
}
@ -481,6 +484,9 @@ class RoomDetailFragment @Inject constructor(
// PRIVATE METHODS *****************************************************************************
private fun setupRecyclerView() {
timelineEventController.callback = this
timelineEventController.timeline = roomDetailViewModel.timeline
val epoxyVisibilityTracker = EpoxyVisibilityTracker()
epoxyVisibilityTracker.attach(recyclerView)
layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
@ -514,8 +520,6 @@ class RoomDetailFragment @Inject constructor(
}
})
timelineEventController.callback = this
if (vectorPreferences.swipeToReplyIsEnabled()) {
val quickReplyHandler = object : RoomMessageTouchHelperCallback.QuickReplayHandler {
override fun performQuickReplyOnHolder(model: EpoxyModel<*>) {
@ -789,11 +793,12 @@ class RoomDetailFragment @Inject constructor(
}
private fun renderState(state: RoomDetailViewState) {
Timber.v("Render state summary complete: ${state.asyncRoomSummary.complete}")
renderRoomSummary(state)
val summary = state.asyncRoomSummary()
val inviter = state.asyncInviter()
if (summary?.membership == Membership.JOIN) {
scrollOnHighlightedEventCallback.timeline = state.timeline
scrollOnHighlightedEventCallback.timeline = roomDetailViewModel.timeline
timelineEventController.update(state)
inviteView.visibility = View.GONE
val uid = session.myUserId
@ -808,9 +813,10 @@ class RoomDetailFragment @Inject constructor(
} else if (state.asyncInviter.complete) {
vectorBaseActivity.finish()
}
val isRoomEncrypted = summary?.isEncrypted ?: false
if (state.tombstoneEvent == null) {
composerLayout.visibility = View.VISIBLE
composerLayout.setRoomEncrypted(state.isEncrypted)
composerLayout.setRoomEncrypted(isRoomEncrypted)
notificationAreaView.render(NotificationAreaView.State.Hidden)
} else {
composerLayout.visibility = View.GONE
@ -1312,7 +1318,7 @@ class RoomDetailFragment @Inject constructor(
val startToCompose = composerLayout.composerEditText.text.isNullOrBlank()
if (startToCompose
&& userId == session.myUserId) {
&& userId == session.myUserId) {
// Empty composer, current user: start an emote
composerLayout.composerEditText.setText(Command.EMOTE.command + " ")
composerLayout.composerEditText.setSelection(Command.EMOTE.length)

View file

@ -20,14 +20,18 @@ import android.net.Uri
import androidx.annotation.IdRes
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.airbnb.mvrx.*
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext
import com.jakewharton.rxrelay2.BehaviorRelay
import com.jakewharton.rxrelay2.PublishRelay
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.MatrixPatterns
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.isImageMessage
@ -89,20 +93,21 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
private val visibleEventsObservable = BehaviorRelay.create<RoomDetailAction.TimelineEventTurnsVisible>()
private val timelineSettings = if (userPreferencesProvider.shouldShowHiddenEvents()) {
TimelineSettings(30,
filterEdits = false,
filterTypes = true,
allowedTypes = TimelineDisplayableEvents.DEBUG_DISPLAYABLE_TYPES,
buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts())
filterEdits = false,
filterTypes = true,
allowedTypes = TimelineDisplayableEvents.DEBUG_DISPLAYABLE_TYPES,
buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts())
} else {
TimelineSettings(30,
filterEdits = true,
filterTypes = true,
allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES,
buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts())
filterEdits = true,
filterTypes = true,
allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES,
buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts())
}
private var timelineEvents = PublishRelay.create<List<TimelineEvent>>()
private var timeline = room.createTimeline(eventId, timelineSettings)
var timeline = room.createTimeline(eventId, timelineSettings)
private set
private val _viewEvents = PublishDataSource<RoomDetailViewEvents>()
val viewEvents: DataSource<RoomDetailViewEvents> = _viewEvents
@ -138,18 +143,17 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
}
init {
timeline.start()
timeline.addListener(this)
observeRoomSummary()
observeSummaryState()
getUnreadState()
observeSyncState()
observeRoomSummary()
observeEventDisplayedActions()
observeSummaryState()
observeDrafts()
observeUnreadState()
room.getRoomSummaryLive()
room.rx().loadRoomMembersIfNeeded().subscribeLogError().disposeOnClear()
timeline.addListener(this)
timeline.start()
setState { copy(timeline = this@RoomDetailViewModel.timeline) }
// Inform the SDK that the room is displayed
session.onRoomDisplayed(initialState.roomId)
}
@ -233,23 +237,23 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
copy(
// Create a sendMode from a draft and retrieve the TimelineEvent
sendMode = when (draft) {
is UserDraft.REGULAR -> SendMode.REGULAR(draft.text)
is UserDraft.QUOTE -> {
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
SendMode.QUOTE(timelineEvent, draft.text)
}
}
is UserDraft.REPLY -> {
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
SendMode.REPLY(timelineEvent, draft.text)
}
}
is UserDraft.EDIT -> {
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
SendMode.EDIT(timelineEvent, draft.text)
}
}
} ?: SendMode.REGULAR("")
is UserDraft.REGULAR -> SendMode.REGULAR(draft.text)
is UserDraft.QUOTE -> {
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
SendMode.QUOTE(timelineEvent, draft.text)
}
}
is UserDraft.REPLY -> {
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
SendMode.REPLY(timelineEvent, draft.text)
}
}
is UserDraft.EDIT -> {
room.getTimeLineEvent(draft.linkedEventId)?.let { timelineEvent ->
SendMode.EDIT(timelineEvent, draft.text)
}
}
} ?: SendMode.REGULAR("")
)
}
}
@ -258,7 +262,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
private fun handleTombstoneEvent(action: RoomDetailAction.HandleTombstoneEvent) {
val tombstoneContent = action.event.getClearContent().toModel<RoomTombstoneContent>()
?: return
?: return
val roomId = tombstoneContent.replacementRoom ?: ""
val isRoomJoined = session.getRoom(roomId)?.roomSummary()?.membership == Membership.JOIN
@ -310,7 +314,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
else -> false
}
// PRIVATE METHODS *****************************************************************************
// PRIVATE METHODS *****************************************************************************
private fun handleSendMessage(action: RoomDetailAction.SendMessage) {
withState { state ->
@ -396,7 +400,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
is SendMode.EDIT -> {
// is original event a reply?
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) {
// TODO check if same content?
room.getTimeLineEvent(inReplyTo)?.let {
@ -405,13 +409,13 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
} else {
val messageContent: MessageContent? =
state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel()
?: state.sendMode.timelineEvent.root.getClearContent().toModel()
?: state.sendMode.timelineEvent.root.getClearContent().toModel()
val existingBody = messageContent?.body ?: ""
if (existingBody != action.text) {
room.editTextMessage(state.sendMode.timelineEvent.root.eventId ?: "",
messageContent?.type ?: MessageType.MSGTYPE_TEXT,
action.text,
action.autoMarkdown)
messageContent?.type ?: MessageType.MSGTYPE_TEXT,
action.text,
action.autoMarkdown)
} else {
Timber.w("Same message content, do not send edition")
}
@ -422,7 +426,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
is SendMode.QUOTE -> {
val messageContent: MessageContent? =
state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel()
?: state.sendMode.timelineEvent.root.getClearContent().toModel()
?: state.sendMode.timelineEvent.root.getClearContent().toModel()
val textMsg = messageContent?.body
val finalText = legacyRiotQuoteText(textMsg, action.text.toString())
@ -538,7 +542,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
when (val tooBigFile = attachments.find { it.size > maxUploadFileSize }) {
null -> room.sendMedias(attachments)
else -> _fileTooBigEvent.postValue(LiveEvent(FileTooBigError(tooBigFile.name
?: tooBigFile.path, tooBigFile.size, maxUploadFileSize)))
?: tooBigFile.path, tooBigFile.size, maxUploadFileSize)))
}
}
}
@ -728,7 +732,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
.filter { it.isNotEmpty() }
.subscribeBy(onNext = { actions ->
val bufferedMostRecentDisplayedEvent = actions.maxBy { it.event.displayIndex }?.event
?: return@subscribeBy
?: return@subscribeBy
val globalMostRecentDisplayedEvent = mostRecentDisplayedEvent
if (trackUnreadMessages.get()) {
if (globalMostRecentDisplayedEvent == null) {
@ -791,10 +795,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
room.rx().liveRoomSummary()
.unwrap()
.execute { async ->
copy(
asyncRoomSummary = async,
isEncrypted = room.isEncrypted()
)
copy(asyncRoomSummary = async)
}
}
@ -880,7 +881,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
override fun onCleared() {
timeline.dispose()
timeline.removeListener(this)
timeline.removeAllListeners()
super.onCleared()
}
}

View file

@ -51,11 +51,9 @@ sealed class UnreadState {
data class RoomDetailViewState(
val roomId: String,
val eventId: String?,
val timeline: Timeline? = null,
val asyncInviter: Async<User> = Uninitialized,
val asyncRoomSummary: Async<RoomSummary> = Uninitialized,
val sendMode: SendMode = SendMode.REGULAR(""),
val isEncrypted: Boolean = false,
val tombstoneEvent: Event? = null,
val tombstoneEventHandling: Async<String> = Uninitialized,
val syncState: SyncState = SyncState.Idle,

View file

@ -95,12 +95,12 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
private val modelCache = arrayListOf<CacheItemData?>()
private var currentSnapshot: List<TimelineEvent> = emptyList()
private var inSubmitList: Boolean = false
private var timeline: Timeline? = null
private var unreadState: UnreadState = UnreadState.Unknown
private var positionOfReadMarker: Int? = null
private var eventIdToHighlight: String? = null
var callback: Callback? = null
var timeline: Timeline? = null
private val listUpdateCallback = object : ListUpdateCallback {
@ -176,10 +176,6 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
}
fun update(viewState: RoomDetailViewState) {
if (timeline?.timelineID != viewState.timeline?.timelineID) {
timeline = viewState.timeline
timeline?.addListener(this)
}
var requestModelBuild = false
if (eventIdToHighlight != viewState.highlightedEventId) {
// Clear cache to force a refresh
@ -205,6 +201,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
timeline?.addListener(this)
timelineMediaSizeProvider.recyclerView = recyclerView
}