diff --git a/app/src/main/java/com/rosetta/messenger/MainActivity.kt b/app/src/main/java/com/rosetta/messenger/MainActivity.kt index 8845d81..07db142 100644 --- a/app/src/main/java/com/rosetta/messenger/MainActivity.kt +++ b/app/src/main/java/com/rosetta/messenger/MainActivity.kt @@ -420,6 +420,8 @@ class MainActivity : FragmentActivity() { com.rosetta.messenger.push.RosettaFirebaseMessagingService.isAppInForeground = true // ⚡ На возврате в приложение пробуем мгновенный reconnect без ожидания backoff. ProtocolManager.reconnectNowIfNeeded("activity_onResume") + // 🔄 Desktop parity: синхронизация при каждом заходе в приложение + ProtocolManager.syncOnForeground() } override fun onPause() { diff --git a/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt b/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt index 2eaff49..6e70758 100644 --- a/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt +++ b/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt @@ -69,6 +69,7 @@ object ProtocolManager { private val _syncInProgress = MutableStateFlow(false) val syncInProgress: StateFlow = _syncInProgress.asStateFlow() @Volatile private var resyncRequiredAfterAccountInit = false + @Volatile private var lastForegroundSyncTime = 0L // Desktop parity: sequential task queue matching dialogQueue.ts (promise chain). // Uses Channel to guarantee strict FIFO ordering (Mutex+lastInboundJob had a race // condition: Dispatchers.IO doesn't guarantee FIFO, so the last-launched job could @@ -561,6 +562,22 @@ object ProtocolManager { fun reconnectNowIfNeeded(reason: String = "foreground_resume") { getProtocol().reconnectNowIfNeeded(reason) } + + /** + * Desktop parity: синхронизация при каждом заходе в приложение. + * Desktop вызывает trySync() на каждый handshakeExchangeComplete. + * На Android — вызываем из onResume(), если уже AUTHENTICATED и не идёт sync. + * Дебаунс 5 секунд чтобы не спамить при быстром alt-tab. + */ + fun syncOnForeground() { + if (!isAuthenticated()) return + if (syncBatchInProgress) return + val now = System.currentTimeMillis() + if (now - lastForegroundSyncTime < 5_000) return + lastForegroundSyncTime = now + addLog("🔄 SYNC on foreground resume") + requestSynchronize() + } /** * Authenticate with server 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 ddd3d1b..0f4a4f7 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 @@ -1148,6 +1148,58 @@ fun ChatsListScreen( } ) + // 🔔 FCM Token + DrawerDivider(isDarkTheme) + run { + var fcmToken by remember { mutableStateOf(null) } + LaunchedEffect(Unit) { + fcmToken = context.getSharedPreferences("rosetta_prefs", Context.MODE_PRIVATE) + .getString("fcm_token", null) + } + val clipboardManager = androidx.compose.ui.platform.LocalClipboardManager.current + val tokenValue = fcmToken + if (!tokenValue.isNullOrEmpty()) { + Column( + modifier = Modifier + .fillMaxWidth() + .clickable { + clipboardManager.setText( + androidx.compose.ui.text.AnnotatedString(tokenValue) + ) + android.widget.Toast.makeText( + context, + "FCM token copied", + android.widget.Toast.LENGTH_SHORT + ).show() + } + .padding(horizontal = 20.dp, vertical = 10.dp) + ) { + Text( + text = "FCM Token (tap to copy)", + fontSize = 11.sp, + fontWeight = FontWeight.Medium, + color = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF8E8E93) + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = tokenValue, + fontSize = 9.sp, + color = if (isDarkTheme) Color(0xFF555555) else Color(0xFFAAAAAA), + maxLines = 3, + overflow = TextOverflow.Ellipsis, + fontFamily = FontFamily.Monospace + ) + } + } else { + Text( + text = "FCM Token: not available", + fontSize = 11.sp, + color = if (isDarkTheme) Color(0xFF555555) else Color(0xFFAAAAAA), + modifier = Modifier.padding(horizontal = 20.dp, vertical = 10.dp) + ) + } + } + } // ═══════════════════════════════════════════════════════════