diff --git a/app/src/main/java/com/github/libretube/extensions/FilterUntil.kt b/app/src/main/java/com/github/libretube/extensions/FilterUntil.kt new file mode 100644 index 000000000..856462a18 --- /dev/null +++ b/app/src/main/java/com/github/libretube/extensions/FilterUntil.kt @@ -0,0 +1,15 @@ +package com.github.libretube.extensions + +/** + * Returns a list of all items until the given condition is fulfilled + * @param predicate The condition which needs to be searched for + * @return a list of all items before the first true condition + */ +fun List.filterUntil(predicate: (T) -> Boolean): List? { + val items = mutableListOf() + this.forEach { + if (predicate(it)) return items + items.add(it) + } + return null +} 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 046401f99..d54bb77f6 100644 --- a/app/src/main/java/com/github/libretube/util/NotificationHelper.kt +++ b/app/src/main/java/com/github/libretube/util/NotificationHelper.kt @@ -32,43 +32,44 @@ object NotificationHelper { ).toLong() // schedule the work manager request if logged in and notifications enabled - if (notificationsEnabled && PreferenceHelper.getToken() != "") { - // required network type for the work - val networkType = when ( - PreferenceHelper.getString(PreferenceKeys.REQUIRED_NETWORK, "all") - ) { - "all" -> NetworkType.CONNECTED - "wifi" -> NetworkType.UNMETERED - "metered" -> NetworkType.METERED - else -> NetworkType.CONNECTED - } - - // requirements for the work - // here: network needed to run the task - val constraints = Constraints.Builder() - .setRequiredNetworkType(networkType) - .build() - - // create the worker - val notificationWorker = PeriodicWorkRequest.Builder( - NotificationWorker::class.java, - checkingFrequency, - TimeUnit.MINUTES - ) - .setConstraints(constraints) - .build() - - // enqueue the task - WorkManager.getInstance(context) - .enqueueUniquePeriodicWork( - NOTIFICATION_WORK_NAME, - existingPeriodicWorkPolicy, - notificationWorker - ) - } else { + if (!notificationsEnabled) { // cancel the work if notifications are disabled or the user is not logged in WorkManager.getInstance(context) .cancelUniqueWork(NOTIFICATION_WORK_NAME) + return } + + // required network type for the work + val networkType = when ( + PreferenceHelper.getString(PreferenceKeys.REQUIRED_NETWORK, "all") + ) { + "all" -> NetworkType.CONNECTED + "wifi" -> NetworkType.UNMETERED + "metered" -> NetworkType.METERED + else -> NetworkType.CONNECTED + } + + // requirements for the work + // here: network needed to run the task + val constraints = Constraints.Builder() + .setRequiredNetworkType(networkType) + .build() + + // create the worker + val notificationWorker = PeriodicWorkRequest.Builder( + NotificationWorker::class.java, + checkingFrequency, + TimeUnit.MINUTES + ) + .setConstraints(constraints) + .build() + + // enqueue the task + WorkManager.getInstance(context) + .enqueueUniquePeriodicWork( + NOTIFICATION_WORK_NAME, + existingPeriodicWorkPolicy, + notificationWorker + ) } } diff --git a/app/src/main/java/com/github/libretube/workers/NotificationWorker.kt b/app/src/main/java/com/github/libretube/workers/NotificationWorker.kt index c5024b249..b8d14e773 100644 --- a/app/src/main/java/com/github/libretube/workers/NotificationWorker.kt +++ b/app/src/main/java/com/github/libretube/workers/NotificationWorker.kt @@ -13,6 +13,7 @@ import com.github.libretube.R import com.github.libretube.api.SubscriptionHelper import com.github.libretube.constants.PUSH_CHANNEL_ID import com.github.libretube.constants.PreferenceKeys +import com.github.libretube.extensions.filterUntil import com.github.libretube.extensions.toID import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.views.TimePickerPreference @@ -26,12 +27,12 @@ import kotlinx.coroutines.runBlocking class NotificationWorker(appContext: Context, parameters: WorkerParameters) : Worker(appContext, parameters) { - private val notificationManager = - appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + private val notificationManager = NotificationManagerCompat.from(appContext) // the id where notification channels start private var notificationId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - notificationManager.activeNotifications.size + 5 + val nManager = appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + nManager.activeNotifications.size + 5 } else { 5 } @@ -90,28 +91,25 @@ class NotificationWorker(appContext: Context, parameters: WorkerParameters) : } val lastSeenStreamId = PreferenceHelper.getLastSeenVideoId() - val latestFeedStreamId = videoFeed[0].url!!.toID() + val latestFeedStreamId = videoFeed.firstOrNull()?.url?.toID() ?: return@runBlocking - // first time notifications enabled or no new video available + // first time notifications are enabled or no new video available if (lastSeenStreamId == "" || lastSeenStreamId == latestFeedStreamId) { PreferenceHelper.setLatestVideoId(lastSeenStreamId) return@runBlocking } - // filter the new videos out - val lastSeenStreamItem = videoFeed.filter { it.url!!.toID() == lastSeenStreamId } + // filter the new videos until the last seen video in the feed + val newStreams = videoFeed.filterUntil { + it.url!!.toID() == lastSeenStreamId + } ?: return@runBlocking - // previous video not found - if (lastSeenStreamItem.isEmpty()) return@runBlocking - - val lastStreamIndex = videoFeed.indexOf(lastSeenStreamItem[0]) - val newVideos = videoFeed.filterIndexed { index, _ -> - index < lastStreamIndex - } + // return if the previous video didn't get found + if (newStreams.isEmpty()) return@runBlocking // hide for notifications unsubscribed channels val channelsToIgnore = PreferenceHelper.getIgnorableNotificationChannels() - val filteredVideos = newVideos.filter { + val filteredVideos = newStreams.filter { channelsToIgnore.none { channelId -> channelId == it.uploaderUrl?.toID() } @@ -119,12 +117,13 @@ class NotificationWorker(appContext: Context, parameters: WorkerParameters) : // group the new streams by the uploader val channelGroups = filteredVideos.groupBy { it.uploaderUrl } + // create a notification for each new stream channelGroups.forEach { (_, streams) -> createNotification( - group = streams[0].uploaderUrl!!.toID(), - title = streams[0].uploaderName.toString(), - isSummary = true + group = streams.first().uploaderUrl!!.toID(), + title = streams.first().uploaderName.toString(), + isGroupSummary = true ) streams.forEach { streamItem -> @@ -136,7 +135,7 @@ class NotificationWorker(appContext: Context, parameters: WorkerParameters) : } } // save the latest streams that got notified about - PreferenceHelper.setLatestVideoId(videoFeed[0].url!!.toID()) + PreferenceHelper.setLatestVideoId(videoFeed.first().url!!.toID()) } // return whether the work succeeded return success @@ -149,7 +148,7 @@ class NotificationWorker(appContext: Context, parameters: WorkerParameters) : title: String, group: String, description: String? = null, - isSummary: Boolean = false + isGroupSummary: Boolean = false ) { // increase the notification ID to guarantee uniqueness notificationId += 1 @@ -172,15 +171,13 @@ class NotificationWorker(appContext: Context, parameters: WorkerParameters) : .setContentIntent(pendingIntent) .setAutoCancel(true) - if (isSummary) { + if (isGroupSummary) { builder.setGroupSummary(true) } else { builder.setContentText(description) } - with(NotificationManagerCompat.from(applicationContext)) { - // notificationId is a unique int for each notification that you must define - notify(notificationId, builder.build()) - } + // notificationId is a unique int for each notification that you must define + notificationManager.notify(notificationId, builder.build()) } } diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml index 1807750db..9e8bbd4fa 100644 --- a/app/src/main/res/values/array.xml +++ b/app/src/main/res/values/array.xml @@ -25,6 +25,51 @@ https://piped-api.privacy.com.de/ + + @string/systemLanguage + العربية + Azərbaycan dili + Euskara + বাংলা + Català + 简体中文 + 繁體中文 + čeština + Dansk + English + Wikang Filipino + Suomi + Français + Deutsch + Ελληνικά + ગુજરાતી + עברית + हिन्दी + Magyar + Bahasa Indonesia + Italiano + 日本語 + 조선말 + latviešu + മലയാളം + मराठी + Norsk + فارسی + ଓଡ଼ିଆ + Polski + Português + Português (BR) + Română + Русский + Slovenčina + سۆرانی + Español + ภาษาไทย + Türkçe + Türkmençe + Українська + + sys ar