android: refine chats list typography badges and time format
Some checks failed
Android CI / android (push) Has started running
Android Release / release (push) Has been cancelled
CI / test (push) Has been cancelled

This commit is contained in:
Codex
2026-03-09 21:40:04 +03:00
parent e717888d8e
commit 2324801f56
2 changed files with 48 additions and 19 deletions

View File

@@ -537,3 +537,12 @@
- Kept search in top app bar action and changed search field default to collapsed (opens via search icon).
- Returned message-type emoji markers in chat previews:
- `🖼` photo, `🎤` voice, `🎵` audio, `🎥` video, `⭕` circle video, `🔗` links.
### Step 87 - Chats list micro-typography and time formatting
- Refined chat row typography hierarchy to be closer to Telegram density:
- title/body/presence font scale aligned and single-line ellipsis for long values.
- Tightened unread/mention badge sizing and spacing for compact right-side metadata.
- Updated trailing time formatter:
- today: `HH:mm`,
- this week: localized short weekday,
- older: `dd.MM.yy`.

View File

@@ -47,6 +47,7 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -60,8 +61,11 @@ import kotlinx.coroutines.flow.collectLatest
import coil.compose.AsyncImage
import ru.daemonlord.messenger.domain.chat.model.ChatItem
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import java.util.Locale
@Composable
fun ChatListRoute(
@@ -576,20 +580,21 @@ private fun ChatRow(
) {
Text(
text = chat.displayTitle,
style = MaterialTheme.typography.titleLarge,
style = MaterialTheme.typography.titleMedium,
fontWeight = if (chat.unreadCount > 0) FontWeight.SemiBold else FontWeight.Normal,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
if (chat.pinned) {
Text(
text = "📌",
style = MaterialTheme.typography.labelMedium,
style = MaterialTheme.typography.labelSmall,
)
}
if (chat.muted) {
Text(
text = "🔕",
style = MaterialTheme.typography.labelMedium,
style = MaterialTheme.typography.labelSmall,
)
}
}
@@ -597,9 +602,10 @@ private fun ChatRow(
if (preview.isNotBlank()) {
Text(
text = preview,
style = MaterialTheme.typography.bodyLarge,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(top = 1.dp),
)
}
@@ -619,7 +625,7 @@ private fun ChatRow(
}
Column(
horizontalAlignment = Alignment.End,
verticalArrangement = Arrangement.spacedBy(5.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
Text(
text = formatChatTime(chat.lastMessageCreatedAt),
@@ -636,28 +642,42 @@ private fun ChatRow(
}
}
@Composable
private fun BadgeChip(label: String) {
AssistChip(
onClick = {},
enabled = false,
label = { Text(text = label) },
colors = AssistChipDefaults.assistChipColors(
disabledContainerColor = MaterialTheme.colorScheme.primaryContainer,
disabledLabelColor = MaterialTheme.colorScheme.onPrimaryContainer,
),
)
}
private val chatTimeFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")
private val chatDateFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yy")
private val chatWeekdayFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("EEE", Locale.getDefault())
private fun formatChatTime(iso: String?): String {
if (iso.isNullOrBlank()) return ""
return runCatching {
Instant.parse(iso).atZone(ZoneId.systemDefault()).toLocalTime().format(chatTimeFormatter)
val zoned = Instant.parse(iso).atZone(ZoneId.systemDefault())
val messageDate = zoned.toLocalDate()
val today = LocalDate.now(ZoneId.systemDefault())
when {
messageDate == today -> zoned.toLocalTime().format(chatTimeFormatter)
ChronoUnit.DAYS.between(messageDate, today) in 1..6 -> zoned.format(chatWeekdayFormatter)
else -> zoned.format(chatDateFormatter)
}
}.getOrElse { "" }
}
@Composable
private fun BadgeChip(label: String) {
Box(
modifier = Modifier
.clip(RoundedCornerShape(10.dp))
.background(MaterialTheme.colorScheme.primaryContainer)
.padding(horizontal = 8.dp, vertical = 2.dp),
contentAlignment = Alignment.Center,
) {
Text(
text = label,
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onPrimaryContainer,
fontWeight = FontWeight.SemiBold,
)
}
}
@Composable
private fun FilterChip(
label: String,