Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Improve Reaction UI #1490

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.geeksville.mesh.ui.message.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
Expand All @@ -38,6 +39,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.database.entity.Reaction
import com.geeksville.mesh.model.Message
Expand All @@ -48,7 +51,7 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce

@Suppress("LongMethod")
@Suppress("LongMethod", "MagicNumber")
@Composable
internal fun MessageList(
messages: List<Message>,
Expand Down Expand Up @@ -95,7 +98,6 @@ internal fun MessageList(
val fromLocal = msg.node.user.id == DataPacket.ID_LOCAL
val selected by remember { derivedStateOf { selectedIds.value.contains(msg.uuid) } }

ReactionRow(fromLocal, msg.emojis) { showReactionDialog = msg.emojis }
Box(Modifier.wrapContentSize(Alignment.TopStart)) {
var expandedNodeMenu by remember { mutableStateOf(false) }
MessageItem(
Expand Down Expand Up @@ -125,6 +127,11 @@ internal fun MessageList(
onAction = onNodeMenuAction
)
}
ReactionRow(
modifier = Modifier.zIndex(1F).offset(y = (-8).dp),
fromLocal = fromLocal,
reactions = msg.emojis
) { showReactionDialog = msg.emojis }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,30 @@

package com.geeksville.mesh.ui.message.components

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.FlowRowOverflow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Badge
import androidx.compose.material.BadgedBox
import androidx.compose.material.ContentAlpha
import androidx.compose.material.Divider
import androidx.compose.material.Icon
Expand All @@ -43,7 +49,7 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.EmojiEmotions
import androidx.compose.material.icons.filled.AddReaction
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -53,10 +59,10 @@ 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.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.database.entity.Reaction
import com.geeksville.mesh.ui.components.BottomSheetDialog
Expand All @@ -80,7 +86,7 @@ fun ReactionButton(
}
IconButton(onClick = { showEmojiPickerDialog = true }) {
Icon(
imageVector = Icons.Default.EmojiEmotions,
imageVector = Icons.Default.AddReaction,
contentDescription = "emoji",
modifier = modifier.size(16.dp),
tint = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.medium),
Expand All @@ -94,42 +100,59 @@ private fun ReactionItem(
emojiCount: Int = 1,
onClick: () -> Unit = {},
) {
BadgedBox(
modifier = Modifier.padding(start = 2.dp, top = 8.dp, end = 2.dp, bottom = 4.dp),
badge = {
if (emojiCount > 1) {
Badge(
backgroundColor = MaterialTheme.colors.onBackground,
contentColor = MaterialTheme.colors.background,
) {
Text(
fontWeight = FontWeight.Bold,
text = emojiCount.toString()
)
}
}
}

Surface(
modifier = Modifier
.padding(2.dp)
.border(
1.dp,
MaterialTheme.colors.secondaryVariant.copy(ContentAlpha.medium),
RoundedCornerShape(8.dp)
)
.clickable { onClick() },
color = MaterialTheme.colors.surface.copy(alpha = ContentAlpha.medium),
contentColor = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.medium),
shape = RoundedCornerShape(8.dp),
elevation = 4.dp,
) {
Surface(
Row(
modifier = Modifier
.clickable { onClick() },
color = MaterialTheme.colors.surface,
shape = RoundedCornerShape(32.dp),
elevation = 4.dp,
.background(MaterialTheme.colors.surface)
.padding(4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = emoji,
modifier = Modifier
.padding(8.dp)
.clip(CircleShape),
style = MaterialTheme.typography.h6,
text = emoji
)
if (emojiCount > 0) {
Spacer(
modifier = Modifier.width(2.dp)
)
AnimatedContent(
targetState = emojiCount,
transitionSpec = {
if (targetState > initialState) {
slideInVertically { -it } togetherWith slideOutVertically { it }
} else {
slideInVertically { it } togetherWith slideOutVertically { -it }
}
}
) {
Text(
text = "$it",
style = MaterialTheme.typography.body2,
)
}
}
}
}
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun ReactionRow(
modifier: Modifier = Modifier,
fromLocal: Boolean,
reactions: List<Reaction> = emptyList(),
onSendReaction: (String) -> Unit = {}
Expand All @@ -146,11 +169,21 @@ fun ReactionRow(
)
}

var maxLines by remember { mutableStateOf(1) }
FlowRow(
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
horizontalArrangement = if (fromLocal) Arrangement.End else Arrangement.Start
horizontalArrangement = if (fromLocal) Arrangement.End else Arrangement.Start,
maxLines = maxLines,
overflow = FlowRowOverflow.expandIndicator {
ReactionItem(
emoji = "...",
emojiCount = 0
) {
maxLines += 1
}
}
) {
emojiList.forEach { entry ->
ReactionItem(
Expand All @@ -164,6 +197,23 @@ fun ReactionRow(
}
}

@Composable
internal fun Ellipsis(text: String, onClick: () -> Unit) {
Surface(
color = MaterialTheme.colors.surface,
contentColor = MaterialTheme.colors.onSurface,
modifier = Modifier
.clickable(onClick = onClick)
) {
Text(
modifier = Modifier
.padding(3.dp),
text = text,
fontSize = 18.sp
)
}
}

fun reduceEmojis(emojis: List<String>): Map<String, Int> = emojis.groupingBy { it }.eachCount()

@Composable
Expand Down Expand Up @@ -231,6 +281,7 @@ fun ReactionItemPreview() {
) {
ReactionItem(emoji = "\uD83D\uDE42")
ReactionItem(emoji = "\uD83D\uDE42", emojiCount = 2)
ReactionItem(emoji = "\uD83D\uDE42", emojiCount = 222)
ReactionButton()
}
}
Expand Down
Loading