diff --git a/app/build.gradle b/app/build.gradle index 4ded3c4b..d81bafc3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -70,6 +70,7 @@ dependencies { compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3' compile 'com.afollestad:material-dialogs:0.7.4.2' + compile 'com.afollestad:material-cab:0.1.2' compile 'com.jpardogo.materialtabstrip:library:1.0.9' compile 'com.readystatesoftware.systembartint:systembartint:1.0.3' compile 'com.melnykov:floatingactionbutton:1.3.0' diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/AbsMultiSelectAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/AbsMultiSelectAdapter.java new file mode 100644 index 00000000..ed8c11f3 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/AbsMultiSelectAdapter.java @@ -0,0 +1,86 @@ +package com.kabouzeid.gramophone.adapter; + +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.view.Menu; +import android.view.MenuItem; + +import com.afollestad.materialcab.MaterialCab; +import com.kabouzeid.gramophone.interfaces.CabHolder; + +import java.util.ArrayList; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public abstract class AbsMultiSelectAdapter extends RecyclerView.Adapter implements MaterialCab.Callback { + private final CabHolder cabHolder; + private MaterialCab cab; + private ArrayList checked; + private int menuRes; + + public AbsMultiSelectAdapter(@Nullable CabHolder cabHolder, int menuRes) { + this.cabHolder = cabHolder; + checked = new ArrayList<>(); + this.menuRes = menuRes; + } + + protected void toggleChecked(final int position) { + if (cabHolder != null) { + openCabIfNecessary(); + + I identifier = getIdentifier(position); + if (!checked.remove(identifier)) checked.add(identifier); + notifyItemChanged(position); + + 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(menuRes, this); + } + } + } + + private void uncheckAll() { + checked.clear(); + notifyDataSetChanged(); + } + + protected boolean isChecked(I identifier) { + return checked.contains(identifier); + } + + 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; + } + + protected abstract I getIdentifier(int position); + + protected abstract void onMultipleItemAction(MenuItem menuItem, ArrayList selection); +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumAdapter.java index 13e80325..a59c5080 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumAdapter.java @@ -1,27 +1,40 @@ package com.kabouzeid.gramophone.adapter; -import android.app.Activity; +import android.annotation.TargetApi; import android.graphics.Bitmap; +import android.os.Build; +import android.support.annotation.Nullable; import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; import android.support.v7.graphics.Palette; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import com.afollestad.materialdialogs.util.DialogUtils; import com.kabouzeid.gramophone.App; 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.AlbumLoader; +import com.kabouzeid.gramophone.loader.AlbumSongLoader; import com.kabouzeid.gramophone.model.Album; import com.kabouzeid.gramophone.model.DataBaseChangedEvent; +import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent; import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity; import com.kabouzeid.gramophone.util.MusicUtil; import com.kabouzeid.gramophone.util.NavigationUtil; import com.kabouzeid.gramophone.util.PreferenceUtils; +import com.kabouzeid.gramophone.util.Util; import com.kabouzeid.gramophone.util.ViewUtil; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; @@ -29,15 +42,16 @@ import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; import com.squareup.otto.Subscribe; +import java.util.ArrayList; import java.util.List; /** * @author Karim Abou Zeid (kabouzeid) */ -public class AlbumAdapter extends RecyclerView.Adapter { +public class AlbumAdapter extends AbsMultiSelectAdapter { public static final String TAG = AlbumAdapter.class.getSimpleName(); - private final Activity activity; + private final AppCompatActivity activity; private boolean usePalette; private List dataSet; @@ -53,6 +67,10 @@ public class AlbumAdapter extends RecyclerView.Adapter resetColors(holder.title, holder.artist, holder.footer); + final boolean isChecked = isChecked(album); + holder.view.setActivated(isChecked); + holder.checkMark.setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE); + holder.title.setText(album.title); holder.artist.setText(album.artistName); @@ -85,34 +103,90 @@ public class AlbumAdapter extends RecyclerView.Adapter return dataSet.size(); } - public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + @Override + protected Album getIdentifier(int position) { + return dataSet.get(position); + } + + @Override + protected void onMultipleItemAction(MenuItem menuItem, ArrayList 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 artist; final View footer; + final ImageView checkMark; + 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); artist = (TextView) itemView.findViewById(R.id.album_interpret); footer = itemView.findViewById(R.id.footer); - itemView.setOnClickListener(this); + checkMark = (ImageView) itemView.findViewById(R.id.check_mark); + view.setOnClickListener(this); + view.setOnLongClickListener(this); + + // fixes the ripple starts at the right position + if (Util.isAtLeastLollipop()) { + view.setOnTouchListener(new View.OnTouchListener() { + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + ((FrameLayout) view.findViewById(R.id.content)).getForeground().setHotspot(motionEvent.getX(), motionEvent.getY()); + return false; + } + }); + } } @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 AlbumAdapter(Activity activity) { + public AlbumAdapter(AppCompatActivity activity, @Nullable CabHolder cabHolder) { + super(cabHolder, R.menu.menu_media_selection); this.activity = activity; usePalette = PreferenceUtils.getInstance(activity).coloredAlbumFootersEnabled(); loadDataSet(); diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAdapter.java index 97e56291..d3a7d7b7 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAdapter.java @@ -1,9 +1,11 @@ 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; @@ -11,10 +13,16 @@ import android.widget.TextView; import com.kabouzeid.gramophone.App; 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.lastfm.artist.LastFMArtistThumbnailUrlLoader; import com.kabouzeid.gramophone.loader.ArtistLoader; +import com.kabouzeid.gramophone.loader.ArtistSongLoader; import com.kabouzeid.gramophone.model.Artist; import com.kabouzeid.gramophone.model.DataBaseChangedEvent; +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; @@ -22,16 +30,18 @@ import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.squareup.otto.Subscribe; +import java.util.ArrayList; import java.util.List; /** * @author Karim Abou Zeid (kabouzeid) */ -public class ArtistAdapter extends RecyclerView.Adapter { - protected final Activity activity; +public class ArtistAdapter extends AbsMultiSelectAdapter { + protected final AppCompatActivity activity; protected List dataSet; - public ArtistAdapter(Activity activity) { + public ArtistAdapter(AppCompatActivity activity, @Nullable CabHolder cabHolder) { + super(cabHolder, R.menu.menu_media_selection); this.activity = activity; loadDataSet(); } @@ -53,6 +63,7 @@ public class ArtistAdapter 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 artists) { + final ArrayList songs = new ArrayList<>(); + for (Artist artist : artists) { + songs.addAll(ArtistSongLoader.getArtistSongList(activity, artist.id)); + } + return songs; + } + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { final TextView artistName; final TextView artistInfo; final ImageView artistImage; + final View view; public ViewHolder(View itemView) { super(itemView); + view = itemView; artistName = (TextView) itemView.findViewById(R.id.artist_name); artistInfo = (TextView) itemView.findViewById(R.id.artist_info); artistImage = (ImageView) itemView.findViewById(R.id.artist_image); - itemView.setOnClickListener(this); + view.setOnClickListener(this); + view.setOnLongClickListener(this); } @Override public void onClick(View v) { - Pair[] artistPairs = new Pair[]{ - Pair.create(artistImage, - activity.getResources().getString(R.string.transition_artist_image) - )}; - if (activity instanceof AbsFabActivity) - artistPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(artistPairs); - NavigationUtil.goToArtist(activity, dataSet.get(getAdapterPosition()).id, artistPairs); + if (isInQuickSelectMode()) { + toggleChecked(getAdapterPosition()); + } else { + Pair[] artistPairs = new Pair[]{ + Pair.create(artistImage, + activity.getResources().getString(R.string.transition_artist_image) + )}; + if (activity instanceof AbsFabActivity) + artistPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(artistPairs); + NavigationUtil.goToArtist(activity, dataSet.get(getAdapterPosition()).id, artistPairs); + } + } + + @Override + public boolean onLongClick(View view) { + toggleChecked(getAdapterPosition()); + return true; } } 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..1251649c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java @@ -1,38 +1,59 @@ 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 List dataSet; + private final AppCompatActivity activity; + private ArrayList dataSet; private final int listMargin; + public ArtistAlbumAdapter(AppCompatActivity activity, ArrayList 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); + } + + public void updateDataSet(ArrayList objects) { + dataSet = objects; + notifyDataSetChanged(); + } + @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(activity).inflate(R.layout.item_grid_artist_album, parent, false); @@ -61,6 +82,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) { - 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/PlaylistAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java index f9162ed6..d76c6893 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java @@ -1,5 +1,6 @@ package com.kabouzeid.gramophone.adapter; +import android.support.annotation.Nullable; import android.support.v4.util.Pair; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.RecyclerView; @@ -10,25 +11,36 @@ import android.view.ViewGroup; import android.widget.PopupMenu; import android.widget.TextView; +import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog; +import com.kabouzeid.gramophone.dialogs.DeletePlaylistDialog; import com.kabouzeid.gramophone.helper.MenuItemClickHelper; +import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.loader.PlaylistLoader; +import com.kabouzeid.gramophone.loader.PlaylistSongLoader; +import com.kabouzeid.gramophone.model.DataBaseChangedEvent; import com.kabouzeid.gramophone.model.Playlist; +import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity; import com.kabouzeid.gramophone.util.NavigationUtil; +import com.squareup.otto.Subscribe; +import java.util.ArrayList; import java.util.List; /** * @author Karim Abou Zeid (kabouzeid) */ -public class PlaylistAdapter extends RecyclerView.Adapter { +public class PlaylistAdapter extends AbsMultiSelectAdapter { public static final String TAG = PlaylistAdapter.class.getSimpleName(); protected final AppCompatActivity activity; protected List dataSet; - public PlaylistAdapter(AppCompatActivity activity) { + public PlaylistAdapter(AppCompatActivity activity, @Nullable CabHolder cabHolder) { + super(cabHolder, R.menu.menu_playlists_selection); this.activity = activity; loadDataSet(); } @@ -45,7 +57,9 @@ public class PlaylistAdapter extends RecyclerView.Adapter selection) { + switch (menuItem.getItemId()) { + case R.id.action_delete_playlist: + DeletePlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST"); + 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 playlists) { + final ArrayList songs = new ArrayList<>(); + for (Playlist playlist : playlists) { + songs.addAll(PlaylistSongLoader.getPlaylistSongList(activity, playlist.id)); + } + return songs; + } + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { public final TextView playlistName; private final View menu; + private final View view; public ViewHolder(View itemView) { super(itemView); + view = itemView; playlistName = (TextView) itemView.findViewById(R.id.playlist_name); menu = itemView.findViewById(R.id.menu); - itemView.setOnClickListener(this); + view.setOnClickListener(this); + view.setOnLongClickListener(this); menu.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -81,10 +126,43 @@ public class PlaylistAdapter extends RecyclerView.Adapter { +public class AlbumSongAdapter extends AbsMultiSelectAdapter { public static final String TAG = AlbumSongAdapter.class.getSimpleName(); protected final AppCompatActivity activity; - protected final ArrayList dataSet; + protected ArrayList dataSet; - public AlbumSongAdapter(AppCompatActivity activity, ArrayList objects) { + public AlbumSongAdapter(AppCompatActivity activity, ArrayList objects, @Nullable CabHolder cabHolder) { + super(cabHolder, R.menu.menu_media_selection); this.activity = activity; dataSet = objects; } + public void updateDataSet(ArrayList objects){ + dataSet = objects; + notifyDataSetChanged(); + } + @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(activity).inflate(R.layout.item_list_album_song, parent, false); @@ -47,6 +58,7 @@ public class AlbumSongAdapter extends RecyclerView.Adapter selection) { + switch (menuItem.getItemId()) { + case R.id.action_delete_from_disk: + DeleteSongsDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_SONGS"); + break; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + break; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(selection); + break; + } + } + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { final TextView songTitle; final TextView trackNumber; final TextView artistName; final ImageView overflowButton; + final View view; public ViewHolder(View itemView) { super(itemView); + view = itemView; songTitle = (TextView) itemView.findViewById(R.id.song_title); trackNumber = (TextView) itemView.findViewById(R.id.track_number); artistName = (TextView) itemView.findViewById(R.id.song_info); overflowButton = (ImageView) itemView.findViewById(R.id.menu); - overflowButton.setOnClickListener(this); - itemView.setOnClickListener(new View.OnClickListener() { + view.setOnClickListener(this); + view.setOnLongClickListener(this); + overflowButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - MusicPlayerRemote.openQueue(dataSet, getAdapterPosition(), true); + PopupMenu popupMenu = new PopupMenu(activity, v); + popupMenu.inflate(R.menu.menu_item_song); + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(getAdapterPosition()), item); + } + }); + popupMenu.show(); } }); } @Override public void onClick(View v) { - PopupMenu popupMenu = new PopupMenu(activity, v); - popupMenu.inflate(R.menu.menu_item_song); - popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(getAdapterPosition()), item); - } - }); - popupMenu.show(); + if (isInQuickSelectMode()) { + toggleChecked(getAdapterPosition()); + } else { + MusicPlayerRemote.openQueue(dataSet, getAdapterPosition(), true); + } + } + + @Override + public boolean onLongClick(View view) { + toggleChecked(getAdapterPosition()); + return true; } } } 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..573e5bf8 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,13 @@ 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.dialogs.AddToPlaylistDialog; +import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog; 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 +27,35 @@ 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; + } + + public void updateDataSet(ArrayList objects) { + dataSet = objects; + notifyDataSetChanged(); } @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 +103,94 @@ 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 selection) { + switch (menuItem.getItemId()) { + case R.id.action_delete_from_disk: + DeleteSongsDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_SONGS"); + break; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + break; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(selection); + break; + } + } + + 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/adapter/songadapter/PlaylistSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/PlaylistSongAdapter.java index f97cab2a..4126a08f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/PlaylistSongAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/PlaylistSongAdapter.java @@ -1,5 +1,6 @@ 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.support.v7.widget.RecyclerView; @@ -12,14 +13,17 @@ import android.widget.PopupMenu; import android.widget.TextView; import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.adapter.AbsMultiSelectAdapter; +import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog; +import com.kabouzeid.gramophone.dialogs.DeleteFromPlaylistDialog; import com.kabouzeid.gramophone.helper.MenuItemClickHelper; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.model.PlaylistSong; 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.kabouzeid.gramophone.util.PlaylistsUtil; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; @@ -29,17 +33,23 @@ import java.util.List; /** * @author Karim Abou Zeid (kabouzeid) */ -public class PlaylistSongAdapter extends RecyclerView.Adapter { +public class PlaylistSongAdapter extends AbsMultiSelectAdapter { public static final String TAG = AlbumSongAdapter.class.getSimpleName(); protected final AppCompatActivity activity; - protected final ArrayList dataSet; + protected ArrayList dataSet; - public PlaylistSongAdapter(AppCompatActivity activity, ArrayList objects) { + public PlaylistSongAdapter(AppCompatActivity activity, ArrayList objects, @Nullable CabHolder cabHolder) { + super(cabHolder, R.menu.menu_playlists_songs_selection); this.activity = activity; dataSet = objects; } + public void updateDataSet(ArrayList objects) { + dataSet = objects; + notifyDataSetChanged(); + } + @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(activity).inflate(R.layout.item_list_song, parent, false); @@ -48,8 +58,9 @@ public class PlaylistSongAdapter extends RecyclerView.Adapter selection) { + switch (menuItem.getItemId()) { + case R.id.action_delete_from_playlist: + DeleteFromPlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_FROM_PLAYLIST"); + break; + case R.id.action_add_to_playlist: + //noinspection unchecked + AddToPlaylistDialog.create((ArrayList) (List) selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + break; + case R.id.action_add_to_current_playing: + //noinspection unchecked + MusicPlayerRemote.enqueue((ArrayList) (List) selection); + break; + } + } + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { final TextView songTitle; final TextView songInfo; final ImageView overflowButton; final ImageView albumArt; + final View view; public ViewHolder(View itemView) { super(itemView); + view = itemView; songTitle = (TextView) itemView.findViewById(R.id.song_title); songInfo = (TextView) itemView.findViewById(R.id.song_info); albumArt = (ImageView) itemView.findViewById(R.id.album_art); + view.setOnClickListener(this); + view.setOnLongClickListener(this); overflowButton = (ImageView) itemView.findViewById(R.id.menu); - overflowButton.setOnClickListener(this); - itemView.setOnClickListener(new View.OnClickListener() { + overflowButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - //noinspection unchecked - MusicPlayerRemote.openQueue((ArrayList) (List) dataSet, getAdapterPosition(), true); + PopupMenu popupMenu = new PopupMenu(activity, v); + popupMenu.inflate(R.menu.menu_item_playlist_song); + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_delete_from_playlist: + DeleteFromPlaylistDialog.create(dataSet.get(getAdapterPosition())).show(activity.getSupportFragmentManager(), "DELETE_FROM_PLAYLIST"); + return true; + case R.id.action_go_to_album: + 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()).albumId, albumPairs); + return true; + } + return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(getAdapterPosition()), item); + } + }); + popupMenu.show(); } }); } @Override public void onClick(View v) { - PopupMenu popupMenu = new PopupMenu(activity, v); - popupMenu.inflate(R.menu.menu_item_playlist_song); - popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_delete_from_playlist: - int position = getAdapterPosition(); - PlaylistsUtil.removeFromPlaylist(activity, dataSet.remove(position)); - notifyItemRemoved(position); - return true; - case R.id.action_go_to_album: - 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()).albumId, albumPairs); - return true; - } - return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(getAdapterPosition()), item); - } - }); - popupMenu.show(); + if (isInQuickSelectMode()) { + toggleChecked(getAdapterPosition()); + } else { + //noinspection unchecked + MusicPlayerRemote.openQueue((ArrayList) (List) dataSet, getAdapterPosition(), true); + } + } + + @Override + public boolean onLongClick(View view) { + toggleChecked(getAdapterPosition()); + return true; } } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/SongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/SongAdapter.java index badb0ba9..5da11120 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/SongAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/SongAdapter.java @@ -12,11 +12,16 @@ import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; +import com.afollestad.materialcab.MaterialCab; import com.afollestad.materialdialogs.ThemeSingleton; import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.adapter.AbsMultiSelectAdapter; +import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog; +import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog; import com.kabouzeid.gramophone.helper.MenuItemClickHelper; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.loader.SongLoader; import com.kabouzeid.gramophone.model.DataBaseChangedEvent; import com.kabouzeid.gramophone.model.Song; @@ -32,7 +37,7 @@ import java.util.ArrayList; /** * @author Karim Abou Zeid (kabouzeid) */ -public class SongAdapter extends RecyclerView.Adapter { +public class SongAdapter extends AbsMultiSelectAdapter implements MaterialCab.Callback { public static final String TAG = AlbumSongAdapter.class.getSimpleName(); private static final int SHUFFLE_BUTTON = 0; @@ -41,7 +46,8 @@ public class SongAdapter extends RecyclerView.Adapter { protected final AppCompatActivity activity; protected ArrayList dataSet; - public SongAdapter(AppCompatActivity activity) { + public SongAdapter(AppCompatActivity activity, CabHolder cabHolder) { + super(cabHolder, R.menu.menu_media_selection); this.activity = activity; loadDataSet(); } @@ -77,6 +83,7 @@ public class SongAdapter extends RecyclerView.Adapter { .resetViewBeforeLoading(true) .build() ); + holder.view.setActivated(isChecked(song)); } else { holder.songTitle.setText(activity.getResources().getString(R.string.shuffle_all).toUpperCase()); holder.songTitle.setTextColor(ThemeSingleton.get().positiveColor); @@ -97,7 +104,27 @@ public class SongAdapter extends RecyclerView.Adapter { return dataSet.size() + 1; } - public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + @Override + protected Song getIdentifier(int position) { + return dataSet.get(position - 1); + } + + @Override + protected void onMultipleItemAction(MenuItem menuItem, ArrayList selection) { + switch (menuItem.getItemId()) { + case R.id.action_delete_from_disk: + DeleteSongsDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_SONGS"); + break; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + break; + case R.id.action_add_to_current_playing: + MusicPlayerRemote.enqueue(selection); + break; + } + } + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { final TextView songTitle; final TextView songInfo; final ImageView overflowButton; @@ -115,45 +142,55 @@ public class SongAdapter extends RecyclerView.Adapter { overflowButton = (ImageView) itemView.findViewById(R.id.menu); separator = itemView.findViewById(R.id.separator); short_separator = itemView.findViewById(R.id.short_separator); - - overflowButton.setOnClickListener(this); - itemView.setOnClickListener(new View.OnClickListener() { + view.setOnClickListener(this); + view.setOnLongClickListener(this); + overflowButton.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v) { - if (getItemViewType() == SHUFFLE_BUTTON) { - MusicPlayerRemote.shuffleAllSongs(activity); - } else { - MusicPlayerRemote.openQueue(dataSet, getAdapterPosition() - 1, true); - } + public void onClick(View view) { + PopupMenu popupMenu = new PopupMenu(activity, view); + popupMenu.inflate(R.menu.menu_item_song); + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + final int position = getAdapterPosition() - 1; + switch (item.getItemId()) { + case R.id.action_go_to_album: + 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(position).albumId, albumPairs); + return true; + } + return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(position), item); + } + }); + popupMenu.show(); } }); } @Override public void onClick(View v) { - PopupMenu popupMenu = new PopupMenu(activity, v); - popupMenu.inflate(R.menu.menu_item_song); - popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - final int position = getAdapterPosition() - 1; - switch (item.getItemId()) { - case R.id.action_go_to_album: - 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(position).albumId, albumPairs); - return true; - } - return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(position), item); - } - }); - popupMenu.show(); + if (getItemViewType() == SHUFFLE_BUTTON) { + MusicPlayerRemote.shuffleAllSongs(activity); + } else if (isInQuickSelectMode()) { + toggleChecked(getAdapterPosition()); + } else { + MusicPlayerRemote.openQueue(dataSet, getAdapterPosition() - 1, true); + } + } + + @Override + public boolean onLongClick(View view) { + if (getItemViewType() == SONG) + toggleChecked(getAdapterPosition()); + return true; } } + @Override public void onDetachedFromRecyclerView(RecyclerView recyclerView) { super.onDetachedFromRecyclerView(recyclerView); diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteFromPlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteFromPlaylistDialog.java new file mode 100644 index 00000000..3e0b3c62 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteFromPlaylistDialog.java @@ -0,0 +1,64 @@ +package com.kabouzeid.gramophone.dialogs; + +import android.app.Dialog; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.text.Html; + +import com.afollestad.materialdialogs.MaterialDialog; +import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.model.PlaylistSong; +import com.kabouzeid.gramophone.util.PlaylistsUtil; + +import java.util.ArrayList; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class DeleteFromPlaylistDialog extends DialogFragment { + + public static DeleteFromPlaylistDialog create(PlaylistSong song) { + ArrayList list = new ArrayList<>(); + list.add(song); + return create(list); + } + + public static DeleteFromPlaylistDialog create(ArrayList songs) { + DeleteFromPlaylistDialog dialog = new DeleteFromPlaylistDialog(); + Bundle args = new Bundle(); + args.putSerializable("songs", songs); + dialog.setArguments(args); + return dialog; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + //noinspection unchecked + final ArrayList songs = (ArrayList) getArguments().getSerializable("songs"); + int title; + CharSequence content; + if (songs.size() > 1) { + title = R.string.delete_songs_from_playlist_title; + content = Html.fromHtml(getString(R.string.delete_x_songs_from_playlist, songs.size())); + } else { + title = R.string.delete_song_from_playlist_title; + content = Html.fromHtml(getString(R.string.delete_song_x_from_playlist, songs.get(0).title)); + } + return new MaterialDialog.Builder(getActivity()) + .title(title) + .content(content) + .positiveText(R.string.delete_action) + .negativeText(android.R.string.cancel) + .callback(new MaterialDialog.ButtonCallback() { + @Override + public void onPositive(MaterialDialog dialog) { + super.onPositive(dialog); + if (getActivity() == null) + return; + PlaylistsUtil.removeFromPlaylist(getActivity(), songs); + } + }).build(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java index a448924f..b9db377e 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java @@ -8,17 +8,26 @@ import android.text.Html; import com.afollestad.materialdialogs.MaterialDialog; import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.model.Playlist; import com.kabouzeid.gramophone.util.PlaylistsUtil; +import java.util.ArrayList; + /** - * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) + * @author Karim Abou Zeid (kabouzeid) */ public class DeletePlaylistDialog extends DialogFragment { - public static DeletePlaylistDialog create(long playlistId) { + public static DeletePlaylistDialog create(Playlist playlist) { + ArrayList list = new ArrayList<>(); + list.add(playlist); + return create(list); + } + + public static DeletePlaylistDialog create(ArrayList playlists) { DeletePlaylistDialog dialog = new DeletePlaylistDialog(); Bundle args = new Bundle(); - args.putLong("playlist_id", playlistId); + args.putSerializable("playlists", playlists); dialog.setArguments(args); return dialog; } @@ -26,11 +35,20 @@ public class DeletePlaylistDialog extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - long playlistId = getArguments().getLong("playlist_id"); + //noinspection unchecked + final ArrayList playlists = (ArrayList) getArguments().getSerializable("playlists"); + int title; + CharSequence content; + if (playlists.size() > 1) { + title = R.string.delete_playlists_title; + content = Html.fromHtml(getString(R.string.delete_x_playlists, playlists.size())); + } else { + title = R.string.delete_playlist_title; + content = Html.fromHtml(getString(R.string.delete_playlist_x, playlists.get(0).name)); + } return new MaterialDialog.Builder(getActivity()) - .title(R.string.delete_playlist_title) - .content(Html.fromHtml(getString(R.string.delete_playlist_x, - PlaylistsUtil.getNameForPlaylist(getActivity(), playlistId)))) + .title(title) + .content(content) .positiveText(R.string.delete_action) .negativeText(android.R.string.cancel) .callback(new MaterialDialog.ButtonCallback() { @@ -39,8 +57,7 @@ public class DeletePlaylistDialog extends DialogFragment { super.onPositive(dialog); if (getActivity() == null) return; - long playlistId = getArguments().getLong("playlist_id"); - PlaylistsUtil.deletePlaylist(getActivity(), playlistId); + PlaylistsUtil.deletePlaylists(getActivity(), playlists); } }).build(); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java index 9f5e8619..f27d6ef7 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java @@ -36,7 +36,7 @@ public class DeleteSongsDialog extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { //noinspection unchecked - ArrayList songs = (ArrayList) getArguments().getSerializable("songs"); + final ArrayList songs = (ArrayList) getArguments().getSerializable("songs"); int title; CharSequence content; if (songs.size() > 1) { @@ -57,8 +57,6 @@ public class DeleteSongsDialog extends DialogFragment { super.onPositive(dialog); if (getActivity() == null) return; - //noinspection unchecked - ArrayList songs = (ArrayList) getArguments().getSerializable("songs"); MusicUtil.deleteTracks(getActivity(), songs); } }).build(); diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/MenuItemClickHelper.java b/app/src/main/java/com/kabouzeid/gramophone/helper/MenuItemClickHelper.java index 508a471d..fbf0e9ee 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/helper/MenuItemClickHelper.java +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/MenuItemClickHelper.java @@ -75,7 +75,7 @@ public class MenuItemClickHelper { RenamePlaylistDialog.create(playlist.id).show(activity.getSupportFragmentManager(), "RENAME_PLAYLIST"); return true; case R.id.action_delete_playlist: - DeletePlaylistDialog.create(playlist.id).show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST"); + DeletePlaylistDialog.create(playlist).show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST"); return true; } return false; diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java index fdf19e15..eb506f61 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java @@ -21,6 +21,7 @@ import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.util.InternalStorageUtil; import java.util.ArrayList; +import java.util.List; import java.util.Random; /** @@ -251,6 +252,14 @@ public class MusicPlayerRemote { } } + public static void enqueue(List songs) { + if (musicService != null) { + musicService.addSongs(songs); + final String toast = songs.size() == 1 ? musicService.getResources().getString(R.string.added_title_to_playing_queue) : musicService.getResources().getString(R.string.added_x_titles_to_playing_queue, songs.size()); + Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show(); + } + } + public static void removeFromQueue(Song song) { if (musicService != null) { musicService.removeSong(song); diff --git a/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java b/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java new file mode 100644 index 00000000..cf836d88 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java @@ -0,0 +1,11 @@ +package com.kabouzeid.gramophone.interfaces; + +import com.afollestad.materialcab.MaterialCab; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public interface CabHolder { + + MaterialCab openCab(final int menuRes, final MaterialCab.Callback callback); +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java index b7a13887..24cdfd55 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java @@ -27,9 +27,8 @@ public class AlbumLoader { final int artistId = cursor.getInt(3); final int songCount = cursor.getInt(4); final int year = cursor.getInt(5); - final String albumArtPath = cursor.getString(6); - final Album album = new Album(id, albumName, artist, artistId, songCount, year, albumArtPath); + final Album album = new Album(id, albumName, artist, artistId, songCount, year); albums.add(album); } while (cursor.moveToNext()); } @@ -58,8 +57,6 @@ public class AlbumLoader { MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS, /* 5 */ MediaStore.Audio.AlbumColumns.FIRST_YEAR, - /* 6 */ - MediaStore.Audio.AlbumColumns.ALBUM_ART }, selection, values, PreferenceUtils.getInstance(context).getAlbumSortOrder()); } @@ -73,9 +70,8 @@ public class AlbumLoader { final int artistId = cursor.getInt(3); final int songCount = cursor.getInt(4); final int year = cursor.getInt(5); - final String albumArtPath = cursor.getString(6); - album = new Album(id, albumName, artist, artistId, songCount, year, albumArtPath); + album = new Album(id, albumName, artist, artistId, songCount, year); } if (cursor != null) { @@ -95,9 +91,8 @@ public class AlbumLoader { final int artistId = cursor.getInt(3); final int songCount = cursor.getInt(4); final int year = cursor.getInt(5); - final String albumArtPath = cursor.getString(6); - final Album album = new Album(id, albumName, artist, artistId, songCount, year, albumArtPath); + final Album album = new Album(id, albumName, artist, artistId, songCount, year); albums.add(album); } while (cursor.moveToNext()); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumSongLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumSongLoader.java index a931616c..df5d1d11 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumSongLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumSongLoader.java @@ -27,9 +27,8 @@ public class AlbumSongLoader { final long duration = cursor.getLong(4); final int trackNumber = cursor.getInt(5); final int artistId = cursor.getInt(6); - final long dateModified = cursor.getInt(7); - final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified); + final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber); songs.add(song); } while (cursor.moveToNext()); } @@ -54,9 +53,7 @@ public class AlbumSongLoader { /* 5 */ MediaStore.Audio.AudioColumns.TRACK, /* 6 */ - MediaStore.Audio.AudioColumns.ARTIST_ID, - /* 7 */ - MediaStore.Audio.AudioColumns.DATE_MODIFIED + MediaStore.Audio.AudioColumns.ARTIST_ID }, (MediaStore.Audio.AudioColumns.IS_MUSIC + "=1") + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''" + " AND " + MediaStore.Audio.AudioColumns.ALBUM_ID + "=" + albumId, null, diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistAlbumLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistAlbumLoader.java index eaa82d0d..4e3a8930 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistAlbumLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistAlbumLoader.java @@ -9,16 +9,15 @@ import com.kabouzeid.gramophone.model.Album; import com.kabouzeid.gramophone.util.PreferenceUtils; import java.util.ArrayList; -import java.util.List; /** * @author Karim Abou Zeid (kabouzeid) */ public class ArtistAlbumLoader { - public static List getArtistAlbumList(final Context context, final int artistId) { + public static ArrayList getArtistAlbumList(final Context context, final int artistId) { Cursor cursor = makeArtistAlbumCursor(context, artistId); - List albums = new ArrayList<>(); + ArrayList albums = new ArrayList<>(); if (cursor != null && cursor.moveToFirst()) { do { final int id = cursor.getInt(0); @@ -26,9 +25,8 @@ public class ArtistAlbumLoader { final String artist = cursor.getString(2); final int songCount = cursor.getInt(3); final int year = cursor.getInt(4); - final String albumArtPath = cursor.getString(5); - final Album album = new Album(id, albumName, artist, artistId, songCount, year, albumArtPath); + final Album album = new Album(id, albumName, artist, artistId, songCount, year); albums.add(album); } while (cursor.moveToNext()); } @@ -51,8 +49,6 @@ public class ArtistAlbumLoader { MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS, /* 4 */ MediaStore.Audio.AlbumColumns.FIRST_YEAR, - /* 5 */ - MediaStore.Audio.AlbumColumns.ALBUM_ART }, null, null, PreferenceUtils.getInstance(context).getArtistAlbumSortOrder()); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistSongLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistSongLoader.java index 3d84ef23..2a68191c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistSongLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistSongLoader.java @@ -27,9 +27,8 @@ public class ArtistSongLoader { final long duration = cursor.getLong(4); final int trackNumber = cursor.getInt(5); final int albumId = cursor.getInt(6); - final long dateModified = cursor.getInt(7); - final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified); + final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber); songs.add(song); } while (cursor.moveToNext()); } @@ -54,9 +53,7 @@ public class ArtistSongLoader { /* 5 */ MediaStore.Audio.AudioColumns.TRACK, /* 6 */ - MediaStore.Audio.AudioColumns.ALBUM_ID, - /* 7 */ - MediaStore.Audio.AudioColumns.DATE_MODIFIED + MediaStore.Audio.AudioColumns.ALBUM_ID }, (MediaStore.Audio.AudioColumns.IS_MUSIC + "=1") + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''" + " AND " + MediaStore.Audio.AudioColumns.ARTIST_ID + "=" + artistId, null, diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/PlaylistSongLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/PlaylistSongLoader.java index 619daf1e..5b201d99 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/PlaylistSongLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/PlaylistSongLoader.java @@ -26,9 +26,8 @@ public class PlaylistSongLoader { final int albumId = cursor.getInt(6); final int artistId = cursor.getInt(7); final int idInPlaylist = cursor.getInt(8); - final long dateModified = cursor.getInt(9); - final PlaylistSong song = new PlaylistSong(id, albumId, artistId, songName, artist, album, duration, trackNumber, playlistID, idInPlaylist, dateModified); + final PlaylistSong song = new PlaylistSong(id, albumId, artistId, songName, artist, album, duration, trackNumber, playlistID, idInPlaylist); songs.add(song); } while (cursor.moveToNext()); @@ -60,9 +59,7 @@ public class PlaylistSongLoader { /* 7 */ AudioColumns.ARTIST_ID, /* 8 */ - MediaStore.Audio.Playlists.Members._ID, - /* 9 */ - MediaStore.Audio.AudioColumns.DATE_MODIFIED + MediaStore.Audio.Playlists.Members._ID }, (AudioColumns.IS_MUSIC + "=1") + " AND " + AudioColumns.TITLE + " != ''", null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/SongLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/SongLoader.java index 9c7e00b5..0bc8607c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/SongLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/SongLoader.java @@ -30,9 +30,8 @@ public class SongLoader { final int trackNumber = cursor.getInt(5); final int artistId = cursor.getInt(6); final int albumId = cursor.getInt(7); - final long dateModified = cursor.getInt(8); - final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified); + final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber); songs.add(song); } while (cursor.moveToNext()); } @@ -68,9 +67,7 @@ public class SongLoader { /* 6 */ MediaStore.Audio.AudioColumns.ARTIST_ID, /* 7 */ - MediaStore.Audio.AudioColumns.ALBUM_ID, - /* 8 */ - MediaStore.Audio.AudioColumns.DATE_MODIFIED + MediaStore.Audio.AudioColumns.ALBUM_ID }, finalSelection, values, PreferenceUtils.getInstance(context).getSongSortOrder()); } @@ -87,9 +84,8 @@ public class SongLoader { final int trackNumber = cursor.getInt(5); final int artistId = cursor.getInt(6); final int albumId = cursor.getInt(7); - final long dateModified = cursor.getInt(8); - final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified); + final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber); songs.add(song); } while (cursor.moveToNext()); } @@ -111,8 +107,7 @@ public class SongLoader { final int trackNumber = cursor.getInt(5); final int artistId = cursor.getInt(6); final int albumId = cursor.getInt(7); - final long dateModified = cursor.getInt(8); - song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified); + song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber); } if (cursor != null) { cursor.close(); diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/Album.java b/app/src/main/java/com/kabouzeid/gramophone/model/Album.java index b674c284..5ebf3844 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/Album.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/Album.java @@ -1,5 +1,7 @@ package com.kabouzeid.gramophone.model; +import android.text.TextUtils; + /** * @author Karim Abou Zeid (kabouzeid) */ @@ -11,17 +13,15 @@ public class Album { public final String artistName; public final int songCount; public final int year; - public final String albumArtPath; //used as cache key public Album(final int id, final String title, final String artistName, final int artistId, - final int songNumber, final int albumYear, final String albumArtPath) { + final int songNumber, final int albumYear) { this.id = id; this.title = title; this.artistName = artistName; this.artistId = artistId; songCount = songNumber; year = albumYear; - this.albumArtPath = albumArtPath != null ? albumArtPath : ""; } public Album() { @@ -31,6 +31,49 @@ public class Album { this.artistId = -1; songCount = -1; year = -1; - this.albumArtPath = ""; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + id; + result = prime * result + (title == null ? 0 : title.hashCode()); + result = prime * result + (artistName == null ? 0 : artistName.hashCode()); + result = prime * result + songCount; + result = prime * result + year; + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Album other = (Album) obj; + if (id != other.id) { + return false; + } + if (!TextUtils.equals(title, other.title)) { + return false; + } + if (!TextUtils.equals(artistName, other.artistName)) { + return false; + } + if (songCount != other.songCount) { + return false; + } + return year == other.year; + } + + @Override + public String toString() { + return title; } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/Artist.java b/app/src/main/java/com/kabouzeid/gramophone/model/Artist.java index 48911ec6..51a1eba7 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/Artist.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/Artist.java @@ -1,5 +1,7 @@ package com.kabouzeid.gramophone.model; +import android.text.TextUtils; + /** * @author Karim Abou Zeid (kabouzeid) */ @@ -22,4 +24,44 @@ public class Artist { songCount = -1; albumCount = -1; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + albumCount; + result = prime * result + id; + result = prime * result + (name == null ? 0 : name.hashCode()); + result = prime * result + songCount; + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Artist other = (Artist) obj; + if (albumCount != other.albumCount) { + return false; + } + if (id != other.id) { + return false; + } + if (!TextUtils.equals(name, other.name)) { + return false; + } + return songCount == other.songCount; + } + + @Override + public String toString() { + return name; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/Playlist.java b/app/src/main/java/com/kabouzeid/gramophone/model/Playlist.java index 8905c4cf..dedc8b2f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/Playlist.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/Playlist.java @@ -1,6 +1,16 @@ package com.kabouzeid.gramophone.model; -public class Playlist { +import android.text.TextUtils; + +import java.io.Serializable; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class Playlist implements Serializable { + + private static final long serialVersionUID = 3013703495354856981L; + public final int id; public final String name; @@ -13,4 +23,36 @@ public class Playlist { this.id = -1; this.name = ""; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + id; + result = prime * result + (name == null ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Playlist other = (Playlist) obj; + if (id != other.id) { + return false; + } + return TextUtils.equals(name, other.name); + } + + @Override + public String toString() { + return name; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/PlaylistSong.java b/app/src/main/java/com/kabouzeid/gramophone/model/PlaylistSong.java index e746a877..8de0beba 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/PlaylistSong.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/PlaylistSong.java @@ -8,8 +8,8 @@ public class PlaylistSong extends Song { public final int idInPlayList; public PlaylistSong(final int id, final int albumId, final int artistId, final String title, final String artistName, - final String albumName, final long duration, final int trackNumber, final int playlistId, final int idInPlayList, final long dateModified) { - super(id, albumId, artistId, title, artistName, albumName, duration, trackNumber, dateModified); + final String albumName, final long duration, final int trackNumber, final int playlistId, final int idInPlayList) { + super(id, albumId, artistId, title, artistName, albumName, duration, trackNumber); this.playlistId = playlistId; this.idInPlayList = idInPlayList; } @@ -19,4 +19,22 @@ public class PlaylistSong extends Song { playlistId = -1; idInPlayList = -1; } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + playlistId; + result = prime * result + idInPlayList; + return result; + } + + @Override + public boolean equals(final Object obj) { + if (super.equals(obj)) { + final PlaylistSong other = (PlaylistSong) obj; + return playlistId == other.playlistId && idInPlayList == other.idInPlayList; + } + return false; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/Song.java b/app/src/main/java/com/kabouzeid/gramophone/model/Song.java index 4497f70b..4543586d 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/Song.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/Song.java @@ -1,5 +1,7 @@ package com.kabouzeid.gramophone.model; +import android.text.TextUtils; + import java.io.Serializable; /** @@ -17,10 +19,9 @@ public class Song implements Serializable { public final String albumName; public final long duration; public final int trackNumber; - public final long dateModified; //used as cache key public Song(final int id, final int albumId, final int artistId, final String title, final String artistName, - final String albumName, final long duration, final int trackNumber, final long dateModified) { + final String albumName, final long duration, final int trackNumber) { this.id = id; this.albumId = albumId; this.artistId = artistId; @@ -29,7 +30,6 @@ public class Song implements Serializable { this.albumName = albumName; this.duration = duration; this.trackNumber = trackNumber; - this.dateModified = dateModified; } public Song() { @@ -41,6 +41,49 @@ public class Song implements Serializable { this.albumName = ""; this.duration = -1; this.trackNumber = -1; - this.dateModified = -1; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (albumName == null ? 0 : albumName.hashCode()); + result = prime * result + (artistName == null ? 0 : artistName.hashCode()); + result = prime * result + (int) duration; + result = prime * result + id; + result = prime * result + (title == null ? 0 : title.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Song other = (Song) obj; + if (id != other.id) { + return false; + } + if (!TextUtils.equals(albumName, other.albumName)) { + return false; + } + if (!TextUtils.equals(artistName, other.artistName)) { + return false; + } + if (duration != other.duration) { + return false; + } + return TextUtils.equals(title, other.title); + } + + @Override + public String toString() { + return title; } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java b/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java index dbabf5e7..53c92f6a 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java +++ b/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java @@ -42,6 +42,7 @@ import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListene import java.io.IOException; import java.util.ArrayList; +import java.util.List; public class MusicService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, AudioManager.OnAudioFocusChangeListener { public static final String ACTION_TOGGLE_PLAYBACK = "com.kabouzeid.gramophone.action.TOGGLE_PLAYBACK"; @@ -552,6 +553,18 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe saveState(); } + public void addSongs(int position, List songs) { + playingQueue.addAll(position, songs); + originalPlayingQueue.addAll(position, songs); + saveState(); + } + + public void addSongs(List songs) { + playingQueue.addAll(songs); + originalPlayingQueue.addAll(songs); + saveState(); + } + public void removeSong(int position) { if (getShuffleMode() == SHUFFLE_MODE_NONE) { playingQueue.remove(position); diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java index 1f5ea6eb..e8cba8e0 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java @@ -16,18 +16,21 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.materialcab.MaterialCab; import com.afollestad.materialdialogs.util.DialogUtils; import com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView; import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.adapter.songadapter.AlbumSongAdapter; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.interfaces.PaletteColorHolder; import com.kabouzeid.gramophone.loader.AlbumLoader; import com.kabouzeid.gramophone.loader.AlbumSongLoader; import com.kabouzeid.gramophone.misc.AppKeys; import com.kabouzeid.gramophone.misc.SmallObservableScrollViewCallbacks; import com.kabouzeid.gramophone.model.Album; +import com.kabouzeid.gramophone.model.DataBaseChangedEvent; import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent; import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity; @@ -51,22 +54,26 @@ import java.util.ArrayList; *

* Should be kinda stable ONLY AS IT IS!!! */ -public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorHolder { +public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorHolder, CabHolder { public static final String TAG = AlbumDetailActivity.class.getSimpleName(); private static final int TAG_EDITOR_REQUEST = 2001; private Album album; private ObservableRecyclerView recyclerView; + private AlbumSongAdapter adapter; + private ArrayList songs; private View statusBar; private ImageView albumArtImageView; private View songsBackgroundView; private TextView albumTitleView; private Toolbar toolbar; + private MaterialCab cab; private int headerOffset; private int titleViewHeight; private int albumArtViewHeight; private int toolbarColor; + private float toolbarAlpha; private int bottomOffset; private final SmallObservableScrollViewCallbacks observableScrollViewCallbacks = new SmallObservableScrollViewCallbacks() { @@ -83,9 +90,9 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH ViewHelper.setTranslationY(songsBackgroundView, Math.max(0, -scrollY + albumArtViewHeight)); // 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 = albumArtViewHeight; @@ -277,10 +284,10 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH } private void setUpSongsAdapter() { - final ArrayList songs = AlbumSongLoader.getAlbumSongList(this, album.id); - final AlbumSongAdapter albumSongAdapter = new AlbumSongAdapter(this, songs); + songs = AlbumSongLoader.getAlbumSongList(this, album.id); + adapter = new AlbumSongAdapter(this, songs, this); recyclerView.setLayoutManager(new GridLayoutManager(this, 1)); - recyclerView.setAdapter(albumSongAdapter); + recyclerView.setAdapter(adapter); } @Override @@ -344,6 +351,19 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH } } + @Subscribe + public void onDataBaseEvent(DataBaseChangedEvent event) { + switch (event.getAction()) { + case DataBaseChangedEvent.SONGS_CHANGED: + case DataBaseChangedEvent.ALBUMS_CHANGED: + case DataBaseChangedEvent.DATABASE_CHANGED: + songs = AlbumSongLoader.getAlbumSongList(this, album.id); + adapter.updateDataSet(songs); + if (songs.size() < 1) finish(); + break; + } + } + @Subscribe public void onUIPreferenceChanged(UIPreferenceChangedEvent event) { switch (event.getAction()) { @@ -358,4 +378,31 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH 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/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java index f8c1a3df..24e0bd45 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; @@ -40,6 +41,7 @@ import com.kabouzeid.gramophone.misc.AppKeys; import com.kabouzeid.gramophone.misc.SmallObservableScrollViewCallbacks; import com.kabouzeid.gramophone.model.Album; import com.kabouzeid.gramophone.model.Artist; +import com.kabouzeid.gramophone.model.DataBaseChangedEvent; import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent; import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity; @@ -55,14 +57,13 @@ import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListene import com.squareup.otto.Subscribe; import java.util.ArrayList; -import java.util.List; /** * A lot of hackery is done in this activity. Changing things may will brake the whole activity. *

* 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,16 +74,21 @@ 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; private RecyclerView albumRecyclerView; private Spanned biography; private ArtistAlbumAdapter albumAdapter; + private ArtistSongAdapter songAdapter; + private ArrayList songs; + private ArrayList albums; private final SmallObservableScrollViewCallbacks observableScrollViewCallbacks = new SmallObservableScrollViewCallbacks() { @Override @@ -98,9 +104,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; @@ -208,8 +214,8 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor songListView.setPadding(0, artistImageViewHeight + titleViewHeight, 0, bottomOffset); songListView.addHeaderView(songListHeader); - final ArrayList songs = ArtistSongLoader.getArtistSongList(this, artist.id); - ArtistSongAdapter songAdapter = new ArtistSongAdapter(this, songs); + songs = ArtistSongLoader.getArtistSongList(this, artist.id); + songAdapter = new ArtistSongAdapter(this, songs, this); songListView.setAdapter(songAdapter); final View contentView = getWindow().getDecorView().findViewById(android.R.id.content); @@ -220,23 +226,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); + albums = ArtistAlbumLoader.getArtistAlbumList(this, artist.id); + albumAdapter = new ArtistAlbumAdapter(this, albums, this); albumRecyclerView.setAdapter(albumAdapter); } @@ -439,6 +434,22 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor }); } + @Subscribe + public void onDataBaseEvent(DataBaseChangedEvent event) { + switch (event.getAction()) { + case DataBaseChangedEvent.SONGS_CHANGED: + case DataBaseChangedEvent.ALBUMS_CHANGED: + case DataBaseChangedEvent.ARTISTS_CHANGED: + case DataBaseChangedEvent.DATABASE_CHANGED: + songs = ArtistSongLoader.getArtistSongList(this, artist.id); + songAdapter.updateDataSet(songs); + albums = ArtistAlbumLoader.getArtistAlbumList(this, artist.id); + albumAdapter.updateDataSet(albums); + if (songs.size() < 1) finish(); + break; + } + } + @Subscribe public void onUIPreferenceChanged(UIPreferenceChangedEvent event) { switch (event.getAction()) { @@ -453,4 +464,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/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java index 1de1e71e..655c0750 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java @@ -25,6 +25,7 @@ import android.view.MenuItem; import android.view.SubMenu; import android.widget.FrameLayout; +import com.afollestad.materialcab.MaterialCab; import com.afollestad.materialdialogs.ThemeSingleton; import com.astuetz.PagerSlidingTabStrip; import com.kabouzeid.gramophone.R; @@ -32,6 +33,7 @@ import com.kabouzeid.gramophone.adapter.PagerAdapter; import com.kabouzeid.gramophone.dialogs.AboutDialog; import com.kabouzeid.gramophone.dialogs.CreatePlaylistDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.interfaces.KabViewsDisableAble; import com.kabouzeid.gramophone.loader.AlbumSongLoader; import com.kabouzeid.gramophone.loader.ArtistSongLoader; @@ -57,7 +59,7 @@ import java.util.List; import java.util.Set; public class MainActivity extends AbsFabActivity - implements NavigationDrawerFragment.NavigationDrawerCallbacks, KabViewsDisableAble { + implements NavigationDrawerFragment.NavigationDrawerCallbacks, KabViewsDisableAble, CabHolder { public static final String TAG = MainActivity.class.getSimpleName(); @@ -69,6 +71,7 @@ public class MainActivity extends AbsFabActivity private ViewPager viewPager; private PagerSlidingTabStrip slidingTabLayout; private int currentPage = -1; + private MaterialCab cab; @Override protected void onCreate(Bundle savedInstanceState) { @@ -553,4 +556,14 @@ public class MainActivity extends AbsFabActivity }); return super.onMenuOpened(featureId, menu); } + + @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) + .setBackgroundColor(PreferenceUtils.getInstance(this).getThemeColorPrimary()) + .start(callback); + return cab; + } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java index 7eacb053..bc54df02 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java @@ -10,12 +10,16 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; +import com.afollestad.materialcab.MaterialCab; +import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.adapter.songadapter.PlaylistSongAdapter; +import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.loader.PlaylistLoader; import com.kabouzeid.gramophone.loader.PlaylistSongLoader; import com.kabouzeid.gramophone.misc.AppKeys; import com.kabouzeid.gramophone.misc.DragSortRecycler; +import com.kabouzeid.gramophone.model.DataBaseChangedEvent; import com.kabouzeid.gramophone.model.Playlist; import com.kabouzeid.gramophone.model.PlaylistSong; import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity; @@ -23,13 +27,17 @@ import com.kabouzeid.gramophone.util.NavigationUtil; import com.kabouzeid.gramophone.util.PlaylistsUtil; import com.kabouzeid.gramophone.util.PreferenceUtils; import com.kabouzeid.gramophone.util.Util; +import com.squareup.otto.Subscribe; import java.util.ArrayList; -public class PlaylistDetailActivity extends AbsFabActivity { +public class PlaylistDetailActivity extends AbsFabActivity implements CabHolder { public static final String TAG = PlaylistDetailActivity.class.getSimpleName(); private Playlist playlist; + private MaterialCab cab; + private PlaylistSongAdapter adapter; + private ArrayList songs; @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override @@ -41,8 +49,8 @@ public class PlaylistDetailActivity extends AbsFabActivity { getIntentExtras(); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); - final ArrayList songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id); - final PlaylistSongAdapter adapter = new PlaylistSongAdapter(this, songs); + songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id); + adapter = new PlaylistSongAdapter(this, songs, this); recyclerView.setLayoutManager(new GridLayoutManager(this, 1)); recyclerView.setAdapter(adapter); @@ -72,6 +80,8 @@ public class PlaylistDetailActivity extends AbsFabActivity { setSupportActionBar(toolbar); getSupportActionBar().setTitle(playlist.name); getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + App.bus.register(this); } @Override @@ -123,4 +133,34 @@ public class PlaylistDetailActivity extends AbsFabActivity { } return super.onOptionsItemSelected(item); } + + @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) + .setBackgroundColor(PreferenceUtils.getInstance(this).getThemeColorPrimary()) + .start(callback); + return cab; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + App.bus.unregister(this); + } + + @Subscribe + public void onDataBaseEvent(DataBaseChangedEvent event) { + switch (event.getAction()) { + case DataBaseChangedEvent.PLAYLISTS_CHANGED: + case DataBaseChangedEvent.DATABASE_CHANGED: + songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id); + adapter.updateDataSet(songs); + findViewById(android.R.id.empty).setVisibility( + songs.size() == 0 ? View.VISIBLE : View.GONE + ); + break; + } + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AbsMainActivityFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AbsMainActivityFragment.java index 271f8452..0739b3b3 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AbsMainActivityFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AbsMainActivityFragment.java @@ -5,6 +5,7 @@ import android.support.v4.app.Fragment; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.interfaces.KabViewsDisableAble; +import com.kabouzeid.gramophone.ui.activities.MainActivity; import com.kabouzeid.gramophone.util.Util; /** @@ -29,6 +30,10 @@ public abstract class AbsMainActivityFragment extends Fragment implements KabVie return getResources().getDimensionPixelSize(R.dimen.bottom_offset_fab_activity); } + protected MainActivity getMainActivity() { + return (MainActivity) getActivity(); + } + @Override public void enableViews() { areViewsEnabled = true; diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AlbumViewFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AlbumViewFragment.java index 69cdb518..bbe38327 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AlbumViewFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AlbumViewFragment.java @@ -30,7 +30,7 @@ public class AlbumViewFragment extends AbsMainActivityRecyclerViewFragment { @Override protected RecyclerView.Adapter createAdapter() { - return new AlbumAdapter(getActivity()); + return new AlbumAdapter(getMainActivity(), getMainActivity()); } public void setColumns(int columns) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/ArtistViewFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/ArtistViewFragment.java index 0c7f0cd4..8f03f74c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/ArtistViewFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/ArtistViewFragment.java @@ -22,6 +22,6 @@ public class ArtistViewFragment extends AbsMainActivityRecyclerViewFragment { @Override protected RecyclerView.Adapter createAdapter() { - return new ArtistAdapter(getActivity()); + return new ArtistAdapter(getMainActivity(), getMainActivity()); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/PlaylistViewFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/PlaylistViewFragment.java index 78230653..8cc0bbfc 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/PlaylistViewFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/PlaylistViewFragment.java @@ -2,7 +2,6 @@ package com.kabouzeid.gramophone.ui.fragments.mainactivityfragments; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -41,7 +40,7 @@ public class PlaylistViewFragment extends AbsMainActivityRecyclerViewFragment { @Override protected RecyclerView.Adapter createAdapter() { - PlaylistAdapter adapter = new PlaylistAdapter((AppCompatActivity) getActivity()); + PlaylistAdapter adapter = new PlaylistAdapter(getMainActivity(), getMainActivity()); View v = getView(); if (v != null) { v.findViewById(android.R.id.empty).setVisibility( diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/SongViewFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/SongViewFragment.java index 1697b487..15a96ed8 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/SongViewFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/SongViewFragment.java @@ -1,6 +1,5 @@ package com.kabouzeid.gramophone.ui.fragments.mainactivityfragments; -import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; @@ -26,6 +25,6 @@ public class SongViewFragment extends AbsMainActivityRecyclerViewFragment { @Override protected RecyclerView.Adapter createAdapter() { - return new SongAdapter((AppCompatActivity) getActivity()); + return new SongAdapter(getMainActivity(), getMainActivity()); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/PlaylistsUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/PlaylistsUtil.java index 8ed31d68..0a2be896 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/PlaylistsUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/PlaylistsUtil.java @@ -12,9 +12,11 @@ import android.widget.Toast; import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.model.DataBaseChangedEvent; +import com.kabouzeid.gramophone.model.Playlist; import com.kabouzeid.gramophone.model.PlaylistSong; import com.kabouzeid.gramophone.model.Song; +import java.util.ArrayList; import java.util.List; /** @@ -59,13 +61,26 @@ public class PlaylistsUtil { // context.getContentResolver().delete(uri, null, null); // } - public static void deletePlaylist(final Context context, final long playlistId) { + public static void deletePlaylists(final Context context, final long playlistId) { final Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI; String where = MediaStore.Audio.Playlists._ID + "=?"; String[] whereVal = {String.valueOf(playlistId)}; context.getContentResolver().delete(uri, where, whereVal); - Toast.makeText(context, context.getResources().getString(R.string.deleted_playlist_x, - getNameForPlaylist(context, playlistId)), Toast.LENGTH_SHORT).show(); + App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED)); + } + + public static void deletePlaylists(final Context context, final ArrayList playlists) { + final Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI; + final StringBuilder selection = new StringBuilder(); + selection.append(MediaStore.Audio.Playlists._ID + " IN ("); + for (int i = 0; i < playlists.size(); i++) { + selection.append(playlists.get(i).id); + if (i < playlists.size() - 1) { + selection.append(","); + } + } + selection.append(")"); + context.getContentResolver().delete(uri, selection.toString(), null); App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED)); } @@ -131,20 +146,20 @@ public class PlaylistsUtil { App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED)); } -// public static void removeFromPlaylist(final Context context, final List songs) { -// Uri uri = MediaStore.Audio.Playlists.Members.getContentUri( -// "external", songs.get(0).playlistId); -// String selectionArgs[] = new String[songs.size()]; -// for (int i = 0; i < selectionArgs.length; i++) { -// selectionArgs[i] = String.valueOf(songs.get(i).idInPlayList); -// } -// String selection = MediaStore.Audio.Playlists.Members._ID + " in ("; -// for (String selectionArg : selectionArgs) selection += "?, "; -// selection = selection.substring(0, selection.length() - 2) + ")"; -// -// context.getContentResolver().delete(uri, selection, selectionArgs); -// App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED)); -// } + public static void removeFromPlaylist(final Context context, final List songs) { + Uri uri = MediaStore.Audio.Playlists.Members.getContentUri( + "external", songs.get(0).playlistId); + String selectionArgs[] = new String[songs.size()]; + for (int i = 0; i < selectionArgs.length; i++) { + selectionArgs[i] = String.valueOf(songs.get(i).idInPlayList); + } + String selection = MediaStore.Audio.Playlists.Members._ID + " in ("; + for (String selectionArg : selectionArgs) selection += "?, "; + selection = selection.substring(0, selection.length() - 2) + ")"; + + context.getContentResolver().delete(uri, selection, selectionArgs); + App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED)); + } // // public static int getSongCountForPlaylist(final Context context, final long playlistId) { // Cursor c = context.getContentResolver().query( diff --git a/app/src/main/res/drawable-hdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..5e89821e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..e466600a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..7efdfab6 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..8d48b838 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..a86bc505 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..1aeb991a Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..3c9e1718 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..aa874a65 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..6ab40bc4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..5d2e8ea3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..82e0ee1f Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..844e8c4e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_check_white_96dp.png b/app/src/main/res/drawable-xxxhdpi/ic_check_white_96dp.png new file mode 100644 index 00000000..5dba3bb8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_check_white_96dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..e7b2514d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..ae4cdc5b Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..cffe4fa8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/layout/activity_album_detail.xml b/app/src/main/res/layout/activity_album_detail.xml index 27cbc717..a8fd61c7 100644 --- a/app/src/main/res/layout/activity_album_detail.xml +++ b/app/src/main/res/layout/activity_album_detail.xml @@ -67,10 +67,21 @@ android:layout_height="@dimen/statusMargin" android:background="@android:color/transparent" /> - + + + + + + + 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/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4386dc78..d47aac85 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -20,15 +20,22 @@ android:fitsSystemWindows="true" /> + android:paddingTop="@dimen/main_toolbar_padding_top" + tools:ignore="UnusedAttribute"> - + + + + + + - + + + + + + + + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="1dp"> - - - + android:layout_height="wrap_content" + android:foreground="?rect_selector"> + tools:ignore="UnusedAttribute,UselessParent"> - + - + + + + + + + + - + + + 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" /> diff --git a/app/src/main/res/layout/item_list_song.xml b/app/src/main/res/layout/item_list_song.xml index cafd0910..07a64767 100644 --- a/app/src/main/res/layout/item_list_song.xml +++ b/app/src/main/res/layout/item_list_song.xml @@ -1,8 +1,8 @@ + android:paddingRight="16dp"> diff --git a/app/src/main/res/menu/menu_media_selection.xml b/app/src/main/res/menu/menu_media_selection.xml new file mode 100644 index 00000000..f2a8ead2 --- /dev/null +++ b/app/src/main/res/menu/menu_media_selection.xml @@ -0,0 +1,23 @@ + +

+ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_playlists_selection.xml b/app/src/main/res/menu/menu_playlists_selection.xml new file mode 100644 index 00000000..2ab37d2d --- /dev/null +++ b/app/src/main/res/menu/menu_playlists_selection.xml @@ -0,0 +1,23 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_playlists_songs_selection.xml b/app/src/main/res/menu/menu_playlists_songs_selection.xml new file mode 100644 index 00000000..4e1677d1 --- /dev/null +++ b/app/src/main/res/menu/menu_playlists_songs_selection.xml @@ -0,0 +1,23 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 2b049b81..a37fbebe 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -1,16 +1,17 @@ "الإعدادات" - عنى - يتم التشغيل حالياً - قائمة الانتظار + " عن التطبيق +" + الإستماع الآن + قائمة الإنتظار بحث استمع لاحقاً - أضف إلى قائمة الانتظار + أضف إلى قائمة الإنتظار أزل من قائمة الانتظار أضف إلى قائمة تشغيل... - تعديل معلومات الموسيقى - حذف + تعديل معلومات الملف + حذف نهائي التفاصيل الألبومات الفنانون @@ -27,30 +28,29 @@ النوع فنان الألبوم السنة - الموسيقى + "المقطع " "الموسيقى (٢ للموسيقى ٢ أو ٣٠٠٤ للموسيقى ٤)" حقل نص اسم الألبوم أو اسم الفنان فارغ تتم كتابة الملف يتم حفظ التغييرات... التفاصيل - اسم الملف + إسم الملف مسار الملف الحجم - التنسيق + نوع الملف الطول معدل البت معدل أخذ العينات - اذهب إلى الفنان - اذهب إلى الألبوم - قائمة الانتظار + إذهب إلى الفنان + إذهب إلى الألبوم + قائمة الإنتظار حفظ كقائمة تشغيل - الأيقونة من - "مشغل الموسيقى فونقراف هو برنامج مجاني بشكلٍ كامل بتصميم أنيق من " + الأيقونة من تصميم + "مشغل الموسيقى فونقراف هو برنامج مجاني بشكلٍ كامل بتصميم أنيق من تصميم" بحث لا توجد نتائج تحديث صورة الفنان يتم التحديث... - "تمت الإضافة إلى قائمة الانتظار" حذف من قائمة التشغيل قائمة تشغيل جديدة... عدد قوائم الشبكة @@ -71,14 +71,14 @@ حذف قائمة التشغيل "إضافة إلى قائمة التشغيل" قائمة تشغيل جديدة - "تحذير: لا يمكن التراجع هذه العملية." + "تحذير: لا يمكن التراجع عن هذه العملية." عشوائي آخر ما تم فتحه فاتح داكن المعادل واجهة المستخدم - السمة الأساسية + الثيم العام الصوت عام في أي مشهد يتم تلوين شريط التنقل @@ -93,4 +93,35 @@ مشهد قائمة التشغيل تعديل معلومات الموسيقى في أي مكان + الهوامش السفلية للألبومات ملونة + لا يوجد معدل صوت + "لا يوجد audio id, شغل شيئا وحاول مرة أخرى." + إفتح قائمة التصفح الجانبية + "إغلاق قائمة التصفح الجانبية" + حذف + إعادة التسمية + إختيار + إفتراضي + اللون الأساسي + اللون الثانوي + تحديد الأزرق النيلي كلون ثيم اساسي. + تحديد الوردي كلون ثانوي. + تحديث الصورة + قائمة التشغيل فارغة + لا توجد قوائم تشغيل + إسم قائمة الشغيل + الأغنية + "متوفر في نظام التشغيل Lollipop." + جعل المحتوى الذي يمر تحت شريط الأدوات مرئيا. + "تلوين الهوامش السفلية للألبومات بلون غلاف الألبوم." + "تعذر تحميل صور هذا الألبوم." + البحث في المكتبة... + إعادة تفحص الملفات... + + تحميل من last.fm + اختيار من ذاكرة التخزين الداخلية + بحث في الإنترنات + حذف الغلاف + + "تمت الإضافة إلى قائمة الانتظار" diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 4649c68c..375c33a0 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -50,7 +50,6 @@ Žádné výsledky Změnit obrázek umělce Aktualizace... - "Přidána 1 skladba do fronty." Vymazat z playlistu Nový playlist... Počet sloupců mřížky @@ -120,4 +119,5 @@ Najít na webu Odstranit obal alba + "Přidána 1 skladba do fronty." diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3f40a4ea..25dd5d07 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -50,7 +50,7 @@ Keine Ergebnisse Interpretenbild aktualisieren Aktualisiere... - "1 Titel wurde der Wiedergabeliste hinzugefügt." + %1$d Titel wurden der Wiedergabeliste hinzugefügt. Aus Playlist entfernen Neue Playlist… Rastergröße @@ -120,4 +120,5 @@ Web suche Cover entfernen + "1 Titel wurde der Wiedergabeliste hinzugefügt." diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index fd24d489..1c20b3bd 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -50,7 +50,6 @@ Κανένα αποτέλεσμα Ανανέωση εικόνας καλλιτέχνη Γίνεται ανανέωση... - "Προστέθηκε ένας τίτλος στη σειρά αναπαραγωγής" Διαγραφή από τη λίστα αναπαραγωγής Νέα λίστα αναπαραγωγής... Στήλες πλέγματος @@ -120,4 +119,5 @@ Αναζήτηση στο διαδίκτυο Διαγραφή εξώφυλλου + "Προστέθηκε ένας τίτλος στη σειρά αναπαραγωγής" diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 27773a0a..da0b4500 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -50,7 +50,6 @@ Sin resultados Actualizar imagen del artista Actualizando... - "1 título añadido a la cola de reproducción" Borrar de la lista de reproducción Nueva lista de reproducción... Columnas de la cuadrícula @@ -118,4 +117,5 @@ Busqueda Web Eliminar Carátula + "1 título añadido a la cola de reproducción" diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 907a03e4..abe8644e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -3,11 +3,11 @@ "Paramètres" À propos Lecture en cours - File de lecture + Liste de lecture Rechercher - Lire ensuite - Ajouter à la file de lecture - Retirer de la file de lecture + Prochaine lecture + Ajouter à la liste de lecture + Retirer de la liste de lecture Ajouter à une playlist... Éditeur d\'infos Supprimer de l\'appareil @@ -31,10 +31,10 @@ "Piste (2 pour piste 2 ou 3004 pour CD3 piste 4)" Veuillez indiquer le nom et l\'artiste de l\'album. Fichier en cours d\'écriture - Sauvegarde des changements... + Sauvegarde en cours... Détails Nom du fichier - Chemin du fichier + Location du fichier Taille Format Durée @@ -45,12 +45,11 @@ File de lecture Sauvegarder Icône par - "Phonograph est un lecteur de musique avec un Material Design et entièrement gratuit créé par" + "Phonograph est un lecteur de musique entièrement gratuit avec le concept de Material Design créé par" Rechercher Aucun résultat Actualiser l\'image de l\'artiste Actualisation... - "1 titre ajouté à la file de lecture." Supprimer de la playlist Nouvelle playlist... Nombre de colonnes @@ -120,4 +119,5 @@ Recherche internet Supprimer la couverture + "1 titre ajouté à la file de lecture." diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index d3022808..daf59af7 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -12,9 +12,9 @@ Modifica tag Elimina Dettagli - album + Album Artisti - brani + Brani Playlist Niente in riproduzione Spiacenti - si è verificato un errore nel tentativo di riprodurre questa canzone @@ -52,7 +52,6 @@ Nessun risultato Aggiorna immagine artista Aggiornamento... - "Un brano aggiunto alla coda." DettagliAttivitàPlaylist Elimina dalla playlist Nuova playlist... @@ -123,4 +122,5 @@ Cerca nel web Rimuovi copertina + "Un brano aggiunto alla coda." diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 5267f8a0..72d56453 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -50,7 +50,6 @@ 결과 없음 아티스트 이미지 변경 변경 중... - "재생 대기열에 1개의 음악을 추가했습니다." 재생목록에서 삭제 새로운 재생목록... 가로세로 격자 @@ -121,4 +120,5 @@ 인터넷 검색 커버 없애기 + "재생 대기열에 1개의 음악을 추가했습니다." diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index c5e71ea7..a2c818eb 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -50,7 +50,6 @@ Geen resultaten Artiest afbeelding bijwerken Bijwerken... - "1 titel toegevoegd aan de afspeelwachtrij." Verwijderen uit afspeellijst Nieuwe afspeellijst... Rasterkolommen @@ -120,4 +119,5 @@ Zoeken op internet Verwijder hoes + "1 titel toegevoegd aan de afspeelwachtrij." diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index e3c05028..f6612073 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -52,7 +52,6 @@ Brak wyników Zaktualizuj zdjęcie wykonawcy Aktualizowanie... - "Dodano 1 tytuł do kolejki odtwarzania" Usuń z listy odtwarzania Nowa lista odtwarzania... Siatka kolumn @@ -122,4 +121,5 @@ Szukaj w sieci Usuń okładkę + "Dodano 1 tytuł do kolejki odtwarzania" diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 9aed5cdb..1ba9e656 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -50,7 +50,6 @@ Sem resultados Atualizar imagem do artista Atualizando... - "1 título adicionado à lista de reprodução" Excluir da playlist Nova playlist... Colunas da grade @@ -120,4 +119,5 @@ Pesquisar na Internet Remover Arte do Album + "1 título adicionado à lista de reprodução" diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 52d6e8e3..c60997c7 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -49,7 +49,6 @@ Nenhum resultado Atualizar imagem do artista Atualizando... - "Adicionada uma música para a fila atual de músicas." Apagar da playlist Colunas da grade Colunas da grade (Paisagem) @@ -74,4 +73,5 @@ Abrir área de navegação "Fechar área de navegação" Música + "Adicionada uma música para a fila atual de músicas." diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 9468a11d..738749e9 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -49,7 +49,6 @@ Niciun rezultat Actualizează imagine artist Actualizare... - "Adăugat 1 melodie la lista de redare." Şterge din playlist Playlist nou... Rânduri pe grid @@ -99,4 +98,5 @@ Culoare Primară Culoare de accent Melodie + "Adăugat 1 melodie la lista de redare." diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 471c1808..b13f32bd 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -50,7 +50,6 @@ Нет результатов Обновить изображение исполнителя Обновление... - "Добавлена 1 композиция в очередь воспроизведения" Удалить из списка воспроизведения Новый список воспроизведения... Столбцы сетки @@ -120,4 +119,5 @@ Поиск в интернете Удалить обложку + "Добавлена 1 композиция в очередь воспроизведения" diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 88fef55e..9b0affcd 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -50,7 +50,6 @@ Inga resultat Uppdatera artistbild Uppdaterar ... - "Lagt till 1 titel till spellistan." Radera från spellista Ny spellista ... Spellista %1$s skapad @@ -115,4 +114,5 @@ Vill du radera %1$d låtar? Weksök Ta bort omslag + "Lagt till 1 titel till spellistan." diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index e3b216e5..33e3beca 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -50,7 +50,6 @@ Sonuç bulunamadı Sanatçı resmini güncelle Güncelleniyor... - "Çalma sırasına 1 başlık eklendi" Çalma listesinden sil Yeni çalma listesi Izgara sütunları @@ -120,4 +119,5 @@ Web\'de ara Albüm Kapağını Kaldır + "Çalma sırasına 1 başlık eklendi" diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 5db100c5..e866a9d4 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -50,7 +50,6 @@ 没有找到结果 更新歌手图片 正在更新… - "该曲目已加入播放队列" 从播放列表中删除 新建播放列表 专辑列数 @@ -120,4 +119,5 @@ 通过网络搜索 删除封面 + "该曲目已加入播放队列" diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index cca45c35..bf78e3b8 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -50,7 +50,6 @@ 無搜尋結果 更新歌手圖片 更新中… - "這歌曲已加入播放佇列" 從音樂清單移除 新增音樂清單 專輯網格列數 @@ -120,4 +119,5 @@ 網路搜尋 刪除封面 + "這歌曲已加入播放佇列" diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index f6f749c2..5d9ae327 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -18,6 +18,7 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a3d04136..fc7e3373 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -53,7 +53,8 @@ No results Update artist image Updating… - Added 1 title to the playing queue. + "Added 1 title to the playing queue." + Added %1$d titles to the playing queue. Playlist Activity Delete from playlist New playlist… @@ -67,16 +68,28 @@ %1$s? ]]> + %1$d playlists? + ]]> %1$s? ]]> %1$d songs? ]]> + %1$s from the playlist? + ]]> + %1$d songs from the playlist? + ]]> Delete Song Delete Songs + Delete Song from Playlist + Delete Songs from Playlist Rename Playlist Delete Playlist + Delete Playlists Add to Playlist New Playlist diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 3e606a12..56e647d3 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -43,7 +43,7 @@