mirror of
https://github.com/element-hq/element-android
synced 2024-11-23 18:05:36 +03:00
Fix impure reducer and use live event
This commit is contained in:
parent
4d7f1b4fee
commit
a734c699ad
11 changed files with 145 additions and 82 deletions
|
@ -19,6 +19,7 @@ package im.vector.matrix.rx
|
|||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import io.reactivex.Observable
|
||||
|
||||
class RxRoom(private val room: Room) {
|
||||
|
@ -31,10 +32,14 @@ class RxRoom(private val room: Room) {
|
|||
return room.getRoomMemberIdsLive().asObservable()
|
||||
}
|
||||
|
||||
fun liveAnnotationSummary(eventId: String): Observable<List<EventAnnotationsSummary>> {
|
||||
fun liveAnnotationSummary(eventId: String): Observable<EventAnnotationsSummary> {
|
||||
return room.getEventSummaryLive(eventId).asObservable()
|
||||
}
|
||||
|
||||
fun liveTimelineEvent(eventId: String): Observable<TimelineEvent> {
|
||||
return room.liveTimeLineEvent(eventId).asObservable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Room.rx(): RxRoom {
|
||||
|
|
|
@ -80,5 +80,5 @@ interface RelationService {
|
|||
*/
|
||||
fun replyToMessage(eventReplied: Event, replyText: String): Cancelable?
|
||||
|
||||
fun getEventSummaryLive(eventId: String): LiveData<List<EventAnnotationsSummary>>
|
||||
fun getEventSummaryLive(eventId: String): LiveData<EventAnnotationsSummary>
|
||||
}
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package im.vector.matrix.android.api.session.room.timeline
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
|
||||
/**
|
||||
* This interface defines methods to interact with the timeline. It's implemented at the room level.
|
||||
*/
|
||||
|
@ -32,4 +34,7 @@ interface TimelineService {
|
|||
|
||||
|
||||
fun getTimeLineEvent(eventId: String): TimelineEvent?
|
||||
|
||||
|
||||
fun liveTimeLineEvent(eventId: String): LiveData<TimelineEvent>
|
||||
}
|
|
@ -17,6 +17,7 @@ package im.vector.matrix.android.internal.session.room.relation
|
|||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
|
@ -27,6 +28,7 @@ import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
|||
import im.vector.matrix.android.api.session.room.model.message.MessageType
|
||||
import im.vector.matrix.android.api.session.room.model.relation.RelationService
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.RealmLiveData
|
||||
import im.vector.matrix.android.internal.database.helper.addSendingEvent
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
|
@ -155,15 +157,13 @@ internal class DefaultRelationService @Inject constructor(private val context: C
|
|||
return workRequest
|
||||
}
|
||||
|
||||
override fun getEventSummaryLive(eventId: String): LiveData<List<EventAnnotationsSummary>> {
|
||||
return monarchy.findAllMappedWithChanges(
|
||||
{ realm ->
|
||||
EventAnnotationsSummaryEntity.where(realm, eventId)
|
||||
},
|
||||
{
|
||||
it.asDomain()
|
||||
}
|
||||
)
|
||||
override fun getEventSummaryLive(eventId: String): LiveData<EventAnnotationsSummary> {
|
||||
val liveEntity = RealmLiveData(monarchy.realmConfiguration) { realm ->
|
||||
EventAnnotationsSummaryEntity.where(realm, eventId)
|
||||
}
|
||||
return Transformations.map(liveEntity) { realmResults ->
|
||||
realmResults.firstOrNull()?.asDomain() ?: EventAnnotationsSummary(eventId, emptyList(), null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,10 +16,14 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.room.timeline
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
||||
import im.vector.matrix.android.internal.database.RealmLiveData
|
||||
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
|
@ -47,5 +51,27 @@ internal class DefaultTimelineService @Inject constructor(private val roomId: St
|
|||
})
|
||||
}
|
||||
|
||||
override fun liveTimeLineEvent(eventId: String): LiveData<TimelineEvent> {
|
||||
val liveEventEntity = RealmLiveData(monarchy.realmConfiguration) { realm ->
|
||||
EventEntity.where(realm, eventId = eventId)
|
||||
}
|
||||
val liveAnnotationsEntity = RealmLiveData(monarchy.realmConfiguration) { realm ->
|
||||
EventAnnotationsSummaryEntity.where(realm, eventId = eventId)
|
||||
}
|
||||
val result = MediatorLiveData<TimelineEvent>()
|
||||
result.addSource(liveEventEntity) { realmResults ->
|
||||
result.value = realmResults.firstOrNull()?.let { timelineEventFactory.create(it) }
|
||||
}
|
||||
|
||||
result.addSource(liveAnnotationsEntity) {
|
||||
liveEventEntity.value?.let {
|
||||
result.value = liveEventEntity.value?.let { realmResults ->
|
||||
//recreate the timeline event
|
||||
realmResults.firstOrNull()?.let { timelineEventFactory.create(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
|
@ -15,10 +15,7 @@
|
|||
*/
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.action
|
||||
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.airbnb.mvrx.*
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
|
@ -28,7 +25,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
|||
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.timeline.TimelineEvent
|
||||
import im.vector.riotredesign.core.di.HasScreenInjector
|
||||
import im.vector.matrix.rx.RxRoom
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||
|
@ -37,27 +34,30 @@ import java.text.SimpleDateFormat
|
|||
import java.util.*
|
||||
|
||||
|
||||
val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault())
|
||||
|
||||
data class MessageActionState(
|
||||
val roomId: String,
|
||||
val eventId: String,
|
||||
val informationData: MessageInformationData,
|
||||
val timelineEvent: TimelineEvent?
|
||||
val timelineEvent: Async<TimelineEvent> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId, informationData = args.informationData)
|
||||
|
||||
|
||||
private val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault())
|
||||
|
||||
fun senderName(): String = informationData.memberName?.toString() ?: ""
|
||||
|
||||
fun time(): String? = timelineEvent?.root?.originServerTs?.let { dateFormat.format(Date(it)) }
|
||||
fun time(): String? = timelineEvent()?.root?.originServerTs?.let { dateFormat.format(Date(it)) }
|
||||
?: ""
|
||||
|
||||
fun canReact(): Boolean = timelineEvent?.root?.type == EventType.MESSAGE && timelineEvent.sendState.isSent()
|
||||
fun canReact(): Boolean = timelineEvent()?.root?.type == EventType.MESSAGE && timelineEvent()?.sendState?.isSent() == true
|
||||
|
||||
fun messageBody(eventHtmlRenderer: EventHtmlRenderer?, noticeEventFormatter: NoticeEventFormatter?): CharSequence? {
|
||||
return when (timelineEvent?.root?.getClearType()) {
|
||||
return when (timelineEvent()?.root?.getClearType()) {
|
||||
EventType.MESSAGE -> {
|
||||
val messageContent: MessageContent? = timelineEvent.annotations?.editSummary?.aggregatedContent?.toModel()
|
||||
?: timelineEvent.root.getClearContent().toModel()
|
||||
val messageContent: MessageContent? = timelineEvent()?.annotations?.editSummary?.aggregatedContent?.toModel()
|
||||
?: timelineEvent()?.root?.getClearContent().toModel()
|
||||
if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) {
|
||||
eventHtmlRenderer?.render(messageContent.formattedBody
|
||||
?: messageContent.body)
|
||||
|
@ -72,7 +72,7 @@ data class MessageActionState(
|
|||
EventType.CALL_INVITE,
|
||||
EventType.CALL_HANGUP,
|
||||
EventType.CALL_ANSWER -> {
|
||||
noticeEventFormatter?.format(timelineEvent)
|
||||
timelineEvent()?.let { noticeEventFormatter?.format(it) }
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
@ -85,10 +85,14 @@ data class MessageActionState(
|
|||
class MessageActionsViewModel @AssistedInject constructor(@Assisted
|
||||
initialState: MessageActionState,
|
||||
private val eventHtmlRenderer: EventHtmlRenderer,
|
||||
private val session: Session,
|
||||
session: Session,
|
||||
private val noticeEventFormatter: NoticeEventFormatter
|
||||
) : VectorViewModel<MessageActionState>(initialState) {
|
||||
|
||||
|
||||
private val eventId = initialState.eventId
|
||||
private val room = session.getRoom(initialState.roomId)
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(initialState: MessageActionState): MessageActionsViewModel
|
||||
|
@ -101,18 +105,19 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
|
|||
return fragment.messageActionViewModelFactory.create(state)
|
||||
}
|
||||
|
||||
override fun initialState(viewModelContext: ViewModelContext): MessageActionState? {
|
||||
val session = (viewModelContext.activity as HasScreenInjector).injector().session()
|
||||
val args: TimelineEventFragmentArgs = viewModelContext.args()
|
||||
val event = session.getRoom(args.roomId)?.getTimeLineEvent(args.eventId)
|
||||
return MessageActionState(
|
||||
args.roomId,
|
||||
args.eventId,
|
||||
args.informationData,
|
||||
event
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
observeEvent()
|
||||
}
|
||||
|
||||
private fun observeEvent() {
|
||||
if (room == null) return
|
||||
RxRoom(room)
|
||||
.liveTimelineEvent(eventId)
|
||||
.execute {
|
||||
copy(timelineEvent = it)
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveBody(state: MessageActionState): CharSequence? {
|
||||
|
|
|
@ -55,7 +55,8 @@ class MessageMenuFragment : VectorBaseFragment() {
|
|||
val inflater = LayoutInflater.from(linearLayout.context)
|
||||
linearLayout.removeAllViews()
|
||||
var insertIndex = 0
|
||||
state.actions.forEachIndexed { index, action ->
|
||||
val actions = state.actions()
|
||||
actions?.forEachIndexed { index, action ->
|
||||
inflateActionView(action, inflater, linearLayout)?.let {
|
||||
it.setOnClickListener {
|
||||
interactionListener?.didSelectMenuAction(action)
|
||||
|
@ -63,7 +64,7 @@ class MessageMenuFragment : VectorBaseFragment() {
|
|||
linearLayout.addView(it, insertIndex)
|
||||
insertIndex++
|
||||
if (addSeparators) {
|
||||
if (index < state.actions.size - 1) {
|
||||
if (index < actions.size - 1) {
|
||||
linearLayout.addView(inflateSeparatorView(), insertIndex)
|
||||
insertIndex++
|
||||
}
|
||||
|
|
|
@ -15,10 +15,7 @@
|
|||
*/
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.action
|
||||
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.airbnb.mvrx.*
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
|
@ -30,6 +27,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageImageConte
|
|||
import im.vector.matrix.android.api.session.room.model.message.MessageType
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.rx.RxRoom
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
|
@ -44,7 +42,7 @@ data class MessageMenuState(
|
|||
val roomId: String,
|
||||
val eventId: String,
|
||||
val informationData: MessageInformationData,
|
||||
val actions: List<SimpleAction> = emptyList()
|
||||
val actions: Async<List<SimpleAction>> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId, informationData = args.informationData)
|
||||
|
@ -63,6 +61,12 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
|||
fun create(initialState: MessageMenuState): MessageMenuViewModel
|
||||
}
|
||||
|
||||
private val room = session.getRoom(initialState.roomId)
|
||||
?: throw IllegalStateException("Shouldn't use this ViewModel without a room")
|
||||
|
||||
private val eventId = initialState.eventId
|
||||
private val informationData: MessageInformationData = initialState.informationData
|
||||
|
||||
companion object : MvRxViewModelFactory<MessageMenuViewModel, MessageMenuState> {
|
||||
|
||||
const val ACTION_ADD_REACTION = "add_reaction"
|
||||
|
@ -87,13 +91,23 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
|||
}
|
||||
|
||||
init {
|
||||
setState { reduceState(this) }
|
||||
observeEvent()
|
||||
}
|
||||
|
||||
private fun reduceState(state: MessageMenuState): MessageMenuState {
|
||||
val event = session.getRoom(state.roomId)?.getTimeLineEvent(state.eventId) ?: return state
|
||||
private fun observeEvent() {
|
||||
RxRoom(room)
|
||||
.liveTimelineEvent(eventId)
|
||||
?.map {
|
||||
actionsForEvent(it)
|
||||
}
|
||||
?.execute {
|
||||
copy(actions = it)
|
||||
}
|
||||
}
|
||||
|
||||
val messageContent: MessageContent? = event.annotations?.editSummary?.aggregatedContent?.toModel()
|
||||
private fun actionsForEvent(event: TimelineEvent): List<SimpleAction> {
|
||||
|
||||
val messageContent: MessageContent? = event.annotations?.editSummary?.aggregatedContent.toModel()
|
||||
?: event.root.getClearContent().toModel()
|
||||
val type = messageContent?.type
|
||||
|
||||
|
@ -114,7 +128,7 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
|||
//TODO is downloading attachement?
|
||||
|
||||
if (canReact(event, messageContent)) {
|
||||
this.add(SimpleAction(ACTION_ADD_REACTION, R.string.message_add_reaction, R.drawable.ic_add_reaction, event.root.eventId))
|
||||
this.add(SimpleAction(ACTION_ADD_REACTION, R.string.message_add_reaction, R.drawable.ic_add_reaction, eventId))
|
||||
}
|
||||
if (canCopy(type)) {
|
||||
//TODO copy images? html? see ClipBoard
|
||||
|
@ -122,23 +136,23 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
|||
}
|
||||
|
||||
if (canReply(event, messageContent)) {
|
||||
this.add(SimpleAction(ACTION_REPLY, R.string.reply, R.drawable.ic_reply, event.root.eventId))
|
||||
this.add(SimpleAction(ACTION_REPLY, R.string.reply, R.drawable.ic_reply, eventId))
|
||||
}
|
||||
|
||||
if (canEdit(event, session.sessionParams.credentials.userId)) {
|
||||
this.add(SimpleAction(ACTION_EDIT, R.string.edit, R.drawable.ic_edit, event.root.eventId))
|
||||
this.add(SimpleAction(ACTION_EDIT, R.string.edit, R.drawable.ic_edit, eventId))
|
||||
}
|
||||
|
||||
if (canRedact(event, session.sessionParams.credentials.userId)) {
|
||||
this.add(SimpleAction(ACTION_DELETE, R.string.delete, R.drawable.ic_delete, event.root.eventId))
|
||||
this.add(SimpleAction(ACTION_DELETE, R.string.delete, R.drawable.ic_delete, eventId))
|
||||
}
|
||||
|
||||
if (canQuote(event, messageContent)) {
|
||||
this.add(SimpleAction(ACTION_QUOTE, R.string.quote, R.drawable.ic_quote, state.eventId))
|
||||
this.add(SimpleAction(ACTION_QUOTE, R.string.quote, R.drawable.ic_quote, eventId))
|
||||
}
|
||||
|
||||
if (canViewReactions(event)) {
|
||||
this.add(SimpleAction(ACTION_VIEW_REACTIONS, R.string.message_view_reaction, R.drawable.ic_view_reactions, state.informationData))
|
||||
this.add(SimpleAction(ACTION_VIEW_REACTIONS, R.string.message_view_reaction, R.drawable.ic_view_reactions, informationData))
|
||||
}
|
||||
|
||||
if (canShare(type)) {
|
||||
|
@ -160,22 +174,22 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
|||
//TODO sent by me or sufficient power level
|
||||
}
|
||||
|
||||
this.add(SimpleAction(VIEW_SOURCE, R.string.view_source, R.drawable.ic_view_source, JSONObject(event.root.toContent()).toString(4)))
|
||||
this.add(SimpleAction(VIEW_SOURCE, R.string.view_source, R.drawable.ic_view_source, JSONObject(event.root.content.toContent()).toString(4)))
|
||||
if (event.isEncrypted()) {
|
||||
val decryptedContent = event.root.mClearEvent?.toContent()?.let {
|
||||
val decryptedContent = event.root.mClearEvent?.content?.toContent().let {
|
||||
JSONObject(it).toString(4)
|
||||
} ?: stringProvider.getString(R.string.encryption_information_decryption_error)
|
||||
this.add(SimpleAction(VIEW_DECRYPTED_SOURCE, R.string.view_decrypted_source, R.drawable.ic_view_source, decryptedContent))
|
||||
}
|
||||
this.add(SimpleAction(ACTION_COPY_PERMALINK, R.string.permalink, R.drawable.ic_permalink, state.eventId))
|
||||
this.add(SimpleAction(ACTION_COPY_PERMALINK, R.string.permalink, R.drawable.ic_permalink, event.root.eventId))
|
||||
|
||||
if (session.sessionParams.credentials.userId != event.root.senderId && event.root.getClearType() == EventType.MESSAGE) {
|
||||
//not sent by me
|
||||
this.add(SimpleAction(ACTION_FLAG, R.string.report_content, R.drawable.ic_flag, state.eventId))
|
||||
this.add(SimpleAction(ACTION_FLAG, R.string.report_content, R.drawable.ic_flag, event.root.eventId))
|
||||
}
|
||||
}
|
||||
}
|
||||
return state.copy(actions = actions)
|
||||
return actions
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ class QuickReactionFragment : VectorBaseFragment() {
|
|||
injector.inject(this)
|
||||
}
|
||||
|
||||
lateinit var textViews: List<TextView>
|
||||
private lateinit var textViews: List<TextView>
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -63,7 +63,8 @@ class QuickReactionFragment : VectorBaseFragment() {
|
|||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) {
|
||||
it.quickStates.forEachIndexed { index, qs ->
|
||||
val quickReactionsStates = it.quickStates() ?: return@withState
|
||||
quickReactionsStates.forEachIndexed { index, qs ->
|
||||
textViews[index].text = qs.reaction
|
||||
textViews[index].alpha = if (qs.isSelected) 0.2f else 1f
|
||||
}
|
||||
|
|
|
@ -15,13 +15,11 @@
|
|||
*/
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.action
|
||||
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.airbnb.mvrx.*
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.rx.RxRoom
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||
|
||||
|
@ -37,7 +35,7 @@ data class QuickReactionState(
|
|||
val roomId: String,
|
||||
val eventId: String,
|
||||
val informationData: MessageInformationData,
|
||||
val quickStates: List<ToggleState> = emptyList(),
|
||||
val quickStates: Async<List<ToggleState>> = Uninitialized,
|
||||
val result: ToggleState? = null
|
||||
/** Pair of 'clickedOn' and current toggles state*/
|
||||
) : MvRxState {
|
||||
|
@ -56,6 +54,9 @@ class QuickReactionViewModel @AssistedInject constructor(@Assisted initialState:
|
|||
fun create(initialState: QuickReactionState): QuickReactionViewModel
|
||||
}
|
||||
|
||||
private val room = session.getRoom(initialState.roomId)
|
||||
private val eventId = initialState.eventId
|
||||
|
||||
companion object : MvRxViewModelFactory<QuickReactionViewModel, QuickReactionState> {
|
||||
|
||||
val quickEmojis = listOf("👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀")
|
||||
|
@ -67,22 +68,30 @@ class QuickReactionViewModel @AssistedInject constructor(@Assisted initialState:
|
|||
}
|
||||
|
||||
init {
|
||||
setState { reduceState(this) }
|
||||
observeReactions()
|
||||
}
|
||||
|
||||
private fun reduceState(state: QuickReactionState): QuickReactionState {
|
||||
val event = session.getRoom(state.roomId)?.getTimeLineEvent(state.eventId) ?: return state
|
||||
val summary = event.annotations?.reactionsSummary
|
||||
val quickReactions = quickEmojis.map { emoji ->
|
||||
ToggleState(emoji, summary?.firstOrNull { it.key == emoji }?.addedByMe ?: false)
|
||||
}
|
||||
return state.copy(quickStates = quickReactions)
|
||||
private fun observeReactions() {
|
||||
if (room == null) return
|
||||
RxRoom(room)
|
||||
.liveAnnotationSummary(eventId)
|
||||
.map { annotations ->
|
||||
quickEmojis.map { emoji ->
|
||||
ToggleState(emoji, annotations.reactionsSummary.firstOrNull { it.key == emoji }?.addedByMe
|
||||
?: false)
|
||||
}
|
||||
}
|
||||
.execute {
|
||||
copy(quickStates = it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun didSelect(index: Int) = withState {
|
||||
val isSelected = it.quickStates[index].isSelected
|
||||
val selectedReaction = it.quickStates()?.get(index) ?: return@withState
|
||||
val isSelected = selectedReaction.isSelected
|
||||
setState {
|
||||
copy(result = ToggleState(it.quickStates[index].reaction, !isSelected))
|
||||
copy(result = ToggleState(selectedReaction.reaction, !isSelected))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,10 +85,8 @@ class ViewReactionViewModel @AssistedInject constructor(@Assisted
|
|||
.liveAnnotationSummary(eventId)
|
||||
.flatMapSingle { summaries ->
|
||||
Observable
|
||||
.fromIterable(summaries)
|
||||
.flatMapIterable { it.reactionsSummary
|
||||
.filter { reactionAggregatedSummary -> isSingleEmoji(reactionAggregatedSummary.key) }
|
||||
}
|
||||
.fromIterable(summaries.reactionsSummary)
|
||||
.filter { reactionAggregatedSummary -> isSingleEmoji(reactionAggregatedSummary.key) }
|
||||
.toReactionInfoList()
|
||||
}
|
||||
.execute {
|
||||
|
@ -112,7 +110,6 @@ class ViewReactionViewModel @AssistedInject constructor(@Assisted
|
|||
timelineDateFormatter.formatMessageHour(localDate)
|
||||
)
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
}.toList()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue