use blurhash for most objects
This commit is contained in:
parent
5085bbc1e7
commit
a66f0d5fcd
24 changed files with 85 additions and 61 deletions
|
|
@ -47,7 +47,6 @@ android {
|
|||
dependencies {
|
||||
implementation 'com.github.jellyfin.jellyfin-apiclient-java:android:0.7.3'
|
||||
implementation 'com.github.woltapp:blurhash:f41a23cc50'
|
||||
implementation 'com.github.florent37:glidepalette:2.1.2'
|
||||
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.11.4'
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
|
|
|
|||
|
|
@ -108,8 +108,8 @@ public class AlbumCoverPagerAdapter extends CustomFragmentStatePagerAdapter {
|
|||
|
||||
private void loadAlbumCover() {
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(getContext()), song.primary)
|
||||
.palette(getActivity()).build()
|
||||
.from(getContext(), song.primary, song.blurHash)
|
||||
.palette().build()
|
||||
.into(new CustomPaletteTarget(binding.playerImage) {
|
||||
@Override
|
||||
public void onColorReady(int color) {
|
||||
|
|
|
|||
|
|
@ -83,8 +83,8 @@ public class GenreAdapter extends RecyclerView.Adapter<GenreAdapter.ViewHolder>
|
|||
if (holder.image == null) return;
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(activity), genre.id)
|
||||
.palette(activity).build()
|
||||
.from(activity, genre.id, genre.id)
|
||||
.palette().build()
|
||||
.into(new CustomPaletteTarget(holder.image) {
|
||||
@Override
|
||||
public void onLoadCleared(Drawable placeholder) {
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@ public class PlaylistAdapter extends AbsMultiSelectAdapter<PlaylistAdapter.ViewH
|
|||
if (holder.image == null) return;
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(activity), playlist.id)
|
||||
.palette(activity).build()
|
||||
.from(activity, playlist.id, playlist.id)
|
||||
.palette().build()
|
||||
.into(new CustomPaletteTarget(holder.image) {
|
||||
@Override
|
||||
public void onLoadCleared(Drawable placeholder) {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder
|
|||
holder.title.setText(album.title);
|
||||
holder.text.setText(MusicUtil.getAlbumInfoString(activity, album));
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(activity), album.primary)
|
||||
.from(activity, album.primary, album.blurHash)
|
||||
.build().into(holder.image);
|
||||
break;
|
||||
case ARTIST:
|
||||
|
|
@ -78,7 +78,7 @@ public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder
|
|||
holder.title.setText(artist.name);
|
||||
holder.text.setText(MusicUtil.getArtistInfoString(activity, artist));
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(activity), artist.primary)
|
||||
.from(activity, artist.primary, artist.blurHash)
|
||||
.build().into(holder.image);
|
||||
break;
|
||||
case SONG:
|
||||
|
|
|
|||
|
|
@ -129,8 +129,8 @@ public class AlbumAdapter extends AbsMultiSelectAdapter<AlbumAdapter.ViewHolder,
|
|||
if (holder.image == null) return;
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(activity), album.primary)
|
||||
.palette(activity).build()
|
||||
.from(activity, album.primary, album.blurHash)
|
||||
.palette().build()
|
||||
.into(new CustomPaletteTarget(holder.image) {
|
||||
@Override
|
||||
public void onLoadCleared(Drawable placeholder) {
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ public class HorizontalAlbumAdapter extends AlbumAdapter {
|
|||
if (holder.image == null) return;
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(activity), album.primary)
|
||||
.palette(activity).build()
|
||||
.from(activity, album.primary, album.blurHash)
|
||||
.palette().build()
|
||||
.into(new CustomPaletteTarget(holder.image) {
|
||||
@Override
|
||||
public void onLoadCleared(Drawable placeholder) {
|
||||
|
|
|
|||
|
|
@ -123,8 +123,8 @@ public class ArtistAdapter extends AbsMultiSelectAdapter<ArtistAdapter.ViewHolde
|
|||
if (holder.image == null) return;
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(activity), artist.primary)
|
||||
.palette(activity).build()
|
||||
.from(activity, artist.primary, artist.blurHash)
|
||||
.palette().build()
|
||||
.into(new CustomPaletteTarget(holder.image) {
|
||||
@Override
|
||||
public void onLoadCleared(Drawable placeholder) {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public class ArtistSongAdapter extends ArrayAdapter<Song> implements MaterialCab
|
|||
songInfo.setText(song.albumName);
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(activity), song.primary)
|
||||
.from(activity, song.primary, song.blurHash)
|
||||
.build().into(albumArt);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
|
|
|
|||
|
|
@ -134,8 +134,8 @@ public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, S
|
|||
if (holder.image == null) return;
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(activity), song.primary)
|
||||
.palette(activity).build()
|
||||
.from(activity, song.primary, song.blurHash)
|
||||
.palette().build()
|
||||
.into(new CustomPaletteTarget(holder.image) {
|
||||
@Override
|
||||
public void onLoadCleared(Drawable placeholder) {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ package com.dkanada.gramophone.glide;
|
|||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
|
@ -17,6 +19,7 @@ import com.dkanada.gramophone.App;
|
|||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.glide.palette.BitmapPaletteCrossFadeFactory;
|
||||
import com.dkanada.gramophone.glide.palette.BitmapPaletteWrapper;
|
||||
import com.wolt.blurhashkt.BlurHashDecoder;
|
||||
|
||||
import org.jellyfin.apiclient.model.dto.ImageOptions;
|
||||
import org.jellyfin.apiclient.model.entities.ImageType;
|
||||
|
|
@ -26,24 +29,34 @@ import static com.bumptech.glide.GenericTransitionOptions.with;
|
|||
public class CustomGlideRequest {
|
||||
public static final DiskCacheStrategy DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.ALL;
|
||||
public static final int DEFAULT_IMAGE = R.drawable.default_album_art;
|
||||
public static final int DEFAULT_DURATION = 200;
|
||||
|
||||
public static class Builder {
|
||||
final RequestManager requestManager;
|
||||
final String item;
|
||||
private final RequestManager requestManager;
|
||||
private final Object item;
|
||||
private final Context context;
|
||||
|
||||
private Builder(@NonNull RequestManager requestManager, String item) {
|
||||
requestManager.applyDefaultRequestOptions(createRequestOptions(item));
|
||||
private Builder(Context context, String item, String placeholder) {
|
||||
this.requestManager = Glide.with(context);
|
||||
this.item = item != null ? createUrl(item) : DEFAULT_IMAGE;
|
||||
this.context = context;
|
||||
|
||||
this.requestManager = requestManager;
|
||||
this.item = item;
|
||||
if (placeholder != null) {
|
||||
Bitmap bitmap = BlurHashDecoder.INSTANCE.decode(placeholder, 20, 20, 1, true);
|
||||
BitmapDrawable drawable = new BitmapDrawable(context.getResources(), bitmap);
|
||||
requestManager.applyDefaultRequestOptions(createRequestOptions(item, drawable));
|
||||
} else {
|
||||
Drawable drawable = ResourcesCompat.getDrawable(context.getResources(), DEFAULT_IMAGE, null);
|
||||
requestManager.applyDefaultRequestOptions(createRequestOptions(item, drawable));
|
||||
}
|
||||
}
|
||||
|
||||
public static Builder from(@NonNull RequestManager requestManager, String item) {
|
||||
return new Builder(requestManager, item);
|
||||
public static Builder from(Context context, String item, String placeholder) {
|
||||
return new Builder(context, item, placeholder);
|
||||
}
|
||||
|
||||
public PaletteBuilder palette(Context context) {
|
||||
return new PaletteBuilder(this, context);
|
||||
public PaletteBuilder palette() {
|
||||
return new PaletteBuilder(this, this.context);
|
||||
}
|
||||
|
||||
public BitmapBuilder bitmap() {
|
||||
|
|
@ -51,10 +64,8 @@ public class CustomGlideRequest {
|
|||
}
|
||||
|
||||
public RequestBuilder<Drawable> build() {
|
||||
Object uri = item != null ? createUrl(item) : DEFAULT_IMAGE;
|
||||
|
||||
return requestManager.load(uri)
|
||||
.transition(DrawableTransitionOptions.withCrossFade());
|
||||
return requestManager.load(item)
|
||||
.transition(DrawableTransitionOptions.withCrossFade(DEFAULT_DURATION));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,10 +77,8 @@ public class CustomGlideRequest {
|
|||
}
|
||||
|
||||
public RequestBuilder<Bitmap> build() {
|
||||
Object uri = builder.item != null ? createUrl(builder.item) : DEFAULT_IMAGE;
|
||||
|
||||
return builder.requestManager.asBitmap().load(uri)
|
||||
.transition(BitmapTransitionOptions.withCrossFade());
|
||||
return builder.requestManager.asBitmap().load(builder.item)
|
||||
.transition(BitmapTransitionOptions.withCrossFade(DEFAULT_DURATION));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,16 +92,15 @@ public class CustomGlideRequest {
|
|||
}
|
||||
|
||||
public RequestBuilder<BitmapPaletteWrapper> build() {
|
||||
Object uri = builder.item != null ? createUrl(builder.item) : DEFAULT_IMAGE;
|
||||
|
||||
return builder.requestManager.as(BitmapPaletteWrapper.class).load(uri)
|
||||
return builder.requestManager.as(BitmapPaletteWrapper.class).load(builder.item)
|
||||
.transition(with(new BitmapPaletteCrossFadeFactory()));
|
||||
}
|
||||
}
|
||||
|
||||
public static RequestOptions createRequestOptions(String item) {
|
||||
public static RequestOptions createRequestOptions(String item, Drawable placeholder) {
|
||||
return new RequestOptions()
|
||||
.centerCrop()
|
||||
.placeholder(placeholder)
|
||||
.error(DEFAULT_IMAGE)
|
||||
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
|
||||
.signature(new ObjectKey(item != null ? item : 0));
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ import android.graphics.Bitmap;
|
|||
|
||||
import com.bumptech.glide.request.transition.BitmapContainerTransitionFactory;
|
||||
import com.bumptech.glide.request.transition.DrawableCrossFadeFactory;
|
||||
import com.dkanada.gramophone.glide.CustomGlideRequest;
|
||||
|
||||
public class BitmapPaletteCrossFadeFactory extends BitmapContainerTransitionFactory<BitmapPaletteWrapper> {
|
||||
public BitmapPaletteCrossFadeFactory() {
|
||||
super(new DrawableCrossFadeFactory.Builder().build());
|
||||
super(new DrawableCrossFadeFactory.Builder(CustomGlideRequest.DEFAULT_DURATION).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ public class Album implements Parcelable {
|
|||
public String artistName;
|
||||
|
||||
public String primary;
|
||||
public String blurHash;
|
||||
|
||||
public Album(BaseItemDto itemDto) {
|
||||
this.id = itemDto.getId();
|
||||
|
|
@ -35,6 +36,9 @@ public class Album implements Parcelable {
|
|||
}
|
||||
|
||||
this.primary = itemDto.getImageTags().containsKey(ImageType.Primary) ? id : null;
|
||||
if (itemDto.getImageBlurHashes().get(ImageType.Primary) != null) {
|
||||
this.blurHash = (String) itemDto.getImageBlurHashes().get(ImageType.Primary).values().toArray()[0];
|
||||
}
|
||||
|
||||
this.songs = new ArrayList<>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,16 @@ public class Artist implements Parcelable {
|
|||
public String name;
|
||||
|
||||
public String primary;
|
||||
public String blurHash;
|
||||
|
||||
public Artist(BaseItemDto itemDto) {
|
||||
this.id = itemDto.getId();
|
||||
this.name = itemDto.getName();
|
||||
|
||||
this.primary = itemDto.getImageTags().containsKey(ImageType.Primary) ? id : null;
|
||||
if (itemDto.getImageBlurHashes().get(ImageType.Primary) != null) {
|
||||
this.blurHash = (String) itemDto.getImageBlurHashes().get(ImageType.Primary).values().toArray()[0];
|
||||
}
|
||||
|
||||
this.genres = new ArrayList<>();
|
||||
this.albums = new ArrayList<>();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.os.Parcelable;
|
|||
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.dto.MediaSourceInfo;
|
||||
import org.jellyfin.apiclient.model.entities.ImageType;
|
||||
import org.jellyfin.apiclient.model.entities.MediaStream;
|
||||
|
||||
public class Song implements Parcelable {
|
||||
|
|
@ -24,6 +25,7 @@ public class Song implements Parcelable {
|
|||
public String artistName;
|
||||
|
||||
public String primary;
|
||||
public String blurHash;
|
||||
public boolean favorite;
|
||||
|
||||
public String path;
|
||||
|
|
@ -59,6 +61,10 @@ public class Song implements Parcelable {
|
|||
this.primary = itemDto.getAlbumPrimaryImageTag() != null ? albumId : null;
|
||||
this.favorite = itemDto.getUserData() != null && itemDto.getUserData().getIsFavorite();
|
||||
|
||||
if (itemDto.getImageBlurHashes().get(ImageType.Primary) != null) {
|
||||
this.blurHash = (String) itemDto.getImageBlurHashes().get(ImageType.Primary).values().toArray()[0];
|
||||
}
|
||||
|
||||
if (itemDto.getMediaSources() != null && itemDto.getMediaSources().get(0) != null) {
|
||||
MediaSourceInfo source = itemDto.getMediaSources().get(0);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.dkanada.gramophone.service;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
|
|
@ -520,6 +521,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
.build());
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void updateMediaSessionMetaData() {
|
||||
final Song song = getCurrentSong();
|
||||
|
||||
|
|
@ -545,7 +547,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
if (PreferenceUtil.getInstance(this).getShowAlbumCover()) {
|
||||
final Point screenSize = Util.getScreenSize(MusicService.this);
|
||||
final RequestBuilder<Bitmap> request = CustomGlideRequest.Builder
|
||||
.from(Glide.with(MusicService.this), song.primary)
|
||||
.from(MusicService.this, song.primary, song.blurHash)
|
||||
.bitmap().build();
|
||||
|
||||
if (PreferenceUtil.getInstance(this).getBlurAlbumCover()) {
|
||||
|
|
|
|||
|
|
@ -89,8 +89,9 @@ public class PlayingNotificationImpl extends PlayingNotification {
|
|||
Glide.with(service).clear(target);
|
||||
}
|
||||
|
||||
target = CustomGlideRequest.Builder.from(Glide.with(service), song.primary)
|
||||
.palette(service).build()
|
||||
target = CustomGlideRequest.Builder
|
||||
.from(service, song.primary, song.blurHash)
|
||||
.palette().build()
|
||||
.into(new SimpleTarget<BitmapPaletteWrapper>(bigNotificationImageSize, bigNotificationImageSize) {
|
||||
@Override
|
||||
public void onResourceReady(BitmapPaletteWrapper resource, Transition<? super BitmapPaletteWrapper> glideAnimation) {
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ public class PlayingNotificationImpl24 extends PlayingNotification {
|
|||
|
||||
final int bigNotificationImageSize = service.getResources().getDimensionPixelSize(R.dimen.notification_big_image_size);
|
||||
service.runOnUiThread(() -> CustomGlideRequest.Builder
|
||||
.from(Glide.with(service), song.primary)
|
||||
.palette(service).build()
|
||||
.from(service, song.primary, song.blurHash)
|
||||
.palette().build()
|
||||
.into(new SimpleTarget<BitmapPaletteWrapper>(bigNotificationImageSize, bigNotificationImageSize) {
|
||||
@Override
|
||||
public void onResourceReady(BitmapPaletteWrapper resource, Transition<? super BitmapPaletteWrapper> glideAnimation) {
|
||||
|
|
|
|||
|
|
@ -110,9 +110,8 @@ public class AlbumDetailActivity extends AbsSlidingMusicPanelActivity implements
|
|||
|
||||
private void loadAlbumCover(String primary) {
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(this), primary)
|
||||
.palette(this).build()
|
||||
.dontAnimate()
|
||||
.from(this, primary, primary)
|
||||
.palette().build().dontAnimate()
|
||||
.into(new CustomPaletteTarget(binding.image) {
|
||||
@Override
|
||||
public void onColorReady(int color) {
|
||||
|
|
|
|||
|
|
@ -146,9 +146,8 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement
|
|||
|
||||
private void loadArtistImage(String primary) {
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(this), primary)
|
||||
.palette(this).build()
|
||||
.dontAnimate()
|
||||
.from(this, primary, primary)
|
||||
.palette().build().dontAnimate()
|
||||
.into(new CustomPaletteTarget(binding.image) {
|
||||
@Override
|
||||
public void onColorReady(int color) {
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity {
|
|||
navigationBinding.text.setText(MusicUtil.getSongInfoString(song));
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(Glide.with(this), song.primary)
|
||||
.from(this, song.primary, song.blurHash)
|
||||
.build().into(navigationBinding.image);
|
||||
} else if (binding.navigationView.getHeaderCount() != 0) {
|
||||
binding.navigationView.removeHeaderView(navigationBinding.getRoot());
|
||||
|
|
|
|||
|
|
@ -96,7 +96,8 @@ public class AppWidgetAlbum extends BaseAppWidget {
|
|||
Glide.with(appContext).clear(target);
|
||||
}
|
||||
|
||||
target = CustomGlideRequest.Builder.from(Glide.with(appContext), song.primary)
|
||||
target = CustomGlideRequest.Builder
|
||||
.from(appContext, song.primary, song.blurHash)
|
||||
.bitmap().build()
|
||||
.into(new SimpleTarget<Bitmap>(widgetImageSize, widgetImageSize) {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -100,9 +100,9 @@ public class AppWidgetCard extends BaseAppWidget {
|
|||
Glide.with(service).clear(target);
|
||||
}
|
||||
|
||||
target = CustomGlideRequest.Builder.from(Glide.with(service), song.primary)
|
||||
.palette(service).build()
|
||||
.centerCrop()
|
||||
target = CustomGlideRequest.Builder
|
||||
.from(service, song.primary, song.blurHash)
|
||||
.palette().build()
|
||||
.into(new SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
|
||||
@Override
|
||||
public void onResourceReady(BitmapPaletteWrapper resource, Transition<? super BitmapPaletteWrapper> glideAnimation) {
|
||||
|
|
|
|||
|
|
@ -93,9 +93,9 @@ public class AppWidgetClassic extends BaseAppWidget {
|
|||
Glide.with(appContext).clear(target);
|
||||
}
|
||||
|
||||
target = CustomGlideRequest.Builder.from(Glide.with(appContext), song.primary)
|
||||
.palette(service).build()
|
||||
.centerCrop()
|
||||
target = CustomGlideRequest.Builder
|
||||
.from(appContext, song.primary, song.blurHash)
|
||||
.palette().build()
|
||||
.into(new SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
|
||||
@Override
|
||||
public void onResourceReady(BitmapPaletteWrapper resource, Transition<? super BitmapPaletteWrapper> glideAnimation) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue