feat: Remove HideKeyboardOnDispose component to streamline keyboard management across screens

This commit is contained in:
k1ngsterr1
2026-01-13 21:35:31 +05:00
parent 7f89ffc779
commit 145a3621a1
7 changed files with 2 additions and 194 deletions

View File

@@ -26,7 +26,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import com.rosetta.messenger.ui.components.HideKeyboardOnDispose
// Beautiful solid colors that fit the theme
private val wordColors = listOf(
@@ -51,9 +50,6 @@ fun ConfirmSeedPhraseScreen(
onBack: () -> Unit,
onConfirmed: () -> Unit
) {
// 🔥 Автоматическое скрытие клавиатуры при выходе с экрана
HideKeyboardOnDispose()
val backgroundColor = if (isDarkTheme) Color(0xFF1E1E1E) else Color(0xFFFFFFFF)
val textColor = if (isDarkTheme) Color.White else Color.Black
val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)

View File

@@ -22,7 +22,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import com.rosetta.messenger.ui.components.HideKeyboardOnDispose
data class AccountInfo(
val id: String,
@@ -64,9 +63,6 @@ fun SelectAccountScreen(
onImportSeed: () -> Unit,
onDismissModal: () -> Unit
) {
// 🔥 Автоматическое скрытие клавиатуры при выходе с экрана
HideKeyboardOnDispose()
val backgroundColor = if (isDarkTheme) Color(0xFF1E1E1E) else Color(0xFFFFFFFF)
val textColor = if (isDarkTheme) Color.White else Color.Black
val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)

View File

@@ -31,7 +31,6 @@ import com.rosetta.messenger.data.DecryptedAccount
import com.rosetta.messenger.data.EncryptedAccount
import com.rosetta.messenger.network.ProtocolManager
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import com.rosetta.messenger.ui.components.HideKeyboardOnDispose
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@@ -42,9 +41,6 @@ fun SetPasswordScreen(
onBack: () -> Unit,
onAccountCreated: (DecryptedAccount) -> Unit
) {
// 🔥 Автоматическое скрытие клавиатуры при выходе с экрана
HideKeyboardOnDispose()
val themeAnimSpec = tween<Color>(durationMillis = 500, easing = CubicBezierEasing(0.4f, 0f, 0.2f, 1f))
val backgroundColor by animateColorAsState(if (isDarkTheme) AuthBackground else AuthBackgroundLight, animationSpec = themeAnimSpec)
val textColor by animateColorAsState(if (isDarkTheme) Color.White else Color.Black, animationSpec = themeAnimSpec)

View File

@@ -42,7 +42,6 @@ import com.rosetta.messenger.network.ProtocolManager
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import com.rosetta.messenger.ui.chats.getAvatarColor
import com.rosetta.messenger.ui.chats.getAvatarText
import com.rosetta.messenger.ui.components.HideKeyboardOnDispose
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
@@ -61,9 +60,6 @@ fun UnlockScreen(
onUnlocked: (DecryptedAccount) -> Unit,
onSwitchAccount: () -> Unit = {}
) {
// 🔥 Автоматическое скрытие клавиатуры при выходе с экрана
HideKeyboardOnDispose()
val themeAnimSpec = tween<Color>(durationMillis = 500, easing = CubicBezierEasing(0.4f, 0f, 0.2f, 1f))
val backgroundColor by animateColorAsState(if (isDarkTheme) AuthBackground else AuthBackgroundLight, animationSpec = themeAnimSpec)
val textColor by animateColorAsState(if (isDarkTheme) Color.White else Color.Black, animationSpec = themeAnimSpec)

View File

@@ -67,8 +67,6 @@ import com.rosetta.messenger.network.SearchUser
import com.rosetta.messenger.ui.components.AppleEmojiPickerPanel
import com.rosetta.messenger.ui.components.AppleEmojiText
import com.rosetta.messenger.ui.components.AppleEmojiTextField
import com.rosetta.messenger.ui.components.HideKeyboardOnDispose
import com.rosetta.messenger.ui.components.rememberKeyboardController
import com.rosetta.messenger.ui.components.VerifiedBadge
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import android.view.inputmethod.InputMethodManager
@@ -218,15 +216,11 @@ fun ChatDetailScreen(
onUserProfileClick: () -> Unit = {},
viewModel: ChatViewModel = viewModel()
) {
// 🔥 Backup: скрывает клавиатуру при dispose (если не скрыли раньше)
HideKeyboardOnDispose()
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
val clipboardManager = androidx.compose.ui.platform.LocalClipboardManager.current
val context = LocalContext.current
val view = LocalView.current
val keyboard = rememberKeyboardController()
val database = remember { com.rosetta.messenger.database.RosettaDatabase.getDatabase(context) }
// 🔔 Badge: количество непрочитанных сообщений из других чатов
@@ -288,9 +282,9 @@ fun ChatDetailScreen(
var selectedMessages by remember { mutableStateOf<Set<String>>(emptySet()) }
val isSelectionMode = selectedMessages.isNotEmpty()
// 🔥 Простое закрытие
// 🔥 Закрытие экрана
val hideKeyboardAndBack: () -> Unit = {
keyboard.hide()
keyboardController?.hide()
onBack()
}

View File

@@ -25,7 +25,6 @@ import androidx.compose.ui.unit.sp
import com.rosetta.messenger.data.RecentSearchesManager
import com.rosetta.messenger.network.ProtocolState
import com.rosetta.messenger.network.SearchUser
import com.rosetta.messenger.ui.components.HideKeyboardOnDispose
// Primary Blue color
private val PrimaryBlue = Color(0xFF54A9EB)
@@ -44,9 +43,6 @@ fun SearchScreen(
onBackClick: () -> Unit,
onUserSelect: (SearchUser) -> Unit
) {
// 🔥 Автоматическое скрытие клавиатуры при выходе с экрана
HideKeyboardOnDispose()
// Цвета ТОЧНО как в ChatsListScreen
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
val textColor = if (isDarkTheme) Color.White else Color(0xFF1a1a1a)

View File

@@ -1,166 +0,0 @@
package com.rosetta.messenger.ui.components
import android.app.Activity
import android.content.Context
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.LocalView
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
/**
* 🎹 Контроллер клавиатуры для Rosetta Messenger
*
* Использует современный WindowInsetsController (API 30+) для мгновенного
* скрытия клавиатуры. Решает проблему "залипания" клавиатуры при навигации.
*
* Использование:
* ```kotlin
* @Composable
* fun MyScreen() {
* // Автоматически скрывает клавиатуру при выходе с экрана
* HideKeyboardOnDispose()
*
* // Или получите контроллер для ручного управления
* val keyboard = rememberKeyboardController()
* Button(onClick = { keyboard.hide() }) { Text("Hide") }
* }
* ```
*/
class KeyboardManager(
private val view: View,
private val context: Context
) {
/**
* 🔥 Скрыть клавиатуру СИНХРОННО и МГНОВЕННО
* Использует 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() {
ViewCompat.getWindowInsetsController(view)?.hide(WindowInsetsCompat.Type.ime())
}
/**
* Показать клавиатуру
*/
fun show() {
ViewCompat.getWindowInsetsController(view)?.show(WindowInsetsCompat.Type.ime())
}
/**
* Скрыть клавиатуру с fallback для старых устройств
*/
fun hideWithFallback() {
// Сначала пробуем WindowInsetsController
ViewCompat.getWindowInsetsController(view)?.hide(WindowInsetsCompat.Type.ime())
// Fallback через InputMethodManager
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
imm?.hideSoftInputFromWindow(view.windowToken, 0)
}
/**
* Проверить, видна ли клавиатура
*/
fun isVisible(): Boolean {
val insets = ViewCompat.getRootWindowInsets(view)
return insets?.isVisible(WindowInsetsCompat.Type.ime()) == true
}
}
/**
* Composable для получения KeyboardManager
*/
@Composable
fun rememberKeyboardController(): KeyboardManager {
val view = LocalView.current
val context = LocalContext.current
return remember(view, context) { KeyboardManager(view, context) }
}
/**
* 🔥 Автоматически скрывает клавиатуру при выходе с экрана (onDispose)
*
* ВАЖНО: Это backup. Основное скрытие должно быть в hideKeyboardAndBack()
*
* Добавьте в начало любого Composable экрана с клавиатурой:
* ```kotlin
* @Composable
* fun ChatScreen() {
* HideKeyboardOnDispose()
* // ... остальной UI
* }
* ```
*/
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun HideKeyboardOnDispose() {
val keyboard = rememberKeyboardController()
DisposableEffect(Unit) {
onDispose {
// Backup скрытие при dispose
keyboard.hideNow()
}
}
}
/**
* 🔥 Расширенная версия с очисткой фокуса
*
* Использовать когда нужно также сбросить фокус с TextField
*/
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun HideKeyboardAndClearFocusOnDispose() {
val keyboard = rememberKeyboardController()
val focusManager = LocalFocusManager.current
DisposableEffect(Unit) {
onDispose {
// Сбрасываем фокус
focusManager.clearFocus(force = true)
// Мгновенное скрытие
keyboard.hideNow()
}
}
}
/**
* Extension function для View - скрыть клавиатуру мгновенно
*/
fun View.hideKeyboardNow() {
ViewCompat.getWindowInsetsController(this)?.hide(WindowInsetsCompat.Type.ime())
}
/**
* Extension function для View - показать клавиатуру
*/
fun View.showKeyboardNow() {
ViewCompat.getWindowInsetsController(this)?.show(WindowInsetsCompat.Type.ime())
}