Initial commit retro music app

This commit is contained in:
h4h13 2018-07-27 18:37:33 +05:30
parent ab332473bc
commit fe890632fd
932 changed files with 83126 additions and 0 deletions

View file

@ -0,0 +1,140 @@
package code.name.monkey.retromusic.glide;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import com.bumptech.glide.BitmapRequestBuilder;
import com.bumptech.glide.DrawableRequestBuilder;
import com.bumptech.glide.DrawableTypeRequest;
import com.bumptech.glide.Priority;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.target.Target;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.RetroApplication;
import code.name.monkey.retromusic.glide.artistimage.ArtistImage;
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder;
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
import code.name.monkey.retromusic.model.Artist;
import code.name.monkey.retromusic.util.ArtistSignatureUtil;
import code.name.monkey.retromusic.util.CustomArtistImageUtil;
public class ArtistGlideRequest {
private static final int DEFAULT_ANIMATION = android.R.anim.fade_in;
private static final DiskCacheStrategy DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.SOURCE;
private static final int DEFAULT_ERROR_IMAGE = R.drawable.default_artist_art;
private static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist,
boolean noCustomImage, boolean forceDownload) {
boolean hasCustomImage = CustomArtistImageUtil.getInstance(RetroApplication.getInstance())
.hasCustomArtistImage(artist);
if (noCustomImage || !hasCustomImage) {
return requestManager.load(new ArtistImage(artist.getName(), forceDownload));
} else {
return requestManager.load(CustomArtistImageUtil.getFile(artist));
}
}
private static Key createSignature(Artist artist) {
return ArtistSignatureUtil.getInstance(RetroApplication.getInstance())
.getArtistSignature(artist.getName());
}
public static class Builder {
final RequestManager requestManager;
final Artist artist;
boolean noCustomImage;
boolean forceDownload;
private Builder(@NonNull RequestManager requestManager, Artist artist) {
this.requestManager = requestManager;
this.artist = artist;
}
public static Builder from(@NonNull RequestManager requestManager, Artist artist) {
return new Builder(requestManager, artist);
}
public PaletteBuilder generatePalette(Context context) {
return new PaletteBuilder(this, context);
}
public BitmapBuilder asBitmap() {
return new BitmapBuilder(this);
}
public Builder noCustomImage(boolean noCustomImage) {
this.noCustomImage = noCustomImage;
return this;
}
public Builder forceDownload(boolean forceDownload) {
this.forceDownload = forceDownload;
return this;
}
public DrawableRequestBuilder<GlideDrawable> build() {
//noinspection unchecked
return createBaseRequest(requestManager, artist, noCustomImage, forceDownload)
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_IMAGE)
.animate(DEFAULT_ANIMATION)
.priority(Priority.LOW)
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.signature(createSignature(artist));
}
}
public static class BitmapBuilder {
private final Builder builder;
BitmapBuilder(Builder builder) {
this.builder = builder;
}
public BitmapRequestBuilder<?, Bitmap> build() {
//noinspection unchecked
return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage,
builder.forceDownload)
.asBitmap()
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_IMAGE)
.animate(DEFAULT_ANIMATION)
.priority(Priority.LOW)
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.signature(createSignature(builder.artist));
}
}
public static class PaletteBuilder {
final Context context;
private final Builder builder;
PaletteBuilder(Builder builder, Context context) {
this.builder = builder;
this.context = context;
}
public BitmapRequestBuilder<?, BitmapPaletteWrapper> build() {
//noinspection unchecked
return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage,
builder.forceDownload)
.asBitmap()
.transcode(new BitmapPaletteTranscoder(context), BitmapPaletteWrapper.class)
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_IMAGE)
.animate(DEFAULT_ANIMATION)
.priority(Priority.LOW)
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.signature(createSignature(builder.artist));
}
}
}

View file

@ -0,0 +1,147 @@
package code.name.monkey.retromusic.glide;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RSRuntimeException;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import code.name.monkey.retromusic.helper.StackBlur;
import code.name.monkey.retromusic.BuildConfig;
import code.name.monkey.retromusic.util.ImageUtil;
public class BlurTransformation extends BitmapTransformation {
static final float DEFAULT_BLUR_RADIUS = 5f;
private Context context;
private float blurRadius;
private int sampling;
private BlurTransformation(Builder builder) {
super(builder.context);
init(builder);
}
private BlurTransformation(Builder builder, BitmapPool bitmapPool) {
super(bitmapPool);
init(builder);
}
private void init(Builder builder) {
this.context = builder.context;
this.blurRadius = builder.blurRadius;
this.sampling = builder.sampling;
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
int sampling;
if (this.sampling == 0) {
sampling = ImageUtil.calculateInSampleSize(toTransform.getWidth(), toTransform.getHeight(), 100);
} else {
sampling = this.sampling;
}
int width = toTransform.getWidth();
int height = toTransform.getHeight();
int scaledWidth = width / sampling;
int scaledHeight = height / sampling;
Bitmap out = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
if (out == null) {
out = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(out);
canvas.scale(1 / (float) sampling, 1 / (float) sampling);
Paint paint = new Paint();
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(toTransform, 0, 0, paint);
if (Build.VERSION.SDK_INT >= 17) {
try {
final RenderScript rs = RenderScript.create(context.getApplicationContext());
final Allocation input = Allocation.createFromBitmap(rs, out, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius(blurRadius);
script.setInput(input);
script.forEach(output);
output.copyTo(out);
rs.destroy();
return out;
} catch (RSRuntimeException e) {
// on some devices RenderScript.create() throws: android.support.v8.renderscript.RSRuntimeException: Error loading libRSSupport library
if (BuildConfig.DEBUG) e.printStackTrace();
}
}
return StackBlur.blur(out, blurRadius);
}
@Override
public String getId() {
return "BlurTransformation(radius=" + blurRadius + ", sampling=" + sampling + ")";
}
public static class Builder {
private Context context;
private BitmapPool bitmapPool;
private float blurRadius = DEFAULT_BLUR_RADIUS;
private int sampling;
public Builder(@NonNull Context context) {
this.context = context;
}
/**
* @param blurRadius The radius to use. Must be between 0 and 25. Default is 5.
* @return the same Builder
*/
public Builder blurRadius(@FloatRange(from = 0.0f, to = 25.0f) float blurRadius) {
this.blurRadius = blurRadius;
return this;
}
/**
* @param sampling The inSampleSize to use. Must be a power of 2, or 1 for no down sampling or 0 for auto detect sampling. Default is 0.
* @return the same Builder
*/
public Builder sampling(int sampling) {
this.sampling = sampling;
return this;
}
/**
* @param bitmapPool The BitmapPool to use.
* @return the same Builder
*/
public Builder bitmapPool(BitmapPool bitmapPool) {
this.bitmapPool = bitmapPool;
return this;
}
public BlurTransformation build() {
if (bitmapPool != null) {
return new BlurTransformation(this, bitmapPool);
}
return new BlurTransformation(this);
}
}
}

View file

@ -0,0 +1,53 @@
package code.name.monkey.retromusic.glide;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import com.bumptech.glide.request.animation.GlideAnimation;
import code.name.monkey.appthemehelper.util.ATHUtil;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.RetroApplication;
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget;
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
import code.name.monkey.retromusic.util.PreferenceUtil;
import static code.name.monkey.retromusic.util.RetroColorUtil.getColor;
import static code.name.monkey.retromusic.util.RetroColorUtil.getDominantColor;
public abstract class RetroMusicColoredTarget extends BitmapPaletteTarget {
public RetroMusicColoredTarget(ImageView view) {
super(view);
}
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
onColorReady(getDefaultFooterColor());
}
@Override
public void onResourceReady(BitmapPaletteWrapper resource,
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
super.onResourceReady(resource, glideAnimation);
int defaultColor = getDefaultFooterColor();
int primaryColor = getColor(resource.getPalette(), defaultColor);
int dominantColor = getDominantColor(resource.getBitmap(), defaultColor);
onColorReady(PreferenceUtil.getInstance(RetroApplication.getInstance()).isDominantColor() ?
dominantColor : primaryColor);
}
protected int getDefaultFooterColor() {
return ATHUtil.resolveColor(getView().getContext(), R.attr.defaultFooterColor);
}
protected int getAlbumArtistFooterColor() {
return ATHUtil.resolveColor(getView().getContext(), R.attr.cardBackgroundColor);
}
public abstract void onColorReady(int color);
}

View file

@ -0,0 +1,27 @@
package code.name.monkey.retromusic.glide;
import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.module.GlideModule;
import code.name.monkey.retromusic.glide.artistimage.ArtistImage;
import code.name.monkey.retromusic.glide.artistimage.ArtistImageLoader;
import code.name.monkey.retromusic.glide.audiocover.AudioFileCover;
import code.name.monkey.retromusic.glide.audiocover.AudioFileCoverLoader;
import java.io.InputStream;
public class RetroMusicGlideModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
}
@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));
}
}

View file

@ -0,0 +1,124 @@
package code.name.monkey.retromusic.glide;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.glide.audiocover.AudioFileCover;
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder;
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
import code.name.monkey.retromusic.model.Song;
import code.name.monkey.retromusic.util.MusicUtil;
import code.name.monkey.retromusic.util.PreferenceUtil;
import com.bumptech.glide.BitmapRequestBuilder;
import com.bumptech.glide.DrawableRequestBuilder;
import com.bumptech.glide.DrawableTypeRequest;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.signature.MediaStoreSignature;
public class SongGlideRequest {
static final DiskCacheStrategy DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.NONE;
static final int DEFAULT_ANIMATION = android.R.anim.fade_in;
static final int DEFAULT_ERROR_IMAGE = R.drawable.default_album_art;
static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Song song,
boolean ignoreMediaStore) {
if (ignoreMediaStore) {
return requestManager.load(new AudioFileCover(song.data));
} else {
return requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.albumId));
}
}
static Key createSignature(Song song) {
return new MediaStoreSignature("", song.dateModified, 0);
}
public static class Builder {
final RequestManager requestManager;
final Song song;
boolean ignoreMediaStore;
private Builder(@NonNull RequestManager requestManager, Song song) {
this.requestManager = requestManager;
this.song = song;
}
public static Builder from(@NonNull RequestManager requestManager, Song song) {
return new Builder(requestManager, song);
}
public PaletteBuilder generatePalette(Context context) {
return new PaletteBuilder(this, context);
}
public BitmapBuilder asBitmap() {
return new BitmapBuilder(this);
}
public Builder checkIgnoreMediaStore(Context context) {
return ignoreMediaStore(PreferenceUtil.getInstance(context).ignoreMediaStoreArtwork());
}
Builder ignoreMediaStore(boolean ignoreMediaStore) {
this.ignoreMediaStore = ignoreMediaStore;
return this;
}
public DrawableRequestBuilder<GlideDrawable> build() {
//noinspection unchecked
return createBaseRequest(requestManager, song, ignoreMediaStore)
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_IMAGE)
.animate(DEFAULT_ANIMATION)
.signature(createSignature(song));
}
}
public static class BitmapBuilder {
private final Builder builder;
BitmapBuilder(Builder builder) {
this.builder = builder;
}
public BitmapRequestBuilder<?, Bitmap> build() {
//noinspection unchecked
return createBaseRequest(builder.requestManager, builder.song, builder.ignoreMediaStore)
.asBitmap()
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_IMAGE)
.animate(DEFAULT_ANIMATION)
.signature(createSignature(builder.song));
}
}
public static class PaletteBuilder {
final Context context;
private final Builder builder;
PaletteBuilder(Builder builder, Context context) {
this.builder = builder;
this.context = context;
}
public BitmapRequestBuilder<?, BitmapPaletteWrapper> build() {
//noinspection unchecked
return createBaseRequest(builder.requestManager, builder.song, builder.ignoreMediaStore)
.asBitmap()
.transcode(new BitmapPaletteTranscoder(context), BitmapPaletteWrapper.class)
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_IMAGE)
.animate(DEFAULT_ANIMATION)
.signature(createSignature(builder.song));
}
}
}

View file

@ -0,0 +1,12 @@
package code.name.monkey.retromusic.glide.artistimage;
public class ArtistImage {
public final String artistName;
public final boolean skipOkHttpCache;
public ArtistImage(String artistName, boolean skipOkHttpCache) {
this.artistName = artistName;
this.skipOkHttpCache = skipOkHttpCache;
}
}

View file

@ -0,0 +1,83 @@
package code.name.monkey.retromusic.glide.artistimage;
import android.content.Context;
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 code.name.monkey.retromusic.rest.LastFMRestClient;
import code.name.monkey.retromusic.rest.model.LastFmArtist;
import code.name.monkey.retromusic.util.LastFMUtil;
import code.name.monkey.retromusic.util.MusicUtil;
import code.name.monkey.retromusic.util.RetroUtil;
import java.io.IOException;
import java.io.InputStream;
import retrofit2.Response;
public class ArtistImageFetcher implements DataFetcher<InputStream> {
public static final String TAG = ArtistImageFetcher.class.getSimpleName();
private final LastFMRestClient lastFMRestClient;
private final ArtistImage model;
private final int width;
private final int height;
private Context context;
private ModelLoader<GlideUrl, InputStream> urlLoader;
private volatile boolean isCancelled;
private DataFetcher<InputStream> urlFetcher;
public ArtistImageFetcher(Context context, LastFMRestClient lastFMRestClient, ArtistImage model, ModelLoader<GlideUrl, InputStream> urlLoader, int width, int height) {
this.context = context;
this.lastFMRestClient = lastFMRestClient;
this.model = model;
this.urlLoader = urlLoader;
this.width = width;
this.height = height;
}
@Override
public String getId() {
// makes sure we never ever return null here
return String.valueOf(model.artistName);
}
@Override
public InputStream loadData(Priority priority) throws Exception {
if (!MusicUtil.isArtistNameUnknown(model.artistName) && RetroUtil.isAllowedToDownloadMetadata(context)) {
Response<LastFmArtist> 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());
}
LastFmArtist lastFmArtist = response.body();
if (isCancelled) return null;
GlideUrl url = new GlideUrl(LastFMUtil.getLargestArtistImageUrl(lastFmArtist.getArtist().getImage()));
urlFetcher = urlLoader.getResourceFetcher(url, width, height);
return urlFetcher.loadData(priority);
}
return null;
}
@Override
public void cleanup() {
if (urlFetcher != null) {
urlFetcher.cleanup();
}
}
@Override
public void cancel() {
isCancelled = true;
if (urlFetcher != null) {
urlFetcher.cancel();
}
}
}

View file

@ -0,0 +1,68 @@
package code.name.monkey.retromusic.glide.artistimage;
import android.content.Context;
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
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 code.name.monkey.retromusic.rest.LastFMRestClient;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
public class ArtistImageLoader implements StreamModelLoader<ArtistImage> {
// 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 = 500;
private Context context;
private LastFMRestClient lastFMClient;
private ModelLoader<GlideUrl, InputStream> urlLoader;
public ArtistImageLoader(Context context, LastFMRestClient lastFMRestClient, ModelLoader<GlideUrl, InputStream> urlLoader) {
this.context = context;
this.lastFMClient = lastFMRestClient;
this.urlLoader = urlLoader;
}
@Override
public DataFetcher<InputStream> getResourceFetcher(ArtistImage model, int width, int height) {
return new ArtistImageFetcher(context, lastFMClient, model, urlLoader, width, height);
}
public static class Factory implements ModelLoaderFactory<ArtistImage, InputStream> {
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<ArtistImage, InputStream> build(Context context, GenericLoaderFactory factories) {
return new ArtistImageLoader(context, lastFMClient, okHttpFactory.build(context, factories));
}
@Override
public void teardown() {
okHttpFactory.teardown();
}
}
}

View file

@ -0,0 +1,10 @@
package code.name.monkey.retromusic.glide.audiocover;
public class AudioFileCover {
public final String filePath;
public AudioFileCover(String filePath) {
this.filePath = filePath;
}
}

View file

@ -0,0 +1,95 @@
package code.name.monkey.retromusic.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;
public class AudioFileCoverFetcher implements DataFetcher<InputStream> {
private static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg", "cover.png", "album.png", "folder.png"};
private final AudioFileCover model;
private FileInputStream stream;
public AudioFileCoverFetcher(AudioFileCover model) {
this.model = model;
}
@Override
public String getId() {
// makes sure we never ever return null here
return String.valueOf(model.filePath);
}
@Override
public InputStream loadData(Priority priority) throws Exception {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(model.filePath);
byte[] picture = retriever.getEmbeddedPicture();
if (picture != null) {
return new ByteArrayInputStream(picture);
} else {
return fallback(model.filePath);
}
} finally {
retriever.release();
}
}
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 | InvalidAudioFrameException | TagException | 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;
}
@Override
public void 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() {
// cannot cancel
}
}

View file

@ -0,0 +1,32 @@
package code.name.monkey.retromusic.glide.audiocover;
import android.content.Context;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GenericLoaderFactory;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;
import com.bumptech.glide.load.model.stream.StreamModelLoader;
import java.io.InputStream;
public class AudioFileCoverLoader implements StreamModelLoader<AudioFileCover> {
@Override
public DataFetcher<InputStream> getResourceFetcher(AudioFileCover model, int width, int height) {
return new AudioFileCoverFetcher(model);
}
public static class Factory implements ModelLoaderFactory<AudioFileCover, InputStream> {
@Override
public ModelLoader<AudioFileCover, InputStream> build(Context context, GenericLoaderFactory factories) {
return new AudioFileCoverLoader();
}
@Override
public void teardown() {
}
}
}

View file

@ -0,0 +1,34 @@
package code.name.monkey.retromusic.glide.palette;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.util.Util;
public class BitmapPaletteResource implements Resource<BitmapPaletteWrapper> {
private final BitmapPaletteWrapper bitmapPaletteWrapper;
private final BitmapPool bitmapPool;
public BitmapPaletteResource(BitmapPaletteWrapper bitmapPaletteWrapper, BitmapPool bitmapPool) {
this.bitmapPaletteWrapper = bitmapPaletteWrapper;
this.bitmapPool = bitmapPool;
}
@Override
public BitmapPaletteWrapper get() {
return bitmapPaletteWrapper;
}
@Override
public int getSize() {
return Util.getBitmapByteSize(bitmapPaletteWrapper.getBitmap());
}
@Override
public void recycle() {
if (!bitmapPool.put(bitmapPaletteWrapper.getBitmap())) {
bitmapPaletteWrapper.getBitmap().recycle();
}
}
}

View file

@ -0,0 +1,17 @@
package code.name.monkey.retromusic.glide.palette;
import android.widget.ImageView;
import com.bumptech.glide.request.target.ImageViewTarget;
public class BitmapPaletteTarget extends ImageViewTarget<BitmapPaletteWrapper> {
public BitmapPaletteTarget(ImageView view) {
super(view);
}
@Override
protected void setResource(BitmapPaletteWrapper bitmapPaletteWrapper) {
view.setImageBitmap(bitmapPaletteWrapper.getBitmap());
}
}

View file

@ -0,0 +1,34 @@
package code.name.monkey.retromusic.glide.palette;
import android.content.Context;
import android.graphics.Bitmap;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import code.name.monkey.retromusic.util.RetroColorUtil;
public class BitmapPaletteTranscoder implements ResourceTranscoder<Bitmap, BitmapPaletteWrapper> {
private final BitmapPool bitmapPool;
public BitmapPaletteTranscoder(Context context) {
this(Glide.get(context).getBitmapPool());
}
public BitmapPaletteTranscoder(BitmapPool bitmapPool) {
this.bitmapPool = bitmapPool;
}
@Override
public Resource<BitmapPaletteWrapper> transcode(Resource<Bitmap> bitmapResource) {
Bitmap bitmap = bitmapResource.get();
BitmapPaletteWrapper bitmapPaletteWrapper = new BitmapPaletteWrapper(bitmap, RetroColorUtil.generatePalette(bitmap));
return new BitmapPaletteResource(bitmapPaletteWrapper, bitmapPool);
}
@Override
public String getId() {
return "BitmapPaletteTranscoder.code.name.monkey.retromusic.glide.palette";
}
}

View file

@ -0,0 +1,22 @@
package code.name.monkey.retromusic.glide.palette;
import android.graphics.Bitmap;
import android.support.v7.graphics.Palette;
public class BitmapPaletteWrapper {
private final Bitmap mBitmap;
private final Palette mPalette;
public BitmapPaletteWrapper(Bitmap bitmap, Palette palette) {
mBitmap = bitmap;
mPalette = palette;
}
public Bitmap getBitmap() {
return mBitmap;
}
public Palette getPalette() {
return mPalette;
}
}