Merge branch 'feat/genres' of git://github.com/arkon/Phonograph into arkon-feat/genres
This commit is contained in:
commit
441b64fce4
15 changed files with 694 additions and 14 deletions
|
|
@ -94,6 +94,7 @@
|
|||
</activity>
|
||||
<activity android:name=".ui.activities.AlbumDetailActivity" />
|
||||
<activity android:name=".ui.activities.ArtistDetailActivity" />
|
||||
<activity android:name=".ui.activities.GenreDetailActivity" />
|
||||
<activity android:name=".ui.activities.PlaylistDetailActivity" />
|
||||
<activity
|
||||
android:name=".ui.activities.tageditor.SongTagEditorActivity"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
package com.kabouzeid.gramophone.adapter;
|
||||
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.kabouzeid.gramophone.adapter.base.MediaEntryViewHolder;
|
||||
import com.kabouzeid.gramophone.model.Genre;
|
||||
import com.kabouzeid.gramophone.util.MusicUtil;
|
||||
import com.kabouzeid.gramophone.util.NavigationUtil;
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class GenreAdapter extends RecyclerView.Adapter<GenreAdapter.ViewHolder> implements FastScrollRecyclerView.SectionedAdapter {
|
||||
|
||||
public static final String TAG = GenreAdapter.class.getSimpleName();
|
||||
|
||||
@NonNull
|
||||
private final AppCompatActivity activity;
|
||||
private ArrayList<Genre> dataSet;
|
||||
private int itemLayoutRes;
|
||||
|
||||
public GenreAdapter(@NonNull AppCompatActivity activity, ArrayList<Genre> dataSet, @LayoutRes int itemLayoutRes) {
|
||||
this.activity = activity;
|
||||
this.dataSet = dataSet;
|
||||
this.itemLayoutRes = itemLayoutRes;
|
||||
}
|
||||
|
||||
public ArrayList<Genre> getDataSet() {
|
||||
return dataSet;
|
||||
}
|
||||
|
||||
public void swapDataSet(ArrayList<Genre> dataSet) {
|
||||
this.dataSet = dataSet;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return dataSet.get(position).hashCode();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
final Genre genre = dataSet.get(position);
|
||||
|
||||
if (holder.title != null) {
|
||||
holder.title.setText(genre.name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return dataSet.size();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getSectionName(int position) {
|
||||
final Genre genre = dataSet.get(position);
|
||||
return genre.id == -1 ? "" : MusicUtil.getSectionName(dataSet.get(position).name);
|
||||
}
|
||||
|
||||
public class ViewHolder extends MediaEntryViewHolder {
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Genre genre = dataSet.get(getAdapterPosition());
|
||||
NavigationUtil.goToGenre(activity, genre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import android.view.ViewGroup;
|
|||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.ui.fragments.mainactivity.library.pager.AlbumsFragment;
|
||||
import com.kabouzeid.gramophone.ui.fragments.mainactivity.library.pager.ArtistsFragment;
|
||||
import com.kabouzeid.gramophone.ui.fragments.mainactivity.library.pager.GenresFragment;
|
||||
import com.kabouzeid.gramophone.ui.fragments.mainactivity.library.pager.PlaylistsFragment;
|
||||
import com.kabouzeid.gramophone.ui.fragments.mainactivity.library.pager.SongsFragment;
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ public class MusicLibraryPagerAdapter extends FragmentPagerAdapter {
|
|||
context.getResources().getString(R.string.songs),
|
||||
context.getResources().getString(R.string.albums),
|
||||
context.getResources().getString(R.string.artists),
|
||||
context.getResources().getString(R.string.genres),
|
||||
context.getResources().getString(R.string.playlists)
|
||||
};
|
||||
final MusicFragments[] fragments = MusicFragments.values();
|
||||
|
|
@ -110,6 +112,7 @@ public class MusicLibraryPagerAdapter extends FragmentPagerAdapter {
|
|||
SONG(SongsFragment.class),
|
||||
ALBUM(AlbumsFragment.class),
|
||||
ARTIST(ArtistsFragment.class),
|
||||
GENRES(GenresFragment.class),
|
||||
PLAYLIST(PlaylistsFragment.class);
|
||||
|
||||
private final Class<? extends Fragment> mFragmentClass;
|
||||
|
|
@ -121,12 +124,10 @@ public class MusicLibraryPagerAdapter extends FragmentPagerAdapter {
|
|||
public Class<? extends Fragment> getFragmentClass() {
|
||||
return mFragmentClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final static class Holder {
|
||||
String mClassName;
|
||||
|
||||
Bundle mParams;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,4 +153,15 @@ public final class SortOrder {
|
|||
+ " ASC";
|
||||
}
|
||||
|
||||
/**
|
||||
* Genre sort order entries.
|
||||
*/
|
||||
public interface GenreSortOrder {
|
||||
/* Genre sort order A-Z */
|
||||
String GENRE_A_Z = MediaStore.Audio.Genres.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Genre sort order Z-A */
|
||||
String ALBUM_Z_A = GENRE_A_Z + " DESC";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@ public interface LoaderIds {
|
|||
int ALBUM_DETAIL_ACTIVITY = 1;
|
||||
int ARTIST_DETAIL_ACTIVITY = 2;
|
||||
int PLAYLIST_DETAIL_ACTIVITY = 3;
|
||||
int SEARCH_ACTIVITY = 4;
|
||||
int FOLDERS_FRAGMENT = 5;
|
||||
int ALBUMS_FRAGMENT = 6;
|
||||
int ARTISTS_FRAGMENT = 7;
|
||||
int PLAYLISTS_FRAGMENT = 8;
|
||||
int SONGS_FRAGMENT = 9;
|
||||
int GENRE_DETAIL_ACTIVITY = 4;
|
||||
int SEARCH_ACTIVITY = 5;
|
||||
int FOLDERS_FRAGMENT = 6;
|
||||
int ALBUMS_FRAGMENT = 7;
|
||||
int ARTISTS_FRAGMENT = 8;
|
||||
int PLAYLISTS_FRAGMENT = 9;
|
||||
int GENRES_FRAGMENT = 10;
|
||||
int SONGS_FRAGMENT = 11;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
package com.kabouzeid.gramophone.loader;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import android.provider.MediaStore.Audio.Genres;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.model.Genre;
|
||||
import com.kabouzeid.gramophone.model.Song;
|
||||
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class GenreLoader {
|
||||
|
||||
@NonNull
|
||||
public static ArrayList<Genre> getAllGenres(@NonNull final Context context) {
|
||||
final String[] projection = new String[]{
|
||||
Genres._ID,
|
||||
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(
|
||||
Genres.EXTERNAL_CONTENT_URI,
|
||||
projection, selection, null, PreferenceUtil.getInstance(context).getGenreSortOrder());
|
||||
|
||||
return getGenresFromCursor(context, cursor);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
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(
|
||||
Genres.Members.getContentUri("external", genreId),
|
||||
SongLoader.BASE_PROJECTION, SongLoader.BASE_SELECTION, null, null);
|
||||
|
||||
return SongLoader.getSongs(cursor);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static ArrayList<Genre> getGenresFromCursor(@NonNull final Context context, @Nullable final Cursor cursor) {
|
||||
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.moveToFirst()) {
|
||||
do {
|
||||
genres.add(getGenreFromCursor(cursor));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
return genres;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Genre getGenreFromCursor(@NonNull final Cursor cursor) {
|
||||
final int id = cursor.getInt(0);
|
||||
final String name = cursor.getString(1);
|
||||
return new Genre(id, name);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
app/src/main/java/com/kabouzeid/gramophone/model/Genre.java
Normal file
72
app/src/main/java/com/kabouzeid/gramophone/model/Genre.java
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package com.kabouzeid.gramophone.model;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public class Genre implements Parcelable {
|
||||
public final int id;
|
||||
public final String name;
|
||||
|
||||
public Genre(final int id, final String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
// For unknown genre
|
||||
public Genre(final String name) {
|
||||
this.id = -1;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Genre genre = (Genre) o;
|
||||
|
||||
if (id != genre.id) return false;
|
||||
return name != null ? name.equals(genre.name) : genre.name == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = id;
|
||||
result = 31 * result + (name != null ? name.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Genre{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(this.id);
|
||||
dest.writeString(this.name);
|
||||
}
|
||||
|
||||
protected Genre(Parcel in) {
|
||||
this.id = in.readInt();
|
||||
this.name = in.readString();
|
||||
}
|
||||
|
||||
public static final Creator<Genre> CREATOR = new Creator<Genre>() {
|
||||
public Genre createFromParcel(Parcel source) {
|
||||
return new Genre(source);
|
||||
}
|
||||
|
||||
public Genre[] newArray(int size) {
|
||||
return new Genre[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
package com.kabouzeid.gramophone.ui.activities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.adapter.song.SongAdapter;
|
||||
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
|
||||
import com.kabouzeid.gramophone.interfaces.CabHolder;
|
||||
import com.kabouzeid.gramophone.interfaces.LoaderIds;
|
||||
import com.kabouzeid.gramophone.loader.GenreLoader;
|
||||
import com.kabouzeid.gramophone.misc.WrappedAsyncTaskLoader;
|
||||
import com.kabouzeid.gramophone.model.Genre;
|
||||
import com.kabouzeid.gramophone.model.Song;
|
||||
import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity;
|
||||
import com.kabouzeid.gramophone.util.PhonographColorUtil;
|
||||
import com.kabouzeid.gramophone.util.ViewUtil;
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class GenreDetailActivity extends AbsSlidingMusicPanelActivity implements CabHolder, LoaderManager.LoaderCallbacks<ArrayList<Song>> {
|
||||
|
||||
public static final String TAG = GenreDetailActivity.class.getSimpleName();
|
||||
private static final int LOADER_ID = LoaderIds.GENRE_DETAIL_ACTIVITY;
|
||||
|
||||
public static final String EXTRA_GENRE = "extra_genre";
|
||||
|
||||
@BindView(R.id.recycler_view)
|
||||
RecyclerView recyclerView;
|
||||
@BindView(R.id.toolbar)
|
||||
Toolbar toolbar;
|
||||
@BindView(android.R.id.empty)
|
||||
TextView empty;
|
||||
|
||||
private Genre genre;
|
||||
|
||||
private MaterialCab cab;
|
||||
private SongAdapter adapter;
|
||||
|
||||
private RecyclerView.Adapter wrappedAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setDrawUnderStatusbar(true);
|
||||
ButterKnife.bind(this);
|
||||
|
||||
setStatusbarColorAuto();
|
||||
setNavigationbarColorAuto();
|
||||
setTaskDescriptionColorAuto();
|
||||
|
||||
genre = getIntent().getExtras().getParcelable(EXTRA_GENRE);
|
||||
|
||||
setUpRecyclerView();
|
||||
|
||||
setUpToolBar();
|
||||
|
||||
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createContentView() {
|
||||
return wrapSlidingMusicPanel(R.layout.activity_genre_detail);
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
ViewUtil.setUpFastScrollRecyclerViewColor(this, ((FastScrollRecyclerView) recyclerView), ThemeStore.accentColor(this));
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
|
||||
adapter = new SongAdapter(this, new ArrayList<Song>(), R.layout.item_list, false, this);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
checkIsEmpty();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setUpToolBar() {
|
||||
toolbar.setBackgroundColor(ThemeStore.primaryColor(this));
|
||||
setSupportActionBar(toolbar);
|
||||
//noinspection ConstantConditions
|
||||
getSupportActionBar().setTitle(genre.name);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_genre_detail, menu);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
switch (id) {
|
||||
case R.id.action_shuffle_genre:
|
||||
MusicPlayerRemote.openAndShuffleQueue(adapter.getDataSet(), true);
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
cab = new MaterialCab(this, R.id.cab_stub)
|
||||
.setMenu(menu)
|
||||
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
|
||||
.setBackgroundColor(PhonographColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(this)))
|
||||
.start(callback);
|
||||
return cab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
else {
|
||||
recyclerView.stopScroll();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaStoreChanged() {
|
||||
super.onMediaStoreChanged();
|
||||
getSupportLoaderManager().restartLoader(LOADER_ID, null, this);
|
||||
}
|
||||
|
||||
private void checkIsEmpty() {
|
||||
empty.setVisibility(
|
||||
adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (recyclerView != null) {
|
||||
recyclerView.setAdapter(null);
|
||||
recyclerView = null;
|
||||
}
|
||||
|
||||
if (wrappedAdapter != null) {
|
||||
WrapperAdapterUtils.releaseAll(wrappedAdapter);
|
||||
wrappedAdapter = null;
|
||||
}
|
||||
adapter = null;
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<ArrayList<Song>> onCreateLoader(int id, Bundle args) {
|
||||
return new GenreDetailActivity.AsyncGenreSongLoader(this, genre);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<ArrayList<Song>> loader, ArrayList<Song> data) {
|
||||
if (adapter != null)
|
||||
adapter.swapDataSet(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<ArrayList<Song>> loader) {
|
||||
if (adapter != null)
|
||||
adapter.swapDataSet(new ArrayList<Song>());
|
||||
}
|
||||
|
||||
private static class AsyncGenreSongLoader extends WrappedAsyncTaskLoader<ArrayList<Song>> {
|
||||
private final Genre genre;
|
||||
|
||||
public AsyncGenreSongLoader(Context context, Genre genre) {
|
||||
super(context);
|
||||
this.genre = genre;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<Song> loadInBackground() {
|
||||
return GenreLoader.getSongs(getContext(), genre.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.kabouzeid.gramophone.ui.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.adapter.GenreAdapter;
|
||||
import com.kabouzeid.gramophone.interfaces.LoaderIds;
|
||||
import com.kabouzeid.gramophone.loader.GenreLoader;
|
||||
import com.kabouzeid.gramophone.misc.WrappedAsyncTaskLoader;
|
||||
import com.kabouzeid.gramophone.model.Genre;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class GenresFragment extends AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearLayoutManager> implements LoaderManager.LoaderCallbacks<ArrayList<Genre>> {
|
||||
|
||||
public static final String TAG = GenresFragment.class.getSimpleName();
|
||||
|
||||
private static final int LOADER_ID = LoaderIds.GENRES_FRAGMENT;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
getLoaderManager().initLoader(LOADER_ID, null, this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected LinearLayoutManager createLayoutManager() {
|
||||
return new LinearLayoutManager(getActivity());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected GenreAdapter createAdapter() {
|
||||
ArrayList<Genre> dataSet = getAdapter() == null ? new ArrayList<Genre>() : getAdapter().getDataSet();
|
||||
return new GenreAdapter(getLibraryFragment().getMainActivity(), dataSet, R.layout.item_list_simple);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getEmptyMessage() {
|
||||
return R.string.no_genres;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaStoreChanged() {
|
||||
getLoaderManager().restartLoader(LOADER_ID, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<ArrayList<Genre>> onCreateLoader(int id, Bundle args) {
|
||||
return new GenresFragment.AsyncGenreLoader(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<ArrayList<Genre>> loader, ArrayList<Genre> data) {
|
||||
getAdapter().swapDataSet(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<ArrayList<Genre>> loader) {
|
||||
getAdapter().swapDataSet(new ArrayList<Genre>());
|
||||
}
|
||||
|
||||
private static class AsyncGenreLoader extends WrappedAsyncTaskLoader<ArrayList<Genre>> {
|
||||
public AsyncGenreLoader(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<Genre> loadInBackground() {
|
||||
return GenreLoader.getAllGenres(getContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,9 +12,11 @@ import android.widget.Toast;
|
|||
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
|
||||
import com.kabouzeid.gramophone.model.Genre;
|
||||
import com.kabouzeid.gramophone.model.Playlist;
|
||||
import com.kabouzeid.gramophone.ui.activities.AlbumDetailActivity;
|
||||
import com.kabouzeid.gramophone.ui.activities.ArtistDetailActivity;
|
||||
import com.kabouzeid.gramophone.ui.activities.GenreDetailActivity;
|
||||
import com.kabouzeid.gramophone.ui.activities.PlaylistDetailActivity;
|
||||
|
||||
/**
|
||||
|
|
@ -38,6 +40,13 @@ public class NavigationUtil {
|
|||
activity.startActivity(intent, ActivityOptionsCompat.makeSceneTransitionAnimation(activity, sharedElements).toBundle());
|
||||
}
|
||||
|
||||
public static void goToGenre(@NonNull final Activity activity, final Genre genre, @Nullable Pair... sharedElements) {
|
||||
final Intent intent = new Intent(activity, GenreDetailActivity.class);
|
||||
intent.putExtra(GenreDetailActivity.EXTRA_GENRE, genre);
|
||||
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void goToPlaylist(@NonNull final Activity activity, final Playlist playlist, @Nullable Pair... sharedElements) {
|
||||
final Intent intent = new Intent(activity, PlaylistDetailActivity.class);
|
||||
intent.putExtra(PlaylistDetailActivity.EXTRA_PLAYLIST, playlist);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public final class PreferenceUtil {
|
|||
public static final String ALBUM_SORT_ORDER = "album_sort_order";
|
||||
public static final String ALBUM_SONG_SORT_ORDER = "album_song_sort_order";
|
||||
public static final String SONG_SORT_ORDER = "song_sort_order";
|
||||
public static final String GENRE_SORT_ORDER = "genre_sort_order";
|
||||
|
||||
public static final String ALBUM_GRID_SIZE = "album_grid_size";
|
||||
public static final String ALBUM_GRID_SIZE_LAND = "album_grid_size_land";
|
||||
|
|
@ -207,13 +208,11 @@ public final class PreferenceUtil {
|
|||
}
|
||||
|
||||
public final String getArtistSongSortOrder() {
|
||||
return mPreferences.getString(ARTIST_SONG_SORT_ORDER,
|
||||
SortOrder.ArtistSongSortOrder.SONG_A_Z);
|
||||
return mPreferences.getString(ARTIST_SONG_SORT_ORDER, SortOrder.ArtistSongSortOrder.SONG_A_Z);
|
||||
}
|
||||
|
||||
public final String getArtistAlbumSortOrder() {
|
||||
return mPreferences.getString(ARTIST_ALBUM_SORT_ORDER,
|
||||
SortOrder.ArtistAlbumSortOrder.ALBUM_YEAR);
|
||||
return mPreferences.getString(ARTIST_ALBUM_SORT_ORDER, SortOrder.ArtistAlbumSortOrder.ALBUM_YEAR);
|
||||
}
|
||||
|
||||
public final String getAlbumSortOrder() {
|
||||
|
|
@ -221,14 +220,17 @@ public final class PreferenceUtil {
|
|||
}
|
||||
|
||||
public final String getAlbumSongSortOrder() {
|
||||
return mPreferences.getString(ALBUM_SONG_SORT_ORDER,
|
||||
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST);
|
||||
return mPreferences.getString(ALBUM_SONG_SORT_ORDER, SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST);
|
||||
}
|
||||
|
||||
public final String getSongSortOrder() {
|
||||
return mPreferences.getString(SONG_SORT_ORDER, SortOrder.SongSortOrder.SONG_A_Z);
|
||||
}
|
||||
|
||||
public final String getGenreSortOrder() {
|
||||
return mPreferences.getString(GENRE_SORT_ORDER, SortOrder.GenreSortOrder.GENRE_A_Z);
|
||||
}
|
||||
|
||||
public long getLastAddedCutoff() {
|
||||
final CalendarUtil calendarUtil = new CalendarUtil();
|
||||
long interval;
|
||||
|
|
|
|||
55
app/src/main/res/layout/activity_genre_detail.xml
Normal file
55
app/src/main/res/layout/activity_genre_detail.xml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:transitionGroup="true"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/status_bar" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?colorPrimary"
|
||||
android:elevation="@dimen/toolbar_elevation"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/Toolbar"
|
||||
android:background="@android:color/transparent" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/cab_stub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbars="none" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/playlist_empty_text"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/empty_text_size"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
29
app/src/main/res/layout/item_list_simple.xml
Normal file
29
app/src/main/res/layout/item_list_simple.xml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:foreground="?attr/rectSelector"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:fontFamily="sans-serif"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
<View
|
||||
android:id="@+id/separator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="?attr/dividerColor" />
|
||||
|
||||
</RelativeLayout>
|
||||
12
app/src/main/res/menu/menu_genre_detail.xml
Normal file
12
app/src/main/res/menu/menu_genre_detail.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="com.kabouzeid.gramophone.ui.activities.GenreDetailActivity">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_shuffle_genre"
|
||||
android:icon="@drawable/ic_shuffle_white_24dp"
|
||||
android:title="@string/action_shuffle_all"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
</menu>
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
<string name="action_set_as_start_directory">Set as start directory</string>
|
||||
<string name="albums">Albums</string>
|
||||
<string name="artists">Artists</string>
|
||||
<string name="genres">Genres</string>
|
||||
<string name="songs">Songs</string>
|
||||
<string name="playlists">Playlists</string>
|
||||
<string name="unplayable_file">Couldn\u2019t play this song.</string>
|
||||
|
|
@ -41,6 +42,7 @@
|
|||
<string name="album">Album</string>
|
||||
<string name="artist">Artist</string>
|
||||
<string name="genre">Genre</string>
|
||||
<string name="unknown_genre">Unknown genre</string>
|
||||
<string name="album_artist">Album artist</string>
|
||||
<string name="year">Year</string>
|
||||
<string name="track_hint">"Track (2 for track 2 or 3004 for CD3 track 4)"</string>
|
||||
|
|
@ -151,6 +153,7 @@
|
|||
<string name="no_albums">No albums</string>
|
||||
<string name="no_songs">No songs</string>
|
||||
<string name="no_artists">No artists</string>
|
||||
<string name="no_genres">No genres</string>
|
||||
<string name="empty">Empty</string>
|
||||
<string name="playlist_name_empty">Playlist name</string>
|
||||
<string name="song">Song</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue