Merge pull request #5645 from element-hq/feature/bma/mutliAccountNotification
Improve rendering notification for multi account
This commit is contained in:
commit
ba0c659df1
34 changed files with 464 additions and 433 deletions
|
|
@ -7,15 +7,10 @@
|
|||
|
||||
package io.element.android.libraries.push.impl.notifications
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
|
@ -32,11 +27,7 @@ import io.element.android.services.appnavstate.api.AppNavigationStateService
|
|||
import io.element.android.services.appnavstate.api.NavigationState
|
||||
import io.element.android.services.appnavstate.api.currentSessionId
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
private val loggerTag = LoggerTag("DefaultNotificationDrawerManager", LoggerTag.NotificationLoggerTag)
|
||||
|
||||
/**
|
||||
* This class receives notification events as they arrive from the PushHandler calling [onNotifiableEventReceived] and
|
||||
|
|
@ -46,7 +37,7 @@ private val loggerTag = LoggerTag("DefaultNotificationDrawerManager", LoggerTag.
|
|||
@SingleIn(AppScope::class)
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultNotificationDrawerManager(
|
||||
private val notificationManager: NotificationManagerCompat,
|
||||
private val notificationDisplayer: NotificationDisplayer,
|
||||
private val notificationRenderer: NotificationRenderer,
|
||||
private val appNavigationStateService: AppNavigationStateService,
|
||||
@AppCoroutineScope
|
||||
|
|
@ -55,25 +46,17 @@ class DefaultNotificationDrawerManager(
|
|||
private val imageLoaderHolder: ImageLoaderHolder,
|
||||
private val activeNotificationsProvider: ActiveNotificationsProvider,
|
||||
) : NotificationCleaner {
|
||||
private var appNavigationStateObserver: Job? = null
|
||||
|
||||
// TODO EAx add a setting per user for this
|
||||
private var useCompleteNotificationFormat = true
|
||||
|
||||
init {
|
||||
// Observe application state
|
||||
appNavigationStateObserver = coroutineScope.launch {
|
||||
coroutineScope.launch {
|
||||
appNavigationStateService.appNavigationState
|
||||
.collect { onAppNavigationStateChange(it.navigationState) }
|
||||
}
|
||||
}
|
||||
|
||||
// For test only
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
internal fun destroy() {
|
||||
appNavigationStateObserver?.cancel()
|
||||
}
|
||||
|
||||
private var currentAppNavigationState: NavigationState? = null
|
||||
|
||||
private fun onAppNavigationStateChange(navigationState: NavigationState) {
|
||||
|
|
@ -124,7 +107,7 @@ class DefaultNotificationDrawerManager(
|
|||
* Clear all known message events for a [sessionId].
|
||||
*/
|
||||
override fun clearAllMessagesEvents(sessionId: SessionId) {
|
||||
notificationManager.cancel(null, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||
notificationDisplayer.cancelNotification(null, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||
clearSummaryNotificationIfNeeded(sessionId)
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +116,7 @@ class DefaultNotificationDrawerManager(
|
|||
*/
|
||||
fun clearAllEvents(sessionId: SessionId) {
|
||||
activeNotificationsProvider.getNotificationsForSession(sessionId)
|
||||
.forEach { notificationManager.cancel(it.tag, it.id) }
|
||||
.forEach { notificationDisplayer.cancelNotification(it.tag, it.id) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -142,7 +125,7 @@ class DefaultNotificationDrawerManager(
|
|||
* Can also be called when a notification for this room is dismissed by the user.
|
||||
*/
|
||||
override fun clearMessagesForRoom(sessionId: SessionId, roomId: RoomId) {
|
||||
notificationManager.cancel(roomId.value, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||
notificationDisplayer.cancelNotification(roomId.value, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||
clearSummaryNotificationIfNeeded(sessionId)
|
||||
}
|
||||
|
||||
|
|
@ -152,13 +135,13 @@ class DefaultNotificationDrawerManager(
|
|||
*/
|
||||
override fun clearMessagesForThread(sessionId: SessionId, roomId: RoomId, threadId: ThreadId) {
|
||||
val tag = NotificationCreator.messageTag(roomId, threadId)
|
||||
notificationManager.cancel(tag, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||
notificationDisplayer.cancelNotification(tag, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||
clearSummaryNotificationIfNeeded(sessionId)
|
||||
}
|
||||
|
||||
override fun clearMembershipNotificationForSession(sessionId: SessionId) {
|
||||
activeNotificationsProvider.getMembershipNotificationForSession(sessionId)
|
||||
.forEach { notificationManager.cancel(it.tag, it.id) }
|
||||
.forEach { notificationDisplayer.cancelNotification(it.tag, it.id) }
|
||||
clearSummaryNotificationIfNeeded(sessionId)
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +150,7 @@ class DefaultNotificationDrawerManager(
|
|||
*/
|
||||
override fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId) {
|
||||
activeNotificationsProvider.getMembershipNotificationForRoom(sessionId, roomId)
|
||||
.forEach { notificationManager.cancel(it.tag, it.id) }
|
||||
.forEach { notificationDisplayer.cancelNotification(it.tag, it.id) }
|
||||
clearSummaryNotificationIfNeeded(sessionId)
|
||||
}
|
||||
|
||||
|
|
@ -176,14 +159,14 @@ class DefaultNotificationDrawerManager(
|
|||
*/
|
||||
override fun clearEvent(sessionId: SessionId, eventId: EventId) {
|
||||
val id = NotificationIdProvider.getRoomEventNotificationId(sessionId)
|
||||
notificationManager.cancel(eventId.value, id)
|
||||
notificationDisplayer.cancelNotification(eventId.value, id)
|
||||
clearSummaryNotificationIfNeeded(sessionId)
|
||||
}
|
||||
|
||||
private fun clearSummaryNotificationIfNeeded(sessionId: SessionId) {
|
||||
val summaryNotification = activeNotificationsProvider.getSummaryNotification(sessionId)
|
||||
if (summaryNotification != null && activeNotificationsProvider.count(sessionId) == 1) {
|
||||
notificationManager.cancel(null, summaryNotification.id)
|
||||
notificationDisplayer.cancelNotification(null, summaryNotification.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -201,29 +184,9 @@ class DefaultNotificationDrawerManager(
|
|||
// We have an avatar and a display name, use it
|
||||
userFromCache
|
||||
} else {
|
||||
client.getSafeUserProfile()
|
||||
client.getUserProfile().getOrNull() ?: MatrixUser(sessionId)
|
||||
}
|
||||
|
||||
notificationRenderer.render(currentUser, useCompleteNotificationFormat, notifiableEvents, imageLoader)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun MatrixClient.getSafeUserProfile(): MatrixUser {
|
||||
return tryOrNull(
|
||||
onException = { Timber.tag(loggerTag.value).e(it, "Unable to retrieve info for user ${sessionId.value}") },
|
||||
operation = {
|
||||
val profile = getUserProfile().getOrNull()
|
||||
// displayName cannot be empty else NotificationCompat.MessagingStyle() will crash
|
||||
if (profile?.displayName.isNullOrEmpty()) {
|
||||
profile?.copy(displayName = sessionId.value)
|
||||
} else {
|
||||
profile
|
||||
}
|
||||
}
|
||||
) ?: MatrixUser(
|
||||
userId = sessionId,
|
||||
displayName = sessionId.value,
|
||||
avatarUrl = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ package io.element.android.libraries.push.impl.notifications
|
|||
import android.app.Notification
|
||||
import android.graphics.Typeface
|
||||
import android.text.style.StyleSpan
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.inSpans
|
||||
import coil3.ImageLoader
|
||||
|
|
@ -19,8 +18,8 @@ import dev.zacsweers.metro.ContributesBinding
|
|||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.push.impl.R
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||
|
|
@ -31,39 +30,37 @@ import io.element.android.services.toolbox.api.strings.StringProvider
|
|||
interface NotificationDataFactory {
|
||||
suspend fun toNotifications(
|
||||
messages: List<NotifiableMessageEvent>,
|
||||
currentUser: MatrixUser,
|
||||
imageLoader: ImageLoader,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): List<RoomNotification>
|
||||
|
||||
@JvmName("toNotificationInvites")
|
||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||
fun toNotifications(
|
||||
invites: List<InviteNotifiableEvent>,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): List<OneShotNotification>
|
||||
|
||||
@JvmName("toNotificationSimpleEvents")
|
||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||
fun toNotifications(
|
||||
simpleEvents: List<SimpleNotifiableEvent>,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): List<OneShotNotification>
|
||||
|
||||
@JvmName("toNotificationFallbackEvents")
|
||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||
fun toNotifications(
|
||||
fallback: List<FallbackNotifiableEvent>,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): List<OneShotNotification>
|
||||
|
||||
fun createSummaryNotification(
|
||||
currentUser: MatrixUser,
|
||||
roomNotifications: List<RoomNotification>,
|
||||
invitationNotifications: List<OneShotNotification>,
|
||||
simpleNotifications: List<OneShotNotification>,
|
||||
fallbackNotifications: List<OneShotNotification>,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): SummaryNotification
|
||||
}
|
||||
|
||||
|
|
@ -77,9 +74,8 @@ class DefaultNotificationDataFactory(
|
|||
) : NotificationDataFactory {
|
||||
override suspend fun toNotifications(
|
||||
messages: List<NotifiableMessageEvent>,
|
||||
currentUser: MatrixUser,
|
||||
imageLoader: ImageLoader,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): List<RoomNotification> {
|
||||
val messagesToDisplay = messages.filterNot { it.canNotBeDisplayed() }
|
||||
.groupBy { it.roomId }
|
||||
|
|
@ -90,13 +86,12 @@ class DefaultNotificationDataFactory(
|
|||
|
||||
eventsByThreadId.map { (threadId, events) ->
|
||||
val notification = roomGroupMessageCreator.createRoomMessage(
|
||||
currentUser = currentUser,
|
||||
events = events,
|
||||
roomId = roomId,
|
||||
threadId = threadId,
|
||||
imageLoader = imageLoader,
|
||||
existingNotification = getExistingNotificationForMessages(currentUser.userId, roomId, threadId),
|
||||
color = color,
|
||||
existingNotification = getExistingNotificationForMessages(notificationAccountParams.user.userId, roomId, threadId),
|
||||
notificationAccountParams = notificationAccountParams,
|
||||
)
|
||||
RoomNotification(
|
||||
notification = notification,
|
||||
|
|
@ -121,12 +116,12 @@ class DefaultNotificationDataFactory(
|
|||
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||
override fun toNotifications(
|
||||
invites: List<InviteNotifiableEvent>,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): List<OneShotNotification> {
|
||||
return invites.map { event ->
|
||||
OneShotNotification(
|
||||
key = event.roomId.value,
|
||||
notification = notificationCreator.createRoomInvitationNotification(event, color),
|
||||
tag = event.roomId.value,
|
||||
notification = notificationCreator.createRoomInvitationNotification(notificationAccountParams, event),
|
||||
summaryLine = event.description,
|
||||
isNoisy = event.noisy,
|
||||
timestamp = event.timestamp
|
||||
|
|
@ -138,12 +133,12 @@ class DefaultNotificationDataFactory(
|
|||
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||
override fun toNotifications(
|
||||
simpleEvents: List<SimpleNotifiableEvent>,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): List<OneShotNotification> {
|
||||
return simpleEvents.map { event ->
|
||||
OneShotNotification(
|
||||
key = event.eventId.value,
|
||||
notification = notificationCreator.createSimpleEventNotification(event, color),
|
||||
tag = event.eventId.value,
|
||||
notification = notificationCreator.createSimpleEventNotification(notificationAccountParams, event),
|
||||
summaryLine = event.description,
|
||||
isNoisy = event.noisy,
|
||||
timestamp = event.timestamp
|
||||
|
|
@ -155,12 +150,12 @@ class DefaultNotificationDataFactory(
|
|||
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||
override fun toNotifications(
|
||||
fallback: List<FallbackNotifiableEvent>,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): List<OneShotNotification> {
|
||||
return fallback.map { event ->
|
||||
OneShotNotification(
|
||||
key = event.eventId.value,
|
||||
notification = notificationCreator.createFallbackNotification(event, color),
|
||||
tag = event.eventId.value,
|
||||
notification = notificationCreator.createFallbackNotification(notificationAccountParams, event),
|
||||
summaryLine = event.description.orEmpty(),
|
||||
isNoisy = false,
|
||||
timestamp = event.timestamp
|
||||
|
|
@ -169,23 +164,21 @@ class DefaultNotificationDataFactory(
|
|||
}
|
||||
|
||||
override fun createSummaryNotification(
|
||||
currentUser: MatrixUser,
|
||||
roomNotifications: List<RoomNotification>,
|
||||
invitationNotifications: List<OneShotNotification>,
|
||||
simpleNotifications: List<OneShotNotification>,
|
||||
fallbackNotifications: List<OneShotNotification>,
|
||||
@ColorInt color: Int,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
): SummaryNotification {
|
||||
return when {
|
||||
roomNotifications.isEmpty() && invitationNotifications.isEmpty() && simpleNotifications.isEmpty() -> SummaryNotification.Removed
|
||||
else -> SummaryNotification.Update(
|
||||
summaryGroupMessageCreator.createSummaryNotification(
|
||||
currentUser = currentUser,
|
||||
roomNotifications = roomNotifications,
|
||||
invitationNotifications = invitationNotifications,
|
||||
simpleNotifications = simpleNotifications,
|
||||
fallbackNotifications = fallbackNotifications,
|
||||
color = color,
|
||||
notificationAccountParams = notificationAccountParams,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -254,7 +247,7 @@ data class RoomNotification(
|
|||
|
||||
data class OneShotNotification(
|
||||
val notification: Notification,
|
||||
val key: String,
|
||||
val tag: String,
|
||||
val summaryLine: CharSequence,
|
||||
val isNoisy: Boolean,
|
||||
val timestamp: Long,
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import io.element.android.libraries.di.annotations.ApplicationContext
|
|||
import timber.log.Timber
|
||||
|
||||
interface NotificationDisplayer {
|
||||
fun showNotificationMessage(tag: String?, id: Int, notification: Notification): Boolean
|
||||
fun cancelNotificationMessage(tag: String?, id: Int)
|
||||
fun showNotification(tag: String?, id: Int, notification: Notification): Boolean
|
||||
fun cancelNotification(tag: String?, id: Int)
|
||||
fun displayDiagnosticNotification(notification: Notification): Boolean
|
||||
fun dismissDiagnosticNotification()
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ class DefaultNotificationDisplayer(
|
|||
@ApplicationContext private val context: Context,
|
||||
private val notificationManager: NotificationManagerCompat
|
||||
) : NotificationDisplayer {
|
||||
override fun showNotificationMessage(tag: String?, id: Int, notification: Notification): Boolean {
|
||||
override fun showNotification(tag: String?, id: Int, notification: Notification): Boolean {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
Timber.w("Not allowed to notify.")
|
||||
return false
|
||||
|
|
@ -40,26 +40,28 @@ class DefaultNotificationDisplayer(
|
|||
return true
|
||||
}
|
||||
|
||||
override fun cancelNotificationMessage(tag: String?, id: Int) {
|
||||
override fun cancelNotification(tag: String?, id: Int) {
|
||||
notificationManager.cancel(tag, id)
|
||||
}
|
||||
|
||||
override fun displayDiagnosticNotification(notification: Notification): Boolean {
|
||||
return showNotificationMessage(
|
||||
tag = "DIAGNOSTIC",
|
||||
return showNotification(
|
||||
tag = TAG_DIAGNOSTIC,
|
||||
id = NOTIFICATION_ID_DIAGNOSTIC,
|
||||
notification = notification
|
||||
)
|
||||
}
|
||||
|
||||
override fun dismissDiagnosticNotification() {
|
||||
cancelNotificationMessage(
|
||||
tag = "DIAGNOSTIC",
|
||||
cancelNotification(
|
||||
tag = TAG_DIAGNOSTIC,
|
||||
id = NOTIFICATION_ID_DIAGNOSTIC
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG_DIAGNOSTIC = "DIAGNOSTIC"
|
||||
|
||||
/* ==========================================================================================
|
||||
* IDs for notifications
|
||||
* ========================================================================================== */
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import io.element.android.features.enterprise.api.EnterpriseService
|
|||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||
|
|
@ -22,6 +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.NotifiableRingingCallEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import kotlinx.coroutines.flow.first
|
||||
import timber.log.Timber
|
||||
|
||||
|
|
@ -32,6 +34,7 @@ class NotificationRenderer(
|
|||
private val notificationDisplayer: NotificationDisplayer,
|
||||
private val notificationDataFactory: NotificationDataFactory,
|
||||
private val enterpriseService: EnterpriseService,
|
||||
private val sessionStore: SessionStore,
|
||||
) {
|
||||
suspend fun render(
|
||||
currentUser: MatrixUser,
|
||||
|
|
@ -41,24 +44,29 @@ class NotificationRenderer(
|
|||
) {
|
||||
val color = enterpriseService.brandColorsFlow(currentUser.userId).first()?.toArgb()
|
||||
?: NotificationConfig.NOTIFICATION_ACCENT_COLOR
|
||||
val numberOfAccounts = sessionStore.numberOfSessions()
|
||||
val notificationAccountParams = NotificationAccountParams(
|
||||
user = currentUser,
|
||||
color = color,
|
||||
showSessionId = numberOfAccounts > 1,
|
||||
)
|
||||
val groupedEvents = eventsToProcess.groupByType()
|
||||
val roomNotifications = notificationDataFactory.toNotifications(groupedEvents.roomEvents, currentUser, imageLoader, color)
|
||||
val invitationNotifications = notificationDataFactory.toNotifications(groupedEvents.invitationEvents, color)
|
||||
val simpleNotifications = notificationDataFactory.toNotifications(groupedEvents.simpleEvents, color)
|
||||
val fallbackNotifications = notificationDataFactory.toNotifications(groupedEvents.fallbackEvents, color)
|
||||
val roomNotifications = notificationDataFactory.toNotifications(groupedEvents.roomEvents, imageLoader, notificationAccountParams)
|
||||
val invitationNotifications = notificationDataFactory.toNotifications(groupedEvents.invitationEvents, notificationAccountParams)
|
||||
val simpleNotifications = notificationDataFactory.toNotifications(groupedEvents.simpleEvents, notificationAccountParams)
|
||||
val fallbackNotifications = notificationDataFactory.toNotifications(groupedEvents.fallbackEvents, notificationAccountParams)
|
||||
val summaryNotification = notificationDataFactory.createSummaryNotification(
|
||||
currentUser = currentUser,
|
||||
roomNotifications = roomNotifications,
|
||||
invitationNotifications = invitationNotifications,
|
||||
simpleNotifications = simpleNotifications,
|
||||
fallbackNotifications = fallbackNotifications,
|
||||
color = color,
|
||||
notificationAccountParams = notificationAccountParams,
|
||||
)
|
||||
|
||||
// Remove summary first to avoid briefly displaying it after dismissing the last notification
|
||||
if (summaryNotification == SummaryNotification.Removed) {
|
||||
Timber.tag(loggerTag.value).d("Removing summary notification")
|
||||
notificationDisplayer.cancelNotificationMessage(
|
||||
notificationDisplayer.cancelNotification(
|
||||
tag = null,
|
||||
id = NotificationIdProvider.getSummaryNotificationId(currentUser.userId)
|
||||
)
|
||||
|
|
@ -69,7 +77,7 @@ class NotificationRenderer(
|
|||
roomId = notificationData.roomId,
|
||||
threadId = notificationData.threadId
|
||||
)
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
notificationDisplayer.showNotification(
|
||||
tag = tag,
|
||||
id = NotificationIdProvider.getRoomMessagesNotificationId(currentUser.userId),
|
||||
notification = notificationData.notification
|
||||
|
|
@ -78,9 +86,9 @@ class NotificationRenderer(
|
|||
|
||||
invitationNotifications.forEach { notificationData ->
|
||||
if (useCompleteNotificationFormat) {
|
||||
Timber.tag(loggerTag.value).d("Updating invitation notification ${notificationData.key}")
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
tag = notificationData.key,
|
||||
Timber.tag(loggerTag.value).d("Updating invitation notification ${notificationData.tag}")
|
||||
notificationDisplayer.showNotification(
|
||||
tag = notificationData.tag,
|
||||
id = NotificationIdProvider.getRoomInvitationNotificationId(currentUser.userId),
|
||||
notification = notificationData.notification
|
||||
)
|
||||
|
|
@ -89,9 +97,9 @@ class NotificationRenderer(
|
|||
|
||||
simpleNotifications.forEach { notificationData ->
|
||||
if (useCompleteNotificationFormat) {
|
||||
Timber.tag(loggerTag.value).d("Updating simple notification ${notificationData.key}")
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
tag = notificationData.key,
|
||||
Timber.tag(loggerTag.value).d("Updating simple notification ${notificationData.tag}")
|
||||
notificationDisplayer.showNotification(
|
||||
tag = notificationData.tag,
|
||||
id = NotificationIdProvider.getRoomEventNotificationId(currentUser.userId),
|
||||
notification = notificationData.notification
|
||||
)
|
||||
|
|
@ -101,7 +109,7 @@ class NotificationRenderer(
|
|||
// Show only the first fallback notification
|
||||
if (fallbackNotifications.isNotEmpty()) {
|
||||
Timber.tag(loggerTag.value).d("Showing fallback notification")
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
notificationDisplayer.showNotification(
|
||||
tag = "FALLBACK",
|
||||
id = NotificationIdProvider.getFallbackNotificationId(currentUser.userId),
|
||||
notification = fallbackNotifications.first().notification
|
||||
|
|
@ -111,7 +119,7 @@ class NotificationRenderer(
|
|||
// Update summary last to avoid briefly displaying it before other notifications
|
||||
if (summaryNotification is SummaryNotification.Update) {
|
||||
Timber.tag(loggerTag.value).d("Updating summary notification")
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
notificationDisplayer.showNotification(
|
||||
tag = null,
|
||||
id = NotificationIdProvider.getSummaryNotificationId(currentUser.userId),
|
||||
notification = summaryNotification.notification
|
||||
|
|
|
|||
|
|
@ -9,15 +9,14 @@ package io.element.android.libraries.push.impl.notifications
|
|||
|
||||
import android.app.Notification
|
||||
import android.graphics.Bitmap
|
||||
import androidx.annotation.ColorInt
|
||||
import coil3.ImageLoader
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader
|
||||
import io.element.android.libraries.push.impl.R
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||
import io.element.android.libraries.push.impl.notifications.factories.isSmartReplyError
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||
|
|
@ -25,13 +24,12 @@ import io.element.android.services.toolbox.api.strings.StringProvider
|
|||
|
||||
interface RoomGroupMessageCreator {
|
||||
suspend fun createRoomMessage(
|
||||
currentUser: MatrixUser,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
events: List<NotifiableMessageEvent>,
|
||||
roomId: RoomId,
|
||||
threadId: ThreadId?,
|
||||
imageLoader: ImageLoader,
|
||||
existingNotification: Notification?,
|
||||
@ColorInt color: Int,
|
||||
): Notification
|
||||
}
|
||||
|
||||
|
|
@ -42,13 +40,12 @@ class DefaultRoomGroupMessageCreator(
|
|||
private val notificationCreator: NotificationCreator,
|
||||
) : RoomGroupMessageCreator {
|
||||
override suspend fun createRoomMessage(
|
||||
currentUser: MatrixUser,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
events: List<NotifiableMessageEvent>,
|
||||
roomId: RoomId,
|
||||
threadId: ThreadId?,
|
||||
imageLoader: ImageLoader,
|
||||
existingNotification: Notification?,
|
||||
@ColorInt color: Int,
|
||||
): Notification {
|
||||
val lastKnownRoomEvent = events.last()
|
||||
val roomName = lastKnownRoomEvent.roomName ?: lastKnownRoomEvent.senderDisambiguatedDisplayName ?: "Room name (${roomId.value.take(8)}…)"
|
||||
|
|
@ -66,8 +63,9 @@ class DefaultRoomGroupMessageCreator(
|
|||
val smartReplyErrors = events.filter { it.isSmartReplyError() }
|
||||
val roomIsDm = !roomIsGroup
|
||||
return notificationCreator.createMessagesListNotification(
|
||||
notificationAccountParams = notificationAccountParams,
|
||||
RoomEventGroupInfo(
|
||||
sessionId = currentUser.userId,
|
||||
sessionId = notificationAccountParams.user.userId,
|
||||
roomId = roomId,
|
||||
roomDisplayName = roomName,
|
||||
isDm = roomIsDm,
|
||||
|
|
@ -80,11 +78,9 @@ class DefaultRoomGroupMessageCreator(
|
|||
largeIcon = largeBitmap,
|
||||
lastMessageTimestamp = lastMessageTimestamp,
|
||||
tickerText = tickerText,
|
||||
currentUser = currentUser,
|
||||
existingNotification = existingNotification,
|
||||
imageLoader = imageLoader,
|
||||
events = events,
|
||||
color = color,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,22 +8,20 @@
|
|||
package io.element.android.libraries.push.impl.notifications
|
||||
|
||||
import android.app.Notification
|
||||
import androidx.annotation.ColorInt
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.push.impl.R
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
|
||||
interface SummaryGroupMessageCreator {
|
||||
fun createSummaryNotification(
|
||||
currentUser: MatrixUser,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
roomNotifications: List<RoomNotification>,
|
||||
invitationNotifications: List<OneShotNotification>,
|
||||
simpleNotifications: List<OneShotNotification>,
|
||||
fallbackNotifications: List<OneShotNotification>,
|
||||
@ColorInt color: Int,
|
||||
): Notification
|
||||
}
|
||||
|
||||
|
|
@ -42,30 +40,25 @@ class DefaultSummaryGroupMessageCreator(
|
|||
private val notificationCreator: NotificationCreator,
|
||||
) : SummaryGroupMessageCreator {
|
||||
override fun createSummaryNotification(
|
||||
currentUser: MatrixUser,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
roomNotifications: List<RoomNotification>,
|
||||
invitationNotifications: List<OneShotNotification>,
|
||||
simpleNotifications: List<OneShotNotification>,
|
||||
fallbackNotifications: List<OneShotNotification>,
|
||||
@ColorInt color: Int,
|
||||
): Notification {
|
||||
val summaryIsNoisy = roomNotifications.any { it.shouldBing } ||
|
||||
invitationNotifications.any { it.isNoisy } ||
|
||||
simpleNotifications.any { it.isNoisy }
|
||||
|
||||
val lastMessageTimestamp = roomNotifications.lastOrNull()?.latestTimestamp
|
||||
?: invitationNotifications.lastOrNull()?.timestamp
|
||||
?: simpleNotifications.last().timestamp
|
||||
|
||||
// FIXME roomIdToEventMap.size is not correct, this is the number of rooms
|
||||
val nbEvents = roomNotifications.size + simpleNotifications.size
|
||||
val nbEvents = roomNotifications.size + invitationNotifications.size + simpleNotifications.size
|
||||
val sumTitle = stringProvider.getQuantityString(R.plurals.notification_compat_summary_title, nbEvents, nbEvents)
|
||||
return notificationCreator.createSummaryListNotification(
|
||||
currentUser,
|
||||
notificationAccountParams = notificationAccountParams,
|
||||
sumTitle,
|
||||
noisy = summaryIsNoisy,
|
||||
lastMessageTimestamp = lastMessageTimestamp,
|
||||
color = color,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.notifications.factories
|
||||
|
||||
import androidx.annotation.ColorInt
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
||||
data class NotificationAccountParams(
|
||||
val user: MatrixUser,
|
||||
@ColorInt val color: Int,
|
||||
val showSessionId: Boolean,
|
||||
)
|
||||
|
|
@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
|||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||
import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader
|
||||
import io.element.android.libraries.push.impl.R
|
||||
import io.element.android.libraries.push.impl.notifications.RoomEventGroupInfo
|
||||
|
|
@ -47,42 +48,40 @@ interface NotificationCreator {
|
|||
* Create a notification for a Room.
|
||||
*/
|
||||
suspend fun createMessagesListNotification(
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
roomInfo: RoomEventGroupInfo,
|
||||
threadId: ThreadId?,
|
||||
largeIcon: Bitmap?,
|
||||
lastMessageTimestamp: Long,
|
||||
tickerText: String,
|
||||
currentUser: MatrixUser,
|
||||
existingNotification: Notification?,
|
||||
imageLoader: ImageLoader,
|
||||
events: List<NotifiableMessageEvent>,
|
||||
@ColorInt color: Int,
|
||||
): Notification
|
||||
|
||||
fun createRoomInvitationNotification(
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
inviteNotifiableEvent: InviteNotifiableEvent,
|
||||
@ColorInt color: Int,
|
||||
): Notification
|
||||
|
||||
fun createSimpleEventNotification(
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
simpleNotifiableEvent: SimpleNotifiableEvent,
|
||||
@ColorInt color: Int,
|
||||
): Notification
|
||||
|
||||
fun createFallbackNotification(
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
fallbackNotifiableEvent: FallbackNotifiableEvent,
|
||||
@ColorInt color: Int,
|
||||
): Notification
|
||||
|
||||
/**
|
||||
* Create the summary notification.
|
||||
*/
|
||||
fun createSummaryListNotification(
|
||||
currentUser: MatrixUser,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
compatSummary: String,
|
||||
noisy: Boolean,
|
||||
lastMessageTimestamp: Long,
|
||||
@ColorInt color: Int,
|
||||
): Notification
|
||||
|
||||
fun createDiagnosticNotification(
|
||||
|
|
@ -118,16 +117,15 @@ class DefaultNotificationCreator(
|
|||
* Create a notification for a Room.
|
||||
*/
|
||||
override suspend fun createMessagesListNotification(
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
roomInfo: RoomEventGroupInfo,
|
||||
threadId: ThreadId?,
|
||||
largeIcon: Bitmap?,
|
||||
lastMessageTimestamp: Long,
|
||||
tickerText: String,
|
||||
currentUser: MatrixUser,
|
||||
existingNotification: Notification?,
|
||||
imageLoader: ImageLoader,
|
||||
events: List<NotifiableMessageEvent>,
|
||||
@ColorInt color: Int,
|
||||
): Notification {
|
||||
// Build the pending intent for when the notification is clicked
|
||||
val eventId = events.firstOrNull()?.eventId
|
||||
|
|
@ -135,7 +133,6 @@ class DefaultNotificationCreator(
|
|||
threadId != null -> pendingIntentFactory.createOpenThreadPendingIntent(roomInfo.sessionId, roomInfo.roomId, eventId, threadId)
|
||||
else -> pendingIntentFactory.createOpenRoomPendingIntent(roomInfo.sessionId, roomInfo.roomId, eventId)
|
||||
}
|
||||
val smallIcon = CommonDrawables.ic_notification
|
||||
val containsMissedCall = events.any { it.type == EventType.RTC_NOTIFICATION }
|
||||
val channelId = if (containsMissedCall) {
|
||||
notificationChannels.getChannelForIncomingCall(false)
|
||||
|
|
@ -159,9 +156,6 @@ class DefaultNotificationCreator(
|
|||
setShortcutId(createShortcutId(roomInfo.sessionId, roomInfo.roomId))
|
||||
}
|
||||
}
|
||||
// Auto-bundling is enabled for 4 or more notifications on API 24+ (N+)
|
||||
// devices and all Wear devices. But we want a custom grouping, so we specify the groupID
|
||||
.setGroup(roomInfo.sessionId.value)
|
||||
.setGroupSummary(false)
|
||||
// In order to avoid notification making sound twice (due to the summary notification)
|
||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
|
||||
|
|
@ -171,8 +165,8 @@ class DefaultNotificationCreator(
|
|||
|
||||
val messagingStyle = existingNotification?.let {
|
||||
MessagingStyle.extractMessagingStyleFromNotification(it)
|
||||
} ?: messagingStyleFromCurrentUser(
|
||||
user = currentUser,
|
||||
} ?: createMessagingStyleFromCurrentUser(
|
||||
user = notificationAccountParams.user,
|
||||
imageLoader = imageLoader,
|
||||
roomName = roomInfo.roomDisplayName,
|
||||
isThread = threadId != null,
|
||||
|
|
@ -187,9 +181,7 @@ class DefaultNotificationCreator(
|
|||
.setWhen(lastMessageTimestamp)
|
||||
// MESSAGING_STYLE sets title and content for API 16 and above devices.
|
||||
.setStyle(messagingStyle)
|
||||
.setSmallIcon(smallIcon)
|
||||
// Set primary color (important for Wear 2.0 Notifications).
|
||||
.setColor(color)
|
||||
.configureWith(notificationAccountParams)
|
||||
// Sets priority for 25 and below. For 26 and above, 'priority' is deprecated for
|
||||
// 'importance' which is set in the NotificationChannel. The integers representing
|
||||
// 'priority' are different from 'importance', so make sure you don't mix them.
|
||||
|
|
@ -202,7 +194,7 @@ class DefaultNotificationCreator(
|
|||
setSound(it)
|
||||
}
|
||||
*/
|
||||
setLights(color, 500, 500)
|
||||
setLights(notificationAccountParams.color, 500, 500)
|
||||
} else {
|
||||
priority = NotificationCompat.PRIORITY_LOW
|
||||
}
|
||||
|
|
@ -234,19 +226,16 @@ class DefaultNotificationCreator(
|
|||
}
|
||||
|
||||
override fun createRoomInvitationNotification(
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
inviteNotifiableEvent: InviteNotifiableEvent,
|
||||
@ColorInt color: Int,
|
||||
): Notification {
|
||||
val smallIcon = CommonDrawables.ic_notification
|
||||
val channelId = notificationChannels.getChannelIdForMessage(inviteNotifiableEvent.noisy)
|
||||
return NotificationCompat.Builder(context, channelId)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setContentTitle((inviteNotifiableEvent.roomName ?: buildMeta.applicationName).annotateForDebug(5))
|
||||
.setContentText(inviteNotifiableEvent.description.annotateForDebug(6))
|
||||
.setGroup(inviteNotifiableEvent.sessionId.value)
|
||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
|
||||
.setSmallIcon(smallIcon)
|
||||
.setColor(color)
|
||||
.configureWith(notificationAccountParams)
|
||||
.apply {
|
||||
addAction(rejectInvitationActionFactory.create(inviteNotifiableEvent))
|
||||
addAction(acceptInvitationActionFactory.create(inviteNotifiableEvent))
|
||||
|
|
@ -261,7 +250,7 @@ class DefaultNotificationCreator(
|
|||
setSound(it)
|
||||
}
|
||||
*/
|
||||
setLights(color, 500, 500)
|
||||
setLights(notificationAccountParams.color, 500, 500)
|
||||
} else {
|
||||
priority = NotificationCompat.PRIORITY_LOW
|
||||
}
|
||||
|
|
@ -277,19 +266,16 @@ class DefaultNotificationCreator(
|
|||
}
|
||||
|
||||
override fun createSimpleEventNotification(
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
simpleNotifiableEvent: SimpleNotifiableEvent,
|
||||
@ColorInt color: Int,
|
||||
): Notification {
|
||||
val smallIcon = CommonDrawables.ic_notification
|
||||
val channelId = notificationChannels.getChannelIdForMessage(simpleNotifiableEvent.noisy)
|
||||
return NotificationCompat.Builder(context, channelId)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setContentTitle(buildMeta.applicationName.annotateForDebug(7))
|
||||
.setContentText(simpleNotifiableEvent.description.annotateForDebug(8))
|
||||
.setGroup(simpleNotifiableEvent.sessionId.value)
|
||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
|
||||
.setSmallIcon(smallIcon)
|
||||
.setColor(color)
|
||||
.configureWith(notificationAccountParams)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntentFactory.createOpenRoomPendingIntent(simpleNotifiableEvent.sessionId, simpleNotifiableEvent.roomId, null))
|
||||
.apply {
|
||||
|
|
@ -301,7 +287,7 @@ class DefaultNotificationCreator(
|
|||
setSound(it)
|
||||
}
|
||||
*/
|
||||
setLights(color, 500, 500)
|
||||
setLights(notificationAccountParams.color, 500, 500)
|
||||
} else {
|
||||
priority = NotificationCompat.PRIORITY_LOW
|
||||
}
|
||||
|
|
@ -310,19 +296,16 @@ class DefaultNotificationCreator(
|
|||
}
|
||||
|
||||
override fun createFallbackNotification(
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
fallbackNotifiableEvent: FallbackNotifiableEvent,
|
||||
@ColorInt color: Int,
|
||||
): Notification {
|
||||
val smallIcon = CommonDrawables.ic_notification
|
||||
val channelId = notificationChannels.getChannelIdForMessage(false)
|
||||
return NotificationCompat.Builder(context, channelId)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setContentTitle(buildMeta.applicationName.annotateForDebug(7))
|
||||
.setContentText(fallbackNotifiableEvent.description.orEmpty().annotateForDebug(8))
|
||||
.setGroup(fallbackNotifiableEvent.sessionId.value)
|
||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
|
||||
.setSmallIcon(smallIcon)
|
||||
.setColor(color)
|
||||
.configureWith(notificationAccountParams)
|
||||
.setAutoCancel(true)
|
||||
.setWhen(fallbackNotifiableEvent.timestamp)
|
||||
// Ideally we'd use `createOpenRoomPendingIntent` here, but the broken notification might apply to an invite
|
||||
|
|
@ -343,24 +326,21 @@ class DefaultNotificationCreator(
|
|||
* Create the summary notification.
|
||||
*/
|
||||
override fun createSummaryListNotification(
|
||||
currentUser: MatrixUser,
|
||||
notificationAccountParams: NotificationAccountParams,
|
||||
compatSummary: String,
|
||||
noisy: Boolean,
|
||||
lastMessageTimestamp: Long,
|
||||
@ColorInt color: Int,
|
||||
): Notification {
|
||||
val smallIcon = CommonDrawables.ic_notification
|
||||
val channelId = notificationChannels.getChannelIdForMessage(noisy)
|
||||
val userId = notificationAccountParams.user.userId
|
||||
return NotificationCompat.Builder(context, channelId)
|
||||
.setOnlyAlertOnce(true)
|
||||
// used in compat < N, after summary is built based on child notifications
|
||||
.setWhen(lastMessageTimestamp)
|
||||
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
||||
.setSmallIcon(smallIcon)
|
||||
.setGroup(currentUser.userId.value)
|
||||
// set this notification as the summary for the group
|
||||
.setGroupSummary(true)
|
||||
.setColor(color)
|
||||
.configureWith(notificationAccountParams)
|
||||
.apply {
|
||||
if (noisy) {
|
||||
// Compat
|
||||
|
|
@ -370,14 +350,14 @@ class DefaultNotificationCreator(
|
|||
setSound(it)
|
||||
}
|
||||
*/
|
||||
setLights(color, 500, 500)
|
||||
setLights(notificationAccountParams.color, 500, 500)
|
||||
} else {
|
||||
// compat
|
||||
priority = NotificationCompat.PRIORITY_LOW
|
||||
}
|
||||
}
|
||||
.setContentIntent(pendingIntentFactory.createOpenSessionPendingIntent(currentUser.userId))
|
||||
.setDeleteIntent(pendingIntentFactory.createDismissSummaryPendingIntent(currentUser.userId))
|
||||
.setContentIntent(pendingIntentFactory.createOpenSessionPendingIntent(userId))
|
||||
.setDeleteIntent(pendingIntentFactory.createDismissSummaryPendingIntent(userId))
|
||||
.build()
|
||||
}
|
||||
|
||||
|
|
@ -468,7 +448,7 @@ class DefaultNotificationCreator(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun messagingStyleFromCurrentUser(
|
||||
private suspend fun createMessagingStyleFromCurrentUser(
|
||||
user: MatrixUser,
|
||||
imageLoader: ImageLoader,
|
||||
roomName: String,
|
||||
|
|
@ -477,7 +457,8 @@ class DefaultNotificationCreator(
|
|||
): MessagingStyle {
|
||||
return MessagingStyle(
|
||||
Person.Builder()
|
||||
.setName(user.displayName?.annotateForDebug(50))
|
||||
// Note: name cannot be empty else NotificationCompat.MessagingStyle() will crash
|
||||
.setName(user.getBestName().annotateForDebug(50))
|
||||
.setIcon(bitmapLoader.getUserIcon(user.avatarUrl, imageLoader))
|
||||
.setKey(user.userId.value)
|
||||
.build()
|
||||
|
|
@ -497,4 +478,13 @@ class DefaultNotificationCreator(
|
|||
}
|
||||
}
|
||||
|
||||
private fun NotificationCompat.Builder.configureWith(notificationAccountParams: NotificationAccountParams) = apply {
|
||||
setSmallIcon(CommonDrawables.ic_notification)
|
||||
setColor(notificationAccountParams.color)
|
||||
setGroup(notificationAccountParams.user.userId.value)
|
||||
if (notificationAccountParams.showSessionId) {
|
||||
setSubText(notificationAccountParams.user.userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
fun NotifiableMessageEvent.isSmartReplyError() = outGoingMessage && outGoingMessageFailed
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class DefaultOnRedactedEventReceived(
|
|||
oldMessage.person
|
||||
)
|
||||
messagingStyle.messages[messageToRedactIndex] = newMessage
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
notificationDisplayer.showNotification(
|
||||
statusBarNotification.tag,
|
||||
statusBarNotification.id,
|
||||
NotificationCompat.Builder(context, notification)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue