From f83491fdfcf3177c7afa239158ffd836fa81e04f Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 28 Jun 2019 14:09:26 +0200 Subject: [PATCH] Fix / impure reducer in action view model --- .../android/api/session/events/model/Event.kt | 2 + .../action/MessageActionsBottomSheet.kt | 21 ++-- .../action/MessageActionsViewModel.kt | 102 +++++++++--------- .../timeline/action/MessageMenuViewModel.kt | 7 ++ 4 files changed, 71 insertions(+), 61 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/Event.kt index 9b6e364e38..a93b3e7d8f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/Event.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/Event.kt @@ -152,6 +152,8 @@ data class Event( mClaimedEd25519Key = decryptionResult.claimedEd25519Key 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 { content?.get("m.relates_to")?.let { clearRelates -> mClearEvent = mClearEvent?.copy( diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt index 9ae2e4e575..391a680e16 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt @@ -45,8 +45,10 @@ import javax.inject.Inject */ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment() { - @Inject lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory - @Inject lateinit var avatarRenderer: AvatarRenderer + @Inject + lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory + @Inject + lateinit var avatarRenderer: AvatarRenderer private val viewModel: MessageActionsViewModel by fragmentViewModel(MessageActionsViewModel::class) private lateinit var actionHandlerModel: ActionsHandler @@ -124,17 +126,18 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment() { } override fun invalidate() = withState(viewModel) { - if (it.showPreview) { + val body = viewModel.resolveBody(it) + if (body != null) { bottom_sheet_message_preview.isVisible = true - senderNameTextView.text = it.senderName - messageBodyTextView.text = it.messageBody - messageTimestampText.text = it.ts - avatarRenderer.render(it.senderAvatarPath, it.userId, it.senderName, senderAvatarImageView) + senderNameTextView.text = it.senderName() + messageBodyTextView.text = body + messageTimestampText.text = it.time() + avatarRenderer.render(it.informationData.avatarUrl, it.informationData.senderId, it.senderName(), senderAvatarImageView) } else { bottom_sheet_message_preview.isVisible = false } - quickReactBottomDivider.isVisible = it.canReact - bottom_sheet_quick_reaction_container.isVisible = it.canReact + quickReactBottomDivider.isVisible = it.canReact() + bottom_sheet_quick_reaction_container.isVisible = it.canReact() return@withState } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index 16dd5d1bbd..bc0091b8e7 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -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.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.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 @@ -35,21 +37,45 @@ 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 userId: String = "", - val senderName: String = "", - val messageBody: CharSequence? = null, - val ts: String? = null, - val showPreview: Boolean = false, - val canReact: Boolean = false, - val senderAvatarPath: String? = null) - : MvRxState { + val timelineEvent: TimelineEvent? +) : 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 ) : VectorViewModel(initialState) { - private val roomId = initialState.roomId - private val eventId = initialState.eventId - private val informationData = initialState.informationData - @AssistedInject.Factory interface Factory { fun create(initialState: MessageActionState): MessageActionsViewModel @@ -77,47 +99,23 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted val fragment: MessageActionsBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() return fragment.messageActionViewModelFactory.create(state) } - } - - init { - setState { reduceState(this) } - } - - private fun reduceState(state: MessageActionState): MessageActionState { - val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault()) - val event = session.getRoom(roomId)?.getTimeLineEvent(eventId) ?: return state - var body: CharSequence? = null - 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) - } + 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 + ) } - return state.copy( - userId = event.root.senderId ?: "", - senderName = informationData.memberName?.toString() ?: "", - messageBody = body, - ts = dateFormat.format(Date(originTs ?: 0)), - showPreview = body != null, - canReact = event.root.type == EventType.MESSAGE && event.sendState.isSent(), - senderAvatarPath = informationData.avatarUrl - ) + + } + + fun resolveBody(state: MessageActionState): CharSequence? { + return state.messageBody(eventHtmlRenderer, noticeEventFormatter) } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt index e01203711d..c0f8baa9b2 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt @@ -15,8 +15,10 @@ */ 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.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject 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_QUICK_REACT = "ACTION_QUICK_REACT" 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 {