diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index f4ac199..b5f6f62 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -901,3 +901,13 @@ - Added top mini audio strip under pinned area: - shows latest audio/voice context from loaded chat, - includes play affordance, speed badge, and dismiss action. + +### Step 126 - Message bubble/composer micro-polish +- Updated message bubble sizing and density: + - reduced bubble width for cleaner conversation rhythm, + - tighter vertical spacing, + - text style adjusted for better readability. +- Refined bottom composer visuals: + - switched to Telegram-like rounded input container look, + - emoji/attach/send buttons now use circular tinted surfaces, + - text input moved to filled style with hidden indicator lines. 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 6df7839..1779188 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 @@ -58,6 +58,8 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -1012,9 +1014,9 @@ fun ChatScreen( .fillMaxWidth() .navigationBarsPadding() .imePadding() - .padding(horizontal = 10.dp, vertical = 8.dp), - color = MaterialTheme.colorScheme.surface.copy(alpha = 0.92f), - shape = RoundedCornerShape(24.dp), + .padding(horizontal = 10.dp, vertical = 6.dp), + color = MaterialTheme.colorScheme.surface.copy(alpha = 0.95f), + shape = RoundedCornerShape(22.dp), ) { Row( modifier = Modifier @@ -1023,30 +1025,49 @@ fun ChatScreen( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp), ) { - IconButton( - onClick = { /* emoji picker step */ }, - enabled = state.canSendMessages, + Surface( + shape = CircleShape, + color = MaterialTheme.colorScheme.primary.copy(alpha = 0.14f), ) { - Icon( - imageVector = Icons.Filled.EmojiEmotions, - contentDescription = "Emoji", - ) + IconButton( + onClick = { /* emoji picker step */ }, + enabled = state.canSendMessages, + ) { + Icon( + imageVector = Icons.Filled.EmojiEmotions, + contentDescription = "Emoji", + ) + } } - OutlinedTextField( + TextField( value = state.inputText, onValueChange = onInputChanged, modifier = Modifier.weight(1f), placeholder = { Text("Message") }, + shape = RoundedCornerShape(14.dp), maxLines = 4, + colors = TextFieldDefaults.colors( + focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.45f), + unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f), + disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.25f), + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, + ), ) - IconButton( - onClick = onPickMedia, - enabled = state.canSendMessages && !state.isUploadingMedia && !state.isRecordingVoice, + Surface( + shape = CircleShape, + color = MaterialTheme.colorScheme.primary.copy(alpha = 0.14f), ) { - if (state.isUploadingMedia) { - CircularProgressIndicator(modifier = Modifier.size(18.dp), strokeWidth = 2.dp) - } else { - Icon(imageVector = Icons.Filled.AttachFile, contentDescription = "Attach") + IconButton( + onClick = onPickMedia, + enabled = state.canSendMessages && !state.isUploadingMedia && !state.isRecordingVoice, + ) { + if (state.isUploadingMedia) { + CircularProgressIndicator(modifier = Modifier.size(18.dp), strokeWidth = 2.dp) + } else { + Icon(imageVector = Icons.Filled.AttachFile, contentDescription = "Attach") + } } } val canSend = state.canSendMessages && @@ -1054,11 +1075,16 @@ fun ChatScreen( !state.isUploadingMedia && state.inputText.isNotBlank() if (canSend) { - IconButton( - onClick = onSendClick, - enabled = state.canSendMessages && !state.isUploadingMedia, + Surface( + shape = CircleShape, + color = MaterialTheme.colorScheme.primary.copy(alpha = 0.18f), ) { - Icon(imageVector = Icons.AutoMirrored.Filled.Send, contentDescription = "Send") + IconButton( + onClick = onSendClick, + enabled = state.canSendMessages && !state.isUploadingMedia, + ) { + Icon(imageVector = Icons.AutoMirrored.Filled.Send, contentDescription = "Send") + } } } else { VoiceHoldToRecordButton( @@ -1291,7 +1317,7 @@ private fun MessageBubble( } Column( modifier = Modifier - .fillMaxWidth(0.84f) + .fillMaxWidth(0.8f) .widthIn(min = 82.dp) .background( color = when { @@ -1305,8 +1331,8 @@ private fun MessageBubble( onClick = onClick, onLongClick = onLongPress, ) - .padding(horizontal = 10.dp, vertical = 8.dp), - verticalArrangement = Arrangement.spacedBy(4.dp), + .padding(horizontal = 10.dp, vertical = 7.dp), + verticalArrangement = Arrangement.spacedBy(3.dp), ) { if (!isOutgoing && !message.senderDisplayName.isNullOrBlank()) { Text( @@ -1373,7 +1399,7 @@ private fun MessageBubble( if (mainText != null || message.attachments.isEmpty()) { Text( text = mainText ?: "[${message.type}]", - style = MaterialTheme.typography.bodyMedium, + style = MaterialTheme.typography.bodyLarge, color = textColor, ) }