Group notifications

This commit is contained in:
Matthieu 2022-02-03 00:35:53 +01:00
parent d8a9ba92c7
commit 57d8962eb6
3 changed files with 79 additions and 27 deletions

View File

@ -12,6 +12,7 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import okhttp3.internal.format
import org.pixeldroid.app.MainActivity
import org.pixeldroid.app.R
import org.pixeldroid.app.posts.PostActivity
@ -72,8 +73,7 @@ class NotificationsWorker(
)
while (!newNotifications.isNullOrEmpty()
&& newNotifications.map { it.created_at ?: Instant.MIN }
.maxOrNull()!! > previouslyLatestNotification?.created_at ?: Instant.MIN
&& newNotifications.maxOf { it.created_at ?: Instant.MIN } > previouslyLatestNotification?.created_at ?: Instant.MIN
) {
// Add to db
val filteredNewNotifications: List<Notification> = newNotifications.filter {
@ -84,6 +84,12 @@ class NotificationsWorker(
db.notificationDao().insertAll(filteredNewNotifications)
//If multiple notifications, show summary of them
if(filteredNewNotifications.size > 1){
showNotificationSummary(filteredNewNotifications, uniqueUserId)
}
// Launch new notifications
filteredNewNotifications.forEach {
showNotification(it, user, uniqueUserId)
@ -107,6 +113,39 @@ class NotificationsWorker(
return Result.success()
}
private fun showNotificationSummary(notifications: List<Notification>, uniqueUserId: String) {
val content = joinNames(
applicationContext,
notifications.mapNotNull { it.account?.getDisplayName() }
)
val title: String = applicationContext.resources.getQuantityString(
R.plurals.notification_title_summary,
notifications.size,
notifications.size
)
val groupBuilder = NotificationCompat.Builder(applicationContext, makeChannelId(uniqueUserId, null))
.setContentTitle(title)
.setContentText(content)
.setGroupSummary(true)
.setAutoCancel(true)
.setGroup(uniqueUserId)
.setSmallIcon(R.drawable.notification_icon)
.setStyle(NotificationCompat.BigTextStyle().bigText(content))
.setContentIntent(
PendingIntent.getActivity(applicationContext, 0, Intent(applicationContext, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
putExtra(SHOW_NOTIFICATION_TAG, true)
}, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
)
with(NotificationManagerCompat.from(applicationContext)) {
notify(uniqueUserId.hashCode(), groupBuilder.build())
}
}
private fun showNotification(
notification: Notification,
user: UserDatabaseEntity,
@ -238,7 +277,8 @@ fun makeNotificationChannels(context: Context, handle: String, channelGroupId: S
/**
* [channelGroupId] is the id used to uniquely identify the group: for us it is a unique id
* identifying a user consisting of the concatenation of the instance uri and user id.
* identifying a user consisting of the concatenation of the instance uri and user id
* (see [makeChannelGroupId]).
*/
private fun makeChannelId(channelGroupId: String, type: Notification.NotificationType?): String =
(channelGroupId + (type ?: NotificationsWorker.otherNotificationType)).hashCode().toString()
@ -265,4 +305,27 @@ fun removeNotificationChannelsFromAccount(context: Context, user: UserDatabaseEn
}
}
}
}
/**
* BidiFormatter.unicodeWrap is insufficient in some cases (see Tusky#1921)
* So we force isolation manually
* https://unicode.org/reports/tr9/#Explicit_Directional_Isolates
*/
fun CharSequence.unicodeWrap(): String = "\u2068${this}\u2069"
private fun joinNames(context: Context, notifications: List<String>): String {
return when {
notifications.size > 3 -> {
context.getString(R.string.notification_summary_large).format(
*notifications.subList(0, 3).map { it.unicodeWrap() }.toTypedArray(),
notifications.size - 3
)
}
else -> context.getString( when(notifications.size) {
2 -> R.string.notification_summary_small
else /* ==3 */-> R.string.notification_summary_medium
}).format(*notifications.map { it.unicodeWrap() }.toTypedArray())
}
}

View File

@ -1,33 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:startY="49.59793"
android:startX="42.9492"
android:endY="92.4963"
android:endX="85.84757"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<group
android:name="foo"
android:scaleX="2"
android:scaleY="2"
android:translateY="0"
android:translateX="0">
android:scaleX="4"
android:scaleY="4"
android:translateX="-53"
android:translateY="-53">
<path
android:pathData="M23.0332,30.2725L27.5781,30.2725C31.8595,30.2725 35.3302,26.9088 35.3302,22.7596C35.3302,18.6103 31.8595,15.2467 27.5781,15.2467L21.0185,15.2467C18.5485,15.2467 16.5461,17.1872 16.5461,19.581L16.5461,36.451L23.0332,30.2725Z"
android:strokeWidth="1"

View File

@ -64,6 +64,15 @@
<string name="poll_notification_channel">"Polls"</string>
<string name="other_notification_channel">"Other"</string>
<plurals name="notification_title_summary" >
<item quantity="one">"%d new notification"</item>
<item quantity="other">"%d new notifications"</item>
</plurals>
<string name="notification_summary_large">%1$s, %2$s, %3$s and %4$d others</string>
<string name="notification_summary_medium">%1$s, %2$s, and %3$s</string>
<string name="notification_summary_small">%1$s and %2$s</string>
<!-- Login page -->