From 1c1a575a24c083a0d58d8bcd78c66c203b777d38 Mon Sep 17 00:00:00 2001 From: linus_lee Date: Fri, 26 Sep 2014 17:50:34 -0700 Subject: [PATCH] Eleven: Add the context menu items to the 2nd layer Part 2/2 Fix the delete case scenarios that I could find where lists were not updating https://cyanogen.atlassian.net/browse/MUSIC-22 Change-Id: I96a97378b5cfd06239e6a470e16c081f55daa012 --- res/layout/activity_album_detail.xml | 2 +- res/layout/album_detail_song.xml | 4 +- res/layout/artist_detail_album.xml | 3 +- res/layout/artist_detail_song.xml | 4 +- .../eleven/adapters/ArtistDetailAlbumAdapter.java | 18 ++++- .../cyngn/eleven/adapters/DetailSongAdapter.java | 27 ++++++- .../eleven/adapters/IEmptyAdapterCallback.java | 8 ++ .../eleven/ui/activities/AlbumDetailActivity.java | 78 +++++++++++++++++-- .../eleven/ui/activities/ArtistDetailActivity.java | 90 +++++++++++++++++++++- .../ui/activities/PlaylistDetailActivity.java | 85 ++++++-------------- .../cyngn/eleven/ui/activities/SearchActivity.java | 27 +------ .../cyngn/eleven/ui/fragments/AlbumFragment.java | 60 ++------------- .../cyngn/eleven/ui/fragments/ArtistFragment.java | 26 +------ .../eleven/ui/fragments/PlaylistFragment.java | 26 +------ .../cyngn/eleven/ui/fragments/QueueFragment.java | 20 ----- .../cyngn/eleven/ui/fragments/RecentFragment.java | 17 +--- .../cyngn/eleven/ui/fragments/SongFragment.java | 10 --- .../ui/fragments/profile/BasicSongFragment.java | 73 +++--------------- .../ui/fragments/profile/LastAddedFragment.java | 10 --- .../ui/fragments/profile/TopTracksFragment.java | 10 --- .../cyngn/eleven/utils/AlbumPopupMenuHelper.java | 51 ++++++++++++ src/com/cyngn/eleven/utils/PopupMenuHelper.java | 50 ++++++------ .../cyngn/eleven/utils/SongPopupMenuHelper.java | 48 ++++++++++++ 23 files changed, 385 insertions(+), 362 deletions(-) create mode 100644 src/com/cyngn/eleven/adapters/IEmptyAdapterCallback.java create mode 100644 src/com/cyngn/eleven/utils/AlbumPopupMenuHelper.java create mode 100644 src/com/cyngn/eleven/utils/SongPopupMenuHelper.java diff --git a/res/layout/activity_album_detail.xml b/res/layout/activity_album_detail.xml index 876a29e..4cd98a0 100644 --- a/res/layout/activity_album_detail.xml +++ b/res/layout/activity_album_detail.xml @@ -11,7 +11,7 @@ android:layout_alignParentLeft="true" android:background="@color/page_header_background" > - - - - - - -implements LoaderCallbacks> { +implements LoaderCallbacks>, IPopupMenuCallback { private static final int TYPE_FIRST = 1; private static final int TYPE_MIDDLE = 2; private static final int TYPE_LAST = 3; @@ -34,6 +36,7 @@ implements LoaderCallbacks> { private final ImageFetcher mImageFetcher; private final LayoutInflater mInflater; private List mAlbums = Collections.emptyList(); + private IListener mListener; public ArtistDetailAlbumAdapter(final Activity activity) { mActivity = activity; @@ -67,6 +70,8 @@ implements LoaderCallbacks> { holder.year.setText(a.mYear); mImageFetcher.loadAlbumImage( a.mArtistName, a.mAlbumName, a.mAlbumId, holder.art); + holder.popupbutton.setPopupMenuClickedListener(mListener); + holder.popupbutton.setPosition(position); addAction(holder.itemView, a); } @@ -83,15 +88,26 @@ implements LoaderCallbacks> { @Override public int getItemCount() { return mAlbums.size(); } + public Album getItem(int position) { + return mAlbums.get(position); + } + + @Override + public void setPopupMenuClickedListener(IListener listener) { + mListener = listener; + } + public static class ViewHolder extends RecyclerView.ViewHolder { public ImageView art; public TextView title; public TextView year; + public PopupMenuButton popupbutton; public ViewHolder(View root) { super(root); art = (ImageView)root.findViewById(R.id.album_art); title = (TextView)root.findViewById(R.id.title); year = (TextView)root.findViewById(R.id.year); + popupbutton = (PopupMenuButton)root.findViewById(R.id.overflow); } } diff --git a/src/com/cyngn/eleven/adapters/DetailSongAdapter.java b/src/com/cyngn/eleven/adapters/DetailSongAdapter.java index ca794f5..a3b2df2 100644 --- a/src/com/cyngn/eleven/adapters/DetailSongAdapter.java +++ b/src/com/cyngn/eleven/adapters/DetailSongAdapter.java @@ -16,16 +16,20 @@ import com.cyngn.eleven.cache.ImageFetcher; import com.cyngn.eleven.model.Song; import com.cyngn.eleven.utils.ApolloUtils; import com.cyngn.eleven.utils.MusicUtils; +import com.cyngn.eleven.widgets.IPopupMenuCallback; +import com.cyngn.eleven.widgets.PopupMenuButton; import java.util.Collections; import java.util.List; public abstract class DetailSongAdapter extends BaseAdapter -implements LoaderCallbacks>, OnItemClickListener { +implements LoaderCallbacks>, OnItemClickListener, IPopupMenuCallback { protected final Activity mActivity; private final ImageFetcher mImageFetcher; private final LayoutInflater mInflater; private List mSongs = Collections.emptyList(); + private IListener mListener; + private IEmptyAdapterCallback mEmptyCallback; public DetailSongAdapter(final Activity activity) { mActivity = activity; @@ -53,6 +57,8 @@ implements LoaderCallbacks>, OnItemClickListener { Song song = getItem(pos); holder.update(song); + holder.popupMenuButton.setPopupMenuClickedListener(mListener); + holder.popupMenuButton.setPosition(pos); return convertView; } @@ -74,7 +80,13 @@ implements LoaderCallbacks>, OnItemClickListener { @Override // LoaderCallbacks public void onLoadFinished(Loader> loader, List songs) { - if (songs.isEmpty()) { return; } + if (songs.isEmpty()) { + if (mEmptyCallback != null) { + mEmptyCallback.onEmptyAdapter(); + } + + return; + } mSongs = songs; notifyDataSetChanged(); } @@ -86,15 +98,26 @@ implements LoaderCallbacks>, OnItemClickListener { mImageFetcher.flush(); } + @Override + public void setPopupMenuClickedListener(IListener listener) { + mListener = listener; + } + + public void setOnEmptyAdapterListener(IEmptyAdapterCallback callback) { + mEmptyCallback = callback; + } + protected abstract Holder newHolder(View root, ImageFetcher fetcher); protected static abstract class Holder { protected ImageFetcher fetcher; protected TextView title; + protected PopupMenuButton popupMenuButton; protected Holder(View root, ImageFetcher fetcher) { this.fetcher = fetcher; title = (TextView)root.findViewById(R.id.title); + popupMenuButton = (PopupMenuButton)root.findViewById(R.id.overflow); } protected abstract void update(Song song); diff --git a/src/com/cyngn/eleven/adapters/IEmptyAdapterCallback.java b/src/com/cyngn/eleven/adapters/IEmptyAdapterCallback.java new file mode 100644 index 0000000..11b9228 --- /dev/null +++ b/src/com/cyngn/eleven/adapters/IEmptyAdapterCallback.java @@ -0,0 +1,8 @@ +/* + * Copyright (C) 2014 Cyanogen, Inc. + */ +package com.cyngn.eleven.adapters; + +public interface IEmptyAdapterCallback { + public void onEmptyAdapter(); +} diff --git a/src/com/cyngn/eleven/ui/activities/AlbumDetailActivity.java b/src/com/cyngn/eleven/ui/activities/AlbumDetailActivity.java index 56971f3..13c9ed1 100644 --- a/src/com/cyngn/eleven/ui/activities/AlbumDetailActivity.java +++ b/src/com/cyngn/eleven/ui/activities/AlbumDetailActivity.java @@ -6,6 +6,7 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.provider.MediaStore; +import android.support.v4.app.FragmentManager; import android.support.v4.app.LoaderManager; import android.view.MenuItem; import android.view.View; @@ -14,22 +15,38 @@ import android.widget.ListView; import android.widget.TextView; import com.cyngn.eleven.Config; +import com.cyngn.eleven.MusicStateListener; import com.cyngn.eleven.R; import com.cyngn.eleven.adapters.AlbumDetailSongAdapter; import com.cyngn.eleven.adapters.DetailSongAdapter; import com.cyngn.eleven.cache.ImageFetcher; +import com.cyngn.eleven.menu.DeleteDialog; +import com.cyngn.eleven.model.Album; import com.cyngn.eleven.model.Song; +import com.cyngn.eleven.utils.AlbumPopupMenuHelper; import com.cyngn.eleven.utils.GenreFetcher; +import com.cyngn.eleven.utils.MusicUtils; +import com.cyngn.eleven.utils.PopupMenuHelper; +import com.cyngn.eleven.utils.SongPopupMenuHelper; +import com.cyngn.eleven.widgets.IPopupMenuCallback; +import com.cyngn.eleven.widgets.PopupMenuButton; import java.util.List; import java.util.Locale; -public class AlbumDetailActivity extends SlidingPanelActivity { +public class AlbumDetailActivity extends SlidingPanelActivity implements MusicStateListener { + private static final int LOADER_ID = 1; private ListView mSongs; private DetailSongAdapter mSongAdapter; private TextView mAlbumDuration; private TextView mGenre; + private PopupMenuHelper mPopupMenuHelper; + private PopupMenuButton mPopupMenuButton; + private PopupMenuHelper mHeaderPopupMenuHelper; + private long mAlbumId; + private String mArtistName; + private String mAlbumName; @Override protected void onCreate(Bundle savedInstanceState) { @@ -42,31 +59,44 @@ public class AlbumDetailActivity extends SlidingPanelActivity { View root = findViewById(R.id.activity_base_content); + setupPopupMenuHelper(); setupHeader(root, artistName, arguments); setupSongList(root); LoaderManager lm = getSupportLoaderManager(); - lm.initLoader(1, arguments, mSongAdapter); + lm.initLoader(LOADER_ID, arguments, mSongAdapter); + + // listen to music state changes + setMusicStateListenerListener(this); } private void setupHeader(View root, String artist, Bundle arguments) { - String album = arguments.getString(Config.NAME); + mAlbumId = arguments.getLong(Config.ID); + mArtistName = artist; + mAlbumName = arguments.getString(Config.NAME); String year = arguments.getString(Config.ALBUM_YEAR); - long albumId = arguments.getLong(Config.ID); int songCount = arguments.getInt(Config.SONG_COUNT); ImageView albumArt = (ImageView)root.findViewById(R.id.album_art); - albumArt.setContentDescription(album); - ImageFetcher.getInstance(this).loadAlbumImage(artist, album, albumId, albumArt); + albumArt.setContentDescription(mAlbumName); + ImageFetcher.getInstance(this).loadAlbumImage(artist, mAlbumName, mAlbumId, albumArt); TextView title = (TextView)root.findViewById(R.id.title); - title.setText(album); + title.setText(mAlbumName); setupCountAndYear(root, year, songCount); // will be updated once we have song data mAlbumDuration = (TextView)root.findViewById(R.id.duration); mGenre = (TextView)root.findViewById(R.id.genre); + + mPopupMenuButton = (PopupMenuButton)root.findViewById(R.id.overflow); + mPopupMenuButton.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { + @Override + public void onPopupMenuClicked(View v, int position) { + mHeaderPopupMenuHelper.showPopupMenu(v, position); + } + }); } private void setupCountAndYear(View root, String year, int songCount) { @@ -84,9 +114,30 @@ public class AlbumDetailActivity extends SlidingPanelActivity { } } + private void setupPopupMenuHelper() { + mPopupMenuHelper = new SongPopupMenuHelper(this, getSupportFragmentManager()) { + @Override + public Song getSong(int position) { + return mSongAdapter.getItem(position); + } + }; + + mHeaderPopupMenuHelper = new AlbumPopupMenuHelper(this, getSupportFragmentManager()) { + public Album getAlbum(int position) { + return new Album(mAlbumId, mAlbumName, mArtistName, -1, null); + } + }; + } + private void setupSongList(View root) { mSongs = (ListView)root.findViewById(R.id.songs); mSongAdapter = new AlbumDetailSongAdapter(this); + mSongAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { + @Override + public void onPopupMenuClicked(View v, int position) { + mPopupMenuHelper.showPopupMenu(v, position); + } + }); mSongs.setAdapter(mSongAdapter); mSongs.setOnItemClickListener(mSongAdapter); } @@ -123,6 +174,9 @@ public class AlbumDetailActivity extends SlidingPanelActivity { /** use the first song on the album to get a genre */ if(!songs.isEmpty()) { GenreFetcher.fetch(this, (int)songs.get(0).mSongId, mGenre); + } else { + // no songs, quit this page + finish(); } } @@ -137,4 +191,14 @@ public class AlbumDetailActivity extends SlidingPanelActivity { mAlbumDuration.setText(durationText); } + + @Override + public void restartLoader() { + getSupportLoaderManager().restartLoader(LOADER_ID, getIntent().getExtras(), mSongAdapter); + } + + @Override + public void onMetaChanged() { + + } } \ No newline at end of file diff --git a/src/com/cyngn/eleven/ui/activities/ArtistDetailActivity.java b/src/com/cyngn/eleven/ui/activities/ArtistDetailActivity.java index 6791d58..ffbf62a 100644 --- a/src/com/cyngn/eleven/ui/activities/ArtistDetailActivity.java +++ b/src/com/cyngn/eleven/ui/activities/ArtistDetailActivity.java @@ -11,12 +11,24 @@ import android.widget.ImageView; import android.widget.ListView; import com.cyngn.eleven.Config; +import com.cyngn.eleven.MusicStateListener; import com.cyngn.eleven.R; import com.cyngn.eleven.adapters.ArtistDetailAlbumAdapter; import com.cyngn.eleven.adapters.ArtistDetailSongAdapter; +import com.cyngn.eleven.adapters.IEmptyAdapterCallback; import com.cyngn.eleven.cache.ImageFetcher; - -public class ArtistDetailActivity extends DetailActivity { +import com.cyngn.eleven.menu.FragmentMenuItems; +import com.cyngn.eleven.model.Album; +import com.cyngn.eleven.model.Song; +import com.cyngn.eleven.utils.AlbumPopupMenuHelper; +import com.cyngn.eleven.utils.SongPopupMenuHelper; +import com.cyngn.eleven.widgets.IPopupMenuCallback; + +import java.util.TreeSet; + +public class ArtistDetailActivity extends DetailActivity implements MusicStateListener { + private final int ALBUM_LOADER_ID = 0; + private final int SONG_LOADER_ID = 1; private ImageView mHero; private View mHeader; @@ -26,6 +38,9 @@ public class ArtistDetailActivity extends DetailActivity { private RecyclerView mAlbums; private ArtistDetailAlbumAdapter mAlbumAdapter; + private SongPopupMenuHelper mSongPopupMenuHelper; + private AlbumPopupMenuHelper mAlbumPopupMenuHelper; + @Override protected int getLayoutToInflate() { return R.layout.activity_artist_detail; } @@ -41,13 +56,16 @@ public class ArtistDetailActivity extends DetailActivity { ViewGroup root = (ViewGroup)findViewById(R.id.activity_base_content); root.setPadding(0, 0, 0, 0); // clear default padding + setupPopupMenuHelpers(); setupSongList(root); setupAlbumList(); setupHero(artistName); LoaderManager lm = getSupportLoaderManager(); - lm.initLoader(0, arguments, mAlbumAdapter); - lm.initLoader(1, arguments, mSongAdapter); + lm.initLoader(ALBUM_LOADER_ID, arguments, mAlbumAdapter); + lm.initLoader(SONG_LOADER_ID, arguments, mSongAdapter); + + setMusicStateListenerListener(this); } private void setupHero(String artistName) { @@ -61,6 +79,12 @@ public class ArtistDetailActivity extends DetailActivity { mAlbums.setHasFixedSize(true); mAlbums.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); mAlbumAdapter = new ArtistDetailAlbumAdapter(this); + mAlbumAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { + @Override + public void onPopupMenuClicked(View v, int position) { + mAlbumPopupMenuHelper.showPopupMenu(v, position); + } + }); mAlbums.setAdapter(mAlbumAdapter); } @@ -71,12 +95,70 @@ public class ArtistDetailActivity extends DetailActivity { mSongs.addHeaderView(mHeader); mSongs.setOnScrollListener(this); mSongAdapter = new ArtistDetailSongAdapter(this); + mSongAdapter.setOnEmptyAdapterListener(new IEmptyAdapterCallback() { + @Override + public void onEmptyAdapter() { + // no results - because the user deleted the last item + finish(); + } + }); + mSongAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { + @Override + public void onPopupMenuClicked(View v, int position) { + mSongPopupMenuHelper.showPopupMenu(v, position); + } + }); mSongs.setAdapter(mSongAdapter); mSongs.setOnItemClickListener(mSongAdapter); } + private void setupPopupMenuHelpers() { + mSongPopupMenuHelper = new SongPopupMenuHelper(this, getSupportFragmentManager()) { + @Override + public Song getSong(int position) { + return mSongAdapter.getItem(position); + } + + @Override + protected void updateMenuIds(PopupMenuType type, TreeSet set) { + super.updateMenuIds(type, set); + + // since we are already on the artist page, this item doesn't make sense + set.remove(FragmentMenuItems.MORE_BY_ARTIST); + } + }; + + mAlbumPopupMenuHelper = new AlbumPopupMenuHelper(this, getSupportFragmentManager()) { + @Override + public Album getAlbum(int position) { + return mAlbumAdapter.getItem(position); + } + + @Override + protected void updateMenuIds(PopupMenuType type, TreeSet set) { + super.updateMenuIds(type, set); + + // since we are already on the artist page, this item doesn't make sense + set.remove(FragmentMenuItems.MORE_BY_ARTIST); + } + }; + } + // TODO: change this class to use the same header strategy as PlaylistDetail protected int getHeaderHeight() { return 0; } protected void setHeaderPosition(float y) { } + + @Override + public void restartLoader() { + Bundle arguments = getIntent().getExtras(); + LoaderManager lm = getSupportLoaderManager(); + lm.restartLoader(ALBUM_LOADER_ID, arguments, mAlbumAdapter); + lm.restartLoader(SONG_LOADER_ID, arguments, mSongAdapter); + } + + @Override + public void onMetaChanged() { + + } } \ No newline at end of file diff --git a/src/com/cyngn/eleven/ui/activities/PlaylistDetailActivity.java b/src/com/cyngn/eleven/ui/activities/PlaylistDetailActivity.java index 991b0d8..c041fde 100644 --- a/src/com/cyngn/eleven/ui/activities/PlaylistDetailActivity.java +++ b/src/com/cyngn/eleven/ui/activities/PlaylistDetailActivity.java @@ -3,7 +3,6 @@ package com.cyngn.eleven.ui.activities; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; -import android.os.SystemClock; import android.provider.MediaStore; import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; @@ -17,6 +16,7 @@ import android.widget.ImageView; import android.widget.TextView; import com.cyngn.eleven.Config; +import com.cyngn.eleven.MusicStateListener; import com.cyngn.eleven.R; import com.cyngn.eleven.adapters.ProfileSongAdapter; import com.cyngn.eleven.cache.ImageFetcher; @@ -25,26 +25,22 @@ import com.cyngn.eleven.dragdrop.DragSortListView.DragScrollProfile; import com.cyngn.eleven.dragdrop.DragSortListView.DropListener; import com.cyngn.eleven.dragdrop.DragSortListView.RemoveListener; import com.cyngn.eleven.loaders.PlaylistSongLoader; -import com.cyngn.eleven.menu.DeleteDialog; import com.cyngn.eleven.menu.FragmentMenuItems; import com.cyngn.eleven.model.Song; import com.cyngn.eleven.recycler.RecycleHolder; import com.cyngn.eleven.utils.MusicUtils; import com.cyngn.eleven.utils.PopupMenuHelper; +import com.cyngn.eleven.utils.SongPopupMenuHelper; import com.cyngn.eleven.widgets.IPopupMenuCallback; import com.cyngn.eleven.widgets.NoResultsContainer; import java.util.ArrayList; import java.util.List; +import java.util.TreeSet; public class PlaylistDetailActivity extends DetailActivity implements LoaderCallbacks>, OnItemClickListener, DropListener, - RemoveListener, DragScrollProfile { - - /** - * Used to keep context menu items from bleeding into other fragments - */ - private static final int GROUP_ID = 8; + RemoveListener, DragScrollProfile, MusicStateListener { /** * LoaderCallbacks identifier @@ -81,65 +77,21 @@ public class PlaylistDetailActivity extends DetailActivity implements protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mPopupMenuHelper = new PopupMenuHelper(this, getSupportFragmentManager()) { - /** - * Represents a song - */ - private Song mSong; - + mPopupMenuHelper = new SongPopupMenuHelper(this, getSupportFragmentManager()) { @Override - protected PopupMenuType onPreparePopupMenu(int position) { - // the header has been long-pressed - for now just return, but later if we want - // to long-press support for the header, do that logic here + public Song getSong(int position) { if (position == 0) { return null; } - // Create a new song - mSong = mAdapter.getItem(position - 1); - - return PopupMenuType.Song; + return mAdapter.getItem(position - 1); } @Override - protected void getAdditionalIds(PopupMenuType type, ArrayList list) { - super.getAdditionalIds(type, list); + protected void updateMenuIds(PopupMenuType type, TreeSet set) { + super.updateMenuIds(type, set); - list.add(FragmentMenuItems.REMOVE_FROM_PLAYLIST); - } - - @Override - protected long[] getIdList() { - return new long[] { mSong.mSongId }; - } - - @Override - protected int getGroupId() { - return GROUP_ID; - } - - @Override - protected long getId() { - return mSong.mSongId; - } - - @Override - protected String getArtistName() { - return mSong.mArtistName; - } - - @Override - protected void onDeleteClicked() { - DeleteDialog.newInstance(mSong.mSongName, getIdList(), null) - .show(getSupportFragmentManager(), "DeleteDialog"); - SystemClock.sleep(10); - mAdapter.notifyDataSetChanged(); - getSupportLoaderManager().restartLoader(LOADER, null, PlaylistDetailActivity.this); - } - - @Override - protected void setShouldRefresh() { - // do nothing here since we restart the loader ourselves + set.add(FragmentMenuItems.REMOVE_FROM_PLAYLIST); } @Override @@ -166,6 +118,9 @@ public class PlaylistDetailActivity extends DetailActivity implements LoaderManager lm = getSupportLoaderManager(); lm.initLoader(0, arguments, this); + + // listen to music state changes + setMusicStateListenerListener(this); } private void setupHero() { @@ -308,10 +263,10 @@ public class PlaylistDetailActivity extends DetailActivity implements // hide the header container mHeaderContainer.setVisibility(View.GONE); - // Start fresh - mAdapter.unload(); // Return the correct count mAdapter.setCount(new ArrayList()); + // Start fresh + mAdapter.unload(); } else { // show the header container mHeaderContainer.setVisibility(View.VISIBLE); @@ -343,4 +298,14 @@ public class PlaylistDetailActivity extends DetailActivity implements // Clear the data in the adapter mAdapter.unload(); } + + @Override + public void restartLoader() { + getSupportLoaderManager().restartLoader(0, getIntent().getExtras(), this); + } + + @Override + public void onMetaChanged() { + + } } \ No newline at end of file diff --git a/src/com/cyngn/eleven/ui/activities/SearchActivity.java b/src/com/cyngn/eleven/ui/activities/SearchActivity.java index 64fb620..42949b4 100644 --- a/src/com/cyngn/eleven/ui/activities/SearchActivity.java +++ b/src/com/cyngn/eleven/ui/activities/SearchActivity.java @@ -72,6 +72,7 @@ import com.cyngn.eleven.widgets.NoResultsContainer; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.TreeSet; import static android.view.View.OnTouchListener; import static com.cyngn.eleven.utils.MusicUtils.mService; @@ -91,11 +92,6 @@ public class SearchActivity extends FragmentActivity implements private static int LOADING_DELAY = 500; /** - * Used to keep context menu items from bleeding into other fragments - */ - private static final int GROUP_ID = 5; - - /** * Identifier for the search loader */ private static int SEARCH_LOADER = 0; @@ -230,11 +226,11 @@ public class SearchActivity extends FragmentActivity implements } @Override - protected void getAdditionalIds(PopupMenuType type, ArrayList list) { - super.getAdditionalIds(type, list); + protected void updateMenuIds(PopupMenuType type, TreeSet set) { + super.updateMenuIds(type, set); if (mSelectedItem.mType == ResultType.Album) { - list.add(FragmentMenuItems.MORE_BY_ARTIST); + set.add(FragmentMenuItems.MORE_BY_ARTIST); } } @@ -242,21 +238,6 @@ public class SearchActivity extends FragmentActivity implements protected String getArtistName() { return mSelectedItem.mArtist; } - - @Override - protected int getGroupId() { - return GROUP_ID; - } - - @Override - protected void onDeleteClicked() { - // do nothing - } - - @Override - protected void setShouldRefresh() { - // do nothing - } }; // Fade it in diff --git a/src/com/cyngn/eleven/ui/fragments/AlbumFragment.java b/src/com/cyngn/eleven/ui/fragments/AlbumFragment.java index c4d4b29..62a5372 100644 --- a/src/com/cyngn/eleven/ui/fragments/AlbumFragment.java +++ b/src/com/cyngn/eleven/ui/fragments/AlbumFragment.java @@ -39,6 +39,7 @@ import com.cyngn.eleven.sectionadapter.SectionAdapter; import com.cyngn.eleven.sectionadapter.SectionCreator; import com.cyngn.eleven.sectionadapter.SectionListContainer; import com.cyngn.eleven.ui.activities.BaseActivity; +import com.cyngn.eleven.utils.AlbumPopupMenuHelper; import com.cyngn.eleven.utils.ApolloUtils; import com.cyngn.eleven.utils.MusicUtils; import com.cyngn.eleven.utils.NavUtils; @@ -56,11 +57,6 @@ public class AlbumFragment extends Fragment implements LoaderCallbacks list) { - list.add(FragmentMenuItems.REMOVE_FROM_RECENT); + protected void updateMenuIds(TreeSet set) { + set.add(FragmentMenuItems.REMOVE_FROM_RECENT); } /** @@ -72,11 +68,6 @@ public class RecentFragment extends BasicSongFragment implements MusicStateListe } @Override - public int getGroupId() { - return GROUP_ID; - } - - @Override public int getLoaderId() { return LOADER; } diff --git a/src/com/cyngn/eleven/ui/fragments/SongFragment.java b/src/com/cyngn/eleven/ui/fragments/SongFragment.java index 660f561..aba1be5 100644 --- a/src/com/cyngn/eleven/ui/fragments/SongFragment.java +++ b/src/com/cyngn/eleven/ui/fragments/SongFragment.java @@ -33,11 +33,6 @@ import com.viewpagerindicator.TitlePageIndicator; public class SongFragment extends BasicSongFragment { /** - * Used to keep context menu items from bleeding into other fragments - */ - private static final int GROUP_ID = 4; - - /** * LoaderCallbacks identifier */ private static final int LOADER = 0; @@ -74,11 +69,6 @@ public class SongFragment extends BasicSongFragment { @Override - public int getGroupId() { - return GROUP_ID; - } - - @Override public int getLoaderId() { return LOADER; } diff --git a/src/com/cyngn/eleven/ui/fragments/profile/BasicSongFragment.java b/src/com/cyngn/eleven/ui/fragments/profile/BasicSongFragment.java index 8f13bf6..4ff9882 100644 --- a/src/com/cyngn/eleven/ui/fragments/profile/BasicSongFragment.java +++ b/src/com/cyngn/eleven/ui/fragments/profile/BasicSongFragment.java @@ -28,17 +28,17 @@ import android.widget.ListView; import com.cyngn.eleven.MusicStateListener; import com.cyngn.eleven.R; import com.cyngn.eleven.adapters.SongAdapter; -import com.cyngn.eleven.menu.DeleteDialog; import com.cyngn.eleven.model.Song; import com.cyngn.eleven.recycler.RecycleHolder; import com.cyngn.eleven.sectionadapter.SectionAdapter; import com.cyngn.eleven.sectionadapter.SectionListContainer; import com.cyngn.eleven.ui.activities.BaseActivity; import com.cyngn.eleven.utils.PopupMenuHelper; +import com.cyngn.eleven.utils.SongPopupMenuHelper; import com.cyngn.eleven.widgets.IPopupMenuCallback; import com.cyngn.eleven.widgets.NoResultsContainer; -import java.util.ArrayList; +import java.util.TreeSet; /** * This class is used to display all of the songs @@ -64,11 +64,6 @@ public abstract class BasicSongFragment extends Fragment implements protected ListView mListView; /** - * True if the list should execute {@code #restartLoader()}. - */ - protected boolean mShouldRefresh = false; - - /** * Pop up menu helper */ private PopupMenuHelper mPopupMenuHelper; @@ -95,56 +90,16 @@ public abstract class BasicSongFragment extends Fragment implements @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mPopupMenuHelper = new PopupMenuHelper(getActivity(), getFragmentManager()) { - /** - * Represents a song - */ - protected Song mSong; - - @Override - protected PopupMenuHelper.PopupMenuType onPreparePopupMenu(int position) { - // Create a new song - mSong = mAdapter.getTItem(position); - - return PopupMenuType.Song; - } - - @Override - protected void getAdditionalIds(PopupMenuType type, ArrayList list) { - super.getAdditionalIds(type, list); - BasicSongFragment.this.getAdditionaIdsForType(list); - } - - @Override - protected long[] getIdList() { - return new long[] { mSong.mSongId }; - } - + mPopupMenuHelper = new SongPopupMenuHelper(getActivity(), getFragmentManager()) { @Override - protected int getGroupId() { - return BasicSongFragment.this.getGroupId(); + public Song getSong(int position) { + return mAdapter.getTItem(position); } @Override - protected void onDeleteClicked() { - mShouldRefresh = true; - DeleteDialog.newInstance(mSong.mSongName, getIdList(), null).show( - getFragmentManager(), "DeleteDialog"); - } - - @Override - protected void setShouldRefresh() { - mShouldRefresh = true; - } - - @Override - protected long getId() { - return mSong.mSongId; - } - - @Override - protected String getArtistName() { - return mSong.mArtistName; + protected void updateMenuIds(PopupMenuType type, TreeSet set) { + super.updateMenuIds(type, set); + BasicSongFragment.this.updateMenuIds(set); } }; @@ -158,7 +113,7 @@ public abstract class BasicSongFragment extends Fragment implements }); } - protected void getAdditionaIdsForType(ArrayList list) { + protected void updateMenuIds(TreeSet set) { // do nothing - let subclasses override } @@ -265,10 +220,7 @@ public abstract class BasicSongFragment extends Fragment implements @Override public void restartLoader() { // Update the list when the user deletes any items - if (mShouldRefresh) { - getLoaderManager().restartLoader(getLoaderId(), null, this); - } - mShouldRefresh = false; + getLoaderManager().restartLoader(getLoaderId(), null, this); } /** @@ -299,11 +251,6 @@ public abstract class BasicSongFragment extends Fragment implements } /** - * Used to keep context menu items from bleeding into other fragments - */ - public abstract int getGroupId(); - - /** * LoaderCallbacks identifier */ public abstract int getLoaderId(); diff --git a/src/com/cyngn/eleven/ui/fragments/profile/LastAddedFragment.java b/src/com/cyngn/eleven/ui/fragments/profile/LastAddedFragment.java index 457a042..abd115a 100644 --- a/src/com/cyngn/eleven/ui/fragments/profile/LastAddedFragment.java +++ b/src/com/cyngn/eleven/ui/fragments/profile/LastAddedFragment.java @@ -32,11 +32,6 @@ import com.cyngn.eleven.widgets.NoResultsContainer; public class LastAddedFragment extends BasicSongFragment { /** - * Used to keep context menu items from bleeding into other fragments - */ - private static final int GROUP_ID = 7; - - /** * LoaderCallbacks identifier */ private static final int LOADER = 0; @@ -51,11 +46,6 @@ public class LastAddedFragment extends BasicSongFragment { } @Override - public int getGroupId() { - return GROUP_ID; - } - - @Override public int getLoaderId() { return LOADER; } diff --git a/src/com/cyngn/eleven/ui/fragments/profile/TopTracksFragment.java b/src/com/cyngn/eleven/ui/fragments/profile/TopTracksFragment.java index e28824e..dc959a1 100644 --- a/src/com/cyngn/eleven/ui/fragments/profile/TopTracksFragment.java +++ b/src/com/cyngn/eleven/ui/fragments/profile/TopTracksFragment.java @@ -38,11 +38,6 @@ import com.cyngn.eleven.widgets.NoResultsContainer; public class TopTracksFragment extends BasicSongFragment { /** - * Used to keep context menu items from bleeding into other fragments - */ - private static final int GROUP_ID = 6; - - /** * LoaderCallbacks identifier */ private static final int LOADER = 0; @@ -68,11 +63,6 @@ public class TopTracksFragment extends BasicSongFragment { } @Override - public int getGroupId() { - return GROUP_ID; - } - - @Override public int getLoaderId() { return LOADER; } diff --git a/src/com/cyngn/eleven/utils/AlbumPopupMenuHelper.java b/src/com/cyngn/eleven/utils/AlbumPopupMenuHelper.java new file mode 100644 index 0000000..a4ea428 --- /dev/null +++ b/src/com/cyngn/eleven/utils/AlbumPopupMenuHelper.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 Cyanogen, Inc. + */ +package com.cyngn.eleven.utils; + + +import android.app.Activity; +import android.support.v4.app.FragmentManager; + +import com.cyngn.eleven.cache.ImageFetcher; +import com.cyngn.eleven.menu.DeleteDialog; +import com.cyngn.eleven.model.Album; + +public abstract class AlbumPopupMenuHelper extends PopupMenuHelper { + protected Album mAlbum; + + public AlbumPopupMenuHelper(Activity activity, FragmentManager fragmentManager) { + super(activity, fragmentManager); + } + + public abstract Album getAlbum(int position); + + @Override + protected PopupMenuType onPreparePopupMenu(int position) { + mAlbum = getAlbum(position); + + if (mAlbum == null) { + return null; + } + + return PopupMenuType.Album; + } + + @Override + protected long[] getIdList() { + return MusicUtils.getSongListForAlbum(mActivity, mAlbum.mAlbumId); + } + + @Override + protected void onDeleteClicked() { + final String album = mAlbum.mAlbumName; + DeleteDialog.newInstance(album, getIdList(), + ImageFetcher.generateAlbumCacheKey(album, mAlbum.mArtistName)) + .show(mFragmentManager, "DeleteDialog"); + } + + @Override + protected String getArtistName() { + return mAlbum.mArtistName; + } +} diff --git a/src/com/cyngn/eleven/utils/PopupMenuHelper.java b/src/com/cyngn/eleven/utils/PopupMenuHelper.java index 856d147..e771578 100644 --- a/src/com/cyngn/eleven/utils/PopupMenuHelper.java +++ b/src/com/cyngn/eleven/utils/PopupMenuHelper.java @@ -19,6 +19,7 @@ import com.cyngn.eleven.menu.RenamePlaylist; import com.cyngn.eleven.provider.RecentStore; import java.util.ArrayList; +import java.util.TreeSet; /** * Simple helper class that does most of the popup menu inflating and handling @@ -84,18 +85,16 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen /** * @return the group id to be used for pop up menu inflating */ - protected abstract int getGroupId(); - - /** - * called when the delete item is pressed. Since delete is different from class to class - * it is not implemented in this class and relies on the contaning classes to implement - */ - protected abstract void onDeleteClicked(); + protected int getGroupId() { + return 0; + } /** - * Tells the containing class that it should probably mark their loaders for refresh + * called when the delete item is pressed. */ - protected abstract void setShouldRefresh(); + protected void onDeleteClicked() { + throw new UnsupportedOperationException("Method Not Implemented!"); + } /** * @return the artist name (when needed) for "more by this artist" @@ -108,6 +107,11 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen * @return the single id that is needed for the "set as my ringtone" */ protected long getId() { + long[] idList = getIdList(); + if (idList.length == 1) { + return idList[0]; + } + throw new UnsupportedOperationException("Method Not Implemented!"); } @@ -137,18 +141,19 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen * @param menu Menu to use for adding to */ protected void createPopupMenu(final Menu menu) { + TreeSet menuItems = new TreeSet(); + // get the default items and add them - int[] menuItems = getIdsForType(mType); - if (menuItems != null) { - for (int id : menuItems) { - addToMenu(menu, id, getStringResourceForId(id)); + int[] defaultItems = getIdsForType(mType); + if (defaultItems != null) { + for (int id : defaultItems) { + menuItems.add(id); } } - // if the containing class wants to add additional items, do it here - ArrayList additionalItems = new ArrayList(); - getAdditionalIds(mType, additionalItems); - for (int id : additionalItems) { + updateMenuIds(mType, menuItems); + + for (int id : menuItems) { addToMenu(menu, id, getAdditionalStringResourceForId(id)); } } @@ -218,11 +223,11 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen } /** - * Gets the additional menu items to inflate + * Allows containing classes to add/remove ids to the menu * @param type the pop up menu type - * @param list the list to add menu items to + * @param set the treeset to add/remove menu items */ - protected void getAdditionalIds(PopupMenuType type, ArrayList list) { + protected void updateMenuIds(PopupMenuType type, TreeSet set) { // do nothing } @@ -290,7 +295,6 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen if (item.getGroupId() == getGroupId()) { switch (item.getItemId()) { case FragmentMenuItems.REMOVE_FROM_RECENT: - setShouldRefresh(); RecentStore.getInstance(mActivity).removeItem(getId()); MusicUtils.refresh(); return true; @@ -322,7 +326,6 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen mFragmentManager, "CreatePlaylist"); return true; case FragmentMenuItems.RENAME_PLAYLIST: - setShouldRefresh(); RenamePlaylist.getInstance(getId()).show( mFragmentManager, "RenameDialog"); return true; @@ -334,18 +337,15 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen NavUtils.openArtistProfile(mActivity, getArtistName()); return true; case FragmentMenuItems.DELETE: - setShouldRefresh(); onDeleteClicked(); return true; case FragmentMenuItems.USE_AS_RINGTONE: MusicUtils.setRingtone(mActivity, getId()); return true; case FragmentMenuItems.REMOVE_FROM_PLAYLIST: - setShouldRefresh(); removeFromPlaylist(); return true; case FragmentMenuItems.REMOVE_FROM_QUEUE: - setShouldRefresh(); removeFromQueue(); return true; case FragmentMenuItems.PLAY_NEXT: diff --git a/src/com/cyngn/eleven/utils/SongPopupMenuHelper.java b/src/com/cyngn/eleven/utils/SongPopupMenuHelper.java new file mode 100644 index 0000000..87299f0 --- /dev/null +++ b/src/com/cyngn/eleven/utils/SongPopupMenuHelper.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 Cyanogen, Inc. + */ +package com.cyngn.eleven.utils; + + +import android.app.Activity; +import android.support.v4.app.FragmentManager; + +import com.cyngn.eleven.menu.DeleteDialog; +import com.cyngn.eleven.model.Song; + +public abstract class SongPopupMenuHelper extends PopupMenuHelper { + protected Song mSong; + + public SongPopupMenuHelper(Activity activity, FragmentManager fragmentManager) { + super(activity, fragmentManager); + } + + public abstract Song getSong(int position); + + @Override + protected PopupMenuHelper.PopupMenuType onPreparePopupMenu(int position) { + mSong = getSong(position); + + if (mSong == null) { + return null; + } + + return PopupMenuType.Song; + } + + @Override + protected long[] getIdList() { + return new long[] { mSong.mSongId }; + } + + @Override + protected String getArtistName() { + return mSong.mArtistName; + } + + @Override + protected void onDeleteClicked() { + DeleteDialog.newInstance(mSong.mSongName, getIdList(), null) + .show(mFragmentManager, "DeleteDialog"); + } +} -- 2.11.0