From 00e9370910918e765ef64e6f31f498e698eb5b3b Mon Sep 17 00:00:00 2001 From: k1ngsterr1 Date: Wed, 11 Mar 2026 22:59:48 +0700 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20push-=D1=83=D0=B2=D0=B5=D0=B4=D0=BE=D0=BC?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F:=20=D0=B2=D0=BE=D1=81=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20=D1=82=D0=BE=D0=BA?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B8=20fallback=20=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/rosetta/messenger/MainActivity.kt | 21 +++++++++++++------ .../messenger/network/ProtocolManager.kt | 20 +++++------------- .../push/RosettaFirebaseMessagingService.kt | 18 +++++++++++----- .../ui/chats/components/InAppCameraScreen.kt | 12 +++-------- .../ui/onboarding/OnboardingScreen.kt | 13 ++++-------- .../messenger/ui/utils/NavigationModeUtils.kt | 16 +++----------- .../ui/utils/SystemBarsStyleUtils.kt | 15 ++++--------- 7 files changed, 47 insertions(+), 68 deletions(-) diff --git a/app/src/main/java/com/rosetta/messenger/MainActivity.kt b/app/src/main/java/com/rosetta/messenger/MainActivity.kt index 1d23041..07ff4cd 100644 --- a/app/src/main/java/com/rosetta/messenger/MainActivity.kt +++ b/app/src/main/java/com/rosetta/messenger/MainActivity.kt @@ -458,15 +458,24 @@ class MainActivity : FragmentActivity() { // Сохраняем токен локально saveFcmToken(token) addFcmLog("💾 Токен сохранен локально") - - // Token will be sent by ProtocolManager.onAuthenticated() - // when protocol reaches AUTHENTICATED state + if (ProtocolManager.isAuthenticated()) { + runCatching { + ProtocolManager.subscribePushTokenIfAvailable( + forceToken = token + ) + } + .onSuccess { + addFcmLog("🔔 Push token отправлен на сервер сразу") + } + .onFailure { error -> + addFcmLog( + "❌ Ошибка отправки push token: ${error.message}" + ) + } + } } else { addFcmLog("⚠️ Токен пустой") } - - // Токен будет отправлен через ProtocolManager.subscribePushTokenIfAvailable() - // при достижении состояния AUTHENTICATED } } catch (e: Exception) { addFcmLog("❌ Ошибка Firebase: ${e.message}") 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 554469b..841e2b0 100644 --- a/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt +++ b/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt @@ -187,11 +187,15 @@ object ProtocolManager { getProtocol().state.collect { newState -> val previous = lastProtocolState if (newState == ProtocolState.AUTHENTICATED && previous != ProtocolState.AUTHENTICATED) { + // New authenticated websocket session: always allow fresh push subscribe. + lastSubscribedToken = null onAuthenticated() } if (newState != ProtocolState.AUTHENTICATED && newState != ProtocolState.HANDSHAKING) { syncRequestInFlight = false setSyncInProgress(false) + // Connection/session dropped: force re-subscribe on next AUTHENTICATED. + lastSubscribedToken = null } lastProtocolState = newState } @@ -616,10 +620,6 @@ object ProtocolManager { * [com.rosetta.messenger.push.RosettaFirebaseMessagingService.onNewToken] * when Firebase rotates the token mid-session. * - * On each connect we send UNSUBSCRIBE first to clear any duplicate - * registrations that may have accumulated on the server, then SUBSCRIBE - * once — guaranteeing exactly one active push binding per device. - * * @param forceToken if non-null, use this token instead of reading SharedPreferences * (used by onNewToken which already has the fresh token). */ @@ -638,23 +638,13 @@ object ProtocolManager { return } - // 1) UNSUBSCRIBE — clears ALL existing registrations for this token on the server. - // This removes duplicates that may have been created before the dedup fix. - val unsubPacket = PacketPushNotification().apply { - notificationsToken = token - action = PushNotificationAction.UNSUBSCRIBE - } - send(unsubPacket) - addLog("🔕 Push token UNSUBSCRIBE sent (clearing duplicates)") - - // 2) SUBSCRIBE — register exactly once. val subPacket = PacketPushNotification().apply { notificationsToken = token action = PushNotificationAction.SUBSCRIBE } send(subPacket) lastSubscribedToken = token - addLog("🔔 Push token SUBSCRIBE sent — single registration") + addLog("🔔 Push token SUBSCRIBE sent") } private fun requestSynchronize() { diff --git a/app/src/main/java/com/rosetta/messenger/push/RosettaFirebaseMessagingService.kt b/app/src/main/java/com/rosetta/messenger/push/RosettaFirebaseMessagingService.kt index 3cd1c06..ae24d72 100644 --- a/app/src/main/java/com/rosetta/messenger/push/RosettaFirebaseMessagingService.kt +++ b/app/src/main/java/com/rosetta/messenger/push/RosettaFirebaseMessagingService.kt @@ -132,6 +132,19 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() { handledMessageData = true } } + + val looksLikeMessagePayload = + type.contains("message") || + data.keys.any { key -> + val lower = key.lowercase(Locale.ROOT) + lower.contains("message") || + lower.contains("text") || + lower.contains("body") + } + if (!handledMessageData && !isReadEvent && looksLikeMessagePayload) { + showSimpleNotification(senderName, messagePreview) + handledMessageData = true + } } // Обрабатываем notification payload (если есть). @@ -164,11 +177,6 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() { } lastNotifTimestamps[dedupKey] = now Log.d(TAG, "\u2705 Showing notification for key=$dedupKey") - // Desktop parity: suppress notifications during sync (useDialogFiber.ts checks - // protocolState != ProtocolState.SYNCHRONIZATION before calling notify()). - if (ProtocolManager.syncInProgress.value) { - return - } val senderKey = senderPublicKey?.trim().orEmpty() if (senderKey.isNotEmpty() && isDialogMuted(senderKey)) { return diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/components/InAppCameraScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/components/InAppCameraScreen.kt index dfe93b6..15ace5b 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/components/InAppCameraScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/components/InAppCameraScreen.kt @@ -187,15 +187,9 @@ fun InAppCameraScreen( window.statusBarColor = originalStatusBarColor insetsController.isAppearanceLightStatusBars = originalLightStatusBars - // Navigation bar: восстанавливаем только если есть нативные кнопки - if (com.rosetta.messenger.ui.utils.NavigationModeUtils.hasNativeNavigationBar(context)) { - window.navigationBarColor = originalNavigationBarColor - insetsController.isAppearanceLightNavigationBars = originalLightNavigationBars - } else { - insetsController.hide(androidx.core.view.WindowInsetsCompat.Type.navigationBars()) - insetsController.systemBarsBehavior = - androidx.core.view.WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - } + window.navigationBarColor = originalNavigationBarColor + insetsController.isAppearanceLightNavigationBars = originalLightNavigationBars + insetsController.show(androidx.core.view.WindowInsetsCompat.Type.navigationBars()) } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/onboarding/OnboardingScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/onboarding/OnboardingScreen.kt index 9b214d4..b438d5c 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/onboarding/OnboardingScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/onboarding/OnboardingScreen.kt @@ -173,15 +173,10 @@ fun OnboardingScreen( if (!view.isInEditMode) { val window = (view.context as android.app.Activity).window val insetsController = WindowCompat.getInsetsController(window, view) - if (NavigationModeUtils.hasNativeNavigationBar(view.context)) { - window.navigationBarColor = - if (isDarkTheme) 0xFF1E1E1E.toInt() else 0xFFFFFFFF.toInt() - } else { - // Жестовая навигация — прячем бар - insetsController.hide(WindowInsetsCompat.Type.navigationBars()) - insetsController.systemBarsBehavior = - WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - } + window.navigationBarColor = + if (isDarkTheme) 0xFF1E1E1E.toInt() else 0xFFFFFFFF.toInt() + insetsController.show(WindowInsetsCompat.Type.navigationBars()) + insetsController.isAppearanceLightNavigationBars = !isDarkTheme } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/utils/NavigationModeUtils.kt b/app/src/main/java/com/rosetta/messenger/ui/utils/NavigationModeUtils.kt index 128b742..d4f12b7 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/utils/NavigationModeUtils.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/utils/NavigationModeUtils.kt @@ -55,25 +55,15 @@ object NavigationModeUtils { } /** - * Показывает или прячет navigation bar в зависимости от типа навигации. - * - Кнопочная навигация → показываем бар - * - Жестовая навигация → прячем бар, свайп снизу временно покажет + * Показывает navigation bar на всех устройствах. */ fun applyNavigationBarVisibility( insetsController: WindowInsetsControllerCompat, context: Context, isDarkTheme: Boolean ) { - if (hasNativeNavigationBar(context)) { - // Есть нативные кнопки — показываем навигационный бар - insetsController.show(WindowInsetsCompat.Type.navigationBars()) - insetsController.isAppearanceLightNavigationBars = !isDarkTheme - } else { - // Жестовая навигация — прячем навигационный бар - insetsController.hide(WindowInsetsCompat.Type.navigationBars()) - insetsController.systemBarsBehavior = - WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - } + insetsController.show(WindowInsetsCompat.Type.navigationBars()) + insetsController.isAppearanceLightNavigationBars = !isDarkTheme } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/utils/SystemBarsStyleUtils.kt b/app/src/main/java/com/rosetta/messenger/ui/utils/SystemBarsStyleUtils.kt index 5014cef..1b05fe4 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/utils/SystemBarsStyleUtils.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/utils/SystemBarsStyleUtils.kt @@ -6,7 +6,6 @@ import android.view.View import android.view.Window import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat -import androidx.core.view.WindowInsetsControllerCompat data class SystemBarsState( val statusBarColor: Int, @@ -48,16 +47,10 @@ object SystemBarsStyleUtils { if (window == null || view == null) return val insetsController = WindowCompat.getInsetsController(window, view) - if (NavigationModeUtils.hasNativeNavigationBar(context)) { - insetsController.show(WindowInsetsCompat.Type.navigationBars()) - if (state != null) { - window.navigationBarColor = state.navigationBarColor - insetsController.isAppearanceLightNavigationBars = state.isLightNavigationBars - } - } else { - insetsController.hide(WindowInsetsCompat.Type.navigationBars()) - insetsController.systemBarsBehavior = - WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + insetsController.show(WindowInsetsCompat.Type.navigationBars()) + if (state != null) { + window.navigationBarColor = state.navigationBarColor + insetsController.isAppearanceLightNavigationBars = state.isLightNavigationBars } }