Highlight user's reactions in message actions menu (#778)
Part of #342 --------- Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
parent
a6825b66e1
commit
8e72d5cab5
15 changed files with 120 additions and 75 deletions
|
|
@ -19,6 +19,7 @@ package io.element.android.features.messages.impl.actionlist
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
|
||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemFileContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemLocationContent
|
||||
|
|
@ -28,47 +29,62 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
|
||||
open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
|
||||
override val values: Sequence<ActionListState>
|
||||
get() = sequenceOf(
|
||||
anActionListState(),
|
||||
anActionListState().copy(target = ActionListState.Target.Loading(aTimelineItemEvent())),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemImageContent()),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemVideoContent()),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemFileContent()),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemLocationContent()),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemLocationContent()),
|
||||
actions = aTimelineItemActionList(),
|
||||
get() {
|
||||
val reactionsState = aTimelineItemReactions(1, isHighlighted = true)
|
||||
return sequenceOf(
|
||||
anActionListState(),
|
||||
anActionListState().copy(target = ActionListState.Target.Loading(aTimelineItemEvent())),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent().copy(
|
||||
reactionsState = reactionsState
|
||||
),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
displayEmojiReactions = false,
|
||||
),
|
||||
)
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemImageContent()).copy(
|
||||
reactionsState = reactionsState
|
||||
),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemVideoContent()).copy(
|
||||
reactionsState = reactionsState
|
||||
),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemFileContent()).copy(
|
||||
reactionsState = reactionsState
|
||||
),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemLocationContent()).copy(
|
||||
reactionsState = reactionsState
|
||||
),
|
||||
actions = aTimelineItemActionList(),
|
||||
)
|
||||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemLocationContent()).copy(
|
||||
reactionsState = reactionsState
|
||||
),
|
||||
actions = aTimelineItemActionList(),
|
||||
),
|
||||
displayEmojiReactions = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun anActionListState() = ActionListState(
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package io.element.android.features.messages.impl.actionlist
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
|
|
@ -46,6 +47,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
|
|
@ -78,7 +80,9 @@ import io.element.android.libraries.designsystem.theme.components.hide
|
|||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail
|
||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
||||
import io.element.android.libraries.theme.ElementTheme
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -178,6 +182,7 @@ private fun SheetContent(
|
|||
if (state.displayEmojiReactions) {
|
||||
item {
|
||||
EmojiReactionsRow(
|
||||
highlightedEmojis = target.event.reactionsState.highlightedKeys,
|
||||
onEmojiReactionClicked = onEmojiReactionClicked,
|
||||
onCustomReactionClicked = onCustomReactionClicked,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
|
@ -322,6 +327,7 @@ private val emojiRippleRadius = 24.dp
|
|||
|
||||
@Composable
|
||||
internal fun EmojiReactionsRow(
|
||||
highlightedEmojis: ImmutableList<String>,
|
||||
onEmojiReactionClicked: (String) -> Unit,
|
||||
onCustomReactionClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -335,7 +341,8 @@ internal fun EmojiReactionsRow(
|
|||
"👍", "👎", "🔥", "❤️", "👏"
|
||||
)
|
||||
for (emoji in defaultEmojis) {
|
||||
EmojiButton(emoji, onEmojiReactionClicked)
|
||||
val isHighlighted = highlightedEmojis.contains(emoji)
|
||||
EmojiButton(emoji, isHighlighted, onEmojiReactionClicked)
|
||||
}
|
||||
|
||||
Icon(
|
||||
|
|
@ -358,19 +365,34 @@ internal fun EmojiReactionsRow(
|
|||
@Composable
|
||||
private fun EmojiButton(
|
||||
emoji: String,
|
||||
isHighlighted: Boolean,
|
||||
onClicked: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Text(
|
||||
emoji,
|
||||
fontSize = 28.dp.toSp(),
|
||||
modifier = modifier.clickable(
|
||||
enabled = true,
|
||||
onClick = { onClicked(emoji) },
|
||||
indication = rememberRipple(bounded = false, radius = emojiRippleRadius),
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
val backgroundColor = if (isHighlighted) {
|
||||
ElementTheme.colors.bgActionPrimaryRest
|
||||
} else {
|
||||
Color.Transparent
|
||||
}
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(48.dp)
|
||||
.background(backgroundColor, RoundedCornerShape(24.dp)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
emoji,
|
||||
fontSize = 28.dp.toSp(),
|
||||
color = Color.White,
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
enabled = true,
|
||||
onClick = { onClicked(emoji) },
|
||||
indication = rememberRipple(bounded = false, radius = emojiRippleRadius),
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
|
|
|
|||
|
|
@ -17,7 +17,14 @@
|
|||
package io.element.android.features.messages.impl.timeline.model
|
||||
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
data class TimelineItemReactions(
|
||||
val reactions: ImmutableList<AggregatedReaction>
|
||||
)
|
||||
) {
|
||||
val highlightedKeys: ImmutableList<String>
|
||||
get() = reactions
|
||||
.filter { it.isHighlighted }
|
||||
.map { it.key }
|
||||
.toPersistentList()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue