Поправлен визуал пузырьков со звонками
This commit is contained in:
@@ -1277,7 +1277,8 @@ fun MainScreen(
|
|||||||
isDarkTheme = isDarkTheme,
|
isDarkTheme = isDarkTheme,
|
||||||
chatWallpaperId = chatWallpaperId,
|
chatWallpaperId = chatWallpaperId,
|
||||||
avatarRepository = avatarRepository,
|
avatarRepository = avatarRepository,
|
||||||
onImageViewerChanged = { isLocked -> isChatSwipeLocked = isLocked }
|
onImageViewerChanged = { isLocked -> isChatSwipeLocked = isLocked },
|
||||||
|
isCallActive = callUiState.isVisible
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ object CallManager {
|
|||||||
updateState {
|
updateState {
|
||||||
it.copy(
|
it.copy(
|
||||||
phase = CallPhase.OUTGOING,
|
phase = CallPhase.OUTGOING,
|
||||||
statusText = "Calling..."
|
statusText = "Calling"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -295,7 +295,8 @@ fun ChatDetailScreen(
|
|||||||
isDarkTheme: Boolean,
|
isDarkTheme: Boolean,
|
||||||
chatWallpaperId: String = "",
|
chatWallpaperId: String = "",
|
||||||
avatarRepository: AvatarRepository? = null,
|
avatarRepository: AvatarRepository? = null,
|
||||||
onImageViewerChanged: (Boolean) -> Unit = {}
|
onImageViewerChanged: (Boolean) -> Unit = {},
|
||||||
|
isCallActive: Boolean = false
|
||||||
) {
|
) {
|
||||||
val viewModel: ChatViewModel = viewModel(key = "chat_${user.publicKey}")
|
val viewModel: ChatViewModel = viewModel(key = "chat_${user.publicKey}")
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@@ -381,6 +382,13 @@ fun ChatDetailScreen(
|
|||||||
// Логирование изменений selection mode
|
// Логирование изменений selection mode
|
||||||
LaunchedEffect(isSelectionMode, selectedMessages.size) {}
|
LaunchedEffect(isSelectionMode, selectedMessages.size) {}
|
||||||
|
|
||||||
|
// Сброс выделения при начале звонка
|
||||||
|
LaunchedEffect(isCallActive) {
|
||||||
|
if (isCallActive) {
|
||||||
|
selectedMessages = emptySet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 🔥 Backup: если клавиатура ещё открыта когда selection mode активировался
|
// 🔥 Backup: если клавиатура ещё открыта когда selection mode активировался
|
||||||
// (клавиатура уже должна быть закрыта в onLongClick, это только backup)
|
// (клавиатура уже должна быть закрыта в onLongClick, это только backup)
|
||||||
LaunchedEffect(isSelectionMode) {
|
LaunchedEffect(isSelectionMode) {
|
||||||
@@ -2974,7 +2982,7 @@ fun ChatDetailScreen(
|
|||||||
avatarRepository =
|
avatarRepository =
|
||||||
avatarRepository,
|
avatarRepository,
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
if (simplePickerPreviewUri != null) {
|
if (simplePickerPreviewUri != null || isCallActive) {
|
||||||
return@MessageBubble
|
return@MessageBubble
|
||||||
}
|
}
|
||||||
// 📳 Haptic feedback при долгом нажатии
|
// 📳 Haptic feedback при долгом нажатии
|
||||||
@@ -3017,7 +3025,7 @@ fun ChatDetailScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
if (simplePickerPreviewUri != null) {
|
if (simplePickerPreviewUri != null || isCallActive) {
|
||||||
return@MessageBubble
|
return@MessageBubble
|
||||||
}
|
}
|
||||||
if (shouldIgnoreTapAfterLongPress(
|
if (shouldIgnoreTapAfterLongPress(
|
||||||
@@ -3039,12 +3047,17 @@ fun ChatDetailScreen(
|
|||||||
message.attachments.all {
|
message.attachments.all {
|
||||||
it.type == AttachmentType.IMAGE
|
it.type == AttachmentType.IMAGE
|
||||||
}
|
}
|
||||||
|
val isCallMessage =
|
||||||
|
message.attachments.isNotEmpty() &&
|
||||||
|
message.attachments.all {
|
||||||
|
it.type == AttachmentType.CALL
|
||||||
|
}
|
||||||
if (isSelectionMode) {
|
if (isSelectionMode) {
|
||||||
toggleMessageSelection(
|
toggleMessageSelection(
|
||||||
selectionKey,
|
selectionKey,
|
||||||
!hasAvatar
|
!hasAvatar
|
||||||
)
|
)
|
||||||
} else if (!hasAvatar && !isPhotoOnly) {
|
} else if (!hasAvatar && (!isPhotoOnly || isCallMessage)) {
|
||||||
// 💬 Tap = context menu
|
// 💬 Tap = context menu
|
||||||
contextMenuMessage = message
|
contextMenuMessage = message
|
||||||
showContextMenu = true
|
showContextMenu = true
|
||||||
|
|||||||
@@ -1593,7 +1593,7 @@ private fun resolveDesktopCallUi(preview: String, isOutgoing: Boolean): DesktopC
|
|||||||
}
|
}
|
||||||
val subtitle =
|
val subtitle =
|
||||||
if (isError) {
|
if (isError) {
|
||||||
"Call was not answered or was rejected"
|
if (isOutgoing) "Rejected" else "Missed"
|
||||||
} else {
|
} else {
|
||||||
formatDesktopCallDuration(durationSec)
|
formatDesktopCallDuration(durationSec)
|
||||||
}
|
}
|
||||||
@@ -1612,19 +1612,14 @@ fun CallAttachment(
|
|||||||
val callUi = remember(attachment.preview, isOutgoing) {
|
val callUi = remember(attachment.preview, isOutgoing) {
|
||||||
resolveDesktopCallUi(attachment.preview, isOutgoing)
|
resolveDesktopCallUi(attachment.preview, isOutgoing)
|
||||||
}
|
}
|
||||||
val containerShape = RoundedCornerShape(10.dp)
|
val containerShape = RoundedCornerShape(17.dp)
|
||||||
val containerBackground =
|
val containerBackground =
|
||||||
if (isOutgoing) {
|
if (isOutgoing) {
|
||||||
Color.White.copy(alpha = 0.12f)
|
PrimaryBlue
|
||||||
} else {
|
} else {
|
||||||
if (isDarkTheme) Color(0xFF1F2733) else Color(0xFFF3F8FF)
|
if (isDarkTheme) Color(0xFF212121) else Color(0xFFF5F5F5)
|
||||||
}
|
|
||||||
val containerBorder =
|
|
||||||
if (isOutgoing) {
|
|
||||||
Color.White.copy(alpha = 0.2f)
|
|
||||||
} else {
|
|
||||||
if (isDarkTheme) Color(0xFF33435A) else Color(0xFFD8E5F4)
|
|
||||||
}
|
}
|
||||||
|
val containerBorder = Color.Transparent
|
||||||
val iconBackground = if (callUi.isError) Color(0xFFE55A5A) else PrimaryBlue
|
val iconBackground = if (callUi.isError) Color(0xFFE55A5A) else PrimaryBlue
|
||||||
val iconVector =
|
val iconVector =
|
||||||
when {
|
when {
|
||||||
@@ -1690,59 +1685,6 @@ fun CallAttachment(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOutgoing) {
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
||||||
Text(
|
|
||||||
text = android.text.format.DateFormat.format("HH:mm", timestamp).toString(),
|
|
||||||
fontSize = 11.sp,
|
|
||||||
color = Color.White.copy(alpha = 0.7f)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
|
||||||
when (messageStatus) {
|
|
||||||
MessageStatus.SENDING -> {
|
|
||||||
Icon(
|
|
||||||
painter = TelegramIcons.Clock,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
|
||||||
modifier = Modifier.size(14.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
MessageStatus.SENT, MessageStatus.DELIVERED -> {
|
|
||||||
Icon(
|
|
||||||
painter = TelegramIcons.Done,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color.White.copy(alpha = 0.8f),
|
|
||||||
modifier = Modifier.size(14.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
MessageStatus.READ -> {
|
|
||||||
Box(modifier = Modifier.height(14.dp)) {
|
|
||||||
Icon(
|
|
||||||
painter = TelegramIcons.Done,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color.White,
|
|
||||||
modifier = Modifier.size(14.dp)
|
|
||||||
)
|
|
||||||
Icon(
|
|
||||||
painter = TelegramIcons.Done,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color.White,
|
|
||||||
modifier = Modifier.size(14.dp).offset(x = 4.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MessageStatus.ERROR -> {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Error,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color(0xFFE53935),
|
|
||||||
modifier = Modifier.size(14.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -666,6 +666,15 @@ fun MessageBubble(
|
|||||||
.IMAGE
|
.IMAGE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val isCallMessage =
|
||||||
|
message.attachments.isNotEmpty() &&
|
||||||
|
message.text.isEmpty() &&
|
||||||
|
message.replyData == null &&
|
||||||
|
message.forwardedMessages.isEmpty() &&
|
||||||
|
message.attachments.all {
|
||||||
|
it.type == AttachmentType.CALL
|
||||||
|
}
|
||||||
|
|
||||||
val isStandaloneGroupInvite =
|
val isStandaloneGroupInvite =
|
||||||
message.attachments.isEmpty() &&
|
message.attachments.isEmpty() &&
|
||||||
message.replyData == null &&
|
message.replyData == null &&
|
||||||
@@ -794,7 +803,8 @@ fun MessageBubble(
|
|||||||
onLongClick = onLongClick
|
onLongClick = onLongClick
|
||||||
)
|
)
|
||||||
.then(
|
.then(
|
||||||
if (false) {
|
if (isCallMessage) {
|
||||||
|
// Звонки без фонового пузырька — у них свой контейнер внутри CallAttachment
|
||||||
Modifier
|
Modifier
|
||||||
} else {
|
} else {
|
||||||
Modifier.clip(bubbleShape)
|
Modifier.clip(bubbleShape)
|
||||||
|
|||||||
@@ -652,12 +652,17 @@ fun MessageInputBar(
|
|||||||
Spacer(modifier = Modifier.height(2.dp))
|
Spacer(modifier = Modifier.height(2.dp))
|
||||||
if (panelReplyMessages.isNotEmpty()) {
|
if (panelReplyMessages.isNotEmpty()) {
|
||||||
val msg = panelReplyMessages.first()
|
val msg = panelReplyMessages.first()
|
||||||
val hasImageAttachment = msg.attachments.any {
|
val hasImageAttachment = msg.attachments.any {
|
||||||
it.type == AttachmentType.IMAGE
|
it.type == AttachmentType.IMAGE
|
||||||
}
|
}
|
||||||
|
val hasCallAttachment = msg.attachments.any {
|
||||||
|
it.type == AttachmentType.CALL
|
||||||
|
}
|
||||||
AppleEmojiText(
|
AppleEmojiText(
|
||||||
text = if (panelReplyMessages.size == 1) {
|
text = if (panelReplyMessages.size == 1) {
|
||||||
if (msg.text.isEmpty() && hasImageAttachment) {
|
if (msg.text.isEmpty() && hasCallAttachment) {
|
||||||
|
"Call"
|
||||||
|
} else if (msg.text.isEmpty() && hasImageAttachment) {
|
||||||
"Photo"
|
"Photo"
|
||||||
} else {
|
} else {
|
||||||
val shortText = msg.text.take(40)
|
val shortText = msg.text.take(40)
|
||||||
|
|||||||
Reference in New Issue
Block a user