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 9115e39..9fb9cb7 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 @@ -612,6 +612,7 @@ private fun ChatScreen( state.isCounterpartRelationshipResolved && !state.isCounterpartContact && !state.isCounterpartBlocked + val showPrivateInfoCard = isPrivateChat && state.counterpartUserId != null val canShowMembersTab = state.chatType.equals("group", ignoreCase = true) || (state.chatType.equals("channel", ignoreCase = true) && state.canManageMembers) val timelineItems = remember(state.messages, context) { buildChatTimelineItems(state.messages, context) } @@ -1165,6 +1166,26 @@ private fun ChatScreen( } } } + AnimatedVisibility( + visible = showPrivateInfoCard, + enter = fadeIn(animationSpec = tween(180)) + slideInVertically( + initialOffsetY = { -it / 4 }, + animationSpec = tween(180), + ), + exit = fadeOut(animationSpec = tween(120)) + slideOutVertically( + targetOffsetY = { -it / 4 }, + animationSpec = tween(120), + ), + ) { + PrivateChatInfoCard( + title = state.counterpartName?.takeIf { it.isNotBlank() } ?: state.chatTitle, + username = state.counterpartUsername, + avatarUrl = state.chatAvatarUrl, + statusText = state.baseChatSubtitle.takeIf { it.isNotBlank() }, + isContact = state.isCounterpartContact, + isBlocked = state.isCounterpartBlocked, + ) + } val strip = topAudioStrip if (strip != null) { Row( @@ -2242,6 +2263,103 @@ private enum class ChatViewerMediaType { Video, } +@Composable +private fun PrivateChatInfoCard( + title: String, + username: String?, + avatarUrl: String?, + statusText: String?, + isContact: Boolean, + isBlocked: Boolean, +) { + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 6.dp), + shape = RoundedCornerShape(20.dp), + color = MaterialTheme.colorScheme.surface.copy(alpha = 0.78f), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 14.dp, vertical = 12.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + if (!avatarUrl.isNullOrBlank()) { + AsyncImage( + model = avatarUrl, + contentDescription = "Private chat avatar", + modifier = Modifier + .size(54.dp) + .clip(CircleShape), + contentScale = ContentScale.Crop, + ) + } else { + Box( + modifier = Modifier + .size(54.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primary.copy(alpha = 0.18f)), + contentAlignment = Alignment.Center, + ) { + Text( + text = title.firstOrNull()?.uppercase() ?: "?", + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight.Bold, + ) + } + } + + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + Text( + text = title.ifBlank { stringResource(id = R.string.chat_unknown_user) }, + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.SemiBold, + ) + username?.takeIf { it.isNotBlank() }?.let { + Text( + text = "@$it", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.primary, + ) + } + statusText?.let { + Text( + text = it, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } + + Column( + horizontalAlignment = Alignment.End, + verticalArrangement = Arrangement.spacedBy(6.dp), + ) { + if (isContact) { + AssistChip( + onClick = {}, + enabled = false, + label = { Text(stringResource(id = R.string.chat_private_info_contact)) }, + ) + } + if (isBlocked) { + AssistChip( + onClick = {}, + enabled = false, + label = { Text(stringResource(id = R.string.chat_private_info_blocked)) }, + ) + } + } + } + } +} + private data class ChatViewerMediaItem( val url: String, val type: ChatViewerMediaType, diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatViewModel.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatViewModel.kt index c298284..a249e5e 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatViewModel.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatViewModel.kt @@ -778,6 +778,10 @@ class ChatViewModel @Inject constructor( it.copy( chatType = chat.type, counterpartUserId = chat.counterpartUserId, + counterpartName = chat.counterpartName, + counterpartUsername = chat.counterpartUsername, + counterpartIsOnline = chat.counterpartIsOnline, + counterpartLastSeenAt = chat.counterpartLastSeenAt, isCounterpartRelationshipResolved = if (chat.type.equals("private", ignoreCase = true) && chat.counterpartUserId != null) { it.isCounterpartRelationshipResolved } else { diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/MessageUiState.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/MessageUiState.kt index 25d94be..7d5bab1 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/MessageUiState.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/MessageUiState.kt @@ -19,6 +19,10 @@ data class MessageUiState( val chatAvatarUrl: String? = null, val chatType: String = "", val counterpartUserId: Long? = null, + val counterpartName: String? = null, + val counterpartUsername: String? = null, + val counterpartIsOnline: Boolean? = null, + val counterpartLastSeenAt: String? = null, val chatRole: String? = null, val chatMuted: Boolean = false, val chatUnreadCount: Int = 0, diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml index d8e9570..a607e2b 100644 --- a/android/app/src/main/res/values-ru/strings.xml +++ b/android/app/src/main/res/values-ru/strings.xml @@ -142,6 +142,8 @@ Можно добавить этого человека в контакты или заблокировать прямо из чата. Добавить контакт Заблокировать + Контакт + Заблокирован группа канал Медиа diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index e77fc57..620b3ac 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -142,6 +142,8 @@ You can add this person to contacts or block them right from the chat. Add contact Block user + Contact + Blocked group channel Media