From a8b111dc8c8a525b23537c1138eae08e23b5f9e8 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 10 Jan 2023 15:04:13 +0300 Subject: [PATCH] Code review fixes. --- .../src/main/res/values/strings.xml | 1 + .../sdk/api/session/events/model/Event.kt | 14 +++- .../timeline/factory/MessageItemFactory.kt | 6 +- .../timeline/format/EventDetailsFormatter.kt | 4 ++ .../helper/MessageInformationDataFactory.kt | 25 +------ .../helper/PollResponseDataFactory.kt | 67 +++++++++++++++++++ .../action/CheckIfCanReplyEventUseCaseTest.kt | 2 +- .../ProcessBodyOfReplyToEventUseCaseTest.kt | 11 +++ 8 files changed, 100 insertions(+), 30 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/PollResponseDataFactory.kt diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 81f4f27127..0a12e859b5 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3509,6 +3509,7 @@ sent a sticker. created a poll. ended a poll. + Poll Ended poll Access Token diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt index 357c2b9608..40c69ceb66 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt @@ -248,7 +248,7 @@ data class Event( if (isRedacted()) return "Message removed" val text = getDecryptedValue() ?: run { if (isPoll()) { - return getPollQuestion() ?: if (isPollStart()) "created a poll." else if (isPollEnd()) "ended a poll." else null + return getTextSummaryForPoll() } return null } @@ -261,13 +261,23 @@ data class Event( isImageMessage() -> "sent an image." isVideoMessage() -> "sent a video." isSticker() -> "sent a sticker." - isPoll() -> getPollQuestion() ?: if (isPollStart()) "created a poll." else if (isPollEnd()) "ended a poll." else null + isPoll() -> getTextSummaryForPoll() isLiveLocation() -> "Live location." isLocationMessage() -> "has shared their location." else -> text } } + private fun getTextSummaryForPoll(): String? { + val pollQuestion = getPollQuestion() + return when { + pollQuestion != null -> pollQuestion + isPollStart() -> "created a poll." + isPollEnd() -> "ended a poll." + else -> null + } + } + private fun Event.isQuote(): Boolean { if (isReplyRenderedInThread()) return false return getDecryptedValue("formatted_body")?.contains("
") ?: false diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 824547b8d0..219ccbe11c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -281,13 +281,9 @@ class MessageItemFactory @Inject constructor( val pollStartEvent = session.roomService().getRoom(roomId)?.getTimelineEvent(pollStartEventId) val pollContent = pollStartEvent?.root?.getClearContent()?.toModel() ?: return null - val aggregatedInformationData = informationData.copy( - pollResponseAggregatedSummary = messageInformationDataFactory.mapPollResponseSummary(pollStartEvent.annotations?.pollResponseSummary) - ) - return buildPollItem( pollContent, - aggregatedInformationData, + informationData, highlight, callback, attributes, diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/EventDetailsFormatter.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/EventDetailsFormatter.kt index f936093a3b..1d3f016951 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/EventDetailsFormatter.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/EventDetailsFormatter.kt @@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.events.model.isAudioMessage import org.matrix.android.sdk.api.session.events.model.isFileMessage import org.matrix.android.sdk.api.session.events.model.isImageMessage import org.matrix.android.sdk.api.session.events.model.isPollEnd +import org.matrix.android.sdk.api.session.events.model.isPollStart import org.matrix.android.sdk.api.session.events.model.isVideoMessage import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent @@ -53,11 +54,14 @@ class EventDetailsFormatter @Inject constructor( event.isVideoMessage() -> formatForVideoMessage(event) event.isAudioMessage() -> formatForAudioMessage(event) event.isFileMessage() -> formatForFileMessage(event) + event.isPollStart() -> formatPollMessage() event.isPollEnd() -> formatPollEndMessage() else -> null } } + private fun formatPollMessage() = context.getString(R.string.message_reply_to_poll_preview) + private fun formatPollEndMessage() = context.getString(R.string.message_reply_to_ended_poll_preview) /** diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index d356c8a7d2..3ee309425a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -23,8 +23,6 @@ import im.vector.app.core.extensions.localDateTime import im.vector.app.features.home.room.detail.timeline.factory.TimelineItemFactoryParams import im.vector.app.features.home.room.detail.timeline.item.E2EDecoration import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData -import im.vector.app.features.home.room.detail.timeline.item.PollResponseData -import im.vector.app.features.home.room.detail.timeline.item.PollVoteSummaryData import im.vector.app.features.home.room.detail.timeline.item.ReferencesInfoData import im.vector.app.features.home.room.detail.timeline.item.SendStateDecoration import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayoutFactory @@ -38,7 +36,6 @@ import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.isSticker import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toValidDecryptedEvent -import org.matrix.android.sdk.api.session.room.model.PollResponseAggregatedSummary import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.message.MessageType @@ -55,7 +52,8 @@ class MessageInformationDataFactory @Inject constructor( private val session: Session, private val dateFormatter: VectorDateFormatter, private val messageLayoutFactory: TimelineMessageLayoutFactory, - private val reactionsSummaryFactory: ReactionsSummaryFactory + private val reactionsSummaryFactory: ReactionsSummaryFactory, + private val pollResponseDataFactory: PollResponseDataFactory, ) { fun create(params: TimelineItemFactoryParams): MessageInformationData { @@ -100,7 +98,7 @@ class MessageInformationDataFactory @Inject constructor( memberName = event.senderInfo.disambiguatedDisplayName, messageLayout = messageLayout, reactionsSummary = reactionsSummaryFactory.create(event), - pollResponseAggregatedSummary = mapPollResponseSummary(event.annotations?.pollResponseSummary), + pollResponseAggregatedSummary = pollResponseDataFactory.create(event), hasBeenEdited = event.hasBeenEdited(), hasPendingEdits = event.annotations?.editSummary?.localEchos?.any() ?: false, referencesInfoData = event.annotations?.referencesAggregatedSummary?.let { referencesAggregatedSummary -> @@ -121,23 +119,6 @@ class MessageInformationDataFactory @Inject constructor( ) } - fun mapPollResponseSummary(pollResponseSummary: PollResponseAggregatedSummary?): PollResponseData? { - return pollResponseSummary?.let { - PollResponseData( - myVote = it.aggregatedContent?.myVote, - isClosed = it.closedTime != null, - votes = it.aggregatedContent?.votesSummary?.mapValues { votesSummary -> - PollVoteSummaryData( - total = votesSummary.value.total, - percentage = votesSummary.value.percentage - ) - }, - winnerVoteCount = it.aggregatedContent?.winnerVoteCount ?: 0, - totalVotes = it.aggregatedContent?.totalVotes ?: 0 - ) - } - } - private fun getSenderId(event: TimelineEvent) = if (event.isEncrypted()) { event.root.toValidDecryptedEvent()?.let { session.cryptoService().deviceWithIdentityKey(it.cryptoSenderKey, it.algorithm)?.userId diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/PollResponseDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/PollResponseDataFactory.kt new file mode 100644 index 0000000000..c71d7d493f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/PollResponseDataFactory.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.timeline.helper + +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.features.home.room.detail.timeline.item.PollResponseData +import im.vector.app.features.home.room.detail.timeline.item.PollVoteSummaryData +import org.matrix.android.sdk.api.session.events.model.getRelationContent +import org.matrix.android.sdk.api.session.events.model.isPollEnd +import org.matrix.android.sdk.api.session.room.getTimelineEvent +import org.matrix.android.sdk.api.session.room.model.PollResponseAggregatedSummary +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import timber.log.Timber +import javax.inject.Inject + +class PollResponseDataFactory @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, +) { + + fun create(event: TimelineEvent): PollResponseData? { + val pollResponseSummary = getPollResponseSummary(event) + return pollResponseSummary?.let { + PollResponseData( + myVote = it.aggregatedContent?.myVote, + isClosed = it.closedTime != null, + votes = it.aggregatedContent?.votesSummary?.mapValues { votesSummary -> + PollVoteSummaryData( + total = votesSummary.value.total, + percentage = votesSummary.value.percentage + ) + }, + winnerVoteCount = it.aggregatedContent?.winnerVoteCount ?: 0, + totalVotes = it.aggregatedContent?.totalVotes ?: 0 + ) + } + } + + private fun getPollResponseSummary(event: TimelineEvent): PollResponseAggregatedSummary? { + if (event.root.isPollEnd()) { + val pollStartEventId = event.root.getRelationContent()?.eventId ?: return null.also { + Timber.e("### Cannot render poll end event because poll start event id is null") + } + return activeSessionHolder + .getSafeActiveSession() + ?.roomService() + ?.getRoom(event.roomId) + ?.getTimelineEvent(pollStartEventId) + ?.annotations + ?.pollResponseSummary + } + return event.annotations?.pollResponseSummary + } +} diff --git a/vector/src/test/java/im/vector/app/features/home/room/detail/timeline/action/CheckIfCanReplyEventUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/home/room/detail/timeline/action/CheckIfCanReplyEventUseCaseTest.kt index 1244a0a108..e6e75b2e20 100644 --- a/vector/src/test/java/im/vector/app/features/home/room/detail/timeline/action/CheckIfCanReplyEventUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/home/room/detail/timeline/action/CheckIfCanReplyEventUseCaseTest.kt @@ -43,7 +43,7 @@ class CheckIfCanReplyEventUseCaseTest { @Test fun `given reply is allowed for the event type when use case is executed then result is true`() { - val eventTypes = EventType.STATE_ROOM_BEACON_INFO.values + EventType.POLL_START.values + EventType.MESSAGE + val eventTypes = EventType.STATE_ROOM_BEACON_INFO.values + EventType.POLL_START.values + EventType.POLL_END.values + EventType.MESSAGE eventTypes.forEach { eventType -> val event = givenAnEvent(eventType) diff --git a/vector/src/test/java/im/vector/app/features/home/room/detail/timeline/render/ProcessBodyOfReplyToEventUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/home/room/detail/timeline/render/ProcessBodyOfReplyToEventUseCaseTest.kt index 69bcb81d5f..c38afe20ec 100644 --- a/vector/src/test/java/im/vector/app/features/home/room/detail/timeline/render/ProcessBodyOfReplyToEventUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/home/room/detail/timeline/render/ProcessBodyOfReplyToEventUseCaseTest.kt @@ -176,6 +176,17 @@ class ProcessBodyOfReplyToEventUseCaseTest { executeAndAssertResult() } + @Test + fun `given a replied event of type poll end message when process the formatted body then content is replaced by correct string`() { + // Given + givenTypeOfRepliedEvent(isPollMessage = true) + givenNewContentForId(R.string.message_reply_to_sender_ended_poll) + every { fakeRepliedEvent.getClearType() } returns EventType.POLL_END.unstable + every { fakeRepliedEvent.getPollQuestion() } returns null + + executeAndAssertResult() + } + @Test fun `given a replied event of type live location message when process the formatted body then content is replaced by correct string`() { // Given