fix: update status bar color management for improved visibility in ChatDetailScreen and OtherProfileScreen
This commit is contained in:
@@ -194,22 +194,24 @@ fun ChatDetailScreen(
|
||||
var imageViewerInitialIndex by remember { mutableStateOf(0) }
|
||||
var imageViewerSourceBounds by remember { mutableStateOf<ImageSourceBounds?>(null) }
|
||||
|
||||
// 🎨 Управление статус баром - чёрный при просмотре фото
|
||||
// 🎨 Управление статус баром
|
||||
DisposableEffect(isDarkTheme, showImageViewer) {
|
||||
val insetsController = window?.let { WindowCompat.getInsetsController(it, view) }
|
||||
|
||||
if (showImageViewer) {
|
||||
// 📸 При просмотре фото - чёрный статус бар
|
||||
window?.statusBarColor = 0xFF000000.toInt()
|
||||
window?.statusBarColor = android.graphics.Color.BLACK
|
||||
insetsController?.isAppearanceLightStatusBars = false
|
||||
} else {
|
||||
// Обычный режим - цвет хедера
|
||||
val headerColor = if (isDarkTheme) 0xFF212121.toInt() else 0xFFFFFFFF.toInt()
|
||||
window?.statusBarColor = headerColor
|
||||
// Обычный режим - прозрачный статус бар, иконки по теме
|
||||
window?.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||
insetsController?.isAppearanceLightStatusBars = !isDarkTheme
|
||||
}
|
||||
|
||||
onDispose { }
|
||||
onDispose {
|
||||
// Восстанавливаем прозрачный статус бар при выходе
|
||||
window?.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||
}
|
||||
}
|
||||
|
||||
// 📷 Camera: URI для сохранения фото
|
||||
@@ -342,8 +344,14 @@ fun ChatDetailScreen(
|
||||
Pair<ChatMessage, Boolean>>() // message, showDateHeader
|
||||
var lastDateString = ""
|
||||
|
||||
// 🔥 КРИТИЧНО: Дедупликация по ID перед сортировкой!
|
||||
val uniqueMessages = messages.distinctBy { it.id }
|
||||
if (uniqueMessages.size != messages.size) {
|
||||
android.util.Log.e("ChatDetailScreen", "🚨 DEDUPLICATED ${messages.size - uniqueMessages.size} messages in UI! Original: ${messages.map { it.id }}")
|
||||
}
|
||||
|
||||
// Сортируем по времени (новые -> старые) для reversed layout
|
||||
val sortedMessages = messages.sortedByDescending { it.timestamp.time }
|
||||
val sortedMessages = uniqueMessages.sortedByDescending { it.timestamp.time }
|
||||
|
||||
for (i in sortedMessages.indices) {
|
||||
val message = sortedMessages[i]
|
||||
@@ -892,7 +900,8 @@ fun ChatDetailScreen(
|
||||
publicKey = user.publicKey,
|
||||
avatarRepository = avatarRepository,
|
||||
size = 40.dp,
|
||||
isDarkTheme = isDarkTheme
|
||||
isDarkTheme = isDarkTheme,
|
||||
displayName = user.title.ifEmpty { user.username } // 🔥 Для инициалов
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +258,18 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
// Добавляем все сразу
|
||||
kotlinx.coroutines.withContext(Dispatchers.Main.immediate) {
|
||||
val currentList = _messages.value
|
||||
_messages.value = (currentList + newMessages).sortedBy { it.timestamp }
|
||||
val newList = (currentList + newMessages).sortedBy { it.timestamp }
|
||||
|
||||
// 🔍 DEBUG: Проверка на дублирующиеся ID
|
||||
val allIds = newList.map { it.id }
|
||||
val duplicates = allIds.groupBy { it }.filter { it.value.size > 1 }.keys
|
||||
if (duplicates.isNotEmpty()) {
|
||||
android.util.Log.e("ChatViewModel", "🚨 DUPLICATE IDS FOUND in pollLatestMessages: $duplicates")
|
||||
android.util.Log.e("ChatViewModel", " currentList ids: ${currentList.map { it.id }}")
|
||||
android.util.Log.e("ChatViewModel", " newMessages ids: ${newMessages.map { it.id }}")
|
||||
}
|
||||
|
||||
_messages.value = newList
|
||||
}
|
||||
|
||||
// Обновляем кэш
|
||||
@@ -359,6 +370,23 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
// ✅ handleIncomingMessage удалён - обработка входящих сообщений теперь ТОЛЬКО в MessageRepository
|
||||
// Это предотвращает дублирование сообщений
|
||||
|
||||
/**
|
||||
* 🔥 Безопасное добавление сообщения - предотвращает дубликаты
|
||||
* Возвращает true если сообщение было добавлено
|
||||
*/
|
||||
private fun addMessageSafely(message: ChatMessage): Boolean {
|
||||
val currentMessages = _messages.value
|
||||
val currentIds = currentMessages.map { it.id }.toSet()
|
||||
android.util.Log.d("ChatViewModel", "🔍 addMessageSafely: id=${message.id}, currentCount=${currentMessages.size}, ids=${currentIds.take(5)}...")
|
||||
if (message.id in currentIds) {
|
||||
android.util.Log.e("ChatViewModel", "🚨 BLOCKED DUPLICATE: id=${message.id} already exists in ${currentIds.size} messages!")
|
||||
return false
|
||||
}
|
||||
_messages.value = currentMessages + message
|
||||
android.util.Log.d("ChatViewModel", "✅ Added message: id=${message.id}, newCount=${_messages.value.size}")
|
||||
return true
|
||||
}
|
||||
|
||||
private fun updateMessageStatus(messageId: String, status: MessageStatus) {
|
||||
_messages.value = _messages.value.map { msg ->
|
||||
if (msg.id == messageId) msg.copy(status = status) else msg
|
||||
@@ -565,10 +593,27 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
// 🔥 СРАЗУ обновляем UI - пользователь видит сообщения мгновенно
|
||||
// НО сохраняем оптимистичные сообщения (SENDING), которые ещё не в БД
|
||||
withContext(Dispatchers.Main.immediate) {
|
||||
val optimisticMessages = _messages.value.filter { msg ->
|
||||
msg.status == MessageStatus.SENDING && messages.none { it.id == msg.id }
|
||||
val dbIds = messages.map { it.id }.toSet()
|
||||
val currentMsgs = _messages.value
|
||||
android.util.Log.d("ChatViewModel", "📥 loadMessages: dbCount=${messages.size}, currentCount=${currentMsgs.size}")
|
||||
android.util.Log.d("ChatViewModel", " DB ids: ${dbIds.take(5)}...")
|
||||
android.util.Log.d("ChatViewModel", " Current ids: ${currentMsgs.map { it.id }.take(5)}...")
|
||||
|
||||
val optimisticMessages = currentMsgs.filter { msg ->
|
||||
msg.status == MessageStatus.SENDING && msg.id !in dbIds
|
||||
}
|
||||
_messages.value = messages + optimisticMessages
|
||||
android.util.Log.d("ChatViewModel", " Optimistic (SENDING, not in DB): ${optimisticMessages.size} - ${optimisticMessages.map { it.id }}")
|
||||
|
||||
val newList = messages + optimisticMessages
|
||||
|
||||
// 🔍 Финальная дедупликация по ID (на всякий случай)
|
||||
val deduplicatedList = newList.distinctBy { it.id }
|
||||
|
||||
if (deduplicatedList.size != newList.size) {
|
||||
android.util.Log.e("ChatViewModel", "🚨 DEDUPLICATED ${newList.size - deduplicatedList.size} messages!")
|
||||
}
|
||||
|
||||
_messages.value = deduplicatedList
|
||||
_isLoading.value = false
|
||||
}
|
||||
|
||||
@@ -1287,7 +1332,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
status = MessageStatus.SENDING,
|
||||
replyData = replyData // Данные для reply bubble
|
||||
)
|
||||
_messages.value = _messages.value + optimisticMessage
|
||||
|
||||
// <20> Безопасное добавление с проверкой дубликатов
|
||||
addMessageSafely(optimisticMessage)
|
||||
_inputText.value = ""
|
||||
|
||||
// 🔥 Очищаем reply после отправки - данные сохраняются в displayReplyMessages для анимации
|
||||
@@ -1475,7 +1522,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
)
|
||||
)
|
||||
)
|
||||
_messages.value = _messages.value + optimisticMessage
|
||||
// 🔥 Безопасное добавление с проверкой дубликатов
|
||||
addMessageSafely(optimisticMessage)
|
||||
_inputText.value = ""
|
||||
|
||||
|
||||
@@ -1531,10 +1579,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
ProtocolManager.send(packet)
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
updateMessageStatus(messageId, MessageStatus.SENT)
|
||||
}
|
||||
|
||||
// 💾 Сохраняем изображение в файл локально (как в desktop)
|
||||
AttachmentFileManager.saveAttachment(
|
||||
context = getApplication(),
|
||||
@@ -1564,10 +1608,19 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
encryptedKey = encryptedKey,
|
||||
timestamp = timestamp,
|
||||
isFromMe = true,
|
||||
delivered = if (isSavedMessages) 2 else 0,
|
||||
delivered = if (isSavedMessages) 2 else 0, // SENDING для обычных
|
||||
attachmentsJson = attachmentsJson
|
||||
)
|
||||
|
||||
// 🔥 После успешной отправки обновляем статус на SENT (2) в БД и UI
|
||||
if (!isSavedMessages) {
|
||||
updateMessageStatusInDb(messageId, 2) // SENT
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
updateMessageStatus(messageId, MessageStatus.SENT)
|
||||
}
|
||||
|
||||
saveDialog(if (text.isNotEmpty()) text else "photo", timestamp)
|
||||
|
||||
} catch (e: Exception) {
|
||||
@@ -1634,7 +1687,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
status = MessageStatus.SENDING,
|
||||
attachments = attachmentsList
|
||||
)
|
||||
_messages.value = _messages.value + optimisticMessage
|
||||
// 🔥 Безопасное добавление с проверкой дубликатов
|
||||
addMessageSafely(optimisticMessage)
|
||||
_inputText.value = ""
|
||||
|
||||
|
||||
@@ -1715,10 +1769,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
ProtocolManager.send(packet)
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
updateMessageStatus(messageId, MessageStatus.SENT)
|
||||
}
|
||||
|
||||
// Сохраняем в БД
|
||||
saveMessageToDatabase(
|
||||
messageId = messageId,
|
||||
@@ -1731,6 +1781,16 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
attachmentsJson = attachmentsJsonArray.toString()
|
||||
)
|
||||
|
||||
// 🔥 Обновляем статус в БД после отправки
|
||||
if (!isSavedMessages) {
|
||||
updateMessageStatusInDb(messageId, 2) // SENT
|
||||
}
|
||||
|
||||
// Обновляем UI
|
||||
withContext(Dispatchers.Main) {
|
||||
updateMessageStatus(messageId, MessageStatus.SENT)
|
||||
}
|
||||
|
||||
saveDialog(if (text.isNotEmpty()) text else "📷 ${images.size} photos", timestamp)
|
||||
|
||||
} catch (e: Exception) {
|
||||
@@ -1785,7 +1845,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
)
|
||||
)
|
||||
)
|
||||
_messages.value = _messages.value + optimisticMessage
|
||||
// 🔥 Безопасное добавление с проверкой дубликатов
|
||||
addMessageSafely(optimisticMessage)
|
||||
_inputText.value = ""
|
||||
|
||||
|
||||
@@ -1838,10 +1899,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
ProtocolManager.send(packet)
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
updateMessageStatus(messageId, MessageStatus.SENT)
|
||||
}
|
||||
|
||||
// ⚠️ НЕ сохраняем файл локально - они слишком большие
|
||||
// Файлы загружаются с Transport Server при необходимости
|
||||
val attachmentsJson = JSONArray().apply {
|
||||
@@ -1853,6 +1910,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
})
|
||||
}.toString()
|
||||
|
||||
// 🔥 Сохраняем сначала с SENDING, потом обновляем на SENT
|
||||
saveMessageToDatabase(
|
||||
messageId = messageId,
|
||||
text = text,
|
||||
@@ -1860,10 +1918,19 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
encryptedKey = encryptedKey,
|
||||
timestamp = timestamp,
|
||||
isFromMe = true,
|
||||
delivered = if (isSavedMessages) 2 else 0,
|
||||
delivered = if (isSavedMessages) 2 else 0, // SENDING для обычных, SENT для saved
|
||||
attachmentsJson = attachmentsJson
|
||||
)
|
||||
|
||||
// 🔥 После успешной отправки обновляем статус на SENT (2) в БД и UI
|
||||
if (!isSavedMessages) {
|
||||
updateMessageStatusInDb(messageId, 2) // SENT
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
updateMessageStatus(messageId, MessageStatus.SENT)
|
||||
}
|
||||
|
||||
saveDialog(if (text.isNotEmpty()) text else "file", timestamp)
|
||||
|
||||
} catch (e: Exception) {
|
||||
@@ -1973,7 +2040,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
)
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
_messages.value = _messages.value + optimisticMessage
|
||||
addMessageSafely(optimisticMessage)
|
||||
}
|
||||
|
||||
// 2. Шифрование текста (пустой текст для аватарки)
|
||||
@@ -2029,10 +2096,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
ProtocolManager.send(packet)
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
updateMessageStatus(messageId, MessageStatus.SENT)
|
||||
}
|
||||
|
||||
// 💾 Сохраняем аватар в файл локально (как IMAGE - с приватным ключом)
|
||||
AttachmentFileManager.saveAttachment(
|
||||
context = getApplication(),
|
||||
@@ -2063,6 +2126,16 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
attachmentsJson = attachmentsJson
|
||||
)
|
||||
|
||||
// 🔥 Обновляем статус в БД после отправки
|
||||
if (!isSavedMessages) {
|
||||
updateMessageStatusInDb(messageId, 2) // SENT
|
||||
}
|
||||
|
||||
// Обновляем UI
|
||||
withContext(Dispatchers.Main) {
|
||||
updateMessageStatus(messageId, MessageStatus.SENT)
|
||||
}
|
||||
|
||||
saveDialog("\$a=Avatar", timestamp)
|
||||
|
||||
|
||||
|
||||
@@ -448,7 +448,8 @@ fun ChatsListScreen(
|
||||
publicKey = accountPublicKey,
|
||||
avatarRepository = avatarRepository,
|
||||
size = 66.dp,
|
||||
isDarkTheme = isDarkTheme
|
||||
isDarkTheme = isDarkTheme,
|
||||
displayName = accountName.ifEmpty { accountUsername } // 🔥 Для инициалов
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1247,7 +1248,8 @@ fun ChatItem(
|
||||
size = 56.dp,
|
||||
isDarkTheme = isDarkTheme,
|
||||
showOnlineIndicator = true,
|
||||
isOnline = chat.isOnline
|
||||
isOnline = chat.isOnline,
|
||||
displayName = chat.name // 🔥 Для инициалов
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
@@ -1724,11 +1726,20 @@ fun DialogItemContent(
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// 🔥 Формируем displayName для инициалов в placeholder
|
||||
val avatarDisplayName = when {
|
||||
dialog.opponentTitle.isNotEmpty() &&
|
||||
dialog.opponentTitle != dialog.opponentKey &&
|
||||
!dialog.opponentTitle.startsWith(dialog.opponentKey.take(7)) -> dialog.opponentTitle
|
||||
dialog.opponentUsername.isNotEmpty() -> dialog.opponentUsername
|
||||
else -> null
|
||||
}
|
||||
com.rosetta.messenger.ui.components.AvatarImage(
|
||||
publicKey = dialog.opponentKey,
|
||||
avatarRepository = avatarRepository,
|
||||
size = 56.dp,
|
||||
isDarkTheme = isDarkTheme
|
||||
isDarkTheme = isDarkTheme,
|
||||
displayName = avatarDisplayName
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -193,12 +193,22 @@ private fun SearchResultItem(
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
} else {
|
||||
// Приоритет: title -> username -> publicKey
|
||||
val initials = when {
|
||||
user.title.isNotEmpty() &&
|
||||
user.title != user.publicKey &&
|
||||
!user.title.startsWith(user.publicKey.take(7)) -> {
|
||||
getInitials(user.title)
|
||||
}
|
||||
user.username.isNotEmpty() -> {
|
||||
user.username.take(2).uppercase()
|
||||
}
|
||||
else -> {
|
||||
user.publicKey.take(2).uppercase()
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = if (user.title.isNotEmpty()) {
|
||||
getInitials(user.title)
|
||||
} else {
|
||||
user.publicKey.take(2).uppercase()
|
||||
},
|
||||
text = initials,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = avatarColors.textColor
|
||||
|
||||
@@ -369,7 +369,8 @@ private fun RecentUserItem(
|
||||
size = 48.dp,
|
||||
isDarkTheme = isDarkTheme,
|
||||
showOnlineIndicator = false,
|
||||
isOnline = false
|
||||
isOnline = false,
|
||||
displayName = user.title.ifEmpty { user.username } // 🔥 Для инициалов
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
@@ -197,8 +197,19 @@ class AppleEmojiEditTextView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
// Восстанавливаем курсор, убедившись что он в допустимых пределах
|
||||
if (cursorPosition >= 0 && cursorPosition <= editable.length) {
|
||||
post { setSelection(cursorPosition.coerceIn(0, editable.length)) }
|
||||
// 🔥 Захватываем длину ДО post, т.к. text может измениться
|
||||
val safePosition = cursorPosition.coerceIn(0, editable.length)
|
||||
if (safePosition >= 0) {
|
||||
post {
|
||||
try {
|
||||
val currentLength = text?.length ?: 0
|
||||
if (safePosition <= currentLength) {
|
||||
setSelection(safePosition.coerceIn(0, currentLength))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// Игнорируем - текст мог измениться
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
isUpdating = false
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.rosetta.messenger.repository.AvatarRepository
|
||||
import com.rosetta.messenger.ui.chats.AvatarColors
|
||||
import com.rosetta.messenger.ui.chats.getAvatarColor
|
||||
import com.rosetta.messenger.ui.chats.getAvatarText
|
||||
import com.rosetta.messenger.ui.chats.getInitials
|
||||
import com.rosetta.messenger.utils.AvatarFileManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -57,7 +58,8 @@ fun AvatarImage(
|
||||
onClick: (() -> Unit)? = null,
|
||||
showOnlineIndicator: Boolean = false,
|
||||
isOnline: Boolean = false,
|
||||
shape: Shape = CircleShape
|
||||
shape: Shape = CircleShape,
|
||||
displayName: String? = null // 🔥 Имя для инициалов (title/username)
|
||||
) {
|
||||
// Получаем аватары из репозитория
|
||||
val avatars by avatarRepository?.getAvatars(publicKey, allDecode = false)?.collectAsState()
|
||||
@@ -113,7 +115,8 @@ fun AvatarImage(
|
||||
publicKey = publicKey,
|
||||
size = size,
|
||||
isDarkTheme = isDarkTheme,
|
||||
shape = shape
|
||||
shape = shape,
|
||||
displayName = displayName
|
||||
)
|
||||
}
|
||||
|
||||
@@ -138,10 +141,16 @@ fun AvatarPlaceholder(
|
||||
size: Dp = 40.dp,
|
||||
isDarkTheme: Boolean,
|
||||
fontSize: TextUnit? = null,
|
||||
shape: Shape = CircleShape
|
||||
shape: Shape = CircleShape,
|
||||
displayName: String? = null // 🔥 Имя для инициалов
|
||||
) {
|
||||
val avatarColors = getAvatarColor(publicKey, isDarkTheme)
|
||||
val avatarText = getAvatarText(publicKey)
|
||||
// 🔥 Используем displayName для инициалов, если оно есть
|
||||
val avatarText = if (!displayName.isNullOrEmpty() && displayName != publicKey && !displayName.startsWith(publicKey.take(7))) {
|
||||
getInitials(displayName)
|
||||
} else {
|
||||
getAvatarText(publicKey)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.rosetta.messenger.ui.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.compose.animation.core.LinearOutSlowInEasing
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
@@ -36,6 +38,7 @@ import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
@@ -82,6 +85,26 @@ fun OtherProfileScreen(
|
||||
val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
|
||||
val avatarColors = getAvatarColor(user.publicKey, isDarkTheme)
|
||||
val context = LocalContext.current
|
||||
val view = LocalView.current
|
||||
val window = remember { (view.context as? Activity)?.window }
|
||||
|
||||
// 🎨 Статус бар - прозрачный с белыми иконками (поверх аватара)
|
||||
DisposableEffect(Unit) {
|
||||
val insetsController = window?.let { WindowCompat.getInsetsController(it, view) }
|
||||
// Сохраняем оригинальные значения
|
||||
val originalStatusBarColor = window?.statusBarColor ?: 0
|
||||
val originalLightStatusBars = insetsController?.isAppearanceLightStatusBars ?: false
|
||||
|
||||
// Прозрачный статус бар с белыми иконками
|
||||
window?.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||
insetsController?.isAppearanceLightStatusBars = false
|
||||
|
||||
onDispose {
|
||||
// Восстанавливаем при выходе
|
||||
window?.statusBarColor = originalStatusBarColor
|
||||
insetsController?.isAppearanceLightStatusBars = originalLightStatusBars
|
||||
}
|
||||
}
|
||||
|
||||
// 🔥 Получаем тот же ChatViewModel что и в ChatDetailScreen для очистки истории
|
||||
val viewModel: ChatViewModel = viewModel(key = "chat_${user.publicKey}")
|
||||
|
||||
Reference in New Issue
Block a user