1
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-11-25 19:37:20 +01:00

Replace UniversalImageLoader with Picasso

This commit is contained in:
Stypox 2021-03-27 14:37:44 +01:00
parent 9c5ac069d7
commit fcef783bbb
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
32 changed files with 294 additions and 528 deletions

View File

@ -246,7 +246,8 @@ dependencies {
// Circular ImageView
implementation "de.hdodenhof:circleimageview:3.1.0"
// Image loading
implementation "com.nostra13.universalimageloader:universal-image-loader:1.9.5"
//noinspection GradleDependency --> 2.8 is the last version, not 2.71828!
implementation "com.squareup.picasso:picasso:2.8"
// Markdown library for Android
implementation "io.noties.markwon:core:${markwonVersion}"

View File

@ -11,10 +11,6 @@ import androidx.core.app.NotificationManagerCompat;
import androidx.multidex.MultiDexApplication;
import androidx.preference.PreferenceManager;
import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import org.acra.ACRA;
import org.acra.config.ACRAConfigurationException;
import org.acra.config.CoreConfiguration;
@ -28,6 +24,7 @@ import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.settings.NewPipeSettings;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.ServiceHelper;
import org.schabi.newpipe.util.StateSaver;
@ -65,9 +62,9 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins;
*/
public class App extends MultiDexApplication {
protected static final String TAG = App.class.toString();
private static App app;
public static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID;
private static final String TAG = App.class.toString();
private static App app;
@Nullable
private Disposable disposable = null;
@ -103,7 +100,9 @@ public class App extends MultiDexApplication {
ServiceHelper.initServices(this);
// Initialize image loader
ImageLoader.getInstance().init(getImageLoaderConfigurations(10, 50));
PicassoHelper.init(this);
PicassoHelper.setShouldLoadImages(PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(getString(R.string.download_thumbnail_key), true));
configureRxJavaErrorHandler();
@ -117,6 +116,7 @@ public class App extends MultiDexApplication {
disposable.dispose();
}
super.onTerminate();
PicassoHelper.terminate();
}
protected Downloader getDownloader() {
@ -201,15 +201,6 @@ public class App extends MultiDexApplication {
});
}
private ImageLoaderConfiguration getImageLoaderConfigurations(final int memoryCacheSizeMb,
final int diskCacheSizeMb) {
return new ImageLoaderConfiguration.Builder(this)
.memoryCache(new LRULimitedMemoryCache(memoryCacheSizeMb * 1024 * 1024))
.diskCacheSize(diskCacheSizeMb * 1024 * 1024)
.imageDownloader(new ImageDownloader(getApplicationContext()))
.build();
}
/**
* Called in {@link #attachBaseContext(Context)} after calling the {@code super} method.
* Should be overridden if MultiDex is enabled, since it has to be initialized before ACRA.

View File

@ -10,14 +10,11 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.nostra13.universalimageloader.core.ImageLoader;
import icepick.Icepick;
import icepick.State;
import leakcanary.AppWatcher;
public abstract class BaseFragment extends Fragment {
public static final ImageLoader IMAGE_LOADER = ImageLoader.getInstance();
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
protected final boolean DEBUG = MainActivity.DEBUG;
protected AppCompatActivity activity;

View File

@ -17,7 +17,6 @@ import org.schabi.newpipe.util.InfoCache;
import org.schabi.newpipe.util.TLSSocketFactoryCompat;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@ -194,36 +193,6 @@ public final class DownloaderImpl extends Downloader {
}
}
public InputStream stream(final String siteUrl) throws IOException {
try {
final okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder()
.method("GET", null).url(siteUrl)
.addHeader("User-Agent", USER_AGENT);
final String cookies = getCookies(siteUrl);
if (!cookies.isEmpty()) {
requestBuilder.addHeader("Cookie", cookies);
}
final okhttp3.Request request = requestBuilder.build();
final okhttp3.Response response = client.newCall(request).execute();
final ResponseBody body = response.body();
if (response.code() == 429) {
throw new ReCaptchaException("reCaptcha Challenge requested", siteUrl);
}
if (body == null) {
response.close();
return null;
}
return body.byteStream();
} catch (final ReCaptchaException e) {
throw new IOException(e.getMessage(), e.getCause());
}
}
@Override
public Response execute(@NonNull final Request request)
throws IOException, ReCaptchaException {

View File

@ -1,48 +0,0 @@
package org.schabi.newpipe;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import androidx.preference.PreferenceManager;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import org.schabi.newpipe.extractor.NewPipe;
import java.io.IOException;
import java.io.InputStream;
public class ImageDownloader extends BaseImageDownloader {
private final Resources resources;
private final SharedPreferences preferences;
private final String downloadThumbnailKey;
public ImageDownloader(final Context context) {
super(context);
this.resources = context.getResources();
this.preferences = PreferenceManager.getDefaultSharedPreferences(context);
this.downloadThumbnailKey = context.getString(R.string.download_thumbnail_key);
}
private boolean isDownloadingThumbnail() {
return preferences.getBoolean(downloadThumbnailKey, true);
}
@SuppressLint("ResourceType")
@Override
public InputStream getStream(final String imageUri, final Object extra) throws IOException {
if (isDownloadingThumbnail()) {
return super.getStream(imageUri, extra);
} else {
return resources.openRawResource(R.drawable.dummy_thumbnail_dark);
}
}
protected InputStream getStreamFromNetwork(final String imageUri, final Object extra)
throws IOException {
final DownloaderImpl downloader = (DownloaderImpl) NewPipe.getDownloader();
return downloader.stream(imageUri);
}
}

View File

@ -48,9 +48,7 @@ import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.tabs.TabLayout;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import com.squareup.picasso.Callback;
import org.schabi.newpipe.App;
import org.schabi.newpipe.R;
@ -90,14 +88,14 @@ import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import java.util.ArrayList;
import java.util.Iterator;
@ -151,6 +149,8 @@ public final class VideoDetailFragment
private static final String DESCRIPTION_TAB_TAG = "DESCRIPTION TAB";
private static final String EMPTY_TAB_TAG = "EMPTY TAB";
private static final String PICASSO_VIDEO_DETAILS_TAG = "PICASSO_VIDEO_DETAILS_TAG";
// tabs
private boolean showComments;
private boolean showRelatedItems;
@ -686,33 +686,23 @@ public final class VideoDetailFragment
}
private void initThumbnailViews(@NonNull final StreamInfo info) {
binding.detailThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
PicassoHelper.loadThumbnail(info.getThumbnailUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
.into(binding.detailThumbnailImageView, new Callback() {
@Override
public void onSuccess() {
}
if (!isEmpty(info.getThumbnailUrl())) {
final ImageLoadingListener onFailListener = new SimpleImageLoadingListener() {
@Override
public void onLoadingFailed(final String imageUri, final View view,
final FailReason failReason) {
showSnackBarError(new ErrorInfo(failReason.getCause(), UserAction.LOAD_IMAGE,
imageUri, info));
}
};
@Override
public void onError(final Exception e) {
showSnackBarError(new ErrorInfo(e, UserAction.LOAD_IMAGE,
info.getThumbnailUrl(), info));
}
});
IMAGE_LOADER.displayImage(info.getThumbnailUrl(), binding.detailThumbnailImageView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, onFailListener);
}
if (!isEmpty(info.getSubChannelAvatarUrl())) {
IMAGE_LOADER.displayImage(info.getSubChannelAvatarUrl(),
binding.detailSubChannelThumbnailView,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
}
if (!isEmpty(info.getUploaderAvatarUrl())) {
IMAGE_LOADER.displayImage(info.getUploaderAvatarUrl(),
binding.detailUploaderThumbnailView,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
}
PicassoHelper.loadAvatar(info.getSubChannelAvatarUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
.into(binding.detailSubChannelThumbnailView);
PicassoHelper.loadAvatar(info.getUploaderAvatarUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
.into(binding.detailUploaderThumbnailView);
}
/*//////////////////////////////////////////////////////////////////////////
@ -1446,8 +1436,7 @@ public final class VideoDetailFragment
}
}
IMAGE_LOADER.cancelDisplayTask(binding.detailThumbnailImageView);
IMAGE_LOADER.cancelDisplayTask(binding.detailSubChannelThumbnailView);
PicassoHelper.cancelTag(PICASSO_VIDEO_DETAILS_TAG);
binding.detailThumbnailImageView.setImageBitmap(null);
binding.detailSubChannelThumbnailView.setImageBitmap(null);
}
@ -2278,10 +2267,8 @@ public final class VideoDetailFragment
binding.overlayTitleTextView.setText(isEmpty(overlayTitle) ? "" : overlayTitle);
binding.overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader);
binding.overlayThumbnail.setImageResource(R.drawable.dummy_thumbnail_dark);
if (!isEmpty(thumbnailUrl)) {
IMAGE_LOADER.displayImage(thumbnailUrl, binding.overlayThumbnail,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null);
}
PicassoHelper.loadThumbnail(thumbnailUrl).tag(PICASSO_VIDEO_DETAILS_TAG)
.into(binding.overlayThumbnail);
}
private void setOverlayPlayPauseImage(final boolean playerIsPlaying) {

View File

@ -40,10 +40,10 @@ import org.schabi.newpipe.local.subscription.SubscriptionManager;
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.util.ArrayList;
@ -66,7 +66,10 @@ import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
implements View.OnClickListener {
private static final int BUTTON_DEBOUNCE_INTERVAL = 100;
private static final String PICASSO_CHANNEL_TAG = "PICASSO_CHANNEL_TAG";
private final CompositeDisposable disposables = new CompositeDisposable();
private Disposable subscribeButtonMonitor;
@ -421,10 +424,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
@Override
public void showLoading() {
super.showLoading();
IMAGE_LOADER.cancelDisplayTask(headerBinding.channelBannerImage);
IMAGE_LOADER.cancelDisplayTask(headerBinding.channelAvatarView);
IMAGE_LOADER.cancelDisplayTask(headerBinding.subChannelAvatarView);
PicassoHelper.cancelTag(PICASSO_CHANNEL_TAG);
animate(headerBinding.channelSubscribeButton, false, 100);
}
@ -433,13 +433,12 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
super.handleResult(result);
headerBinding.getRoot().setVisibility(View.VISIBLE);
IMAGE_LOADER.displayImage(result.getBannerUrl(), headerBinding.channelBannerImage,
ImageDisplayConstants.DISPLAY_BANNER_OPTIONS);
IMAGE_LOADER.displayImage(result.getAvatarUrl(), headerBinding.channelAvatarView,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
IMAGE_LOADER.displayImage(result.getParentChannelAvatarUrl(),
headerBinding.subChannelAvatarView,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
PicassoHelper.loadBanner(result.getBannerUrl()).tag(PICASSO_CHANNEL_TAG)
.into(headerBinding.channelBannerImage);
PicassoHelper.loadAvatar(result.getAvatarUrl()).tag(PICASSO_CHANNEL_TAG)
.into(headerBinding.channelAvatarView);
PicassoHelper.loadAvatar(result.getParentChannelAvatarUrl()).tag(PICASSO_CHANNEL_TAG)
.into(headerBinding.subChannelAvatarView);
headerBinding.channelSubscriberView.setVisibility(View.VISIBLE);
if (result.getSubscriberCount() >= 0) {

View File

@ -41,7 +41,7 @@ import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
@ -64,12 +64,16 @@ import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
private static final String PICASSO_PLAYLIST_TAG = "PICASSO_PLAYLIST_TAG";
private CompositeDisposable disposables;
private Subscription bookmarkReactor;
private AtomicBoolean isBookmarkButtonReady;
private RemotePlaylistManager remotePlaylistManager;
private PlaylistRemoteEntity playlistEntity;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
@ -274,7 +278,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
animate(headerBinding.getRoot(), false, 200);
animateHideRecyclerViewAllowingScrolling(itemsList);
IMAGE_LOADER.cancelDisplayTask(headerBinding.uploaderAvatarView);
PicassoHelper.cancelTag(PICASSO_PLAYLIST_TAG);
animate(headerBinding.uploaderLayout, false, 200);
}
@ -317,8 +321,8 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
R.drawable.ic_radio)
);
} else {
IMAGE_LOADER.displayImage(avatarUrl, headerBinding.uploaderAvatarView,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
PicassoHelper.loadAvatar(avatarUrl).tag(PICASSO_PLAYLIST_TAG)
.into(headerBinding.uploaderAvatarView);
}
headerBinding.playlistStreamCount.setText(Localization

View File

@ -6,8 +6,6 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
@ -51,7 +49,6 @@ import org.schabi.newpipe.util.OnClickGesture;
public class InfoItemBuilder {
private final Context context;
private final ImageLoader imageLoader = ImageLoader.getInstance();
private OnClickGesture<StreamInfoItem> onStreamSelectedListener;
private OnClickGesture<ChannelInfoItem> onChannelSelectedListener;
@ -101,10 +98,6 @@ public class InfoItemBuilder {
return context;
}
public ImageLoader getImageLoader() {
return imageLoader;
}
public OnClickGesture<StreamInfoItem> getOnStreamSelectedListener() {
return onStreamSelectedListener;
}

View File

@ -3,13 +3,12 @@ package org.schabi.newpipe.info_list
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.nostra13.universalimageloader.core.ImageLoader
import com.xwray.groupie.GroupieViewHolder
import com.xwray.groupie.Item
import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.stream.StreamSegment
import org.schabi.newpipe.util.ImageDisplayConstants
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.PicassoHelper
class StreamSegmentItem(
private val item: StreamSegment,
@ -24,10 +23,8 @@ class StreamSegmentItem(
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
item.previewUrl?.let {
ImageLoader.getInstance().displayImage(
it, viewHolder.root.findViewById<ImageView>(R.id.previewImage),
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS
)
PicassoHelper.loadThumbnail(it)
.into(viewHolder.root.findViewById<ImageView>(R.id.previewImage))
}
viewHolder.root.findViewById<TextView>(R.id.textViewTitle).text = item.title
if (item.channelName == null) {

View File

@ -8,7 +8,7 @@ import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.Localization;
import de.hdodenhof.circleimageview.CircleImageView;
@ -43,10 +43,7 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
itemTitleView.setText(item.getName());
itemAdditionalDetailView.setText(getDetailLine(item));
itemBuilder.getImageLoader()
.displayImage(item.getThumbnailUrl(),
itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
PicassoHelper.loadThumbnail(item.getThumbnailUrl()).into(itemThumbnailView);
itemView.setOnClickListener(view -> {
if (itemBuilder.getOnChannelSelectedListener() != null) {

View File

@ -1,6 +1,5 @@
package org.schabi.newpipe.info_list.holder;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
@ -12,7 +11,6 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.PreferenceManager;
import org.schabi.newpipe.R;
import org.schabi.newpipe.error.ErrorActivity;
@ -22,11 +20,11 @@ import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.CommentTextOnTouchListener;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.external_communication.TimestampExtractor;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import org.schabi.newpipe.util.PicassoHelper;
import java.util.regex.Matcher;
@ -38,11 +36,9 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
private static final int COMMENT_DEFAULT_LINES = 2;
private static final int COMMENT_EXPANDED_LINES = 1000;
private final String downloadThumbnailKey;
private final int commentHorizontalPadding;
private final int commentVerticalPadding;
private SharedPreferences preferences = null;
private final RelativeLayout itemRoot;
public final CircleImageView itemThumbnailView;
private final TextView itemContentView;
@ -83,9 +79,6 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
itemPublishedTime = itemView.findViewById(R.id.itemPublishedTime);
itemContentView = itemView.findViewById(R.id.itemCommentContentView);
downloadThumbnailKey = infoItemBuilder.getContext().
getString(R.string.download_thumbnail_key);
commentHorizontalPadding = (int) infoItemBuilder.getContext()
.getResources().getDimension(R.dimen.comments_horizontal_padding);
commentVerticalPadding = (int) infoItemBuilder.getContext()
@ -105,14 +98,8 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
}
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
preferences = PreferenceManager.getDefaultSharedPreferences(itemBuilder.getContext());
itemBuilder.getImageLoader()
.displayImage(item.getUploaderAvatarUrl(),
itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
if (preferences.getBoolean(downloadThumbnailKey, true)) {
PicassoHelper.loadAvatar(item.getUploaderAvatarUrl()).into(itemThumbnailView);
if (PicassoHelper.getShouldLoadImages()) {
itemThumbnailView.setVisibility(View.VISIBLE);
itemRoot.setPadding(commentVerticalPadding, commentVerticalPadding,
commentVerticalPadding, commentVerticalPadding);

View File

@ -9,7 +9,7 @@ import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.Localization;
public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
@ -46,9 +46,7 @@ public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
.localizeStreamCountMini(itemStreamCountView.getContext(), item.getStreamCount()));
itemUploaderView.setText(item.getUploaderName());
itemBuilder.getImageLoader()
.displayImage(item.getThumbnailUrl(), itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
PicassoHelper.loadPlaylistThumbnail(item.getThumbnailUrl()).into(itemThumbnailView);
itemView.setOnClickListener(view -> {
if (itemBuilder.getOnPlaylistSelectedListener() != null) {

View File

@ -15,7 +15,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.ktx.ViewUtils;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar;
@ -83,10 +83,7 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
}
// Default thumbnail is shown on error, while loading and if the url is empty
itemBuilder.getImageLoader()
.displayImage(item.getThumbnailUrl(),
itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
PicassoHelper.loadThumbnail(item.getThumbnailUrl()).into(itemThumbnailView);
itemView.setOnClickListener(view -> {
if (itemBuilder.getOnStreamSelectedListener() != null) {

View File

@ -1,10 +1,6 @@
package org.schabi.newpipe.local;
import android.content.Context;
import android.widget.ImageView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.util.OnClickGesture;
@ -31,7 +27,6 @@ import org.schabi.newpipe.util.OnClickGesture;
public class LocalItemBuilder {
private final Context context;
private final ImageLoader imageLoader = ImageLoader.getInstance();
private OnClickGesture<LocalItem> onSelectedListener;
@ -43,11 +38,6 @@ public class LocalItemBuilder {
return context;
}
public void displayImage(final String url, final ImageView view,
final DisplayImageOptions options) {
imageLoader.displayImage(url, view, options);
}
public OnClickGesture<LocalItem> getOnItemSelectedListener() {
return onSelectedListener;
}

View File

@ -5,7 +5,6 @@ import android.text.TextUtils
import android.view.View
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
import com.nostra13.universalimageloader.core.ImageLoader
import com.xwray.groupie.viewbinding.BindableItem
import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.R
@ -16,8 +15,8 @@ import org.schabi.newpipe.extractor.stream.StreamType.AUDIO_LIVE_STREAM
import org.schabi.newpipe.extractor.stream.StreamType.AUDIO_STREAM
import org.schabi.newpipe.extractor.stream.StreamType.LIVE_STREAM
import org.schabi.newpipe.extractor.stream.StreamType.VIDEO_STREAM
import org.schabi.newpipe.util.ImageDisplayConstants
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.PicassoHelper
import java.util.concurrent.TimeUnit
data class StreamItem(
@ -93,10 +92,7 @@ data class StreamItem(
viewBinding.itemProgressView.visibility = View.GONE
}
ImageLoader.getInstance().displayImage(
stream.thumbnailUrl, viewBinding.itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS
)
PicassoHelper.loadThumbnail(stream.thumbnailUrl).into(viewBinding.itemThumbnailView)
if (itemVersion != ItemVersion.MINI) {
viewBinding.itemAdditionalDetails.text =

View File

@ -7,7 +7,7 @@ import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.Localization;
import java.time.format.DateTimeFormatter;
@ -36,8 +36,7 @@ public class LocalPlaylistItemHolder extends PlaylistItemHolder {
itemStreamCountView.getContext(), item.streamCount));
itemUploaderView.setVisibility(View.INVISIBLE);
itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView,
ImageDisplayConstants.DISPLAY_PLAYLIST_OPTIONS);
PicassoHelper.loadPlaylistThumbnail(item.thumbnailUrl).into(itemThumbnailView);
super.updateFromItem(localItem, historyRecordManager, dateTimeFormatter);
}

View File

@ -15,7 +15,7 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.ktx.ViewUtils;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar;
@ -81,8 +81,8 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
}
// Default thumbnail is shown on error, while loading and if the url is empty
itemBuilder.displayImage(item.getStreamEntity().getThumbnailUrl(), itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
PicassoHelper.loadThumbnail(item.getStreamEntity().getThumbnailUrl())
.into(itemThumbnailView);
itemView.setOnClickListener(view -> {
if (itemBuilder.getOnItemSelectedListener() != null) {

View File

@ -15,7 +15,7 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.ktx.ViewUtils;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar;
@ -114,8 +114,8 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
}
// Default thumbnail is shown on error, while loading and if the url is empty
itemBuilder.displayImage(item.getStreamEntity().getThumbnailUrl(), itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
PicassoHelper.loadThumbnail(item.getStreamEntity().getThumbnailUrl())
.into(itemThumbnailView);
itemView.setOnClickListener(view -> {
if (itemBuilder.getOnItemSelectedListener() != null) {

View File

@ -8,7 +8,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.Localization;
import java.time.format.DateTimeFormatter;
@ -44,9 +44,7 @@ public class RemotePlaylistItemHolder extends PlaylistItemHolder {
itemUploaderView.setText(NewPipe.getNameOfService(item.getServiceId()));
}
itemBuilder.displayImage(item.getThumbnailUrl(), itemThumbnailView,
ImageDisplayConstants.DISPLAY_PLAYLIST_OPTIONS);
PicassoHelper.loadPlaylistThumbnail(item.getThumbnailUrl()).into(itemThumbnailView);
super.updateFromItem(localItem, historyRecordManager, dateTimeFormatter);
}

View File

@ -3,14 +3,13 @@ package org.schabi.newpipe.local.subscription.item
import android.content.Context
import android.widget.ImageView
import android.widget.TextView
import com.nostra13.universalimageloader.core.ImageLoader
import com.xwray.groupie.GroupieViewHolder
import com.xwray.groupie.Item
import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.channel.ChannelInfoItem
import org.schabi.newpipe.util.ImageDisplayConstants
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.OnClickGesture
import org.schabi.newpipe.util.PicassoHelper
class ChannelItem(
private val infoItem: ChannelInfoItem,
@ -40,10 +39,7 @@ class ChannelItem(
itemChannelDescriptionView.text = infoItem.description
}
ImageLoader.getInstance().displayImage(
infoItem.thumbnailUrl, itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS
)
PicassoHelper.loadThumbnail(infoItem.thumbnailUrl).into(itemThumbnailView)
gesturesListener?.run {
viewHolder.root.setOnClickListener { selected(infoItem) }

View File

@ -3,7 +3,6 @@ package org.schabi.newpipe.local.subscription.item
import android.view.View
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.nostra13.universalimageloader.core.ImageLoader
import com.xwray.groupie.viewbinding.BindableItem
import com.xwray.groupie.viewbinding.GroupieViewHolder
import org.schabi.newpipe.R
@ -11,7 +10,7 @@ import org.schabi.newpipe.database.subscription.SubscriptionEntity
import org.schabi.newpipe.databinding.PickerSubscriptionItemBinding
import org.schabi.newpipe.ktx.AnimationType
import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.util.ImageDisplayConstants
import org.schabi.newpipe.util.PicassoHelper
data class PickerSubscriptionItem(
val subscriptionEntity: SubscriptionEntity,
@ -22,11 +21,7 @@ data class PickerSubscriptionItem(
override fun getSpanSize(spanCount: Int, position: Int): Int = 1
override fun bind(viewBinding: PickerSubscriptionItemBinding, position: Int) {
ImageLoader.getInstance().displayImage(
subscriptionEntity.avatarUrl,
viewBinding.thumbnailView, ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS
)
PicassoHelper.loadAvatar(subscriptionEntity.avatarUrl).into(viewBinding.thumbnailView)
viewBinding.titleView.text = subscriptionEntity.name
viewBinding.selectedHighlight.isVisible = isSelected
}

View File

@ -18,6 +18,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
@ -82,9 +83,9 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoListener;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import com.squareup.picasso.Transformation;
import org.schabi.newpipe.DownloaderImpl;
import org.schabi.newpipe.MainActivity;
@ -128,11 +129,11 @@ import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
import org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHelper;
import org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHolder;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.SerializedCache;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import org.schabi.newpipe.views.ExpandableSurfaceView;
@ -196,7 +197,6 @@ import static org.schabi.newpipe.util.Localization.containsCaseInsensitive;
public final class Player implements
EventListener,
PlaybackListener,
ImageLoadingListener,
VideoListener,
SeekBar.OnSeekBarChangeListener,
View.OnClickListener,
@ -250,6 +250,9 @@ public final class Player implements
private static final int RENDERER_UNAVAILABLE = -1;
private static final String PICASSO_PLAYER_TAG = "PICASSO_PLAYER_TAG";
private static final String PICASSO_TRANSFORMATION_KEY = "PICASSO_TRANSFORMATION_KEY";
/*//////////////////////////////////////////////////////////////////////////
// Playback
//////////////////////////////////////////////////////////////////////////*/
@ -820,7 +823,7 @@ public final class Player implements
databaseUpdateDisposable.clear();
progressUpdateDisposable.set(null);
ImageLoader.getInstance().stop();
PicassoHelper.cancelTag(PICASSO_PLAYER_TAG);
if (binding != null) {
binding.endScreen.setImageBitmap(null);
@ -1215,14 +1218,71 @@ public final class Player implements
private void initThumbnail(final String url) {
if (DEBUG) {
Log.d(TAG, "Thumbnail - initThumbnail() called");
Log.d(TAG, "Thumbnail - initThumbnail() called with url = ["
+ (url == null ? "null" : url) + "]");
}
if (url == null || url.isEmpty()) {
return;
}
ImageLoader.getInstance().resume();
ImageLoader.getInstance()
.loadImage(url, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, this);
// scale down the notification thumbnail for performance
PicassoHelper.loadThumbnail(url)
.tag(PICASSO_PLAYER_TAG)
.transform(new Transformation() {
@Override
public Bitmap transform(final Bitmap source) {
final float notificationThumbnailWidth = Math.min(
context.getResources()
.getDimension(R.dimen.player_notification_thumbnail_width),
source.getWidth());
return Bitmap.createScaledBitmap(
source,
(int) notificationThumbnailWidth,
(int) (source.getHeight()
/ (source.getWidth() / notificationThumbnailWidth)),
true);
}
@Override
public String key() {
return PICASSO_TRANSFORMATION_KEY;
}
})
.into(new Target() {
@Override
public void onBitmapLoaded(final Bitmap bitmap, final Picasso.LoadedFrom from) {
if (DEBUG) {
Log.d(TAG, "Thumbnail - onLoadingComplete() called with: "
+ "url = [" + url + "], " + "loadedImage = [" + bitmap + " -> "
+ bitmap.getWidth() + "x" + bitmap.getHeight()
+ "], from = [" + from + "]");
}
currentThumbnail = bitmap;
NotificationUtil.getInstance()
.createNotificationIfNeededAndUpdate(Player.this, false);
// there is a new thumbnail, so changed the end screen thumbnail, too.
updateEndScreenThumbnail();
}
@Override
public void onBitmapFailed(final Exception e, final Drawable errorDrawable) {
Log.e(TAG, "Thumbnail - onBitmapFailed() called with: url = ["
+ url + "]", e);
currentThumbnail = null;
NotificationUtil.getInstance()
.createNotificationIfNeededAndUpdate(Player.this, false);
}
@Override
public void onPrepareLoad(final Drawable placeHolderDrawable) {
if (DEBUG) {
Log.d(TAG, "Thumbnail - onLoadingStarted() called with: url = ["
+ url + "]");
}
}
});
}
/**
@ -1296,61 +1356,6 @@ public final class Player implements
return Math.min(currentThumbnail.getHeight(), screenHeight);
}
}
@Override
public void onLoadingStarted(final String imageUri, final View view) {
if (DEBUG) {
Log.d(TAG, "Thumbnail - onLoadingStarted() called on: "
+ "imageUri = [" + imageUri + "], view = [" + view + "]");
}
}
@Override
public void onLoadingFailed(final String imageUri, final View view,
final FailReason failReason) {
Log.e(TAG, "Thumbnail - onLoadingFailed() called on imageUri = [" + imageUri + "]",
failReason.getCause());
currentThumbnail = null;
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
@Override
public void onLoadingComplete(final String imageUri, final View view,
final Bitmap loadedImage) {
// scale down the notification thumbnail for performance
final float notificationThumbnailWidth = Math.min(
context.getResources().getDimension(R.dimen.player_notification_thumbnail_width),
loadedImage.getWidth());
currentThumbnail = Bitmap.createScaledBitmap(
loadedImage,
(int) notificationThumbnailWidth,
(int) (loadedImage.getHeight()
/ (loadedImage.getWidth() / notificationThumbnailWidth)),
true);
if (DEBUG) {
Log.d(TAG, "Thumbnail - onLoadingComplete() called with: "
+ "imageUri = [" + imageUri + "], view = [" + view + "], "
+ "loadedImage = [" + loadedImage + "], "
+ loadedImage.getWidth() + "x" + loadedImage.getHeight()
+ ", scaled notification width = " + notificationThumbnailWidth);
}
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
// there is a new thumbnail, thus the end screen thumbnail needs to be changed, too.
updateEndScreenThumbnail();
}
@Override
public void onLoadingCancelled(final String imageUri, final View view) {
if (DEBUG) {
Log.d(TAG, "Thumbnail - onLoadingCancelled() called with: "
+ "imageUri = [" + imageUri + "], view = [" + view + "]");
}
currentThumbnail = null;
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
//endregion

View File

@ -5,11 +5,9 @@ import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.PicassoHelper;
public class PlayQueueItemBuilder {
private static final String TAG = PlayQueueItemBuilder.class.toString();
@ -35,8 +33,7 @@ public class PlayQueueItemBuilder {
holder.itemDurationView.setVisibility(View.GONE);
}
ImageLoader.getInstance().displayImage(item.getThumbnailUrl(), holder.itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
PicassoHelper.loadThumbnail(item.getThumbnailUrl()).into(holder.itemThumbnailView);
holder.itemRoot.setOnClickListener(view -> {
if (onItemClickListener != null) {

View File

@ -1,16 +1,18 @@
package org.schabi.newpipe.player.seekbarpreview;
import static org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHelper.SeekbarPreviewThumbnailType;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.common.base.Stopwatch;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.extractor.stream.Frameset;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.PicassoHelper;
import java.util.Comparator;
import java.util.HashMap;
@ -21,11 +23,8 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import static org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHelper.SeekbarPreviewThumbnailType;
public class SeekbarPreviewThumbnailHolder {
// This has to be <= 23 chars on devices running Android 7 or lower (API <= 25)
@ -174,6 +173,7 @@ public class SeekbarPreviewThumbnailHolder {
}
}
@Nullable
private Bitmap getBitMapFrom(final String url) {
if (url == null) {
Log.w(TAG, "url is null; This should never happen");
@ -182,24 +182,11 @@ public class SeekbarPreviewThumbnailHolder {
final Stopwatch sw = Log.isLoggable(TAG, Log.DEBUG) ? Stopwatch.createStarted() : null;
try {
final SyncImageLoadingListener syncImageLoadingListener =
new SyncImageLoadingListener();
Log.d(TAG, "Downloading bitmap for seekbarPreview from '" + url + "'");
// Ensure that everything is running
ImageLoader.getInstance().resume();
// Load the image
// Impl-Note:
// Gets the bitmap within the timeout of 15 seconds imposed by default by OkHttpClient
// Ensure that your are not running on the main-Thread this will otherwise hang
ImageLoader.getInstance().loadImage(
url,
ImageDisplayConstants.DISPLAY_SEEKBAR_PREVIEW_OPTIONS,
syncImageLoadingListener);
// Get the bitmap within the timeout
final Bitmap bitmap =
syncImageLoadingListener.waitForBitmapOrThrow(30, TimeUnit.SECONDS);
final Bitmap bitmap = PicassoHelper.loadSeekbarThumbnailPreview(url).get();
if (sw != null) {
Log.d(TAG,

View File

@ -1,87 +0,0 @@
package org.schabi.newpipe.player.seekbarpreview;
import android.graphics.Bitmap;
import android.view.View;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Listener for synchronously downloading of an image/bitmap.
*/
public class SyncImageLoadingListener extends SimpleImageLoadingListener {
private final CountDownLatch countDownLatch = new CountDownLatch(1);
private Bitmap bitmap;
private boolean cancelled = false;
private FailReason failReason = null;
@SuppressWarnings("checkstyle:HiddenField")
@Override
public void onLoadingFailed(
final String imageUri,
final View view,
final FailReason failReason) {
this.failReason = failReason;
countDownLatch.countDown();
}
@Override
public void onLoadingComplete(
final String imageUri,
final View view,
final Bitmap loadedImage) {
bitmap = loadedImage;
countDownLatch.countDown();
}
@Override
public void onLoadingCancelled(final String imageUri, final View view) {
cancelled = true;
countDownLatch.countDown();
}
public Bitmap waitForBitmapOrThrow(final long timeout, final TimeUnit timeUnit)
throws InterruptedException, TimeoutException {
// Wait for the download to finish
if (!countDownLatch.await(timeout, timeUnit)) {
throw new TimeoutException("Couldn't get the image in time");
}
if (isCancelled()) {
throw new CancellationException("Download of image was cancelled");
}
if (getFailReason() != null) {
throw new RuntimeException("Failed to download image" + getFailReason().getType(),
getFailReason().getCause());
}
if (getBitmap() == null) {
throw new NullPointerException("Bitmap is null");
}
return getBitmap();
}
public Bitmap getBitmap() {
return bitmap;
}
public boolean isCancelled() {
return cancelled;
}
public FailReason getFailReason() {
return failReason;
}
}

View File

@ -17,8 +17,6 @@ import androidx.core.content.ContextCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.DownloaderImpl;
import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
@ -29,6 +27,7 @@ import org.schabi.newpipe.extractor.localization.ContentCountry;
import org.schabi.newpipe.extractor.localization.Localization;
import org.schabi.newpipe.streams.io.StoredFileHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.ZipHelper;
import java.io.File;
@ -50,7 +49,6 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
private ContentSettingsManager manager;
private String importExportDataPathKey;
private String thumbnailLoadToggleKey;
private String youtubeRestrictedModeEnabledKey;
private Localization initialSelectedLocalization;
@ -69,7 +67,6 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
manager.deleteSettingsFile();
importExportDataPathKey = getString(R.string.import_export_data_path);
thumbnailLoadToggleKey = getString(R.string.download_thumbnail_key);
youtubeRestrictedModeEnabledKey = getString(R.string.youtube_restricted_mode_enabled);
addPreferencesFromResource(R.xml.content_settings);
@ -112,20 +109,24 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
if (defaultPreferences.getString(getString(R.string.recaptcha_cookies_key), "").isEmpty()) {
clearCookiePref.setVisible(false);
}
findPreference(getString(R.string.download_thumbnail_key)).setOnPreferenceChangeListener(
(preference, newValue) -> {
PicassoHelper.setShouldLoadImages((Boolean) newValue);
try {
PicassoHelper.clearCache(preference.getContext());
Toast.makeText(preference.getContext(),
R.string.thumbnail_cache_wipe_complete_notice, Toast.LENGTH_SHORT)
.show();
} catch (final IOException e) {
Log.e(TAG, "Unable to clear Picasso cache", e);
}
return true;
});
}
@Override
public boolean onPreferenceTreeClick(final Preference preference) {
if (preference.getKey().equals(thumbnailLoadToggleKey)) {
final ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.stop();
imageLoader.clearDiskCache();
imageLoader.clearMemoryCache();
imageLoader.resume();
Toast.makeText(preference.getContext(), R.string.thumbnail_cache_wipe_complete_notice,
Toast.LENGTH_SHORT).show();
}
if (preference.getKey().equals(youtubeRestrictedModeEnabledKey)) {
final Context context = getContext();
if (context != null) {

View File

@ -14,13 +14,11 @@ import androidx.fragment.app.DialogFragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.error.ErrorActivity;
import org.schabi.newpipe.local.subscription.SubscriptionManager;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.util.List;
@ -54,13 +52,6 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
*/
public class SelectChannelFragment extends DialogFragment {
/**
* This contains the base display options for images.
*/
private static final DisplayImageOptions DISPLAY_IMAGE_OPTIONS
= new DisplayImageOptions.Builder().cacheInMemory(true).build();
private final ImageLoader imageLoader = ImageLoader.getInstance();
private OnSelectedListener onSelectedListener = null;
private OnCancelListener onCancelListener = null;
@ -199,8 +190,7 @@ public class SelectChannelFragment extends DialogFragment {
final SubscriptionEntity entry = subscriptions.get(position);
holder.titleView.setText(entry.getName());
holder.view.setOnClickListener(view -> clickedItem(position));
imageLoader.displayImage(entry.getAvatarUrl(), holder.thumbnailView,
DISPLAY_IMAGE_OPTIONS);
PicassoHelper.loadAvatar(entry.getAvatarUrl()).into(holder.thumbnailView);
}
@Override

View File

@ -14,9 +14,6 @@ import androidx.fragment.app.DialogFragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.AppDatabase;
@ -29,6 +26,7 @@ import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
import org.schabi.newpipe.util.PicassoHelper;
import java.util.List;
import java.util.Vector;
@ -38,13 +36,6 @@ import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.disposables.Disposable;
public class SelectPlaylistFragment extends DialogFragment {
/**
* This contains the base display options for images.
*/
private static final DisplayImageOptions DISPLAY_IMAGE_OPTIONS
= new DisplayImageOptions.Builder().cacheInMemory(true).build();
private final ImageLoader imageLoader = ImageLoader.getInstance();
private OnSelectedListener onSelectedListener = null;
@ -170,16 +161,15 @@ public class SelectPlaylistFragment extends DialogFragment {
holder.titleView.setText(entry.name);
holder.view.setOnClickListener(view -> clickedItem(position));
imageLoader.displayImage(entry.thumbnailUrl, holder.thumbnailView,
DISPLAY_IMAGE_OPTIONS);
PicassoHelper.loadPlaylistThumbnail(entry.thumbnailUrl).into(holder.thumbnailView);
} else if (selectedItem instanceof PlaylistRemoteEntity) {
final PlaylistRemoteEntity entry = ((PlaylistRemoteEntity) selectedItem);
holder.titleView.setText(entry.getName());
holder.view.setOnClickListener(view -> clickedItem(position));
imageLoader.displayImage(entry.getThumbnailUrl(), holder.thumbnailView,
DISPLAY_IMAGE_OPTIONS);
PicassoHelper.loadPlaylistThumbnail(entry.getThumbnailUrl())
.into(holder.thumbnailView);
}
}

View File

@ -1,65 +0,0 @@
package org.schabi.newpipe.util;
import android.graphics.Bitmap;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import org.schabi.newpipe.R;
public final class ImageDisplayConstants {
private static final int BITMAP_FADE_IN_DURATION_MILLIS = 250;
/**
* This constant contains the base display options.
*/
private static final DisplayImageOptions BASE_DISPLAY_IMAGE_OPTIONS =
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.resetViewBeforeLoading(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.imageScaleType(ImageScaleType.EXACTLY)
.displayer(new FadeInBitmapDisplayer(BITMAP_FADE_IN_DURATION_MILLIS))
.build();
/*//////////////////////////////////////////////////////////////////////////
// DisplayImageOptions default configurations
//////////////////////////////////////////////////////////////////////////*/
public static final DisplayImageOptions DISPLAY_AVATAR_OPTIONS =
new DisplayImageOptions.Builder()
.cloneFrom(BASE_DISPLAY_IMAGE_OPTIONS)
.showImageForEmptyUri(R.drawable.buddy)
.showImageOnFail(R.drawable.buddy)
.build();
public static final DisplayImageOptions DISPLAY_THUMBNAIL_OPTIONS =
new DisplayImageOptions.Builder()
.cloneFrom(BASE_DISPLAY_IMAGE_OPTIONS)
.showImageForEmptyUri(R.drawable.dummy_thumbnail)
.showImageOnFail(R.drawable.dummy_thumbnail)
.build();
public static final DisplayImageOptions DISPLAY_BANNER_OPTIONS =
new DisplayImageOptions.Builder()
.cloneFrom(BASE_DISPLAY_IMAGE_OPTIONS)
.showImageForEmptyUri(R.drawable.channel_banner)
.showImageOnFail(R.drawable.channel_banner)
.build();
public static final DisplayImageOptions DISPLAY_PLAYLIST_OPTIONS =
new DisplayImageOptions.Builder()
.cloneFrom(BASE_DISPLAY_IMAGE_OPTIONS)
.showImageForEmptyUri(R.drawable.dummy_thumbnail_playlist)
.showImageOnFail(R.drawable.dummy_thumbnail_playlist)
.build();
public static final DisplayImageOptions DISPLAY_SEEKBAR_PREVIEW_OPTIONS =
new DisplayImageOptions.Builder()
.cloneFrom(BASE_DISPLAY_IMAGE_OPTIONS)
.build();
private ImageDisplayConstants() { }
}

View File

@ -18,8 +18,6 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
@ -259,10 +257,9 @@ public final class NavigationHelper {
if (context instanceof Activity) {
new AlertDialog.Builder(context)
.setMessage(R.string.no_player_found)
.setPositiveButton(R.string.install, (dialog, which) -> {
ShareUtils.openUrlInBrowser(context,
context.getString(R.string.fdroid_vlc_url), false);
})
.setPositiveButton(R.string.install,
(dialog, which) -> ShareUtils.openUrlInBrowser(context,
context.getString(R.string.fdroid_vlc_url), false))
.setNegativeButton(R.string.cancel, (dialog, which)
-> Log.i("NavigationHelper", "You unlocked a secret unicorn."))
.show();
@ -284,8 +281,6 @@ public final class NavigationHelper {
}
public static void gotoMainFragment(final FragmentManager fragmentManager) {
ImageLoader.getInstance().clearMemoryCache();
final boolean popped = fragmentManager.popBackStackImmediate(MAIN_FRAGMENT_TAG, 0);
if (!popped) {
openMainFragment(fragmentManager);

View File

@ -0,0 +1,110 @@
package org.schabi.newpipe.util;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import com.squareup.picasso.Cache;
import com.squareup.picasso.LruCache;
import com.squareup.picasso.OkHttp3Downloader;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.RequestCreator;
import org.schabi.newpipe.R;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
public final class PicassoHelper {
private PicassoHelper() {
}
private static Cache picassoCache;
private static OkHttpClient picassoDownloaderClient;
// suppress because terminate() is called in App.onTerminate(), preventing leaks
@SuppressLint("StaticFieldLeak")
private static Picasso picassoInstance;
private static boolean shouldLoadImages;
public static void init(final Context context) {
picassoCache = new LruCache(10 * 1024 * 1024);
picassoDownloaderClient = new OkHttpClient.Builder()
.cache(new okhttp3.Cache(new File(context.getExternalCacheDir(), "picasso"),
50 * 1024 * 1024))
// this should already be the default timeout in OkHttp3, but just to be sure...
.callTimeout(15, TimeUnit.SECONDS)
.build();
picassoInstance = new Picasso.Builder(context)
.memoryCache(picassoCache) // memory cache
.downloader(new OkHttp3Downloader(picassoDownloaderClient)) // disk cache
.defaultBitmapConfig(Bitmap.Config.RGB_565)
.build();
}
public static void terminate() {
picassoCache = null;
picassoDownloaderClient = null;
if (picassoInstance != null) {
picassoInstance.shutdown();
picassoInstance = null;
}
}
public static void clearCache(final Context context) throws IOException {
picassoInstance.shutdown();
picassoCache.clear(); // clear memory cache
picassoDownloaderClient.cache().delete(); // clear disk cache
init(context);
}
public static void cancelTag(final Object tag) {
picassoInstance.cancelTag(tag);
}
public static void setShouldLoadImages(final boolean shouldLoadImages) {
PicassoHelper.shouldLoadImages = shouldLoadImages;
}
public static boolean getShouldLoadImages() {
return shouldLoadImages;
}
public static RequestCreator loadAvatar(final String url) {
return loadImageDefault(url, R.drawable.buddy);
}
public static RequestCreator loadThumbnail(final String url) {
return loadImageDefault(url, R.drawable.dummy_thumbnail);
}
public static RequestCreator loadBanner(final String url) {
return loadImageDefault(url, R.drawable.channel_banner);
}
public static RequestCreator loadPlaylistThumbnail(final String url) {
return loadImageDefault(url, R.drawable.dummy_thumbnail_playlist);
}
public static RequestCreator loadSeekbarThumbnailPreview(final String url) {
return picassoInstance.load(url);
}
private static RequestCreator loadImageDefault(final String url, final int placeholderResId) {
return picassoInstance
.load((!shouldLoadImages || isBlank(url)) ? null : url)
.placeholder(placeholderResId)
.error(placeholderResId);
}
}