Fix: Ensure sender's name truncates correctly in incoming messages
This commit resolves an issue where the sender's name in incoming message bubbles would not truncate properly, potentially breaking the layout. The fix ensures the name text correctly adapts to the width of the message bubble. Additionally, this change introduces `ImmutableList` for message attachments to improve performance and refactors where the conversion to `ImmutableList` happens, moving it into the `MessageMapper`. Key changes: - The `MessageBubble` now reports its width, allowing the sender's name `Text` to be constrained correctly. - Sender's name now uses `labelMedium` typography. - Enabled showing the sender's name by default in `MessagesHistoryViewModelImpl`. - Changed `UiItem.Message.attachments` from `List` to `ImmutableList` for better Compose performance. - Moved the `toImmutableList()` conversion for attachments into the `MessageMapper`.
This commit is contained in:
+1
-1
@@ -1231,7 +1231,7 @@ class MessagesHistoryViewModelImpl(
|
|||||||
val newUiMessages = messages.mapIndexed { index, message ->
|
val newUiMessages = messages.mapIndexed { index, message ->
|
||||||
message.asPresentation(
|
message.asPresentation(
|
||||||
resourceProvider = resourceProvider,
|
resourceProvider = resourceProvider,
|
||||||
showName = false,
|
showName = true,
|
||||||
prevMessage = messages.getOrNull(index + 1),
|
prevMessage = messages.getOrNull(index + 1),
|
||||||
nextMessage = messages.getOrNull(index - 1),
|
nextMessage = messages.getOrNull(index - 1),
|
||||||
showTimeInActionMessages = AppSettings.Experimental.showTimeInActionMessages,
|
showTimeInActionMessages = AppSettings.Experimental.showTimeInActionMessages,
|
||||||
|
|||||||
+2
-1
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable
|
|||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import dev.meloda.fast.common.model.UiImage
|
import dev.meloda.fast.common.model.UiImage
|
||||||
import dev.meloda.fast.model.api.domain.VkAttachment
|
import dev.meloda.fast.model.api.domain.VkAttachment
|
||||||
|
import dev.meloda.fast.ui.util.ImmutableList
|
||||||
|
|
||||||
sealed class UiItem(
|
sealed class UiItem(
|
||||||
open val id: Long,
|
open val id: Long,
|
||||||
@@ -31,7 +32,7 @@ sealed class UiItem(
|
|||||||
val isSelected: Boolean,
|
val isSelected: Boolean,
|
||||||
val isPinned: Boolean,
|
val isPinned: Boolean,
|
||||||
val isImportant: Boolean,
|
val isImportant: Boolean,
|
||||||
val attachments: List<VkAttachment>?,
|
val attachments: ImmutableList<VkAttachment>?,
|
||||||
val replyCmId: Long?,
|
val replyCmId: Long?,
|
||||||
val replyTitle: String?,
|
val replyTitle: String?,
|
||||||
val replySummary: String?
|
val replySummary: String?
|
||||||
|
|||||||
+6
-1
@@ -27,6 +27,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
|
import androidx.compose.ui.layout.onSizeChanged
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
@@ -58,7 +59,8 @@ fun MessageBubble(
|
|||||||
replySummary: String? = null,
|
replySummary: String? = null,
|
||||||
onClick: (VkAttachment) -> Unit = {},
|
onClick: (VkAttachment) -> Unit = {},
|
||||||
onLongClick: (VkAttachment) -> Unit = {},
|
onLongClick: (VkAttachment) -> Unit = {},
|
||||||
onReplyClick: () -> Unit = {}
|
onReplyClick: () -> Unit = {},
|
||||||
|
onBubbleWidthChange: (Int) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
|
|
||||||
@@ -149,6 +151,9 @@ fun MessageBubble(
|
|||||||
.onGloballyPositioned {
|
.onGloballyPositioned {
|
||||||
bubbleContainerWidth = it.size.width
|
bubbleContainerWidth = it.size.width
|
||||||
}
|
}
|
||||||
|
.onSizeChanged {
|
||||||
|
onBubbleWidthChange(it.width)
|
||||||
|
}
|
||||||
.widthIn(min = if (shouldFill) attachmentsContainerWidth.dp else 56.dp)
|
.widthIn(min = if (shouldFill) attachmentsContainerWidth.dp else 56.dp)
|
||||||
.clip(
|
.clip(
|
||||||
RoundedCornerShape(
|
RoundedCornerShape(
|
||||||
|
|||||||
+20
-6
@@ -20,12 +20,16 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberUpdatedState
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
@@ -36,7 +40,6 @@ import com.conena.nanokt.android.content.dpInPx
|
|||||||
import dev.meloda.fast.messageshistory.model.UiItem
|
import dev.meloda.fast.messageshistory.model.UiItem
|
||||||
import dev.meloda.fast.model.api.domain.VkAttachment
|
import dev.meloda.fast.model.api.domain.VkAttachment
|
||||||
import dev.meloda.fast.ui.R
|
import dev.meloda.fast.ui.R
|
||||||
import dev.meloda.fast.ui.util.ImmutableList.Companion.toImmutableList
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -49,10 +52,16 @@ fun IncomingMessageBubble(
|
|||||||
onLongClick: (VkAttachment) -> Unit = {},
|
onLongClick: (VkAttachment) -> Unit = {},
|
||||||
onReplyClick: () -> Unit = {}
|
onReplyClick: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
|
val density = LocalDensity.current
|
||||||
|
|
||||||
val currentOnClick by rememberUpdatedState(onClick)
|
val currentOnClick by rememberUpdatedState(onClick)
|
||||||
val currentOnLongClick by rememberUpdatedState(onLongClick)
|
val currentOnLongClick by rememberUpdatedState(onLongClick)
|
||||||
val currentOnReplyClick by rememberUpdatedState(onReplyClick)
|
val currentOnReplyClick by rememberUpdatedState(onReplyClick)
|
||||||
|
|
||||||
|
var bubbleContainerWidth by remember {
|
||||||
|
mutableStateOf(0.dp)
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -103,9 +112,12 @@ fun IncomingMessageBubble(
|
|||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = 12.dp)
|
.padding(start = 12.dp)
|
||||||
.widthIn(max = 140.dp),
|
.widthIn(
|
||||||
|
max = (bubbleContainerWidth.takeIf { it > 0.dp }
|
||||||
|
?: 140.dp) - 24.dp
|
||||||
|
),
|
||||||
text = message.name,
|
text = message.name,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
@@ -123,14 +135,16 @@ fun IncomingMessageBubble(
|
|||||||
isPinned = message.isPinned,
|
isPinned = message.isPinned,
|
||||||
isImportant = message.isImportant,
|
isImportant = message.isImportant,
|
||||||
isSelected = message.isSelected,
|
isSelected = message.isSelected,
|
||||||
attachments = message.attachments?.toImmutableList(),
|
attachments = message.attachments,
|
||||||
replyTitle = message.replyTitle,
|
replyTitle = message.replyTitle,
|
||||||
replySummary = message.replySummary,
|
replySummary = message.replySummary,
|
||||||
onClick = currentOnClick,
|
onClick = currentOnClick,
|
||||||
onLongClick = currentOnLongClick,
|
onLongClick = currentOnLongClick,
|
||||||
onReplyClick = currentOnReplyClick
|
onReplyClick = currentOnReplyClick,
|
||||||
|
onBubbleWidthChange = {
|
||||||
|
bubbleContainerWidth = with(density) { it.toDp() }
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.fillMaxWidth(0.25f))
|
Spacer(modifier = Modifier.fillMaxWidth(0.25f))
|
||||||
|
|||||||
+1
-1
@@ -80,7 +80,7 @@ fun OutgoingMessageBubble(
|
|||||||
isPinned = message.isPinned,
|
isPinned = message.isPinned,
|
||||||
isImportant = message.isImportant,
|
isImportant = message.isImportant,
|
||||||
isSelected = message.isSelected,
|
isSelected = message.isSelected,
|
||||||
attachments = message.attachments?.toImmutableList(),
|
attachments = message.attachments,
|
||||||
replyTitle = message.replyTitle,
|
replyTitle = message.replyTitle,
|
||||||
replySummary = message.replySummary,
|
replySummary = message.replySummary,
|
||||||
onClick = currentOnClick,
|
onClick = currentOnClick,
|
||||||
|
|||||||
+2
-1
@@ -24,6 +24,7 @@ import dev.meloda.fast.model.api.domain.FormatDataType
|
|||||||
import dev.meloda.fast.model.api.domain.VkConversation
|
import dev.meloda.fast.model.api.domain.VkConversation
|
||||||
import dev.meloda.fast.model.api.domain.VkMessage
|
import dev.meloda.fast.model.api.domain.VkMessage
|
||||||
import dev.meloda.fast.ui.R
|
import dev.meloda.fast.ui.R
|
||||||
|
import dev.meloda.fast.ui.util.ImmutableList.Companion.toImmutableList
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@@ -156,7 +157,7 @@ fun VkMessage.asPresentation(
|
|||||||
isSelected = isSelected,
|
isSelected = isSelected,
|
||||||
isPinned = isPinned,
|
isPinned = isPinned,
|
||||||
isImportant = isImportant,
|
isImportant = isImportant,
|
||||||
attachments = attachments?.ifEmpty { null },
|
attachments = attachments?.ifEmpty { null }?.toImmutableList(),
|
||||||
replyCmId = replyMessage?.cmId,
|
replyCmId = replyMessage?.cmId,
|
||||||
replyTitle = extractReplyTitle(),
|
replyTitle = extractReplyTitle(),
|
||||||
replySummary = extractReplySummary()
|
replySummary = extractReplySummary()
|
||||||
|
|||||||
Reference in New Issue
Block a user