diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt index ef5267dd59..e01e7acdf3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt @@ -286,7 +286,7 @@ class EventNotificationConsumer( val repliedNote = LocalCache.getNoteIfExists(replyTargetId) if (repliedNote?.author?.pubkeyHex == account.signer.pubKey) { val threadRoot = event.markedRoot()?.eventId ?: event.unmarkedRoot()?.eventId ?: replyTargetId - ReplyNotification.notify(applicationContext, account, event, repliedNote.event?.content, threadRoot) + ReplyNotification.notify(applicationContext, account, event, repliedNote, threadRoot) return } } @@ -301,14 +301,14 @@ class EventNotificationConsumer( val isTarget = event.replyAuthorKeys().contains(pubKey) || event.rootAuthorKeys().contains(pubKey) if (!isTarget) return - val parentContent = event.replyingTo()?.let { LocalCache.getNoteIfExists(it)?.event?.content } + val parentNote = event.replyingTo()?.let { LocalCache.getNoteIfExists(it) } val threadRoot = event.rootEventIds().firstOrNull() ?: event.rootAddressIds().firstOrNull() ?: event.replyingToAddressOrEvent() ?: event.id - ReplyNotification.notify(applicationContext, account, event, parentContent, threadRoot) + ReplyNotification.notify(applicationContext, account, event, parentNote, threadRoot) } private suspend fun notifyChannelMessage( @@ -318,13 +318,9 @@ class EventNotificationConsumer( val note = LocalCache.getNoteIfExists(event.id) ?: return if (NotificationFeedFilter.isNotifiablePublicChatReply(note, account.signer.pubKey)) { - val parentContent = - note.replyTo - ?.lastOrNull() - ?.event - ?.content + val parentNote = note.replyTo?.lastOrNull() val threadRoot = event.channelId() ?: event.id - ReplyNotification.notify(applicationContext, account, event, parentContent, threadRoot) + ReplyNotification.notify(applicationContext, account, event, parentNote, threadRoot) } else { MentionNotification.notify(applicationContext, account, event) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt index a3685e2910..67fed14b67 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt @@ -152,6 +152,13 @@ object NotificationUtils { val senderName: String, val body: String, val pictureUrl: String?, + /** + * True when the parent was authored by the logged-in account, so it is + * attributed to the MessagingStyle `me` Person (avatar + "you") rather than + * shown as a separate participant. False for a third party's note — e.g. a + * reply to someone else's reply in a thread the account started. + */ + val isFromMe: Boolean = false, ) // --------------------------------------------------------------------- @@ -284,13 +291,19 @@ object NotificationUtils { val messagingStyle = NotificationCompat.MessagingStyle(me) if (parent != null) { - val parentAvatar = parent.pictureUrl?.let { loadBitmap(it, applicationContext) }?.let { circleCrop(it) } val parentSender = - Person - .Builder() - .setName(parent.senderName) - .apply { parentAvatar?.let { setIcon(IconCompat.createWithBitmap(it)) } } - .build() + if (parent.isFromMe) { + // The account authored the parent — reuse the `me` Person so it + // renders as self with the account's avatar, not a stranger. + me + } else { + val parentAvatar = parent.pictureUrl?.let { loadBitmap(it, applicationContext) }?.let { circleCrop(it) } + Person + .Builder() + .setName(parent.senderName) + .apply { parentAvatar?.let { setIcon(IconCompat.createWithBitmap(it)) } } + .build() + } messagingStyle.addMessage(parent.body, (time - 1) * 1000, parentSender) } messagingStyle.addMessage(messageBody, time * 1000, sender) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReplyNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReplyNotification.kt index 01bfa0d955..beadc2b4a9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReplyNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReplyNotification.kt @@ -24,6 +24,7 @@ import android.content.Context import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache +import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher @@ -51,7 +52,7 @@ object ReplyNotification { context: Context, account: Account, event: Event, - parentContent: String?, + parentNote: Note?, threadRootId: String, ) { val replyNote = LocalCache.getNoteIfExists(event.id) ?: return @@ -63,17 +64,27 @@ object ReplyNotification { val citedUsers = NotificationContent.resolveMentions(event.content).citedUsers + // The parent may be the account's own note (a direct reply) OR a third + // party's — e.g. someone replying to another reply in a thread the account + // started. Attribute it to whoever actually wrote it, and observe that + // author so their name/avatar fill in like the replier's do. + val parentContent = parentNote?.event?.content + val parentAuthor = parentNote?.author + val parentIsFromMe = parentAuthor?.pubkeyHex == account.signer.pubKey + val observedParentAuthor = parentAuthor?.takeUnless { parentIsFromMe } + val nm = context.notificationManager() NotificationEnricher.enrichAndPost( context = context, account = account, notificationId = event.id, - users = listOf(author) + citedUsers, + users = listOf(author) + citedUsers + listOfNotNull(observedParentAuthor), notes = listOf(replyNote), isComplete = { author.metadataOrNull()?.bestName() != null && - citedUsers.all { it.metadataOrNull()?.bestName() != null } + citedUsers.all { it.metadataOrNull()?.bestName() != null } && + (observedParentAuthor == null || observedParentAuthor.metadataOrNull()?.bestName() != null) }, ) { val user = author.toBestDisplayName() @@ -82,9 +93,15 @@ object ReplyNotification { val parent = parentExcerpt?.let { ParentMessage( - senderName = stringRes(context, R.string.app_notification_me), + senderName = + if (parentIsFromMe || parentAuthor == null) { + stringRes(context, R.string.app_notification_me) + } else { + parentAuthor.toBestDisplayName() + }, body = it, - pictureUrl = account.userProfile().profilePicture(), + pictureUrl = if (parentIsFromMe) account.userProfile().profilePicture() else parentAuthor?.profilePicture(), + isFromMe = parentIsFromMe, ) } nm.postConversation(