Iterate on reactions (#668)
This commit is contained in:
parent
c7ec8bc9e9
commit
2cef47c271
8 changed files with 51 additions and 33 deletions
|
|
@ -100,7 +100,7 @@ internal fun aTimelineItemEvent(
|
||||||
sendState: EventSendState = EventSendState.Sent(eventId),
|
sendState: EventSendState = EventSendState.Sent(eventId),
|
||||||
inReplyTo: InReplyTo? = null,
|
inReplyTo: InReplyTo? = null,
|
||||||
debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(),
|
debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(),
|
||||||
timelineItemReactions: TimelineItemReactions = aTimelineItemReactions(isMine = isMine),
|
timelineItemReactions: TimelineItemReactions = aTimelineItemReactions(),
|
||||||
): TimelineItem.Event {
|
): TimelineItem.Event {
|
||||||
return TimelineItem.Event(
|
return TimelineItem.Event(
|
||||||
id = eventId.value,
|
id = eventId.value,
|
||||||
|
|
@ -122,12 +122,12 @@ internal fun aTimelineItemEvent(
|
||||||
|
|
||||||
fun aTimelineItemReactions(
|
fun aTimelineItemReactions(
|
||||||
count: Int = 1,
|
count: Int = 1,
|
||||||
isMine: Boolean = true,
|
isHighlighted: Boolean = false,
|
||||||
): TimelineItemReactions {
|
): TimelineItemReactions {
|
||||||
return TimelineItemReactions(
|
return TimelineItemReactions(
|
||||||
reactions = buildList {
|
reactions = buildList {
|
||||||
repeat(count) {
|
repeat(count) {
|
||||||
add(AggregatedReaction(key = "👍", count = (it + 1).toString(), isOnMyMessage = isMine))
|
add(AggregatedReaction(key = "👍", count = 1 + it, isHighlighted = isHighlighted))
|
||||||
}
|
}
|
||||||
}.toPersistentList()
|
}.toPersistentList()
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
package io.element.android.features.messages.impl.timeline.components
|
package io.element.android.features.messages.impl.timeline.components
|
||||||
|
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -27,6 +29,7 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
@ -41,25 +44,36 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MessagesReactionButton(reaction: AggregatedReaction, modifier: Modifier = Modifier) {
|
fun MessagesReactionButton(reaction: AggregatedReaction, modifier: Modifier = Modifier) {
|
||||||
val backgroundColor = if (reaction.isOnMyMessage) {
|
// First Surface is to render a border with the same background color as the background
|
||||||
ElementTheme.colors.messageFromMeBackground
|
|
||||||
} else {
|
|
||||||
ElementTheme.colors.messageFromOtherBackground
|
|
||||||
}
|
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
color = backgroundColor,
|
// TODO Should use compound.bgSubtlePrimary
|
||||||
|
color = ElementTheme.colors.gray300,
|
||||||
border = BorderStroke(2.dp, MaterialTheme.colorScheme.background),
|
border = BorderStroke(2.dp, MaterialTheme.colorScheme.background),
|
||||||
shape = RoundedCornerShape(corner = CornerSize(14.dp)),
|
shape = RoundedCornerShape(corner = CornerSize(14.dp)),
|
||||||
) {
|
) {
|
||||||
Row(
|
Box(modifier = Modifier.padding(2.dp)) {
|
||||||
modifier = Modifier.padding(vertical = 6.dp, horizontal = 12.dp),
|
val reactionModifier = if (reaction.isHighlighted) {
|
||||||
verticalAlignment = Alignment.CenterVertically
|
Modifier
|
||||||
) {
|
// TODO Check the color, should use compound.borderInteractivePrimary
|
||||||
// TODO `reaction.isHighlighted` is not used.
|
.border(BorderStroke(1.dp, Color(0xFF808994)), RoundedCornerShape(corner = CornerSize(12.dp)))
|
||||||
Text(text = reaction.key, fontSize = 14.sp)
|
} else {
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
Modifier
|
||||||
Text(text = reaction.count, color = MaterialTheme.colorScheme.secondary, fontSize = 12.sp)
|
}
|
||||||
|
Row(
|
||||||
|
modifier = reactionModifier.padding(vertical = 4.dp, horizontal = 12.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(text = reaction.key, fontSize = 15.sp)
|
||||||
|
if (reaction.count > 1) {
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Text(
|
||||||
|
text = reaction.count.toString(),
|
||||||
|
color = if (reaction.isHighlighted) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary,
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItemReac
|
||||||
import io.element.android.libraries.core.bool.orTrue
|
import io.element.android.libraries.core.bool.orTrue
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||||
|
|
@ -34,6 +35,7 @@ import javax.inject.Inject
|
||||||
|
|
||||||
class TimelineItemEventFactory @Inject constructor(
|
class TimelineItemEventFactory @Inject constructor(
|
||||||
private val contentFactory: TimelineItemContentFactory,
|
private val contentFactory: TimelineItemContentFactory,
|
||||||
|
private val matrixClient: MatrixClient,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun create(
|
fun create(
|
||||||
|
|
@ -91,11 +93,11 @@ class TimelineItemEventFactory @Inject constructor(
|
||||||
val aggregatedReactions = event.reactions.map {
|
val aggregatedReactions = event.reactions.map {
|
||||||
AggregatedReaction(
|
AggregatedReaction(
|
||||||
key = it.key,
|
key = it.key,
|
||||||
count = it.count.toString(),
|
count = it.count.toInt(),
|
||||||
isHighlighted = false,
|
isHighlighted = it.senderIds.contains(matrixClient.sessionId),
|
||||||
isOnMyMessage = event.isOwn,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
aggregatedReactions.sortedByDescending { it.count }
|
||||||
return TimelineItemReactions(aggregatedReactions.toImmutableList())
|
return TimelineItemReactions(aggregatedReactions.toImmutableList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,11 @@
|
||||||
|
|
||||||
package io.element.android.features.messages.impl.timeline.model
|
package io.element.android.features.messages.impl.timeline.model
|
||||||
|
|
||||||
data class AggregatedReaction constructor(
|
/**
|
||||||
|
* @property isHighlighted true if the reaction has (also) been sent by the current user.
|
||||||
|
*/
|
||||||
|
data class AggregatedReaction(
|
||||||
val key: String,
|
val key: String,
|
||||||
val count: String,
|
val count: Int,
|
||||||
val isOnMyMessage: Boolean,
|
|
||||||
val isHighlighted: Boolean = false
|
val isHighlighted: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -22,22 +22,18 @@ open class AggregatedReactionProvider : PreviewParameterProvider<AggregatedReact
|
||||||
override val values: Sequence<AggregatedReaction>
|
override val values: Sequence<AggregatedReaction>
|
||||||
get() = sequenceOf(false, true).flatMap {
|
get() = sequenceOf(false, true).flatMap {
|
||||||
sequenceOf(
|
sequenceOf(
|
||||||
anAggregatedReaction(isOnMyMessage = it),
|
anAggregatedReaction(isHighlighted = it),
|
||||||
anAggregatedReaction(isOnMyMessage = it, count = "88"),
|
anAggregatedReaction(isHighlighted = it, count = 88),
|
||||||
anAggregatedReaction(isOnMyMessage = it, isHighlighted = true),
|
|
||||||
anAggregatedReaction(isOnMyMessage = it, count = "88", isHighlighted = true),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun anAggregatedReaction(
|
fun anAggregatedReaction(
|
||||||
key: String = "👍",
|
key: String = "👍",
|
||||||
count: String = "1", // TODO Why is it a String?
|
count: Int = 1,
|
||||||
isOnMyMessage: Boolean = false,
|
|
||||||
isHighlighted: Boolean = false,
|
isHighlighted: Boolean = false,
|
||||||
) = AggregatedReaction(
|
) = AggregatedReaction(
|
||||||
key = key,
|
key = key,
|
||||||
count = count,
|
count = count,
|
||||||
isOnMyMessage = isOnMyMessage,
|
|
||||||
isHighlighted = isHighlighted,
|
isHighlighted = isHighlighted,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ internal fun aMessageEvent(
|
||||||
content = content,
|
content = content,
|
||||||
sentTime = "",
|
sentTime = "",
|
||||||
isMine = isMine,
|
isMine = isMine,
|
||||||
reactionsState = aTimelineItemReactions(count = 0, isMine = isMine),
|
reactionsState = aTimelineItemReactions(count = 0),
|
||||||
sendState = EventSendState.Sent(AN_EVENT_ID),
|
sendState = EventSendState.Sent(AN_EVENT_ID),
|
||||||
inReplyTo = inReplyTo,
|
inReplyTo = inReplyTo,
|
||||||
debugInfo = debugInfo,
|
debugInfo = debugInfo,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,10 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.timeline.item.event
|
package io.element.android.libraries.matrix.api.timeline.item.event
|
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
|
||||||
data class EventReaction(
|
data class EventReaction(
|
||||||
val key: String,
|
val key: String,
|
||||||
val count: Long
|
val count: Long,
|
||||||
|
val senderIds: List<UserId>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,8 @@ private fun List<Reaction>?.map(): List<EventReaction> {
|
||||||
return this?.map {
|
return this?.map {
|
||||||
EventReaction(
|
EventReaction(
|
||||||
key = it.key,
|
key = it.key,
|
||||||
count = it.count.toLong()
|
count = it.count.toLong(),
|
||||||
|
senderIds = it.senders.map { sender -> UserId(sender) }
|
||||||
)
|
)
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue