Merge pull request #1162 from Bnyro/master

grouped notifications
This commit is contained in:
Bnyro 2022-08-25 22:36:45 +02:00 committed by GitHub
commit 70813ec449
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 46 deletions

View File

@ -55,7 +55,11 @@ class MyApp : Application() {
/** /**
* Initialize the notification listener in the background * 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 * Handler for uncaught exceptions

View File

@ -33,9 +33,9 @@ class NotificationSettings : MaterialPreferenceFragment() {
private fun updateNotificationPrefs() { private fun updateNotificationPrefs() {
// replace the previous queued work request // replace the previous queued work request
NotificationHelper.enqueueWork( NotificationHelper(requireContext())
requireContext(), .enqueueWork(
ExistingPeriodicWorkPolicy.REPLACE existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.REPLACE
) )
} }
} }

View File

@ -12,7 +12,6 @@ import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager import androidx.work.WorkManager
import com.github.libretube.NOTIFICATION_WORK_NAME import com.github.libretube.NOTIFICATION_WORK_NAME
import com.github.libretube.PUSH_CHANNEL_ID import com.github.libretube.PUSH_CHANNEL_ID
import com.github.libretube.PUSH_NOTIFICATION_ID
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.activities.MainActivity import com.github.libretube.activities.MainActivity
import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.RetrofitInstance
@ -23,12 +22,15 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
object NotificationHelper { class NotificationHelper(
private val context: Context
) {
private var notificationId = 1
/** /**
* Enqueue the work manager task * Enqueue the work manager task
*/ */
fun enqueueWork( fun enqueueWork(
context: Context,
existingPeriodicWorkPolicy: ExistingPeriodicWorkPolicy existingPeriodicWorkPolicy: ExistingPeriodicWorkPolicy
) { ) {
// get the notification preferences // get the notification preferences
@ -87,7 +89,7 @@ object NotificationHelper {
/** /**
* check whether new streams are available in subscriptions * check whether new streams are available in subscriptions
*/ */
fun checkForNewStreams(context: Context): Boolean { fun checkForNewStreams(): Boolean {
var result = true var result = true
val token = PreferenceHelper.getToken() val token = PreferenceHelper.getToken()
@ -112,41 +114,40 @@ object NotificationHelper {
val lastSeenStreamId = PreferenceHelper.getLatestVideoId() val lastSeenStreamId = PreferenceHelper.getLatestVideoId()
val latestFeedStreamId = videoFeed[0].url.toID() val latestFeedStreamId = videoFeed[0].url.toID()
// first time notifications enabled // first time notifications enabled or no new video available
if (lastSeenStreamId == "") { if (lastSeenStreamId == "" || lastSeenStreamId == latestFeedStreamId) {
PreferenceHelper.setLatestVideoId(lastSeenStreamId) PreferenceHelper.setLatestVideoId(lastSeenStreamId)
} else if (lastSeenStreamId != latestFeedStreamId) { return@runBlocking
// get the index of the last user-seen video }
var newStreamIndex = -1
videoFeed.forEachIndexed { index, stream -> // filter the new videos out
if (stream.url?.toID() == lastSeenStreamId) { val lastSeenStreamItem = videoFeed.filter { it.url.toID() == lastSeenStreamId }
newStreamIndex = index
} // 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 // return whether the work succeeded
@ -156,7 +157,11 @@ object NotificationHelper {
/** /**
* Notification that is created when new streams are found * 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 { val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK 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) val builder = NotificationCompat.Builder(context, PUSH_CHANNEL_ID)
.setContentTitle(title) .setContentTitle(title)
.setSmallIcon(R.drawable.ic_notification)
.setContentText(description) .setContentText(description)
.setGroup(group)
.setSmallIcon(R.drawable.ic_notification)
.setPriority(NotificationCompat.PRIORITY_DEFAULT) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification // Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
.setAutoCancel(true) .setAutoCancel(true)
with(NotificationManagerCompat.from(context)) { with(NotificationManagerCompat.from(context)) {
// notificationId is a unique int for each notification that you must define // 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)
} }
} }
} }

View File

@ -12,7 +12,8 @@ class NotificationWorker(appContext: Context, parameters: WorkerParameters) :
override fun doWork(): Result { override fun doWork(): Result {
// check whether there are new streams and notify if there are some // 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 success if the API request succeeded
return if (result) Result.success() else Result.retry() return if (result) Result.success() else Result.retry()
} }