Library annotations (#638)

Populate album name / artist name / song counts across different view as "subtitle" that enriches the main info displayed in the title.
This includes the notification, different list-based views, the main menu, the now-playing view, search result...

For example, the included images show the added annotations highlighted with white underline
![screenshot_20190108-035119](https://user-images.githubusercontent.com/13333482/50807749-ce600000-12fb-11e9-86c6-9efb41389194.jpg)
![screenshot_20190108-035137](https://user-images.githubusercontent.com/13333482/50807750-ce600000-12fb-11e9-90e2-650aae0b159a.jpg)
![screenshot_20190108-035228](https://user-images.githubusercontent.com/13333482/50807751-ce600000-12fb-11e9-8f74-b04dbae0c6d2.jpg)
![screenshot_20190108-035244](https://user-images.githubusercontent.com/13333482/50807752-cef89680-12fb-11e9-892c-80fd55805c11.jpg)
![screenshot_20190108-035414](https://user-images.githubusercontent.com/13333482/50807753-cef89680-12fb-11e9-80a1-ee784c855876.jpg)
This commit is contained in:
soncaokim 2019-01-22 04:48:25 +01:00 committed by Eugene
commit b0a4ffdcb5
14 changed files with 100 additions and 47 deletions

View file

@ -72,7 +72,7 @@ public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder
case ALBUM:
final Album album = (Album) dataSet.get(position);
holder.title.setText(album.getTitle());
holder.text.setText(album.getArtistName());
holder.text.setText(MusicUtil.getAlbumInfoString(activity, album));
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity).build()
.into(holder.image);
@ -87,7 +87,7 @@ public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder
case SONG:
final Song song = (Song) dataSet.get(position);
holder.title.setText(song.title);
holder.text.setText(song.albumName);
holder.text.setText(MusicUtil.getSongInfoString(song));
break;
default:
holder.title.setText(dataSet.get(position).toString());

View file

@ -27,6 +27,7 @@ import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.ArrayList;
@ -84,7 +85,10 @@ public class AlbumAdapter extends AbsMultiSelectAdapter<AlbumAdapter.ViewHolder,
}
protected String getAlbumText(Album album) {
return album.getArtistName();
return MusicUtil.buildInfoString(
album.getArtistName(),
MusicUtil.getSongCountString(activity, album.songs.size())
);
}
@Override

View file

@ -158,7 +158,7 @@ public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, S
}
protected String getSongText(Song song) {
return song.artistName;
return MusicUtil.getSongInfoString(song);
}
@Override

View file

@ -16,12 +16,12 @@ import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.widget.RemoteViews;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.util.MusicUtil;
public abstract class BaseAppWidget extends AppWidgetProvider {
public static final String NAME = "app_widget";
@ -137,12 +137,6 @@ public abstract class BaseAppWidget extends AppWidgetProvider {
}
protected String getSongArtistAndAlbum(final Song song) {
final StringBuilder builder = new StringBuilder();
builder.append(song.artistName);
if (!TextUtils.isEmpty(song.artistName) && !TextUtils.isEmpty(song.albumName)) {
builder.append("");
}
builder.append(song.albumName);
return builder.toString();
return MusicUtil.getSongInfoString(song);
}
}

View file

@ -5,6 +5,7 @@ import android.os.Parcel;
import android.support.annotation.NonNull;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.util.MusicUtil;
import java.util.ArrayList;
@ -13,8 +14,6 @@ import java.util.ArrayList;
*/
public abstract class AbsCustomPlaylist extends Playlist {
public static final String INFO_STRING_SEPARATOR = "";
public AbsCustomPlaylist(int id, String name) {
super(id, name);
}
@ -32,14 +31,12 @@ public abstract class AbsCustomPlaylist extends Playlist {
@NonNull
@Override
public String getInfoString(@NonNull Context context) {
String baseInfo = super.getInfoString(context);
int songCount = getSongs(context).size();
String songCountText = (songCount == 0) ?
context.getString(R.string.no_songs) :
String.valueOf(songCount) + " " + context.getString(R.string.songs);
String songCountString = MusicUtil.getSongCountString(context, songCount);
if (baseInfo.isEmpty()) {return songCountText;}
return songCountText + INFO_STRING_SEPARATOR + baseInfo;
return MusicUtil.buildInfoString(
songCountString,
super.getInfoString(context)
);
}
}

View file

@ -8,6 +8,7 @@ import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.loader.TopAndRecentlyPlayedTracksLoader;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.provider.HistoryStore;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import java.util.ArrayList;
@ -24,11 +25,12 @@ public class HistoryPlaylist extends AbsSmartPlaylist {
@NonNull
@Override
public String getInfoString(@NonNull Context context) {
String baseInfo = super.getInfoString(context);
String cutoff = PreferenceUtil.getInstance(context).getRecentlyPlayedCutoffText(context);
if (baseInfo.isEmpty()) {return cutoff;}
return cutoff + INFO_STRING_SEPARATOR + baseInfo;
return MusicUtil.buildInfoString(
cutoff,
super.getInfoString(context)
);
}
@NonNull

View file

@ -7,6 +7,7 @@ import android.support.annotation.NonNull;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.loader.LastAddedLoader;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import java.util.ArrayList;
@ -23,11 +24,12 @@ public class LastAddedPlaylist extends AbsSmartPlaylist {
@NonNull
@Override
public String getInfoString(@NonNull Context context) {
String baseInfo = super.getInfoString(context);
String cutoff = PreferenceUtil.getInstance(context).getLastAddedCutoffText(context);
if (baseInfo.isEmpty()) {return cutoff;}
return cutoff + INFO_STRING_SEPARATOR + baseInfo;
return MusicUtil.buildInfoString(
cutoff,
super.getInfoString(context)
);
}
@NonNull

View file

@ -7,6 +7,7 @@ import android.support.annotation.NonNull;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.loader.TopAndRecentlyPlayedTracksLoader;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import java.util.ArrayList;
@ -23,11 +24,12 @@ public class NotRecentlyPlayedPlaylist extends AbsSmartPlaylist {
@NonNull
@Override
public String getInfoString(@NonNull Context context) {
String baseInfo = super.getInfoString(context);
String cutoff = PreferenceUtil.getInstance(context).getRecentlyPlayedCutoffText(context);
if (baseInfo.isEmpty()) {return cutoff;}
return cutoff + INFO_STRING_SEPARATOR + baseInfo;
return MusicUtil.buildInfoString(
cutoff,
super.getInfoString(context)
);
}
@NonNull

View file

@ -11,7 +11,6 @@ import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.support.v4.media.app.NotificationCompat.MediaStyle;
import android.support.v7.graphics.Palette;
import android.text.TextUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
@ -22,6 +21,7 @@ import com.kabouzeid.gramophone.glide.palette.BitmapPaletteWrapper;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MainActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import static com.kabouzeid.gramophone.service.MusicService.ACTION_REWIND;
@ -36,11 +36,8 @@ public class PlayingNotificationImpl24 extends PlayingNotification {
final Song song = service.getCurrentSong();
final String albumName = song.albumName;
final String artistName = song.artistName;
final boolean isPlaying = service.isPlaying();
final String text = TextUtils.isEmpty(albumName)
? artistName : artistName + " - " + albumName;
final String text = MusicUtil.getSongInfoString(song);
final int playButtonResId = isPlaying
? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;

View file

@ -23,6 +23,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.kabouzeid.appthemehelper.ThemeStore;
import com.kabouzeid.appthemehelper.util.ATHUtil;
import com.kabouzeid.appthemehelper.util.NavigationViewUtil;
@ -42,7 +43,9 @@ import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity;
import com.kabouzeid.gramophone.ui.activities.intro.AppIntroActivity;
import com.kabouzeid.gramophone.ui.fragments.mainactivity.folders.FoldersFragment;
import com.kabouzeid.gramophone.ui.fragments.mainactivity.library.LibraryFragment;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import java.util.ArrayList;
@ -217,7 +220,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity {
});
}
((TextView) navigationDrawerHeader.findViewById(R.id.title)).setText(song.title);
((TextView) navigationDrawerHeader.findViewById(R.id.text)).setText(song.artistName);
((TextView) navigationDrawerHeader.findViewById(R.id.text)).setText(MusicUtil.getSongInfoString(song));
SongGlideRequest.Builder.from(Glide.with(this), song)
.checkIgnoreMediaStore(this).build()
.into(((ImageView) navigationDrawerHeader.findViewById(R.id.image)));

View file

@ -132,7 +132,12 @@ public abstract class AbsPlayerFragment extends AbsMusicServiceFragment implemen
}
protected String getUpNextAndQueueTime() {
return getResources().getString(R.string.up_next) + "" + MusicUtil.getReadableDurationString(MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.getPosition()));
final long duration = MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.getPosition());
return MusicUtil.buildInfoString(
getResources().getString(R.string.up_next),
MusicUtil.getReadableDurationString(duration)
);
}
public abstract void onShow();

View file

@ -568,7 +568,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
public void updateCurrentSong(Song song) {
currentSong = song;
currentSongViewHolder.title.setText(song.title);
currentSongViewHolder.text.setText(song.artistName);
currentSongViewHolder.text.setText(MusicUtil.getSongInfoString(song));
}
@Override
@ -603,7 +603,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
@Override
public void updateCurrentSong(Song song) {
fragment.toolbar.setTitle(song.title);
fragment.toolbar.setSubtitle(song.artistName);
fragment.toolbar.setSubtitle(MusicUtil.getSongInfoString(song));
}
@Override

View file

@ -548,7 +548,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
public void updateCurrentSong(Song song) {
currentSong = song;
currentSongViewHolder.title.setText(song.title);
currentSongViewHolder.text.setText(song.artistName);
currentSongViewHolder.text.setText(MusicUtil.getSongInfoString(song));
}
@Override
@ -576,7 +576,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
@Override
public void updateCurrentSong(Song song) {
fragment.toolbar.setTitle(song.title);
fragment.toolbar.setSubtitle(song.artistName);
fragment.toolbar.setSubtitle(MusicUtil.getSongInfoString(song));
}
@Override

View file

@ -22,11 +22,13 @@ import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.loader.PlaylistLoader;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.Genre;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics;
import com.kabouzeid.gramophone.util.MusicUtil;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.tag.FieldKey;
@ -107,22 +109,45 @@ public class MusicUtil {
public static String getArtistInfoString(@NonNull final Context context, @NonNull final Artist artist) {
int albumCount = artist.getAlbumCount();
int songCount = artist.getSongCount();
String albumString = albumCount == 1 ? context.getResources().getString(R.string.album) : context.getResources().getString(R.string.albums);
String songString = songCount == 1 ? context.getResources().getString(R.string.song) : context.getResources().getString(R.string.songs);
return albumCount + " " + albumString + "" + songCount + " " + songString;
return MusicUtil.buildInfoString(
MusicUtil.getAlbumCountString(context, albumCount),
MusicUtil.getSongCountString(context, songCount)
);
}
@NonNull
public static String getAlbumInfoString(@NonNull final Context context, @NonNull final Album album) {
int songCount = album.getSongCount();
return MusicUtil.buildInfoString(
album.getArtistName(),
MusicUtil.getSongCountString(context, songCount)
);
}
@NonNull
public static String getSongInfoString(@NonNull final Song song) {
return MusicUtil.buildInfoString(
song.artistName,
song.albumName
);
}
@NonNull
public static String getGenreInfoString(@NonNull final Context context, @NonNull final Genre genre) {
int songCount = genre.songCount;
String songString = songCount == 1 ? context.getResources().getString(R.string.song) : context.getResources().getString(R.string.songs);
return songCount + " " + songString;
return MusicUtil.getSongCountString(context, songCount);
}
@NonNull
public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List<Song> songs) {
final long duration = getTotalDuration(context, songs);
return MusicUtil.getSongCountString(context, songs.size()) + "" + MusicUtil.getReadableDurationString(duration);
return MusicUtil.buildInfoString(
MusicUtil.getSongCountString(context, songs.size()),
MusicUtil.getReadableDurationString(duration)
);
}
@NonNull
@ -162,6 +187,28 @@ public class MusicUtil {
}
}
/**
* Build a concatenated string from the provided arguments
* The intended purpose is to show extra annotations
* to a music library item.
* Ex: for a given album --> buildInfoString(album.artist, album.songCount)
*/
public static String buildInfoString(@NonNull final String string1, @NonNull final String string2)
{
// Skip empty strings
if (string1.isEmpty()) {return string2;}
if (string2.isEmpty()) {return string1;}
final String separator = "";
final StringBuilder builder = new StringBuilder();
builder.append(string1);
builder.append(separator);
builder.append(string2);
return builder.toString();
}
//iTunes uses for example 1002 for track 2 CD1 or 3011 for track 11 CD3.
//this method converts those values to normal tracknumbers
public static int getFixedTrackNumber(int trackNumberToFix) {