mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +03:00
Fix / impure reducer in action view model
This commit is contained in:
parent
a9dd06562a
commit
f83491fdfc
4 changed files with 71 additions and 61 deletions
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue