From c7c542ac4afc217e73fd29cf209c89cdc9fa1f87 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Thu, 25 Aug 2022 22:36:07 +0200 Subject: [PATCH] grouped notifications --- .../main/java/com/github/libretube/MyApp.kt | 6 +- .../preferences/NotificationSettings.kt | 8 +- .../libretube/util/NotificationHelper.kt | 103 +++++++++++------- .../libretube/util/NotificationWorker.kt | 3 +- 4 files changed, 74 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/com/github/libretube/MyApp.kt b/app/src/main/java/com/github/libretube/MyApp.kt index 5f74f948b..d267bc226 100644 --- a/app/src/main/java/com/github/libretube/MyApp.kt +++ b/app/src/main/java/com/github/libretube/MyApp.kt @@ -55,7 +55,11 @@ class MyApp : Application() { /** * Initialize the notification listener in the background */ - NotificationHelper.enqueueWork(this, ExistingPeriodicWorkPolicy.KEEP) + NotificationHelper(this).enqueueWork( + existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.KEEP + ) + + NotificationHelper(this).checkForNewStreams() /** * Handler for uncaught exceptions diff --git a/app/src/main/java/com/github/libretube/preferences/NotificationSettings.kt b/app/src/main/java/com/github/libretube/preferences/NotificationSettings.kt index bd1c6fe99..e3740a0e4 100644 --- a/app/src/main/java/com/github/libretube/preferences/NotificationSettings.kt +++ b/app/src/main/java/com/github/libretube/preferences/NotificationSettings.kt @@ -33,9 +33,9 @@ class NotificationSettings : MaterialPreferenceFragment() { private fun updateNotificationPrefs() { // replace the previous queued work request - NotificationHelper.enqueueWork( - requireContext(), - ExistingPeriodicWorkPolicy.REPLACE - ) + NotificationHelper(requireContext()) + .enqueueWork( + existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.REPLACE + ) } } diff --git a/app/src/main/java/com/github/libretube/util/NotificationHelper.kt b/app/src/main/java/com/github/libretube/util/NotificationHelper.kt index c0d9bbc1b..e8c0df861 100644 --- a/app/src/main/java/com/github/libretube/util/NotificationHelper.kt +++ b/app/src/main/java/com/github/libretube/util/NotificationHelper.kt @@ -12,7 +12,6 @@ import androidx.work.PeriodicWorkRequest import androidx.work.WorkManager import com.github.libretube.NOTIFICATION_WORK_NAME import com.github.libretube.PUSH_CHANNEL_ID -import com.github.libretube.PUSH_NOTIFICATION_ID import com.github.libretube.R import com.github.libretube.activities.MainActivity import com.github.libretube.api.RetrofitInstance @@ -23,12 +22,15 @@ import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking import java.util.concurrent.TimeUnit -object NotificationHelper { +class NotificationHelper( + private val context: Context +) { + private var notificationId = 1 + /** * Enqueue the work manager task */ fun enqueueWork( - context: Context, existingPeriodicWorkPolicy: ExistingPeriodicWorkPolicy ) { // get the notification preferences @@ -87,7 +89,7 @@ object NotificationHelper { /** * check whether new streams are available in subscriptions */ - fun checkForNewStreams(context: Context): Boolean { + fun checkForNewStreams(): Boolean { var result = true val token = PreferenceHelper.getToken() @@ -112,41 +114,40 @@ object NotificationHelper { val lastSeenStreamId = PreferenceHelper.getLatestVideoId() val latestFeedStreamId = videoFeed[0].url.toID() - // first time notifications enabled - if (lastSeenStreamId == "") { + // first time notifications enabled or no new video available + if (lastSeenStreamId == "" || lastSeenStreamId == latestFeedStreamId) { PreferenceHelper.setLatestVideoId(lastSeenStreamId) - } else if (lastSeenStreamId != latestFeedStreamId) { - // get the index of the last user-seen video - var newStreamIndex = -1 - videoFeed.forEachIndexed { index, stream -> - if (stream.url?.toID() == lastSeenStreamId) { - newStreamIndex = index - } + return@runBlocking + } + + // filter the new videos out + val lastSeenStreamItem = videoFeed.filter { it.url.toID() == lastSeenStreamId } + + // previous video not found + if (lastSeenStreamItem.isEmpty()) return@runBlocking + + val lastStreamIndex = videoFeed.indexOf(lastSeenStreamItem[0]) + val newVideos = videoFeed.filterIndexed { index, _ -> + index < lastStreamIndex + } + + // group the new streams by the uploader + val channelGroups = newVideos.groupBy { it.uploaderUrl } + // create a notification for each new stream + channelGroups.forEach { (_, streams) -> + createGroupSummaryNotification( + group = streams[0].uploaderUrl.toID(), + uploaderName = streams[0].uploaderName.toString() + ) + + streams.forEach { streamItem -> + notificationId += 1 + createNotification( + title = streamItem.title.toString(), + description = streamItem.uploaderName.toString(), + group = streamItem.uploaderUrl.toID() + ) } - if (newStreamIndex == -1) return@runBlocking - val (title, description) = when (newStreamIndex) { - // only one new stream available - 1 -> { - Pair(videoFeed[0].title, videoFeed[0].uploaderName) - } - else -> { - Pair( - // return the amount of new streams as title - context.getString( - R.string.new_streams_count, - newStreamIndex.toString() - ), - // return the first few uploader as description - context.getString( - R.string.new_streams_by, - videoFeed[0].uploaderName + ", " + videoFeed[1].uploaderName + ", " + videoFeed[2].uploaderName - ) - ) - } - } - // save the id of the last recent video for the next time it's running - PreferenceHelper.setLatestVideoId(videoFeed[0].url.toID()) - createNotification(context, title!!, description!!) } } // return whether the work succeeded @@ -156,7 +157,11 @@ object NotificationHelper { /** * Notification that is created when new streams are found */ - fun createNotification(context: Context, title: String, description: String) { + private fun createNotification( + title: String, + description: String, + group: String + ) { val intent = Intent(context, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } @@ -169,15 +174,33 @@ object NotificationHelper { val builder = NotificationCompat.Builder(context, PUSH_CHANNEL_ID) .setContentTitle(title) - .setSmallIcon(R.drawable.ic_notification) .setContentText(description) + .setGroup(group) + .setSmallIcon(R.drawable.ic_notification) .setPriority(NotificationCompat.PRIORITY_DEFAULT) // Set the intent that will fire when the user taps the notification .setContentIntent(pendingIntent) .setAutoCancel(true) with(NotificationManagerCompat.from(context)) { // notificationId is a unique int for each notification that you must define - notify(PUSH_NOTIFICATION_ID, builder.build()) + notify(notificationId, builder.build()) + } + } + + private fun createGroupSummaryNotification( + uploaderName: String, + group: String + ) { + val summaryNotification = NotificationCompat.Builder(context, PUSH_CHANNEL_ID) + .setContentTitle(uploaderName) + .setSmallIcon(R.drawable.ic_notification) + .setGroup(group) + .setGroupSummary(true) + .build() + + with(NotificationManagerCompat.from(context)) { + // notificationId is a unique int for each notification that you must define + notify(notificationId, summaryNotification) } } } diff --git a/app/src/main/java/com/github/libretube/util/NotificationWorker.kt b/app/src/main/java/com/github/libretube/util/NotificationWorker.kt index 2263dd4be..ea7e06da2 100644 --- a/app/src/main/java/com/github/libretube/util/NotificationWorker.kt +++ b/app/src/main/java/com/github/libretube/util/NotificationWorker.kt @@ -12,7 +12,8 @@ class NotificationWorker(appContext: Context, parameters: WorkerParameters) : override fun doWork(): Result { // check whether there are new streams and notify if there are some - val result = NotificationHelper.checkForNewStreams(applicationContext) + val result = NotificationHelper(applicationContext) + .checkForNewStreams() // return success if the API request succeeded return if (result) Result.success() else Result.retry() }