Replaced Ion with Glide. Big performance boost, and should also fix the FCs many people get because of recycled bitmaps. Fixed the ripple flickering by using ?selectableItemBackground on Lollipop again instead of custom ripple. Search is broken for now, remake in progress.

This commit is contained in:
Karim Abou Zeid 2015-04-22 21:17:38 +02:00
commit ee2b661eb4
34 changed files with 448 additions and 667 deletions

View file

@ -2,6 +2,7 @@ package com.kabouzeid.gramophone.adapter;
import android.app.Activity;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.v4.util.Pair;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.RecyclerView;
@ -12,6 +13,12 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.loader.AlbumLoader;
@ -23,11 +30,6 @@ import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.ImageViewBitmapInfo;
import com.koushikdutta.ion.Ion;
import com.koushikdutta.ion.bitmap.BitmapInfo;
import com.squareup.otto.Subscribe;
import java.util.List;
@ -51,9 +53,9 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
@Override
public void onViewRecycled(ViewHolder holder) {
super.onViewRecycled(holder);
Object tag = holder.image.getTag();
if (tag instanceof Future) {
((Future) tag).cancel();
Object tag = holder.albumArt.getTag();
if (tag instanceof Request) {
((Request) tag).clear();
}
}
@ -63,35 +65,30 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
resetColors(holder.title, holder.artist, holder.footer);
holder.title.setText(album.title);
holder.artist.setText(album.artistName);
holder.image.setTag(
Ion.with(activity)
.load(MusicUtil.getAlbumArtUri(album.id).toString())
.withBitmap()
.resize(holder.image.getWidth(), holder.image.getHeight())
.centerCrop()
.intoImageView(holder.image)
.withBitmapInfo()
.setCallback(new FutureCallback<ImageViewBitmapInfo>() {
holder.albumArt.setTag(
Glide.with(activity)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(album.id))
.error(R.drawable.default_album_art)
.listener(new RequestListener<Uri, GlideDrawable>() {
@Override
public void onCompleted(Exception e, ImageViewBitmapInfo result) {
if (result != null) {
BitmapInfo info = result.getBitmapInfo();
if (info != null) {
Bitmap bitmap = info.bitmap;
if (bitmap != null) {
if (usePalette)
applyPalette(bitmap, holder.title, holder.artist, holder.footer);
return;
}
}
}
holder.image.setImageResource(R.drawable.default_album_art);
public boolean onException(Exception e, Uri model, Target<GlideDrawable> target, boolean isFirstResource) {
if (usePalette)
paletteBlackAndWhite(holder.title, holder.artist, holder.footer);
applyPalette(null, holder.title, holder.artist, holder.footer);
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, Uri model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
if (usePalette)
applyPalette(((GlideBitmapDrawable) resource).getBitmap(), holder.title, holder.artist, holder.footer);
return false;
}
})
.into(holder.albumArt)
.getRequest()
);
}
@ -101,14 +98,14 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
final ImageView image;
final ImageView albumArt;
final TextView title;
final TextView artist;
final View footer;
public ViewHolder(View itemView) {
super(itemView);
image = (ImageView) itemView.findViewById(R.id.album_art);
albumArt = (ImageView) itemView.findViewById(R.id.album_art);
title = (TextView) itemView.findViewById(R.id.album_title);
artist = (TextView) itemView.findViewById(R.id.album_interpret);
footer = itemView.findViewById(R.id.footer);
@ -118,7 +115,7 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
@Override
public void onClick(View v) {
Pair[] albumPairs = new Pair[]{
Pair.create(image,
Pair.create(albumArt,
activity.getResources().getString(R.string.transition_album_cover)
)};
if (activity instanceof AbsFabActivity)
@ -138,20 +135,24 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
}
private void applyPalette(Bitmap bitmap, final TextView title, final TextView artist, final View footer) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
title.setTextColor(vibrantSwatch.getTitleTextColor());
artist.setTextColor(vibrantSwatch.getTitleTextColor());
ViewUtil.animateViewColor(footer, DialogUtils.resolveColor(activity, R.attr.default_bar_color), vibrantSwatch.getRgb());
} else {
paletteBlackAndWhite(title, artist, footer);
if (bitmap != null) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
title.setTextColor(vibrantSwatch.getTitleTextColor());
artist.setTextColor(vibrantSwatch.getTitleTextColor());
ViewUtil.animateViewColor(footer, DialogUtils.resolveColor(activity, R.attr.default_bar_color), vibrantSwatch.getRgb());
} else {
paletteBlackAndWhite(title, artist, footer);
}
}
}
});
});
} else {
paletteBlackAndWhite(title, artist, footer);
}
}
private void paletteBlackAndWhite(final TextView title, final TextView artist, final View footer) {

View file

@ -1,7 +1,6 @@
package com.kabouzeid.gramophone.adapter;
import android.app.Activity;
import android.graphics.Bitmap;
import android.support.v4.util.Pair;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@ -10,6 +9,7 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.lastfm.artist.LastFMArtistThumbnailUrlLoader;
@ -17,9 +17,8 @@ import com.kabouzeid.gramophone.loader.ArtistLoader;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import com.squareup.otto.Subscribe;
import java.util.List;
@ -51,25 +50,16 @@ public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder
final Artist artist = dataSet.get(position);
holder.artistName.setText(artist.name);
holder.artistInfo.setText(artist.getSubTitle());
holder.artistInfo.setText(MusicUtil.getArtistInfoString(activity, artist));
holder.artistImage.setImageResource(R.drawable.default_artist_image);
LastFMArtistThumbnailUrlLoader.loadArtistThumbnailUrl(activity, artist.name, false, new LastFMArtistThumbnailUrlLoader.ArtistThumbnailUrlLoaderCallback() {
@Override
public void onArtistThumbnailUrlLoaded(final String url) {
Ion.with(activity)
Glide.with(activity)
.load(url)
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
@Override
public void onCompleted(Exception e, Bitmap result) {
if (result != null)
holder.artistImage.setImageBitmap(result);
else {
holder.artistImage.setImageResource(R.drawable.default_artist_image);
}
}
});
.error(R.drawable.default_artist_image)
.into(holder.artistImage);
}
});
}

View file

@ -9,12 +9,13 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.Request;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.koushikdutta.ion.Ion;
import java.util.List;
@ -44,17 +45,25 @@ public class ArtistAlbumAdapter extends RecyclerView.Adapter<ArtistAlbumAdapter.
return new ViewHolder(view);
}
@Override
public void onViewRecycled(ViewHolder holder) {
super.onViewRecycled(holder);
Object tag = holder.albumArt.getTag();
if (tag instanceof Request) {
((Request) tag).clear();
}
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final Album album = dataSet.get(position);
Ion.with(activity)
.load(MusicUtil.getAlbumArtUri(album.id).toString())
.withBitmap()
.resize(holder.albumArt.getWidth(), holder.albumArt.getHeight())
.centerCrop()
.error(R.drawable.default_album_art)
.intoImageView(holder.albumArt);
holder.albumArt.setTag(Glide.with(activity)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(album.id))
.error(R.drawable.default_album_art)
.into(holder.albumArt)
.getRequest()
);
holder.title.setText(album.title);
holder.year.setText(String.valueOf(album.year));

View file

@ -1,91 +1,39 @@
package com.kabouzeid.gramophone.adapter;
import android.graphics.Color;
import android.graphics.Typeface;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.model.SearchEntry;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.SearchActivity;
import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class SearchAdapter extends ArrayAdapter<SearchEntry> {
public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder> {
private Activity activity;
private final AppCompatActivity activity;
public SearchAdapter(AppCompatActivity activity, List<SearchEntry> objects) {
super(activity, R.layout.item_list_search, objects);
public SearchAdapter(AppCompatActivity activity) {
this.activity = activity;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_list_search, parent, false);
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return 0;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
final SearchEntry item = getItem(position);
final TextView title = (TextView) convertView.findViewById(R.id.title);
final TextView subTitle = (TextView) convertView.findViewById(R.id.sub_title);
final ImageView imageView = (ImageView) convertView.findViewById(R.id.image);
final ImageView overflowButton = (ImageView) convertView.findViewById(R.id.menu);
if (item instanceof SearchActivity.LabelEntry) {
title.setTypeface(null, Typeface.BOLD);
subTitle.setVisibility(View.GONE);
imageView.setVisibility(View.GONE);
overflowButton.setVisibility(View.GONE);
convertView.setBackgroundColor(DialogUtils.resolveColor(getContext(), R.attr.default_bar_color));
} else if (item instanceof Song) {
title.setTypeface(null, Typeface.NORMAL);
subTitle.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
convertView.setBackgroundColor(Color.TRANSPARENT);
overflowButton.setVisibility(View.VISIBLE);
overflowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
PopupMenu popupMenu = new PopupMenu(activity, view);
popupMenu.inflate(R.menu.menu_item_song);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
return MenuItemClickHelper.handleSongMenuClick(activity, (Song) item, menuItem);
}
});
popupMenu.show();
}
});
} else {
title.setTypeface(null, Typeface.NORMAL);
subTitle.setVisibility(View.VISIBLE);
imageView.setVisibility(View.VISIBLE);
overflowButton.setVisibility(View.GONE);
convertView.setBackgroundColor(Color.TRANSPARENT);
}
title.setText(item.getTitle());
subTitle.setText(item.getSubTitle());
imageView.setImageBitmap(null);
item.loadImage(getContext(), imageView);
return convertView;
}
}

View file

@ -11,13 +11,13 @@ import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.koushikdutta.ion.Ion;
import java.util.List;
@ -47,13 +47,10 @@ public class ArtistSongAdapter extends ArrayAdapter<Song> {
songTitle.setText(song.title);
songInfo.setText(song.albumName);
Ion.with(activity)
.load(MusicUtil.getAlbumArtUri(song.albumId).toString())
.withBitmap()
.resize(albumArt.getWidth(), albumArt.getHeight())
.centerCrop()
Glide.with(activity)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(song.albumId))
.error(R.drawable.default_album_art)
.intoImageView(albumArt);
.into(albumArt);
final ImageView overflowButton = (ImageView) convertView.findViewById(R.id.menu);
overflowButton.setOnClickListener(new View.OnClickListener() {

View file

@ -11,6 +11,8 @@ import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.Request;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
@ -20,7 +22,6 @@ import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PlaylistsUtil;
import com.koushikdutta.ion.Ion;
import java.util.ArrayList;
import java.util.List;
@ -48,6 +49,10 @@ public class PlaylistSongAdapter extends RecyclerView.Adapter<PlaylistSongAdapte
@Override
public void onViewRecycled(ViewHolder holder) {
super.onViewRecycled(holder);
Object tag = holder.albumArt.getTag();
if (tag instanceof Request) {
((Request) tag).clear();
}
}
@Override
@ -56,15 +61,12 @@ public class PlaylistSongAdapter extends RecyclerView.Adapter<PlaylistSongAdapte
holder.songTitle.setText(song.title);
holder.songInfo.setText(song.artistName);
holder.albumArt.setTag(
Ion.with(activity)
.load(MusicUtil.getAlbumArtUri(song.albumId).toString())
.withBitmap()
.resize(holder.albumArt.getWidth(), holder.albumArt.getHeight())
.centerCrop()
Glide.with(activity)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(song.albumId))
.error(R.drawable.default_album_art)
.intoImageView(holder.albumArt)
.into(holder.albumArt)
.getRequest()
);
}

View file

@ -13,6 +13,8 @@ import android.widget.PopupMenu;
import android.widget.TextView;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.Request;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
@ -23,7 +25,6 @@ import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.koushikdutta.ion.Ion;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
@ -55,6 +56,15 @@ public class SongAdapter extends RecyclerView.Adapter<SongAdapter.ViewHolder> {
return new ViewHolder(view);
}
@Override
public void onViewRecycled(ViewHolder holder) {
super.onViewRecycled(holder);
Object tag = holder.albumArt.getTag();
if (tag instanceof Request) {
((Request) tag).clear();
}
}
@Override
public int getItemViewType(int position) {
return position == 0 ? SHUFFLE_BUTTON : SONG;
@ -67,14 +77,13 @@ public class SongAdapter extends RecyclerView.Adapter<SongAdapter.ViewHolder> {
holder.songTitle.setText(song.title);
holder.songInfo.setText(song.artistName);
Ion.with(activity)
.load(MusicUtil.getAlbumArtUri(song.albumId).toString())
.withBitmap()
.resize(holder.albumArt.getWidth(), holder.albumArt.getHeight())
.centerCrop()
.error(R.drawable.default_album_art)
.intoImageView(holder.albumArt);
holder.albumArt.setTag(
Glide.with(activity)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(song.albumId))
.error(R.drawable.default_album_art)
.into(holder.albumArt)
.getRequest()
);
} else {
holder.songTitle.setText(activity.getResources().getString(R.string.shuffle_all).toUpperCase());
holder.songTitle.setTextColor(ThemeSingleton.get().positiveColor);

View file

@ -7,21 +7,23 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.widget.RemoteViews;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MusicControllerActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
public class MusicPlayerWidget extends AppWidgetProvider {
private static RemoteViews widgetLayout;
private static Future albumArtTask;
private static Request albumArtRequest;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
@ -59,27 +61,35 @@ public class MusicPlayerWidget extends AppWidgetProvider {
}
private static void loadAlbumArt(final Context context, final Song song) {
if (albumArtTask != null) albumArtTask.cancel();
albumArtTask = Ion.with(context)
.load(MusicUtil.getAlbumArtUri(song.albumId).toString())
.noCache()
if (albumArtRequest != null) albumArtRequest.clear();
final int notificationAlbumArtSize = context.getResources().getDimensionPixelSize(R.dimen.app_widget_small_artwork_height);
albumArtRequest = Glide.with(context)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(song.albumId))
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
.skipMemoryCache(true)
.listener(new RequestListener<Uri, Bitmap>() {
@Override
public void onCompleted(Exception e, Bitmap result) {
if (result != null) setAlbumArt(context, result);
else resetAlbumArt(context);
public boolean onException(Exception e, Uri model, Target<Bitmap> target, boolean isFirstResource) {
setAlbumArt(context, null);
return false;
}
});
}
private static void resetAlbumArt(final Context context) {
widgetLayout.setImageViewResource(R.id.album_art, R.drawable.default_album_art);
updateWidgets(context);
@Override
public boolean onResourceReady(Bitmap resource, Uri model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
setAlbumArt(context, resource);
return false;
}
})
.into(notificationAlbumArtSize, notificationAlbumArtSize)
.getRequest();
}
private static void setAlbumArt(final Context context, final Bitmap albumArt) {
widgetLayout.setImageViewBitmap(R.id.album_art, albumArt);
if (albumArt != null) {
widgetLayout.setImageViewBitmap(R.id.album_art, albumArt);
} else {
widgetLayout.setImageViewResource(R.id.album_art, R.drawable.default_album_art);
}
updateWidgets(context);
}

View file

@ -44,7 +44,7 @@ public class DeleteSongsDialog extends DialogFragment {
content = Html.fromHtml(getString(R.string.delete_x_songs, songs.size()));
} else {
title = R.string.delete_song_title;
content = Html.fromHtml(getString(R.string.delete_song_x, songs.get(0).getTitle()));
content = Html.fromHtml(getString(R.string.delete_song_x, songs.get(0).title));
}
return new MaterialDialog.Builder(getActivity())
.title(title)

View file

@ -12,17 +12,19 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.widget.RemoteViews;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MusicControllerActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
public class PlayingNotificationHelper {
@ -37,7 +39,8 @@ public class PlayingNotificationHelper {
private RemoteViews notificationLayout;
private RemoteViews notificationLayoutExpanded;
private Future albumArtTask;
private Request albumArtRequest;
private Song currentSong;
public PlayingNotificationHelper(final MusicService service) {
this.service = service;
@ -46,6 +49,7 @@ public class PlayingNotificationHelper {
}
public void buildNotification(final Song song, final boolean isPlaying) {
currentSong = song;
notificationLayout = new RemoteViews(service.getPackageName(),
R.layout.notification_playing);
notificationLayoutExpanded = new RemoteViews(service.getPackageName(),
@ -61,9 +65,9 @@ public class PlayingNotificationHelper {
.build();
notification.bigContentView = notificationLayoutExpanded;
setUpCollapsedLayout(song);
setUpExpandedLayout(song);
loadAlbumArt(song);
setUpCollapsedLayout();
setUpExpandedLayout();
loadAlbumArt();
setUpPlaybackActions(isPlaying);
setUpExpandedPlaybackActions(isPlaying);
@ -140,41 +144,55 @@ public class PlayingNotificationHelper {
return null;
}
private void setUpCollapsedLayout(final Song song) {
notificationLayout.setTextViewText(R.id.song_title, song.title);
notificationLayout.setTextViewText(R.id.song_artist, song.artistName);
private void setUpCollapsedLayout() {
if (currentSong != null) {
notificationLayout.setTextViewText(R.id.song_title, currentSong.title);
notificationLayout.setTextViewText(R.id.song_artist, currentSong.artistName);
}
}
private void setUpExpandedLayout(final Song song) {
notificationLayoutExpanded.setTextViewText(R.id.song_title, song.title);
notificationLayoutExpanded.setTextViewText(R.id.song_artist, song.artistName);
notificationLayoutExpanded.setTextViewText(R.id.album_title, song.albumName);
private void setUpExpandedLayout() {
if (currentSong != null) {
notificationLayoutExpanded.setTextViewText(R.id.song_title, currentSong.title);
notificationLayoutExpanded.setTextViewText(R.id.song_artist, currentSong.artistName);
notificationLayoutExpanded.setTextViewText(R.id.album_title, currentSong.albumName);
}
}
private void loadAlbumArt(final Song song) {
if (albumArtTask != null) albumArtTask.cancel();
albumArtTask = Ion.with(service)
.load(MusicUtil.getAlbumArtUri(song.albumId).toString())
.noCache()
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
@Override
public void onCompleted(Exception e, Bitmap result) {
if (result != null) setAlbumArt(result);
else resetAlbumArt();
}
});
}
private void loadAlbumArt() {
if (currentSong != null) {
if (albumArtRequest != null) albumArtRequest.clear();
final int notificationAlbumArtSize = service.getResources().getDimensionPixelSize(R.dimen.notification_albumart_size);
albumArtRequest = Glide.with(service)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(currentSong.albumId))
.asBitmap()
.skipMemoryCache(true)
.listener(new RequestListener<Uri, Bitmap>() {
@Override
public boolean onException(Exception e, Uri model, Target<Bitmap> target, boolean isFirstResource) {
setAlbumArt(null);
return false;
}
private void resetAlbumArt() {
notificationLayout.setImageViewResource(R.id.album_art, R.drawable.default_album_art);
notificationLayoutExpanded.setImageViewResource(R.id.album_art, R.drawable.default_album_art);
notificationManager.notify(NOTIFICATION_ID, notification);
@Override
public boolean onResourceReady(Bitmap resource, Uri model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
setAlbumArt(resource);
return false;
}
})
.into(notificationAlbumArtSize, notificationAlbumArtSize)
.getRequest();
}
}
private void setAlbumArt(Bitmap albumArt) {
notificationLayout.setImageViewBitmap(R.id.album_art, albumArt);
notificationLayoutExpanded.setImageViewBitmap(R.id.album_art, albumArt);
if (albumArt != null) {
notificationLayout.setImageViewBitmap(R.id.album_art, albumArt);
notificationLayoutExpanded.setImageViewBitmap(R.id.album_art, albumArt);
} else {
notificationLayout.setImageViewResource(R.id.album_art, R.drawable.default_album_art);
notificationLayoutExpanded.setImageViewResource(R.id.album_art, R.drawable.default_album_art);
}
notificationManager.notify(NOTIFICATION_ID, notification);
}

View file

@ -1,16 +1,9 @@
package com.kabouzeid.gramophone.model;
import android.content.Context;
import android.widget.ImageView;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.koushikdutta.ion.Ion;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class Album implements SearchEntry {
public class Album {
public final int id;
public int artistId;
@ -36,31 +29,4 @@ public class Album implements SearchEntry {
songCount = -1;
year = -1;
}
@Override
public String getTitle() {
return title;
}
@Override
public String getSubTitle() {
return artistName;
}
@Override
public void loadImage(final Context context, final ImageView imageView) {
imageView.setImageResource(R.drawable.default_album_art);
imageView.post(new Runnable() {
@Override
public void run() {
Ion.with(context)
.load(MusicUtil.getAlbumArtUri(id).toString())
.withBitmap()
.resize(imageView.getWidth(), imageView.getHeight())
.centerCrop()
.error(R.drawable.default_album_art)
.intoImageView(imageView);
}
});
}
}

View file

@ -1,16 +1,9 @@
package com.kabouzeid.gramophone.model;
import android.content.Context;
import android.widget.ImageView;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.lastfm.artist.LastFMArtistThumbnailUrlLoader;
import com.koushikdutta.ion.Ion;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class Artist implements SearchEntry {
public class Artist {
public final int id;
public final String name;
public final int albumCount;
@ -29,36 +22,4 @@ public class Artist implements SearchEntry {
songCount = -1;
albumCount = -1;
}
@Override
public String getTitle() {
return name;
}
@Override
public String getSubTitle() {
return songCount + " Songs | " + albumCount + " Albums";
}
@Override
public void loadImage(final Context context, final ImageView imageView) {
imageView.setImageResource(R.drawable.default_artist_image);
LastFMArtistThumbnailUrlLoader.loadArtistThumbnailUrl(context, name, false, new LastFMArtistThumbnailUrlLoader.ArtistThumbnailUrlLoaderCallback() {
@Override
public void onArtistThumbnailUrlLoaded(final String url) {
imageView.post(new Runnable() {
@Override
public void run() {
Ion.with(context)
.load(url)
.withBitmap()
.resize(imageView.getWidth(), imageView.getHeight())
.centerCrop()
.error(R.drawable.default_artist_image)
.intoImageView(imageView);
}
});
}
});
}
}

View file

@ -1,15 +0,0 @@
package com.kabouzeid.gramophone.model;
import android.content.Context;
import android.widget.ImageView;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public interface SearchEntry {
String getTitle();
String getSubTitle();
void loadImage(Context context, ImageView imageView);
}

View file

@ -1,14 +1,11 @@
package com.kabouzeid.gramophone.model;
import android.content.Context;
import android.widget.ImageView;
import java.io.Serializable;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class Song implements Serializable, SearchEntry {
public class Song implements Serializable {
public int id;
public final int albumId;
@ -41,19 +38,4 @@ public class Song implements Serializable, SearchEntry {
this.duration = -1;
this.trackNumber = -1;
}
@Override
public String getTitle() {
return title;
}
@Override
public String getSubTitle() {
return artistName;
}
@Override
public void loadImage(Context context, ImageView imageView) {
}
}

View file

@ -22,6 +22,10 @@ import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.appwidget.MusicPlayerWidget;
@ -32,9 +36,6 @@ import com.kabouzeid.gramophone.model.MusicRemoteEvent;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.InternalStorageUtil;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import java.io.IOException;
import java.util.ArrayList;
@ -79,7 +80,7 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe
private PlayingNotificationHelper playingNotificationHelper;
private AudioManager audioManager;
private RemoteControlClient remoteControlClient;
private Future remoteControlClientAlbumArtTask;
private Request remoteControlClientAlbumArtRequest;
private PowerManager.WakeLock wakeLock;
public MusicService() {
@ -357,17 +358,26 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe
.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, song.duration)
.apply();
if (remoteControlClientAlbumArtTask != null) remoteControlClientAlbumArtTask.cancel();
remoteControlClientAlbumArtTask = Ion.with(this)
.load(MusicUtil.getAlbumArtUri(song.albumId).toString())
.noCache()
if (remoteControlClientAlbumArtRequest != null) remoteControlClientAlbumArtRequest.clear();
remoteControlClientAlbumArtRequest = Glide.with(this)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(song.albumId))
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
.skipMemoryCache(true)
.listener(new RequestListener<Uri, Bitmap>() {
@Override
public void onCompleted(Exception e, Bitmap result) {
updateRemoteControlClientBitmap(result);
public boolean onException(Exception e, Uri model, Target<Bitmap> target, boolean isFirstResource) {
updateRemoteControlClientBitmap(null);
return false;
}
});
@Override
public boolean onResourceReady(Bitmap resource, Uri model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
updateRemoteControlClientBitmap(resource);
return false;
}
})
.into(-1, -1)
.getRequest();
}
private void updateRemoteControlClientBitmap(final Bitmap albumArt) {

View file

@ -4,6 +4,7 @@ import android.annotation.TargetApi;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.util.Pair;
@ -17,6 +18,11 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
@ -37,8 +43,6 @@ import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import com.nineoldandroids.view.ViewHelper;
import com.squareup.otto.Subscribe;
@ -170,51 +174,54 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
}
private void setUpAlbumArtAndApplyPalette() {
albumArtImageView.post(new Runnable() {
@Override
public void run() {
Ion.with(AlbumDetailActivity.this)
.load(MusicUtil.getAlbumArtUri(album.id).toString())
.withBitmap()
.smartSize(false)
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onCompleted(Exception e, Bitmap result) {
if (result != null) {
albumArtImageView.setImageBitmap(result);
applyPalette(result);
} else {
albumArtImageView.setImageResource(R.drawable.default_album_art);
resetColors();
}
if (Util.isAtLeastLollipop()) startPostponedEnterTransition();
}
});
}
});
Glide.with(AlbumDetailActivity.this)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(album.id))
.error(R.drawable.default_album_art)
.listener(new RequestListener<Uri, GlideDrawable>() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onException(Exception e, Uri model, Target<GlideDrawable> target, boolean isFirstResource) {
applyPalette(null);
if (Util.isAtLeastLollipop()) startPostponedEnterTransition();
return false;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onResourceReady(GlideDrawable resource, Uri model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
applyPalette(((GlideBitmapDrawable) resource).getBitmap());
if (Util.isAtLeastLollipop()) startPostponedEnterTransition();
// workaround for glide not working well with shared element, dont remove this redundant looking call!
albumArtImageView.setImageDrawable(resource);
return false;
}
})
.into(albumArtImageView);
}
private void applyPalette(Bitmap bitmap) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
toolbarColor = vibrantSwatch.getRgb();
albumTitleView.setBackgroundColor(toolbarColor);
albumTitleView.setTextColor(vibrantSwatch.getTitleTextColor());
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(AlbumDetailActivity.this).coloredNavigationBarAlbumEnabled())
getWindow().setNavigationBarColor(toolbarColor);
notifyTaskColorChange(toolbarColor);
} else {
resetColors();
if (bitmap != null) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
toolbarColor = vibrantSwatch.getRgb();
albumTitleView.setBackgroundColor(toolbarColor);
albumTitleView.setTextColor(vibrantSwatch.getTitleTextColor());
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(AlbumDetailActivity.this).coloredNavigationBarAlbumEnabled())
getWindow().setNavigationBarColor(toolbarColor);
notifyTaskColorChange(toolbarColor);
} else {
resetColors();
}
}
}
});
});
} else {
resetColors();
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)

View file

@ -24,6 +24,11 @@ import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.github.ksoichiro.android.observablescrollview.ObservableListView;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
@ -47,8 +52,6 @@ import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import com.nineoldandroids.view.ViewHelper;
import com.squareup.otto.Subscribe;
@ -265,51 +268,50 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
LastFMArtistImageUrlLoader.loadArtistImageUrl(this, artist.name, forceDownload, new LastFMArtistImageUrlLoader.ArtistImageUrlLoaderCallback() {
@Override
public void onArtistImageUrlLoaded(final String url) {
artistImage.post(new Runnable() {
@Override
public void run() {
Ion.with(ArtistDetailActivity.this)
.load(url)
.withBitmap()
.smartSize(false)
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
@Override
public void onCompleted(Exception e, Bitmap result) {
if (result != null) {
artistImage.setImageBitmap(result);
applyPalette(result);
} else {
artistImage.setImageResource(R.drawable.default_artist_image);
resetColors();
}
}
});
}
});
Glide.with(ArtistDetailActivity.this)
.load(url)
.error(R.drawable.default_artist_image)
.listener(new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
applyPalette(null);
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
applyPalette(((GlideBitmapDrawable) resource).getBitmap());
return false;
}
})
.into(artistImage);
}
});
}
private void applyPalette(Bitmap bitmap) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
toolbarColor = vibrantSwatch.getRgb();
artistNameTv.setBackgroundColor(vibrantSwatch.getRgb());
artistNameTv.setTextColor(vibrantSwatch.getTitleTextColor());
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(ArtistDetailActivity.this).coloredNavigationBarArtistEnabled())
getWindow().setNavigationBarColor(vibrantSwatch.getRgb());
notifyTaskColorChange(toolbarColor);
} else {
resetColors();
if (bitmap != null) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
toolbarColor = vibrantSwatch.getRgb();
artistNameTv.setBackgroundColor(vibrantSwatch.getRgb());
artistNameTv.setTextColor(vibrantSwatch.getTitleTextColor());
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(ArtistDetailActivity.this).coloredNavigationBarArtistEnabled())
getWindow().setNavigationBarColor(vibrantSwatch.getRgb());
notifyTaskColorChange(toolbarColor);
} else {
resetColors();
}
}
}
});
});
} else {
resetColors();
}
}
@Override

View file

@ -2,7 +2,6 @@ package com.kabouzeid.gramophone.ui.activities;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@ -28,6 +27,7 @@ import android.widget.FrameLayout;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.astuetz.PagerSlidingTabStrip;
import com.bumptech.glide.Glide;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.PagerAdapter;
import com.kabouzeid.gramophone.dialogs.AboutDialog;
@ -49,8 +49,6 @@ import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import java.lang.reflect.Field;
import java.util.ArrayList;
@ -204,22 +202,13 @@ public class MainActivity extends AbsFabActivity
if (navigationDrawerFragment != null) {
Song song = MusicPlayerRemote.getCurrentSong();
if (song.id != -1) {
Ion.with(this)
.load(MusicUtil.getAlbumArtUri(song.albumId).toString())
.withBitmap()
.smartSize(false)
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
@Override
public void onCompleted(Exception e, Bitmap result) {
if (result != null)
navigationDrawerFragment.getAlbumArtImageView().setImageBitmap(result);
else
navigationDrawerFragment.getAlbumArtImageView().setImageResource(R.drawable.default_album_art);
}
});
navigationDrawerFragment.getSongTitle().setText(song.title);
navigationDrawerFragment.getSongArtist().setText(song.artistName);
Glide.with(this)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(song.albumId))
.error(R.drawable.default_album_art)
.placeholder(R.drawable.default_album_art)
.into(navigationDrawerFragment.getAlbumArtImageView());
}
}
}

View file

@ -5,6 +5,7 @@ import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.graphics.Palette;
@ -22,6 +23,11 @@ import android.widget.Toast;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
@ -41,8 +47,6 @@ import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import com.nineoldandroids.view.ViewPropertyAnimator;
import com.squareup.otto.Subscribe;
@ -56,7 +60,7 @@ public class MusicControllerActivity extends AbsFabActivity {
private Song song;
private ImageView albumArt;
private ImageView artistArt;
private ImageView artistImage;
private TextView songTitle;
private TextView songArtist;
private TextView currentSongProgress;
@ -118,7 +122,7 @@ public class MusicControllerActivity extends AbsFabActivity {
repeatButton = (ImageButton) findViewById(R.id.repeat_button);
shuffleButton = (ImageButton) findViewById(R.id.shuffle_button);
albumArt = (ImageView) findViewById(R.id.album_art);
artistArt = (ImageView) findViewById(R.id.artist_image);
artistImage = (ImageView) findViewById(R.id.artist_image);
songTitle = (TextView) findViewById(R.id.song_title);
songArtist = (TextView) findViewById(R.id.song_artist);
currentSongProgress = (TextView) findViewById(R.id.song_current_progress);
@ -294,48 +298,47 @@ public class MusicControllerActivity extends AbsFabActivity {
}
private void setUpAlbumArtAndApplyPalette() {
albumArt.post(new Runnable() {
@Override
public void run() {
Ion.with(MusicControllerActivity.this)
.load(MusicUtil.getAlbumArtUri(song.albumId).toString())
.withBitmap()
.smartSize(false)
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onCompleted(Exception e, Bitmap result) {
if (result != null) {
albumArt.setImageBitmap(result);
applyPalette(result);
} else {
albumArt.setImageResource(R.drawable.default_album_art);
resetColors();
}
}
});
}
});
Glide.with(this)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(song.albumId))
.error(R.drawable.default_album_art)
.placeholder(R.drawable.default_album_art)
.listener(new RequestListener<Uri, GlideDrawable>() {
@Override
public boolean onException(Exception e, Uri model, Target<GlideDrawable> target, boolean isFirstResource) {
applyPalette(null);
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, Uri model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
applyPalette(((GlideBitmapDrawable) resource).getBitmap());
return false;
}
})
.into(albumArt);
}
private void applyPalette(Bitmap bitmap) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
final int swatchRgb = vibrantSwatch.getRgb();
animateColorChange(swatchRgb);
songTitle.setTextColor(vibrantSwatch.getTitleTextColor());
songArtist.setTextColor(vibrantSwatch.getBodyTextColor());
notifyTaskColorChange(swatchRgb);
} else {
resetColors();
if (bitmap != null) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
final int swatchRgb = vibrantSwatch.getRgb();
animateColorChange(swatchRgb);
songTitle.setTextColor(vibrantSwatch.getTitleTextColor());
songArtist.setTextColor(vibrantSwatch.getBodyTextColor());
notifyTaskColorChange(swatchRgb);
} else {
resetColors();
}
}
}
});
});
} else {
resetColors();
}
}
private void resetColors() {
@ -364,14 +367,15 @@ public class MusicControllerActivity extends AbsFabActivity {
}
private void setUpArtistArt() {
if (artistArt != null) {
artistArt.setImageResource(R.drawable.default_artist_image);
if (artistImage != null) {
artistImage.setImageResource(R.drawable.default_artist_image);
LastFMArtistImageUrlLoader.loadArtistImageUrl(this, song.artistName, false, new LastFMArtistImageUrlLoader.ArtistImageUrlLoaderCallback() {
@Override
public void onArtistImageUrlLoaded(String url) {
Ion.with(artistArt)
Glide.with(MusicControllerActivity.this)
.load(url)
.error(R.drawable.default_artist_image)
.load(url);
.into(artistImage);
}
});
}

View file

@ -2,49 +2,33 @@ package com.kabouzeid.gramophone.ui.activities;
import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v4.util.Pair;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.SearchAdapter;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.loader.AlbumLoader;
import com.kabouzeid.gramophone.loader.ArtistLoader;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.SearchEntry;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import java.util.ArrayList;
import java.util.List;
public class SearchActivity extends AbsBaseActivity {
public static final String TAG = SearchActivity.class.getSimpleName();
private ListView listView;
private RecyclerView recyclerView;
private SearchView searchView;
private SearchAdapter searchAdapter;
@SuppressLint("NewApi")
@Override
@ -54,38 +38,11 @@ public class SearchActivity extends AbsBaseActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
listView = (ListView) findViewById(R.id.list);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Object item = parent.getItemAtPosition(position);
if (item instanceof SearchEntry) {
if (item instanceof Song) {
ArrayList<Song> playList = new ArrayList<>();
playList.add((Song) item);
MusicPlayerRemote.openQueue(playList, 0, true);
} else if (item instanceof Album) {
NavigationUtil.goToAlbum(SearchActivity.this,
((Album) item).id,
new Pair[]{
Pair.create(view.findViewById(R.id.image),
getResources().getString(R.string.transition_album_cover)
)
});
} else if (item instanceof Artist) {
NavigationUtil.goToArtist(SearchActivity.this,
((Artist) item).id,
new Pair[]{
Pair.create(view.findViewById(R.id.image),
getResources().getString(R.string.transition_artist_image)
)
});
}
}
}
});
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
searchAdapter = new SearchAdapter(this);
recyclerView.setAdapter(searchAdapter);
listView.setOnTouchListener(new View.OnTouchListener() {
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Util.hideSoftKeyboard(SearchActivity.this);
@ -120,13 +77,13 @@ public class SearchActivity extends AbsBaseActivity {
@Override
public void enableViews() {
super.enableViews();
listView.setEnabled(true);
recyclerView.setEnabled(true);
}
@Override
public void disableViews() {
super.disableViews();
listView.setEnabled(false);
recyclerView.setEnabled(false);
}
@Override
@ -192,65 +149,6 @@ public class SearchActivity extends AbsBaseActivity {
}
private void search(String query) {
List<SearchEntry> results = new ArrayList<>();
if (!query.trim().equals("")) {
LabelEntry songLabel = new LabelEntry(getResources().getString(R.string.songs).toUpperCase());
results.add(songLabel);
List<Song> songs = SongLoader.getSongs(this, query);
results.addAll(songs);
songLabel.setNumber(songs.size());
LabelEntry artistLabel = new LabelEntry(getResources().getString(R.string.artists).toUpperCase());
results.add(artistLabel);
List<Artist> artists = ArtistLoader.getArtists(this, query);
results.addAll(artists);
artistLabel.setNumber(artists.size());
LabelEntry albumLabel = new LabelEntry(getResources().getString(R.string.albums).toUpperCase());
results.add(albumLabel);
List<Album> albums = AlbumLoader.getAlbums(this, query);
results.addAll(albums);
albumLabel.setNumber(albums.size());
}
if (results.size() <= 3) {
results.clear();
results.add(new LabelEntry(getResources().getString(R.string.no_results).toUpperCase()));
}
ArrayAdapter adapter = new SearchAdapter(this, results);
listView.setAdapter(adapter);
}
public static class LabelEntry implements SearchEntry {
final String title;
String label;
public LabelEntry(String label) {
this.label = label;
this.title = label;
}
public void setNumber(int number) {
if (number != -1) {
label = title + " (" + number + ")";
} else {
label = title;
}
}
@Override
public String getTitle() {
return label;
}
@Override
public String getSubTitle() {
return "";
}
@Override
public void loadImage(Context context, ImageView imageView) {
}
}
}

View file

@ -32,7 +32,6 @@ import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.koushikdutta.ion.Ion;
import com.melnykov.fab.FloatingActionButton;
import com.nineoldandroids.view.ViewHelper;
import com.nineoldandroids.view.ViewPropertyAnimator;
@ -378,11 +377,9 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
}
if (deleteArtwork) {
MusicUtil.deleteAlbumArt(AbsTagEditorActivity.this, getId());
Ion.getDefault(AbsTagEditorActivity.this).getBitmapCache().clear();
Ion.getDefault(AbsTagEditorActivity.this).getCache().clear();
//Glide.get(AbsTagEditorActivity.this).clearMemory();
} else if (artwork != null) {
Ion.getDefault(AbsTagEditorActivity.this).getBitmapCache().clear();
Ion.getDefault(AbsTagEditorActivity.this).getCache().clear();
//Glide.get(AbsTagEditorActivity.this).clearMemory();
}
runOnUiThread(new Runnable() {
@Override

View file

@ -9,14 +9,15 @@ import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.lastfm.album.LastFMAlbumImageUrlLoader;
import com.kabouzeid.gramophone.loader.AlbumSongLoader;
import com.kabouzeid.gramophone.loader.SongFilePathLoader;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.images.Artwork;
@ -94,17 +95,22 @@ public class AlbumTagEditorActivity extends AbsTagEditorActivity implements Text
LastFMAlbumImageUrlLoader.loadAlbumImageUrl(this, albumTitleStr, albumArtistNameStr, new LastFMAlbumImageUrlLoader.AlbumImageUrlLoaderCallback() {
@Override
public void onAlbumImageUrlLoaded(String url) {
Ion.with(AlbumTagEditorActivity.this)
Glide.with(AlbumTagEditorActivity.this)
.load(url)
.withBitmap()
.resize(500, 500)
.centerCrop()
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
.centerCrop()
.listener(new RequestListener<String, Bitmap>() {
@Override
public void onCompleted(Exception e, Bitmap result) {
if (result != null) {
albumArtBitmap = result;
public boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {
Toast.makeText(AlbumTagEditorActivity.this,
R.string.failed_download_albumart, Toast.LENGTH_SHORT).show();
return false;
}
@Override
public boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
if (resource != null) {
albumArtBitmap = resource;
setImageBitmap(albumArtBitmap);
deleteAlbumArt = false;
dataChanged();
@ -113,8 +119,10 @@ public class AlbumTagEditorActivity extends AbsTagEditorActivity implements Text
Toast.makeText(AlbumTagEditorActivity.this,
R.string.failed_download_albumart, Toast.LENGTH_SHORT).show();
}
return false;
}
});
})
.into(500, 500);
}
@Override
@ -183,24 +191,29 @@ public class AlbumTagEditorActivity extends AbsTagEditorActivity implements Text
@Override
protected void loadImageFromFile(final Uri selectedFileUri) {
Ion.with(this)
.load(selectedFileUri.toString())
.withBitmap()
.resize(500, 500)
.centerCrop()
Glide.with(this)
.load(selectedFileUri)
.asBitmap()
.setCallback(new FutureCallback<Bitmap>() {
.centerCrop()
.listener(new RequestListener<Uri, Bitmap>() {
@Override
public void onCompleted(Exception e, Bitmap result) {
if (result != null) {
albumArtBitmap = result;
public boolean onException(Exception e, Uri model, Target<Bitmap> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Bitmap resource, Uri model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
if (resource != null) {
albumArtBitmap = resource;
setImageBitmap(albumArtBitmap);
deleteAlbumArt = false;
dataChanged();
setResult(RESULT_OK);
}
return false;
}
});
})
.into(500, 500);
}
@Override

View file

@ -13,13 +13,14 @@ import android.util.Log;
import android.widget.Toast;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Song;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
@ -36,14 +37,8 @@ public class MusicUtil {
return ContentUris.withAppendedId(sArtworkUri, album_id);
}
public static boolean hasAlbumArt(final Context context, int album_id) {
try {
context.getContentResolver().openFileDescriptor(getAlbumArtUri(album_id), "r");
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
}
return true;
public static String getArtistInfoString(Context context, Artist artist) {
return artist.songCount + " " + context.getResources().getString(R.string.songs) + " | " + artist.albumCount + " " + context.getResources().getString(R.string.albums);
}
public static String getReadableDurationString(long songDurationMillis) {