android: add reply and forwarded blocks to chat bubbles
Some checks failed
CI / test (push) Failing after 2m9s
Some checks failed
CI / test (push) Failing after 2m9s
This commit is contained in:
@@ -195,3 +195,8 @@
|
|||||||
- Added Room self-relation in `MessageLocalModel` to resolve reply preview fallback from referenced message.
|
- Added Room self-relation in `MessageLocalModel` to resolve reply preview fallback from referenced message.
|
||||||
- Updated message mappers and repository/realtime temporary entity creation for new model fields.
|
- Updated message mappers and repository/realtime temporary entity creation for new model fields.
|
||||||
- Bumped Room schema version to `7`.
|
- Bumped Room schema version to `7`.
|
||||||
|
|
||||||
|
### Step 31 - Chat UI / reply-forward bubble blocks
|
||||||
|
- Added inline forwarded header rendering in message bubbles with display-name fallback.
|
||||||
|
- Added inline reply preview block in message bubbles (author + snippet) based on new preview fields/fallbacks.
|
||||||
|
- Updated Telegram UI batch-2 checklist items for reply-preview and forwarded header.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.imePadding
|
import androidx.compose.foundation.layout.imePadding
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
@@ -399,16 +400,51 @@ private fun MessageBubble(
|
|||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (message.forwardedFromMessageId != null || !message.forwardedFromDisplayName.isNullOrBlank()) {
|
||||||
|
Text(
|
||||||
|
text = "Forwarded from ${message.forwardedFromDisplayName?.takeIf { it.isNotBlank() } ?: "#${message.forwardedFromMessageId ?: "?"}"}",
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
color = if (isOutgoing) {
|
||||||
|
MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.78f)
|
||||||
|
} else {
|
||||||
|
MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.78f)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (message.replyToMessageId != null) {
|
||||||
|
val replyAuthor = message.replyPreviewSenderName?.takeIf { it.isNotBlank() }
|
||||||
|
?: "#${message.replyToMessageId}"
|
||||||
|
val replySnippet = message.replyPreviewText?.takeIf { it.isNotBlank() } ?: "[media]"
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 4.dp)
|
||||||
|
.background(
|
||||||
|
color = if (isOutgoing) {
|
||||||
|
MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.16f)
|
||||||
|
} else {
|
||||||
|
MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.16f)
|
||||||
|
},
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
)
|
||||||
|
.padding(horizontal = 8.dp, vertical = 6.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = replyAuthor,
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = replySnippet,
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
maxLines = 2,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Text(
|
Text(
|
||||||
text = message.text ?: "[${message.type}]",
|
text = message.text ?: "[${message.type}]",
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
)
|
)
|
||||||
if (message.forwardedFromMessageId != null) {
|
|
||||||
Text(
|
|
||||||
text = "Forwarded from #${message.forwardedFromMessageId}",
|
|
||||||
style = MaterialTheme.typography.labelSmall,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (reactions.isNotEmpty()) {
|
if (reactions.isNotEmpty()) {
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||||
reactions.forEach { reaction ->
|
reactions.forEach { reaction ->
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
- [ ] Иконка emoji слева, поле ввода, скрепка, кнопка отправки/голосового.
|
- [ ] Иконка emoji слева, поле ввода, скрепка, кнопка отправки/голосового.
|
||||||
- [ ] Корректные отступы от nav bar + IME.
|
- [ ] Корректные отступы от nav bar + IME.
|
||||||
- [ ] Сообщения вход/выход: плотные пузыри, время и delivery статус внизу справа.
|
- [ ] Сообщения вход/выход: плотные пузыри, время и delivery статус внизу справа.
|
||||||
- [ ] Reply-preview внутри outgoing bubble (вертикальная полоска, автор, snippet).
|
- [x] Reply-preview внутри outgoing bubble (вертикальная полоска, автор, snippet).
|
||||||
- [ ] Forwarded header в сообщении ("Переслано от ...") + мини-аватар.
|
- [x] Forwarded header в сообщении ("Переслано от ...") + мини-аватар.
|
||||||
- [ ] Поддержка chat wallpaper (обои в фоне, читабельный контраст поверх).
|
- [ ] Поддержка chat wallpaper (обои в фоне, читабельный контраст поверх).
|
||||||
|
|
||||||
## P0 — Voice/Audio Message UI
|
## P0 — Voice/Audio Message UI
|
||||||
|
|||||||
Reference in New Issue
Block a user