Merge pull request #2053 from vector-im/feature/fix_poll_reply

Feature/fix poll reply
This commit is contained in:
Benoit Marty 2020-09-08 12:19:32 +02:00 committed by GitHub
commit 00b53ee577
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 25 deletions

View File

@ -7,7 +7,7 @@ Features ✨:
Improvements 🙌: Improvements 🙌:
- You can now join room through permalink and within room directory search - You can now join room through permalink and within room directory search
- Add long click gesture to copy userId, user display name, room name, room topic and room alias (#1774) - Add long click gesture to copy userId, user display name, room name, room topic and room alias (#1774)
- Fix several issues when uploading bug files (#1889) - Fix several issues when uploading big files (#1889)
- Do not propose to verify session if there is only one session and 4S is not configured (#1901) - Do not propose to verify session if there is only one session and 4S is not configured (#1901)
- Call screen does not use proximity sensor (#1735) - Call screen does not use proximity sensor (#1735)
@ -27,6 +27,8 @@ Bugfix 🐛:
- Support for image compression on Android 10 - Support for image compression on Android 10
- Verification popup won't show - Verification popup won't show
- Android 6: App crash when read Contact permission is granted (#2064) - Android 6: App crash when read Contact permission is granted (#2064)
- JSON for verification events leaks in to the room list (#1246)
- Replies to poll appears in timeline as unsupported events during sending (#1004)
Translations 🗣: Translations 🗣:
- The SDK is now using SAS string translations from [Weblate Matrix-doc project](https://translate.riot.im/projects/matrix-doc/) (#1909) - The SDK is now using SAS string translations from [Weblate Matrix-doc project](https://translate.riot.im/projects/matrix-doc/) (#1909)

View File

@ -347,7 +347,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
if (userId == senderId) { if (userId == senderId) {
sumModel.myVote = optionIndex sumModel.myVote = optionIndex
} }
Timber.v("## POLL adding vote $optionIndex for user $senderId in poll :$relatedEventId ") Timber.v("## POLL adding vote $optionIndex for user $senderId in poll :$targetEventId ")
} else { } else {
Timber.v("## POLL Ignoring vote (older than known one) eventId:$eventId ") Timber.v("## POLL Ignoring vote (older than known one) eventId:$eventId ")
} }
@ -356,7 +356,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
if (userId == senderId) { if (userId == senderId) {
sumModel.myVote = optionIndex sumModel.myVote = optionIndex
} }
Timber.v("## POLL adding vote $optionIndex for user $senderId in poll :$relatedEventId ") Timber.v("## POLL adding vote $optionIndex for user $senderId in poll :$targetEventId ")
} }
sumModel.votes = votes sumModel.votes = votes
if (isLocalEcho) { if (isLocalEcho) {

View File

@ -17,6 +17,16 @@
package org.matrix.android.sdk.internal.session.room.timeline package org.matrix.android.sdk.internal.session.room.timeline
import io.realm.OrderedCollectionChangeSet
import io.realm.OrderedRealmCollectionChangeListener
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.RealmQuery
import io.realm.RealmResults
import io.realm.Sort
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
@ -44,16 +54,6 @@ import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.util.Debouncer import org.matrix.android.sdk.internal.util.Debouncer
import org.matrix.android.sdk.internal.util.createBackgroundHandler import org.matrix.android.sdk.internal.util.createBackgroundHandler
import org.matrix.android.sdk.internal.util.createUIHandler import org.matrix.android.sdk.internal.util.createUIHandler
import io.realm.OrderedCollectionChangeSet
import io.realm.OrderedRealmCollectionChangeListener
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.RealmQuery
import io.realm.RealmResults
import io.realm.Sort
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import timber.log.Timber import timber.log.Timber
import java.util.Collections import java.util.Collections
import java.util.UUID import java.util.UUID
@ -317,12 +317,15 @@ internal class DefaultTimeline(
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
fun onLocalEchoCreated(onLocalEchoCreated: OnLocalEchoCreated) { fun onLocalEchoCreated(onLocalEchoCreated: OnLocalEchoCreated) {
if (isLive && onLocalEchoCreated.roomId == roomId) { if (isLive && onLocalEchoCreated.roomId == roomId) {
listeners.forEach { // do not add events that would have been filtered
it.onNewTimelineEvents(listOf(onLocalEchoCreated.timelineEvent.eventId)) if (listOf(onLocalEchoCreated.timelineEvent).filterEventsWithSettings().isNotEmpty()) {
listeners.forEach {
it.onNewTimelineEvents(listOf(onLocalEchoCreated.timelineEvent.eventId))
}
Timber.v("On local echo created: ${onLocalEchoCreated.timelineEvent.eventId}")
inMemorySendingEvents.add(0, onLocalEchoCreated.timelineEvent)
postSnapshot()
} }
Timber.v("On local echo created: $onLocalEchoCreated")
inMemorySendingEvents.add(0, onLocalEchoCreated.timelineEvent)
postSnapshot()
} }
} }
@ -778,7 +781,7 @@ internal class DefaultTimeline(
val filterEdits = if (settings.filterEdits && it.root.type == EventType.MESSAGE) { val filterEdits = if (settings.filterEdits && it.root.type == EventType.MESSAGE) {
val messageContent = it.root.content.toModel<MessageContent>() val messageContent = it.root.content.toModel<MessageContent>()
messageContent?.relatesTo?.type != RelationType.REPLACE messageContent?.relatesTo?.type != RelationType.REPLACE && messageContent?.relatesTo?.type != RelationType.RESPONSE
} else { } else {
true true
} }

View File

@ -63,6 +63,7 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage
import org.matrix.android.sdk.api.session.events.model.LocalEcho
import org.matrix.android.sdk.api.session.events.model.isTextMessage import org.matrix.android.sdk.api.session.events.model.isTextMessage
import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
@ -1218,6 +1219,8 @@ class RoomDetailViewModel @AssistedInject constructor(
} }
private fun handleReplyToOptions(action: RoomDetailAction.ReplyToOptions) { private fun handleReplyToOptions(action: RoomDetailAction.ReplyToOptions) {
// Do not allow to reply to unsent local echo
if (LocalEcho.isLocalEchoId(action.eventId)) return
room.sendOptionsReply(action.eventId, action.optionIndex, action.optionValue) room.sendOptionsReply(action.eventId, action.optionIndex, action.optionValue)
} }

View File

@ -20,15 +20,17 @@ import im.vector.app.EmojiCompatWrapper
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import me.gujun.android.span.span
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.message.MessageOptionsContent
import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.model.message.MessageType
import org.matrix.android.sdk.api.session.room.model.message.OPTION_TYPE_BUTTONS
import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent
import org.matrix.android.sdk.api.session.room.timeline.isReply import org.matrix.android.sdk.api.session.room.timeline.isReply
import me.gujun.android.span.span
import javax.inject.Inject import javax.inject.Inject
class DisplayableEventFormatter @Inject constructor( class DisplayableEventFormatter @Inject constructor(
@ -51,16 +53,16 @@ class DisplayableEventFormatter @Inject constructor(
val senderName = timelineEvent.senderInfo.disambiguatedDisplayName val senderName = timelineEvent.senderInfo.disambiguatedDisplayName
when (timelineEvent.root.getClearType()) { when (timelineEvent.root.getClearType()) {
EventType.STICKER -> { EventType.STICKER -> {
return simpleFormat(senderName, stringProvider.getString(R.string.send_a_sticker), appendAuthor) return simpleFormat(senderName, stringProvider.getString(R.string.send_a_sticker), appendAuthor)
} }
EventType.REACTION -> { EventType.REACTION -> {
timelineEvent.root.getClearContent().toModel<ReactionContent>()?.relatesTo?.let { timelineEvent.root.getClearContent().toModel<ReactionContent>()?.relatesTo?.let {
val emojiSpanned = emojiCompatWrapper.safeEmojiSpanify(it.key) val emojiSpanned = emojiCompatWrapper.safeEmojiSpanify(stringProvider.getString(R.string.sent_a_reaction, it.key))
return simpleFormat(senderName, emojiSpanned, appendAuthor) return simpleFormat(senderName, emojiSpanned, appendAuthor)
} }
} }
EventType.MESSAGE -> { EventType.MESSAGE -> {
timelineEvent.getLastMessageContent()?.let { messageContent -> timelineEvent.getLastMessageContent()?.let { messageContent ->
when (messageContent.msgType) { when (messageContent.msgType) {
MessageType.MSGTYPE_VERIFICATION_REQUEST -> { MessageType.MSGTYPE_VERIFICATION_REQUEST -> {
@ -88,13 +90,45 @@ class DisplayableEventFormatter @Inject constructor(
simpleFormat(senderName, messageContent.body, appendAuthor) simpleFormat(senderName, messageContent.body, appendAuthor)
} }
} }
MessageType.MSGTYPE_RESPONSE -> {
// do not show that?
return span { }
}
MessageType.MSGTYPE_OPTIONS -> {
return when (messageContent) {
is MessageOptionsContent -> {
val previewText = if (messageContent.optionType == OPTION_TYPE_BUTTONS) {
stringProvider.getString(R.string.sent_a_bot_buttons)
} else {
stringProvider.getString(R.string.sent_a_poll)
}
simpleFormat(senderName, previewText, appendAuthor)
}
else -> {
span { }
}
}
}
else -> { else -> {
return simpleFormat(senderName, messageContent.body, appendAuthor) return simpleFormat(senderName, messageContent.body, appendAuthor)
} }
} }
} }
} }
else -> { EventType.KEY_VERIFICATION_CANCEL,
EventType.KEY_VERIFICATION_DONE -> {
// cancel and done can appear in timeline, so should have representation
return simpleFormat(senderName, stringProvider.getString(R.string.sent_verification_conclusion), appendAuthor)
}
EventType.KEY_VERIFICATION_START,
EventType.KEY_VERIFICATION_ACCEPT,
EventType.KEY_VERIFICATION_MAC,
EventType.KEY_VERIFICATION_KEY,
EventType.KEY_VERIFICATION_READY,
EventType.CALL_CANDIDATES -> {
return span { }
}
else -> {
return span { return span {
text = noticeEventFormatter.format(timelineEvent) ?: "" text = noticeEventFormatter.format(timelineEvent) ?: ""
textStyle = "italic" textStyle = "italic"

View File

@ -75,6 +75,8 @@ abstract class MessagePollItem : AbsMessageItem<MessagePollItem.Holder>() {
optionsContent?.options?.forEachIndexed { index, item -> optionsContent?.options?.forEachIndexed { index, item ->
if (index < buttons.size) { if (index < buttons.size) {
buttons[index].let { buttons[index].let {
// current limitation, have to wait for event to be sent in order to reply
it.isEnabled = informationData?.sendState?.isSent() ?: false
it.text = item.label it.text = item.label
it.isVisible = true it.isVisible = true
} }

View File

@ -2067,6 +2067,10 @@
<string name="sent_an_audio_file">Audio</string> <string name="sent_an_audio_file">Audio</string>
<string name="sent_a_file">File</string> <string name="sent_a_file">File</string>
<string name="send_a_sticker">Sticker</string> <string name="send_a_sticker">Sticker</string>
<string name="sent_a_poll">Poll</string>
<string name="sent_a_bot_buttons">Bot Buttons</string>
<string name="sent_a_reaction">Reacted with: %s</string>
<string name="sent_verification_conclusion">Verification Conclusion</string>
<string name="verification_request_waiting">Waiting…</string> <string name="verification_request_waiting">Waiting…</string>
<string name="verification_request_other_cancelled">%s cancelled</string> <string name="verification_request_other_cancelled">%s cancelled</string>