mirror of
https://github.com/AntennaPod/AntennaPod.git
synced 2025-02-02 03:36:48 +01:00
Merge pull request #2859 from ByteHamster/glide-48
Upgraded Glide to version 4.8.0
This commit is contained in:
commit
d7e7684cc0
@ -162,6 +162,7 @@ dependencies {
|
||||
implementation "commons-io:commons-io:$commonsioVersion"
|
||||
implementation "org.jsoup:jsoup:$jsoupVersion"
|
||||
implementation "com.github.bumptech.glide:glide:$glideVersion"
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:$glideVersion"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
||||
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
|
||||
implementation "com.squareup.okio:okio:$okioVersion"
|
||||
|
@ -391,10 +391,6 @@
|
||||
android:resource="@xml/provider_paths"/>
|
||||
</provider>
|
||||
|
||||
<meta-data
|
||||
android:name="de.danoeh.antennapod.core.glide.ApGlideModule"
|
||||
android:value="GlideModule" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.car.application"
|
||||
android:resource="@xml/automotive_app_desc"/>
|
||||
|
@ -18,6 +18,7 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -122,19 +123,21 @@ public class FeedInfoActivity extends AppCompatActivity {
|
||||
Log.d(TAG, "URL is " + feed.getDownload_url());
|
||||
Glide.with(FeedInfoActivity.this)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
Glide.with(FeedInfoActivity.this)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation(FeedInfoActivity.this))
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation())
|
||||
.dontAnimate())
|
||||
.into(imgvBackground);
|
||||
|
||||
txtvTitle.setText(feed.getTitle());
|
||||
|
@ -25,6 +25,7 @@ import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
||||
@ -153,19 +154,21 @@ public class FeedSettingsActivity extends AppCompatActivity {
|
||||
FeedPreferences prefs = feed.getPreferences();
|
||||
Glide.with(FeedSettingsActivity.this)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
Glide.with(FeedSettingsActivity.this)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation(FeedSettingsActivity.this))
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation())
|
||||
.dontAnimate())
|
||||
.into(imgvBackground);
|
||||
|
||||
txtvTitle.setText(feed.getTitle());
|
||||
|
@ -28,6 +28,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
@ -397,11 +398,12 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
if (StringUtils.isNotBlank(feed.getImageUrl())) {
|
||||
Glide.with(this)
|
||||
.load(feed.getImageUrl())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(cover);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@ import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
@ -29,7 +28,6 @@ import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
@ -193,12 +191,12 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
|
||||
holder.butSecondary.setTag(item);
|
||||
holder.butSecondary.setOnClickListener(secondaryActionListener);
|
||||
|
||||
Glide.with(mainActivityRef.get())
|
||||
.load(item.getImageLocation())
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(new CoverTarget(item.getFeed().getImageLocation(), holder.placeholder, holder.cover, mainActivityRef.get()));
|
||||
new CoverLoader(mainActivityRef.get())
|
||||
.withUri(item.getImageLocation())
|
||||
.withFallbackUri(item.getFeed().getImageLocation())
|
||||
.withPlaceholderView(holder.placeholder)
|
||||
.withCoverView(holder.cover)
|
||||
.load();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
113
app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
Normal file
113
app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
Normal file
@ -0,0 +1,113 @@
|
||||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.CustomViewTarget;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
|
||||
public class CoverLoader {
|
||||
private String uri;
|
||||
private String fallbackUri;
|
||||
private TextView txtvPlaceholder;
|
||||
private ImageView imgvCover;
|
||||
private MainActivity activity;
|
||||
private int errorResource = -1;
|
||||
|
||||
public CoverLoader(MainActivity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public CoverLoader withUri(String uri) {
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withFallbackUri(String uri) {
|
||||
fallbackUri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withCoverView(ImageView coverView) {
|
||||
imgvCover = coverView;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withError(int errorResource) {
|
||||
this.errorResource = errorResource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withPlaceholderView(TextView placeholderView) {
|
||||
txtvPlaceholder = placeholderView;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void load() {
|
||||
RequestOptions options = new RequestOptions()
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate();
|
||||
|
||||
if (errorResource != -1) {
|
||||
options = options.error(errorResource);
|
||||
}
|
||||
|
||||
RequestBuilder builder = Glide.with(activity)
|
||||
.load(uri)
|
||||
.apply(options);
|
||||
|
||||
if (fallbackUri != null && txtvPlaceholder != null && imgvCover != null) {
|
||||
builder = builder.error(Glide.with(activity)
|
||||
.load(fallbackUri)
|
||||
.apply(options));
|
||||
}
|
||||
|
||||
builder.into(new CoverTarget(txtvPlaceholder, imgvCover));
|
||||
}
|
||||
|
||||
class CoverTarget extends CustomViewTarget<ImageView, Drawable> {
|
||||
private final WeakReference<TextView> placeholder;
|
||||
private final WeakReference<ImageView> cover;
|
||||
|
||||
public CoverTarget(TextView txtvPlaceholder, ImageView imgvCover) {
|
||||
super(imgvCover);
|
||||
placeholder = new WeakReference<>(txtvPlaceholder);
|
||||
cover = new WeakReference<>(imgvCover);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Drawable errorDrawable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
|
||||
TextView txtvPlaceholder = placeholder.get();
|
||||
if (txtvPlaceholder != null) {
|
||||
txtvPlaceholder.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
ImageView ivCover = cover.get();
|
||||
ivCover.setImageDrawable(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResourceCleared(@Nullable Drawable placeholder) {
|
||||
ImageView ivCover = cover.get();
|
||||
ivCover.setImageDrawable(placeholder);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
|
||||
class CoverTarget extends GlideDrawableImageViewTarget {
|
||||
|
||||
private final WeakReference<String> fallback;
|
||||
private final WeakReference<TextView> placeholder;
|
||||
private final WeakReference<ImageView> cover;
|
||||
private final WeakReference<MainActivity> mainActivity;
|
||||
|
||||
public CoverTarget(String fallbackUri, TextView txtvPlaceholder, ImageView imgvCover, MainActivity activity) {
|
||||
super(imgvCover);
|
||||
fallback = new WeakReference<>(fallbackUri);
|
||||
placeholder = new WeakReference<>(txtvPlaceholder);
|
||||
cover = new WeakReference<>(imgvCover);
|
||||
mainActivity = new WeakReference<>(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
||||
String fallbackUri = fallback.get();
|
||||
TextView txtvPlaceholder = placeholder.get();
|
||||
ImageView imgvCover = cover.get();
|
||||
if (fallbackUri != null && txtvPlaceholder != null && imgvCover != null) {
|
||||
MainActivity activity = mainActivity.get();
|
||||
Glide.with(activity)
|
||||
.load(fallbackUri)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(new CoverTarget(null, txtvPlaceholder, imgvCover, activity));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceReady(GlideDrawable drawable, GlideAnimation<? super GlideDrawable> anim) {
|
||||
super.onResourceReady(drawable, anim);
|
||||
TextView txtvPlaceholder = placeholder.get();
|
||||
if (txtvPlaceholder != null) {
|
||||
txtvPlaceholder.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
@ -79,11 +80,12 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
|
||||
|
||||
Glide.with(context)
|
||||
.load(item.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.imageView);
|
||||
|
||||
if(item.isPlayed()) {
|
||||
|
@ -17,6 +17,7 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.joanzapata.iconify.widget.IconTextView;
|
||||
|
||||
@ -336,11 +337,12 @@ public class NavListAdapter extends BaseAdapter
|
||||
|
||||
Glide.with(context)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.image);
|
||||
|
||||
holder.title.setText(feed.getTitle());
|
||||
|
@ -23,6 +23,7 @@ import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
@ -291,12 +292,12 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
||||
butSecondary.setTag(item);
|
||||
butSecondary.setOnClickListener(secondaryActionListener);
|
||||
|
||||
Glide.with(mainActivity.get())
|
||||
.load(item.getImageLocation())
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(new CoverTarget(item.getFeed().getImageLocation(), placeholder, cover, mainActivity.get()));
|
||||
new CoverLoader(mainActivity.get())
|
||||
.withUri(item.getImageLocation())
|
||||
.withFallbackUri(item.getFeed().getImageLocation())
|
||||
.withPlaceholderView(placeholder)
|
||||
.withCoverView(cover)
|
||||
.load();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedComponent;
|
||||
@ -81,11 +82,12 @@ public class SearchlistAdapter extends BaseAdapter {
|
||||
|
||||
Glide.with(context)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.cover);
|
||||
|
||||
} else if (component.getClass() == FeedItem.class) {
|
||||
@ -100,11 +102,12 @@ public class SearchlistAdapter extends BaseAdapter {
|
||||
|
||||
Glide.with(context)
|
||||
.load(item.getFeed().getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.cover);
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import com.bumptech.glide.Glide;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
@ -72,11 +73,12 @@ public class StatisticsListAdapter extends BaseAdapter {
|
||||
|
||||
Glide.with(context)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.image);
|
||||
|
||||
holder.title.setText(feed.getTitle());
|
||||
|
@ -14,6 +14,7 @@ import com.bumptech.glide.Glide;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
@ -108,7 +109,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
|
||||
holder.count.setVisibility(View.INVISIBLE);
|
||||
|
||||
// when this holder is reused, we could else end up with a cover image
|
||||
Glide.clear(holder.imageView);
|
||||
Glide.with(mainActivityRef.get()).clear(holder.imageView);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
@ -125,13 +126,13 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
|
||||
} else {
|
||||
holder.count.setVisibility(View.GONE);
|
||||
}
|
||||
Glide.with(mainActivityRef.get())
|
||||
.load(feed.getImageLocation())
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(new CoverTarget(null, holder.feedTitle, holder.imageView, mainActivityRef.get()));
|
||||
|
||||
new CoverLoader(mainActivityRef.get())
|
||||
.withUri(feed.getImageLocation())
|
||||
.withPlaceholderView(holder.feedTitle)
|
||||
.withCoverView(holder.imageView)
|
||||
.withError(R.color.light_gray)
|
||||
.load();
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
@ -52,11 +53,12 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> {
|
||||
if (StringUtils.isNotBlank(podcast.getLogoUrl())) {
|
||||
Glide.with(convertView.getContext())
|
||||
.load(podcast.getLogoUrl())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.image);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@ import android.widget.TextView;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@ -80,10 +82,11 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
||||
//Update the empty imageView with the image from the feed
|
||||
Glide.with(context)
|
||||
.load(podcast.imageUrl)
|
||||
.placeholder(R.color.light_gray)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(viewHolder.coverView);
|
||||
|
||||
//Feed the grid view
|
||||
|
@ -11,6 +11,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MediaplayerInfoActivity.MediaplayerInfoContentFragment;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
@ -60,9 +61,10 @@ public class CoverFragment extends Fragment implements MediaplayerInfoContentFra
|
||||
txtvEpisodeTitle.setText(media.getEpisodeTitle());
|
||||
Glide.with(this)
|
||||
.load(media.getImageLocation())
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.dontAnimate()
|
||||
.fitCenter()
|
||||
.apply(new RequestOptions()
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.dontAnimate()
|
||||
.fitCenter())
|
||||
.into(imgvCover);
|
||||
} else {
|
||||
Log.w(TAG, "loadMediaInfo was called while media was null");
|
||||
|
@ -16,6 +16,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
@ -207,11 +208,12 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
|
||||
Glide.with(getActivity())
|
||||
.load(media.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
|
||||
fragmentLayout.setVisibility(View.VISIBLE);
|
||||
|
@ -31,6 +31,7 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.joanzapata.iconify.widget.IconButton;
|
||||
|
||||
@ -378,11 +379,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
|
||||
Glide.with(getActivity())
|
||||
.load(item.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
|
||||
progbarDownload.setVisibility(View.GONE);
|
||||
|
@ -24,6 +24,8 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.IconDrawable;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.joanzapata.iconify.widget.IconTextView;
|
||||
|
||||
@ -518,20 +520,22 @@ public class ItemlistFragment extends ListFragment {
|
||||
private void loadFeedImage() {
|
||||
Glide.with(getActivity())
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation(getActivity()))
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation())
|
||||
.dontAnimate())
|
||||
.into(imgvBackground);
|
||||
|
||||
Glide.with(getActivity())
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@ -463,10 +464,10 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
|
||||
} else if (iconUri != null) {
|
||||
try {
|
||||
art = Glide.with(getContext().getApplicationContext())
|
||||
.load(iconUri.toString())
|
||||
.asBitmap()
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
|
||||
.load(iconUri.toString())
|
||||
.apply(RequestOptions.diskCacheStrategyOf(ApGlideSettings.AP_DISK_CACHE_STRATEGY))
|
||||
.submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
|
||||
.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Log.e(TAG, "Image art load failed", e);
|
||||
|
@ -49,8 +49,8 @@ project.ext {
|
||||
commonstextVersion = "1.3"
|
||||
eventbusVersion = "2.4.0"
|
||||
flattr4jVersion = "2.14"
|
||||
glideVersion = "3.8.0"
|
||||
glideOkhttpIntegrationVersion = "1.5.0"
|
||||
glideVersion = "4.8.0"
|
||||
glideOkhttpIntegrationVersion = "4.8.0"
|
||||
iconifyVersion = "2.2.2"
|
||||
jsoupVersion = "1.11.2"
|
||||
materialDialogsVersion = "0.9.0.2"
|
||||
|
@ -60,6 +60,7 @@ dependencies {
|
||||
implementation "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion"
|
||||
implementation "org.jsoup:jsoup:$jsoupVersion"
|
||||
implementation "com.github.bumptech.glide:glide:$glideVersion"
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:$glideVersion"
|
||||
implementation "com.github.bumptech.glide:okhttp3-integration:$glideOkhttpIntegrationVersion@aar"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
||||
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
|
||||
|
@ -2,31 +2,35 @@ package de.danoeh.antennapod.core.glide;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.GlideBuilder;
|
||||
import com.bumptech.glide.Registry;
|
||||
import com.bumptech.glide.annotation.GlideModule;
|
||||
import com.bumptech.glide.load.DecodeFormat;
|
||||
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory;
|
||||
import com.bumptech.glide.module.GlideModule;
|
||||
import com.bumptech.glide.module.AppGlideModule;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
|
||||
/**
|
||||
* {@see com.bumptech.glide.integration.okhttp.OkHttpGlideModule}
|
||||
*/
|
||||
public class ApGlideModule implements GlideModule {
|
||||
@GlideModule
|
||||
public class ApGlideModule extends AppGlideModule {
|
||||
|
||||
@Override
|
||||
public void applyOptions(Context context, GlideBuilder builder) {
|
||||
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
|
||||
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
|
||||
builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.PREFER_ARGB_8888));
|
||||
builder.setDiskCache(new InternalCacheDiskCacheFactory(context,
|
||||
UserPreferences.getImageCacheSize()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerComponents(Context context, Glide glide) {
|
||||
glide.register(String.class, InputStream.class, new ApOkHttpUrlLoader.Factory());
|
||||
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
|
||||
registry.append(String.class, InputStream.class, new ApOkHttpUrlLoader.Factory());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package de.danoeh.antennapod.core.glide;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher;
|
||||
import com.bumptech.glide.load.data.DataFetcher;
|
||||
import com.bumptech.glide.load.model.GenericLoaderFactory;
|
||||
import com.bumptech.glide.load.Options;
|
||||
import com.bumptech.glide.load.model.GlideUrl;
|
||||
import com.bumptech.glide.load.model.ModelLoader;
|
||||
import com.bumptech.glide.load.model.ModelLoaderFactory;
|
||||
@ -15,6 +15,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
import com.bumptech.glide.load.model.MultiModelLoaderFactory;
|
||||
import com.bumptech.glide.signature.ObjectKey;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.service.download.HttpDownloader;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
@ -56,19 +58,20 @@ class ApOkHttpUrlLoader implements ModelLoader<String, InputStream> {
|
||||
/**
|
||||
* Constructor for a new Factory that runs requests using a static singleton client.
|
||||
*/
|
||||
public Factory() {
|
||||
Factory() {
|
||||
this(getInternalClient());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a new Factory that runs requests using given client.
|
||||
*/
|
||||
public Factory(OkHttpClient client) {
|
||||
Factory(OkHttpClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ModelLoader<String, InputStream> build(Context context, GenericLoaderFactory factories) {
|
||||
public ModelLoader<String, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
|
||||
return new ApOkHttpUrlLoader(client);
|
||||
}
|
||||
|
||||
@ -84,20 +87,26 @@ class ApOkHttpUrlLoader implements ModelLoader<String, InputStream> {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DataFetcher<InputStream> getResourceFetcher(String model, int width, int height) {
|
||||
Log.d(TAG, "getResourceFetcher() called with: " + "model = [" + model + "], width = ["
|
||||
public LoadData<InputStream> buildLoadData(@NonNull String model, int width, int height, @NonNull Options options) {
|
||||
Log.d(TAG, "buildLoadData() called with: " + "model = [" + model + "], width = ["
|
||||
+ width + "], height = [" + height + "]");
|
||||
if(TextUtils.isEmpty(model)) {
|
||||
return null;
|
||||
} else if(model.startsWith("/")) {
|
||||
return new AudioCoverFetcher(model);
|
||||
return new LoadData<>(new ObjectKey(model), new AudioCoverFetcher(model));
|
||||
} else {
|
||||
GlideUrl url = new GlideUrl(model);
|
||||
return new OkHttpStreamFetcher(client, url);
|
||||
return new LoadData<>(new ObjectKey(model), new OkHttpStreamFetcher(client, url));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handles(@NonNull String s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class NetworkAllowanceInterceptor implements Interceptor {
|
||||
|
||||
@Override
|
||||
|
@ -2,7 +2,9 @@ package de.danoeh.antennapod.core.glide;
|
||||
|
||||
import android.media.MediaMetadataRetriever;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import com.bumptech.glide.Priority;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.data.DataFetcher;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
@ -20,22 +22,20 @@ class AudioCoverFetcher implements DataFetcher<InputStream> {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override public String getId() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override public InputStream loadData(Priority priority) throws Exception {
|
||||
@Override
|
||||
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
try {
|
||||
retriever.setDataSource(path);
|
||||
byte[] picture = retriever.getEmbeddedPicture();
|
||||
if (picture != null) {
|
||||
return new ByteArrayInputStream(picture);
|
||||
callback.onDataReady(new ByteArrayInputStream(picture));
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
retriever.release();
|
||||
}
|
||||
throw new IOException("Loading embedded cover did not work");
|
||||
callback.onLoadFailed(new IOException("Loading embedded cover did not work"));
|
||||
}
|
||||
|
||||
@Override public void cleanup() {
|
||||
@ -44,4 +44,16 @@ class AudioCoverFetcher implements DataFetcher<InputStream> {
|
||||
@Override public void cancel() {
|
||||
// cannot cancel
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Class<InputStream> getDataClass() {
|
||||
return InputStream.class;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DataSource getDataSource() {
|
||||
return DataSource.LOCAL;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
package de.danoeh.antennapod.core.glide;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.ThumbnailUtils;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class FastBlurTransformation extends BitmapTransformation {
|
||||
|
||||
private static final String TAG = FastBlurTransformation.class.getSimpleName();
|
||||
@ -15,8 +17,8 @@ public class FastBlurTransformation extends BitmapTransformation {
|
||||
private static final int STACK_BLUR_RADIUS = 1;
|
||||
private static final int BLUR_IMAGE_WIDTH = 150;
|
||||
|
||||
public FastBlurTransformation(Context context) {
|
||||
super(context);
|
||||
public FastBlurTransformation() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -33,11 +35,6 @@ public class FastBlurTransformation extends BitmapTransformation {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "FastBlurTransformation[width=" + BLUR_IMAGE_WIDTH + "px,radius=" + STACK_BLUR_RADIUS +"]";
|
||||
}
|
||||
|
||||
private static Bitmap fastBlur(Bitmap bitmap, int radius) {
|
||||
|
||||
// Stack Blur v1.0 from
|
||||
@ -264,4 +261,8 @@ public class FastBlurTransformation extends BitmapTransformation {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
|
||||
messageDigest.update(TAG.getBytes());
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ import android.view.SurfaceHolder;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -1165,10 +1166,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, imageLocation);
|
||||
try {
|
||||
Bitmap art = Glide.with(this)
|
||||
.load(imageLocation)
|
||||
.asBitmap()
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
|
||||
.load(imageLocation)
|
||||
.apply(RequestOptions.diskCacheStrategyOf(ApGlideSettings.AP_DISK_CACHE_STRATEGY))
|
||||
.submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
|
||||
.get();
|
||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
|
||||
} catch (Throwable tr) {
|
||||
@ -1239,11 +1240,11 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
android.R.dimen.notification_large_icon_width);
|
||||
try {
|
||||
icon = Glide.with(PlaybackService.this)
|
||||
.load(playable.getImageLocation())
|
||||
.asBitmap()
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.centerCrop()
|
||||
.into(iconSize, iconSize)
|
||||
.load(playable.getImageLocation())
|
||||
.apply(RequestOptions.diskCacheStrategyOf(ApGlideSettings.AP_DISK_CACHE_STRATEGY))
|
||||
.apply(new RequestOptions().centerCrop())
|
||||
.submit(iconSize, iconSize)
|
||||
.get();
|
||||
} catch (Throwable tr) {
|
||||
Log.e(TAG, "Error loading the media icon for the notification", tr);
|
||||
|
Loading…
x
Reference in New Issue
Block a user