Фикс клавиатуры, скругления input, iOS 26 layout, доставка сообщений и синхронизация
This commit is contained in:
@@ -124,6 +124,35 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Android parity: `reconnectNowIfNeeded(reason: "foreground")`.
|
||||
/// On foreground resume, always force reconnect — iOS suspends the process in
|
||||
/// background, server RSTs TCP, but `didCloseWith` never fires (zombie socket).
|
||||
/// Android doesn't have this because OkHttp fires onFailure in background.
|
||||
/// Previously iOS used ping-first (3s timeout) which was too slow.
|
||||
func forceReconnectOnForeground() {
|
||||
guard savedPublicKey != nil, savedPrivateHash != nil else { return }
|
||||
|
||||
// Android parity: skip if handshake or device verification is in progress.
|
||||
// These are active flows that should not be interrupted.
|
||||
switch connectionState {
|
||||
case .handshaking, .deviceVerificationRequired:
|
||||
return
|
||||
case .connecting:
|
||||
if client.isConnecting { return }
|
||||
case .authenticated, .connected, .disconnected:
|
||||
break // Always reconnect — .authenticated/.connected may be zombie on iOS
|
||||
}
|
||||
|
||||
Self.logger.info("⚡ Foreground reconnect — tearing down potential zombie socket")
|
||||
pingVerificationInProgress = false
|
||||
pingTimeoutTask?.cancel()
|
||||
pingTimeoutTask = nil
|
||||
handshakeComplete = false
|
||||
heartbeatTask?.cancel()
|
||||
connectionState = .connecting
|
||||
client.forceReconnect()
|
||||
}
|
||||
|
||||
/// Android parity: `reconnectNowIfNeeded()` — if already in an active state,
|
||||
/// skip reconnect. Otherwise reset backoff and connect immediately.
|
||||
func reconnectIfNeeded() {
|
||||
@@ -191,7 +220,13 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
handshakeComplete = false
|
||||
heartbeatTask?.cancel()
|
||||
Task { @MainActor in
|
||||
self.connectionState = .connecting
|
||||
// Guard: only downgrade to .connecting if reconnect hasn't already progressed.
|
||||
// forceReconnect() is called synchronously below — if it completes fast,
|
||||
// this async Task could overwrite .authenticated/.handshaking with .connecting.
|
||||
let s = self.connectionState
|
||||
if s != .authenticated && s != .handshaking && s != .connected {
|
||||
self.connectionState = .connecting
|
||||
}
|
||||
}
|
||||
client.forceReconnect()
|
||||
}
|
||||
@@ -291,7 +326,11 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
self.handshakeComplete = false
|
||||
self.heartbeatTask?.cancel()
|
||||
Task { @MainActor in
|
||||
self.connectionState = .connecting
|
||||
// Guard: only downgrade to .connecting if reconnect hasn't already progressed.
|
||||
let s = self.connectionState
|
||||
if s != .authenticated && s != .handshaking && s != .connected {
|
||||
self.connectionState = .connecting
|
||||
}
|
||||
}
|
||||
self.client.forceReconnect()
|
||||
}
|
||||
@@ -339,7 +378,11 @@ final class ProtocolManager: @unchecked Sendable {
|
||||
self.handshakeComplete = false
|
||||
self.heartbeatTask?.cancel()
|
||||
Task { @MainActor in
|
||||
self.connectionState = .connecting
|
||||
// Guard: only downgrade to .connecting if reconnect hasn't already progressed.
|
||||
let s = self.connectionState
|
||||
if s != .authenticated && s != .handshaking && s != .connected {
|
||||
self.connectionState = .connecting
|
||||
}
|
||||
}
|
||||
self.client.forceReconnect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user