Code review fixes.
This commit is contained in:
parent
8100a2e674
commit
30115fa2b9
@ -16,8 +16,13 @@
|
|||||||
|
|
||||||
package im.vector.app.features.home.room.detail.timeline.factory
|
package im.vector.app.features.home.room.detail.timeline.factory
|
||||||
|
|
||||||
|
import android.text.Spannable
|
||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableStringBuilder
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
|
import android.text.TextPaint
|
||||||
|
import android.text.style.AbsoluteSizeSpan
|
||||||
|
import android.text.style.ClickableSpan
|
||||||
|
import android.text.style.ForegroundColorSpan
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
@ -30,7 +35,6 @@ import im.vector.app.core.time.Clock
|
|||||||
import im.vector.app.core.utils.DimensionConverter
|
import im.vector.app.core.utils.DimensionConverter
|
||||||
import im.vector.app.core.utils.containsOnlyEmojis
|
import im.vector.app.core.utils.containsOnlyEmojis
|
||||||
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.app.features.home.room.detail.timeline.factory.MessageItemFactoryHelper.annotateWithEdited
|
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlaybackTracker
|
import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlaybackTracker
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
|
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder
|
import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder
|
||||||
@ -253,7 +257,7 @@ class MessageItemFactory @Inject constructor(
|
|||||||
question: String,
|
question: String,
|
||||||
callback: TimelineEventController.Callback?,
|
callback: TimelineEventController.Callback?,
|
||||||
) = if (informationData.hasBeenEdited) {
|
) = if (informationData.hasBeenEdited) {
|
||||||
annotateWithEdited(stringProvider, colorProvider, dimensionConverter, question, callback, informationData)
|
annotateWithEdited(question, callback, informationData)
|
||||||
} else {
|
} else {
|
||||||
question
|
question
|
||||||
}.toEpoxyCharSequence()
|
}.toEpoxyCharSequence()
|
||||||
@ -554,7 +558,7 @@ class MessageItemFactory @Inject constructor(
|
|||||||
return MessageTextItem_()
|
return MessageTextItem_()
|
||||||
.message(
|
.message(
|
||||||
if (informationData.hasBeenEdited) {
|
if (informationData.hasBeenEdited) {
|
||||||
annotateWithEdited(stringProvider, colorProvider, dimensionConverter, linkifiedBody, callback, informationData)
|
annotateWithEdited(linkifiedBody, callback, informationData)
|
||||||
} else {
|
} else {
|
||||||
linkifiedBody
|
linkifiedBody
|
||||||
}.toEpoxyCharSequence()
|
}.toEpoxyCharSequence()
|
||||||
@ -572,6 +576,50 @@ class MessageItemFactory @Inject constructor(
|
|||||||
.movementMethod(createLinkMovementMethod(callback))
|
.movementMethod(createLinkMovementMethod(callback))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun annotateWithEdited(
|
||||||
|
linkifiedBody: CharSequence,
|
||||||
|
callback: TimelineEventController.Callback?,
|
||||||
|
informationData: MessageInformationData,
|
||||||
|
): Spannable {
|
||||||
|
val spannable = SpannableStringBuilder()
|
||||||
|
spannable.append(linkifiedBody)
|
||||||
|
val editedSuffix = stringProvider.getString(R.string.edited_suffix)
|
||||||
|
spannable.append(" ").append(editedSuffix)
|
||||||
|
val color = colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary)
|
||||||
|
val editStart = spannable.lastIndexOf(editedSuffix)
|
||||||
|
val editEnd = editStart + editedSuffix.length
|
||||||
|
spannable.setSpan(
|
||||||
|
ForegroundColorSpan(color),
|
||||||
|
editStart,
|
||||||
|
editEnd,
|
||||||
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
|
||||||
|
// Note: text size is set to 14sp
|
||||||
|
spannable.setSpan(
|
||||||
|
AbsoluteSizeSpan(dimensionConverter.spToPx(13)),
|
||||||
|
editStart,
|
||||||
|
editEnd,
|
||||||
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
|
||||||
|
spannable.setSpan(
|
||||||
|
object : ClickableSpan() {
|
||||||
|
override fun onClick(widget: View) {
|
||||||
|
callback?.onEditedDecorationClicked(informationData)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateDrawState(ds: TextPaint) {
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
},
|
||||||
|
editStart,
|
||||||
|
editEnd,
|
||||||
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
return spannable
|
||||||
|
}
|
||||||
|
|
||||||
private fun buildNoticeMessageItem(
|
private fun buildNoticeMessageItem(
|
||||||
messageContent: MessageNoticeContent,
|
messageContent: MessageNoticeContent,
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
@ -618,7 +666,7 @@ class MessageItemFactory @Inject constructor(
|
|||||||
return MessageTextItem_()
|
return MessageTextItem_()
|
||||||
.message(
|
.message(
|
||||||
if (informationData.hasBeenEdited) {
|
if (informationData.hasBeenEdited) {
|
||||||
annotateWithEdited(stringProvider, colorProvider, dimensionConverter, message, callback, informationData)
|
annotateWithEdited(message, callback, informationData)
|
||||||
} else {
|
} else {
|
||||||
message
|
message
|
||||||
}.toEpoxyCharSequence()
|
}.toEpoxyCharSequence()
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2022 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.factory
|
|
||||||
|
|
||||||
import android.text.Spannable
|
|
||||||
import android.text.SpannableStringBuilder
|
|
||||||
import android.text.Spanned
|
|
||||||
import android.text.TextPaint
|
|
||||||
import android.text.style.AbsoluteSizeSpan
|
|
||||||
import android.text.style.ClickableSpan
|
|
||||||
import android.text.style.ForegroundColorSpan
|
|
||||||
import android.view.View
|
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.resources.ColorProvider
|
|
||||||
import im.vector.app.core.resources.StringProvider
|
|
||||||
import im.vector.app.core.utils.DimensionConverter
|
|
||||||
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
|
|
||||||
|
|
||||||
object MessageItemFactoryHelper {
|
|
||||||
|
|
||||||
fun annotateWithEdited(
|
|
||||||
stringProvider: StringProvider,
|
|
||||||
colorProvider: ColorProvider,
|
|
||||||
dimensionConverter: DimensionConverter,
|
|
||||||
linkifiedBody: CharSequence,
|
|
||||||
callback: TimelineEventController.Callback?,
|
|
||||||
informationData: MessageInformationData,
|
|
||||||
): Spannable {
|
|
||||||
val spannable = SpannableStringBuilder()
|
|
||||||
spannable.append(linkifiedBody)
|
|
||||||
val editedSuffix = stringProvider.getString(R.string.edited_suffix)
|
|
||||||
spannable.append(" ").append(editedSuffix)
|
|
||||||
val color = colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary)
|
|
||||||
val editStart = spannable.lastIndexOf(editedSuffix)
|
|
||||||
val editEnd = editStart + editedSuffix.length
|
|
||||||
spannable.setSpan(
|
|
||||||
ForegroundColorSpan(color),
|
|
||||||
editStart,
|
|
||||||
editEnd,
|
|
||||||
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
|
|
||||||
)
|
|
||||||
|
|
||||||
// Note: text size is set to 14sp
|
|
||||||
spannable.setSpan(
|
|
||||||
AbsoluteSizeSpan(dimensionConverter.spToPx(13)),
|
|
||||||
editStart,
|
|
||||||
editEnd,
|
|
||||||
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
|
|
||||||
)
|
|
||||||
|
|
||||||
spannable.setSpan(
|
|
||||||
object : ClickableSpan() {
|
|
||||||
override fun onClick(widget: View) {
|
|
||||||
callback?.onEditedDecorationClicked(informationData)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateDrawState(ds: TextPaint) {
|
|
||||||
// nop
|
|
||||||
}
|
|
||||||
},
|
|
||||||
editStart,
|
|
||||||
editEnd,
|
|
||||||
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
|
|
||||||
)
|
|
||||||
return spannable
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package im.vector.app.features.home.room.detail.timeline.factory
|
package im.vector.app.features.home.room.detail.timeline.factory
|
||||||
|
|
||||||
import com.airbnb.mvrx.test.MvRxTestRule
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
|
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.PollOptionViewState
|
import im.vector.app.features.home.room.detail.timeline.item.PollOptionViewState
|
||||||
@ -26,11 +25,8 @@ import im.vector.app.features.home.room.detail.timeline.item.ReactionsSummaryDat
|
|||||||
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
|
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
|
||||||
import im.vector.app.features.poll.PollViewState
|
import im.vector.app.features.poll.PollViewState
|
||||||
import im.vector.app.test.fakes.FakeStringProvider
|
import im.vector.app.test.fakes.FakeStringProvider
|
||||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.amshove.kluent.shouldBeEqualTo
|
import org.amshove.kluent.shouldBeEqualTo
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.PollAnswer
|
import org.matrix.android.sdk.api.session.room.model.message.PollAnswer
|
||||||
@ -83,12 +79,6 @@ private val A_POLL_CONTENT = MessagePollContent(
|
|||||||
|
|
||||||
class PollItemViewStateFactoryTest {
|
class PollItemViewStateFactoryTest {
|
||||||
|
|
||||||
private val testDispatcher = UnconfinedTestDispatcher()
|
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
val mvRxTestRule = MvRxTestRule(
|
|
||||||
testDispatcher = testDispatcher // See https://github.com/airbnb/mavericks/issues/599
|
|
||||||
)
|
|
||||||
private lateinit var pollItemViewStateFactory: PollItemViewStateFactory
|
private lateinit var pollItemViewStateFactory: PollItemViewStateFactory
|
||||||
|
|
||||||
private val stringProvider = FakeStringProvider()
|
private val stringProvider = FakeStringProvider()
|
||||||
@ -102,7 +92,7 @@ class PollItemViewStateFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a sending poll state then poll is not votable and option states are PollSending`() = runTest {
|
fun `given a sending poll state then poll is not votable and option states are PollSending`() {
|
||||||
val sendingPollInformationData = A_MESSAGE_INFORMATION_DATA.copy(sendState = SendState.SENDING)
|
val sendingPollInformationData = A_MESSAGE_INFORMATION_DATA.copy(sendState = SendState.SENDING)
|
||||||
val pollViewState = pollItemViewStateFactory.create(
|
val pollViewState = pollItemViewStateFactory.create(
|
||||||
pollContent = A_POLL_CONTENT,
|
pollContent = A_POLL_CONTENT,
|
||||||
@ -123,7 +113,7 @@ class PollItemViewStateFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a sent poll state when poll is closed then poll is not votable and option states are Ended`() = runTest {
|
fun `given a sent poll state when poll is closed then poll is not votable and option states are Ended`() {
|
||||||
val closedPollSummary = A_POLL_RESPONSE_DATA.copy(isClosed = true)
|
val closedPollSummary = A_POLL_RESPONSE_DATA.copy(isClosed = true)
|
||||||
val closedPollInformationData = A_MESSAGE_INFORMATION_DATA.copy(pollResponseAggregatedSummary = closedPollSummary)
|
val closedPollInformationData = A_MESSAGE_INFORMATION_DATA.copy(pollResponseAggregatedSummary = closedPollSummary)
|
||||||
|
|
||||||
@ -149,7 +139,7 @@ class PollItemViewStateFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a sent poll when undisclosed poll type is selected then poll is votable and option states are PollUndisclosed`() = runTest {
|
fun `given a sent poll when undisclosed poll type is selected then poll is votable and option states are PollUndisclosed`() {
|
||||||
val pollViewState = pollItemViewStateFactory.create(
|
val pollViewState = pollItemViewStateFactory.create(
|
||||||
pollContent = A_POLL_CONTENT,
|
pollContent = A_POLL_CONTENT,
|
||||||
informationData = A_MESSAGE_INFORMATION_DATA,
|
informationData = A_MESSAGE_INFORMATION_DATA,
|
||||||
@ -170,7 +160,7 @@ class PollItemViewStateFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a sent poll when my vote exists then poll is still votable and options states are PollVoted`() = runTest {
|
fun `given a sent poll when my vote exists then poll is still votable and options states are PollVoted`() {
|
||||||
val votedPollData = A_POLL_RESPONSE_DATA.copy(
|
val votedPollData = A_POLL_RESPONSE_DATA.copy(
|
||||||
totalVotes = 1,
|
totalVotes = 1,
|
||||||
myVote = A_POLL_OPTION_IDS[0],
|
myVote = A_POLL_OPTION_IDS[0],
|
||||||
@ -205,7 +195,7 @@ class PollItemViewStateFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a sent poll when poll type is disclosed then poll is votable and option view states are PollReady`() = runTest {
|
fun `given a sent poll when poll type is disclosed then poll is votable and option view states are PollReady`() {
|
||||||
val disclosedPollContent = A_POLL_CONTENT.copy(
|
val disclosedPollContent = A_POLL_CONTENT.copy(
|
||||||
unstablePollCreationInfo = A_POLL_CONTENT.getBestPollCreationInfo()?.copy(
|
unstablePollCreationInfo = A_POLL_CONTENT.getBestPollCreationInfo()?.copy(
|
||||||
kind = PollType.DISCLOSED_UNSTABLE
|
kind = PollType.DISCLOSED_UNSTABLE
|
||||||
|
Loading…
Reference in New Issue
Block a user