1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-06-23 13:43:20 +00:00

Merge pull request #10078 from Isira-Seneviratne/Improve_feed_notifications

Improve new stream notifications
This commit is contained in:
Isira Seneviratne 2023-07-20 06:39:19 +05:30 committed by GitHub
commit c658f28b02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 91 additions and 35 deletions

View File

@ -1,6 +1,8 @@
package org.schabi.newpipe.local.feed.notifications package org.schabi.newpipe.local.feed.notifications
import android.app.Notification
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
@ -12,13 +14,13 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.PendingIntentCompat import androidx.core.app.PendingIntentCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import com.squareup.picasso.Target import com.squareup.picasso.Target
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
import org.schabi.newpipe.local.feed.service.FeedUpdateInfo import org.schabi.newpipe.local.feed.service.FeedUpdateInfo
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.NavigationHelper import org.schabi.newpipe.util.NavigationHelper
import org.schabi.newpipe.util.PicassoHelper import org.schabi.newpipe.util.PicassoHelper
@ -26,32 +28,27 @@ import org.schabi.newpipe.util.PicassoHelper
* Helper for everything related to show notifications about new streams to the user. * Helper for everything related to show notifications about new streams to the user.
*/ */
class NotificationHelper(val context: Context) { class NotificationHelper(val context: Context) {
private val manager = NotificationManagerCompat.from(context)
private val manager = context.getSystemService(
Context.NOTIFICATION_SERVICE
) as NotificationManager
private val iconLoadingTargets = ArrayList<Target>() private val iconLoadingTargets = ArrayList<Target>()
/** /**
* Show a notification about new streams from a single channel. * Show notifications for new streams from a single channel. The individual notifications are
* Opening the notification will open the corresponding channel page. * expandable on Android 7.0 and later.
*
* Opening the summary notification will open the corresponding channel page. Opening the
* individual notifications will open the corresponding video.
*/ */
fun displayNewStreamsNotification(data: FeedUpdateInfo) { fun displayNewStreamsNotifications(data: FeedUpdateInfo) {
val newStreams: List<StreamInfoItem> = data.newStreams val newStreams = data.newStreams
val summary = context.resources.getQuantityString( val summary = context.resources.getQuantityString(
R.plurals.new_streams, newStreams.size, newStreams.size R.plurals.new_streams, newStreams.size, newStreams.size
) )
val builder = NotificationCompat.Builder( val summaryBuilder = NotificationCompat.Builder(
context, context,
context.getString(R.string.streams_notification_channel_id) context.getString(R.string.streams_notification_channel_id)
) )
.setContentTitle(Localization.concatenateStrings(data.name, summary)) .setContentTitle(data.name)
.setContentText( .setContentText(summary)
data.listInfo.relatedItems.joinToString(
context.getString(R.string.enumeration_comma)
) { x -> x.name }
)
.setNumber(newStreams.size) .setNumber(newStreams.size)
.setBadgeIconType(NotificationCompat.BADGE_ICON_LARGE) .setBadgeIconType(NotificationCompat.BADGE_ICON_LARGE)
.setPriority(NotificationCompat.PRIORITY_DEFAULT) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
@ -60,16 +57,18 @@ class NotificationHelper(val context: Context) {
.setColorized(true) .setColorized(true)
.setAutoCancel(true) .setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_SOCIAL) .setCategory(NotificationCompat.CATEGORY_SOCIAL)
.setGroupSummary(true)
.setGroup(data.listInfo.url)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
// Build style // Build a summary notification for Android versions < 7.0
val style = NotificationCompat.InboxStyle() val style = NotificationCompat.InboxStyle()
.setBigContentTitle(data.name)
newStreams.forEach { style.addLine(it.name) } newStreams.forEach { style.addLine(it.name) }
style.setSummaryText(summary) summaryBuilder.setStyle(style)
style.setBigContentTitle(data.name)
builder.setStyle(style)
// open the channel page when clicking on the notification // open the channel page when clicking on the summary notification
builder.setContentIntent( summaryBuilder.setContentIntent(
PendingIntentCompat.getActivity( PendingIntentCompat.getActivity(
context, context,
data.pseudoId, data.pseudoId,
@ -84,13 +83,23 @@ class NotificationHelper(val context: Context) {
// a Target is like a listener for image loading events // a Target is like a listener for image loading events
val target = object : Target { val target = object : Target {
override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) { override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) {
builder.setLargeIcon(bitmap) // set only if there is actually one // set channel icon only if there is actually one (for Android versions < 7.0)
manager.notify(data.pseudoId, builder.build()) summaryBuilder.setLargeIcon(bitmap)
// Show individual stream notifications, set channel icon only if there is actually
// one
showStreamNotifications(newStreams, data.listInfo.serviceId, bitmap)
// Show summary notification
manager.notify(data.pseudoId, summaryBuilder.build())
iconLoadingTargets.remove(this) // allow it to be garbage-collected iconLoadingTargets.remove(this) // allow it to be garbage-collected
} }
override fun onBitmapFailed(e: Exception, errorDrawable: Drawable) { override fun onBitmapFailed(e: Exception, errorDrawable: Drawable) {
manager.notify(data.pseudoId, builder.build()) // Show individual stream notifications
showStreamNotifications(newStreams, data.listInfo.serviceId, null)
// Show summary notification
manager.notify(data.pseudoId, summaryBuilder.build())
iconLoadingTargets.remove(this) // allow it to be garbage-collected iconLoadingTargets.remove(this) // allow it to be garbage-collected
} }
@ -106,6 +115,49 @@ class NotificationHelper(val context: Context) {
PicassoHelper.loadNotificationIcon(data.avatarUrl).into(target) PicassoHelper.loadNotificationIcon(data.avatarUrl).into(target)
} }
private fun showStreamNotifications(
newStreams: List<StreamInfoItem>,
serviceId: Int,
channelIcon: Bitmap?
) {
for (stream in newStreams) {
val notification = createStreamNotification(stream, serviceId, channelIcon)
manager.notify(stream.url.hashCode(), notification)
}
}
private fun createStreamNotification(
item: StreamInfoItem,
serviceId: Int,
channelIcon: Bitmap?
): Notification {
return NotificationCompat.Builder(
context,
context.getString(R.string.streams_notification_channel_id)
)
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
.setLargeIcon(channelIcon)
.setContentTitle(item.name)
.setContentText(item.uploaderName)
.setGroup(item.uploaderUrl)
.setColor(ContextCompat.getColor(context, R.color.ic_launcher_background))
.setColorized(true)
.setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_SOCIAL)
.setContentIntent(
// Open the stream link in the player when clicking on the notification.
PendingIntentCompat.getActivity(
context,
item.url.hashCode(),
NavigationHelper.getStreamIntent(context, serviceId, item.url, item.name),
PendingIntent.FLAG_UPDATE_CURRENT,
false
)
)
.setSilent(true) // Avoid creating noise for individual stream notifications.
.build()
}
companion object { companion object {
/** /**
* Check whether notifications are enabled on the device. * Check whether notifications are enabled on the device.
@ -124,9 +176,7 @@ class NotificationHelper(val context: Context) {
fun areNotificationsEnabledOnDevice(context: Context): Boolean { fun areNotificationsEnabledOnDevice(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = context.getString(R.string.streams_notification_channel_id) val channelId = context.getString(R.string.streams_notification_channel_id)
val manager = context.getSystemService( val manager = context.getSystemService<NotificationManager>()!!
Context.NOTIFICATION_SERVICE
) as NotificationManager
val enabled = manager.areNotificationsEnabled() val enabled = manager.areNotificationsEnabled()
val channel = manager.getNotificationChannel(channelId) val channel = manager.getNotificationChannel(channelId)
val importance = channel?.importance val importance = channel?.importance

View File

@ -55,7 +55,7 @@ class NotificationWorker(
.map { feedUpdateInfoList -> .map { feedUpdateInfoList ->
// display notifications for each feedUpdateInfo (i.e. channel) // display notifications for each feedUpdateInfo (i.e. channel)
feedUpdateInfoList.forEach { feedUpdateInfo -> feedUpdateInfoList.forEach { feedUpdateInfo ->
notificationHelper.displayNewStreamsNotification(feedUpdateInfo) notificationHelper.displayNewStreamsNotifications(feedUpdateInfo)
} }
return@map Result.success() return@map Result.success()
} }

View File

@ -563,11 +563,8 @@ public final class NavigationHelper {
@Nullable final PlayQueue playQueue, @Nullable final PlayQueue playQueue,
final boolean switchingPlayers) { final boolean switchingPlayers) {
final Intent intent = getOpenIntent(context, url, serviceId, final Intent intent = getStreamIntent(context, serviceId, url, title)
StreamingService.LinkType.STREAM); .putExtra(VideoDetailFragment.KEY_SWITCHING_PLAYERS, switchingPlayers);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Constants.KEY_TITLE, title);
intent.putExtra(VideoDetailFragment.KEY_SWITCHING_PLAYERS, switchingPlayers);
if (playQueue != null) { if (playQueue != null) {
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class); final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
@ -680,6 +677,15 @@ public final class NavigationHelper {
return getOpenIntent(context, url, serviceId, StreamingService.LinkType.CHANNEL); return getOpenIntent(context, url, serviceId, StreamingService.LinkType.CHANNEL);
} }
public static Intent getStreamIntent(final Context context,
final int serviceId,
final String url,
@Nullable final String title) {
return getOpenIntent(context, url, serviceId, StreamingService.LinkType.STREAM)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(Constants.KEY_TITLE, title);
}
/** /**
* Finish this <code>Activity</code> as well as all <code>Activities</code> running below it * Finish this <code>Activity</code> as well as all <code>Activities</code> running below it
* and then start <code>MainActivity</code>. * and then start <code>MainActivity</code>.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 B

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 823 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 802 B

After

Width:  |  Height:  |  Size: 1.5 KiB