Notifications: render current user name and avatar.
This commit is contained in:
parent
c91e8e5050
commit
bc9ec5a28a
6 changed files with 83 additions and 66 deletions
|
|
@ -16,21 +16,21 @@
|
|||
|
||||
package io.element.android.libraries.push.impl.notifications
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import androidx.annotation.WorkerThread
|
||||
import io.element.android.libraries.androidutils.throttler.FirstThrottler
|
||||
import io.element.android.libraries.core.cache.CircularCache
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
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.api.store.PushDataStore
|
||||
import io.element.android.libraries.push.impl.R
|
||||
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.shouldIgnoreMessageEventInRoom
|
||||
|
|
@ -38,6 +38,7 @@ import io.element.android.services.appnavstate.api.AppNavigationState
|
|||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -48,7 +49,6 @@ import javax.inject.Inject
|
|||
*/
|
||||
@SingleIn(AppScope::class)
|
||||
class NotificationDrawerManager @Inject constructor(
|
||||
@ApplicationContext context: Context,
|
||||
private val pushDataStore: PushDataStore,
|
||||
private val notifiableEventProcessor: NotifiableEventProcessor,
|
||||
private val notificationRenderer: NotificationRenderer,
|
||||
|
|
@ -57,6 +57,7 @@ class NotificationDrawerManager @Inject constructor(
|
|||
private val appNavigationStateService: AppNavigationStateService,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val buildMeta: BuildMeta,
|
||||
private val matrixAuthenticationService: MatrixAuthenticationService,
|
||||
) {
|
||||
|
||||
private val handlerThread: HandlerThread = HandlerThread("NotificationDrawerManager", Thread.MIN_PRIORITY)
|
||||
|
|
@ -66,7 +67,6 @@ class NotificationDrawerManager @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 val avatarSize = context.resources.getDimensionPixelSize(R.dimen.profile_avatar_size)
|
||||
private var currentAppNavigationState: AppNavigationState? = null
|
||||
private val firstThrottler = FirstThrottler(200)
|
||||
|
||||
|
|
@ -239,6 +239,7 @@ class NotificationDrawerManager @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun renderEvents(eventsToRender: List<ProcessedEvent<NotifiableEvent>>) {
|
||||
// Group by sessionId
|
||||
val eventsForSessions = eventsToRender.groupBy {
|
||||
|
|
@ -246,17 +247,29 @@ class NotificationDrawerManager @Inject constructor(
|
|||
}
|
||||
|
||||
eventsForSessions.forEach { (sessionId, notifiableEvents) ->
|
||||
// TODO EAx val user = session.getUserOrDefault(session.myUserId)
|
||||
// myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash
|
||||
val myUserDisplayName = "Todo display name" // user.toMatrixItem().getBestName()
|
||||
// TODO EAx avatar URL
|
||||
val myUserAvatarUrl = null // session.contentUrlResolver().resolveThumbnail(
|
||||
// contentUrl = user.avatarUrl,
|
||||
// width = avatarSize,
|
||||
// height = avatarSize,
|
||||
// method = ContentUrlResolver.ThumbnailMethod.SCALE
|
||||
//)
|
||||
notificationRenderer.render(sessionId, myUserDisplayName, myUserAvatarUrl, useCompleteNotificationFormat, notifiableEvents)
|
||||
val currentUser = tryOrNull(
|
||||
onError = { Timber.e(it, "Unable to retrieve info for user ${sessionId.value}") },
|
||||
operation = {
|
||||
runBlocking {
|
||||
val client = matrixAuthenticationService.restoreSession(sessionId).getOrNull()
|
||||
|
||||
// myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash
|
||||
val myUserDisplayName = client?.loadUserDisplayName()?.getOrNull() ?: sessionId.value
|
||||
val userAvatarUrl = client?.loadUserAvatarURLString()?.getOrNull()
|
||||
MatrixUser(
|
||||
userId = sessionId,
|
||||
displayName = myUserDisplayName,
|
||||
avatarUrl = userAvatarUrl
|
||||
)
|
||||
}
|
||||
}
|
||||
) ?: MatrixUser(
|
||||
userId = sessionId,
|
||||
displayName = sessionId.value,
|
||||
avatarUrl = null
|
||||
)
|
||||
|
||||
notificationRenderer.render(currentUser, useCompleteNotificationFormat, notifiableEvents)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package io.element.android.libraries.push.impl.notifications
|
|||
|
||||
import android.app.Notification
|
||||
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.user.MatrixUser
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationFactory
|
||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||
|
|
@ -35,9 +35,7 @@ class NotificationFactory @Inject constructor(
|
|||
) {
|
||||
|
||||
fun Map<RoomId, ProcessedMessageEvents>.toNotifications(
|
||||
sessionId: SessionId,
|
||||
myUserDisplayName: String,
|
||||
myUserAvatarUrl: String?
|
||||
currentUser: MatrixUser,
|
||||
): List<RoomNotification> {
|
||||
return map { (roomId, events) ->
|
||||
when {
|
||||
|
|
@ -45,11 +43,9 @@ class NotificationFactory @Inject constructor(
|
|||
else -> {
|
||||
val messageEvents = events.onlyKeptEvents().filterNot { it.isRedacted }
|
||||
roomGroupMessageCreator.createRoomMessage(
|
||||
sessionId = sessionId,
|
||||
currentUser = currentUser,
|
||||
events = messageEvents,
|
||||
roomId = roomId,
|
||||
userDisplayName = myUserDisplayName,
|
||||
userAvatarUrl = myUserAvatarUrl
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -99,7 +95,7 @@ class NotificationFactory @Inject constructor(
|
|||
}
|
||||
|
||||
fun createSummaryNotification(
|
||||
sessionId: SessionId,
|
||||
currentUser: MatrixUser,
|
||||
roomNotifications: List<RoomNotification>,
|
||||
invitationNotifications: List<OneShotNotification>,
|
||||
simpleNotifications: List<OneShotNotification>,
|
||||
|
|
@ -112,7 +108,7 @@ class NotificationFactory @Inject constructor(
|
|||
roomMeta.isEmpty() && invitationMeta.isEmpty() && simpleMeta.isEmpty() -> SummaryNotification.Removed
|
||||
else -> SummaryNotification.Update(
|
||||
summaryGroupMessageCreator.createSummaryNotification(
|
||||
sessionId = sessionId,
|
||||
currentUser = currentUser,
|
||||
roomNotifications = roomMeta,
|
||||
invitationNotifications = invitationMeta,
|
||||
simpleNotifications = simpleMeta,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package io.element.android.libraries.push.impl.notifications
|
|||
|
||||
import androidx.annotation.WorkerThread
|
||||
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.user.MatrixUser
|
||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||
|
|
@ -34,19 +34,17 @@ class NotificationRenderer @Inject constructor(
|
|||
|
||||
@WorkerThread
|
||||
fun render(
|
||||
sessionId: SessionId,
|
||||
myUserDisplayName: String,
|
||||
myUserAvatarUrl: String?,
|
||||
currentUser: MatrixUser,
|
||||
useCompleteNotificationFormat: Boolean,
|
||||
eventsToProcess: List<ProcessedEvent<NotifiableEvent>>
|
||||
) {
|
||||
val (roomEvents, simpleEvents, invitationEvents) = eventsToProcess.groupByType()
|
||||
with(notificationFactory) {
|
||||
val roomNotifications = roomEvents.toNotifications(sessionId, myUserDisplayName, myUserAvatarUrl)
|
||||
val roomNotifications = roomEvents.toNotifications(currentUser)
|
||||
val invitationNotifications = invitationEvents.toNotifications()
|
||||
val simpleNotifications = simpleEvents.toNotifications()
|
||||
val summaryNotification = createSummaryNotification(
|
||||
sessionId = sessionId,
|
||||
currentUser = currentUser,
|
||||
roomNotifications = roomNotifications,
|
||||
invitationNotifications = invitationNotifications,
|
||||
simpleNotifications = simpleNotifications,
|
||||
|
|
@ -56,21 +54,27 @@ class NotificationRenderer @Inject constructor(
|
|||
// Remove summary first to avoid briefly displaying it after dismissing the last notification
|
||||
if (summaryNotification == SummaryNotification.Removed) {
|
||||
Timber.d("Removing summary notification")
|
||||
notificationDisplayer.cancelNotificationMessage(null, notificationIdProvider.getSummaryNotificationId(sessionId))
|
||||
notificationDisplayer.cancelNotificationMessage(
|
||||
tag = null,
|
||||
id = notificationIdProvider.getSummaryNotificationId(currentUser.userId)
|
||||
)
|
||||
}
|
||||
|
||||
roomNotifications.forEach { wrapper ->
|
||||
when (wrapper) {
|
||||
is RoomNotification.Removed -> {
|
||||
Timber.d("Removing room messages notification ${wrapper.roomId}")
|
||||
notificationDisplayer.cancelNotificationMessage(wrapper.roomId.value, notificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||
notificationDisplayer.cancelNotificationMessage(
|
||||
tag = wrapper.roomId.value,
|
||||
id = notificationIdProvider.getRoomMessagesNotificationId(currentUser.userId)
|
||||
)
|
||||
}
|
||||
is RoomNotification.Message -> if (useCompleteNotificationFormat) {
|
||||
Timber.d("Updating room messages notification ${wrapper.meta.roomId}")
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
wrapper.meta.roomId.value,
|
||||
notificationIdProvider.getRoomMessagesNotificationId(sessionId),
|
||||
wrapper.notification
|
||||
tag = wrapper.meta.roomId.value,
|
||||
id = notificationIdProvider.getRoomMessagesNotificationId(currentUser.userId),
|
||||
notification = wrapper.notification
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -80,14 +84,17 @@ class NotificationRenderer @Inject constructor(
|
|||
when (wrapper) {
|
||||
is OneShotNotification.Removed -> {
|
||||
Timber.d("Removing invitation notification ${wrapper.key}")
|
||||
notificationDisplayer.cancelNotificationMessage(wrapper.key, notificationIdProvider.getRoomInvitationNotificationId(sessionId))
|
||||
notificationDisplayer.cancelNotificationMessage(
|
||||
tag = wrapper.key,
|
||||
id = notificationIdProvider.getRoomInvitationNotificationId(currentUser.userId)
|
||||
)
|
||||
}
|
||||
is OneShotNotification.Append -> if (useCompleteNotificationFormat) {
|
||||
Timber.d("Updating invitation notification ${wrapper.meta.key}")
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
wrapper.meta.key,
|
||||
notificationIdProvider.getRoomInvitationNotificationId(sessionId),
|
||||
wrapper.notification
|
||||
tag = wrapper.meta.key,
|
||||
id = notificationIdProvider.getRoomInvitationNotificationId(currentUser.userId),
|
||||
notification = wrapper.notification
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -97,14 +104,17 @@ class NotificationRenderer @Inject constructor(
|
|||
when (wrapper) {
|
||||
is OneShotNotification.Removed -> {
|
||||
Timber.d("Removing simple notification ${wrapper.key}")
|
||||
notificationDisplayer.cancelNotificationMessage(wrapper.key, notificationIdProvider.getRoomEventNotificationId(sessionId))
|
||||
notificationDisplayer.cancelNotificationMessage(
|
||||
tag = wrapper.key,
|
||||
id = notificationIdProvider.getRoomEventNotificationId(currentUser.userId)
|
||||
)
|
||||
}
|
||||
is OneShotNotification.Append -> if (useCompleteNotificationFormat) {
|
||||
Timber.d("Updating simple notification ${wrapper.meta.key}")
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
wrapper.meta.key,
|
||||
notificationIdProvider.getRoomEventNotificationId(sessionId),
|
||||
wrapper.notification
|
||||
tag = wrapper.meta.key,
|
||||
id = notificationIdProvider.getRoomEventNotificationId(currentUser.userId),
|
||||
notification = wrapper.notification
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -114,9 +124,9 @@ class NotificationRenderer @Inject constructor(
|
|||
if (summaryNotification is SummaryNotification.Update) {
|
||||
Timber.d("Updating summary notification")
|
||||
notificationDisplayer.showNotificationMessage(
|
||||
null,
|
||||
notificationIdProvider.getSummaryNotificationId(sessionId),
|
||||
summaryNotification.notification
|
||||
tag = null,
|
||||
id = notificationIdProvider.getSummaryNotificationId(currentUser.userId),
|
||||
notification = summaryNotification.notification
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import android.graphics.Bitmap
|
|||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.Person
|
||||
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.user.MatrixUser
|
||||
import io.element.android.libraries.push.impl.R
|
||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationFactory
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||
|
|
@ -37,19 +37,17 @@ class RoomGroupMessageCreator @Inject constructor(
|
|||
) {
|
||||
|
||||
fun createRoomMessage(
|
||||
sessionId: SessionId,
|
||||
currentUser: MatrixUser,
|
||||
events: List<NotifiableMessageEvent>,
|
||||
roomId: RoomId,
|
||||
userDisplayName: String,
|
||||
userAvatarUrl: String?
|
||||
): RoomNotification.Message {
|
||||
val lastKnownRoomEvent = events.last()
|
||||
val roomName = lastKnownRoomEvent.roomName ?: lastKnownRoomEvent.senderName ?: "Room name (${roomId.value.take(8)}…)"
|
||||
val roomIsGroup = !lastKnownRoomEvent.roomIsDirect
|
||||
val style = NotificationCompat.MessagingStyle(
|
||||
Person.Builder()
|
||||
.setName(userDisplayName)
|
||||
.setIcon(bitmapLoader.getUserIcon(userAvatarUrl))
|
||||
.setName(currentUser.displayName)
|
||||
.setIcon(bitmapLoader.getUserIcon(currentUser.avatarUrl))
|
||||
.setKey(lastKnownRoomEvent.sessionId.value)
|
||||
.build()
|
||||
).also {
|
||||
|
|
@ -80,7 +78,7 @@ class RoomGroupMessageCreator @Inject constructor(
|
|||
notificationFactory.createMessagesListNotification(
|
||||
style,
|
||||
RoomEventGroupInfo(
|
||||
sessionId = sessionId,
|
||||
sessionId = currentUser.userId,
|
||||
roomId = roomId,
|
||||
roomDisplayName = roomName,
|
||||
isDirect = !roomIsGroup,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package io.element.android.libraries.push.impl.notifications
|
|||
|
||||
import android.app.Notification
|
||||
import androidx.core.app.NotificationCompat
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
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.NotificationFactory
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
|
|
@ -44,7 +44,7 @@ class SummaryGroupMessageCreator @Inject constructor(
|
|||
) {
|
||||
|
||||
fun createSummaryNotification(
|
||||
sessionId: SessionId,
|
||||
currentUser: MatrixUser,
|
||||
roomNotifications: List<RoomNotification.Message.Meta>,
|
||||
invitationNotifications: List<OneShotNotification.Append.Meta>,
|
||||
simpleNotifications: List<OneShotNotification.Append.Meta>,
|
||||
|
|
@ -74,7 +74,7 @@ class SummaryGroupMessageCreator @Inject constructor(
|
|||
.setSummaryText(stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages, nbEvents, nbEvents))
|
||||
return if (useCompleteNotificationFormat) {
|
||||
notificationFactory.createSummaryListNotification(
|
||||
sessionId,
|
||||
currentUser,
|
||||
summaryInboxStyle,
|
||||
sumTitle,
|
||||
noisy = summaryIsNoisy,
|
||||
|
|
@ -82,7 +82,7 @@ class SummaryGroupMessageCreator @Inject constructor(
|
|||
)
|
||||
} else {
|
||||
processSimpleGroupSummary(
|
||||
sessionId,
|
||||
currentUser,
|
||||
summaryIsNoisy,
|
||||
messageCount,
|
||||
simpleNotifications.size,
|
||||
|
|
@ -94,7 +94,7 @@ class SummaryGroupMessageCreator @Inject constructor(
|
|||
}
|
||||
|
||||
private fun processSimpleGroupSummary(
|
||||
sessionId: SessionId,
|
||||
currentUser: MatrixUser,
|
||||
summaryIsNoisy: Boolean,
|
||||
messageEventsCount: Int,
|
||||
simpleEventsCount: Int,
|
||||
|
|
@ -167,7 +167,7 @@ class SummaryGroupMessageCreator @Inject constructor(
|
|||
}
|
||||
}
|
||||
return notificationFactory.createSummaryListNotification(
|
||||
sessionId = sessionId,
|
||||
currentUser = currentUser,
|
||||
style = null,
|
||||
compatSummary = privacyTitle,
|
||||
noisy = summaryIsNoisy,
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.core.content.res.ResourcesCompat
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
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.RoomEventGroupInfo
|
||||
import io.element.android.libraries.push.impl.notifications.channels.NotificationChannels
|
||||
|
|
@ -226,7 +226,7 @@ class NotificationFactory @Inject constructor(
|
|||
* Create the summary notification.
|
||||
*/
|
||||
fun createSummaryListNotification(
|
||||
sessionId: SessionId,
|
||||
currentUser: MatrixUser,
|
||||
style: NotificationCompat.InboxStyle?,
|
||||
compatSummary: String,
|
||||
noisy: Boolean,
|
||||
|
|
@ -240,12 +240,12 @@ class NotificationFactory @Inject constructor(
|
|||
// used in compat < N, after summary is built based on child notifications
|
||||
.setWhen(lastMessageTimestamp)
|
||||
.setStyle(style)
|
||||
.setContentTitle(sessionId.value)
|
||||
.setContentTitle(currentUser.userId.value)
|
||||
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
||||
.setSmallIcon(smallIcon)
|
||||
// set content text to support devices running API level < 24
|
||||
.setContentText(compatSummary)
|
||||
.setGroup(sessionId.value)
|
||||
.setGroup(currentUser.userId.value)
|
||||
// set this notification as the summary for the group
|
||||
.setGroupSummary(true)
|
||||
.setColor(accentColor)
|
||||
|
|
@ -264,8 +264,8 @@ class NotificationFactory @Inject constructor(
|
|||
priority = NotificationCompat.PRIORITY_LOW
|
||||
}
|
||||
}
|
||||
.setContentIntent(pendingIntentFactory.createOpenSessionPendingIntent(sessionId))
|
||||
.setDeleteIntent(pendingIntentFactory.createDismissSummaryPendingIntent(sessionId))
|
||||
.setContentIntent(pendingIntentFactory.createOpenSessionPendingIntent(currentUser.userId))
|
||||
.setDeleteIntent(pendingIntentFactory.createDismissSummaryPendingIntent(currentUser.userId))
|
||||
.build()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue