Remove unknown genre, add number of songs

This commit is contained in:
Eugene Cheung 2017-12-14 23:11:47 -05:00
commit 918090ee63
No known key found for this signature in database
GPG key ID: E1FD745328866B0A
6 changed files with 52 additions and 74 deletions

View file

@ -59,6 +59,9 @@ public class GenreAdapter extends RecyclerView.Adapter<GenreAdapter.ViewHolder>
if (holder.title != null) { if (holder.title != null) {
holder.title.setText(genre.name); holder.title.setText(genre.name);
} }
if (holder.text != null) {
holder.text.setText(MusicUtil.getGenreInfoString(activity, genre));
}
} }
@Override @Override

View file

@ -2,13 +2,10 @@ package com.kabouzeid.gramophone.loader;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.MediaStore.Audio.Genres; import android.provider.MediaStore.Audio.Genres;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Genre; import com.kabouzeid.gramophone.model.Genre;
import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.PreferenceUtil; import com.kabouzeid.gramophone.util.PreferenceUtil;
@ -23,26 +20,16 @@ public class GenreLoader {
Genres._ID, Genres._ID,
Genres.NAME Genres.NAME
}; };
// Genres that actually have songs
final String selection = Genres._ID + " IN" +
" (SELECT " + Genres.Members.GENRE_ID + " FROM audio_genres_map WHERE " + Genres.Members.AUDIO_ID + " IN" +
" (SELECT " + Genres._ID + " FROM audio_meta WHERE " + SongLoader.BASE_SELECTION + "))";
final Cursor cursor = context.getContentResolver().query( final Cursor cursor = context.getContentResolver().query(
Genres.EXTERNAL_CONTENT_URI, Genres.EXTERNAL_CONTENT_URI,
projection, selection, null, PreferenceUtil.getInstance(context).getGenreSortOrder()); projection, null, null, PreferenceUtil.getInstance(context).getGenreSortOrder());
return getGenresFromCursor(context, cursor); return getGenresFromCursor(context, cursor);
} }
@NonNull @NonNull
public static ArrayList<Song> getSongs(@NonNull final Context context, final int genreId) { public static ArrayList<Song> getSongs(@NonNull final Context context, final int genreId) {
// The genres table only stores songs that have a genre specified,
// so we need to get songs without a genre a different way.
if (genreId == -1) {
return getSongsWithNoGenre(context);
}
final Cursor cursor = context.getContentResolver().query( final Cursor cursor = context.getContentResolver().query(
Genres.Members.getContentUri("external", genreId), Genres.Members.getContentUri("external", genreId),
SongLoader.BASE_PROJECTION, SongLoader.BASE_SELECTION, null, null); SongLoader.BASE_PROJECTION, SongLoader.BASE_SELECTION, null, null);
@ -53,15 +40,10 @@ public class GenreLoader {
@NonNull @NonNull
private static ArrayList<Genre> getGenresFromCursor(@NonNull final Context context, @Nullable final Cursor cursor) { private static ArrayList<Genre> getGenresFromCursor(@NonNull final Context context, @Nullable final Cursor cursor) {
final ArrayList<Genre> genres = new ArrayList<>(); final ArrayList<Genre> genres = new ArrayList<>();
if (hasSongsWithNoGenre(context)) {
genres.add(new Genre(context.getResources().getString(R.string.unknown_genre)));
}
if (cursor != null) { if (cursor != null) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do {
genres.add(getGenreFromCursor(cursor)); genres.add(getGenreFromCursor(context, cursor));
} while (cursor.moveToNext()); } while (cursor.moveToNext());
} }
cursor.close(); cursor.close();
@ -70,41 +52,10 @@ public class GenreLoader {
} }
@NonNull @NonNull
private static Genre getGenreFromCursor(@NonNull final Cursor cursor) { private static Genre getGenreFromCursor(@NonNull final Context context, @NonNull final Cursor cursor) {
final int id = cursor.getInt(0); final int id = cursor.getInt(0);
final String name = cursor.getString(1); final String name = cursor.getString(1);
return new Genre(id, name); final int songs = getSongs(context, id).size();
} return new Genre(id, name, songs);
@NonNull
private static ArrayList<Song> getSongsWithNoGenre(@NonNull final Context context) {
String selection = BaseColumns._ID + " NOT IN " +
"(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)";
return SongLoader.getSongs(SongLoader.makeSongCursor(context, selection, null));
}
private static boolean hasSongsWithNoGenre(@NonNull final Context context) {
final Cursor allSongsCursor = SongLoader.makeSongCursor(context, null, null);
final Cursor allSongsWithGenreCursor = makeAllSongsWithGenreCursor(context);
if (allSongsCursor == null || allSongsWithGenreCursor == null) {
return false;
}
final boolean hasSongsWithNoGenre = allSongsCursor.getCount() > allSongsWithGenreCursor.getCount();
allSongsCursor.close();
allSongsWithGenreCursor.close();
return hasSongsWithNoGenre;
}
@Nullable
private static Cursor makeAllSongsWithGenreCursor(@NonNull final Context context) {
try {
return context.getContentResolver().query(
Uri.parse("content://media/external/audio/genres/all/members"),
new String[]{Genres.Members.AUDIO_ID}, null, null, null);
} catch (SecurityException e) {
return null;
}
} }
} }

View file

@ -6,16 +6,12 @@ import android.os.Parcelable;
public class Genre implements Parcelable { public class Genre implements Parcelable {
public final int id; public final int id;
public final String name; public final String name;
public final int songs;
public Genre(final int id, final String name) { public Genre(final int id, final String name, final int songs) {
this.id = id; this.id = id;
this.name = name; this.name = name;
} this.songs = songs;
// For unknown genre
public Genre(final String name) {
this.id = -1;
this.name = name;
} }
@Override @Override
@ -26,13 +22,15 @@ public class Genre implements Parcelable {
Genre genre = (Genre) o; Genre genre = (Genre) o;
if (id != genre.id) return false; if (id != genre.id) return false;
return name != null ? name.equals(genre.name) : genre.name == null; if (!name.equals(genre.name)) return false;
return songs == genre.songs;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = id; int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0); result = 31 * result + name.hashCode();
result = 31 * result + songs;
return result; return result;
} }
@ -41,6 +39,7 @@ public class Genre implements Parcelable {
return "Genre{" + return "Genre{" +
"id=" + id + "id=" + id +
", name='" + name + '\'' + ", name='" + name + '\'' +
", songs=" + songs +
'}'; '}';
} }
@ -53,11 +52,13 @@ public class Genre implements Parcelable {
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.id); dest.writeInt(this.id);
dest.writeString(this.name); dest.writeString(this.name);
dest.writeInt(this.songs);
} }
protected Genre(Parcel in) { protected Genre(Parcel in) {
this.id = in.readInt(); this.id = in.readInt();
this.name = in.readString(); this.name = in.readString();
this.songs = in.readInt();
} }
public static final Creator<Genre> CREATOR = new Creator<Genre>() { public static final Creator<Genre> CREATOR = new Creator<Genre>() {

View file

@ -23,6 +23,7 @@ import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.loader.PlaylistLoader; import com.kabouzeid.gramophone.loader.PlaylistLoader;
import com.kabouzeid.gramophone.loader.SongLoader; import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.Artist; import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.Genre;
import com.kabouzeid.gramophone.model.Playlist; import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics; import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics;
@ -114,6 +115,13 @@ public class MusicUtil {
return albumCount + " " + albumString + "" + songCount + " " + songString; return albumCount + " " + albumString + "" + songCount + " " + songString;
} }
@NonNull
public static String getGenreInfoString(@NonNull final Context context, @NonNull final Genre genre) {
int songCount = genre.songs;
String songString = songCount == 1 ? context.getResources().getString(R.string.song) : context.getResources().getString(R.string.songs);
return songCount + " " + songString;
}
@NonNull @NonNull
public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List<Song> songs) { public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List<Song> songs) {
final int songCount = songs.size(); final int songCount = songs.size();

View file

@ -6,18 +6,34 @@
android:foreground="?attr/rectSelector" android:foreground="?attr/rectSelector"
tools:ignore="UnusedAttribute"> tools:ignore="UnusedAttribute">
<TextView <LinearLayout
android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginEnd="16dp" android:paddingEnd="16dp"
android:layout_marginLeft="16dp" android:paddingLeft="16dp"
android:layout_marginRight="16dp" android:paddingRight="16dp"
android:layout_marginStart="16dp" android:paddingStart="16dp"
android:fontFamily="sans-serif" android:orientation="vertical">
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" /> <TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="?android:textColorSecondary" />
</LinearLayout>
<View <View
android:id="@+id/separator" android:id="@+id/separator"
@ -26,4 +42,4 @@
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:background="?attr/dividerColor" /> android:background="?attr/dividerColor" />
</RelativeLayout> </RelativeLayout>

View file

@ -42,7 +42,6 @@
<string name="album">Album</string> <string name="album">Album</string>
<string name="artist">Artist</string> <string name="artist">Artist</string>
<string name="genre">Genre</string> <string name="genre">Genre</string>
<string name="unknown_genre">Unknown genre</string>
<string name="album_artist">Album artist</string> <string name="album_artist">Album artist</string>
<string name="year">Year</string> <string name="year">Year</string>
<string name="track_hint">"Track (2 for track 2 or 3004 for CD3 track 4)"</string> <string name="track_hint">"Track (2 for track 2 or 3004 for CD3 track 4)"</string>