Merge branch 'develop' into fix/jme/880-sliding-sync-loop-expires-and-restarts

This commit is contained in:
Benoit Marty 2023-07-17 22:18:59 +02:00 committed by GitHub
commit 80cf8e758a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
157 changed files with 3808 additions and 538 deletions

View file

@ -32,9 +32,7 @@ import io.element.android.libraries.matrix.api.MatrixClientProvider
import io.element.android.libraries.push.api.notifications.NotificationDrawerManager
import io.element.android.libraries.push.api.store.PushDataStore
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
import io.element.android.libraries.push.impl.notifications.model.shouldIgnoreEventInRoom
import io.element.android.services.appnavstate.api.AppNavigationState
import io.element.android.services.appnavstate.api.NavigationState
import io.element.android.services.appnavstate.api.AppNavigationStateService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
@ -65,7 +63,6 @@ class DefaultNotificationDrawerManager @Inject constructor(
* Lazily initializes the NotificationState as we rely on having a current session in order to fetch the persisted queue of events.
*/
private val notificationState by lazy { createInitialNotificationState() }
private var currentAppNavigationState: AppNavigationState? = null
private val firstThrottler = FirstThrottler(200)
// TODO EAx add a setting per user for this
@ -74,26 +71,25 @@ class DefaultNotificationDrawerManager @Inject constructor(
init {
// Observe application state
coroutineScope.launch {
appNavigationStateService.appNavigationStateFlow
.collect { onAppNavigationStateChange(it) }
appNavigationStateService.appNavigationState
.collect { onAppNavigationStateChange(it.navigationState) }
}
}
private fun onAppNavigationStateChange(appNavigationState: AppNavigationState) {
currentAppNavigationState = appNavigationState
when (appNavigationState) {
AppNavigationState.Root -> {}
is AppNavigationState.Session -> {}
is AppNavigationState.Space -> {}
is AppNavigationState.Room -> {
private fun onAppNavigationStateChange(navigationState: NavigationState) {
when (navigationState) {
NavigationState.Root -> {}
is NavigationState.Session -> {}
is NavigationState.Space -> {}
is NavigationState.Room -> {
// Cleanup notification for current room
clearMessagesForRoom(appNavigationState.parentSpace.parentSession.sessionId, appNavigationState.roomId)
clearMessagesForRoom(navigationState.parentSpace.parentSession.sessionId, navigationState.roomId)
}
is AppNavigationState.Thread -> {
is NavigationState.Thread -> {
onEnteringThread(
appNavigationState.parentRoom.parentSpace.parentSession.sessionId,
appNavigationState.parentRoom.roomId,
appNavigationState.threadId
navigationState.parentRoom.parentSpace.parentSession.sessionId,
navigationState.parentRoom.roomId,
navigationState.threadId
)
}
}
@ -225,7 +221,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
private suspend fun refreshNotificationDrawerBg() {
Timber.v("refreshNotificationDrawerBg()")
val eventsToRender = notificationState.updateQueuedEvents(this) { queuedEvents, renderedEvents ->
notifiableEventProcessor.process(queuedEvents.rawEvents(), currentAppNavigationState, renderedEvents).also {
notifiableEventProcessor.process(queuedEvents.rawEvents(), renderedEvents).also {
queuedEvents.clearAndAdd(it.onlyKeptEvents())
}
}
@ -274,8 +270,4 @@ class DefaultNotificationDrawerManager @Inject constructor(
notificationRenderer.render(currentUser, useCompleteNotificationFormat, notifiableEvents)
}
}
fun shouldIgnoreMessageEventInRoom(resolvedEvent: NotifiableMessageEvent): Boolean {
return resolvedEvent.shouldIgnoreEventInRoom(currentAppNavigationState)
}
}

View file

@ -23,7 +23,7 @@ import io.element.android.libraries.push.impl.notifications.model.NotifiableEven
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
import io.element.android.libraries.push.impl.notifications.model.shouldIgnoreEventInRoom
import io.element.android.services.appnavstate.api.AppNavigationState
import io.element.android.services.appnavstate.api.AppNavigationStateService
import timber.log.Timber
import javax.inject.Inject
@ -31,18 +31,19 @@ private typealias ProcessedEvents = List<ProcessedEvent<NotifiableEvent>>
class NotifiableEventProcessor @Inject constructor(
private val outdatedDetector: OutdatedEventDetector,
private val appNavigationStateService: AppNavigationStateService,
) {
fun process(
queuedEvents: List<NotifiableEvent>,
appNavigationState: AppNavigationState?,
renderedEvents: ProcessedEvents,
): ProcessedEvents {
val appState = appNavigationStateService.appNavigationState.value
val processedEvents = queuedEvents.map {
val type = when (it) {
is InviteNotifiableEvent -> ProcessedEvent.Type.KEEP
is NotifiableMessageEvent -> when {
it.shouldIgnoreEventInRoom(appNavigationState) -> {
it.shouldIgnoreEventInRoom(appState) -> {
ProcessedEvent.Type.REMOVE
.also { Timber.d("notification message removed due to currently viewing the same room or thread") }
}
@ -55,7 +56,7 @@ class NotifiableEventProcessor @Inject constructor(
else -> ProcessedEvent.Type.KEEP
}
is FallbackNotifiableEvent -> when {
it.shouldIgnoreEventInRoom(appNavigationState) -> {
it.shouldIgnoreEventInRoom(appState) -> {
ProcessedEvent.Type.REMOVE
.also { Timber.d("notification fallback removed due to currently viewing the same room or thread") }
}

View file

@ -16,8 +16,6 @@
package io.element.android.libraries.push.impl.notifications.model
import android.net.Uri
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
@ -69,18 +67,13 @@ data class NotifiableMessageEvent(
/**
* Used to check if a notification should be ignored based on the current app and navigation state.
*/
fun NotifiableEvent.shouldIgnoreEventInRoom(
appNavigationState: AppNavigationState?
): Boolean {
val currentSessionId = appNavigationState?.currentSessionId() ?: return false
return when (val currentRoomId = appNavigationState.currentRoomId()) {
fun NotifiableEvent.shouldIgnoreEventInRoom(appNavigationState: AppNavigationState): Boolean {
val currentSessionId = appNavigationState.navigationState.currentSessionId() ?: return false
return when (val currentRoomId = appNavigationState.navigationState.currentRoomId()) {
null -> false
else -> isAppInForeground
else -> appNavigationState.isInForeground
&& sessionId == currentSessionId
&& roomId == currentRoomId
&& (this as? NotifiableMessageEvent)?.threadId == appNavigationState.currentThreadId()
&& (this as? NotifiableMessageEvent)?.threadId == appNavigationState.navigationState.currentThreadId()
}
}
private val isAppInForeground: Boolean
get() = ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)

View file

@ -4,7 +4,6 @@
<string name="notification_channel_listening_for_events">"Listening for events"</string>
<string name="notification_channel_noisy">"Noisy notifications"</string>
<string name="notification_channel_silent">"Silent notifications"</string>
<string name="notification_fallback_content">"Notification"</string>
<string name="notification_inline_reply_failed">"** Failed to send - please open room"</string>
<string name="notification_invitation_action_join">"Join"</string>
<string name="notification_invitation_action_reject">"Reject"</string>
@ -48,5 +47,6 @@
<string name="push_distributor_background_sync_android">"Background synchronization"</string>
<string name="push_distributor_firebase_android">"Google Services"</string>
<string name="push_no_valid_google_play_services_apk_android">"No valid Google Play Services found. Notifications may not work properly."</string>
<string name="notification_fallback_content">"Notification"</string>
<string name="notification_room_action_quick_reply">"Quick reply"</string>
</resources>