Refactor image handling and decoding logic
- Introduced a maximum bitmap decode dimension to prevent excessive memory usage. - Enhanced base64 to bitmap conversion by extracting payload and applying EXIF orientation. - Improved error handling for image downloads and decoding processes. - Simplified media picker and chat input components to manage keyboard visibility more effectively. - Updated color selection grid to adaptively adjust based on available width. - Added safety checks for notifications and call actions in profile screens. - Optimized bitmap decoding in uriToBase64Image to handle large images more efficiently.
This commit is contained in:
@@ -591,7 +591,38 @@ class Protocol(
|
||||
* Check if connected and authenticated
|
||||
*/
|
||||
fun isAuthenticated(): Boolean = _state.value == ProtocolState.AUTHENTICATED
|
||||
|
||||
|
||||
/**
|
||||
* Foreground fast reconnect:
|
||||
* on app resume we should not wait scheduled exponential backoff.
|
||||
*/
|
||||
fun reconnectNowIfNeeded(reason: String = "foreground") {
|
||||
val currentState = _state.value
|
||||
val hasCredentials = !lastPublicKey.isNullOrBlank() && !lastPrivateHash.isNullOrBlank()
|
||||
|
||||
log(
|
||||
"⚡ FAST RECONNECT CHECK: state=$currentState, hasCredentials=$hasCredentials, isConnecting=$isConnecting, reason=$reason"
|
||||
)
|
||||
|
||||
if (!hasCredentials) return
|
||||
|
||||
if (
|
||||
currentState == ProtocolState.AUTHENTICATED ||
|
||||
currentState == ProtocolState.HANDSHAKING ||
|
||||
currentState == ProtocolState.DEVICE_VERIFICATION_REQUIRED ||
|
||||
currentState == ProtocolState.CONNECTED ||
|
||||
(currentState == ProtocolState.CONNECTING && isConnecting)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// Reset backoff and connect immediately.
|
||||
reconnectAttempts = 0
|
||||
reconnectJob?.cancel()
|
||||
reconnectJob = null
|
||||
connect()
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if connected (may not be authenticated yet)
|
||||
*/
|
||||
|
||||
@@ -9,6 +9,8 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import java.security.SecureRandom
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
@@ -66,8 +68,18 @@ object ProtocolManager {
|
||||
private var uiLogsEnabled = false
|
||||
private var lastProtocolState: ProtocolState? = null
|
||||
@Volatile private var syncBatchInProgress = false
|
||||
private val _syncInProgress = MutableStateFlow(false)
|
||||
val syncInProgress: StateFlow<Boolean> = _syncInProgress.asStateFlow()
|
||||
@Volatile private var resyncRequiredAfterAccountInit = false
|
||||
private val inboundPacketTasks = AtomicInteger(0)
|
||||
private val inboundPacketMutex = Mutex()
|
||||
|
||||
private fun setSyncInProgress(value: Boolean) {
|
||||
syncBatchInProgress = value
|
||||
if (_syncInProgress.value != value) {
|
||||
_syncInProgress.value = value
|
||||
}
|
||||
}
|
||||
|
||||
fun addLog(message: String) {
|
||||
val timestamp = dateFormat.format(Date())
|
||||
@@ -107,6 +119,9 @@ object ProtocolManager {
|
||||
if (newState == ProtocolState.AUTHENTICATED && previous != ProtocolState.AUTHENTICATED) {
|
||||
onAuthenticated()
|
||||
}
|
||||
if (newState != ProtocolState.AUTHENTICATED && newState != ProtocolState.HANDSHAKING) {
|
||||
setSyncInProgress(false)
|
||||
}
|
||||
lastProtocolState = newState
|
||||
}
|
||||
}
|
||||
@@ -117,7 +132,7 @@ object ProtocolManager {
|
||||
* Должен вызываться после авторизации пользователя
|
||||
*/
|
||||
fun initializeAccount(publicKey: String, privateKey: String) {
|
||||
syncBatchInProgress = false
|
||||
setSyncInProgress(false)
|
||||
messageRepository?.initialize(publicKey, privateKey)
|
||||
if (resyncRequiredAfterAccountInit || protocol?.isAuthenticated() == true) {
|
||||
resyncRequiredAfterAccountInit = false
|
||||
@@ -309,7 +324,10 @@ object ProtocolManager {
|
||||
inboundPacketTasks.incrementAndGet()
|
||||
scope.launch {
|
||||
try {
|
||||
block()
|
||||
// Preserve packet handling order to avoid read/message races during sync.
|
||||
inboundPacketMutex.withLock {
|
||||
block()
|
||||
}
|
||||
} finally {
|
||||
inboundPacketTasks.decrementAndGet()
|
||||
}
|
||||
@@ -331,6 +349,7 @@ object ProtocolManager {
|
||||
}
|
||||
|
||||
private fun onAuthenticated() {
|
||||
setSyncInProgress(false)
|
||||
TransportManager.requestTransportServer()
|
||||
fetchOwnProfile()
|
||||
requestSynchronize()
|
||||
@@ -378,17 +397,16 @@ object ProtocolManager {
|
||||
scope.launch {
|
||||
when (packet.status) {
|
||||
SyncStatus.BATCH_START -> {
|
||||
syncBatchInProgress = true
|
||||
setSyncInProgress(true)
|
||||
}
|
||||
SyncStatus.BATCH_END -> {
|
||||
syncBatchInProgress = true
|
||||
setSyncInProgress(true)
|
||||
waitInboundPacketTasks()
|
||||
messageRepository?.updateLastSyncTimestamp(packet.timestamp)
|
||||
syncBatchInProgress = false
|
||||
sendSynchronize(packet.timestamp)
|
||||
}
|
||||
SyncStatus.NOT_NEEDED -> {
|
||||
syncBatchInProgress = false
|
||||
setSyncInProgress(false)
|
||||
messageRepository?.updateLastSyncTimestamp(packet.timestamp)
|
||||
}
|
||||
}
|
||||
@@ -423,6 +441,13 @@ object ProtocolManager {
|
||||
fun connect() {
|
||||
getProtocol().connect()
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger immediate reconnect on app foreground (skip waiting backoff timer).
|
||||
*/
|
||||
fun reconnectNowIfNeeded(reason: String = "foreground_resume") {
|
||||
getProtocol().reconnectNowIfNeeded(reason)
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate with server
|
||||
@@ -647,7 +672,7 @@ object ProtocolManager {
|
||||
protocol?.clearCredentials()
|
||||
_devices.value = emptyList()
|
||||
_pendingDeviceVerification.value = null
|
||||
syncBatchInProgress = false
|
||||
setSyncInProgress(false)
|
||||
inboundPacketTasks.set(0)
|
||||
}
|
||||
|
||||
@@ -659,7 +684,7 @@ object ProtocolManager {
|
||||
protocol = null
|
||||
_devices.value = emptyList()
|
||||
_pendingDeviceVerification.value = null
|
||||
syncBatchInProgress = false
|
||||
setSyncInProgress(false)
|
||||
inboundPacketTasks.set(0)
|
||||
scope.cancel()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user