feat: Add account initialization in ProtocolManager and enhance keyboard handling on screen exit
This commit is contained in:
@@ -53,6 +53,15 @@ object ProtocolManager {
|
|||||||
setupPacketHandlers()
|
setupPacketHandlers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 🔥 Инициализация аккаунта - КРИТИЧНО для получения сообщений!
|
||||||
|
* Должен вызываться после авторизации пользователя
|
||||||
|
*/
|
||||||
|
fun initializeAccount(publicKey: String, privateKey: String) {
|
||||||
|
addLog("🔐 Initializing account for message handling: ${publicKey.take(16)}...")
|
||||||
|
messageRepository?.initialize(publicKey, privateKey)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Настройка обработчиков пакетов
|
* Настройка обработчиков пакетов
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ fun ChatDetailScreen(
|
|||||||
onUserProfileClick: () -> Unit = {},
|
onUserProfileClick: () -> Unit = {},
|
||||||
viewModel: ChatViewModel = viewModel()
|
viewModel: ChatViewModel = viewModel()
|
||||||
) {
|
) {
|
||||||
// 🔥 Автоматическое скрытие клавиатуры при выходе с экрана
|
// 🔥 Backup: скрывает клавиатуру при dispose (если не скрыли раньше)
|
||||||
HideKeyboardOnDispose()
|
HideKeyboardOnDispose()
|
||||||
|
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
@@ -288,14 +288,16 @@ fun ChatDetailScreen(
|
|||||||
var selectedMessages by remember { mutableStateOf<Set<String>>(emptySet()) }
|
var selectedMessages by remember { mutableStateOf<Set<String>>(emptySet()) }
|
||||||
val isSelectionMode = selectedMessages.isNotEmpty()
|
val isSelectionMode = selectedMessages.isNotEmpty()
|
||||||
|
|
||||||
// 🔥 Быстрое закрытие - мгновенный выход без дополнительной анимации
|
// 🔥 Быстрое закрытие - СНАЧАЛА скрываем клавиатуру, ПОТОМ выходим
|
||||||
val hideKeyboardAndBack: () -> Unit = {
|
val hideKeyboardAndBack: () -> Unit = {
|
||||||
// Мгновенно убираем фокус и клавиатуру
|
// 1. Убираем фокус (это важно сделать первым!)
|
||||||
focusManager.clearFocus(force = true)
|
focusManager.clearFocus(force = true)
|
||||||
keyboardController?.hide()
|
|
||||||
// Сразу выходим - анимация в MainActivity
|
// 2. Мгновенное синхронное скрытие клавиатуры через InputMethodManager
|
||||||
|
keyboard.hideNow()
|
||||||
|
|
||||||
|
// 3. Теперь выходим - клавиатура уже скрыта
|
||||||
onBack()
|
onBack()
|
||||||
Unit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Определяем это Saved Messages или обычный чат
|
// Определяем это Saved Messages или обычный чат
|
||||||
@@ -378,8 +380,9 @@ fun ChatDetailScreen(
|
|||||||
// 🔥 Cleanup при выходе из экрана
|
// 🔥 Cleanup при выходе из экрана
|
||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
onDispose {
|
onDispose {
|
||||||
focusManager.clearFocus()
|
// Скрываем клавиатуру синхронно (backup если не скрыли раньше)
|
||||||
keyboardController?.hide()
|
focusManager.clearFocus(force = true)
|
||||||
|
keyboard.hideNow()
|
||||||
// 🔥 Закрываем диалог - сообщения больше не будут читаться автоматически
|
// 🔥 Закрываем диалог - сообщения больше не будут читаться автоматически
|
||||||
viewModel.closeDialog()
|
viewModel.closeDialog()
|
||||||
}
|
}
|
||||||
@@ -527,11 +530,15 @@ fun ChatDetailScreen(
|
|||||||
) {
|
) {
|
||||||
// 🔔 Кнопка назад с badge непрочитанных сообщений
|
// 🔔 Кнопка назад с badge непрочитанных сообщений
|
||||||
Box {
|
Box {
|
||||||
IconButton(onClick = hideKeyboardAndBack) {
|
IconButton(
|
||||||
|
onClick = hideKeyboardAndBack,
|
||||||
|
modifier = Modifier.size(40.dp)
|
||||||
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.ArrowBack,
|
Icons.Default.KeyboardArrowLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = headerIconColor
|
tint = headerIconColor,
|
||||||
|
modifier = Modifier.size(32.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Badge с количеством непрочитанных из других чатов
|
// Badge с количеством непрочитанных из других чатов
|
||||||
@@ -542,7 +549,7 @@ fun ChatDetailScreen(
|
|||||||
.offset(x = (-4).dp, y = 6.dp)
|
.offset(x = (-4).dp, y = 6.dp)
|
||||||
.size(if (totalUnreadFromOthers > 9) 20.dp else 18.dp)
|
.size(if (totalUnreadFromOthers > 9) 20.dp else 18.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(PrimaryBlue),
|
.background(Color(0xFFFF3B30)), // Красный цвет как в iOS
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@@ -558,6 +565,8 @@ fun ChatDetailScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
|
||||||
// Аватар
|
// Аватар
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
|
|||||||
@@ -189,6 +189,8 @@ fun ChatsListScreen(
|
|||||||
chatsViewModel.setAccount(accountPublicKey, accountPrivateKey)
|
chatsViewModel.setAccount(accountPublicKey, accountPrivateKey)
|
||||||
// Устанавливаем аккаунт для RecentSearchesManager
|
// Устанавливаем аккаунт для RecentSearchesManager
|
||||||
RecentSearchesManager.setAccount(accountPublicKey)
|
RecentSearchesManager.setAccount(accountPublicKey)
|
||||||
|
// 🔥 КРИТИЧНО: Инициализируем MessageRepository для обработки входящих сообщений
|
||||||
|
ProtocolManager.initializeAccount(accountPublicKey, accountPrivateKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.rosetta.messenger.ui.components
|
package com.rosetta.messenger.ui.components
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
@@ -38,10 +39,29 @@ class KeyboardManager(
|
|||||||
private val context: Context
|
private val context: Context
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Скрыть клавиатуру мгновенно (WindowInsetsController - API 30+)
|
* 🔥 Скрыть клавиатуру СИНХРОННО и МГНОВЕННО
|
||||||
|
* Использует InputMethodManager - самый надёжный способ
|
||||||
|
*/
|
||||||
|
fun hideNow() {
|
||||||
|
// 1. Убираем фокус с текущего view
|
||||||
|
view.clearFocus()
|
||||||
|
|
||||||
|
// 2. InputMethodManager - синхронное скрытие
|
||||||
|
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||||
|
imm?.hideSoftInputFromWindow(view.windowToken, 0)
|
||||||
|
|
||||||
|
// 3. WindowInsetsController как backup
|
||||||
|
try {
|
||||||
|
ViewCompat.getWindowInsetsController(view)?.hide(WindowInsetsCompat.Type.ime())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Скрыть клавиатуру (асинхронно через WindowInsetsController)
|
||||||
*/
|
*/
|
||||||
fun hide() {
|
fun hide() {
|
||||||
// WindowInsetsController - самый быстрый способ (API 30+)
|
|
||||||
ViewCompat.getWindowInsetsController(view)?.hide(WindowInsetsCompat.Type.ime())
|
ViewCompat.getWindowInsetsController(view)?.hide(WindowInsetsCompat.Type.ime())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +106,8 @@ fun rememberKeyboardController(): KeyboardManager {
|
|||||||
/**
|
/**
|
||||||
* 🔥 Автоматически скрывает клавиатуру при выходе с экрана (onDispose)
|
* 🔥 Автоматически скрывает клавиатуру при выходе с экрана (onDispose)
|
||||||
*
|
*
|
||||||
|
* ВАЖНО: Это backup. Основное скрытие должно быть в hideKeyboardAndBack()
|
||||||
|
*
|
||||||
* Добавьте в начало любого Composable экрана с клавиатурой:
|
* Добавьте в начало любого Composable экрана с клавиатурой:
|
||||||
* ```kotlin
|
* ```kotlin
|
||||||
* @Composable
|
* @Composable
|
||||||
@@ -99,14 +121,11 @@ fun rememberKeyboardController(): KeyboardManager {
|
|||||||
@Composable
|
@Composable
|
||||||
fun HideKeyboardOnDispose() {
|
fun HideKeyboardOnDispose() {
|
||||||
val keyboard = rememberKeyboardController()
|
val keyboard = rememberKeyboardController()
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
|
||||||
|
|
||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
onDispose {
|
onDispose {
|
||||||
// WindowInsetsController - мгновенное скрытие
|
// Backup скрытие при dispose
|
||||||
keyboard.hide()
|
keyboard.hideNow()
|
||||||
// Fallback для Compose
|
|
||||||
keyboardController?.hide()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,17 +139,14 @@ fun HideKeyboardOnDispose() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun HideKeyboardAndClearFocusOnDispose() {
|
fun HideKeyboardAndClearFocusOnDispose() {
|
||||||
val keyboard = rememberKeyboardController()
|
val keyboard = rememberKeyboardController()
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
|
|
||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
onDispose {
|
onDispose {
|
||||||
// Сбрасываем фокус
|
// Сбрасываем фокус
|
||||||
focusManager.clearFocus(force = true)
|
focusManager.clearFocus(force = true)
|
||||||
// WindowInsetsController - мгновенное скрытие
|
// Мгновенное скрытие
|
||||||
keyboard.hide()
|
keyboard.hideNow()
|
||||||
// Fallback для Compose
|
|
||||||
keyboardController?.hide()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user