Skip to content

Commit 1c037e5

Browse files
committed
Show avatars on message notifications
1 parent a97a062 commit 1c037e5

13 files changed

Lines changed: 78 additions & 32 deletions

legacy/common/src/main/java/com/fsck/k9/notification/K9NotificationResourceProvider.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
package com.fsck.k9.notification
22

33
import android.content.Context
4+
import android.graphics.Bitmap
45
import app.k9mail.core.ui.legacy.designsystem.atom.icon.Icons
6+
import com.fsck.k9.activity.misc.ContactPicture
7+
import com.fsck.k9.mail.Address
58
import com.fsck.k9.ui.R
9+
import com.fsck.k9.view.RecipientSelectView
10+
import kotlinx.coroutines.Dispatchers
11+
import kotlinx.coroutines.withContext
612

713
class K9NotificationResourceProvider(private val context: Context) : NotificationResourceProvider {
814
override val iconWarning: Int = Icons.Outlined.Warning
@@ -38,6 +44,10 @@ class K9NotificationResourceProvider(private val context: Context) : Notificatio
3844
override fun authenticationErrorBody(accountName: String): String =
3945
context.getString(R.string.notification_authentication_error_text, accountName)
4046

47+
override suspend fun avatar(address: Address): Bitmap? = withContext(Dispatchers.IO) {
48+
ContactPicture.getContactPictureLoader().getContactPicture(RecipientSelectView.Recipient(address))
49+
}
50+
4151
override fun notifyErrorTitle(): String = context.getString(R.string.notification_notify_error_title)
4252

4353
override fun notifyErrorText(): String = context.getString(R.string.notification_notify_error_text)

legacy/core/src/main/java/com/fsck/k9/notification/CoreNotificationKoinModule.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.content.Context
55
import androidx.core.app.NotificationManagerCompat
66
import java.util.concurrent.Executors
77
import kotlin.time.ExperimentalTime
8+
import org.koin.android.ext.koin.androidApplication
89
import org.koin.dsl.module
910

1011
val coreNotificationModule = module {
@@ -111,6 +112,7 @@ val coreNotificationModule = module {
111112
actionCreator = get(),
112113
resourceProvider = get(),
113114
lockScreenNotificationCreator = get(),
115+
application = androidApplication(),
114116
)
115117
}
116118
factory {

legacy/core/src/main/java/com/fsck/k9/notification/NotificationContent.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package com.fsck.k9.notification
22

33
import app.k9mail.legacy.message.controller.MessageReference
4+
import com.fsck.k9.mail.Address
45

56
internal data class NotificationContent(
67
val messageReference: MessageReference,
7-
val sender: String,
8+
val sender: Address,
89
val subject: String,
910
val preview: CharSequence,
1011
val summary: CharSequence,

legacy/core/src/main/java/com/fsck/k9/notification/NotificationContentCreator.kt

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.text.SpannableStringBuilder
44
import app.k9mail.core.android.common.contact.ContactRepository
55
import app.k9mail.legacy.message.extractors.PreviewResult.PreviewType
66
import com.fsck.k9.helper.MessageHelper
7+
import com.fsck.k9.mail.Address
78
import com.fsck.k9.mail.Message
89
import com.fsck.k9.mailstore.LocalMessage
910
import net.thunderbird.core.android.account.LegacyAccountDto
@@ -19,10 +20,10 @@ internal class NotificationContentCreator(
1920

2021
return NotificationContent(
2122
messageReference = message.makeMessageReference(),
22-
sender = getMessageSenderForDisplay(sender),
23+
sender = sender,
2324
subject = getMessageSubject(message),
2425
preview = getMessagePreview(message),
25-
summary = buildMessageSummary(sender, getMessageSubject(message)),
26+
summary = buildMessageSummary(sender.personal, getMessageSubject(message)),
2627
)
2728
}
2829

@@ -70,7 +71,7 @@ internal class NotificationContentCreator(
7071
}
7172

7273
@Suppress("ReturnCount")
73-
private fun getMessageSender(account: LegacyAccountDto, message: Message): String? {
74+
private fun getMessageSender(account: LegacyAccountDto, message: Message): Address {
7475
val messageListPreferences = messageListPreferencesManager.getConfig()
7576
val localContactRepository = if (messageListPreferences.isShowContactName) contactRepository else null
7677
var isSelf = false
@@ -79,20 +80,23 @@ internal class NotificationContentCreator(
7980
if (!fromAddresses.isNullOrEmpty()) {
8081
isSelf = account.isAnIdentity(fromAddresses)
8182
if (!isSelf) {
82-
return MessageHelper.toFriendly(
83-
fromAddresses.first(),
83+
val firstFrom = fromAddresses.first()
84+
val personal = MessageHelper.toFriendly(
85+
firstFrom,
8486
messageListPreferences.isShowCorrespondentNames,
8587
messageListPreferences.isChangeContactNameColor,
8688
messageListPreferences.contactNameColor,
8789
localContactRepository,
8890
).toString()
91+
return Address(firstFrom.address, personal)
8992
}
9093
}
9194

9295
if (isSelf) {
9396
// show To: if the message was sent from me
9497
val recipients = message.getRecipients(Message.RecipientType.TO)
9598
if (!recipients.isNullOrEmpty()) {
99+
val firstRecipient = recipients.first()
96100
val recipientDisplayName = MessageHelper.toFriendly(
97101
address = recipients.first(),
98102
isShowCorrespondentNames = messageListPreferences
@@ -102,14 +106,11 @@ internal class NotificationContentCreator(
102106
contactNameColor = messageListPreferences.contactNameColor,
103107
contactRepository = localContactRepository,
104108
).toString()
105-
return resourceProvider.recipientDisplayName(recipientDisplayName)
109+
val personal = resourceProvider.recipientDisplayName(recipientDisplayName)
110+
return Address(firstRecipient.address, personal)
106111
}
107112
}
108113

109-
return null
110-
}
111-
112-
private fun getMessageSenderForDisplay(sender: String?): String {
113-
return sender ?: resourceProvider.noSender()
114+
return Address("no.sender@example.com", resourceProvider.noSender())
114115
}
115116
}

legacy/core/src/main/java/com/fsck/k9/notification/NotificationResourceProvider.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.fsck.k9.notification
22

3+
import android.graphics.Bitmap
4+
import com.fsck.k9.mail.Address
5+
36
interface NotificationResourceProvider {
47
val iconWarning: Int
58
val iconMarkAsRead: Int
@@ -25,6 +28,8 @@ interface NotificationResourceProvider {
2528
fun authenticationErrorTitle(): String
2629
fun authenticationErrorBody(accountName: String): String
2730

31+
suspend fun avatar(address: Address): Bitmap?
32+
2833
fun notifyErrorTitle(): String
2934
fun notifyErrorText(): String
3035

legacy/core/src/main/java/com/fsck/k9/notification/SingleMessageNotificationCreator.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
package com.fsck.k9.notification
22

3+
import android.app.Application
34
import androidx.core.app.NotificationCompat
45
import androidx.core.app.NotificationCompat.WearableExtender
6+
import androidx.core.graphics.drawable.IconCompat
57
import com.fsck.k9.notification.NotificationChannelManager.ChannelType
8+
import kotlinx.coroutines.CoroutineScope
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.SupervisorJob
11+
import kotlinx.coroutines.launch
612
import net.thunderbird.core.logging.legacy.Log
713
import androidx.core.app.NotificationCompat.Builder as NotificationBuilder
814

@@ -11,12 +17,15 @@ internal class SingleMessageNotificationCreator(
1117
private val actionCreator: NotificationActionCreator,
1218
private val resourceProvider: NotificationResourceProvider,
1319
private val lockScreenNotificationCreator: LockScreenNotificationCreator,
20+
private val application: Application,
1421
) {
22+
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
23+
1524
fun createSingleNotification(
1625
baseNotificationData: BaseNotificationData,
1726
singleNotificationData: SingleNotificationData,
1827
isGroupSummary: Boolean = false,
19-
) {
28+
) = scope.launch {
2029
val account = baseNotificationData.account
2130
val notificationId = singleNotificationData.notificationId
2231
val content = singleNotificationData.content
@@ -27,10 +36,11 @@ internal class SingleMessageNotificationCreator(
2736
.setGroupSummary(isGroupSummary)
2837
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
2938
.setSmallIcon(resourceProvider.iconNewMail)
39+
.setAvatar(singleNotificationData.content)
3040
.setColor(baseNotificationData.color)
3141
.setWhen(singleNotificationData.timestamp)
3242
.setTicker(content.summary)
33-
.setContentTitle(content.sender)
43+
.setContentTitle(content.sender.personal)
3444
.setContentText(content.subject)
3545
.setSubText(baseNotificationData.accountName)
3646
.setBigText(content.preview)
@@ -52,6 +62,12 @@ internal class SingleMessageNotificationCreator(
5262
notificationHelper.notify(account, notificationId, notification)
5363
}
5464

65+
private suspend fun NotificationBuilder.setAvatar(content: NotificationContent) = apply {
66+
resourceProvider.avatar(content.sender)?.let {
67+
setLargeIcon(IconCompat.createWithAdaptiveBitmap(it).toIcon(application))
68+
}
69+
}
70+
5571
private fun NotificationBuilder.setBigText(text: CharSequence) = apply {
5672
setStyle(NotificationCompat.BigTextStyle().bigText(text))
5773
}

legacy/core/src/test/java/com/fsck/k9/notification/BaseNotificationDataCreatorTest.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import assertk.assertions.isNotNull
77
import assertk.assertions.isSameInstanceAs
88
import com.fsck.k9.K9
99
import com.fsck.k9.K9.LockScreenNotificationVisibility
10+
import com.fsck.k9.mail.Address
1011
import net.thunderbird.core.android.account.Identity
1112
import net.thunderbird.core.android.account.LegacyAccountDto
1213
import net.thunderbird.feature.notification.NotificationLight
@@ -129,7 +130,8 @@ class BaseNotificationDataCreatorTest {
129130

130131
assertThat(result.lockScreenNotificationData).isInstanceOf<LockScreenNotificationData.SenderNames>()
131132
val senderNamesData = result.lockScreenNotificationData as LockScreenNotificationData.SenderNames
132-
assertThat(senderNamesData.senderNames).isEqualTo("Sender One, Sender Two, Sender Three")
133+
assertThat(senderNamesData.senderNames)
134+
.isEqualTo("Sender One <irrelevant>, Sender Two <irrelevant>, Sender Three <irrelevant>")
133135
}
134136

135137
@Test
@@ -201,7 +203,7 @@ class BaseNotificationDataCreatorTest {
201203
timestamp = 0L,
202204
content = NotificationContent(
203205
messageReference = mock(),
204-
sender = sender,
206+
sender = Address("irrelevant", sender),
205207
preview = "irrelevant",
206208
summary = "irrelevant",
207209
subject = "irrelevant",

legacy/core/src/test/java/com/fsck/k9/notification/NewMailNotificationManagerTest.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import assertk.assertions.isInstanceOf
1313
import assertk.assertions.isNotNull
1414
import assertk.assertions.isNull
1515
import assertk.assertions.isTrue
16+
import com.fsck.k9.mail.Address
1617
import com.fsck.k9.mailstore.LocalMessage
1718
import com.fsck.k9.mailstore.LocalStore
1819
import com.fsck.k9.mailstore.LocalStoreProvider
@@ -116,7 +117,7 @@ class NewMailNotificationManagerTest {
116117
assertThat(result.singleNotificationData.first().content).isEqualTo(
117118
NotificationContent(
118119
messageReference = createMessageReference("msg-1"),
119-
sender = "sender",
120+
sender = Address("irrelevant", "sender"),
120121
subject = "subject",
121122
preview = "preview",
122123
summary = "summary",
@@ -153,7 +154,7 @@ class NewMailNotificationManagerTest {
153154
assertThat(result.singleNotificationData.first().content).isEqualTo(
154155
NotificationContent(
155156
messageReference = createMessageReference("msg-2"),
156-
sender = "Zoe",
157+
sender = Address("irrelevant", "Zoe"),
157158
subject = "Meeting",
158159
preview = "We need to talk",
159160
summary = "Zoe Meeting",
@@ -320,7 +321,7 @@ class NewMailNotificationManagerTest {
320321
assertThat(singleNotificationData.content).isEqualTo(
321322
NotificationContent(
322323
messageReference = createMessageReference("msg-restore"),
323-
sender = "Alice",
324+
sender = Address("irrelevant", "Alice"),
324325
subject = "Another one",
325326
preview = "Are you tired of me yet?",
326327
summary = "Alice Another one",
@@ -362,7 +363,7 @@ class NewMailNotificationManagerTest {
362363
assertThat(singleNotificationData.content).isEqualTo(
363364
NotificationContent(
364365
messageReference = createMessageReference("uid-1"),
365-
sender = "Sender",
366+
sender = Address("irrelevant", "Sender"),
366367
subject = "Subject",
367368
preview = "Preview",
368369
summary = "Summary",
@@ -375,7 +376,7 @@ class NewMailNotificationManagerTest {
375376
assertThat(summaryNotificationData.singleNotificationData.content).isEqualTo(
376377
NotificationContent(
377378
messageReference = createMessageReference("uid-1"),
378-
sender = "Sender",
379+
sender = Address("irrelevant", "Sender"),
379380
subject = "Subject",
380381
preview = "Preview",
381382
summary = "Summary",
@@ -445,7 +446,7 @@ class NewMailNotificationManagerTest {
445446
on { createFromMessage(account, message) } doReturn
446447
NotificationContent(
447448
messageReference = createMessageReference(messageUid),
448-
sender,
449+
sender = Address("irrelevant", sender),
449450
subject,
450451
preview,
451452
summary,
@@ -473,7 +474,7 @@ class NewMailNotificationManagerTest {
473474
on { createFromMessage(account, message) } doReturn
474475
NotificationContent(
475476
messageReference = createMessageReference(messageUid),
476-
sender,
477+
Address("irrelevant", sender),
477478
subject,
478479
preview,
479480
summary,

legacy/core/src/test/java/com/fsck/k9/notification/NotificationContentCreatorTest.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class NotificationContentCreatorTest : RobolectricTest() {
4040
val content = contentCreator.createFromMessage(account, message)
4141

4242
assertThat(content.messageReference).isEqualTo(messageReference)
43-
assertThat(content.sender).isEqualTo(SENDER_NAME)
43+
assertThat(content.sender.personal).isEqualTo(SENDER_NAME)
4444
assertThat(content.subject).isEqualTo(SUBJECT)
4545
assertThat(content.preview.toString()).isEqualTo("$SUBJECT\n$PREVIEW")
4646
assertThat(content.summary.toString()).isEqualTo("$SENDER_NAME $SUBJECT")
@@ -106,8 +106,8 @@ class NotificationContentCreatorTest : RobolectricTest() {
106106

107107
val content = contentCreator.createFromMessage(account, message)
108108

109-
assertThat(content.sender).isEqualTo("No sender")
110-
assertThat(content.summary.toString()).isEqualTo(SUBJECT)
109+
assertThat(content.sender.personal).isEqualTo("No sender")
110+
assertThat(content.summary.toString()).isEqualTo("No sender $SUBJECT")
111111
}
112112

113113
@Test
@@ -118,7 +118,7 @@ class NotificationContentCreatorTest : RobolectricTest() {
118118

119119
val content = contentCreator.createFromMessage(account, message)
120120

121-
assertThat(content.sender).isEqualTo("To:Bob")
121+
assertThat(content.sender.personal).isEqualTo("To:Bob")
122122
assertThat(content.summary.toString()).isEqualTo("To:Bob $SUBJECT")
123123
}
124124

@@ -133,10 +133,10 @@ class NotificationContentCreatorTest : RobolectricTest() {
133133

134134
val content = contentCreator.createFromMessage(account, message)
135135

136-
assertThat(content.sender).isEqualTo("No sender")
136+
assertThat(content.sender.personal).isEqualTo("No sender")
137137
assertThat(content.subject).isEqualTo("(No subject)")
138138
assertThat(content.preview.toString()).isEqualTo("(No subject)")
139-
assertThat(content.summary.toString()).isEqualTo("(No subject)")
139+
assertThat(content.summary.toString()).isEqualTo("No sender (No subject)")
140140
}
141141

142142
private fun createNotificationContentCreator(): NotificationContentCreator {

legacy/core/src/test/java/com/fsck/k9/notification/NotificationDataStoreTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import assertk.assertions.isNotNull
1212
import assertk.assertions.isNull
1313
import assertk.assertions.isSameInstanceAs
1414
import assertk.assertions.isTrue
15+
import com.fsck.k9.mail.Address
1516
import kotlin.test.assertNotNull
1617
import net.thunderbird.core.android.account.LegacyAccountDto
1718
import net.thunderbird.core.android.testing.RobolectricTest
@@ -247,7 +248,7 @@ class NotificationDataStoreTest : RobolectricTest() {
247248
private fun createNotificationContent(messageReference: MessageReference): NotificationContent {
248249
return NotificationContent(
249250
messageReference = messageReference,
250-
sender = "irrelevant",
251+
sender = Address("irrelevant", "irrelevant"),
251252
subject = "irrelevant",
252253
preview = "irrelevant",
253254
summary = "irrelevant",

0 commit comments

Comments
 (0)