Message state: fix and clean code after Benoits review

This commit is contained in:
ganfra 2021-03-10 19:32:50 +01:00
parent 6c8e2f1fd6
commit ea21892d03
4 changed files with 29 additions and 19 deletions
matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room
vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action

View file

@ -38,7 +38,6 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.task.configureWith

View file

@ -87,7 +87,7 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv
} }
override fun getTimeLineEventLive(eventId: String): LiveData<Optional<TimelineEvent>> { override fun getTimeLineEventLive(eventId: String): LiveData<Optional<TimelineEvent>> {
return LiveTimelineEvent(timelineInput, monarchy, taskExecutor, timelineEventMapper, roomId, eventId) return LiveTimelineEvent(timelineInput, monarchy, taskExecutor.executorScope, timelineEventMapper, roomId, eventId)
} }
override fun getAttachmentMessages(): List<TimelineEvent> { override fun getAttachmentMessages(): List<TimelineEvent> {

View file

@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.Transformations
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.events.model.LocalEcho import org.matrix.android.sdk.api.session.events.model.LocalEcho
@ -29,14 +30,14 @@ import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.task.TaskExecutor import java.util.concurrent.atomic.AtomicBoolean
/** /**
* This class takes care of handling case where local echo is replaced by the synced event in the db. * This class takes care of handling case where local echo is replaced by the synced event in the db.
*/ */
internal class LiveTimelineEvent(private val timelineInput: TimelineInput, internal class LiveTimelineEvent(private val timelineInput: TimelineInput,
private val monarchy: Monarchy, private val monarchy: Monarchy,
private val taskExecutor: TaskExecutor, private val coroutineScope: CoroutineScope,
private val timelineEventMapper: TimelineEventMapper, private val timelineEventMapper: TimelineEventMapper,
private val roomId: String, private val roomId: String,
private val eventId: String) private val eventId: String)
@ -45,12 +46,15 @@ internal class LiveTimelineEvent(private val timelineInput: TimelineInput,
private var queryLiveData: LiveData<Optional<TimelineEvent>>? = null private var queryLiveData: LiveData<Optional<TimelineEvent>>? = null
// If we are listening to local echo, we want to be aware when event is synced
private var shouldObserveSync = AtomicBoolean(LocalEcho.isLocalEchoId(eventId))
init { init {
buildAndObserveQuery(eventId) buildAndObserveQuery(eventId)
} }
// Makes sure it's made on the main thread // Makes sure it's made on the main thread
private fun buildAndObserveQuery(eventIdToObserve: String) = taskExecutor.executorScope.launch(Dispatchers.Main) { private fun buildAndObserveQuery(eventIdToObserve: String) = coroutineScope.launch(Dispatchers.Main) {
queryLiveData?.also { queryLiveData?.also {
removeSource(it) removeSource(it)
} }
@ -60,14 +64,15 @@ internal class LiveTimelineEvent(private val timelineInput: TimelineInput,
) )
queryLiveData = Transformations.map(liveData) { events -> queryLiveData = Transformations.map(liveData) { events ->
events.firstOrNull().toOptional() events.firstOrNull().toOptional()
} }.also {
queryLiveData?.also {
addSource(it) { newValue -> value = newValue } addSource(it) { newValue -> value = newValue }
} }
} }
override fun onLocalEchoSynced(roomId: String, localEchoEventId: String, syncedEventId: String) { override fun onLocalEchoSynced(roomId: String, localEchoEventId: String, syncedEventId: String) {
if (localEchoEventId == eventId) { if (this.roomId == roomId && localEchoEventId == this.eventId) {
timelineInput.listeners.remove(this)
shouldObserveSync.set(false)
// rebuild the query with the new eventId // rebuild the query with the new eventId
buildAndObserveQuery(syncedEventId) buildAndObserveQuery(syncedEventId)
} }
@ -75,15 +80,14 @@ internal class LiveTimelineEvent(private val timelineInput: TimelineInput,
override fun onActive() { override fun onActive() {
super.onActive() super.onActive()
// If we are listening to local echo, we want to be aware when event is synced if (shouldObserveSync.get()) {
if (LocalEcho.isLocalEchoId(eventId)) {
timelineInput.listeners.add(this) timelineInput.listeners.add(this)
} }
} }
override fun onInactive() { override fun onInactive() {
super.onInactive() super.onInactive()
if (LocalEcho.isLocalEchoId(eventId)) { if (shouldObserveSync.get()) {
timelineInput.listeners.remove(this) timelineInput.listeners.remove(this)
} }
} }

View file

@ -18,6 +18,7 @@ package im.vector.app.features.home.room.detail.timeline.action
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import com.jakewharton.rxrelay2.BehaviorRelay
import dagger.Lazy import dagger.Lazy
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
@ -75,6 +76,8 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
pillsPostProcessorFactory.create(initialState.roomId) pillsPostProcessorFactory.create(initialState.roomId)
} }
private val eventIdObservable = BehaviorRelay.createDefault(initialState.eventId)
@AssistedFactory @AssistedFactory
interface Factory { interface Factory {
fun create(initialState: MessageActionState): MessageActionsViewModel fun create(initialState: MessageActionState): MessageActionsViewModel
@ -90,6 +93,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
init { init {
observeEvent() observeEvent()
observeReactions()
observePowerLevel() observePowerLevel()
observeTimelineEventState() observeTimelineEventState()
} }
@ -135,8 +139,10 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
} }
} }
private fun observeReactions(eventId: String) { private fun observeReactions() {
if (room == null) return if (room == null) return
eventIdObservable
.switchMap { eventId ->
room.rx() room.rx()
.liveAnnotationSummary(eventId) .liveAnnotationSummary(eventId)
.map { annotations -> .map { annotations ->
@ -144,6 +150,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
ToggleState(emoji, annotations.getOrNull()?.reactionsSummary?.firstOrNull { it.key == emoji }?.addedByMe ?: false) ToggleState(emoji, annotations.getOrNull()?.reactionsSummary?.firstOrNull { it.key == emoji }?.addedByMe ?: false)
} }
} }
}
.execute { .execute {
copy(quickStates = it) copy(quickStates = it)
} }
@ -152,7 +159,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
private fun observeTimelineEventState() { private fun observeTimelineEventState() {
selectSubscribe(MessageActionState::timelineEvent, MessageActionState::actionPermissions) { timelineEvent, permissions -> selectSubscribe(MessageActionState::timelineEvent, MessageActionState::actionPermissions) { timelineEvent, permissions ->
val nonNullTimelineEvent = timelineEvent() ?: return@selectSubscribe val nonNullTimelineEvent = timelineEvent() ?: return@selectSubscribe
observeReactions(nonNullTimelineEvent.eventId) eventIdObservable.accept(nonNullTimelineEvent.eventId)
setState { setState {
copy( copy(
eventId = nonNullTimelineEvent.eventId, eventId = nonNullTimelineEvent.eventId,