feat: Integrate Firebase Cloud Messaging for push notifications; add service to handle token and message reception
This commit is contained in:
@@ -358,9 +358,6 @@ fun ChatDetailScreen(
|
||||
val chatTitle =
|
||||
if (isSavedMessages) "Saved Messages"
|
||||
else user.title.ifEmpty { user.publicKey.take(10) }
|
||||
|
||||
// Состояние показа логов
|
||||
var showLogs by remember { mutableStateOf(false) }
|
||||
|
||||
// 📨 Forward: показывать ли выбор чата
|
||||
var showForwardPicker by remember { mutableStateOf(false) }
|
||||
@@ -375,12 +372,7 @@ fun ChatDetailScreen(
|
||||
chatsListViewModel.setAccount(currentUserPublicKey, currentUserPrivateKey)
|
||||
}
|
||||
}
|
||||
// 🚀 Собираем логи ТОЛЬКО когда они показываются - иначе каждый лог вызывает перекомпозицию!
|
||||
val debugLogs = if (showLogs) {
|
||||
com.rosetta.messenger.network.ProtocolManager.debugLogs.collectAsState().value
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
|
||||
// Состояние выпадающего меню
|
||||
var showMenu by remember { mutableStateOf(false) }
|
||||
@@ -935,39 +927,7 @@ fun ChatDetailScreen(
|
||||
else Color.Black.copy(alpha = 0.08f)
|
||||
)
|
||||
}
|
||||
|
||||
// Debug Logs
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 4.dp)
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.BugReport,
|
||||
contentDescription = null,
|
||||
tint = secondaryTextColor,
|
||||
modifier = Modifier.size(22.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(14.dp))
|
||||
Text(
|
||||
"Debug Logs",
|
||||
color = textColor,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
showMenu = false
|
||||
showLogs = true
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 8.dp)
|
||||
.background(inputBackgroundColor),
|
||||
colors = MenuDefaults.itemColors(
|
||||
textColor = textColor
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1390,58 +1350,6 @@ fun ChatDetailScreen(
|
||||
}
|
||||
} // Закрытие Box с fade-in
|
||||
|
||||
// Диалог логов
|
||||
if (showLogs) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showLogs = false },
|
||||
containerColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color.White,
|
||||
title = {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Debug Logs (${debugLogs.size})", fontWeight = FontWeight.Bold, color = textColor)
|
||||
IconButton(
|
||||
onClick = {
|
||||
com.rosetta.messenger.network.ProtocolManager.clearLogs()
|
||||
}
|
||||
) { Icon(Icons.Default.Delete, contentDescription = "Clear", tint = Color(0xFFFF3B30)) }
|
||||
}
|
||||
},
|
||||
text = {
|
||||
LazyColumn(modifier = Modifier.fillMaxWidth().heightIn(max = 500.dp)) {
|
||||
items(debugLogs.reversed()) { log ->
|
||||
val logColor = when {
|
||||
log.contains("❌") || log.contains("Error") -> Color(0xFFFF3B30)
|
||||
log.contains("✅") -> Color(0xFF38B24D)
|
||||
log.contains("📤") -> PrimaryBlue
|
||||
log.contains("📥") -> Color(0xFFFF9500)
|
||||
log.contains("⚠️") -> Color(0xFFFFCC00)
|
||||
else -> if (isDarkTheme) Color.White.copy(alpha = 0.8f) else Color.Black.copy(alpha = 0.8f)
|
||||
}
|
||||
Text(
|
||||
text = log,
|
||||
fontSize = 11.sp,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
color = logColor,
|
||||
modifier = Modifier.padding(vertical = 2.dp)
|
||||
)
|
||||
}
|
||||
if (debugLogs.isEmpty()) {
|
||||
item {
|
||||
Text(
|
||||
text = "No logs yet. Try sending a message.",
|
||||
color = secondaryTextColor,
|
||||
fontSize = 12.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = { TextButton(onClick = { showLogs = false }) { Text("Close", color = PrimaryBlue) } }
|
||||
)
|
||||
}
|
||||
|
||||
// Диалог подтверждения удаления чата
|
||||
if (showDeleteConfirm) {
|
||||
|
||||
@@ -281,129 +281,290 @@ fun ChatsListScreen(
|
||||
drawerState = drawerState,
|
||||
drawerContent = {
|
||||
ModalDrawerSheet(
|
||||
drawerContainerColor = drawerBackgroundColor,
|
||||
modifier = Modifier.width(280.dp)
|
||||
drawerContainerColor = Color.Transparent,
|
||||
windowInsets = WindowInsets(0), // 🎨 Убираем системные отступы - drawer идет до верха
|
||||
modifier = Modifier.width(300.dp)
|
||||
) {
|
||||
// Drawer Header
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.padding(
|
||||
top = 48.dp,
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
bottom = 16.dp
|
||||
)
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(drawerBackgroundColor)
|
||||
) {
|
||||
// Avatar
|
||||
val avatarColors = getAvatarColor(accountPublicKey, isDarkTheme)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 🎨 DRAWER HEADER - Avatar and status
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
val headerColor = if (isDarkTheme) {
|
||||
Color(0xFF2C5282)
|
||||
} else {
|
||||
Color(0xFF4A90D9)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.size(64.dp)
|
||||
.clip(CircleShape)
|
||||
.background(avatarColors.backgroundColor),
|
||||
contentAlignment = Alignment.Center
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = headerColor)
|
||||
.statusBarsPadding() // 🎨 Контент начинается после status bar
|
||||
.padding(
|
||||
top = 16.dp,
|
||||
start = 20.dp,
|
||||
end = 20.dp,
|
||||
bottom = 20.dp
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = getAvatarText(accountPublicKey),
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = avatarColors.textColor
|
||||
Column {
|
||||
// Avatar with border
|
||||
val avatarColors = getAvatarColor(accountPublicKey, isDarkTheme)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(72.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White.copy(alpha = 0.2f))
|
||||
.padding(3.dp)
|
||||
.clip(CircleShape)
|
||||
.background(avatarColors.backgroundColor),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = getAvatarText(accountPublicKey),
|
||||
fontSize = 26.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = avatarColors.textColor
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
|
||||
// Public key (username style) - clickable для копирования
|
||||
val truncatedKey =
|
||||
if (accountPublicKey.length > 16) {
|
||||
"${accountPublicKey.take(8)}...${accountPublicKey.takeLast(6)}"
|
||||
} else accountPublicKey
|
||||
|
||||
val context = androidx.compose.ui.platform.LocalContext.current
|
||||
var showCopiedToast by remember { mutableStateOf(false) }
|
||||
|
||||
// Плавная замена текста
|
||||
AnimatedContent(
|
||||
targetState = showCopiedToast,
|
||||
transitionSpec = {
|
||||
fadeIn(animationSpec = tween(300)) togetherWith
|
||||
fadeOut(animationSpec = tween(300))
|
||||
},
|
||||
label = "copiedAnimation"
|
||||
) { isCopied ->
|
||||
Text(
|
||||
text = if (isCopied) "Copied!" else truncatedKey,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color.White,
|
||||
fontStyle = if (isCopied) androidx.compose.ui.text.font.FontStyle.Italic else androidx.compose.ui.text.font.FontStyle.Normal,
|
||||
modifier = Modifier.clickable {
|
||||
if (!showCopiedToast) {
|
||||
// Копируем публичный ключ
|
||||
val clipboard = context.getSystemService(android.content.Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
|
||||
val clip = android.content.ClipData.newPlainText("Public Key", accountPublicKey)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
showCopiedToast = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Автоматически возвращаем обратно через 1.5 секунды
|
||||
if (showCopiedToast) {
|
||||
LaunchedEffect(Unit) {
|
||||
kotlinx.coroutines.delay(1500)
|
||||
showCopiedToast = false
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
|
||||
// Connection status indicator
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.clickable { showStatusDialog = true }
|
||||
) {
|
||||
val statusColor = when (protocolState) {
|
||||
ProtocolState.AUTHENTICATED -> Color(0xFF4ADE80)
|
||||
ProtocolState.CONNECTING, ProtocolState.CONNECTED, ProtocolState.HANDSHAKING -> Color(0xFFFBBF24)
|
||||
else -> Color(0xFFF87171)
|
||||
}
|
||||
val statusText = when (protocolState) {
|
||||
ProtocolState.AUTHENTICATED -> "Online"
|
||||
ProtocolState.CONNECTING, ProtocolState.CONNECTED, ProtocolState.HANDSHAKING -> "Connecting..."
|
||||
else -> "Offline"
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(8.dp)
|
||||
.clip(CircleShape)
|
||||
.background(statusColor)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
Text(
|
||||
text = statusText,
|
||||
fontSize = 13.sp,
|
||||
color = Color.White.copy(alpha = 0.85f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 📱 MENU ITEMS
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(vertical = 8.dp)
|
||||
) {
|
||||
val menuIconColor = if (isDarkTheme) Color(0xFFB0B0B0) else Color(0xFF5C5C5C)
|
||||
|
||||
// 👤 Profile Section
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = Icons.Outlined.Person,
|
||||
text = "My Profile",
|
||||
iconColor = menuIconColor,
|
||||
textColor = textColor,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onProfileClick()
|
||||
}
|
||||
)
|
||||
|
||||
// 📖 Saved Messages
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = Icons.Outlined.Bookmark,
|
||||
text = "Saved Messages",
|
||||
iconColor = menuIconColor,
|
||||
textColor = textColor,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onSavedMessagesClick()
|
||||
}
|
||||
)
|
||||
|
||||
DrawerDivider(isDarkTheme)
|
||||
|
||||
// 👥 Contacts
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = Icons.Outlined.Contacts,
|
||||
text = "Contacts",
|
||||
iconColor = menuIconColor,
|
||||
textColor = textColor,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onContactsClick()
|
||||
}
|
||||
)
|
||||
|
||||
// 📞 Calls
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = Icons.Outlined.Call,
|
||||
text = "Calls",
|
||||
iconColor = menuIconColor,
|
||||
textColor = textColor,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onCallsClick()
|
||||
}
|
||||
)
|
||||
|
||||
// ➕ Invite Friends
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = Icons.Outlined.PersonAdd,
|
||||
text = "Invite Friends",
|
||||
iconColor = menuIconColor,
|
||||
textColor = textColor,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onInviteFriendsClick()
|
||||
}
|
||||
)
|
||||
|
||||
DrawerDivider(isDarkTheme)
|
||||
|
||||
// ⚙️ Settings
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = Icons.Outlined.Settings,
|
||||
text = "Settings",
|
||||
iconColor = menuIconColor,
|
||||
textColor = textColor,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onSettingsClick()
|
||||
}
|
||||
)
|
||||
|
||||
// 🌓 Theme Toggle
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = if (isDarkTheme) Icons.Outlined.LightMode else Icons.Outlined.DarkMode,
|
||||
text = if (isDarkTheme) "Light Mode" else "Dark Mode",
|
||||
iconColor = menuIconColor,
|
||||
textColor = textColor,
|
||||
onClick = { onToggleTheme() }
|
||||
)
|
||||
|
||||
// ❓ Help
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
text = "Help & FAQ",
|
||||
iconColor = menuIconColor,
|
||||
textColor = textColor,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
// TODO: Add help screen navigation
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// Public key
|
||||
val truncatedKey =
|
||||
if (accountPublicKey.length > 12) {
|
||||
"${accountPublicKey.take(6)}...${accountPublicKey.takeLast(4)}"
|
||||
} else accountPublicKey
|
||||
|
||||
Text(
|
||||
text = truncatedKey,
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = textColor
|
||||
)
|
||||
}
|
||||
|
||||
Divider(color = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8))
|
||||
|
||||
// Menu Items - прозрачный фон без странных цветов
|
||||
val drawerItemColors = NavigationDrawerItemDefaults.colors(
|
||||
unselectedContainerColor = Color.Transparent,
|
||||
unselectedIconColor = if (isDarkTheme) Color.White else Color.Black,
|
||||
unselectedTextColor = textColor
|
||||
)
|
||||
|
||||
NavigationDrawerItem(
|
||||
icon = { Icon(Icons.Outlined.Person, contentDescription = null) },
|
||||
label = { Text("My Profile") },
|
||||
selected = false,
|
||||
colors = drawerItemColors,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onProfileClick()
|
||||
}
|
||||
)
|
||||
|
||||
NavigationDrawerItem(
|
||||
icon = { Icon(Icons.Outlined.Settings, contentDescription = null) },
|
||||
label = { Text("Settings") },
|
||||
selected = false,
|
||||
colors = drawerItemColors,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onSettingsClick()
|
||||
}
|
||||
)
|
||||
|
||||
NavigationDrawerItem(
|
||||
icon = {
|
||||
Icon(
|
||||
if (isDarkTheme) Icons.Default.LightMode
|
||||
else Icons.Default.DarkMode,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
label = { Text(if (isDarkTheme) "Light Mode" else "Dark Mode") },
|
||||
selected = false,
|
||||
colors = drawerItemColors,
|
||||
onClick = {
|
||||
// Don't close drawer when toggling theme
|
||||
onToggleTheme()
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
// Logout
|
||||
Divider(color = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8))
|
||||
|
||||
NavigationDrawerItem(
|
||||
icon = {
|
||||
Icon(
|
||||
Icons.Default.Logout,
|
||||
contentDescription = null,
|
||||
tint = Color(0xFFFF3B30)
|
||||
)
|
||||
},
|
||||
label = { Text("Log Out", color = Color(0xFFFF3B30)) },
|
||||
selected = false,
|
||||
colors = NavigationDrawerItemDefaults.colors(
|
||||
unselectedContainerColor = Color.Transparent
|
||||
),
|
||||
onClick = {
|
||||
scope.launch {
|
||||
drawerState.close()
|
||||
kotlinx.coroutines.delay(150)
|
||||
onLogout()
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 🚪 FOOTER - Logout & Version
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Divider(
|
||||
color = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8),
|
||||
thickness = 0.5.dp
|
||||
)
|
||||
|
||||
// Logout
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = Icons.Outlined.Logout,
|
||||
text = "Log Out",
|
||||
iconColor = Color(0xFFFF4444),
|
||||
textColor = Color(0xFFFF4444),
|
||||
onClick = {
|
||||
scope.launch {
|
||||
drawerState.close()
|
||||
kotlinx.coroutines.delay(150)
|
||||
onLogout()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
// Version info
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp, vertical = 12.dp),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
Text(
|
||||
text = "Rosetta v1.0.0",
|
||||
fontSize = 12.sp,
|
||||
color = if (isDarkTheme) Color(0xFF666666) else Color(0xFF999999)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
@@ -1442,7 +1603,7 @@ fun RequestsScreen(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
items(requests, key = { it.opponentKey }) { request ->
|
||||
DialogItem(
|
||||
DialogItemContent(
|
||||
dialog = request,
|
||||
isDarkTheme = isDarkTheme,
|
||||
isTyping = false,
|
||||
@@ -1459,3 +1620,73 @@ fun RequestsScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🎨 Enhanced Drawer Menu Item - красивый пункт меню с hover эффектом
|
||||
*/
|
||||
@Composable
|
||||
fun DrawerMenuItemEnhanced(
|
||||
icon: androidx.compose.ui.graphics.vector.ImageVector,
|
||||
text: String,
|
||||
iconColor: Color,
|
||||
textColor: Color,
|
||||
badge: String? = null,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 20.dp, vertical = 14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = iconColor,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = textColor,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
badge?.let {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = Color(0xFF4A90D9),
|
||||
shape = RoundedCornerShape(10.dp)
|
||||
)
|
||||
.padding(horizontal = 8.dp, vertical = 2.dp)
|
||||
) {
|
||||
Text(
|
||||
text = it,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 📏 Drawer Divider - разделитель между секциями
|
||||
*/
|
||||
@Composable
|
||||
fun DrawerDivider(isDarkTheme: Boolean) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Divider(
|
||||
modifier = Modifier.padding(horizontal = 20.dp),
|
||||
color = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFEEEEEE),
|
||||
thickness = 0.5.dp
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
|
||||
@@ -253,8 +253,30 @@ fun SearchScreen(
|
||||
}
|
||||
} else {
|
||||
// Search Results
|
||||
// Проверяем, не ищет ли пользователь сам себя (Saved Messages)
|
||||
val isSavedMessagesSearch = searchQuery.trim().let { query ->
|
||||
query.equals(currentUserPublicKey, ignoreCase = true) ||
|
||||
query.equals(currentUserPublicKey.take(8), ignoreCase = true) ||
|
||||
query.equals(currentUserPublicKey.takeLast(8), ignoreCase = true)
|
||||
}
|
||||
|
||||
// Если ищем себя - показываем Saved Messages как первый результат
|
||||
val resultsWithSavedMessages = if (isSavedMessagesSearch && searchResults.none { it.publicKey == currentUserPublicKey }) {
|
||||
listOf(
|
||||
SearchUser(
|
||||
title = "Saved Messages",
|
||||
username = "",
|
||||
publicKey = currentUserPublicKey,
|
||||
verified = 0,
|
||||
online = 1
|
||||
)
|
||||
) + searchResults.filter { it.publicKey != currentUserPublicKey }
|
||||
} else {
|
||||
searchResults
|
||||
}
|
||||
|
||||
SearchResultsList(
|
||||
searchResults = searchResults,
|
||||
searchResults = resultsWithSavedMessages,
|
||||
isSearching = isSearching,
|
||||
currentUserPublicKey = currentUserPublicKey,
|
||||
isDarkTheme = isDarkTheme,
|
||||
@@ -262,8 +284,10 @@ fun SearchScreen(
|
||||
onUserClick = { user ->
|
||||
// Мгновенно закрываем клавиатуру
|
||||
hideKeyboardInstantly()
|
||||
// Сохраняем пользователя в историю
|
||||
RecentSearchesManager.addUser(user)
|
||||
// Сохраняем пользователя в историю (кроме Saved Messages)
|
||||
if (user.publicKey != currentUserPublicKey) {
|
||||
RecentSearchesManager.addUser(user)
|
||||
}
|
||||
onUserSelect(user)
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user