11package org.schabi.newpipe.local.feed.notifications
22
3+ import android.app.Notification
34import android.app.NotificationManager
5+ import android.app.PendingIntent
46import android.content.Context
57import android.content.Intent
68import android.graphics.Bitmap
@@ -12,6 +14,7 @@ import androidx.core.app.NotificationCompat
1214import androidx.core.app.NotificationManagerCompat
1315import androidx.core.app.PendingIntentCompat
1416import androidx.core.content.ContextCompat
17+ import androidx.core.content.getSystemService
1518import androidx.preference.PreferenceManager
1619import com.squareup.picasso.Picasso
1720import com.squareup.picasso.Target
@@ -26,31 +29,30 @@ import org.schabi.newpipe.util.PicassoHelper
2629 * Helper for everything related to show notifications about new streams to the user.
2730 */
2831class NotificationHelper (val context : Context ) {
29-
30- private val manager = context.getSystemService(
31- Context .NOTIFICATION_SERVICE
32- ) as NotificationManager
33-
32+ private val manager = context.getSystemService<NotificationManager >()!!
3433 private val iconLoadingTargets = ArrayList <Target >()
3534
3635 /* *
37- * Show a notification about new streams from a single channel.
38- * Opening the notification will open the corresponding channel page.
36+ * Show notifications for new streams from a single channel. The individual notifications are
37+ * expandable on Android 7.0 and later.
38+ *
39+ * Opening the summary notification will open the corresponding channel page. Opening the
40+ * individual notifications will open the corresponding video.
3941 */
40- fun displayNewStreamsNotification (data : FeedUpdateInfo ) {
41- val newStreams: List < StreamInfoItem > = data.newStreams
42+ fun displayNewStreamsNotifications (data : FeedUpdateInfo ) {
43+ val newStreams = data.newStreams
4244 val summary = context.resources.getQuantityString(
4345 R .plurals.new_streams, newStreams.size, newStreams.size
4446 )
45- val builder = NotificationCompat .Builder (
47+ val summaryBuilder = NotificationCompat .Builder (
4648 context,
4749 context.getString(R .string.streams_notification_channel_id)
4850 )
4951 .setContentTitle(Localization .concatenateStrings(data.name, summary))
5052 .setContentText(
5153 data.listInfo.relatedItems.joinToString(
5254 context.getString(R .string.enumeration_comma)
53- ) { x -> x .name }
55+ ) { it .name }
5456 )
5557 .setNumber(newStreams.size)
5658 .setBadgeIconType(NotificationCompat .BADGE_ICON_LARGE )
@@ -60,16 +62,19 @@ class NotificationHelper(val context: Context) {
6062 .setColorized(true )
6163 .setAutoCancel(true )
6264 .setCategory(NotificationCompat .CATEGORY_SOCIAL )
65+ .setGroupSummary(true )
66+ .setGroup(data.listInfo.url)
67+ .setGroupAlertBehavior(NotificationCompat .GROUP_ALERT_SUMMARY )
6368
64- // Build style
69+ // Build a summary notification for Android versions < 7.0
6570 val style = NotificationCompat .InboxStyle ()
71+ .setSummaryText(summary)
72+ .setBigContentTitle(data.name)
6673 newStreams.forEach { style.addLine(it.name) }
67- style.setSummaryText(summary)
68- style.setBigContentTitle(data.name)
69- builder.setStyle(style)
74+ summaryBuilder.setStyle(style)
7075
71- // open the channel page when clicking on the notification
72- builder .setContentIntent(
76+ // open the channel page when clicking on the summary notification
77+ summaryBuilder .setContentIntent(
7378 PendingIntentCompat .getActivity(
7479 context,
7580 data.pseudoId,
@@ -84,13 +89,21 @@ class NotificationHelper(val context: Context) {
8489 // a Target is like a listener for image loading events
8590 val target = object : Target {
8691 override fun onBitmapLoaded (bitmap : Bitmap , from : Picasso .LoadedFrom ) {
87- builder.setLargeIcon(bitmap) // set only if there is actually one
88- manager.notify(data.pseudoId, builder.build())
92+ summaryBuilder.setLargeIcon(bitmap) // set only if there is actually one
93+
94+ // Show individual stream notifications
95+ showStreamNotifications(newStreams, data.listInfo.serviceId)
96+ // Show summary notification
97+ manager.notify(data.pseudoId, summaryBuilder.build())
98+
8999 iconLoadingTargets.remove(this ) // allow it to be garbage-collected
90100 }
91101
92102 override fun onBitmapFailed (e : Exception , errorDrawable : Drawable ) {
93- manager.notify(data.pseudoId, builder.build())
103+ // Show individual stream notifications
104+ showStreamNotifications(newStreams, data.listInfo.serviceId)
105+ // Show summary notification
106+ manager.notify(data.pseudoId, summaryBuilder.build())
94107 iconLoadingTargets.remove(this ) // allow it to be garbage-collected
95108 }
96109
@@ -106,6 +119,41 @@ class NotificationHelper(val context: Context) {
106119 PicassoHelper .loadNotificationIcon(data.avatarUrl).into(target)
107120 }
108121
122+ private fun showStreamNotifications (newStreams : List <StreamInfoItem >, serviceId : Int ) {
123+ newStreams.asSequence()
124+ .map { it to createStreamNotification(it, serviceId) }
125+ .forEach { (stream, notification) ->
126+ manager.notify(stream.url.hashCode(), notification)
127+ }
128+ }
129+
130+ private fun createStreamNotification (item : StreamInfoItem , serviceId : Int ): Notification {
131+ return NotificationCompat .Builder (
132+ context,
133+ context.getString(R .string.streams_notification_channel_id)
134+ )
135+ .setSmallIcon(R .drawable.ic_newpipe_triangle_white)
136+ .setContentTitle(item.name)
137+ .setContentText(item.uploaderName)
138+ .setGroup(item.uploaderUrl)
139+ .setColor(ContextCompat .getColor(context, R .color.ic_launcher_background))
140+ .setColorized(true )
141+ .setAutoCancel(true )
142+ .setCategory(NotificationCompat .CATEGORY_SOCIAL )
143+ .setContentIntent(
144+ // Open the stream link in the player when clicking on the notification.
145+ PendingIntentCompat .getActivity(
146+ context,
147+ item.url.hashCode(),
148+ NavigationHelper .getStreamIntent(context, serviceId, item.url, item.name),
149+ PendingIntent .FLAG_UPDATE_CURRENT ,
150+ false
151+ )
152+ )
153+ .setSilent(true ) // Avoid creating noise for individual stream notifications.
154+ .build()
155+ }
156+
109157 companion object {
110158 /* *
111159 * Check whether notifications are enabled on the device.
@@ -124,9 +172,7 @@ class NotificationHelper(val context: Context) {
124172 fun areNotificationsEnabledOnDevice (context : Context ): Boolean {
125173 return if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
126174 val channelId = context.getString(R .string.streams_notification_channel_id)
127- val manager = context.getSystemService(
128- Context .NOTIFICATION_SERVICE
129- ) as NotificationManager
175+ val manager = context.getSystemService<NotificationManager >()!!
130176 val enabled = manager.areNotificationsEnabled()
131177 val channel = manager.getNotificationChannel(channelId)
132178 val importance = channel?.importance
0 commit comments