Исправил переход по своему тэгу в группах и убрал лишнюю подсветку

- Клик по своему упоминанию теперь сразу открывает My Profile без экрана OtherProfile и kebab-меню\n- Нормализовал сравнение аккаунта по publicKey/username (trim + ignoreCase)\n- Убрал жёлтую подсветку сообщений с упоминанием в группах\n- Подровнял положение бейджа верификации рядом с именем
This commit is contained in:
2026-03-06 20:03:50 +05:00
parent 06dc9a2b5d
commit db605cb392
4 changed files with 61 additions and 40 deletions

View File

@@ -640,9 +640,34 @@ fun MainScreen(
if (screen is Screen.Requests && navStack.any { it is Screen.Requests }) return
navStack = navStack + screen
}
fun isCurrentAccountUser(user: SearchUser): Boolean {
val candidatePublicKey = user.publicKey.trim()
val normalizedAccountPublicKey = accountPublicKey.trim()
if (
candidatePublicKey.isNotBlank() &&
normalizedAccountPublicKey.isNotBlank() &&
candidatePublicKey.equals(normalizedAccountPublicKey, ignoreCase = true)
) {
return true
}
val candidateUsername = user.username.trim().trimStart('@')
val normalizedAccountUsername = accountUsername.trim().trimStart('@')
return candidatePublicKey.isBlank() &&
candidateUsername.isNotBlank() &&
normalizedAccountUsername.isNotBlank() &&
candidateUsername.equals(normalizedAccountUsername, ignoreCase = true)
}
fun popScreen() {
navStack = navStack.dropLast(1)
}
fun openOwnProfile() {
navStack =
navStack.filterNot {
it is Screen.ChatDetail || it is Screen.OtherProfile || it is Screen.GroupInfo
}
pushScreen(Screen.Profile)
}
fun popProfileAndChildren() {
navStack =
navStack.filterNot {
@@ -977,9 +1002,9 @@ fun MainScreen(
totalUnreadFromOthers = totalUnreadFromOthers,
onBack = { popChatAndChildren() },
onUserProfileClick = { user ->
if (user.publicKey == accountPublicKey) {
if (isCurrentAccountUser(user)) {
// Свой профиль — открываем My Profile
pushScreen(Screen.Profile)
openOwnProfile()
} else {
// Открываем профиль другого пользователя
pushScreen(Screen.OtherProfile(user))
@@ -1025,8 +1050,8 @@ fun MainScreen(
avatarRepository = avatarRepository,
onBack = { navStack = navStack.filterNot { it is Screen.GroupInfo } },
onMemberClick = { member ->
if (member.publicKey == accountPublicKey) {
pushScreen(Screen.Profile)
if (isCurrentAccountUser(member)) {
openOwnProfile()
} else {
pushScreen(Screen.OtherProfile(member))
}

View File

@@ -2322,6 +2322,10 @@ fun ChatDetailScreen(
username.trim().trimStart('@').lowercase(Locale.ROOT)
if (normalizedUsername.isBlank()) return@MessageBubble
scope.launch {
val normalizedCurrentUsername =
currentUserUsername.trim().trimStart('@').lowercase(Locale.ROOT)
val normalizedOpponentUsername =
user.username.trim().trimStart('@').lowercase(Locale.ROOT)
val targetPublicKey =
mentionCandidates
.firstOrNull {
@@ -2331,22 +2335,34 @@ fun ChatDetailScreen(
)
}
?.publicKey
?.trim()
?.takeIf { it.isNotBlank() }
?: run {
val normalizedCurrent =
currentUserUsername.trim().trimStart('@').lowercase(Locale.ROOT)
if (normalizedCurrent == normalizedUsername && currentUserPublicKey.isNotBlank()) {
currentUserPublicKey
?: run {
if (normalizedCurrentUsername == normalizedUsername && currentUserPublicKey.isNotBlank()) {
currentUserPublicKey.trim()
} else {
val normalizedOpponent =
user.username.trim().trimStart('@').lowercase(Locale.ROOT)
if (normalizedOpponent == normalizedUsername && user.publicKey.isNotBlank()) user.publicKey
if (normalizedOpponentUsername == normalizedUsername && user.publicKey.isNotBlank()) user.publicKey.trim()
else ""
}
}
if (targetPublicKey.isBlank()) return@launch
if (targetPublicKey.equals(currentUserPublicKey.trim(), ignoreCase = true)) {
showContextMenu = false
contextMenuMessage = null
onUserProfileClick(
SearchUser(
title = currentUserName.ifBlank { "You" },
username = currentUserUsername.trim().trimStart('@'),
publicKey = currentUserPublicKey.trim(),
verified = 0,
online = 0
)
)
return@launch
}
val resolvedUser = viewModel.resolveUserForProfile(targetPublicKey)
if (resolvedUser != null) {
showContextMenu = false

View File

@@ -90,22 +90,6 @@ import kotlinx.coroutines.withContext
* organization
*/
private fun containsUserMention(text: String, username: String): Boolean {
val normalizedUsername = username.trim().trimStart('@')
if (normalizedUsername.isBlank()) return false
val mentionRegex =
Regex(
pattern = """(^|\s)@${Regex.escape(normalizedUsername)}(?=\b)""",
options = setOf(RegexOption.IGNORE_CASE)
)
return mentionRegex.containsMatchIn(text)
}
private fun containsAllMention(text: String): Boolean {
val mentionRegex = Regex("""(^|\s)@all(?=\b)""", setOf(RegexOption.IGNORE_CASE))
return mentionRegex.containsMatchIn(text)
}
/**
* Telegram-style layout для текста сообщения с временем. Если текст + время помещаются в одну
* строку - располагает их рядом. Если текст длинный и переносится - время встаёт в правый нижний
@@ -361,21 +345,10 @@ fun MessageBubble(
)
// Colors
val isMentionedIncoming =
remember(message.text, message.isOutgoing, isGroupChat, currentUserUsername) {
!message.isOutgoing &&
isGroupChat &&
message.text.isNotBlank() &&
(containsAllMention(message.text) ||
containsUserMention(message.text, currentUserUsername))
}
val bubbleColor =
remember(message.isOutgoing, isDarkTheme, isMentionedIncoming) {
remember(message.isOutgoing, isDarkTheme) {
if (message.isOutgoing) {
PrimaryBlue
} else if (isMentionedIncoming) {
if (isDarkTheme) Color(0xFF3A3422) else Color(0xFFFFF3CD)
} else {
if (isDarkTheme) Color(0xFF212121) else Color(0xFFF5F5F5)
}

View File

@@ -9,6 +9,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -35,6 +36,11 @@ fun VerifiedBadge(
if (verified <= 0) return
var showDialog by remember { mutableStateOf(false) }
val inlineOffsetY: Dp = when {
size <= 16 -> (-0.5).dp
size <= 20 -> (-1).dp
else -> 0.dp
}
// Цвет верификации: в тёмной теме — как индикаторы прочтения (PrimaryBlue), в светлой — #ACD2F9
val badgeColor =
@@ -58,6 +64,7 @@ fun VerifiedBadge(
contentDescription = "Verified",
tint = badgeColor,
modifier = modifier
.offset(y = inlineOffsetY)
.size(size.dp)
.clickable { showDialog = true }
)