Undo Reaction

This commit is contained in:
Valere
2019-05-17 17:15:44 +02:00
parent 207579c59f
commit 6eafa3c43d
29 changed files with 587 additions and 75 deletions

View File

@ -28,7 +28,10 @@ sealed class RoomDetailActions {
data class EventDisplayed(val event: TimelineEvent) : RoomDetailActions()
data class LoadMore(val direction: Timeline.Direction) : RoomDetailActions()
data class SendReaction(val reaction: String, val targetEventId: String) : RoomDetailActions()
data class RedactAction(val targetEventId: String, val reason: String? = "") : RoomDetailActions()
data class UndoReaction(val targetEventId: String, val key: String, val reason: String? = "") : RoomDetailActions()
object AcceptInvite : RoomDetailActions()
object RejectInvite : RoomDetailActions()
}

View File

@ -521,7 +521,8 @@ class RoomDetailFragment :
//we should test the current real state of reaction on this event
roomDetailViewModel.process(RoomDetailActions.SendReaction(reaction, informationData.eventId))
} else {
//TODO it's an undo :/
//I need to redact a reaction
roomDetailViewModel.process(RoomDetailActions.UndoReaction(informationData.eventId,reaction))
}
}
@ -546,7 +547,11 @@ class RoomDetailFragment :
snack.view.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.notification_accent_color))
snack.show()
}
MessageMenuViewModel.ACTION_SHARE -> {
MessageMenuViewModel.ACTION_DELETE -> {
val eventId = actionData.data?.toString() ?: return
roomDetailViewModel.process(RoomDetailActions.RedactAction(eventId,context?.getString(R.string.event_redacted_by_user_reason)))
}
MessageMenuViewModel.ACTION_SHARE -> {
//TODO current data communication is too limited
//Need to now the media type
actionData.data?.toString()?.let {

View File

@ -80,6 +80,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
is RoomDetailActions.SendReaction -> handleSendReaction(action)
is RoomDetailActions.AcceptInvite -> handleAcceptInvite()
is RoomDetailActions.RejectInvite -> handleRejectInvite()
is RoomDetailActions.RedactAction -> handleRedactEvent(action)
}
}
@ -190,6 +191,16 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
room.sendReaction(action.reaction, action.targetEventId)
}
private fun handleRedactEvent(action: RoomDetailActions.RedactAction) {
val event = room.getTimeLineEvent(action.targetEventId) ?: return
room.redactEvent(event.root, action.reason)
}
private fun handleUndoReact(action: RoomDetailActions.UndoReaction) {
room.undoReaction(action.key, action.targetEventId, session.sessionParams.credentials.userId)
}
private fun handleSendMedia(action: RoomDetailActions.SendMedia) {
val attachments = action.mediaFiles.map {
ContentAttachmentData(

View File

@ -73,6 +73,10 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
this.add(SimpleAction(ACTION_COPY, R.string.copy, R.drawable.ic_copy, messageContent.body))
}
if(canRedact(event, currentSession.sessionParams.credentials.userId)) {
this.add(SimpleAction(ACTION_DELETE, R.string.delete, R.drawable.ic_material_delete, event.root.eventId))
}
if (canQuote(event, messageContent)) {
//TODO quote icon
this.add(SimpleAction(ACTION_QUOTE, R.string.quote, R.drawable.ic_quote, parcel.eventId))
@ -148,6 +152,14 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
}
}
private fun canRedact(event: TimelineEvent, myUserId: String): Boolean {
//Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment
if (event.root.type != EventType.MESSAGE) return false
//TODO if user is admin or moderator
return event.root.sender == myUserId
}
private fun canCopy(type: String): Boolean {
return when (type) {
MessageType.MSGTYPE_TEXT,
@ -162,6 +174,8 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
}
private fun canShare(type: String): Boolean {
return when (type) {
MessageType.MSGTYPE_IMAGE,

View File

@ -66,7 +66,6 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|| nextEvent?.root?.type != EventType.MESSAGE
|| isNextMessageReceivedMoreThanOneHourAgo
val messageContent: MessageContent = event.root.content.toModel() ?: return null
val time = timelineDateFormatter.formatMessageHour(date)
val avatarUrl = event.senderAvatar
val memberName = event.senderName ?: event.root.sender ?: ""
@ -84,8 +83,12 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
orderedReactionList = event.annotations?.reactionsSummary?.map { Triple(it.key, it.count, it.addedByMe) }
)
//Test for reactions UX
//informationData.orderedReactionList = listOf( Triple("👍",1,false), Triple("👎",2,false))
if (event.root.unsignedData?.redactedEvent != null) {
//message is redacted
return buildRedactedItem(informationData)
}
val messageContent: MessageContent = event.root.content.toModel() ?: return null
// val all = event.root.toContent()
// val ev = all.toModel<Event>()
@ -347,6 +350,11 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
}
}
private fun buildRedactedItem(informationData: MessageInformationData): RedactedMessageItem? {
return RedactedMessageItem_()
.informationData(informationData)
}
private fun linkifyBody(body: CharSequence, callback: TimelineEventController.Callback?): CharSequence {
val spannable = SpannableStringBuilder(body)
MatrixLinkify.addLinks(spannable, object : MatrixPermalinkSpan.Callback {

View File

@ -55,11 +55,11 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
var reactionClickListener: ReactionButton.ReactedListener = object : ReactionButton.ReactedListener {
override fun onReacted(reactionButton: ReactionButton) {
reactionPillCallback?.onClickOnReactionPill(informationData, reactionButton.reactionString,true)
reactionPillCallback?.onClickOnReactionPill(informationData, reactionButton.reactionString, true)
}
override fun onUnReacted(reactionButton: ReactionButton) {
reactionPillCallback?.onClickOnReactionPill(informationData, reactionButton.reactionString,false)
reactionPillCallback?.onClickOnReactionPill(informationData, reactionButton.reactionString, false)
}
}
@ -123,10 +123,6 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
}
}
override fun unbind(holder: H) {
super.unbind(holder)
}
protected fun View.renderSendState() {
isClickable = informationData.sendState.isSent()
alpha = if (informationData.sendState.isSent()) 1f else 0.5f

View File

@ -0,0 +1,22 @@
package im.vector.riotredesign.features.home.room.detail.timeline.item
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotredesign.R
@EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class RedactedMessageItem : AbsMessageItem<RedactedMessageItem.Holder>() {
@EpoxyAttribute
override lateinit var informationData: MessageInformationData
override fun getStubType(): Int = STUB_ID
class Holder : AbsMessageItem.Holder() {
override fun getStubId(): Int = STUB_ID
}
companion object {
private val STUB_ID = R.id.messageContentRedactedStub
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="10dp" />
<solid android:color="?vctr_list_divider_color" />
</shape>

View File

@ -81,6 +81,12 @@
android:layout="@layout/item_timeline_event_file_stub"
tools:ignore="MissingConstraints" />
<ViewStub
android:id="@+id/messageContentRedactedStub"
style="@style/TimelineContentStubLayoutParams"
android:layout_height="20dp"
android:layout="@layout/item_timeline_event_redacted_stub"
tools:ignore="MissingConstraints" />
<!-- TODO: For now we show 8 reactions maximum, this will need rework when needed-->

View File

@ -0,0 +1,5 @@
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="@drawable/redacted_background"
/>

View File

@ -13,4 +13,7 @@
<string name="reactions_like">Like</string>
<string name="message_add_reaction">Add Reaction</string>
<string name="event_redacted_by_user_reason">Event deleted by user</string>
<string name="event_redacted_by_admin_reason">Event moderated by room admin</string>
</resources>