Skip to content

Commit 01f3ed0

Browse files
committed
Fix loading icon in streams notifications
1 parent 19fd7bc commit 01f3ed0

4 files changed

Lines changed: 67 additions & 102 deletions

File tree

app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationHelper.kt

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,18 @@ import android.app.NotificationManager
44
import android.app.PendingIntent
55
import android.content.Context
66
import android.content.Intent
7-
import android.graphics.BitmapFactory
87
import android.net.Uri
98
import android.os.Build
109
import android.provider.Settings
1110
import androidx.core.app.NotificationCompat
1211
import androidx.core.app.NotificationManagerCompat
1312
import androidx.core.content.ContextCompat
1413
import androidx.preference.PreferenceManager
15-
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
16-
import io.reactivex.rxjava3.core.Completable
17-
import io.reactivex.rxjava3.core.Single
18-
import io.reactivex.rxjava3.schedulers.Schedulers
1914
import org.schabi.newpipe.R
2015
import org.schabi.newpipe.extractor.stream.StreamInfoItem
2116
import org.schabi.newpipe.local.feed.service.FeedUpdateInfo
2217
import org.schabi.newpipe.util.NavigationHelper
18+
import org.schabi.newpipe.util.PicassoHelper
2319

2420
/**
2521
* Helper for everything related to show notifications about new streams to the user.
@@ -34,7 +30,7 @@ class NotificationHelper(val context: Context) {
3430
* Show a notification about new streams from a single channel.
3531
* Opening the notification will open the corresponding channel page.
3632
*/
37-
fun displayNewStreamsNotification(data: FeedUpdateInfo): Completable {
33+
fun displayNewStreamsNotification(data: FeedUpdateInfo) {
3834
val newStreams: List<StreamInfoItem> = data.newStreams
3935
val summary = context.resources.getQuantityString(
4036
R.plurals.new_streams, newStreams.size, newStreams.size
@@ -59,12 +55,6 @@ class NotificationHelper(val context: Context) {
5955
.setBadgeIconType(NotificationCompat.BADGE_ICON_LARGE)
6056
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
6157
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
62-
.setLargeIcon(
63-
BitmapFactory.decodeResource(
64-
context.resources,
65-
R.drawable.ic_newpipe_triangle_white
66-
)
67-
)
6858
.setColor(ContextCompat.getColor(context, R.color.ic_launcher_background))
6959
.setColorized(true)
7060
.setAutoCancel(true)
@@ -87,19 +77,17 @@ class NotificationHelper(val context: Context) {
8777
NavigationHelper
8878
.getChannelIntent(context, data.listInfo.serviceId, data.listInfo.url)
8979
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
90-
0
80+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
81+
PendingIntent.FLAG_IMMUTABLE
82+
else
83+
0
9184
)
9285
)
9386

94-
return Single.create(NotificationIcon(context, data.avatarUrl))
95-
.subscribeOn(Schedulers.io())
96-
.observeOn(AndroidSchedulers.mainThread())
97-
.doOnSuccess { icon ->
98-
builder.setLargeIcon(icon)
99-
}
100-
.ignoreElement()
101-
.onErrorComplete()
102-
.doOnComplete { manager.notify(data.pseudoId, builder.build()) }
87+
PicassoHelper.loadNotificationIcon(data.avatarUrl, context) { bitmap ->
88+
builder.setLargeIcon(bitmap)
89+
manager.notify(data.pseudoId, builder.build())
90+
}
10391
}
10492

10593
companion object {

app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationIcon.kt

Lines changed: 0 additions & 60 deletions
This file was deleted.

app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.schabi.newpipe.local.feed.notifications
22

33
import android.content.Context
4+
import android.util.Log
45
import androidx.core.app.NotificationCompat
56
import androidx.work.BackoffPolicy
67
import androidx.work.Constraints
@@ -12,7 +13,7 @@ import androidx.work.PeriodicWorkRequest
1213
import androidx.work.WorkManager
1314
import androidx.work.WorkerParameters
1415
import androidx.work.rxjava3.RxWorker
15-
import io.reactivex.rxjava3.core.Observable
16+
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
1617
import io.reactivex.rxjava3.core.Single
1718
import org.schabi.newpipe.App
1819
import org.schabi.newpipe.R
@@ -34,30 +35,39 @@ class NotificationWorker(
3435
}
3536
private val feedLoadManager = FeedLoadManager(appContext)
3637

37-
override fun createWork(): Single<Result> = if (isEnabled(applicationContext)) {
38+
override fun createWork(): Single<Result> = if (areNotificationsEnabled(applicationContext)) {
3839
feedLoadManager.startLoading(
3940
ignoreOutdatedThreshold = true,
4041
groupId = FeedLoadManager.GROUP_NOTIFICATION_ENABLED
4142
)
43+
.doOnSubscribe { showLoadingFeedForegroundNotification() }
4244
.map { feed ->
43-
feed.mapNotNull { x ->
44-
x.value?.takeIf {
45-
it.newStreams.isNotEmpty()
45+
// filter out feedUpdateInfo items (i.e. channels) with nothing new
46+
feed.mapNotNull {
47+
it.value?.takeIf { feedUpdateInfo ->
48+
feedUpdateInfo.newStreams.isNotEmpty()
4649
}
4750
}
4851
}
49-
.doOnSubscribe { setForegroundAsync(createForegroundInfo()) }
50-
.flatMapObservable { Observable.fromIterable(it) }
51-
.flatMapCompletable { x -> notificationHelper.displayNewStreamsNotification(x) }
52-
.toSingleDefault(Result.success())
52+
.observeOn(AndroidSchedulers.mainThread()) // Picasso requires calls from main thread
53+
.map { feedUpdateInfoList ->
54+
// display notifications for each feedUpdateInfo (i.e. channel)
55+
feedUpdateInfoList.forEach { feedUpdateInfo ->
56+
notificationHelper.displayNewStreamsNotification(feedUpdateInfo)
57+
}
58+
return@map Result.success()
59+
}
60+
.doOnError { throwable ->
61+
Log.e(TAG, "Error while displaying streams notifications", throwable)
62+
// TODO show error notification
63+
}
5364
.onErrorReturnItem(Result.failure())
5465
} else {
55-
// Can be the case when the user disables notifications for NewPipe
56-
// in the device's app settings.
66+
// the user can disable streams notifications in the device's app settings
5767
Single.just(Result.success())
5868
}
5969

60-
private fun createForegroundInfo(): ForegroundInfo {
70+
private fun showLoadingFeedForegroundNotification() {
6171
val notification = NotificationCompat.Builder(
6272
applicationContext,
6373
applicationContext.getString(R.string.notification_channel_id)
@@ -68,14 +78,15 @@ class NotificationWorker(
6878
.setPriority(NotificationCompat.PRIORITY_LOW)
6979
.setContentTitle(applicationContext.getString(R.string.feed_notification_loading))
7080
.build()
71-
return ForegroundInfo(FeedLoadService.NOTIFICATION_ID, notification)
81+
setForegroundAsync(ForegroundInfo(FeedLoadService.NOTIFICATION_ID, notification))
7282
}
7383

7484
companion object {
7585

76-
private const val TAG = App.PACKAGE_NAME + "_streams_notifications"
86+
private val TAG = NotificationWorker::class.java.simpleName
87+
private const val WORK_TAG = App.PACKAGE_NAME + "_streams_notifications"
7788

78-
private fun isEnabled(context: Context) =
89+
private fun areNotificationsEnabled(context: Context) =
7990
NotificationHelper.areNewStreamsNotificationsEnabled(context) &&
8091
NotificationHelper.areNotificationsEnabledOnDevice(context)
8192

@@ -86,7 +97,7 @@ class NotificationWorker(
8697
*/
8798
@JvmStatic
8899
fun initialize(context: Context) {
89-
if (isEnabled(context)) {
100+
if (areNotificationsEnabled(context)) {
90101
schedule(context)
91102
} else {
92103
cancel(context)
@@ -114,13 +125,13 @@ class NotificationWorker(
114125
options.interval,
115126
TimeUnit.MILLISECONDS
116127
).setConstraints(constraints)
117-
.addTag(TAG)
128+
.addTag(WORK_TAG)
118129
.setBackoffCriteria(BackoffPolicy.LINEAR, 30, TimeUnit.MINUTES)
119130
.build()
120131

121132
WorkManager.getInstance(context)
122133
.enqueueUniquePeriodicWork(
123-
TAG,
134+
WORK_TAG,
124135
if (force) {
125136
ExistingPeriodicWorkPolicy.REPLACE
126137
} else {
@@ -139,7 +150,7 @@ class NotificationWorker(
139150
@JvmStatic
140151
fun runNow(context: Context) {
141152
val request = OneTimeWorkRequestBuilder<NotificationWorker>()
142-
.addTag(TAG)
153+
.addTag(WORK_TAG)
143154
.build()
144155
WorkManager.getInstance(context).enqueue(request)
145156
}
@@ -149,7 +160,7 @@ class NotificationWorker(
149160
*/
150161
@JvmStatic
151162
fun cancel(context: Context) {
152-
WorkManager.getInstance(context).cancelAllWorkByTag(TAG)
163+
WorkManager.getInstance(context).cancelAllWorkByTag(WORK_TAG)
153164
}
154165
}
155166
}

app/src/main/java/org/schabi/newpipe/util/PicassoHelper.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import android.annotation.SuppressLint;
66
import android.content.Context;
77
import android.graphics.Bitmap;
8+
import android.graphics.BitmapFactory;
9+
import android.graphics.drawable.Drawable;
810

911
import com.squareup.picasso.Cache;
1012
import com.squareup.picasso.LruCache;
@@ -19,6 +21,7 @@
1921
import java.io.File;
2022
import java.io.IOException;
2123
import java.util.concurrent.TimeUnit;
24+
import java.util.function.Consumer;
2225

2326
import okhttp3.OkHttpClient;
2427

@@ -161,6 +164,29 @@ public String key() {
161164
}
162165

163166

167+
public static void loadNotificationIcon(final String url,
168+
final Context context,
169+
final Consumer<Bitmap> bitmapConsumer) {
170+
loadImageDefault(url, R.drawable.ic_newpipe_triangle_white)
171+
.into(new Target() {
172+
@Override
173+
public void onBitmapLoaded(final Bitmap bitmap, final Picasso.LoadedFrom from) {
174+
bitmapConsumer.accept(bitmap);
175+
}
176+
177+
@Override
178+
public void onBitmapFailed(final Exception e, final Drawable errorDrawable) {
179+
bitmapConsumer.accept(BitmapFactory.decodeResource(context.getResources(),
180+
R.drawable.ic_newpipe_triangle_white));
181+
}
182+
183+
@Override
184+
public void onPrepareLoad(final Drawable placeHolderDrawable) {
185+
}
186+
});
187+
}
188+
189+
164190
private static RequestCreator loadImageDefault(final String url, final int placeholderResId) {
165191
if (!shouldLoadImages || isBlank(url)) {
166192
return picassoInstance

0 commit comments

Comments
 (0)