Merge branch 'multi-select'

This commit is contained in:
Karim Abou Zeid 2015-05-25 19:49:30 +02:00
commit 464c5fdc1b
87 changed files with 1606 additions and 380 deletions

View file

@ -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'

View file

@ -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<VH extends RecyclerView.ViewHolder, I> extends RecyclerView.Adapter<VH> implements MaterialCab.Callback {
private final CabHolder cabHolder;
private MaterialCab cab;
private ArrayList<I> 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<I> selection);
}

View file

@ -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<AlbumAdapter.ViewHolder> {
public class AlbumAdapter extends AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album> {
public static final String TAG = AlbumAdapter.class.getSimpleName();
private final Activity activity;
private final AppCompatActivity activity;
private boolean usePalette;
private List<Album> dataSet;
@ -53,6 +67,10 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
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<AlbumAdapter.ViewHolder>
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<Album> 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<Song> getSongList(List<Album> albums) {
final ArrayList<Song> 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();

View file

@ -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<ArtistAdapter.ViewHolder> {
protected final Activity activity;
public class ArtistAdapter extends AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist> {
protected final AppCompatActivity activity;
protected List<Artist> 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<ArtistAdapter.ViewHolder
holder.artistName.setText(artist.name);
holder.artistInfo.setText(MusicUtil.getArtistInfoString(activity, artist));
holder.artistImage.setImageResource(R.drawable.default_artist_image);
holder.view.setActivated(isChecked(artist));
LastFMArtistThumbnailUrlLoader.loadArtistThumbnailUrl(activity, artist.name, false, new LastFMArtistThumbnailUrlLoader.ArtistThumbnailUrlLoaderCallback() {
@Override
@ -73,28 +84,69 @@ public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder
return dataSet.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected Artist getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<Artist> 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<Song> getSongList(List<Artist> artists) {
final ArrayList<Song> 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;
}
}

View file

@ -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<ArtistAlbumAdapter.ViewHolder> {
public class ArtistAlbumAdapter extends AbsMultiSelectAdapter<ArtistAlbumAdapter.ViewHolder, Album> {
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<Album> dataSet;
private final AppCompatActivity activity;
private ArrayList<Album> dataSet;
private final int listMargin;
public ArtistAlbumAdapter(AppCompatActivity activity, ArrayList<Album> 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<Album> 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<ArtistAlbumAdapter.
holder.title.setText(album.title);
holder.year.setText(String.valueOf(album.year));
holder.view.setActivated(isChecked(album));
}
@Override
@ -77,34 +99,69 @@ public class ArtistAlbumAdapter extends RecyclerView.Adapter<ArtistAlbumAdapter.
} else return TYPE_MIDDLE;
}
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<Album> 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<Song> getSongList(List<Album> albums) {
final ArrayList<Song> 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<Album> objects) {
this.activity = activity;
dataSet = objects;
listMargin = activity.getResources().getDimensionPixelSize(R.dimen.default_item_margin);
}
}

View file

@ -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<PlaylistAdapter.ViewHolder> {
public class PlaylistAdapter extends AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist> {
public static final String TAG = PlaylistAdapter.class.getSimpleName();
protected final AppCompatActivity activity;
protected List<Playlist> 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<PlaylistAdapter.ViewHo
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.playlistName.setText(dataSet.get(position).name);
final Playlist playlist = dataSet.get(position);
holder.playlistName.setText(playlist.name);
holder.view.setActivated(isChecked(playlist));
}
@Override
@ -53,15 +67,46 @@ public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHo
return dataSet.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected Playlist getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<Playlist> 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<Song> getSongList(List<Playlist> playlists) {
final ArrayList<Song> 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<PlaylistAdapter.ViewHo
@Override
public void onClick(View view) {
Pair[] sharedViews = null;
if (activity instanceof AbsFabActivity)
sharedViews = ((AbsFabActivity) activity).getSharedViewsWithFab(null);
NavigationUtil.goToPlaylist(activity, dataSet.get(getAdapterPosition()).id, sharedViews);
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
Pair[] sharedViews = null;
if (activity instanceof AbsFabActivity)
sharedViews = ((AbsFabActivity) activity).getSharedViewsWithFab(null);
NavigationUtil.goToPlaylist(activity, dataSet.get(getAdapterPosition()).id, sharedViews);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
App.bus.unregister(this);
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
App.bus.register(this);
}
@Subscribe
public void onDataBaseEvent(DataBaseChangedEvent event) {
switch (event.getAction()) {
case DataBaseChangedEvent.PLAYLISTS_CHANGED:
case DataBaseChangedEvent.DATABASE_CHANGED:
loadDataSet();
notifyDataSetChanged();
break;
}
}
}

View file

@ -11,6 +11,7 @@ import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
@ -20,11 +21,13 @@ import com.kabouzeid.gramophone.loader.ArtistLoader;
import com.kabouzeid.gramophone.loader.SongLoader;
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.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.Collections;
@ -41,12 +44,14 @@ public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder
private AppCompatActivity activity;
private List results = Collections.emptyList();
private String query;
public SearchAdapter(AppCompatActivity activity) {
this.activity = activity;
}
public void search(String query) {
this.query = query;
results = new ArrayList();
if (!query.trim().equals("")) {
List songs = SongLoader.getSongs(activity, query);
@ -224,4 +229,26 @@ public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder
}
}
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
App.bus.unregister(this);
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
App.bus.register(this);
}
@Subscribe
public void onDataBaseEvent(DataBaseChangedEvent event) {
switch (event.getAction()) {
case DataBaseChangedEvent.ALBUMS_CHANGED:
case DataBaseChangedEvent.DATABASE_CHANGED:
search(query);
break;
}
}
}

View file

@ -1,5 +1,6 @@
package com.kabouzeid.gramophone.adapter.songadapter;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@ -11,8 +12,12 @@ 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.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.util.MusicUtil;
@ -21,17 +26,23 @@ import java.util.ArrayList;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class AlbumSongAdapter extends RecyclerView.Adapter<AlbumSongAdapter.ViewHolder> {
public class AlbumSongAdapter extends AbsMultiSelectAdapter<AlbumSongAdapter.ViewHolder, Song> {
public static final String TAG = AlbumSongAdapter.class.getSimpleName();
protected final AppCompatActivity activity;
protected final ArrayList<Song> dataSet;
protected ArrayList<Song> dataSet;
public AlbumSongAdapter(AppCompatActivity activity, ArrayList<Song> objects) {
public AlbumSongAdapter(AppCompatActivity activity, ArrayList<Song> objects, @Nullable CabHolder cabHolder) {
super(cabHolder, R.menu.menu_media_selection);
this.activity = activity;
dataSet = objects;
}
public void updateDataSet(ArrayList<Song> 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<AlbumSongAdapter.View
holder.trackNumber.setText(trackNumberString);
holder.songTitle.setText(song.title);
holder.artistName.setText(MusicUtil.getReadableDurationString(song.duration));
holder.view.setActivated(isChecked(song));
}
@Override
@ -54,38 +66,71 @@ public class AlbumSongAdapter extends RecyclerView.Adapter<AlbumSongAdapter.View
return dataSet.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected Song getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<Song> 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;
}
}
}

View file

@ -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<Song> {
public class ArtistSongAdapter extends ArrayAdapter<Song> implements MaterialCab.Callback {
private final CabHolder cabHolder;
private MaterialCab cab;
private ArrayList<Song> dataSet;
private ArrayList<Song> checked;
private final AppCompatActivity activity;
public ArtistSongAdapter(AppCompatActivity activity, List<Song> songs) {
public ArtistSongAdapter(AppCompatActivity activity, ArrayList<Song> 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<Song> 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<Song> {
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<Song> 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;
}
}

View file

@ -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<PlaylistSongAdapter.ViewHolder> {
public class PlaylistSongAdapter extends AbsMultiSelectAdapter<PlaylistSongAdapter.ViewHolder, PlaylistSong> {
public static final String TAG = AlbumSongAdapter.class.getSimpleName();
protected final AppCompatActivity activity;
protected final ArrayList<PlaylistSong> dataSet;
protected ArrayList<PlaylistSong> dataSet;
public PlaylistSongAdapter(AppCompatActivity activity, ArrayList<PlaylistSong> objects) {
public PlaylistSongAdapter(AppCompatActivity activity, ArrayList<PlaylistSong> objects, @Nullable CabHolder cabHolder) {
super(cabHolder, R.menu.menu_playlists_songs_selection);
this.activity = activity;
dataSet = objects;
}
public void updateDataSet(ArrayList<PlaylistSong> 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<PlaylistSongAdapte
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final Song song = dataSet.get(position);
final PlaylistSong song = dataSet.get(position);
holder.view.setActivated(isChecked(song));
holder.songTitle.setText(song.title);
holder.songInfo.setText(song.artistName);
ImageLoader.getInstance().displayImage(
@ -68,54 +79,87 @@ public class PlaylistSongAdapter extends RecyclerView.Adapter<PlaylistSongAdapte
return dataSet.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected PlaylistSong getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<PlaylistSong> 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<Song>) (List) selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
break;
case R.id.action_add_to_current_playing:
//noinspection unchecked
MusicPlayerRemote.enqueue((ArrayList<Song>) (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<Song>) (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<Song>) (List) dataSet, getAdapterPosition(), true);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
}

View file

@ -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<SongAdapter.ViewHolder> {
public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song> 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<SongAdapter.ViewHolder> {
protected final AppCompatActivity activity;
protected ArrayList<Song> 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<SongAdapter.ViewHolder> {
.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<SongAdapter.ViewHolder> {
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<Song> 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<SongAdapter.ViewHolder> {
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);

View file

@ -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<PlaylistSong> list = new ArrayList<>();
list.add(song);
return create(list);
}
public static DeleteFromPlaylistDialog create(ArrayList<PlaylistSong> 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<PlaylistSong> songs = (ArrayList<PlaylistSong>) 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();
}
}

View file

@ -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<Playlist> list = new ArrayList<>();
list.add(playlist);
return create(list);
}
public static DeletePlaylistDialog create(ArrayList<Playlist> 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<Playlist> playlists = (ArrayList<Playlist>) 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();
}

View file

@ -36,7 +36,7 @@ public class DeleteSongsDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//noinspection unchecked
ArrayList<Song> songs = (ArrayList<Song>) getArguments().getSerializable("songs");
final ArrayList<Song> songs = (ArrayList<Song>) 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<Song> songs = (ArrayList<Song>) getArguments().getSerializable("songs");
MusicUtil.deleteTracks(getActivity(), songs);
}
}).build();

View file

@ -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;

View file

@ -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<Song> 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);

View file

@ -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);
}

View file

@ -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());
}

View file

@ -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,

View file

@ -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<Album> getArtistAlbumList(final Context context, final int artistId) {
public static ArrayList<Album> getArtistAlbumList(final Context context, final int artistId) {
Cursor cursor = makeArtistAlbumCursor(context, artistId);
List<Album> albums = new ArrayList<>();
ArrayList<Album> 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());
}
}

View file

@ -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,

View file

@ -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);
}

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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<Song> songs) {
playingQueue.addAll(position, songs);
originalPlayingQueue.addAll(position, songs);
saveState();
}
public void addSongs(List<Song> songs) {
playingQueue.addAll(songs);
originalPlayingQueue.addAll(songs);
saveState();
}
public void removeSong(int position) {
if (getShuffleMode() == SHUFFLE_MODE_NONE) {
playingQueue.remove(position);

View file

@ -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;
* <p/>
* 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<Song> 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<Song> 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;
}
}

View file

@ -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.
* <p/>
* 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<Song> songs;
private ArrayList<Album> 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<Song> 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<Album> 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;
}
}

View file

@ -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;
}
}

View file

@ -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<PlaylistSong> 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<PlaylistSong> 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;
}
}
}

View file

@ -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;

View file

@ -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) {

View file

@ -22,6 +22,6 @@ public class ArtistViewFragment extends AbsMainActivityRecyclerViewFragment {
@Override
protected RecyclerView.Adapter createAdapter() {
return new ArtistAdapter(getActivity());
return new ArtistAdapter(getMainActivity(), getMainActivity());
}
}

View file

@ -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(

View file

@ -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());
}
}

View file

@ -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<Playlist> 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<PlaylistSong> 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<PlaylistSong> 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(

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

View file

@ -67,10 +67,21 @@
android:layout_height="@dimen/statusMargin"
android:background="@android:color/transparent" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="@android:color/transparent" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="@android:color/transparent" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</FrameLayout>
</LinearLayout>

View file

@ -67,10 +67,21 @@
android:layout_height="@dimen/statusMargin"
android:background="@android:color/transparent" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="@android:color/transparent" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="@android:color/transparent" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</FrameLayout>
</LinearLayout>

View file

@ -20,15 +20,22 @@
android:fitsSystemWindows="true" />
<LinearLayout
android:elevation="@dimen/toolbar_elevation"
android:id="@+id/toolbarFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/main_toolbar_padding_top">
android:paddingTop="@dimen/main_toolbar_padding_top"
tools:ignore="UnusedAttribute">
<android.support.v7.widget.Toolbar
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:elevation="0dp"
android:background="?colorPrimary">
<TextView
@ -46,12 +53,19 @@
</android.support.v7.widget.Toolbar>
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</FrameLayout>
<com.astuetz.PagerSlidingTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="@dimen/tab_height"
android:background="?colorPrimary"
android:elevation="@dimen/toolbar_elevation"
android:elevation="0dp"
android:paddingLeft="64dp"
android:paddingStart="64dp"
android:textColor="@color/sliding_tabs_deactivated"

View file

@ -9,10 +9,21 @@
android:orientation="vertical"
android:paddingTop="@dimen/main_toolbar_padding_top">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="?colorPrimary" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="@android:color/transparent" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</FrameLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"

View file

@ -1,56 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:foreground="?rect_selector"
app:elevation="3dp">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="1dp">
<LinearLayout
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:ignore="UnusedAttribute,UselessParent">
<com.kabouzeid.gramophone.views.SquareImageView
android:id="@+id/album_art"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:transitionName="@string/transition_album_cover" />
android:layout_height="wrap_content"
android:foreground="?rect_selector">
<LinearLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?default_bar_color"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp"
android:transitionName="@string/transition_album_text">
tools:ignore="UnusedAttribute,UselessParent">
<TextView
android:id="@+id/album_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
android:textColor="?title_text_color" />
<com.kabouzeid.gramophone.views.SquareImageView
android:id="@+id/album_art"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/default_album_art"
android:transitionName="@string/transition_album_cover" />
<TextView
android:id="@+id/album_interpret"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="?caption_text_color" />
<LinearLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="68dp"
android:background="?default_bar_color"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:transitionName="@string/transition_album_text">
<TextView
android:id="@+id/album_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
android:textColor="?title_text_color" />
<TextView
android:id="@+id/album_interpret"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
android:textColor="?caption_text_color" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</FrameLayout>
<ImageView
android:id="@+id/check_mark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingBottom="68dp"
android:src="@drawable/ic_check_white_96dp"
android:tint="?check_mark_color"
android:visibility="invisible" />
</FrameLayout>

View file

@ -1,16 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="72dp">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="72dp"
android:foreground="?rect_selector">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingStart="16dp">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingStart="16dp">
<com.kabouzeid.gramophone.views.SquareImageView
android:id="@+id/album_art"
@ -30,30 +31,30 @@
android:orientation="vertical">
<TextView
android:textColor="?title_text_color"
android:id="@+id/song_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
android:textColor="?title_text_color" />
<TextView
android:textColor="?caption_text_color"
android:id="@+id/song_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="?caption_text_color" />
</LinearLayout>
<ImageView
android:id="@+id/menu"
style="@style/OverFlowButton"
android:layout_gravity="center_vertical"
android:layout_marginRight="2dp"
android:layout_marginEnd="2dp"
android:layout_marginRight="2dp"
tools:ignore="ContentDescription" />
</LinearLayout>

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="72dp"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="72dp"
android:foreground="?rect_selector">
<LinearLayout
@ -11,7 +11,7 @@
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingStart="16dp">
android:paddingRight="16dp">
<com.kabouzeid.gramophone.views.SquareImageView
android:id="@+id/album_art"
@ -53,8 +53,8 @@
android:id="@+id/menu"
style="@style/OverFlowButton"
android:layout_gravity="center_vertical"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginEnd="2dp"
tools:ignore="ContentDescription" />
</LinearLayout>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_add_to_playlist"
android:icon="@drawable/ic_playlist_add_white_24dp"
android:title="@string/action_add_to_playlist"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_add_to_current_playing"
android:icon="@drawable/ic_queue_white_24dp"
android:title="@string/action_add_to_playing_queue"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_delete_from_disk"
android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/action_delete_from_disk"
app:showAsAction="ifRoom" />
</menu>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_add_to_playlist"
android:icon="@drawable/ic_playlist_add_white_24dp"
android:title="@string/action_add_to_playlist"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_add_to_current_playing"
android:icon="@drawable/ic_queue_white_24dp"
android:title="@string/action_add_to_playing_queue"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_delete_playlist"
android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/delete_playlists_title"
app:showAsAction="ifRoom" />
</menu>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_add_to_playlist"
android:icon="@drawable/ic_playlist_add_white_24dp"
android:title="@string/action_add_to_playlist"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_add_to_current_playing"
android:icon="@drawable/ic_queue_white_24dp"
android:title="@string/action_add_to_playing_queue"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_delete_from_playlist"
android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/action_delete_from_playlist"
app:showAsAction="ifRoom" />
</menu>

View file

@ -1,16 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="action_settings">"الإعدادات"</string>
<string name="action_about">عنى</string>
<string name="action_currently_playing">يتم التشغيل حالياً</string>
<string name="action_playing_queue">قائمة الانتظار</string>
<string name="action_about">" عن التطبيق
"</string>
<string name="action_currently_playing">الإستماع الآن</string>
<string name="action_playing_queue">قائمة الإنتظار</string>
<string name="action_search">بحث</string>
<string name="action_play_next">استمع لاحقاً</string>
<string name="action_add_to_playing_queue">أضف إلى قائمة الانتظار</string>
<string name="action_add_to_playing_queue">أضف إلى قائمة الإنتظار</string>
<string name="action_remove_from_playing_queue">أزل من قائمة الانتظار</string>
<string name="action_add_to_playlist">أضف إلى قائمة تشغيل...</string>
<string name="action_tag_editor">تعديل معلومات الموسيقى</string>
<string name="action_delete_from_disk">حذف</string>
<string name="action_tag_editor">تعديل معلومات الملف</string>
<string name="action_delete_from_disk">حذف نهائي</string>
<string name="action_details">التفاصيل</string>
<string name="albums">الألبومات</string>
<string name="artists">الفنانون</string>
@ -27,30 +28,29 @@
<string name="genre">النوع</string>
<string name="album_artist">فنان الألبوم</string>
<string name="year">السنة</string>
<string name="track">الموسيقى</string>
<string name="track">"المقطع "</string>
<string name="track_hint">"الموسيقى (٢ للموسيقى ٢ أو ٣٠٠٤ للموسيقى ٤)"</string>
<string name="album_or_artist_empty">حقل نص اسم الألبوم أو اسم الفنان فارغ</string>
<string name="writing_file_number">تتم كتابة الملف</string>
<string name="saving_changes">يتم حفظ التغييرات...</string>
<string name="label_details">التفاصيل</string>
<string name="label_file_name">اسم الملف</string>
<string name="label_file_name">إسم الملف</string>
<string name="label_file_path">مسار الملف</string>
<string name="label_file_size">الحجم</string>
<string name="label_file_format">التنسيق</string>
<string name="label_file_format">نوع الملف</string>
<string name="label_track_length">الطول</string>
<string name="label_bit_rate">معدل البت</string>
<string name="label_sampling_rate">معدل أخذ العينات</string>
<string name="action_go_to_artist">اذهب إلى الفنان</string>
<string name="action_go_to_album">اذهب إلى الألبوم</string>
<string name="label_current_playing_queue">قائمة الانتظار</string>
<string name="action_go_to_artist">إذهب إلى الفنان</string>
<string name="action_go_to_album">إذهب إلى الألبوم</string>
<string name="label_current_playing_queue">قائمة الإنتظار</string>
<string name="save_as_playlist">حفظ كقائمة تشغيل</string>
<string name="credits_3">الأيقونة من</string>
<string name="credits_1">"مشغل الموسيقى فونقراف هو برنامج مجاني بشكلٍ كامل بتصميم أنيق من "</string>
<string name="credits_3">الأيقونة من تصميم</string>
<string name="credits_1">"مشغل الموسيقى فونقراف هو برنامج مجاني بشكلٍ كامل بتصميم أنيق من تصميم"</string>
<string name="title_activity_search">بحث</string>
<string name="no_results">لا توجد نتائج</string>
<string name="action_re_download_artist_image">تحديث صورة الفنان</string>
<string name="updating">يتم التحديث...</string>
<string name="added_title_to_playing_queue">"تمت الإضافة إلى قائمة الانتظار"</string>
<string name="action_delete_from_playlist">حذف من قائمة التشغيل</string>
<string name="new_playlist_action">قائمة تشغيل جديدة...</string>
<string name="action_grid_columns">عدد قوائم الشبكة</string>
@ -71,14 +71,14 @@
<string name="delete_playlist_title">حذف قائمة التشغيل</string>
<string name="add_playlist_title">"إضافة إلى قائمة التشغيل"</string>
<string name="new_playlist_title">قائمة تشغيل جديدة</string>
<string name="delete_warning">"تحذير: لا يمكن التراجع هذه العملية."</string>
<string name="delete_warning">"تحذير: لا يمكن التراجع عن هذه العملية."</string>
<string name="shuffle_all">عشوائي</string>
<string name="last_opened">آخر ما تم فتحه</string>
<string name="light_theme_name">فاتح</string>
<string name="dark_theme_name">داكن</string>
<string name="equalizer">المعادل</string>
<string name="pref_header_ui">واجهة المستخدم</string>
<string name="pref_title_general_theme">السمة الأساسية</string>
<string name="pref_title_general_theme">الثيم العام</string>
<string name="pref_header_audio">الصوت</string>
<string name="pref_header_general">عام</string>
<string name="pref_summary_colored_navigation_bar">في أي مشهد يتم تلوين شريط التنقل</string>
@ -93,4 +93,35 @@
<string name="pref_title_colored_navigation_bar_playlists">مشهد قائمة التشغيل</string>
<string name="pref_title_colored_navigation_bar_tag_editor">تعديل معلومات الموسيقى</string>
<string name="pref_title_colored_navigation_bar_other_screens">في أي مكان</string>
<string name="pref_title_colored_album_footers">الهوامش السفلية للألبومات ملونة</string>
<string name="no_equalizer">لا يوجد معدل صوت</string>
<string name="no_audio_ID">"لا يوجد audio id, شغل شيئا وحاول مرة أخرى."</string>
<string name="navigation_drawer_open">إفتح قائمة التصفح الجانبية</string>
<string name="navigation_drawer_close">"إغلاق قائمة التصفح الجانبية"</string>
<string name="delete_action">حذف</string>
<string name="rename_action">إعادة التسمية</string>
<string name="select">إختيار</string>
<string name="default_str">إفتراضي</string>
<string name="primary_color">اللون الأساسي</string>
<string name="accent_color">اللون الثانوي</string>
<string name="primary_color_desc">تحديد الأزرق النيلي كلون ثيم اساسي.</string>
<string name="accent_color_desc">تحديد الوردي كلون ثانوي.</string>
<string name="update_image">تحديث الصورة</string>
<string name="playlist_empty_text">قائمة التشغيل فارغة</string>
<string name="no_playlists">لا توجد قوائم تشغيل</string>
<string name="playlist_name">إسم قائمة الشغيل</string>
<string name="song">الأغنية</string>
<string name="pref_only_lollipop">"متوفر في نظام التشغيل Lollipop."</string>
<string name="pref_summary_transparent_toolbar">جعل المحتوى الذي يمر تحت شريط الأدوات مرئيا.</string>
<string name="pref_summary_colored_album_footers">"تلوين الهوامش السفلية للألبومات بلون غلاف الألبوم."</string>
<string name="failed_download_albumart">"تعذر تحميل صور هذا الألبوم."</string>
<string name="search_hint">البحث في المكتبة...</string>
<string name="rescanning_media">إعادة تفحص الملفات...</string>
<string-array name="update_album_cover_options">
<item>تحميل من last.fm</item>
<item>اختيار من ذاكرة التخزين الداخلية</item>
<item>بحث في الإنترنات</item>
<item>حذف الغلاف</item>
</string-array>
<string name="added_title_to_playing_queue">"تمت الإضافة إلى قائمة الانتظار"</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">Žádné výsledky</string>
<string name="action_re_download_artist_image">Změnit obrázek umělce</string>
<string name="updating">Aktualizace...</string>
<string name="added_title_to_playing_queue">"Přidána 1 skladba do fronty."</string>
<string name="action_delete_from_playlist">Vymazat z playlistu</string>
<string name="new_playlist_action">Nový playlist...</string>
<string name="action_grid_columns">Počet sloupců mřížky</string>
@ -120,4 +119,5 @@
<item>Najít na webu</item>
<item>Odstranit obal alba</item>
</string-array>
<string name="added_title_to_playing_queue">"Přidána 1 skladba do fronty."</string>
</resources>

View file

@ -50,7 +50,7 @@
<string name="no_results">Keine Ergebnisse</string>
<string name="action_re_download_artist_image">Interpretenbild aktualisieren</string>
<string name="updating">Aktualisiere...</string>
<string name="added_title_to_playing_queue">"1 Titel wurde der Wiedergabeliste hinzugefügt."</string>
<string name="added_x_titles_to_playing_queue">%1$d Titel wurden der Wiedergabeliste hinzugefügt.</string>
<string name="action_delete_from_playlist">Aus Playlist entfernen</string>
<string name="new_playlist_action">Neue Playlist…</string>
<string name="action_grid_columns">Rastergröße</string>
@ -120,4 +120,5 @@
<item>Web suche</item>
<item>Cover entfernen</item>
</string-array>
<string name="added_title_to_playing_queue">"1 Titel wurde der Wiedergabeliste hinzugefügt."</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">Κανένα αποτέλεσμα</string>
<string name="action_re_download_artist_image">Ανανέωση εικόνας καλλιτέχνη</string>
<string name="updating">Γίνεται ανανέωση...</string>
<string name="added_title_to_playing_queue">"Προστέθηκε ένας τίτλος στη σειρά αναπαραγωγής"</string>
<string name="action_delete_from_playlist">Διαγραφή από τη λίστα αναπαραγωγής</string>
<string name="new_playlist_action">Νέα λίστα αναπαραγωγής...</string>
<string name="action_grid_columns">Στήλες πλέγματος</string>
@ -120,4 +119,5 @@
<item>Αναζήτηση στο διαδίκτυο</item>
<item>Διαγραφή εξώφυλλου</item>
</string-array>
<string name="added_title_to_playing_queue">"Προστέθηκε ένας τίτλος στη σειρά αναπαραγωγής"</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">Sin resultados</string>
<string name="action_re_download_artist_image">Actualizar imagen del artista</string>
<string name="updating">Actualizando...</string>
<string name="added_title_to_playing_queue">"1 título añadido a la cola de reproducción"</string>
<string name="action_delete_from_playlist">Borrar de la lista de reproducción</string>
<string name="new_playlist_action">Nueva lista de reproducción...</string>
<string name="action_grid_columns">Columnas de la cuadrícula</string>
@ -118,4 +117,5 @@
<item>Busqueda Web</item>
<item>Eliminar Carátula</item>
</string-array>
<string name="added_title_to_playing_queue">"1 título añadido a la cola de reproducción"</string>
</resources>

View file

@ -3,11 +3,11 @@
<string name="action_settings">"Paramètres"</string>
<string name="action_about">À propos</string>
<string name="action_currently_playing">Lecture en cours</string>
<string name="action_playing_queue">File de lecture</string>
<string name="action_playing_queue">Liste de lecture</string>
<string name="action_search">Rechercher</string>
<string name="action_play_next">Lire ensuite</string>
<string name="action_add_to_playing_queue">Ajouter à la file de lecture</string>
<string name="action_remove_from_playing_queue">Retirer de la file de lecture</string>
<string name="action_play_next">Prochaine lecture</string>
<string name="action_add_to_playing_queue">Ajouter à la liste de lecture</string>
<string name="action_remove_from_playing_queue">Retirer de la liste de lecture</string>
<string name="action_add_to_playlist">Ajouter à une playlist...</string>
<string name="action_tag_editor">Éditeur d\'infos</string>
<string name="action_delete_from_disk">Supprimer de l\'appareil</string>
@ -31,10 +31,10 @@
<string name="track_hint">"Piste (2 pour piste 2 ou 3004 pour CD3 piste 4)"</string>
<string name="album_or_artist_empty">Veuillez indiquer le nom et l\'artiste de l\'album.</string>
<string name="writing_file_number">Fichier en cours d\'écriture</string>
<string name="saving_changes">Sauvegarde des changements...</string>
<string name="saving_changes">Sauvegarde en cours...</string>
<string name="label_details">Détails</string>
<string name="label_file_name">Nom du fichier</string>
<string name="label_file_path">Chemin du fichier</string>
<string name="label_file_path">Location du fichier</string>
<string name="label_file_size">Taille</string>
<string name="label_file_format">Format</string>
<string name="label_track_length">Durée</string>
@ -45,12 +45,11 @@
<string name="label_current_playing_queue">File de lecture</string>
<string name="save_as_playlist">Sauvegarder</string>
<string name="credits_3">Icône par</string>
<string name="credits_1">"Phonograph est un lecteur de musique avec un Material Design et entièrement gratuit créé par"</string>
<string name="credits_1">"Phonograph est un lecteur de musique entièrement gratuit avec le concept de Material Design créé par"</string>
<string name="title_activity_search">Rechercher</string>
<string name="no_results">Aucun résultat</string>
<string name="action_re_download_artist_image">Actualiser l\'image de l\'artiste</string>
<string name="updating">Actualisation...</string>
<string name="added_title_to_playing_queue">"1 titre ajouté à la file de lecture."</string>
<string name="action_delete_from_playlist">Supprimer de la playlist</string>
<string name="new_playlist_action">Nouvelle playlist...</string>
<string name="action_grid_columns">Nombre de colonnes</string>
@ -120,4 +119,5 @@
<item>Recherche internet</item>
<item>Supprimer la couverture</item>
</string-array>
<string name="added_title_to_playing_queue">"1 titre ajouté à la file de lecture."</string>
</resources>

View file

@ -12,9 +12,9 @@
<string name="action_tag_editor">Modifica tag</string>
<string name="action_delete_from_disk">Elimina</string>
<string name="action_details">Dettagli</string>
<string name="albums">album</string>
<string name="albums">Album</string>
<string name="artists">Artisti</string>
<string name="songs">brani</string>
<string name="songs">Brani</string>
<string name="playlists">Playlist</string>
<string name="nothing_playing">Niente in riproduzione</string>
<string name="unplayable_file">Spiacenti - si è verificato un errore nel tentativo di riprodurre questa canzone</string>
@ -52,7 +52,6 @@
<string name="no_results">Nessun risultato</string>
<string name="action_re_download_artist_image">Aggiorna immagine artista</string>
<string name="updating">Aggiornamento...</string>
<string name="added_title_to_playing_queue">"Un brano aggiunto alla coda."</string>
<string name="title_activity_playlist_detail">DettagliAttivitàPlaylist</string>
<string name="action_delete_from_playlist">Elimina dalla playlist</string>
<string name="new_playlist_action">Nuova playlist...</string>
@ -123,4 +122,5 @@
<item>Cerca nel web</item>
<item>Rimuovi copertina</item>
</string-array>
<string name="added_title_to_playing_queue">"Un brano aggiunto alla coda."</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">결과 없음</string>
<string name="action_re_download_artist_image">아티스트 이미지 변경</string>
<string name="updating">변경 중...</string>
<string name="added_title_to_playing_queue">"재생 대기열에 1개의 음악을 추가했습니다."</string>
<string name="action_delete_from_playlist">재생목록에서 삭제</string>
<string name="new_playlist_action">새로운 재생목록...</string>
<string name="action_grid_columns">가로세로 격자</string>
@ -121,4 +120,5 @@
<item>인터넷 검색</item>
<item>커버 없애기</item>
</string-array>
<string name="added_title_to_playing_queue">"재생 대기열에 1개의 음악을 추가했습니다."</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">Geen resultaten</string>
<string name="action_re_download_artist_image">Artiest afbeelding bijwerken</string>
<string name="updating">Bijwerken...</string>
<string name="added_title_to_playing_queue">"1 titel toegevoegd aan de afspeelwachtrij."</string>
<string name="action_delete_from_playlist">Verwijderen uit afspeellijst</string>
<string name="new_playlist_action">Nieuwe afspeellijst...</string>
<string name="action_grid_columns">Rasterkolommen</string>
@ -120,4 +119,5 @@
<item>Zoeken op internet</item>
<item>Verwijder hoes</item>
</string-array>
<string name="added_title_to_playing_queue">"1 titel toegevoegd aan de afspeelwachtrij."</string>
</resources>

View file

@ -52,7 +52,6 @@
<string name="no_results">Brak wyników</string>
<string name="action_re_download_artist_image">Zaktualizuj zdjęcie wykonawcy</string>
<string name="updating">Aktualizowanie...</string>
<string name="added_title_to_playing_queue">"Dodano 1 tytuł do kolejki odtwarzania"</string>
<string name="action_delete_from_playlist">Usuń z listy odtwarzania</string>
<string name="new_playlist_action">Nowa lista odtwarzania...</string>
<string name="action_grid_columns">Siatka kolumn</string>
@ -122,4 +121,5 @@
<item>Szukaj w sieci</item>
<item>Usuń okładkę</item>
</string-array>
<string name="added_title_to_playing_queue">"Dodano 1 tytuł do kolejki odtwarzania"</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">Sem resultados</string>
<string name="action_re_download_artist_image">Atualizar imagem do artista</string>
<string name="updating">Atualizando...</string>
<string name="added_title_to_playing_queue">"1 título adicionado à lista de reprodução"</string>
<string name="action_delete_from_playlist">Excluir da playlist</string>
<string name="new_playlist_action">Nova playlist...</string>
<string name="action_grid_columns">Colunas da grade</string>
@ -120,4 +119,5 @@
<item>Pesquisar na Internet</item>
<item>Remover Arte do Album</item>
</string-array>
<string name="added_title_to_playing_queue">"1 título adicionado à lista de reprodução"</string>
</resources>

View file

@ -49,7 +49,6 @@
<string name="no_results">Nenhum resultado</string>
<string name="action_re_download_artist_image">Atualizar imagem do artista</string>
<string name="updating">Atualizando...</string>
<string name="added_title_to_playing_queue">"Adicionada uma música para a fila atual de músicas."</string>
<string name="action_delete_from_playlist">Apagar da playlist</string>
<string name="action_grid_columns">Colunas da grade</string>
<string name="action_grid_columns_land">Colunas da grade (Paisagem)</string>
@ -74,4 +73,5 @@
<string name="navigation_drawer_open">Abrir área de navegação</string>
<string name="navigation_drawer_close">"Fechar área de navegação"</string>
<string name="song">Música</string>
<string name="added_title_to_playing_queue">"Adicionada uma música para a fila atual de músicas."</string>
</resources>

View file

@ -49,7 +49,6 @@
<string name="no_results">Niciun rezultat</string>
<string name="action_re_download_artist_image">Actualizează imagine artist</string>
<string name="updating">Actualizare...</string>
<string name="added_title_to_playing_queue">"Adăugat 1 melodie la lista de redare."</string>
<string name="action_delete_from_playlist">Şterge din playlist</string>
<string name="new_playlist_action">Playlist nou...</string>
<string name="action_grid_columns">Rânduri pe grid</string>
@ -99,4 +98,5 @@
<string name="primary_color">Culoare Primară</string>
<string name="accent_color">Culoare de accent</string>
<string name="song">Melodie</string>
<string name="added_title_to_playing_queue">"Adăugat 1 melodie la lista de redare."</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">Нет результатов</string>
<string name="action_re_download_artist_image">Обновить изображение исполнителя</string>
<string name="updating">Обновление...</string>
<string name="added_title_to_playing_queue">"Добавлена 1 композиция в очередь воспроизведения"</string>
<string name="action_delete_from_playlist">Удалить из списка воспроизведения</string>
<string name="new_playlist_action">Новый список воспроизведения...</string>
<string name="action_grid_columns">Столбцы сетки</string>
@ -120,4 +119,5 @@
<item>Поиск в интернете</item>
<item>Удалить обложку</item>
</string-array>
<string name="added_title_to_playing_queue">"Добавлена 1 композиция в очередь воспроизведения"</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">Inga resultat</string>
<string name="action_re_download_artist_image">Uppdatera artistbild</string>
<string name="updating">Uppdaterar ...</string>
<string name="added_title_to_playing_queue">"Lagt till 1 titel till spellistan."</string>
<string name="action_delete_from_playlist">Radera från spellista</string>
<string name="new_playlist_action">Ny spellista ...</string>
<string name="created_playlist_x">Spellista %1$s skapad</string>
@ -115,4 +114,5 @@ Vill du radera <b>%1$d</b> låtar?
<item>Weksök</item>
<item>Ta bort omslag</item>
</string-array>
<string name="added_title_to_playing_queue">"Lagt till 1 titel till spellistan."</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">Sonuç bulunamadı</string>
<string name="action_re_download_artist_image">Sanatçı resmini güncelle</string>
<string name="updating">Güncelleniyor...</string>
<string name="added_title_to_playing_queue">"Çalma sırasına 1 başlık eklendi"</string>
<string name="action_delete_from_playlist">Çalma listesinden sil</string>
<string name="new_playlist_action">Yeni çalma listesi</string>
<string name="action_grid_columns">Izgara sütunları</string>
@ -120,4 +119,5 @@
<item>Web\'de ara</item>
<item>Albüm Kapağını Kaldır</item>
</string-array>
<string name="added_title_to_playing_queue">"Çalma sırasına 1 başlık eklendi"</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">没有找到结果</string>
<string name="action_re_download_artist_image">更新歌手图片</string>
<string name="updating">正在更新…</string>
<string name="added_title_to_playing_queue">"该曲目已加入播放队列"</string>
<string name="action_delete_from_playlist">从播放列表中删除</string>
<string name="new_playlist_action">新建播放列表</string>
<string name="action_grid_columns">专辑列数</string>
@ -120,4 +119,5 @@
<item>通过网络搜索</item>
<item>删除封面</item>
</string-array>
<string name="added_title_to_playing_queue">"该曲目已加入播放队列"</string>
</resources>

View file

@ -50,7 +50,6 @@
<string name="no_results">無搜尋結果</string>
<string name="action_re_download_artist_image">更新歌手圖片</string>
<string name="updating">更新中…</string>
<string name="added_title_to_playing_queue">"這歌曲已加入播放佇列"</string>
<string name="action_delete_from_playlist">從音樂清單移除</string>
<string name="new_playlist_action">新增音樂清單</string>
<string name="action_grid_columns">專輯網格列數</string>
@ -120,4 +119,5 @@
<item>網路搜尋</item>
<item>刪除封面</item>
</string-array>
<string name="added_title_to_playing_queue">"這歌曲已加入播放佇列"</string>
</resources>

View file

@ -18,6 +18,7 @@
<attr name="drawable_color_enabled" format="color" />
<attr name="themed_drawable_color" format="color" />
<attr name="check_mark_color" format="color" />
<attr name="default_bar_color" format="color" />
<attr name="card_color" format="color" />

View file

@ -53,7 +53,8 @@
<string name="no_results">No results</string>
<string name="action_re_download_artist_image">Update artist image</string>
<string name="updating">Updating…</string>
<string name="added_title_to_playing_queue">Added 1 title to the playing queue.</string>
<string name="added_title_to_playing_queue">"Added 1 title to the playing queue."</string>
<string name="added_x_titles_to_playing_queue">Added %1$d titles to the playing queue.</string>
<string name="title_activity_playlist_detail">Playlist Activity</string>
<string name="action_delete_from_playlist">Delete from playlist</string>
<string name="new_playlist_action">New playlist…</string>
@ -67,16 +68,28 @@
<string name="delete_playlist_x"><![CDATA[
Do you want to delete the playlist <b>%1$s</b>?
]]></string>
<string name="delete_x_playlists"><![CDATA[
Do you want to delete <b>%1$d</b> playlists?
]]></string>
<string name="delete_song_x"><![CDATA[
Do you want to delete the song <b>%1$s</b>?
]]></string>
<string name="delete_x_songs"><![CDATA[
Do you want to delete <b>%1$d</b> songs?
]]></string>
<string name="delete_song_x_from_playlist"><![CDATA[
Do you want to delete the song <b>%1$s</b> from the playlist?
]]></string>
<string name="delete_x_songs_from_playlist"><![CDATA[
Do you want to delete <b>%1$d</b> songs from the playlist?
]]></string>
<string name="delete_song_title">Delete Song</string>
<string name="delete_songs_title">Delete Songs</string>
<string name="delete_song_from_playlist_title">Delete Song from Playlist</string>
<string name="delete_songs_from_playlist_title">Delete Songs from Playlist</string>
<string name="rename_playlist_title">Rename Playlist</string>
<string name="delete_playlist_title">Delete Playlist</string>
<string name="delete_playlists_title">Delete Playlists</string>
<string name="add_playlist_title">Add to Playlist</string>
<string name="new_playlist_title">New Playlist</string>

View file

@ -43,7 +43,7 @@
<style name="Toolbar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">?attr/actionBarSize</item>
<item name="theme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
<item name="android:theme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
<item name="android:minHeight">@dimen/abc_action_bar_default_height_material</item>
<item name="popupTheme">?toolbarPopupTheme</item>
<item name="android:elevation" tools:ignore="NewApi">@dimen/toolbar_elevation</item>

View file

@ -25,6 +25,7 @@
<item name="nav_drawer_icon_color">#fff</item>
<item name="themed_drawable_color">@color/materialmusic_dark_themed_drawable_color</item>
<item name="check_mark_color">@color/grey_900</item>
<item name="default_bar_color">@color/materialmusic_dark_default_bar_color</item>
<item name="card_color">@color/materialmusic_dark_default_bar_color</item>
@ -56,6 +57,7 @@
<item name="nav_drawer_icon_color">#000</item>
<item name="themed_drawable_color">@color/materialmusic_themed_drawable_color</item>
<item name="check_mark_color">@color/white</item>
<item name="default_bar_color">@color/materialmusic_default_bar_color</item>
<item name="card_color">@color/white</item>