From 90c25c5eb8753aa7847f5f6d5134ecd6cc66e860 Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 10 Mar 2026 01:32:19 +0300 Subject: [PATCH] android: polish chat info tabs and media grid layout --- android/CHANGELOG.md | 8 ++ .../messenger/ui/chat/ChatScreen.kt | 96 ++++++++++++++++--- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index c67ec6f..41265d5 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -876,3 +876,11 @@ - `Links` - `Voice` - Implemented local tab content from current loaded chat messages/attachments to provide immediate media/files/links/voice overview. + +### Step 123 - Chat info visual pass (Telegram-like density) +- Updated `Chat info` tabs to pill-style horizontal chips with tighter Telegram-like spacing. +- Improved tab content rendering: + - `Media` now uses a 3-column thumbnail grid. + - `Files / Links / Voice` use denser card rows with icon+meta layout. + - `Voice` rows now show a dedicated play affordance. +- Refined menu order in chat `3-dot` popup and kept actions consistent with current no-calls scope. diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt index 729b515..b0f9548 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt @@ -33,10 +33,16 @@ import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.rememberScrollState import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api @@ -103,6 +109,7 @@ import androidx.compose.material.icons.filled.Wallpaper import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.Link +import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.icons.automirrored.filled.InsertDriveFile import coil.compose.AsyncImage import kotlinx.coroutines.flow.collectLatest @@ -444,13 +451,13 @@ fun ChatScreen( }, ) DropdownMenuItem( - text = { Text("Notifications") }, - leadingIcon = { Icon(Icons.Filled.Notifications, contentDescription = null) }, + text = { Text("Change wallpaper") }, + leadingIcon = { Icon(Icons.Filled.Wallpaper, contentDescription = null) }, onClick = { showChatMenu = false }, ) DropdownMenuItem( - text = { Text("Change wallpaper") }, - leadingIcon = { Icon(Icons.Filled.Wallpaper, contentDescription = null) }, + text = { Text("Notifications") }, + leadingIcon = { Icon(Icons.Filled.Notifications, contentDescription = null) }, onClick = { showChatMenu = false }, ) DropdownMenuItem( @@ -795,7 +802,9 @@ fun ChatScreen( } } Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .horizontalScroll(rememberScrollState()), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { ChatInfoTab.entries.forEach { tab -> @@ -803,19 +812,16 @@ fun ChatScreen( Surface( shape = RoundedCornerShape(16.dp), color = if (selected) { - MaterialTheme.colorScheme.primary.copy(alpha = 0.22f) + MaterialTheme.colorScheme.primary.copy(alpha = 0.24f) } else { - MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f) + MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.48f) }, modifier = Modifier - .weight(1f) .clip(RoundedCornerShape(16.dp)) .clickable { chatInfoTab = tab }, ) { Box( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 8.dp), + modifier = Modifier.padding(horizontal = 14.dp, vertical = 8.dp), contentAlignment = Alignment.Center, ) { Text( @@ -1743,6 +1749,7 @@ private data class ChatInfoEntry( val title: String, val subtitle: String, val previewImageUrl: String? = null, + val previewIsVideo: Boolean = false, ) @Composable @@ -1775,6 +1782,61 @@ private fun ChatInfoTabContent( } return } + if (tab == ChatInfoTab.Media) { + LazyVerticalGrid( + columns = GridCells.Fixed(3), + modifier = Modifier + .fillMaxWidth() + .height(320.dp), + verticalArrangement = Arrangement.spacedBy(2.dp), + horizontalArrangement = Arrangement.spacedBy(2.dp), + ) { + items(filtered.take(120)) { entry -> + Box( + modifier = Modifier + .fillMaxWidth() + .aspectRatio(1f) + .clip(RoundedCornerShape(4.dp)) + .background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f)), + ) { + if (!entry.previewImageUrl.isNullOrBlank()) { + AsyncImage( + model = entry.previewImageUrl, + contentDescription = null, + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop, + ) + } else { + Icon( + imageVector = Icons.Filled.Movie, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .align(Alignment.Center) + .size(20.dp), + ) + } + if (entry.previewIsVideo) { + Surface( + shape = RoundedCornerShape(8.dp), + color = Color.Black.copy(alpha = 0.5f), + modifier = Modifier + .align(Alignment.BottomStart) + .padding(6.dp), + ) { + Text( + text = "Video", + modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp), + style = MaterialTheme.typography.labelSmall, + color = Color.White, + ) + } + } + } + } + } + return + } LazyColumn( modifier = Modifier .fillMaxWidth() @@ -1786,8 +1848,8 @@ private fun ChatInfoTabContent( modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(12.dp)) - .background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f)) - .padding(10.dp), + .background(MaterialTheme.colorScheme.surface.copy(alpha = 0.55f)) + .padding(horizontal = 10.dp, vertical = 9.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp), ) { @@ -1835,6 +1897,13 @@ private fun ChatInfoTabContent( maxLines = 2, ) } + if (tab == ChatInfoTab.Voice) { + Icon( + imageVector = Icons.Filled.PlayArrow, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + ) + } } } } @@ -1857,6 +1926,7 @@ private fun buildChatInfoEntries(messages: List): List