feat: Enhance search functionality and user experience
- Added local account metadata handling in SearchScreen for improved "Saved Messages" search fallback. - Updated search logic to include username and account name checks when searching for the user. - Introduced search logging in SearchUsersViewModel for better debugging and tracking of search queries. - Refactored image download process in AttachmentComponents to include detailed logging for debugging. - Created AttachmentDownloadDebugLogger to manage and display download logs. - Improved DeviceVerificationBanner UI for better user engagement during device verification. - Adjusted OtherProfileScreen layout to enhance information visibility and user interaction. - Updated network security configuration to include new Let's Encrypt certificate for CDN.
This commit is contained in:
@@ -35,6 +35,16 @@ class PacketSearch : Packet() {
|
||||
stream.writeInt16(getPacketId())
|
||||
stream.writeString(privateKey)
|
||||
stream.writeString(search)
|
||||
// Desktop parity: packet always includes users count block.
|
||||
// For client requests this is 0, but field must be present for server parser.
|
||||
stream.writeInt16(users.size)
|
||||
users.forEach { user ->
|
||||
stream.writeString(user.username)
|
||||
stream.writeString(user.title)
|
||||
stream.writeString(user.publicKey)
|
||||
stream.writeInt8(user.verified)
|
||||
stream.writeInt8(user.online)
|
||||
}
|
||||
return stream
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.os.Build
|
||||
import com.rosetta.messenger.data.AccountManager
|
||||
import com.rosetta.messenger.data.MessageRepository
|
||||
import com.rosetta.messenger.data.isPlaceholderAccountName
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -277,7 +278,7 @@ object ProtocolManager {
|
||||
// Если это наш own profile — сохраняем username/name в AccountManager
|
||||
if (user.publicKey == ownPublicKey && appContext != null) {
|
||||
val accountManager = AccountManager(appContext!!)
|
||||
if (user.title.isNotBlank()) {
|
||||
if (user.title.isNotBlank() && !isPlaceholderAccountName(user.title)) {
|
||||
accountManager.updateAccountName(user.publicKey, user.title)
|
||||
}
|
||||
if (user.username.isNotBlank()) {
|
||||
@@ -333,6 +334,24 @@ object ProtocolManager {
|
||||
TransportManager.requestTransportServer()
|
||||
fetchOwnProfile()
|
||||
requestSynchronize()
|
||||
subscribePushTokenIfAvailable()
|
||||
}
|
||||
|
||||
private fun subscribePushTokenIfAvailable() {
|
||||
val context = appContext ?: return
|
||||
val token =
|
||||
context.getSharedPreferences("rosetta_prefs", Context.MODE_PRIVATE)
|
||||
.getString("fcm_token", null)
|
||||
?.trim()
|
||||
.orEmpty()
|
||||
if (token.isEmpty()) return
|
||||
|
||||
val packet = PacketPushNotification().apply {
|
||||
notificationsToken = token
|
||||
action = PushNotificationAction.SUBSCRIBE
|
||||
}
|
||||
send(packet)
|
||||
addLog("🔔 Push token subscribe requested on AUTHENTICATED")
|
||||
}
|
||||
|
||||
private fun requestSynchronize() {
|
||||
|
||||
@@ -8,7 +8,6 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.*
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.resume
|
||||
@@ -29,12 +28,8 @@ data class TransportState(
|
||||
* Совместимо с desktop версией (TransportProvider)
|
||||
*/
|
||||
object TransportManager {
|
||||
private const val TAG = "TransportManager"
|
||||
private const val MAX_RETRIES = 3
|
||||
private const val INITIAL_BACKOFF_MS = 1000L
|
||||
|
||||
// Fallback transport server (CDN)
|
||||
private const val FALLBACK_TRANSPORT_SERVER = "https://cdn.rosetta-im.com"
|
||||
|
||||
private var transportServer: String? = null
|
||||
|
||||
@@ -54,20 +49,32 @@ object TransportManager {
|
||||
* Установить адрес транспортного сервера
|
||||
*/
|
||||
fun setTransportServer(server: String) {
|
||||
transportServer = server
|
||||
val normalized = server.trim().trimEnd('/')
|
||||
transportServer = normalized.ifBlank { null }
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить адрес транспортного сервера (с fallback)
|
||||
* Получить текущий адрес транспортного сервера
|
||||
*/
|
||||
fun getTransportServer(): String = transportServer ?: FALLBACK_TRANSPORT_SERVER
|
||||
fun getTransportServer(): String? = transportServer
|
||||
|
||||
/**
|
||||
* Получить активный сервер для скачивания/загрузки
|
||||
* Получить активный сервер для скачивания/загрузки.
|
||||
* Desktop parity: ждём сервер из PacketRequestTransport (0x0F), а не используем hardcoded CDN.
|
||||
*/
|
||||
private fun getActiveServer(): String {
|
||||
val server = transportServer ?: FALLBACK_TRANSPORT_SERVER
|
||||
return server
|
||||
private suspend fun getActiveServer(): String {
|
||||
transportServer?.let { return it }
|
||||
|
||||
requestTransportServer()
|
||||
repeat(40) { // 10s total
|
||||
val server = transportServer
|
||||
if (!server.isNullOrBlank()) {
|
||||
return server
|
||||
}
|
||||
delay(250)
|
||||
}
|
||||
|
||||
throw IOException("Transport server is not set")
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user