diff --git a/app/src/main/java/com/rosetta/messenger/data/RecentSearchesManager.kt b/app/src/main/java/com/rosetta/messenger/data/RecentSearchesManager.kt index 60ae8c8..20c0b21 100644 --- a/app/src/main/java/com/rosetta/messenger/data/RecentSearchesManager.kt +++ b/app/src/main/java/com/rosetta/messenger/data/RecentSearchesManager.kt @@ -11,23 +11,38 @@ import org.json.JSONObject /** * Менеджер для хранения недавно открытых пользователей (до 15 записей) + * Привязан к аккаунту пользователя */ object RecentSearchesManager { private const val PREFS_NAME = "recent_searches" - private const val KEY_USERS = "recent_users" + private const val KEY_USERS_PREFIX = "recent_users_" // + accountPublicKey private const val MAX_USERS = 15 private lateinit var prefs: SharedPreferences + private var currentAccount: String = "" private val _recentUsers = MutableStateFlow>(emptyList()) val recentUsers: StateFlow> = _recentUsers.asStateFlow() fun init(context: Context) { prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + } + + /** + * Установить текущий аккаунт и загрузить его историю + */ + fun setAccount(accountPublicKey: String) { + currentAccount = accountPublicKey loadUsers() } + private fun getUsersKey(): String = KEY_USERS_PREFIX + currentAccount + private fun loadUsers() { - val usersJson = prefs.getString(KEY_USERS, "[]") ?: "[]" + if (currentAccount.isEmpty()) { + _recentUsers.value = emptyList() + return + } + val usersJson = prefs.getString(getUsersKey(), "[]") ?: "[]" try { val jsonArray = JSONArray(usersJson) val users = mutableListOf() @@ -53,6 +68,8 @@ object RecentSearchesManager { * Добавить пользователя в историю */ fun addUser(user: SearchUser) { + if (currentAccount.isEmpty()) return + val currentUsers = _recentUsers.value.toMutableList() // Удаляем если уже есть (чтобы переместить наверх) @@ -73,6 +90,8 @@ object RecentSearchesManager { * Удалить пользователя из истории */ fun removeUser(publicKey: String) { + if (currentAccount.isEmpty()) return + val currentUsers = _recentUsers.value.toMutableList() currentUsers.removeAll { it.publicKey == publicKey } _recentUsers.value = currentUsers @@ -80,14 +99,18 @@ object RecentSearchesManager { } /** - * Очистить всю историю + * Очистить всю историю текущего аккаунта */ fun clearAll() { _recentUsers.value = emptyList() - prefs.edit().remove(KEY_USERS).apply() + if (currentAccount.isNotEmpty()) { + prefs.edit().remove(getUsersKey()).apply() + } } private fun saveUsers(users: List) { + if (currentAccount.isEmpty()) return + val jsonArray = JSONArray() users.forEach { user -> val obj = JSONObject().apply { @@ -99,6 +122,6 @@ object RecentSearchesManager { } jsonArray.put(obj) } - prefs.edit().putString(KEY_USERS, jsonArray.toString()).apply() + prefs.edit().putString(getUsersKey(), jsonArray.toString()).apply() } } diff --git a/app/src/main/java/com/rosetta/messenger/network/Protocol.kt b/app/src/main/java/com/rosetta/messenger/network/Protocol.kt index da2489b..cdc87aa 100644 --- a/app/src/main/java/com/rosetta/messenger/network/Protocol.kt +++ b/app/src/main/java/com/rosetta/messenger/network/Protocol.kt @@ -110,8 +110,9 @@ class Protocol( private fun startHeartbeat(intervalSeconds: Int) { heartbeatJob?.cancel() - val intervalMs = (intervalSeconds * 1000L) / 2 // Send at half the interval - log("💓 Starting heartbeat with interval: ${intervalSeconds}s (sending every ${intervalMs}ms)") + // Отправляем чаще - каждые 1/3 интервала (чтобы не терять соединение) + val intervalMs = (intervalSeconds * 1000L) / 3 + log("💓 Starting heartbeat with server interval: ${intervalSeconds}s (sending every ${intervalMs}ms = ${intervalMs/1000}s)") heartbeatJob = scope.launch { // ⚡ СРАЗУ отправляем первый heartbeat (как в Архиве) @@ -200,16 +201,17 @@ class Protocol( } override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { - log("⚠️ WebSocket closing: code=$code reason='$reason'") - log("⚠️ Stack trace at closing:") - Thread.currentThread().stackTrace.take(10).forEach { - log(" at $it") + // Code 3887 - кастомный код сервера, просто делаем reconnect тихо + if (code != 3887) { + log("⚠️ WebSocket closing: code=$code reason='$reason'") } } override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { - log("❌ WebSocket closed: code=$code reason='$reason'") - log("❌ State was: ${_state.value}") + // Для кода 3887 не логируем - это частое закрытие сервером + if (code != 3887) { + log("❌ WebSocket closed: code=$code reason='$reason'") + } handleDisconnect() } @@ -358,20 +360,13 @@ class Protocol( // Автоматический reconnect (простая логика как в Архиве - без счётчиков) if (!isManuallyClosed) { - log("🔄 Connection lost from $previousState, attempting to reconnect...") - log("🔄 Reconnecting in ${RECONNECT_INTERVAL}ms") + log("🔄 Reconnecting silently...") scope.launch { - delay(RECONNECT_INTERVAL) + // Быстрый reconnect - 1 секунда + delay(1000L) if (!isManuallyClosed) { connect() - // В Desktop проверяется socket?.readyState == WebSocket.OPEN - // В Android аналог - проверка state - if (_state.value == ProtocolState.CONNECTED || - _state.value == ProtocolState.AUTHENTICATED) { - return@launch - } - // В Desktop emit('reconnect') происходит здесь } } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt index 2dcb8aa..9aa2f27 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.airbnb.lottie.compose.* import com.rosetta.messenger.R +import com.rosetta.messenger.data.RecentSearchesManager import com.rosetta.messenger.database.DialogEntity import com.rosetta.messenger.network.ProtocolManager import com.rosetta.messenger.network.ProtocolState @@ -183,6 +184,8 @@ fun ChatsListScreen( LaunchedEffect(accountPublicKey) { if (accountPublicKey.isNotEmpty()) { chatsViewModel.setAccount(accountPublicKey) + // Устанавливаем аккаунт для RecentSearchesManager + RecentSearchesManager.setAccount(accountPublicKey) } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/SearchScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/SearchScreen.kt index 420de9f..2da2ca8 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/SearchScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/SearchScreen.kt @@ -58,6 +58,13 @@ fun SearchScreen( // Recent users (не текстовые запросы, а пользователи) val recentUsers by RecentSearchesManager.recentUsers.collectAsState() + // Устанавливаем аккаунт для RecentSearchesManager + LaunchedEffect(currentUserPublicKey) { + if (currentUserPublicKey.isNotEmpty()) { + RecentSearchesManager.setAccount(currentUserPublicKey) + } + } + // Устанавливаем privateKeyHash LaunchedEffect(privateKeyHash) { if (privateKeyHash.isNotEmpty()) {