From dec0832b6e6b28d634c5c6afe6d71a4023329c3e Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 21 Jun 2019 14:56:12 +0200 Subject: [PATCH] feat: replace artist image by a mosaic of covers --- .../gramophone/glide/ArtistGlideRequest.java | 27 +-- .../glide/PhonographGlideModule.java | 6 +- .../glide/artistimage/AlbumCover.java | 37 ++++ .../glide/artistimage/ArtistImage.java | 11 +- .../glide/artistimage/ArtistImageFetcher.java | 166 +++++++++++++----- .../glide/artistimage/ArtistImageLoader.java | 47 +---- .../audiocover/AudioFileCoverFetcher.java | 59 ++----- .../glide/audiocover/AudioFileCoverUtils.java | 49 ++++++ .../ui/activities/ArtistDetailActivity.java | 36 ++-- .../kabouzeid/gramophone/util/ImageUtil.java | 9 + 10 files changed, 281 insertions(+), 166 deletions(-) create mode 100644 app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/AlbumCover.java create mode 100644 app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverUtils.java diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/ArtistGlideRequest.java b/app/src/main/java/com/kabouzeid/gramophone/glide/ArtistGlideRequest.java index 04a6fd78..6ffeba72 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/glide/ArtistGlideRequest.java +++ b/app/src/main/java/com/kabouzeid/gramophone/glide/ArtistGlideRequest.java @@ -4,6 +4,9 @@ import android.content.Context; import android.graphics.Bitmap; import androidx.annotation.NonNull; +import java.util.ArrayList; +import java.util.List; + import com.bumptech.glide.BitmapRequestBuilder; import com.bumptech.glide.DrawableRequestBuilder; import com.bumptech.glide.DrawableTypeRequest; @@ -15,10 +18,13 @@ import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.target.Target; import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.glide.artistimage.AlbumCover; import com.kabouzeid.gramophone.glide.artistimage.ArtistImage; import com.kabouzeid.gramophone.glide.palette.BitmapPaletteTranscoder; import com.kabouzeid.gramophone.glide.palette.BitmapPaletteWrapper; +import com.kabouzeid.gramophone.model.Album; import com.kabouzeid.gramophone.model.Artist; +import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.util.ArtistSignatureUtil; import com.kabouzeid.gramophone.util.CustomArtistImageUtil; @@ -35,7 +41,6 @@ public class ArtistGlideRequest { final RequestManager requestManager; final Artist artist; boolean noCustomImage; - boolean forceDownload; public static Builder from(@NonNull RequestManager requestManager, Artist artist) { return new Builder(requestManager, artist); @@ -59,14 +64,9 @@ public class ArtistGlideRequest { return this; } - public Builder forceDownload(boolean forceDownload) { - this.forceDownload = forceDownload; - return this; - } - public DrawableRequestBuilder build() { //noinspection unchecked - return createBaseRequest(requestManager, artist, noCustomImage, forceDownload) + return createBaseRequest(requestManager, artist, noCustomImage) .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) .error(DEFAULT_ERROR_IMAGE) .animate(DEFAULT_ANIMATION) @@ -85,7 +85,7 @@ public class ArtistGlideRequest { public BitmapRequestBuilder build() { //noinspection unchecked - return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage, builder.forceDownload) + return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage) .asBitmap() .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) .error(DEFAULT_ERROR_IMAGE) @@ -107,7 +107,7 @@ public class ArtistGlideRequest { public BitmapRequestBuilder build() { //noinspection unchecked - return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage, builder.forceDownload) + return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage) .asBitmap() .transcode(new BitmapPaletteTranscoder(context), BitmapPaletteWrapper.class) .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) @@ -119,10 +119,15 @@ public class ArtistGlideRequest { } } - public static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist, boolean noCustomImage, boolean forceDownload) { + public static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist, boolean noCustomImage) { boolean hasCustomImage = CustomArtistImageUtil.getInstance(App.getInstance()).hasCustomArtistImage(artist); if (noCustomImage || !hasCustomImage) { - return requestManager.load(new ArtistImage(artist.getName(), forceDownload)); + final List songs = new ArrayList<>(); + for (final Album album : artist.albums) { + final Song song = album.safeGetFirstSong(); + songs.add(new AlbumCover(album.getYear(), song.data)); + } + return requestManager.load(new ArtistImage(artist.getName(), songs)); } else { return requestManager.load(CustomArtistImageUtil.getFile(artist)); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/PhonographGlideModule.java b/app/src/main/java/com/kabouzeid/gramophone/glide/PhonographGlideModule.java index 5feb54eb..407c28e0 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/glide/PhonographGlideModule.java +++ b/app/src/main/java/com/kabouzeid/gramophone/glide/PhonographGlideModule.java @@ -2,6 +2,8 @@ package com.kabouzeid.gramophone.glide; import android.content.Context; +import java.io.InputStream; + import com.bumptech.glide.Glide; import com.bumptech.glide.GlideBuilder; import com.bumptech.glide.module.GlideModule; @@ -10,8 +12,6 @@ import com.kabouzeid.gramophone.glide.artistimage.ArtistImageLoader; import com.kabouzeid.gramophone.glide.audiocover.AudioFileCover; import com.kabouzeid.gramophone.glide.audiocover.AudioFileCoverLoader; -import java.io.InputStream; - /** * @author Karim Abou Zeid (kabouzeid) */ @@ -24,6 +24,6 @@ public class PhonographGlideModule implements GlideModule { @Override public void registerComponents(Context context, Glide glide) { glide.register(AudioFileCover.class, InputStream.class, new AudioFileCoverLoader.Factory()); - glide.register(ArtistImage.class, InputStream.class, new ArtistImageLoader.Factory(context)); + glide.register(ArtistImage.class, InputStream.class, new ArtistImageLoader.Factory()); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/AlbumCover.java b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/AlbumCover.java new file mode 100644 index 00000000..9f026078 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/AlbumCover.java @@ -0,0 +1,37 @@ +package com.kabouzeid.gramophone.glide.artistimage; + +/** + * Used to define the artist cover + */ +public class AlbumCover { + + private int year; + + private String filePath; + + public AlbumCover(int year, String filePath) { + + this.filePath = filePath; + this.year = year; + } + + public int getYear() { + + return year; + } + + public void setYear(int year) { + + this.year = year; + } + + public String getFilePath() { + + return filePath; + } + + public void setFilePath(String filePath) { + + this.filePath = filePath; + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImage.java b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImage.java index 4c3803bb..a3df544e 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImage.java +++ b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImage.java @@ -1,14 +1,19 @@ package com.kabouzeid.gramophone.glide.artistimage; +import java.util.List; + /** * @author Karim Abou Zeid (kabouzeid) */ public class ArtistImage { public final String artistName; - public final boolean skipOkHttpCache; - public ArtistImage(String artistName, boolean skipOkHttpCache) { + // filePath to get the image of the artist + public final List albumCovers; + + public ArtistImage(String artistName, final List albumCovers) { + this.artistName = artistName; - this.skipOkHttpCache = skipOkHttpCache; + this.albumCovers = albumCovers; } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageFetcher.java b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageFetcher.java index e554755f..bb45d6e6 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageFetcher.java +++ b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageFetcher.java @@ -1,43 +1,36 @@ package com.kabouzeid.gramophone.glide.artistimage; -import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.media.MediaMetadataRetriever; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import com.bumptech.glide.Priority; import com.bumptech.glide.load.data.DataFetcher; -import com.bumptech.glide.load.model.GlideUrl; -import com.bumptech.glide.load.model.ModelLoader; -import com.kabouzeid.gramophone.lastfm.rest.LastFMRestClient; -import com.kabouzeid.gramophone.lastfm.rest.model.LastFmArtist; -import com.kabouzeid.gramophone.util.LastFMUtil; -import com.kabouzeid.gramophone.util.MusicUtil; -import com.kabouzeid.gramophone.util.PreferenceUtil; - -import java.io.IOException; -import java.io.InputStream; - -import retrofit2.Response; +import com.kabouzeid.gramophone.glide.audiocover.AudioFileCoverUtils; +import com.kabouzeid.gramophone.util.ImageUtil; /** * @author Karim Abou Zeid (kabouzeid) */ public class ArtistImageFetcher implements DataFetcher { - private Context context; - private final LastFMRestClient lastFMRestClient; private final ArtistImage model; - private ModelLoader urlLoader; - private final int width; - private final int height; - private volatile boolean isCancelled; - private DataFetcher urlFetcher; - public ArtistImageFetcher(Context context, LastFMRestClient lastFMRestClient, ArtistImage model, ModelLoader urlLoader, int width, int height) { - this.context = context; - this.lastFMRestClient = lastFMRestClient; + private InputStream stream; + + public ArtistImageFetcher(final ArtistImage model) { + this.model = model; - this.urlLoader = urlLoader; - this.width = width; - this.height = height; } @Override @@ -48,37 +41,126 @@ public class ArtistImageFetcher implements DataFetcher { @Override public InputStream loadData(Priority priority) throws Exception { - if (!MusicUtil.isArtistNameUnknown(model.artistName) && PreferenceUtil.isAllowedToDownloadMetadata(context)) { - Response response = lastFMRestClient.getApiService().getArtistInfo(model.artistName, null, model.skipOkHttpCache ? "no-cache" : null).execute(); - if (!response.isSuccessful()) { - throw new IOException("Request failed with code: " + response.code()); + return stream = getMosaic(model.albumCovers); + } + + private InputStream getMosaic(final List albumCovers) throws FileNotFoundException { + + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + + int artistBitMapSize = 512; + + final Map images = new HashMap<>(); + + InputStream result = null; + List streams = new ArrayList<>(); + + try { + for (final AlbumCover cover : albumCovers) { + + retriever.setDataSource(cover.getFilePath()); + byte[] picture = retriever.getEmbeddedPicture(); + final InputStream stream; + if (picture != null) { + stream = new ByteArrayInputStream(picture); + } else { + stream = AudioFileCoverUtils.fallback(cover.getFilePath()); + } + + if (stream != null) { + images.put(stream, cover.getYear()); + } } - LastFmArtist lastFmArtist = response.body(); + int nbImages = images.size(); - if (isCancelled) return null; + if (nbImages > 3) { + streams = new ArrayList<>(images.keySet()); - GlideUrl url = new GlideUrl(LastFMUtil.getLargestArtistImageUrl(lastFmArtist.getArtist().getImage())); - urlFetcher = urlLoader.getResourceFetcher(url, width, height); + int divisor = 1; + for (int i = 1; i < nbImages && Math.pow(i, 2) <= nbImages; ++i) { + divisor = i; + } + divisor += 1; + double nbTiles = Math.pow(divisor, 2); + + if (nbImages < nbTiles) { + divisor -= 1; + nbTiles = Math.pow(divisor, 2); + } + final int resize = (artistBitMapSize / divisor) + 1; + + final Bitmap bitmap = Bitmap.createBitmap(artistBitMapSize, artistBitMapSize, Bitmap.Config.RGB_565); + final Canvas canvas = new Canvas(bitmap); + + int x = 0; + int y = 0; + + for (int i = 0; i < streams.size() && i < nbTiles; ++i) { + final Bitmap bitmap1 = ImageUtil.resize(streams.get(i), resize, resize); + canvas.drawBitmap(bitmap1, x, y, null); + x += resize; + + if (x >= artistBitMapSize) { + x = 0; + y += resize; + } + } + + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); + result = new ByteArrayInputStream(bos.toByteArray()); + + } else if (nbImages > 0) { + // we return the last cover album of the artist + Map.Entry maxEntryYear = null; + + for (final Map.Entry entry : images.entrySet()) { + if (maxEntryYear == null || entry.getValue() + .compareTo(maxEntryYear.getValue()) > 0) { + maxEntryYear = entry; + } + } + + if (maxEntryYear != null) { + result = maxEntryYear.getKey(); + } else { + result = images.entrySet() + .iterator() + .next() + .getKey(); + } + + } + } finally { + retriever.release(); + try { + for (final InputStream stream : streams) { + stream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } - return urlFetcher.loadData(priority); } - return null; + return result; } @Override public void cleanup() { - if (urlFetcher != null) { - urlFetcher.cleanup(); + // already cleaned up in loadData and ByteArrayInputStream will be GC'd + if (stream != null) { + try { + stream.close(); + } catch (IOException ignore) { + // can't do much about it + } } } @Override public void cancel() { - isCancelled = true; - if (urlFetcher != null) { - urlFetcher.cancel(); - } + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageLoader.java b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageLoader.java index f99fef3a..c6a61ca0 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageLoader.java @@ -2,68 +2,37 @@ package com.kabouzeid.gramophone.glide.artistimage; import android.content.Context; -import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader; +import java.io.InputStream; + import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.model.GenericLoaderFactory; -import com.bumptech.glide.load.model.GlideUrl; import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.model.ModelLoaderFactory; import com.bumptech.glide.load.model.stream.StreamModelLoader; -import com.kabouzeid.gramophone.lastfm.rest.LastFMRestClient; - -import java.io.InputStream; -import java.util.concurrent.TimeUnit; - -import okhttp3.OkHttpClient; /** * @author Karim Abou Zeid (kabouzeid) */ public class ArtistImageLoader implements StreamModelLoader { - // we need these very low values to make sure our artist image loading calls doesn't block the image loading queue - private static final int TIMEOUT = 700; - - private Context context; - private LastFMRestClient lastFMClient; - private ModelLoader urlLoader; - - public ArtistImageLoader(Context context, LastFMRestClient lastFMRestClient, ModelLoader urlLoader) { - this.context = context; - this.lastFMClient = lastFMRestClient; - this.urlLoader = urlLoader; - } @Override - public DataFetcher getResourceFetcher(ArtistImage model, int width, int height) { - return new ArtistImageFetcher(context, lastFMClient, model, urlLoader, width, height); + public DataFetcher getResourceFetcher(final ArtistImage model, int width, int height) { + + return new ArtistImageFetcher(model); } public static class Factory implements ModelLoaderFactory { - private LastFMRestClient lastFMClient; - private OkHttpUrlLoader.Factory okHttpFactory; - - public Factory(Context context) { - okHttpFactory = new OkHttpUrlLoader.Factory(new OkHttpClient.Builder() - .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS) - .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS) - .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) - .build()); - lastFMClient = new LastFMRestClient(LastFMRestClient.createDefaultOkHttpClientBuilder(context) - .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS) - .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS) - .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) - .build()); - } @Override public ModelLoader build(Context context, GenericLoaderFactory factories) { - return new ArtistImageLoader(context, lastFMClient, okHttpFactory.build(context, factories)); + + return new ArtistImageLoader(); } @Override public void teardown() { - okHttpFactory.teardown(); + } } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverFetcher.java b/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverFetcher.java index efacb32f..e1deb6aa 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverFetcher.java +++ b/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverFetcher.java @@ -2,30 +2,23 @@ package com.kabouzeid.gramophone.glide.audiocover; import android.media.MediaMetadataRetriever; -import com.bumptech.glide.Priority; -import com.bumptech.glide.load.data.DataFetcher; - -import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; -import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; -import org.jaudiotagger.audio.mp3.MP3File; -import org.jaudiotagger.tag.TagException; -import org.jaudiotagger.tag.images.Artwork; - import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import com.bumptech.glide.Priority; +import com.bumptech.glide.load.data.DataFetcher; + /** * @author Karim Abou Zeid (kabouzeid) */ public class AudioFileCoverFetcher implements DataFetcher { private final AudioFileCover model; - private FileInputStream stream; + + private InputStream stream; public AudioFileCoverFetcher(AudioFileCover model) { + this.model = model; } @@ -36,50 +29,22 @@ public class AudioFileCoverFetcher implements DataFetcher { } @Override - public InputStream loadData(Priority priority) throws Exception { - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + public InputStream loadData(final Priority priority) throws Exception { + + final MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(model.filePath); byte[] picture = retriever.getEmbeddedPicture(); if (picture != null) { - return new ByteArrayInputStream(picture); + stream = new ByteArrayInputStream(picture); } else { - return fallback(model.filePath); + stream = AudioFileCoverUtils.fallback(model.filePath); } } finally { retriever.release(); } - } - private static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg", "cover.png", "album.png", "folder.png"}; - - private InputStream fallback(String path) throws FileNotFoundException { - // Method 1: use embedded high resolution album art if there is any - try { - MP3File mp3File = new MP3File(path); - if (mp3File.hasID3v2Tag()) { - Artwork art = mp3File.getTag().getFirstArtwork(); - if (art != null) { - byte[] imageData = art.getBinaryData(); - return new ByteArrayInputStream(imageData); - } - } - // If there are any exceptions, we ignore them and continue to the other fallback method - } catch (ReadOnlyFileException ignored) { - } catch (InvalidAudioFrameException ignored) { - } catch (TagException ignored) { - } catch (IOException ignored) { - } - - // Method 2: look for album art in external files - File parent = new File(path).getParentFile(); - for (String fallback : FALLBACKS) { - File cover = new File(parent, fallback); - if (cover.exists()) { - return stream = new FileInputStream(cover); - } - } - return null; + return stream; } @Override diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverUtils.java b/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverUtils.java new file mode 100644 index 00000000..51cbf994 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverUtils.java @@ -0,0 +1,49 @@ +package com.kabouzeid.gramophone.glide.audiocover; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.audio.mp3.MP3File; +import org.jaudiotagger.tag.TagException; +import org.jaudiotagger.tag.images.Artwork; + +public class AudioFileCoverUtils { + + public static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg", "cover.png", "album.png", "folder.png"}; + + + public static InputStream fallback(String path) throws FileNotFoundException { + // Method 1: use embedded high resolution album art if there is any + try { + MP3File mp3File = new MP3File(path); + if (mp3File.hasID3v2Tag()) { + Artwork art = mp3File.getTag().getFirstArtwork(); + if (art != null) { + byte[] imageData = art.getBinaryData(); + return new ByteArrayInputStream(imageData); + } + } + // If there are any exceptions, we ignore them and continue to the other fallback method + } catch (ReadOnlyFileException ignored) { + } catch (InvalidAudioFrameException ignored) { + } catch (TagException ignored) { + } catch (IOException ignored) { + } + + // Method 2: look for album art in external files + final File parent = new File(path).getParentFile(); + for (String fallback : FALLBACKS) { + File cover = new File(parent, fallback); + if (cover.exists()) { + return new FileInputStream(cover); + } + } + return null; + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java index 26fab885..a46ab160 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java @@ -4,13 +4,6 @@ import android.content.Context; import android.content.Intent; import android.graphics.PorterDuff; import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.loader.app.LoaderManager; -import androidx.loader.content.Loader; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.appcompat.widget.Toolbar; import android.text.Html; import android.text.Spanned; import android.view.LayoutInflater; @@ -20,6 +13,21 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.loader.app.LoaderManager; +import androidx.loader.content.Loader; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; +import butterknife.ButterKnife; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +import java.util.List; +import java.util.Locale; import com.afollestad.materialcab.MaterialCab; import com.afollestad.materialdialogs.MaterialDialog; @@ -53,16 +61,6 @@ import com.kabouzeid.gramophone.util.NavigationUtil; import com.kabouzeid.gramophone.util.PhonographColorUtil; import com.kabouzeid.gramophone.util.PreferenceUtil; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import butterknife.BindView; -import butterknife.ButterKnife; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - /** * Be careful when changing things in this Activity! */ @@ -113,7 +111,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement private LastFMRestClient lastFMRestClient; - private boolean forceDownload; private final SimpleObservableScrollViewCallbacks observableScrollViewCallbacks = new SimpleObservableScrollViewCallbacks() { @Override public void onScrollChanged(int scrollY, boolean b, boolean b2) { @@ -254,7 +251,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement private void loadArtistImage() { ArtistGlideRequest.Builder.from(Glide.with(this), artist) - .forceDownload(forceDownload) .generatePalette(this).build() .dontAnimate() .into(new PhonographColoredTarget(artistImage) { @@ -263,7 +259,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement setColors(color); } }); - forceDownload = false; } @Override @@ -375,7 +370,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement case R.id.action_reset_artist_image: Toast.makeText(ArtistDetailActivity.this, getResources().getString(R.string.updating), Toast.LENGTH_SHORT).show(); CustomArtistImageUtil.getInstance(ArtistDetailActivity.this).resetCustomArtistImage(artist); - forceDownload = true; return true; case R.id.action_colored_footers: item.setChecked(!item.isChecked()); diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/ImageUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/ImageUtil.java index 47e50ffd..5fa9ea8f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/ImageUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/ImageUtil.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.os.Build; @@ -14,6 +15,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; +import java.io.InputStream; + import com.kabouzeid.appthemehelper.util.TintHelper; /** @@ -109,4 +112,10 @@ public class ImageUtil { a.recycle(); return drawable; } + + public static Bitmap resize(InputStream stream, int scaledWidth, int scaledHeight) { + final Bitmap bitmap = BitmapFactory.decodeStream(stream); + return Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true); + + } }