Introduce LiveLocationContent for the timeline (needs sdk)
This commit is contained in:
@@ -32,6 +32,8 @@ import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.location.api.internal.StaticMapPlaceholder
|
||||
import io.element.android.features.location.api.internal.StaticMapUrlBuilder
|
||||
import io.element.android.features.location.api.internal.centerBottomEdge
|
||||
import io.element.android.libraries.designsystem.components.LocationPinMarker
|
||||
import io.element.android.libraries.designsystem.components.PinVariant
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
@@ -45,6 +47,7 @@ fun StaticMapView(
|
||||
lat: Double,
|
||||
lon: Double,
|
||||
zoom: Double,
|
||||
pinVariant: PinVariant,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
darkMode: Boolean = !ElementTheme.isLightTheme,
|
||||
@@ -95,12 +98,7 @@ fun StaticMapView(
|
||||
// We apply ContentScale.Fit to scale the image to fill the AsyncImage should this be the case.
|
||||
contentScale = ContentScale.Fit,
|
||||
)
|
||||
Icon(
|
||||
resourceId = CommonDrawables.pin,
|
||||
contentDescription = null,
|
||||
tint = Color.Unspecified,
|
||||
modifier = Modifier.centerBottomEdge(this),
|
||||
)
|
||||
LocationPinMarker(variant = pinVariant, modifier = Modifier.centerBottomEdge(this))
|
||||
} else {
|
||||
StaticMapPlaceholder(
|
||||
showProgress = collectedState.value.isLoading(),
|
||||
@@ -127,6 +125,7 @@ internal fun StaticMapViewPreview() = ElementPreview {
|
||||
lon = 0.0,
|
||||
zoom = 0.0,
|
||||
contentDescription = null,
|
||||
pinVariant = PinVariant.PinnedLocation,
|
||||
modifier = Modifier.size(400.dp),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ internal class MapTilerStaticMapUrlBuilder(
|
||||
// image smaller than the available space in pixels.
|
||||
// The resulting image will have to be scaled to fit the available space in order
|
||||
// to keep the perceived content size constant at the expense of sharpness.
|
||||
return "$baseUrl/$mapId/static/$lon,$lat,$finalZoom/${finalWidth}x${finalHeight}$scale.webp?key=$apiKey&attribution=bottomleft"
|
||||
return "$baseUrl/$mapId/static/$lon,$lat,$finalZoom/${finalWidth}x${finalHeight}$scale.webp?key=$apiKey&attribution=topright"
|
||||
}
|
||||
|
||||
override fun isServiceAvailable() = apiKey.isNotEmpty()
|
||||
|
||||
@@ -39,7 +39,7 @@ import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugIn
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.aProfileTimelineDetailsReady
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.aProfileDetailsReady
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
@@ -166,7 +166,7 @@ internal fun aTimelineItemEvent(
|
||||
isMine = isMine,
|
||||
isEditable = isEditable,
|
||||
canBeRepliedTo = canBeRepliedTo,
|
||||
senderProfile = aProfileTimelineDetailsReady(
|
||||
senderProfile = aProfileDetailsReady(
|
||||
displayName = senderDisplayName,
|
||||
displayNameAmbiguous = displayNameAmbiguous,
|
||||
),
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.event
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
@@ -19,33 +17,28 @@ import androidx.compose.ui.unit.dp
|
||||
import io.element.android.features.location.api.StaticMapView
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContentProvider
|
||||
import io.element.android.libraries.designsystem.components.PinVariant
|
||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
@Composable
|
||||
fun TimelineItemLocationView(
|
||||
content: TimelineItemLocationContent,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(modifier = modifier.fillMaxWidth()) {
|
||||
content.description?.let {
|
||||
Text(
|
||||
text = it,
|
||||
modifier = Modifier.padding(start = 12.dp, end = 12.dp, top = 8.dp, bottom = 8.dp),
|
||||
)
|
||||
}
|
||||
|
||||
StaticMapView(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = 188.dp),
|
||||
lat = content.location.lat,
|
||||
lon = content.location.lon,
|
||||
zoom = 15.0,
|
||||
contentDescription = content.body
|
||||
)
|
||||
}
|
||||
StaticMapView(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = 188.dp),
|
||||
pinVariant = content.pinVariant,
|
||||
lat = content.location.lat,
|
||||
lon = content.location.lon,
|
||||
zoom = 15.0,
|
||||
contentDescription = content.body
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
package io.element.android.features.messages.impl.timeline.factories.event
|
||||
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
@@ -22,6 +24,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventTimeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.LegacyCallInviteContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.LiveLocationContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
||||
@@ -70,10 +73,10 @@ class TimelineItemContentFactory(
|
||||
is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent)
|
||||
is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent)
|
||||
is MessageContent -> {
|
||||
val senderDisambiguatedDisplayName = senderProfile.getDisambiguatedDisplayName(sender)
|
||||
messageFactory.create(
|
||||
senderId = sender,
|
||||
senderProfile = senderProfile,
|
||||
content = itemContent,
|
||||
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||
eventId = eventId,
|
||||
)
|
||||
}
|
||||
@@ -96,6 +99,24 @@ class TimelineItemContentFactory(
|
||||
is UnableToDecryptContent -> utdFactory.create(itemContent)
|
||||
is CallNotifyContent -> TimelineItemRtcNotificationContent()
|
||||
is UnknownContent -> TimelineItemUnknownContent
|
||||
is LiveLocationContent -> {
|
||||
val lastKnownLocation = itemContent.locations.mapNotNull { beacon ->
|
||||
Location.fromGeoUri(beacon.geoUri)
|
||||
}.lastOrNull()
|
||||
if (lastKnownLocation != null) {
|
||||
TimelineItemLocationContent(
|
||||
body = itemContent.body.trimEnd(),
|
||||
description = itemContent.description?.trimEnd(),
|
||||
assetType = itemContent.assetType,
|
||||
senderId = sender,
|
||||
senderProfile = senderProfile,
|
||||
location = lastKnownLocation,
|
||||
mode = TimelineItemLocationContent.Mode.Live(isActive = itemContent.isLive)
|
||||
)
|
||||
} else {
|
||||
TimelineItemUnknownContent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,13 @@ import io.element.android.features.messages.impl.utils.TextPillificationHelper
|
||||
import io.element.android.libraries.androidutils.filesize.FileSizeFormatter
|
||||
import io.element.android.libraries.androidutils.text.safeLinkify
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.designsystem.components.PinVariant
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType
|
||||
@@ -39,10 +44,13 @@ import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessa
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
|
||||
import io.element.android.libraries.matrix.ui.messages.toHtmlDocument
|
||||
import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
@@ -65,11 +73,13 @@ class TimelineItemContentMessageFactory(
|
||||
) {
|
||||
fun create(
|
||||
content: MessageContent,
|
||||
senderDisambiguatedDisplayName: String,
|
||||
senderId: UserId,
|
||||
senderProfile: ProfileDetails,
|
||||
eventId: EventId?,
|
||||
): TimelineItemEventContent {
|
||||
return when (val messageType = content.type) {
|
||||
is EmoteMessageType -> {
|
||||
val senderDisambiguatedDisplayName = senderProfile.getDisambiguatedDisplayName(senderId)
|
||||
val emoteBody = "* $senderDisambiguatedDisplayName ${messageType.body.trimEnd()}"
|
||||
val dom = messageType.formatted?.toHtmlDocument(
|
||||
permalinkParser = permalinkParser,
|
||||
@@ -135,8 +145,8 @@ class TimelineItemContentMessageFactory(
|
||||
}
|
||||
is LocationMessageType -> {
|
||||
val location = Location.fromGeoUri(messageType.geoUri)
|
||||
val body = messageType.body.trimEnd()
|
||||
if (location == null) {
|
||||
val body = messageType.body.trimEnd()
|
||||
TimelineItemTextContent(
|
||||
body = body,
|
||||
htmlDocument = null,
|
||||
@@ -145,9 +155,13 @@ class TimelineItemContentMessageFactory(
|
||||
)
|
||||
} else {
|
||||
TimelineItemLocationContent(
|
||||
body = messageType.body.trimEnd(),
|
||||
body = body,
|
||||
location = location,
|
||||
description = messageType.description
|
||||
description = messageType.description,
|
||||
senderId = senderId,
|
||||
senderProfile = senderProfile,
|
||||
assetType = messageType.assetType,
|
||||
mode = TimelineItemLocationContent.Mode.Static
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyCon
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.LegacyCallInviteContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.LiveLocationContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
||||
@@ -81,7 +82,8 @@ internal fun MatrixTimelineItem.Event.canBeDisplayedInBubbleBlock(): Boolean {
|
||||
RedactedContent,
|
||||
is StickerContent,
|
||||
is PollContent,
|
||||
is UnableToDecryptContent -> true
|
||||
is UnableToDecryptContent,
|
||||
is LiveLocationContent -> true
|
||||
// Can't be grouped
|
||||
is FailedToParseStateContent,
|
||||
is ProfileChangeContent,
|
||||
|
||||
@@ -28,7 +28,8 @@ class TimelineItemEventContentProvider : PreviewParameterProvider<TimelineItemEv
|
||||
aTimelineItemAudioContent("An even bigger bigger bigger bigger bigger bigger bigger sound name which doesn't fit .mp3"),
|
||||
aTimelineItemVoiceContent(),
|
||||
aTimelineItemLocationContent(),
|
||||
aTimelineItemLocationContent("Location description"),
|
||||
aTimelineItemLocationContent(),
|
||||
aTimelineItemLocationContent(mode = TimelineItemLocationContent.Mode.Live(isActive = true)),
|
||||
aTimelineItemPollContent(),
|
||||
aTimelineItemNoticeContent(),
|
||||
aTimelineItemRedactedContent(),
|
||||
|
||||
@@ -9,13 +9,55 @@
|
||||
package io.element.android.features.messages.impl.timeline.model.event
|
||||
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.libraries.designsystem.components.PinVariant
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getDisplayName
|
||||
|
||||
data class TimelineItemLocationContent(
|
||||
val body: String,
|
||||
val senderId: UserId,
|
||||
val senderProfile: ProfileDetails,
|
||||
val location: Location,
|
||||
val description: String? = null,
|
||||
val assetType: AssetType? = null,
|
||||
val mode: Mode,
|
||||
) : TimelineItemEventContent {
|
||||
|
||||
val pinVariant = when (mode) {
|
||||
is Mode.Live -> {
|
||||
if (mode.isActive) {
|
||||
PinVariant.UserLocation(avatarData = senderAvatar(), isLive = true)
|
||||
} else {
|
||||
PinVariant.StaleLocation
|
||||
}
|
||||
}
|
||||
Mode.Static -> {
|
||||
when (assetType) {
|
||||
AssetType.PIN -> PinVariant.PinnedLocation
|
||||
AssetType.SENDER,
|
||||
null -> PinVariant.UserLocation(avatarData = senderAvatar(), isLive = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun senderAvatar() = AvatarData(
|
||||
senderId.value,
|
||||
name = senderProfile.getDisplayName(),
|
||||
url = senderProfile.getAvatarUrl(),
|
||||
// Size is irrelevant as the PinMarker will override anyway.
|
||||
size = AvatarSize.TimelineSender
|
||||
)
|
||||
|
||||
sealed interface Mode {
|
||||
data object Static : Mode
|
||||
data class Live(val isActive: Boolean) : Mode
|
||||
}
|
||||
|
||||
override val type: String = "TimelineItemLocationContent"
|
||||
}
|
||||
|
||||
|
||||
@@ -10,21 +10,34 @@ package io.element.android.features.messages.impl.timeline.model.event
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
|
||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.aProfileDetailsReady
|
||||
|
||||
open class TimelineItemLocationContentProvider : PreviewParameterProvider<TimelineItemLocationContent> {
|
||||
override val values: Sequence<TimelineItemLocationContent>
|
||||
get() = sequenceOf(
|
||||
aTimelineItemLocationContent(),
|
||||
aTimelineItemLocationContent("This is a description!"),
|
||||
aTimelineItemLocationContent(mode = TimelineItemLocationContent.Mode.Live(isActive = true)),
|
||||
aTimelineItemLocationContent(mode = TimelineItemLocationContent.Mode.Live(isActive = false)),
|
||||
)
|
||||
}
|
||||
|
||||
fun aTimelineItemLocationContent(description: String? = null) = TimelineItemLocationContent(
|
||||
body = "User location geo:52.2445,0.7186;u=5000",
|
||||
fun aTimelineItemLocationContent(
|
||||
body: String = "",
|
||||
senderId: UserId = UserId("@sender:matrix.org"),
|
||||
senderProfile: ProfileDetails = aProfileDetailsReady(),
|
||||
mode: TimelineItemLocationContent.Mode = TimelineItemLocationContent.Mode.Static,
|
||||
) = TimelineItemLocationContent(
|
||||
body = body,
|
||||
location = Location(
|
||||
lat = 52.2445,
|
||||
lon = 0.7186,
|
||||
accuracy = 5000f,
|
||||
),
|
||||
description = description,
|
||||
senderId = senderId,
|
||||
senderProfile = senderProfile,
|
||||
mode = mode
|
||||
)
|
||||
|
||||
@@ -31,7 +31,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.A_USER_NAME
|
||||
import io.element.android.libraries.matrix.test.core.FakeSendHandle
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.aProfileTimelineDetailsReady
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.aProfileDetailsReady
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal fun aMessageEvent(
|
||||
@@ -52,7 +52,7 @@ internal fun aMessageEvent(
|
||||
eventId = eventId,
|
||||
transactionId = transactionId,
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileTimelineDetailsReady(displayName = A_USER_NAME),
|
||||
senderProfile = aProfileDetailsReady(displayName = A_USER_NAME),
|
||||
senderAvatar = AvatarData(A_USER_ID.value, A_USER_NAME, size = AvatarSize.TimelineSender),
|
||||
content = content,
|
||||
sentTime = "",
|
||||
|
||||
@@ -60,8 +60,10 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.media.aMediaSource
|
||||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||
import io.element.android.libraries.matrix.test.timeline.aProfileDetails
|
||||
import io.element.android.libraries.matrix.test.timeline.aStickerContent
|
||||
import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH
|
||||
import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation
|
||||
@@ -84,7 +86,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = OtherMessageType(msgType = "a_type", body = "body")),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemTextContent(
|
||||
@@ -102,14 +105,18 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val assetType = AssetType.SENDER
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = LocationMessageType("body", "geo:1,2", "description", assetType)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemLocationContent(
|
||||
body = "body",
|
||||
location = Location(lat = 1.0, lon = 2.0, accuracy = 0.0F),
|
||||
location = Location(lat = 1.0, lon = 2.0, accuracy = null),
|
||||
description = "description",
|
||||
assetType = assetType,
|
||||
mode = TimelineItemLocationContent.Mode.Static,
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
)
|
||||
assertThat(result).isEqualTo(expected)
|
||||
}
|
||||
@@ -119,7 +126,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = LocationMessageType("body", "", null, null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemTextContent(
|
||||
@@ -136,7 +144,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = TextMessageType("body", null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemTextContent(
|
||||
@@ -153,7 +162,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = TextMessageType("https://www.example.org", null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
) as TimelineItemTextContent
|
||||
val expected = TimelineItemTextContent(
|
||||
@@ -200,7 +210,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
formatted = FormattedBody(MessageFormat.HTML, expected.toString())
|
||||
)
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
assertThat((result as TimelineItemTextContent).formattedBody).isEqualTo(expected)
|
||||
@@ -218,7 +229,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
formatted = FormattedBody(MessageFormat.UNKNOWN, "formatted")
|
||||
)
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
assertThat((result as TimelineItemTextContent).formattedBody).isEqualTo(SpannedString("body"))
|
||||
@@ -229,7 +241,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = VideoMessageType("filename", null, null, MediaSource("url"), null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemVideoContent(
|
||||
@@ -282,7 +295,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
),
|
||||
isEdited = true,
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemVideoContent(
|
||||
@@ -312,7 +326,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = AudioMessageType("filename", null, null, MediaSource("url"), null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemAudioContent(
|
||||
@@ -348,7 +363,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
),
|
||||
isEdited = true,
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemAudioContent(
|
||||
@@ -371,7 +387,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = VoiceMessageType("filename", null, null, MediaSource("url"), null, null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemVoiceContent(
|
||||
@@ -413,7 +430,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
),
|
||||
isEdited = true,
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemVoiceContent(
|
||||
@@ -438,7 +456,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = ImageMessageType("filename", "body", null, MediaSource("url"), null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemImageContent(
|
||||
@@ -518,7 +537,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
),
|
||||
isEdited = true,
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemImageContent(
|
||||
@@ -547,7 +567,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = FileMessageType("filename", null, null, MediaSource("url"), null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemFileContent(
|
||||
@@ -589,7 +610,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
),
|
||||
isEdited = true,
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemFileContent(
|
||||
@@ -612,7 +634,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = NoticeMessageType("body", null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemNoticeContent(
|
||||
@@ -634,7 +657,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
formatted = FormattedBody(MessageFormat.HTML, "formatted")
|
||||
)
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
(result as TimelineItemNoticeContent).formattedBody.assertSpannedEquals(SpannedString("formatted"))
|
||||
@@ -645,7 +669,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = EmoteMessageType("body", null)),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails("Bob"),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemEmoteContent(
|
||||
@@ -667,7 +692,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
formatted = FormattedBody(MessageFormat.HTML, "formatted")
|
||||
)
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails("Bob"),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
|
||||
@@ -693,7 +719,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
formatted = FormattedBody(MessageFormat.HTML, "Test <a href=\"https://www.example.org\">me@matrix.org</a>")
|
||||
)
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
(result as TimelineItemTextContent).formattedBody.assertSpannedEquals(expectedSpanned)
|
||||
@@ -718,7 +745,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
formatted = FormattedBody(MessageFormat.HTML, "Test https://www.example.org")
|
||||
)
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
(result as TimelineItemTextContent).formattedBody.assertSpannedEquals(expectedSpanned)
|
||||
@@ -744,7 +772,8 @@ class TimelineItemContentMessageFactoryTest {
|
||||
formatted = FormattedBody(MessageFormat.HTML, "Test https://www.example.org")
|
||||
)
|
||||
),
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
senderId = A_USER_ID,
|
||||
senderProfile = aProfileDetails(),
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSen
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.core.FakeSendHandle
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.aProfileTimelineDetailsReady
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.aProfileDetailsReady
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import org.junit.Test
|
||||
|
||||
@@ -34,7 +34,7 @@ class TimelineItemGrouperTest {
|
||||
id = UniqueId("0"),
|
||||
senderId = A_USER_ID,
|
||||
senderAvatar = anAvatarData(),
|
||||
senderProfile = aProfileTimelineDetailsReady(displayName = ""),
|
||||
senderProfile = aProfileDetailsReady(displayName = ""),
|
||||
content = TimelineItemStateEventContent(body = "a state event"),
|
||||
reactionsState = aTimelineItemReactions(count = 0),
|
||||
readReceiptState = TimelineItemReadReceipts(emptyList<ReadReceiptData>().toImmutableList()),
|
||||
|
||||
Reference in New Issue
Block a user