converted to Glide 4
This commit is contained in:
parent
96aa205405
commit
f4c56c8484
45 changed files with 853 additions and 945 deletions
|
@ -1,112 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import code.name.monkey.retromusic.App
|
||||
import code.name.monkey.retromusic.R
|
||||
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
|
||||
import com.bumptech.glide.*
|
||||
import com.bumptech.glide.load.Key
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.target.Target
|
||||
|
||||
object ArtistGlideRequest {
|
||||
|
||||
private const val DEFAULT_ANIMATION = android.R.anim.fade_in
|
||||
private val DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.ALL
|
||||
private const val DEFAULT_ERROR_IMAGE = R.drawable.default_artist_art
|
||||
|
||||
private fun createBaseRequest(requestManager: RequestManager, artist: Artist, noCustomImage: Boolean, forceDownload: Boolean): DrawableTypeRequest<*> {
|
||||
val hasCustomImage = CustomArtistImageUtil.getInstance(App.instance)
|
||||
.hasCustomArtistImage(artist)
|
||||
return if (noCustomImage || !hasCustomImage) {
|
||||
requestManager.load(ArtistImage(artist.name, forceDownload))
|
||||
} else {
|
||||
requestManager.load(CustomArtistImageUtil.getFile(artist))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSignature(artist: Artist): Key {
|
||||
return ArtistSignatureUtil.getInstance(App.instance)
|
||||
.getArtistSignature(artist.name)
|
||||
}
|
||||
|
||||
class Builder private constructor(internal val requestManager: RequestManager, internal val artist: Artist) {
|
||||
internal var noCustomImage: Boolean = false
|
||||
internal var forceDownload: Boolean = false
|
||||
|
||||
fun generatePalette(context: Context): PaletteBuilder {
|
||||
return PaletteBuilder(this, context)
|
||||
}
|
||||
|
||||
fun asBitmap(): BitmapBuilder {
|
||||
return BitmapBuilder(this)
|
||||
}
|
||||
|
||||
fun noCustomImage(noCustomImage: Boolean): Builder {
|
||||
this.noCustomImage = noCustomImage
|
||||
return this
|
||||
}
|
||||
|
||||
fun forceDownload(forceDownload: Boolean): Builder {
|
||||
this.forceDownload = forceDownload
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): DrawableRequestBuilder<out Any> {
|
||||
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))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun from(requestManager: RequestManager, artist: Artist): Builder {
|
||||
return Builder(requestManager, artist)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BitmapBuilder internal constructor(private val builder: Builder) {
|
||||
|
||||
fun build(): BitmapRequestBuilder<*, Bitmap> {
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
class PaletteBuilder internal constructor(private val builder: Builder, internal val context: Context) {
|
||||
|
||||
fun build(): BitmapRequestBuilder<*, BitmapPaletteWrapper> {
|
||||
|
||||
return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage,
|
||||
builder.forceDownload)
|
||||
.asBitmap()
|
||||
.transcode(BitmapPaletteTranscoder(context), BitmapPaletteWrapper::class.java)
|
||||
|
||||
.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))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +1,30 @@
|
|||
package code.name.monkey.retromusic.glide
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
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.renderscript.*
|
||||
import androidx.annotation.FloatRange
|
||||
|
||||
import code.name.monkey.retromusic.BuildConfig
|
||||
import code.name.monkey.retromusic.helper.StackBlur
|
||||
import code.name.monkey.retromusic.util.ImageUtil
|
||||
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
|
||||
import java.security.MessageDigest
|
||||
|
||||
|
||||
class BlurTransformation : BitmapTransformation {
|
||||
|
||||
private var context: Context? = null
|
||||
private var blurRadius: Float = 0.toFloat()
|
||||
private var sampling: Int = 0
|
||||
|
||||
private constructor(builder: Builder) : super(builder.context) {
|
||||
private constructor(builder: Builder) : super() {
|
||||
init(builder)
|
||||
}
|
||||
|
||||
private constructor(builder: Builder, bitmapPool: BitmapPool) : super(bitmapPool) {
|
||||
private constructor(builder: Builder, bitmapPool: BitmapPool) : super() {
|
||||
init(builder)
|
||||
}
|
||||
|
||||
|
@ -41,7 +34,6 @@ class BlurTransformation : BitmapTransformation {
|
|||
this.sampling = builder.sampling
|
||||
}
|
||||
|
||||
|
||||
override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap? {
|
||||
val sampling: Int
|
||||
if (this.sampling == 0) {
|
||||
|
@ -93,14 +85,22 @@ class BlurTransformation : BitmapTransformation {
|
|||
return StackBlur.blur(out, blurRadius)
|
||||
}
|
||||
|
||||
override fun getId(): String {
|
||||
return "BlurTransformation(radius=$blurRadius, sampling=$sampling)"
|
||||
override fun equals(o: Any?): Boolean {
|
||||
return o is BlurTransformation
|
||||
}
|
||||
|
||||
class Builder(internal val context: Context) {
|
||||
private var bitmapPool: BitmapPool? = null
|
||||
internal var blurRadius = DEFAULT_BLUR_RADIUS
|
||||
internal var sampling: Int = 0
|
||||
override fun hashCode(): Int {
|
||||
return ID.hashCode()
|
||||
}
|
||||
|
||||
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
|
||||
messageDigest.update("BlurTransformation(radius=$blurRadius, sampling=$sampling)".toByteArray(CHARSET))
|
||||
}
|
||||
|
||||
class Builder(val context: Context) {
|
||||
var bitmapPool: BitmapPool? = null
|
||||
var blurRadius = DEFAULT_BLUR_RADIUS
|
||||
var sampling: Int = 0
|
||||
|
||||
/**
|
||||
* @param blurRadius The radius to use. Must be between 0 and 25. Default is 5.
|
||||
|
@ -137,6 +137,8 @@ class BlurTransformation : BitmapTransformation {
|
|||
}
|
||||
|
||||
companion object {
|
||||
internal const val DEFAULT_BLUR_RADIUS = 5f
|
||||
|
||||
val DEFAULT_BLUR_RADIUS = 5f
|
||||
private val ID = "com.poupa.vinylmusicplayer.glide.BlurTransformation"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package code.name.monkey.retromusic.glide;
|
||||
|
||||
import com.bumptech.glide.GenericTransitionOptions;
|
||||
import com.bumptech.glide.Priority;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.annotation.GlideExtension;
|
||||
import com.bumptech.glide.annotation.GlideOption;
|
||||
import com.bumptech.glide.annotation.GlideType;
|
||||
import com.bumptech.glide.load.Key;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.bumptech.glide.signature.MediaStoreSignature;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import code.name.monkey.retromusic.App;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.glide.artistimage.ArtistImage;
|
||||
import code.name.monkey.retromusic.glide.audiocover.AudioFileCover;
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
||||
import code.name.monkey.retromusic.model.Artist;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.util.ArtistSignatureUtil;
|
||||
import code.name.monkey.retromusic.util.CustomArtistImageUtil;
|
||||
import code.name.monkey.retromusic.util.MusicUtil;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
|
||||
@GlideExtension
|
||||
public final class RetroGlideExtension {
|
||||
private RetroGlideExtension() {
|
||||
}
|
||||
|
||||
@GlideType(BitmapPaletteWrapper.class)
|
||||
public static void asBitmapPalette(RequestBuilder<BitmapPaletteWrapper> requestBuilder) {
|
||||
}
|
||||
|
||||
@GlideOption
|
||||
public static RequestOptions artistOptions(@NonNull RequestOptions requestOptions, Artist artist) {
|
||||
return requestOptions
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.error(R.drawable.default_artist_art)
|
||||
.placeholder(R.drawable.default_artist_art)
|
||||
.priority(Priority.LOW)
|
||||
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
|
||||
.signature(createSignature(artist));
|
||||
}
|
||||
|
||||
@GlideOption
|
||||
public static RequestOptions songOptions(@NonNull RequestOptions requestOptions, Song song) {
|
||||
return requestOptions
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.error(R.drawable.default_album_art)
|
||||
.placeholder(R.drawable.default_album_art)
|
||||
.signature(createSignature(song));
|
||||
}
|
||||
|
||||
public static Key createSignature(Artist artist) {
|
||||
return ArtistSignatureUtil.getInstance().getArtistSignature(artist.getName());
|
||||
}
|
||||
|
||||
public static Key createSignature(Song song) {
|
||||
return new MediaStoreSignature("", song.getDateModified(), 0);
|
||||
}
|
||||
|
||||
public static Object getArtistModel(Artist artist) {
|
||||
return getArtistModel(artist, CustomArtistImageUtil.Companion.getInstance(App.Companion.getContext()).hasCustomArtistImage(artist), false);
|
||||
}
|
||||
|
||||
public static Object getArtistModel(Artist artist, boolean forceDownload) {
|
||||
return getArtistModel(artist, CustomArtistImageUtil.Companion.getInstance(App.Companion.getContext()).hasCustomArtistImage(artist), forceDownload);
|
||||
}
|
||||
|
||||
public static Object getArtistModel(Artist artist, boolean hasCustomImage, boolean forceDownload) {
|
||||
if (!hasCustomImage) {
|
||||
return new ArtistImage(artist.getName(), forceDownload);
|
||||
} else {
|
||||
return CustomArtistImageUtil.getFile(artist);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object getSongModel(Song song) {
|
||||
return getSongModel(song, PreferenceUtil.getInstance().ignoreMediaStoreArtwork());
|
||||
}
|
||||
|
||||
public static Object getSongModel(Song song, boolean ignoreMediaStore) {
|
||||
if (ignoreMediaStore) {
|
||||
return new AudioFileCover(song.getData());
|
||||
} else {
|
||||
return MusicUtil.getMediaStoreAlbumCoverUri(song.getAlbumId());
|
||||
}
|
||||
}
|
||||
|
||||
public static <TranscodeType> GenericTransitionOptions<TranscodeType> getDefaultTransition() {
|
||||
return new GenericTransitionOptions<TranscodeType>().transition(android.R.anim.fade_in);
|
||||
}
|
||||
}
|
|
@ -2,17 +2,14 @@ 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.glide.palette.BitmapPaletteTarget
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
|
||||
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
|
||||
import code.name.monkey.retromusic.util.RetroColorUtil.getDominantColor
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
|
||||
|
||||
abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(view) {
|
||||
|
@ -23,13 +20,13 @@ abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(vi
|
|||
protected val albumArtistFooterColor: Int
|
||||
get() = ATHUtil.resolveColor(getView().context, R.attr.cardBackgroundColor)
|
||||
|
||||
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
|
||||
super.onLoadFailed(e, errorDrawable)
|
||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||
super.onLoadFailed(errorDrawable)
|
||||
onColorReady(defaultFooterColor)
|
||||
}
|
||||
|
||||
override fun onResourceReady(resource: BitmapPaletteWrapper,
|
||||
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?) {
|
||||
glideAnimation: Transition<in BitmapPaletteWrapper>?) {
|
||||
super.onResourceReady(resource, glideAnimation)
|
||||
val defaultColor = defaultFooterColor
|
||||
|
||||
|
|
|
@ -1,25 +1,29 @@
|
|||
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 android.graphics.Bitmap
|
||||
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 code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.Registry
|
||||
import com.bumptech.glide.annotation.GlideModule
|
||||
import com.bumptech.glide.module.AppGlideModule
|
||||
import java.io.InputStream
|
||||
|
||||
|
||||
class RetroMusicGlideModule : GlideModule {
|
||||
override fun applyOptions(context: Context, builder: GlideBuilder) {
|
||||
|
||||
@GlideModule
|
||||
class RetroMusicGlideModule : AppGlideModule() {
|
||||
override fun registerComponents(context: Context, glide: Glide,
|
||||
registry: Registry) {
|
||||
registry.append(AudioFileCover::class.java, InputStream::class.java, AudioFileCoverLoader.Factory())
|
||||
registry.append(ArtistImage::class.java, InputStream::class.java, ArtistImageLoader.Factory(context))
|
||||
registry.register(Bitmap::class.java, BitmapPaletteWrapper::class.java, BitmapPaletteTranscoder())
|
||||
}
|
||||
|
||||
override fun registerComponents(context: Context, glide: Glide) {
|
||||
glide.register(AudioFileCover::class.java, InputStream::class.java, AudioFileCoverLoader.Factory())
|
||||
glide.register(ArtistImage::class.java, InputStream::class.java, ArtistImageLoader.Factory(context))
|
||||
override fun isManifestParsingEnabled(): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package code.name.monkey.retromusic.glide
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
import com.bumptech.glide.request.Request
|
||||
import com.bumptech.glide.request.target.SizeReadyCallback
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import com.bumptech.glide.util.Util
|
||||
|
||||
open class RetroSimpleTarget<T> @JvmOverloads constructor(private val width: Int = Target.SIZE_ORIGINAL, private val height: Int = Target.SIZE_ORIGINAL) : Target<T> {
|
||||
|
||||
private var request: Request? = null
|
||||
|
||||
override fun getRequest(): Request? {
|
||||
return request
|
||||
}
|
||||
|
||||
override fun setRequest(request: Request?) {
|
||||
this.request = request
|
||||
}
|
||||
|
||||
override fun onLoadStarted(placeholder: Drawable?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onResourceReady(resource: T, transition: Transition<in T>?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onLoadCleared(placeholder: Drawable?) {
|
||||
|
||||
}
|
||||
|
||||
override fun getSize(cb: SizeReadyCallback) {
|
||||
if (!Util.isValidDimensions(width, height)) {
|
||||
throw IllegalArgumentException(
|
||||
"Width and height must both be > 0 or Target#SIZE_ORIGINAL, but given" + " width: "
|
||||
+ width + " and height: " + height + ", either provide dimensions in the constructor"
|
||||
+ " or call override()")
|
||||
}
|
||||
cb.onSizeReady(width, height)
|
||||
}
|
||||
|
||||
override fun removeCallback(cb: SizeReadyCallback) {
|
||||
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
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.signature.MediaStoreSignature
|
||||
|
||||
|
||||
object SongGlideRequest {
|
||||
|
||||
internal val DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.NONE
|
||||
internal const val DEFAULT_ANIMATION = android.R.anim.fade_in
|
||||
internal const val DEFAULT_ERROR_IMAGE = R.drawable.default_album_art
|
||||
|
||||
internal fun createBaseRequest(requestManager: RequestManager, song: Song,
|
||||
ignoreMediaStore: Boolean): DrawableTypeRequest<*> {
|
||||
return if (ignoreMediaStore) {
|
||||
requestManager.load(AudioFileCover(song.data!!))
|
||||
} else {
|
||||
requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.albumId))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createSignature(song: Song): Key {
|
||||
return MediaStoreSignature("", song.dateModified, 0)
|
||||
}
|
||||
|
||||
class Builder private constructor(internal val requestManager: RequestManager, internal val song: Song) {
|
||||
internal var ignoreMediaStore: Boolean = false
|
||||
|
||||
fun generatePalette(context: Context): PaletteBuilder {
|
||||
return PaletteBuilder(this, context)
|
||||
}
|
||||
|
||||
fun asBitmap(): BitmapBuilder {
|
||||
return BitmapBuilder(this)
|
||||
}
|
||||
|
||||
fun checkIgnoreMediaStore(context: Context): Builder {
|
||||
return ignoreMediaStore(PreferenceUtil.getInstance().ignoreMediaStoreArtwork())
|
||||
}
|
||||
|
||||
fun ignoreMediaStore(ignoreMediaStore: Boolean): Builder {
|
||||
this.ignoreMediaStore = ignoreMediaStore
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): DrawableRequestBuilder<out Any> {
|
||||
return createBaseRequest(requestManager, song, ignoreMediaStore)
|
||||
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
|
||||
.error(DEFAULT_ERROR_IMAGE)
|
||||
.animate(DEFAULT_ANIMATION)
|
||||
.signature(createSignature(song))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun from(requestManager: RequestManager, song: Song): Builder {
|
||||
return Builder(requestManager, song)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BitmapBuilder internal constructor(private val builder: Builder) {
|
||||
|
||||
fun build(): BitmapRequestBuilder<*, Bitmap> {
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
class PaletteBuilder internal constructor(private val builder: Builder, internal val context: Context) {
|
||||
|
||||
fun build(): BitmapRequestBuilder<*, BitmapPaletteWrapper> {
|
||||
|
||||
return createBaseRequest(builder.requestManager, builder.song, builder.ignoreMediaStore)
|
||||
.asBitmap()
|
||||
.transcode(BitmapPaletteTranscoder(context), BitmapPaletteWrapper::class.java)
|
||||
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
|
||||
.error(DEFAULT_ERROR_IMAGE)
|
||||
.animate(DEFAULT_ANIMATION)
|
||||
.signature(createSignature(builder.song))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,69 +1,98 @@
|
|||
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 android.text.TextUtils
|
||||
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 com.bumptech.glide.Priority
|
||||
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.data.DataFetcher
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
|
||||
import java.io.IOException
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import java.io.InputStream
|
||||
|
||||
import retrofit2.Response
|
||||
|
||||
|
||||
class ArtistImageFetcher(private val context: Context, private val lastFMRestClient: LastFMRestClient, private val model: ArtistImage, private val urlLoader: ModelLoader<GlideUrl, InputStream>, private val width: Int, private val height: Int) : DataFetcher<InputStream> {
|
||||
class ArtistImageFetcher(private val context: Context, private val lastFMRestClient: LastFMRestClient, private val okHttp: OkHttpClient, private val model: ArtistImage, width: Int, height: Int) : DataFetcher<InputStream> {
|
||||
@Volatile
|
||||
private var isCancelled: Boolean = false
|
||||
private var urlFetcher: DataFetcher<InputStream>? = null
|
||||
private var call: Call<LastFmArtist>? = null
|
||||
private var streamFetcher: OkHttpStreamFetcher? = null
|
||||
|
||||
override fun getId(): String {
|
||||
// makes sure we never ever return null here
|
||||
return model.artistName
|
||||
|
||||
override fun getDataClass(): Class<InputStream> {
|
||||
return InputStream::class.java
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun loadData(priority: Priority): InputStream? {
|
||||
if (!MusicUtil.isArtistNameUnknown(model.artistName) && RetroUtil.isAllowedToDownloadMetadata(context)) {
|
||||
val response = lastFMRestClient.apiService.getArtistInfo(model.artistName, null, if (model.skipOkHttpCache) "no-cache" else null).execute()
|
||||
|
||||
if (!response.isSuccessful) {
|
||||
throw IOException("Request failed with code: " + response.code())
|
||||
override fun getDataSource(): DataSource {
|
||||
return DataSource.REMOTE
|
||||
}
|
||||
|
||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||
try {
|
||||
if (!MusicUtil.isArtistNameUnknown(model.artistName) && RetroUtil.isAllowedToDownloadMetadata(context)) {
|
||||
call = lastFMRestClient.apiService.getArtistInfo(model.artistName, null, if (model.skipOkHttpCache) "no-cache" else null)
|
||||
call!!.enqueue(object : Callback<LastFmArtist> {
|
||||
override fun onResponse(call: Call<LastFmArtist>, response: Response<LastFmArtist>) {
|
||||
if (isCancelled) {
|
||||
callback.onDataReady(null)
|
||||
return
|
||||
}
|
||||
|
||||
val lastFmArtist = response.body()
|
||||
if (lastFmArtist == null || lastFmArtist.artist == null || lastFmArtist.artist.image == null) {
|
||||
callback.onLoadFailed(Exception("No artist image url found"))
|
||||
return
|
||||
}
|
||||
|
||||
val url = LastFMUtil.getLargestArtistImageUrl(lastFmArtist.artist.image)
|
||||
if (TextUtils.isEmpty(url) || TextUtils.isEmpty(url.trim { it <= ' ' })) {
|
||||
callback.onLoadFailed(Exception("No artist image url found"))
|
||||
return
|
||||
}
|
||||
|
||||
streamFetcher = OkHttpStreamFetcher(okHttp, GlideUrl(url))
|
||||
streamFetcher!!.loadData(priority, callback)
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<LastFmArtist>, throwable: Throwable) {
|
||||
callback.onLoadFailed(Exception(throwable))
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
val lastFmArtist = response.body()
|
||||
|
||||
if (isCancelled) return null
|
||||
|
||||
val url = GlideUrl(LastFMUtil.getLargestArtistImageUrl(lastFmArtist!!.artist.image))
|
||||
urlFetcher = urlLoader.getResourceFetcher(url, width, height)
|
||||
|
||||
return urlFetcher!!.loadData(priority)
|
||||
} catch (e: Exception) {
|
||||
callback.onLoadFailed(e)
|
||||
}
|
||||
return null
|
||||
|
||||
}
|
||||
|
||||
override fun cleanup() {
|
||||
if (urlFetcher != null) {
|
||||
urlFetcher!!.cleanup()
|
||||
if (streamFetcher != null) {
|
||||
streamFetcher!!.cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
isCancelled = true
|
||||
if (urlFetcher != null) {
|
||||
urlFetcher!!.cancel()
|
||||
if (call != null) {
|
||||
call!!.cancel()
|
||||
}
|
||||
if (streamFetcher != null) {
|
||||
streamFetcher!!.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = ArtistImageFetcher::class.java.simpleName
|
||||
val TAG: String = ArtistImageFetcher::class.java.simpleName
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +1,49 @@
|
|||
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 code.name.monkey.retromusic.rest.LastFMRestClient
|
||||
import com.bumptech.glide.load.Options
|
||||
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 com.bumptech.glide.load.model.MultiModelLoaderFactory
|
||||
import com.bumptech.glide.signature.ObjectKey
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.InputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
class ArtistImageLoader(private val context: Context, private val lastFMClient: LastFMRestClient, private val okhttp: OkHttpClient) : ModelLoader<ArtistImage, InputStream> {
|
||||
|
||||
class ArtistImageLoader(private val context: Context, private val lastFMClient: LastFMRestClient, private val urlLoader: ModelLoader<GlideUrl, InputStream>) : StreamModelLoader<ArtistImage> {
|
||||
|
||||
override fun getResourceFetcher(model: ArtistImage, width: Int, height: Int): DataFetcher<InputStream> {
|
||||
return ArtistImageFetcher(context, lastFMClient, model, urlLoader, width, height)
|
||||
override fun buildLoadData(model: ArtistImage, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
|
||||
return ModelLoader.LoadData(ObjectKey(model.artistName), ArtistImageFetcher(context, lastFMClient, okhttp, model, width, height))
|
||||
}
|
||||
|
||||
class Factory(context: Context) : ModelLoaderFactory<ArtistImage, InputStream> {
|
||||
override fun handles(model: ArtistImage): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
class Factory(private val context: Context) : ModelLoaderFactory<ArtistImage, InputStream> {
|
||||
private val lastFMClient: LastFMRestClient = LastFMRestClient(LastFMRestClient.createDefaultOkHttpClientBuilder(context)
|
||||
.connectTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||
.readTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||
.writeTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||
.build())
|
||||
private val okHttpFactory: OkHttpUrlLoader.Factory = OkHttpUrlLoader.Factory(OkHttpClient.Builder()
|
||||
private val okHttp: OkHttpClient = OkHttpClient.Builder()
|
||||
.connectTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||
.readTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||
.writeTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||
.build())
|
||||
.build()
|
||||
|
||||
override fun build(context: Context, factories: GenericLoaderFactory): ModelLoader<ArtistImage, InputStream> {
|
||||
return ArtistImageLoader(context, lastFMClient, okHttpFactory.build(context, factories))
|
||||
|
||||
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<ArtistImage, InputStream> {
|
||||
return ArtistImageLoader(context, lastFMClient, okHttp)
|
||||
}
|
||||
|
||||
override fun teardown() {
|
||||
okHttpFactory.teardown()
|
||||
}
|
||||
override fun teardown() {}
|
||||
}
|
||||
|
||||
companion object {
|
||||
// we need these very low values to make sure our artist image loading calls doesn't block the image loading queue
|
||||
private const val TIMEOUT = 500
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,41 +2,48 @@ package code.name.monkey.retromusic.glide.audiocover
|
|||
|
||||
import android.media.MediaMetadataRetriever
|
||||
import com.bumptech.glide.Priority
|
||||
import com.bumptech.glide.load.DataSource
|
||||
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 java.io.*
|
||||
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
class AudioFileCoverFetcher(private val model: AudioFileCover) : DataFetcher<InputStream> {
|
||||
private var stream: FileInputStream? = null
|
||||
|
||||
override fun getId(): String {
|
||||
// makes sure we never ever return null here
|
||||
return model.filePath
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun loadData(priority: Priority): InputStream? {
|
||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
val data: InputStream?
|
||||
try {
|
||||
retriever.setDataSource(model.filePath)
|
||||
val picture = retriever.embeddedPicture
|
||||
return if (picture != null) {
|
||||
ByteArrayInputStream(picture)
|
||||
if (picture != null) {
|
||||
data = ByteArrayInputStream(picture)
|
||||
} else {
|
||||
fallback(model.filePath)
|
||||
data = fallback(model.filePath)
|
||||
}
|
||||
callback.onDataReady(data)
|
||||
} catch (e: FileNotFoundException) {
|
||||
callback.onLoadFailed(e)
|
||||
} finally {
|
||||
retriever.release()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getDataClass(): Class<InputStream> {
|
||||
return InputStream::class.java
|
||||
}
|
||||
|
||||
|
||||
override fun getDataSource(): DataSource {
|
||||
return DataSource.LOCAL
|
||||
}
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
private fun fallback(path: String): InputStream? {
|
||||
// Method 1: use embedded high resolution album art if there is any
|
||||
try {
|
||||
val mp3File = MP3File(path)
|
||||
if (mp3File.hasID3v2Tag()) {
|
||||
|
@ -47,10 +54,7 @@ class AudioFileCoverFetcher(private val model: AudioFileCover) : DataFetcher<Inp
|
|||
}
|
||||
}
|
||||
// If there are any exceptions, we ignore them and continue to the other fallback method
|
||||
} catch (ignored: ReadOnlyFileException) {
|
||||
} catch (ignored: InvalidAudioFrameException) {
|
||||
} catch (ignored: TagException) {
|
||||
} catch (ignored: IOException) {
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
// Method 2: look for album art in external files
|
||||
|
@ -82,6 +86,7 @@ class AudioFileCoverFetcher(private val model: AudioFileCover) : DataFetcher<Inp
|
|||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val FALLBACKS = arrayOf("cover.jpg", "album.jpg", "folder.jpg", "cover.png", "album.png", "folder.png")
|
||||
}
|
||||
}
|
|
@ -1,24 +1,27 @@
|
|||
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.Options
|
||||
import com.bumptech.glide.load.model.ModelLoader
|
||||
import com.bumptech.glide.load.model.ModelLoader.LoadData
|
||||
import com.bumptech.glide.load.model.ModelLoaderFactory
|
||||
import com.bumptech.glide.load.model.stream.StreamModelLoader
|
||||
|
||||
import com.bumptech.glide.load.model.MultiModelLoaderFactory
|
||||
import com.bumptech.glide.signature.ObjectKey
|
||||
import java.io.InputStream
|
||||
|
||||
|
||||
class AudioFileCoverLoader : StreamModelLoader<AudioFileCover> {
|
||||
|
||||
override fun getResourceFetcher(model: AudioFileCover, width: Int, height: Int): DataFetcher<InputStream> {
|
||||
return AudioFileCoverFetcher(model)
|
||||
class AudioFileCoverLoader : ModelLoader<AudioFileCover, InputStream> {
|
||||
override fun buildLoadData(model: AudioFileCover, width: Int, height: Int,
|
||||
options: Options): LoadData<InputStream>? {
|
||||
return LoadData(ObjectKey(model.filePath), AudioFileCoverFetcher(model))
|
||||
}
|
||||
|
||||
override fun handles(model: AudioFileCover): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
class Factory : ModelLoaderFactory<AudioFileCover, InputStream> {
|
||||
override fun build(context: Context, factories: GenericLoaderFactory): ModelLoader<AudioFileCover, InputStream> {
|
||||
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<AudioFileCover, InputStream> {
|
||||
return AudioFileCoverLoader()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
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
|
||||
|
||||
|
||||
class BitmapPaletteResource(private val bitmapPaletteWrapper: BitmapPaletteWrapper, private val bitmapPool: BitmapPool) : Resource<BitmapPaletteWrapper> {
|
||||
class BitmapPaletteResource(private val bitmapPaletteWrapper: BitmapPaletteWrapper) : Resource<BitmapPaletteWrapper> {
|
||||
|
||||
override fun get(): BitmapPaletteWrapper {
|
||||
return bitmapPaletteWrapper
|
||||
}
|
||||
|
||||
override fun getResourceClass(): Class<BitmapPaletteWrapper> {
|
||||
return BitmapPaletteWrapper::class.java
|
||||
}
|
||||
|
||||
override fun getSize(): Int {
|
||||
return Util.getBitmapByteSize(bitmapPaletteWrapper.bitmap)
|
||||
}
|
||||
|
||||
override fun recycle() {
|
||||
if (!bitmapPool.put(bitmapPaletteWrapper.bitmap)) {
|
||||
bitmapPaletteWrapper.bitmap.recycle()
|
||||
}
|
||||
bitmapPaletteWrapper.bitmap.recycle()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,14 @@
|
|||
package code.name.monkey.retromusic.glide.palette
|
||||
|
||||
import android.widget.ImageView
|
||||
|
||||
import com.bumptech.glide.request.target.ImageViewTarget
|
||||
|
||||
open class BitmapPaletteTarget(view: ImageView) : ImageViewTarget<BitmapPaletteWrapper>(view) {
|
||||
|
||||
override fun setResource(bitmapPaletteWrapper: BitmapPaletteWrapper) {
|
||||
view.setImageBitmap(bitmapPaletteWrapper.bitmap)
|
||||
override fun setResource(bitmapPaletteWrapper: BitmapPaletteWrapper?) {
|
||||
if (bitmapPaletteWrapper != null) {
|
||||
view.setImageBitmap(bitmapPaletteWrapper.bitmap)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,25 +1,16 @@
|
|||
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
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.engine.Resource
|
||||
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder
|
||||
|
||||
class BitmapPaletteTranscoder(private val bitmapPool: BitmapPool) : ResourceTranscoder<Bitmap, BitmapPaletteWrapper> {
|
||||
|
||||
constructor(context: Context) : this(Glide.get(context).bitmapPool) {}
|
||||
|
||||
override fun transcode(bitmapResource: Resource<Bitmap>): Resource<BitmapPaletteWrapper> {
|
||||
class BitmapPaletteTranscoder : ResourceTranscoder<Bitmap, BitmapPaletteWrapper> {
|
||||
override fun transcode(bitmapResource: Resource<Bitmap>, options: Options): Resource<BitmapPaletteWrapper>? {
|
||||
val bitmap = bitmapResource.get()
|
||||
val bitmapPaletteWrapper = BitmapPaletteWrapper(bitmap, RetroColorUtil.generatePalette(bitmap)!!)
|
||||
return BitmapPaletteResource(bitmapPaletteWrapper, bitmapPool)
|
||||
}
|
||||
|
||||
override fun getId(): String {
|
||||
return "BitmapPaletteTranscoder.code.name.monkey.retromusic.glide.palette"
|
||||
return BitmapPaletteResource(bitmapPaletteWrapper)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue