Fix / impure reducer in action view model

This commit is contained in:
Valere 2019-06-28 14:09:26 +02:00
parent a9dd06562a
commit f83491fdfc
4 changed files with 71 additions and 61 deletions

View file

@ -152,6 +152,8 @@ data class Event(
mClaimedEd25519Key = decryptionResult.claimedEd25519Key mClaimedEd25519Key = decryptionResult.claimedEd25519Key
mForwardingCurve25519KeyChain = decryptionResult.forwardingCurve25519KeyChain mForwardingCurve25519KeyChain = decryptionResult.forwardingCurve25519KeyChain
// For encrypted events with relation, the m.relates_to is kept in clear, so we need to put it back
// in the clear event
try { try {
content?.get("m.relates_to")?.let { clearRelates -> content?.get("m.relates_to")?.let { clearRelates ->
mClearEvent = mClearEvent?.copy( mClearEvent = mClearEvent?.copy(

View file

@ -45,8 +45,10 @@ import javax.inject.Inject
*/ */
class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment() { class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment() {
@Inject lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory @Inject
@Inject lateinit var avatarRenderer: AvatarRenderer lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory
@Inject
lateinit var avatarRenderer: AvatarRenderer
private val viewModel: MessageActionsViewModel by fragmentViewModel(MessageActionsViewModel::class) private val viewModel: MessageActionsViewModel by fragmentViewModel(MessageActionsViewModel::class)
private lateinit var actionHandlerModel: ActionsHandler private lateinit var actionHandlerModel: ActionsHandler
@ -124,17 +126,18 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment() {
} }
override fun invalidate() = withState(viewModel) { override fun invalidate() = withState(viewModel) {
if (it.showPreview) { val body = viewModel.resolveBody(it)
if (body != null) {
bottom_sheet_message_preview.isVisible = true bottom_sheet_message_preview.isVisible = true
senderNameTextView.text = it.senderName senderNameTextView.text = it.senderName()
messageBodyTextView.text = it.messageBody messageBodyTextView.text = body
messageTimestampText.text = it.ts messageTimestampText.text = it.time()
avatarRenderer.render(it.senderAvatarPath, it.userId, it.senderName, senderAvatarImageView) avatarRenderer.render(it.informationData.avatarUrl, it.informationData.senderId, it.senderName(), senderAvatarImageView)
} else { } else {
bottom_sheet_message_preview.isVisible = false bottom_sheet_message_preview.isVisible = false
} }
quickReactBottomDivider.isVisible = it.canReact quickReactBottomDivider.isVisible = it.canReact()
bottom_sheet_quick_reaction_container.isVisible = it.canReact bottom_sheet_quick_reaction_container.isVisible = it.canReact()
return@withState return@withState
} }

View file

@ -27,6 +27,8 @@ import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.message.MessageContent 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.MessageTextContent
import im.vector.matrix.android.api.session.room.model.message.MessageType 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.riotredesign.core.platform.VectorViewModel 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.format.NoticeEventFormatter
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
@ -35,21 +37,45 @@ import java.text.SimpleDateFormat
import java.util.* import java.util.*
val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault())
data class MessageActionState( data class MessageActionState(
val roomId: String, val roomId: String,
val eventId: String, val eventId: String,
val informationData: MessageInformationData, val informationData: MessageInformationData,
val userId: String = "", val timelineEvent: TimelineEvent?
val senderName: String = "", ) : MvRxState {
val messageBody: CharSequence? = null,
val ts: String? = null,
val showPreview: Boolean = false,
val canReact: Boolean = false,
val senderAvatarPath: String? = null)
: MvRxState {
constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId, informationData = args.informationData) fun senderName(): String = informationData.memberName?.toString() ?: ""
fun time(): String? = dateFormat.format(Date(timelineEvent?.root?.originServerTs ?: 0))
fun canReact(): Boolean = timelineEvent?.root?.type == EventType.MESSAGE && timelineEvent.sendState.isSent()
fun messageBody(eventHtmlRenderer: EventHtmlRenderer?, noticeEventFormatter: NoticeEventFormatter?): CharSequence? {
return when (timelineEvent?.root?.getClearType()) {
EventType.MESSAGE -> {
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)
} else {
messageContent?.body
}
}
EventType.STATE_ROOM_NAME,
EventType.STATE_ROOM_TOPIC,
EventType.STATE_ROOM_MEMBER,
EventType.STATE_HISTORY_VISIBILITY,
EventType.CALL_INVITE,
EventType.CALL_HANGUP,
EventType.CALL_ANSWER -> {
noticeEventFormatter?.format(timelineEvent)
}
else -> null
}
}
} }
/** /**
@ -62,10 +88,6 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
private val noticeEventFormatter: NoticeEventFormatter private val noticeEventFormatter: NoticeEventFormatter
) : VectorViewModel<MessageActionState>(initialState) { ) : VectorViewModel<MessageActionState>(initialState) {
private val roomId = initialState.roomId
private val eventId = initialState.eventId
private val informationData = initialState.informationData
@AssistedInject.Factory @AssistedInject.Factory
interface Factory { interface Factory {
fun create(initialState: MessageActionState): MessageActionsViewModel fun create(initialState: MessageActionState): MessageActionsViewModel
@ -77,47 +99,23 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
val fragment: MessageActionsBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() val fragment: MessageActionsBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
return fragment.messageActionViewModelFactory.create(state) return fragment.messageActionViewModelFactory.create(state)
} }
}
override fun initialState(viewModelContext: ViewModelContext): MessageActionState? {
init { val session = (viewModelContext.activity as HasScreenInjector).injector().session()
setState { reduceState(this) } val args: TimelineEventFragmentArgs = viewModelContext.args()
} val event = session.getRoom(args.roomId)?.getTimeLineEvent(args.eventId)
return MessageActionState(
private fun reduceState(state: MessageActionState): MessageActionState { args.roomId,
val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault()) args.eventId,
val event = session.getRoom(roomId)?.getTimeLineEvent(eventId) ?: return state args.informationData,
var body: CharSequence? = null event
val originTs = event.root.originServerTs )
when (event.root.getClearType()) {
EventType.MESSAGE -> {
val messageContent: MessageContent? = event.annotations?.editSummary?.aggregatedContent?.toModel()
?: event.root.getClearContent().toModel()
body = messageContent?.body
if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) {
body = eventHtmlRenderer.render(messageContent.formattedBody
?: messageContent.body)
}
}
EventType.STATE_ROOM_NAME,
EventType.STATE_ROOM_TOPIC,
EventType.STATE_ROOM_MEMBER,
EventType.STATE_HISTORY_VISIBILITY,
EventType.CALL_INVITE,
EventType.CALL_HANGUP,
EventType.CALL_ANSWER -> {
body = noticeEventFormatter.format(event)
}
} }
return state.copy(
userId = event.root.senderId ?: "", }
senderName = informationData.memberName?.toString() ?: "",
messageBody = body, fun resolveBody(state: MessageActionState): CharSequence? {
ts = dateFormat.format(Date(originTs ?: 0)), return state.messageBody(eventHtmlRenderer, noticeEventFormatter)
showPreview = body != null,
canReact = event.root.type == EventType.MESSAGE && event.sendState.isSent(),
senderAvatarPath = informationData.avatarUrl
)
} }
} }

View file

@ -15,8 +15,10 @@
*/ */
package im.vector.riotredesign.features.home.room.detail.timeline.action package im.vector.riotredesign.features.home.room.detail.timeline.action
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
@ -77,6 +79,11 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
const val ACTION_FLAG = "ACTION_FLAG" const val ACTION_FLAG = "ACTION_FLAG"
const val ACTION_QUICK_REACT = "ACTION_QUICK_REACT" const val ACTION_QUICK_REACT = "ACTION_QUICK_REACT"
const val ACTION_VIEW_REACTIONS = "ACTION_VIEW_REACTIONS" const val ACTION_VIEW_REACTIONS = "ACTION_VIEW_REACTIONS"
override fun create(viewModelContext: ViewModelContext, state: MessageMenuState): MessageMenuViewModel? {
val fragment: MessageMenuFragment = (viewModelContext as FragmentViewModelContext).fragment()
return fragment.messageMenuViewModelFactory.create(state)
}
} }
init { init {