From f033819620bd6ae44fecfc373065b7afe59775b5 Mon Sep 17 00:00:00 2001 From: Karim Abou Zeid Date: Mon, 25 May 2015 18:11:51 +0200 Subject: [PATCH] Artist album and artist song multi select --- .../adapter/ArtistAlbumAdapter.java | 78 ++++++++++++--- .../songadapter/ArtistSongAdapter.java | 99 ++++++++++++++++++- .../ui/activities/ArtistDetailActivity.java | 55 +++++++---- .../res/layout/activity_artist_detail.xml | 19 +++- .../main/res/layout/item_list_artist_song.xml | 29 +++--- 5 files changed, 227 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java index 720cd6a5..449fbdd6 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java @@ -1,35 +1,44 @@ package com.kabouzeid.gramophone.adapter; -import android.app.Activity; +import android.support.annotation.Nullable; import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog; +import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog; +import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.CabHolder; +import com.kabouzeid.gramophone.loader.AlbumSongLoader; import com.kabouzeid.gramophone.model.Album; +import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity; import com.kabouzeid.gramophone.util.MusicUtil; import com.kabouzeid.gramophone.util.NavigationUtil; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; +import java.util.ArrayList; import java.util.List; /** * @author Karim Abou Zeid (kabouzeid) */ -public class ArtistAlbumAdapter extends RecyclerView.Adapter { +public class ArtistAlbumAdapter extends AbsMultiSelectAdapter { public static final String TAG = AlbumAdapter.class.getSimpleName(); private static final int TYPE_FIRST = 1; private static final int TYPE_MIDDLE = 2; private static final int TYPE_LAST = 3; - private final Activity activity; + private final AppCompatActivity activity; private final List dataSet; private final int listMargin; @@ -61,6 +70,7 @@ public class ArtistAlbumAdapter extends RecyclerView.Adapter selection) { + switch (menuItem.getItemId()) { + case R.id.action_delete_from_disk: + DeleteSongsDialog.create(getSongList(selection)).show(activity.getSupportFragmentManager(), "DELETE_SONGS"); + break; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(getSongList(selection)).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + break; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(getSongList(selection)); + break; + } + } + + private ArrayList getSongList(List albums) { + final ArrayList songs = new ArrayList<>(); + for (Album album : albums) { + songs.addAll(AlbumSongLoader.getAlbumSongList(activity, album.id)); + } + return songs; + } + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { final ImageView albumArt; final TextView title; final TextView year; + final View view; public ViewHolder(View itemView) { super(itemView); + view = itemView; albumArt = (ImageView) itemView.findViewById(R.id.album_art); title = (TextView) itemView.findViewById(R.id.album_title); year = (TextView) itemView.findViewById(R.id.album_year); - itemView.setOnClickListener(this); + view.setOnClickListener(this); + view.setOnLongClickListener(this); } @Override public void onClick(View v) { - Pair[] albumPairs = new Pair[]{ - Pair.create(albumArt, - activity.getResources().getString(R.string.transition_album_cover) - )}; - if (activity instanceof AbsFabActivity) - albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs); - NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).id, albumPairs); + if (isInQuickSelectMode()) { + toggleChecked(getAdapterPosition()); + } else { + Pair[] albumPairs = new Pair[]{ + Pair.create(albumArt, + activity.getResources().getString(R.string.transition_album_cover) + )}; + if (activity instanceof AbsFabActivity) + albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs); + NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).id, albumPairs); + } + } + + @Override + public boolean onLongClick(View view) { + toggleChecked(getAdapterPosition()); + return true; } } - public ArtistAlbumAdapter(Activity activity, List objects) { + public ArtistAlbumAdapter(AppCompatActivity activity, List objects, @Nullable CabHolder cabHolder) { + super(cabHolder, R.menu.menu_media_selection); this.activity = activity; dataSet = objects; listMargin = activity.getResources().getDimensionPixelSize(R.dimen.default_item_margin); diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/ArtistSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/ArtistSongAdapter.java index e49eca39..5bf43ed3 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/ArtistSongAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/ArtistSongAdapter.java @@ -1,8 +1,10 @@ package com.kabouzeid.gramophone.adapter.songadapter; +import android.support.annotation.Nullable; import android.support.v4.util.Pair; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; +import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -11,8 +13,11 @@ import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; +import com.afollestad.materialcab.MaterialCab; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.helper.MenuItemClickHelper; +import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity; import com.kabouzeid.gramophone.util.MusicUtil; @@ -20,22 +25,30 @@ import com.kabouzeid.gramophone.util.NavigationUtil; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; -import java.util.List; +import java.util.ArrayList; /** * @author Karim Abou Zeid (kabouzeid) */ -public class ArtistSongAdapter extends ArrayAdapter { +public class ArtistSongAdapter extends ArrayAdapter implements MaterialCab.Callback { + + private final CabHolder cabHolder; + private MaterialCab cab; + private ArrayList dataSet; + private ArrayList checked; private final AppCompatActivity activity; - public ArtistSongAdapter(AppCompatActivity activity, List songs) { + public ArtistSongAdapter(AppCompatActivity activity, ArrayList songs, @Nullable CabHolder cabHolder) { super(activity, R.layout.item_list_song, songs); this.activity = activity; + this.cabHolder = cabHolder; + checked = new ArrayList<>(); + dataSet = songs; } @Override - public View getView(int position, View convertView, ViewGroup parent) { + public View getView(final int position, View convertView, ViewGroup parent) { final Song song = getItem(position); if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_list_artist_song, parent, false); @@ -83,6 +96,84 @@ public class ArtistSongAdapter extends ArrayAdapter { popupMenu.show(); } }); + + convertView.setActivated(isChecked(song)); + convertView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (isInQuickSelectMode()) { + toggleChecked(song); + } else { + MusicPlayerRemote.openQueue(dataSet, position, true); + } + } + }); + convertView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View view) { + toggleChecked(song); + return true; + } + }); + return convertView; } + + private void onMultipleItemAction(MenuItem menuItem, ArrayList songs) { + + } + + protected void toggleChecked(Song song) { + if (cabHolder != null) { + openCabIfNecessary(); + + if (!checked.remove(song)) checked.add(song); + notifyDataSetChanged(); + + final int size = checked.size(); + if (size <= 0) cab.finish(); + else if (size == 1) cab.setTitle(checked.get(0).toString()); + else if (size > 1) cab.setTitle(String.valueOf(size)); + } + } + + private void openCabIfNecessary() { + if (cabHolder != null) { + if (cab == null || !cab.isActive()) { + cab = cabHolder.openCab(R.menu.menu_media_selection, this); + } + } + } + + private void uncheckAll() { + checked.clear(); + notifyDataSetChanged(); + } + + protected boolean isChecked(Song song) { + return checked.contains(song); + } + + protected boolean isInQuickSelectMode() { + return cab != null && cab.isActive(); + } + + @Override + public boolean onCabCreated(MaterialCab materialCab, Menu menu) { + return true; + } + + @Override + public boolean onCabItemClicked(MenuItem menuItem) { + onMultipleItemAction(menuItem, new ArrayList<>(checked)); + cab.finish(); + uncheckAll(); + return true; + } + + @Override + public boolean onCabFinished(MaterialCab materialCab) { + uncheckAll(); + return true; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java index f8c1a3df..b67a1523 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java @@ -17,11 +17,11 @@ import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import com.afollestad.materialcab.MaterialCab; import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.util.DialogUtils; import com.github.ksoichiro.android.observablescrollview.ObservableListView; @@ -30,6 +30,7 @@ import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.adapter.ArtistAlbumAdapter; import com.kabouzeid.gramophone.adapter.songadapter.ArtistSongAdapter; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.interfaces.PaletteColorHolder; import com.kabouzeid.gramophone.lastfm.artist.LastFMArtistBiographyLoader; import com.kabouzeid.gramophone.lastfm.artist.LastFMArtistImageUrlLoader; @@ -62,7 +63,7 @@ import java.util.List; *

* Should be kinda stable ONLY AS IT IS!!! */ -public class ArtistDetailActivity extends AbsFabActivity implements PaletteColorHolder { +public class ArtistDetailActivity extends AbsFabActivity implements PaletteColorHolder, CabHolder { public static final String TAG = ArtistDetailActivity.class.getSimpleName(); private Artist artist; @@ -73,10 +74,12 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor private View songsBackgroundView; private TextView artistNameTv; private Toolbar toolbar; + private MaterialCab cab; private int headerOffset; private int titleViewHeight; private int artistImageViewHeight; private int toolbarColor; + private float toolbarAlpha; private int bottomOffset; private View songListHeader; @@ -98,9 +101,9 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor ViewHelper.setTranslationY(songsBackgroundView, Math.max(0, -scrollY + artistImageViewHeight)); // Change alpha of overlay - float alpha = Math.max(0, Math.min(1, (float) scrollY / flexibleRange)); - ViewUtil.setBackgroundAlpha(toolbar, alpha, toolbarColor); - ViewUtil.setBackgroundAlpha(statusBar, alpha, toolbarColor); + toolbarAlpha = Math.max(0, Math.min(1, (float) scrollY / flexibleRange)); + ViewUtil.setBackgroundAlpha(toolbar, toolbarAlpha, toolbarColor); + ViewUtil.setBackgroundAlpha(statusBar, cab != null && cab.isActive() ? 1 : toolbarAlpha, toolbarColor); // Translate name text int maxTitleTranslationY = artistImageViewHeight; @@ -209,7 +212,7 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor songListView.addHeaderView(songListHeader); final ArrayList songs = ArtistSongLoader.getArtistSongList(this, artist.id); - ArtistSongAdapter songAdapter = new ArtistSongAdapter(this, songs); + ArtistSongAdapter songAdapter = new ArtistSongAdapter(this, songs, this); songListView.setAdapter(songAdapter); final View contentView = getWindow().getDecorView().findViewById(android.R.id.content); @@ -220,23 +223,12 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor observableScrollViewCallbacks.onScrollChanged(-(artistImageViewHeight + titleViewHeight), false, false); } }); - - songListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - // header view has position 0 - if (position == 0) { - return; - } - MusicPlayerRemote.openQueue(songs, position - 1, true); - } - }); } private void setUpAlbumRecyclerView() { albumRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); List albums = ArtistAlbumLoader.getArtistAlbumList(this, artist.id); - albumAdapter = new ArtistAlbumAdapter(this, albums); + albumAdapter = new ArtistAlbumAdapter(this, albums, this); albumRecyclerView.setAdapter(albumAdapter); } @@ -453,4 +445,31 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor super.onDestroy(); App.bus.unregister(this); } + + @Override + public MaterialCab openCab(int menuRes, final MaterialCab.Callback callback) { + if (cab != null && cab.isActive()) cab.finish(); + cab = new MaterialCab(this, R.id.cab_stub) + .setMenu(menuRes) + .setBackgroundColor(getPaletteColor()) + .start(new MaterialCab.Callback() { + @Override + public boolean onCabCreated(MaterialCab materialCab, Menu menu) { + ViewUtil.setBackgroundAlpha(statusBar, 1, toolbarColor); + return callback.onCabCreated(materialCab, menu); + } + + @Override + public boolean onCabItemClicked(MenuItem menuItem) { + return callback.onCabItemClicked(menuItem); + } + + @Override + public boolean onCabFinished(MaterialCab materialCab) { + ViewUtil.setBackgroundAlpha(statusBar, toolbarAlpha, toolbarColor); + return callback.onCabFinished(materialCab); + } + }); + return cab; + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_artist_detail.xml b/app/src/main/res/layout/activity_artist_detail.xml index 503684e0..177cecbc 100644 --- a/app/src/main/res/layout/activity_artist_detail.xml +++ b/app/src/main/res/layout/activity_artist_detail.xml @@ -67,10 +67,21 @@ android:layout_height="@dimen/statusMargin" android:background="@android:color/transparent" /> - + + + + + + + diff --git a/app/src/main/res/layout/item_list_artist_song.xml b/app/src/main/res/layout/item_list_artist_song.xml index 0f30285a..818a14a9 100644 --- a/app/src/main/res/layout/item_list_artist_song.xml +++ b/app/src/main/res/layout/item_list_artist_song.xml @@ -1,16 +1,17 @@ + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="72dp" + android:foreground="?rect_selector"> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:descendantFocusability="blocksDescendants" + android:orientation="horizontal" + android:paddingLeft="16dp" + android:paddingStart="16dp"> + android:textAppearance="@style/TextAppearance.AppCompat.Subhead" + android:textColor="?title_text_color" /> + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textColor="?caption_text_color" />