change application id for release

This commit is contained in:
dkanada 2020-05-09 04:43:09 +09:00
commit 9d08253655
159 changed files with 801 additions and 801 deletions

View file

@ -0,0 +1,154 @@
package com.dkanada.gramophone.adapter;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.glide.CustomGlideRequest;
import com.dkanada.gramophone.glide.CustomPaletteTarget;
import com.dkanada.gramophone.misc.CustomFragmentStatePagerAdapter;
import com.dkanada.gramophone.model.Song;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class AlbumCoverPagerAdapter extends CustomFragmentStatePagerAdapter {
private List<Song> dataSet;
private AlbumCoverFragment.ColorReceiver currentColorReceiver;
private int currentColorReceiverPosition = -1;
public AlbumCoverPagerAdapter(FragmentManager fm, List<Song> dataSet) {
super(fm);
this.dataSet = dataSet;
}
@Override
public Fragment getItem(final int position) {
return AlbumCoverFragment.newInstance(dataSet.get(position));
}
@Override
public int getCount() {
return dataSet.size();
}
@Override
@NonNull
public Object instantiateItem(ViewGroup container, int position) {
Object o = super.instantiateItem(container, position);
if (currentColorReceiver != null && currentColorReceiverPosition == position) {
receiveColor(currentColorReceiver, currentColorReceiverPosition);
}
return o;
}
// only the latest ColorReceiver is guaranteed a response
public void receiveColor(AlbumCoverFragment.ColorReceiver colorReceiver, int position) {
AlbumCoverFragment fragment = (AlbumCoverFragment) getFragment(position);
if (fragment != null) {
currentColorReceiver = null;
currentColorReceiverPosition = -1;
fragment.receiveColor(colorReceiver, position);
} else {
currentColorReceiver = colorReceiver;
currentColorReceiverPosition = position;
}
}
public static class AlbumCoverFragment extends Fragment {
private static final String SONG_ARG = "song";
private Unbinder unbinder;
@BindView(R.id.player_image)
ImageView albumCover;
private boolean isColorReady;
private int color;
private Song song;
private ColorReceiver colorReceiver;
private int request;
public static AlbumCoverFragment newInstance(final Song song) {
AlbumCoverFragment frag = new AlbumCoverFragment();
final Bundle args = new Bundle();
args.putParcelable(SONG_ARG, song);
frag.setArguments(args);
return frag;
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
song = getArguments().getParcelable(SONG_ARG);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_album_cover, container, false);
unbinder = ButterKnife.bind(this, view);
return view;
}
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
loadAlbumCover();
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
colorReceiver = null;
}
private void loadAlbumCover() {
CustomGlideRequest.Builder
.from(Glide.with(getContext()), song.primary)
.generatePalette(getActivity()).build()
.into(new CustomPaletteTarget(albumCover) {
@Override
public void onColorReady(int color) {
setColor(color);
}
});
}
private void setColor(int color) {
this.color = color;
isColorReady = true;
if (colorReceiver != null) {
colorReceiver.onColorReady(color, request);
colorReceiver = null;
}
}
public void receiveColor(ColorReceiver colorReceiver, int request) {
if (isColorReady) {
colorReceiver.onColorReady(color, request);
} else {
this.colorReceiver = colorReceiver;
this.request = request;
}
}
public interface ColorReceiver {
void onColorReady(int color, int request);
}
}
}

View file

@ -0,0 +1,112 @@
package com.dkanada.gramophone.adapter;
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.model.CategoryInfo;
import com.dkanada.gramophone.helper.SwipeAndDragHelper;
import java.util.List;
public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapter.ViewHolder> implements SwipeAndDragHelper.ActionCompletionContract {
private List<CategoryInfo> categoryInfos;
private ItemTouchHelper touchHelper;
public CategoryInfoAdapter(List<CategoryInfo> categoryInfos) {
this.categoryInfos = categoryInfos;
SwipeAndDragHelper swipeAndDragHelper = new SwipeAndDragHelper(this);
touchHelper = new ItemTouchHelper(swipeAndDragHelper);
}
@Override
@NonNull
public CategoryInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.preference_dialog_library_categories_listitem, parent, false);
return new ViewHolder(view);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
CategoryInfo categoryInfo = categoryInfos.get(position);
holder.checkBox.setChecked(categoryInfo.visible);
holder.title.setText(holder.title.getResources().getString(categoryInfo.category.stringRes));
holder.itemView.setOnClickListener(v -> {
if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) {
categoryInfo.visible = !categoryInfo.visible;
holder.checkBox.setChecked(categoryInfo.visible);
} else {
Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category, Toast.LENGTH_SHORT).show();
}
});
holder.dragView.setOnTouchListener((view, event) -> {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
touchHelper.startDrag(holder);
}
return false;
}
);
}
@Override
public int getItemCount() {
return categoryInfos.size();
}
public void setCategoryInfos(List<CategoryInfo> categoryInfos) {
this.categoryInfos = categoryInfos;
notifyDataSetChanged();
}
@Override
public void onViewMoved(int oldPosition, int newPosition) {
CategoryInfo categoryInfo = categoryInfos.get(oldPosition);
categoryInfos.remove(oldPosition);
categoryInfos.add(newPosition, categoryInfo);
notifyItemMoved(oldPosition, newPosition);
}
public void attachToRecyclerView(RecyclerView recyclerView) {
touchHelper.attachToRecyclerView(recyclerView);
}
public List<CategoryInfo> getCategoryInfos() {
return categoryInfos;
}
private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
if (categoryInfo.visible) {
for (CategoryInfo c : categoryInfos) {
if (c != categoryInfo && c.visible) return false;
}
}
return true;
}
static class ViewHolder extends RecyclerView.ViewHolder {
public CheckBox checkBox;
public TextView title;
public View dragView;
public ViewHolder(View view) {
super(view);
checkBox = view.findViewById(R.id.checkbox);
title = view.findViewById(R.id.title);
dragView = view.findViewById(R.id.drag_view);
}
}
}

View file

@ -0,0 +1,123 @@
package com.dkanada.gramophone.adapter;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.bumptech.glide.Glide;
import com.dkanada.gramophone.adapter.base.MediaEntryViewHolder;
import com.dkanada.gramophone.glide.CustomGlideRequest;
import com.dkanada.gramophone.glide.CustomPaletteTarget;
import com.dkanada.gramophone.model.Genre;
import com.dkanada.gramophone.util.MusicUtil;
import com.dkanada.gramophone.util.NavigationUtil;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.List;
public class GenreAdapter extends RecyclerView.Adapter<GenreAdapter.ViewHolder> implements FastScrollRecyclerView.SectionedAdapter {
private final AppCompatActivity activity;
private List<Genre> dataSet;
private int itemLayoutRes;
public GenreAdapter(@NonNull AppCompatActivity activity, List<Genre> dataSet, @LayoutRes int itemLayoutRes) {
this.activity = activity;
this.dataSet = dataSet;
this.itemLayoutRes = itemLayoutRes;
}
public List<Genre> getDataSet() {
return dataSet;
}
public void swapDataSet(List<Genre> dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
@Override
public long getItemId(int position) {
return dataSet.get(position).hashCode();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final Genre genre = dataSet.get(position);
if (holder.getAdapterPosition() == getItemCount() - 1) {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.GONE);
}
} else {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.VISIBLE);
}
}
if (holder.menu != null) {
holder.menu.setVisibility(View.GONE);
}
if (holder.title != null) {
holder.title.setText(genre.name);
}
loadImage(genre, holder);
}
protected void loadImage(Genre genre, final GenreAdapter.ViewHolder holder) {
if (holder.image == null) return;
CustomGlideRequest.Builder
.from(Glide.with(activity), genre.id)
.generatePalette(activity).build()
.into(new CustomPaletteTarget(holder.image) {
@Override
public void onLoadCleared(Drawable placeholder) {
super.onLoadCleared(placeholder);
}
@Override
public void onColorReady(int color) {
}
});
}
@Override
public int getItemCount() {
return dataSet.size();
}
@NonNull
@Override
public String getSectionName(int position) {
final Genre genre = dataSet.get(position);
return genre.id.hashCode() == -1 ? "" : MusicUtil.getSectionName(dataSet.get(position).name);
}
public class ViewHolder extends MediaEntryViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
public void onClick(View view) {
Genre genre = dataSet.get(getAdapterPosition());
NavigationUtil.goToGenre(activity, genre);
}
}
}

View file

@ -0,0 +1,189 @@
package com.dkanada.gramophone.adapter;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import android.util.SparseArray;
import android.view.ViewGroup;
import com.dkanada.gramophone.model.CategoryInfo;
import com.dkanada.gramophone.ui.fragments.mainactivity.library.pager.AlbumsFragment;
import com.dkanada.gramophone.ui.fragments.mainactivity.library.pager.ArtistsFragment;
import com.dkanada.gramophone.ui.fragments.mainactivity.library.pager.GenresFragment;
import com.dkanada.gramophone.ui.fragments.mainactivity.library.pager.PlaylistsFragment;
import com.dkanada.gramophone.ui.fragments.mainactivity.library.pager.SongsFragment;
import com.dkanada.gramophone.util.PreferenceUtil;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
public class MusicLibraryPagerAdapter extends FragmentPagerAdapter {
private final SparseArray<WeakReference<Fragment>> mFragmentArray = new SparseArray<>();
private final List<Holder> mHolderList = new ArrayList<>();
@NonNull
private final Context mContext;
public MusicLibraryPagerAdapter(@NonNull final Context context, final FragmentManager fragmentManager) {
super(fragmentManager);
mContext = context;
setCategoryInfos(PreferenceUtil.getInstance(context).getLibraryCategories());
}
public void setCategoryInfos(@NonNull List<CategoryInfo> categoryInfos) {
mHolderList.clear();
for (CategoryInfo categoryInfo : categoryInfos) {
if (categoryInfo.visible) {
MusicFragments fragment = MusicFragments.valueOf(categoryInfo.category.toString());
Holder holder = new Holder();
holder.mClassName = fragment.getFragmentClass().getName();
holder.title = mContext.getResources()
.getString(categoryInfo.category.stringRes)
.toUpperCase(Locale.getDefault());
mHolderList.add(holder);
}
}
alignCache();
notifyDataSetChanged();
}
public Fragment getFragment(final int position) {
final WeakReference<Fragment> mWeakFragment = mFragmentArray.get(position);
if (mWeakFragment != null && mWeakFragment.get() != null) {
return mWeakFragment.get();
}
return getItem(position);
}
@Override
public int getItemPosition(@NonNull Object fragment) {
for (int i = 0, size = mHolderList.size(); i < size; i++) {
Holder holder = mHolderList.get(i);
if (holder.mClassName.equals(fragment.getClass().getName())) {
return i;
}
}
return POSITION_NONE;
}
@Override
public long getItemId(int position) {
// as fragment position is not fixed, we can't use position as id
return MusicFragments.of(getFragment(position).getClass()).ordinal();
}
@NonNull
@Override
public Object instantiateItem(@NonNull final ViewGroup container, final int position) {
final Fragment mFragment = (Fragment) super.instantiateItem(container, position);
final WeakReference<Fragment> mWeakFragment = mFragmentArray.get(position);
if (mWeakFragment != null) {
mWeakFragment.clear();
}
mFragmentArray.put(position, new WeakReference<>(mFragment));
return mFragment;
}
@Override
public Fragment getItem(final int position) {
final Holder mCurrentHolder = mHolderList.get(position);
return Fragment.instantiate(mContext, mCurrentHolder.mClassName, mCurrentHolder.mParams);
}
@Override
public void destroyItem(final ViewGroup container, final int position, final Object object) {
super.destroyItem(container, position, object);
final WeakReference<Fragment> mWeakFragment = mFragmentArray.get(position);
if (mWeakFragment != null) {
mWeakFragment.clear();
}
}
@Override
public int getCount() {
return mHolderList.size();
}
@NonNull
@Override
public CharSequence getPageTitle(final int position) {
return mHolderList.get(position).title;
}
/**
* Aligns the fragment cache with the current category layout.
*/
private void alignCache() {
if (mFragmentArray.size() == 0) return;
HashMap<String, WeakReference<Fragment>> mappings = new HashMap<>(mFragmentArray.size());
for (int i = 0, size = mFragmentArray.size(); i < size; i++) {
WeakReference<Fragment> ref = mFragmentArray.valueAt(i);
Fragment fragment = ref.get();
if (fragment != null) {
mappings.put(fragment.getClass().getName(), ref);
}
}
for (int i = 0, size = mHolderList.size(); i < size; i++) {
WeakReference<Fragment> ref = mappings.get(mHolderList.get(i).mClassName);
if (ref != null) {
mFragmentArray.put(i, ref);
} else {
mFragmentArray.remove(i);
}
}
}
public enum MusicFragments {
SONGS(SongsFragment.class),
ALBUMS(AlbumsFragment.class),
ARTISTS(ArtistsFragment.class),
GENRES(GenresFragment.class),
PLAYLISTS(PlaylistsFragment.class);
private final Class<? extends Fragment> mFragmentClass;
MusicFragments(final Class<? extends Fragment> fragmentClass) {
mFragmentClass = fragmentClass;
}
public Class<? extends Fragment> getFragmentClass() {
return mFragmentClass;
}
public static MusicFragments of(Class<?> cl) {
MusicFragments[] fragments = All.FRAGMENTS;
for (MusicFragments fragment : fragments) {
if (cl.equals(fragment.mFragmentClass)) {
return fragment;
}
}
throw new IllegalArgumentException("Unknown music fragment " + cl);
}
private static class All {
public static final MusicFragments[] FRAGMENTS = values();
}
}
private final static class Holder {
String mClassName;
Bundle mParams;
String title;
}
}

View file

@ -0,0 +1,175 @@
package com.dkanada.gramophone.adapter;
import android.graphics.drawable.Drawable;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupMenu;
import com.bumptech.glide.Glide;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.base.AbsMultiSelectAdapter;
import com.dkanada.gramophone.adapter.base.MediaEntryViewHolder;
import com.dkanada.gramophone.dialogs.DeletePlaylistDialog;
import com.dkanada.gramophone.glide.CustomGlideRequest;
import com.dkanada.gramophone.glide.CustomPaletteTarget;
import com.dkanada.gramophone.helper.menu.PlaylistMenuHelper;
import com.dkanada.gramophone.helper.menu.SongsMenuHelper;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Playlist;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.NavigationUtil;
import java.util.ArrayList;
import java.util.List;
public class PlaylistAdapter extends AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist> {
protected final AppCompatActivity activity;
protected List<Playlist> dataSet;
protected int itemLayoutRes;
public PlaylistAdapter(AppCompatActivity activity, List<Playlist> dataSet, @LayoutRes int itemLayoutRes, @Nullable CabHolder cabHolder) {
super(activity, cabHolder, R.menu.menu_playlists_selection);
this.activity = activity;
this.dataSet = dataSet;
this.itemLayoutRes = itemLayoutRes;
setHasStableIds(true);
}
public List<Playlist> getDataSet() {
return dataSet;
}
public void swapDataSet(List<Playlist> dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
@Override
public long getItemId(int position) {
return dataSet.get(position).hashCode();
}
@Override
@NonNull
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return createViewHolder(view, viewType);
}
protected ViewHolder createViewHolder(View view, int viewType) {
return new ViewHolder(view, viewType);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final Playlist playlist = dataSet.get(position);
holder.itemView.setActivated(isChecked(playlist));
if (holder.title != null) {
holder.title.setText(playlist.name);
}
if (holder.getAdapterPosition() == getItemCount() - 1) {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.GONE);
}
} else {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.VISIBLE);
}
}
loadImage(playlist, holder);
}
protected void loadImage(Playlist playlist, final PlaylistAdapter.ViewHolder holder) {
if (holder.image == null) return;
CustomGlideRequest.Builder
.from(Glide.with(activity), playlist.id)
.generatePalette(activity).build()
.into(new CustomPaletteTarget(holder.image) {
@Override
public void onLoadCleared(Drawable placeholder) {
super.onLoadCleared(placeholder);
}
@Override
public void onColorReady(int color) {
}
});
}
@Override
public int getItemCount() {
return dataSet.size();
}
@Override
protected Playlist getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected String getName(Playlist playlist) {
return playlist.name;
}
@Override
protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List<Playlist> selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_playlist:
DeletePlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST");
break;
default:
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.getItemId());
break;
}
}
@NonNull
private List<Song> getSongList(@NonNull List<Playlist> playlists) {
final List<Song> songs = new ArrayList<>();
return songs;
}
public class ViewHolder extends MediaEntryViewHolder {
public ViewHolder(@NonNull View itemView, int itemViewType) {
super(itemView);
if (menu != null) {
menu.setOnClickListener(view -> {
final PopupMenu popupMenu = new PopupMenu(activity, view);
popupMenu.inflate(R.menu.menu_item_playlist);
popupMenu.setOnMenuItemClickListener(item -> PlaylistMenuHelper.handleMenuClick(activity, dataSet.get(getAdapterPosition()), item));
popupMenu.show();
});
}
}
@Override
public void onClick(View view) {
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
Playlist playlist = dataSet.get(getAdapterPosition());
NavigationUtil.goToPlaylist(activity, playlist);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
}

View file

@ -0,0 +1,167 @@
package com.dkanada.gramophone.adapter;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.bumptech.glide.Glide;
import com.kabouzeid.appthemehelper.util.ATHUtil;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.base.MediaEntryViewHolder;
import com.dkanada.gramophone.glide.CustomGlideRequest;
import com.dkanada.gramophone.helper.MusicPlayerRemote;
import com.dkanada.gramophone.helper.menu.SongMenuHelper;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.model.Artist;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.MusicUtil;
import com.dkanada.gramophone.util.NavigationUtil;
import java.util.ArrayList;
import java.util.List;
public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder> {
private static final int HEADER = 0;
private static final int ALBUM = 1;
private static final int ARTIST = 2;
private static final int SONG = 3;
private final AppCompatActivity activity;
private List<Object> dataSet;
public SearchAdapter(@NonNull AppCompatActivity activity, @NonNull List<Object> dataSet) {
this.activity = activity;
this.dataSet = dataSet;
}
public void swapDataSet(@NonNull List<Object> dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
@Override
public int getItemViewType(int position) {
if (dataSet.get(position) instanceof Album) return ALBUM;
if (dataSet.get(position) instanceof Artist) return ARTIST;
if (dataSet.get(position) instanceof Song) return SONG;
return HEADER;
}
@Override
@NonNull
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == HEADER)
return new ViewHolder(LayoutInflater.from(activity).inflate(R.layout.sub_header, parent, false), viewType);
return new ViewHolder(LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false), viewType);
}
@SuppressWarnings("ConstantConditions")
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case ALBUM:
final Album album = (Album) dataSet.get(position);
holder.title.setText(album.getTitle());
holder.text.setText(MusicUtil.getAlbumInfoString(activity, album));
CustomGlideRequest.Builder
.from(Glide.with(activity), album.primary)
.build().into(holder.image);
break;
case ARTIST:
final Artist artist = (Artist) dataSet.get(position);
holder.title.setText(artist.getName());
holder.text.setText(MusicUtil.getArtistInfoString(activity, artist));
CustomGlideRequest.Builder
.from(Glide.with(activity), artist.primary)
.build().into(holder.image);
break;
case SONG:
final Song song = (Song) dataSet.get(position);
holder.title.setText(song.title);
holder.text.setText(MusicUtil.getSongInfoString(song));
break;
default:
holder.title.setText(dataSet.get(position).toString());
break;
}
}
@Override
public int getItemCount() {
return dataSet.size();
}
public class ViewHolder extends MediaEntryViewHolder {
public ViewHolder(@NonNull View itemView, int itemViewType) {
super(itemView);
itemView.setOnLongClickListener(null);
if (itemViewType != HEADER) {
itemView.setBackgroundColor(ATHUtil.resolveColor(activity, R.attr.cardBackgroundColor));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
itemView.setElevation(activity.getResources().getDimensionPixelSize(R.dimen.card_elevation));
}
if (shortSeparator != null) {
shortSeparator.setVisibility(View.GONE);
}
}
if (menu != null) {
if (itemViewType == SONG) {
menu.setVisibility(View.VISIBLE);
menu.setOnClickListener(new SongMenuHelper.OnClickSongMenu(activity) {
@Override
public Song getSong() {
return (Song) dataSet.get(getAdapterPosition());
}
});
} else {
menu.setVisibility(View.GONE);
}
}
switch (itemViewType) {
case ALBUM:
setImageTransitionName(activity.getString(R.string.transition_album_art));
break;
case ARTIST:
setImageTransitionName(activity.getString(R.string.transition_artist_image));
break;
default:
View container = itemView.findViewById(R.id.image_container);
if (container != null) {
container.setVisibility(View.GONE);
}
break;
}
}
@Override
public void onClick(View view) {
Object item = dataSet.get(getAdapterPosition());
switch (getItemViewType()) {
case ALBUM:
NavigationUtil.goToAlbum(activity,
(Album) item,
Pair.create(image, activity.getResources().getString(R.string.transition_album_art)));
break;
case ARTIST:
NavigationUtil.goToArtist(activity,
(Artist) item,
Pair.create(image, activity.getResources().getString(R.string.transition_artist_image)));
break;
case SONG:
List<Song> playList = new ArrayList<>();
playList.add((Song) item);
MusicPlayerRemote.openQueue(playList, 0, true);
break;
}
}
}
}

View file

@ -0,0 +1,232 @@
package com.dkanada.gramophone.adapter.album;
import android.graphics.drawable.Drawable;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import com.bumptech.glide.Glide;
import com.kabouzeid.appthemehelper.util.ColorUtil;
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.base.AbsMultiSelectAdapter;
import com.dkanada.gramophone.adapter.base.MediaEntryViewHolder;
import com.dkanada.gramophone.glide.CustomGlideRequest;
import com.dkanada.gramophone.glide.CustomPaletteTarget;
import com.dkanada.gramophone.helper.menu.SongsMenuHelper;
import com.dkanada.gramophone.helper.sort.SortMethod;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.MusicUtil;
import com.dkanada.gramophone.util.NavigationUtil;
import com.dkanada.gramophone.util.PreferenceUtil;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.ArrayList;
import java.util.List;
public class AlbumAdapter extends AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album> implements FastScrollRecyclerView.SectionedAdapter {
protected final AppCompatActivity activity;
protected List<Album> dataSet;
protected int itemLayoutRes;
protected boolean usePalette;
public AlbumAdapter(@NonNull AppCompatActivity activity, List<Album> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, cabHolder, R.menu.menu_media_selection);
this.activity = activity;
this.dataSet = dataSet;
this.itemLayoutRes = itemLayoutRes;
this.usePalette = usePalette;
setHasStableIds(true);
}
public void usePalette(boolean usePalette) {
this.usePalette = usePalette;
notifyDataSetChanged();
}
public void swapDataSet(List<Album> dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
public List<Album> getDataSet() {
return dataSet;
}
@Override
@NonNull
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return createViewHolder(view, viewType);
}
protected ViewHolder createViewHolder(View view, int viewType) {
return new ViewHolder(view);
}
protected String getAlbumTitle(Album album) {
return album.getTitle();
}
protected String getAlbumText(Album album) {
return MusicUtil.getAlbumInfoString(activity, album);
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
final Album album = dataSet.get(position);
final boolean isChecked = isChecked(album);
holder.itemView.setActivated(isChecked);
if (holder.getAdapterPosition() == getItemCount() - 1) {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.GONE);
}
} else {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.VISIBLE);
}
}
if (holder.title != null) {
holder.title.setText(getAlbumTitle(album));
}
if (holder.text != null) {
holder.text.setText(getAlbumText(album));
}
loadAlbumCover(album, holder);
}
protected void setColors(int color, ViewHolder holder) {
if (holder.paletteColorContainer != null) {
holder.paletteColorContainer.setBackgroundColor(color);
if (holder.title != null) {
holder.title.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color)));
}
if (holder.text != null) {
holder.text.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color)));
}
}
}
protected void loadAlbumCover(Album album, final ViewHolder holder) {
if (holder.image == null) return;
CustomGlideRequest.Builder
.from(Glide.with(activity), album.primary)
.generatePalette(activity).build()
.into(new CustomPaletteTarget(holder.image) {
@Override
public void onLoadCleared(Drawable placeholder) {
super.onLoadCleared(placeholder);
setColors(getDefaultFooterColor(), holder);
}
@Override
public void onColorReady(int color) {
if (usePalette) {
setColors(color, holder);
} else {
setColors(getDefaultFooterColor(), holder);
}
}
});
}
@Override
public int getItemCount() {
return dataSet.size();
}
@Override
public long getItemId(int position) {
return dataSet.get(position).hashCode();
}
@Override
protected Album getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected String getName(Album album) {
return album.getTitle();
}
@Override
protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List<Album> selection) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.getItemId());
}
@NonNull
private List<Song> getSongList(@NonNull List<Album> albums) {
final List<Song> songs = new ArrayList<>();
for (Album album : albums) {
songs.addAll(album.songs);
}
return songs;
}
@NonNull
@Override
public String getSectionName(int position) {
@Nullable String sectionName = null;
switch (PreferenceUtil.getInstance(activity).getAlbumSortMethod()) {
case SortMethod.NAME:
sectionName = dataSet.get(position).getTitle();
break;
case SortMethod.ARTIST:
sectionName = dataSet.get(position).getArtistName();
break;
case SortMethod.YEAR:
return MusicUtil.getYearString(dataSet.get(position).getYear());
case SortMethod.RANDOM:
return activity.getResources().getString(R.string.random);
}
return MusicUtil.getSectionName(sectionName);
}
public class ViewHolder extends MediaEntryViewHolder {
public ViewHolder(@NonNull final View itemView) {
super(itemView);
setImageTransitionName(activity.getString(R.string.transition_album_art));
if (menu != null) {
menu.setVisibility(View.GONE);
}
}
@Override
public void onClick(View v) {
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
Pair[] albumPairs = new Pair[]{Pair.create(image, activity.getResources().getString(R.string.transition_album_art))};
NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()), albumPairs);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
}

View file

@ -0,0 +1,84 @@
package com.dkanada.gramophone.adapter.album;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import android.view.View;
import android.view.ViewGroup;
import com.bumptech.glide.Glide;
import com.kabouzeid.appthemehelper.util.ColorUtil;
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
import com.dkanada.gramophone.glide.CustomGlideRequest;
import com.dkanada.gramophone.glide.CustomPaletteTarget;
import com.dkanada.gramophone.helper.HorizontalAdapterHelper;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.util.MusicUtil;
import java.util.List;
public class HorizontalAlbumAdapter extends AlbumAdapter {
public HorizontalAlbumAdapter(@NonNull AppCompatActivity activity, List<Album> dataSet, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, usePalette, cabHolder);
}
@Override
protected ViewHolder createViewHolder(View view, int viewType) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
HorizontalAdapterHelper.applyMarginToLayoutParams(activity, params, viewType);
return new ViewHolder(view);
}
@Override
protected void setColors(int color, ViewHolder holder) {
if (holder.itemView != null) {
CardView card=(CardView)holder.itemView;
card.setCardBackgroundColor(color);
if (holder.title != null) {
holder.title.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color)));
}
if (holder.text != null) {
holder.text.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color)));
}
}
}
@Override
protected void loadAlbumCover(Album album, final ViewHolder holder) {
if (holder.image == null) return;
CustomGlideRequest.Builder
.from(Glide.with(activity), album.primary)
.generatePalette(activity).build()
.into(new CustomPaletteTarget(holder.image) {
@Override
public void onLoadCleared(Drawable placeholder) {
super.onLoadCleared(placeholder);
setColors(getAlbumArtistFooterColor(), holder);
}
@Override
public void onColorReady(int color) {
if (usePalette) {
setColors(color, holder);
} else {
setColors(getAlbumArtistFooterColor(), holder);
}
}
});
}
@Override
protected String getAlbumText(Album album) {
return MusicUtil.getYearString(album.getYear());
}
@Override
public int getItemViewType(int position) {
return HorizontalAdapterHelper.getItemViewtype(position, getItemCount());
}
}

View file

@ -0,0 +1,209 @@
package com.dkanada.gramophone.adapter.artist;
import android.graphics.drawable.Drawable;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import com.bumptech.glide.Glide;
import com.kabouzeid.appthemehelper.util.ColorUtil;
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.base.AbsMultiSelectAdapter;
import com.dkanada.gramophone.adapter.base.MediaEntryViewHolder;
import com.dkanada.gramophone.glide.CustomGlideRequest;
import com.dkanada.gramophone.glide.CustomPaletteTarget;
import com.dkanada.gramophone.helper.menu.SongsMenuHelper;
import com.dkanada.gramophone.helper.sort.SortMethod;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Artist;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.MusicUtil;
import com.dkanada.gramophone.util.NavigationUtil;
import com.dkanada.gramophone.util.PreferenceUtil;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.ArrayList;
import java.util.List;
public class ArtistAdapter extends AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist> implements FastScrollRecyclerView.SectionedAdapter {
protected final AppCompatActivity activity;
protected List<Artist> dataSet;
protected int itemLayoutRes;
protected boolean usePalette;
public ArtistAdapter(@NonNull AppCompatActivity activity, List<Artist> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, cabHolder, R.menu.menu_media_selection);
this.activity = activity;
this.dataSet = dataSet;
this.itemLayoutRes = itemLayoutRes;
this.usePalette = usePalette;
setHasStableIds(true);
}
public void swapDataSet(List<Artist> dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
public List<Artist> getDataSet() {
return dataSet;
}
public void usePalette(boolean usePalette) {
this.usePalette = usePalette;
notifyDataSetChanged();
}
@Override
public long getItemId(int position) {
return dataSet.get(position).hashCode();
}
@Override
@NonNull
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return createViewHolder(view);
}
protected ViewHolder createViewHolder(View view) {
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
final Artist artist = dataSet.get(position);
boolean isChecked = isChecked(artist);
holder.itemView.setActivated(isChecked);
if (holder.getAdapterPosition() == getItemCount() - 1) {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.GONE);
}
} else {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.VISIBLE);
}
}
if (holder.title != null) {
holder.title.setText(artist.getName());
}
if (holder.text != null) {
holder.text.setText(MusicUtil.getArtistInfoString(activity, artist));
}
holder.itemView.setActivated(isChecked(artist));
loadArtistImage(artist, holder);
}
private void setColors(int color, ViewHolder holder) {
if (holder.paletteColorContainer != null) {
holder.paletteColorContainer.setBackgroundColor(color);
if (holder.title != null) {
holder.title.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color)));
}
if (holder.text != null) {
holder.text.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color)));
}
}
}
protected void loadArtistImage(Artist artist, final ViewHolder holder) {
if (holder.image == null) return;
CustomGlideRequest.Builder
.from(Glide.with(activity), artist.primary)
.generatePalette(activity).build()
.into(new CustomPaletteTarget(holder.image) {
@Override
public void onLoadCleared(Drawable placeholder) {
super.onLoadCleared(placeholder);
setColors(getDefaultFooterColor(), holder);
}
@Override
public void onColorReady(int color) {
if (usePalette) {
setColors(color, holder);
} else {
setColors(getDefaultFooterColor(), holder);
}
}
});
}
@Override
public int getItemCount() {
return dataSet.size();
}
@Override
protected Artist getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected String getName(Artist artist) {
return artist.getName();
}
@Override
protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List<Artist> selection) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.getItemId());
}
@NonNull
private List<Song> getSongList(@NonNull List<Artist> artists) {
final List<Song> songs = new ArrayList<>();
for (Artist artist : artists) {
songs.addAll(artist.getSongs());
}
return songs;
}
@NonNull
@Override
public String getSectionName(int position) {
return MusicUtil.getSectionName(dataSet.get(position).getName());
}
public class ViewHolder extends MediaEntryViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
setImageTransitionName(activity.getString(R.string.transition_artist_image));
if (menu != null) {
menu.setVisibility(View.GONE);
}
}
@Override
public void onClick(View v) {
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
Pair[] artistPairs = new Pair[]{Pair.create(image, activity.getResources().getString(R.string.transition_artist_image))};
NavigationUtil.goToArtist(activity, dataSet.get(getAdapterPosition()), artistPairs);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
}

View file

@ -0,0 +1,125 @@
package com.dkanada.gramophone.adapter.base;
import android.content.Context;
import androidx.annotation.MenuRes;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import com.afollestad.materialcab.MaterialCab;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.interfaces.CabHolder;
import java.util.ArrayList;
import java.util.List;
public abstract class AbsMultiSelectAdapter<VH extends RecyclerView.ViewHolder, I> extends RecyclerView.Adapter<VH> implements MaterialCab.Callback {
private final Context context;
private final CabHolder cabHolder;
private int menuRes;
private MaterialCab cab;
private List<I> checked;
public AbsMultiSelectAdapter(Context context, @Nullable CabHolder cabHolder, @MenuRes int menuRes) {
this.context = context;
this.cabHolder = cabHolder;
this.menuRes = menuRes;
this.checked = new ArrayList<>();
}
protected void setMultiSelectMenuRes(@MenuRes int menuRes) {
this.menuRes = menuRes;
}
protected boolean toggleChecked(final int position) {
if (cabHolder != null) {
I identifier = getIdentifier(position);
if (identifier == null) return false;
if (!checked.remove(identifier)) checked.add(identifier);
notifyItemChanged(position);
updateCab();
return true;
}
return false;
}
protected void checkAll() {
if (cabHolder != null) {
checked.clear();
for (int i = 0; i < getItemCount(); i++) {
I identifier = getIdentifier(i);
if (identifier != null) {
checked.add(identifier);
}
}
notifyDataSetChanged();
updateCab();
}
}
private void updateCab() {
if (cabHolder != null) {
if (cab == null || !cab.isActive()) {
cab = cabHolder.openCab(menuRes, this);
}
final int size = checked.size();
if (size <= 0) cab.finish();
else if (size == 1) cab.setTitle(getName(checked.get(0)));
else cab.setTitle(context.getString(R.string.x_selected, size));
}
}
private void clearChecked() {
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) {
if (menuItem.getItemId() == R.id.action_multi_select_adapter_check_all) {
checkAll();
} else {
onMultipleItemAction(menuItem, new ArrayList<>(checked));
cab.finish();
clearChecked();
}
return true;
}
@Override
public boolean onCabFinished(MaterialCab materialCab) {
clearChecked();
return true;
}
protected String getName(I object) {
return object.toString();
}
@Nullable
protected abstract I getIdentifier(int position);
protected abstract void onMultipleItemAction(MenuItem menuItem, List<I> selection);
}

View file

@ -0,0 +1,75 @@
package com.dkanada.gramophone.adapter.base;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.dkanada.gramophone.R;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MediaEntryViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
@Nullable
@BindView(R.id.image)
public ImageView image;
@Nullable
@BindView(R.id.image_text)
public TextView imageText;
@Nullable
@BindView(R.id.title)
public TextView title;
@Nullable
@BindView(R.id.text)
public TextView text;
@Nullable
@BindView(R.id.menu)
public View menu;
@Nullable
@BindView(R.id.separator)
public View separator;
@Nullable
@BindView(R.id.short_separator)
public View shortSeparator;
@Nullable
@BindView(R.id.drag_view)
public View dragView;
@Nullable
@BindView(R.id.palette_color_container)
public View paletteColorContainer;
public MediaEntryViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
protected void setImageTransitionName(@NonNull String transitionName) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && image != null) {
image.setTransitionName(transitionName);
}
}
@Override
public boolean onLongClick(View v) {
return false;
}
@Override
public void onClick(View v) {
}
}

View file

@ -0,0 +1,112 @@
package com.dkanada.gramophone.adapter.song;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.helper.MusicPlayerRemote;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Song;
import java.util.List;
public abstract class AbsOffsetSongAdapter extends SongAdapter {
protected static final int OFFSET_ITEM = 0;
protected static final int SONG = 1;
public AbsOffsetSongAdapter(AppCompatActivity activity, List<Song> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
}
public AbsOffsetSongAdapter(AppCompatActivity activity, List<Song> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, boolean showSectionName) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, showSectionName);
}
@NonNull
@Override
public SongAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == OFFSET_ITEM) {
View view = LayoutInflater.from(activity).inflate(R.layout.item_list_single_row, parent, false);
return createViewHolder(view);
}
return super.onCreateViewHolder(parent, viewType);
}
@Override
protected SongAdapter.ViewHolder createViewHolder(View view) {
return new AbsOffsetSongAdapter.ViewHolder(view);
}
@Override
public long getItemId(int position) {
position--;
if (position < 0) return -2;
return super.getItemId(position);
}
@Nullable
@Override
protected Song getIdentifier(int position) {
position--;
if (position < 0) return null;
return super.getIdentifier(position);
}
@Override
public int getItemCount() {
int superItemCount = super.getItemCount();
return superItemCount == 0 ? 0 : superItemCount + 1;
}
@Override
public int getItemViewType(int position) {
return position == 0 ? OFFSET_ITEM : SONG;
}
@NonNull
@Override
public String getSectionName(int position) {
position--;
if (position < 0) return "";
return super.getSectionName(position);
}
public class ViewHolder extends SongAdapter.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
protected Song getSong() {
// return empty song just to be safe
if (getItemViewType() == OFFSET_ITEM) return Song.EMPTY_SONG;
return dataSet.get(getAdapterPosition() - 1);
}
@Override
public void onClick(View v) {
if (isInQuickSelectMode() && getItemViewType() != OFFSET_ITEM) {
toggleChecked(getAdapterPosition());
} else {
MusicPlayerRemote.openQueue(dataSet, getAdapterPosition() - 1, true);
}
}
@Override
public boolean onLongClick(View view) {
if (getItemViewType() == OFFSET_ITEM) return false;
toggleChecked(getAdapterPosition());
return true;
}
}
}

View file

@ -0,0 +1,61 @@
package com.dkanada.gramophone.adapter.song;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.MusicUtil;
import java.util.List;
public class AlbumSongAdapter extends SongAdapter {
public AlbumSongAdapter(AppCompatActivity activity, List<Song> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
}
@Override
protected SongAdapter.ViewHolder createViewHolder(View view) {
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull SongAdapter.ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
final Song song = dataSet.get(position);
if (holder.imageText != null) {
final int trackNumber = MusicUtil.getFixedTrackNumber(song.trackNumber);
final String trackNumberString = trackNumber > 0 ? String.valueOf(trackNumber) : "-";
holder.imageText.setText(trackNumberString);
}
}
@Override
protected String getSongText(Song song) {
return MusicUtil.getReadableDurationString(song.duration);
}
public class ViewHolder extends SongAdapter.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
if (imageText != null) {
imageText.setVisibility(View.VISIBLE);
}
if (image != null) {
image.setVisibility(View.GONE);
}
}
}
@Override
protected void loadAlbumCover(Song song, SongAdapter.ViewHolder holder) {
// don't want to load it in this adapter
}
}

View file

@ -0,0 +1,188 @@
package com.dkanada.gramophone.adapter.song;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.materialcab.MaterialCab;
import com.bumptech.glide.Glide;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.glide.CustomGlideRequest;
import com.dkanada.gramophone.helper.MusicPlayerRemote;
import com.dkanada.gramophone.helper.menu.SongMenuHelper;
import com.dkanada.gramophone.helper.menu.SongsMenuHelper;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.NavigationUtil;
import java.util.ArrayList;
import java.util.List;
public class ArtistSongAdapter extends ArrayAdapter<Song> implements MaterialCab.Callback {
@Nullable
private final CabHolder cabHolder;
private MaterialCab cab;
private List<Song> dataSet;
private List<Song> checked;
@NonNull
private final AppCompatActivity activity;
public ArtistSongAdapter(@NonNull AppCompatActivity activity, @NonNull List<Song> dataSet, @Nullable CabHolder cabHolder) {
super(activity, R.layout.item_list, dataSet);
this.activity = activity;
this.cabHolder = cabHolder;
this.dataSet = dataSet;
checked = new ArrayList<>();
}
public List<Song> getDataSet() {
return dataSet;
}
public void swapDataSet(List<Song> dataSet) {
this.dataSet = dataSet;
clear();
addAll(dataSet);
notifyDataSetChanged();
}
@Override
@NonNull
public View getView(final int position, View convertView, @NonNull ViewGroup parent) {
final Song song = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_list, parent, false);
}
final TextView songTitle = convertView.findViewById(R.id.title);
final TextView songInfo = convertView.findViewById(R.id.text);
final ImageView albumArt = convertView.findViewById(R.id.image);
final View shortSeparator = convertView.findViewById(R.id.short_separator);
if (position == getCount() - 1) {
if (shortSeparator != null) {
shortSeparator.setVisibility(View.GONE);
}
} else {
if (shortSeparator != null) {
shortSeparator.setVisibility(View.VISIBLE);
}
}
songTitle.setText(song.title);
songInfo.setText(song.albumName);
CustomGlideRequest.Builder
.from(Glide.with(activity), song.primary)
.build().into(albumArt);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
albumArt.setTransitionName(activity.getString(R.string.transition_album_art));
}
final ImageView overflowButton = convertView.findViewById(R.id.menu);
overflowButton.setOnClickListener(new SongMenuHelper.OnClickSongMenu(activity) {
@Override
public Song getSong() {
return song;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.action_go_to_album) {
Pair[] albumPairs = new Pair[]{Pair.create(albumArt, activity.getResources().getString(R.string.transition_album_art))};
NavigationUtil.goToAlbum(activity, new Album(song), albumPairs);
return true;
}
return super.onMenuItemClick(item);
}
});
convertView.setActivated(isChecked(song));
convertView.setOnClickListener(view -> {
if (isInQuickSelectMode()) {
toggleChecked(song);
} else {
MusicPlayerRemote.openQueue(dataSet, position, true);
}
});
convertView.setOnLongClickListener(view -> {
toggleChecked(song);
return true;
});
return convertView;
}
private void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List<Song> selection) {
SongsMenuHelper.handleMenuClick(activity, selection, menuItem.getItemId());
}
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).title);
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(@NonNull MenuItem menuItem) {
onMultipleItemAction(menuItem, new ArrayList<>(checked));
cab.finish();
unCheckAll();
return true;
}
@Override
public boolean onCabFinished(MaterialCab materialCab) {
unCheckAll();
return true;
}
}

View file

@ -0,0 +1,135 @@
package com.dkanada.gramophone.adapter.song;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder;
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.dialogs.RemoveFromPlaylistDialog;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.ViewUtil;
import java.util.List;
public class OrderablePlaylistSongAdapter extends PlaylistSongAdapter implements DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
private OnMoveItemListener onMoveItemListener;
public OrderablePlaylistSongAdapter(@NonNull AppCompatActivity activity, @NonNull List<Song> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, @Nullable OnMoveItemListener onMoveItemListener) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
setMultiSelectMenuRes(R.menu.menu_playlists_songs_selection);
this.onMoveItemListener = onMoveItemListener;
}
@Override
protected SongAdapter.ViewHolder createViewHolder(View view) {
return new OrderablePlaylistSongAdapter.ViewHolder(view);
}
@Override
public long getItemId(int position) {
position--;
if (position < 0) return -2;
return dataSet.get(position).id.hashCode();
}
@Override
protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List<Song> selection) {
switch (menuItem.getItemId()) {
case R.id.action_remove_from_playlist:
RemoveFromPlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
return;
}
super.onMultipleItemAction(menuItem, selection);
}
@Override
public boolean onCheckCanStartDrag(ViewHolder holder, int position, int x, int y) {
return onMoveItemListener != null && position > 0 &&
(ViewUtil.hitTest(holder.dragView, x, y) || ViewUtil.hitTest(holder.image, x, y));
}
@Override
public ItemDraggableRange onGetItemDraggableRange(ViewHolder holder, int position) {
return new ItemDraggableRange(1, dataSet.size());
}
@Override
public void onMoveItem(int fromPosition, int toPosition) {
if (onMoveItemListener != null && fromPosition != toPosition) {
onMoveItemListener.onMoveItem(fromPosition - 1, toPosition - 1);
}
}
@Override
public boolean onCheckCanDrop(int draggingPosition, int dropPosition) {
return dropPosition > 0;
}
@Override
public void onItemDragStarted(int position) {
notifyDataSetChanged();
}
@Override
public void onItemDragFinished(int fromPosition, int toPosition, boolean result) {
notifyDataSetChanged();
}
public interface OnMoveItemListener {
void onMoveItem(int fromPosition, int toPosition);
}
public class ViewHolder extends PlaylistSongAdapter.ViewHolder implements DraggableItemViewHolder {
@DraggableItemStateFlags
private int mDragStateFlags;
public ViewHolder(@NonNull View itemView) {
super(itemView);
if (dragView != null) {
if (onMoveItemListener != null) {
dragView.setVisibility(View.VISIBLE);
} else {
dragView.setVisibility(View.GONE);
}
}
}
@Override
protected int getSongMenuRes() {
return R.menu.menu_item_playlist_song;
}
@Override
protected boolean onSongMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_remove_from_playlist:
RemoveFromPlaylistDialog.create(getSong()).show(activity.getSupportFragmentManager(), "REMOVE_FROM_PLAYLIST");
return true;
}
return super.onSongMenuItemClick(item);
}
@Override
public void setDragStateFlags(@DraggableItemStateFlags int flags) {
mDragStateFlags = flags;
}
@Override
@DraggableItemStateFlags
public int getDragStateFlags() {
return mDragStateFlags;
}
}
}

View file

@ -0,0 +1,170 @@
package com.dkanada.gramophone.adapter.song;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder;
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.helper.MusicPlayerRemote;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.ViewUtil;
import java.util.List;
public class PlayingQueueAdapter extends SongAdapter implements DraggableItemAdapter<PlayingQueueAdapter.ViewHolder> {
private static final int HISTORY = 0;
private static final int CURRENT = 1;
private static final int UP_NEXT = 2;
private int current;
public PlayingQueueAdapter(AppCompatActivity activity, List<Song> dataSet, int current, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
this.current = current;
}
@Override
protected SongAdapter.ViewHolder createViewHolder(View view) {
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull SongAdapter.ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
if (holder.imageText != null) {
holder.imageText.setText(String.valueOf(position - current));
}
if (holder.getItemViewType() == HISTORY || holder.getItemViewType() == CURRENT) {
setAlpha(holder, 0.5f);
}
}
@Override
public int getItemViewType(int position) {
if (position < current) {
return HISTORY;
} else if (position > current) {
return UP_NEXT;
}
return CURRENT;
}
@Override
protected void loadAlbumCover(Song song, SongAdapter.ViewHolder holder) {
// don't want to load it in this adapter
}
public void swapDataSet(List<Song> dataSet, int position) {
this.dataSet = dataSet;
current = position;
notifyDataSetChanged();
}
public void setCurrent(int current) {
this.current = current;
notifyDataSetChanged();
}
protected void setAlpha(SongAdapter.ViewHolder holder, float alpha) {
if (holder.image != null) {
holder.image.setAlpha(alpha);
}
if (holder.title != null) {
holder.title.setAlpha(alpha);
}
if (holder.text != null) {
holder.text.setAlpha(alpha);
}
if (holder.imageText != null) {
holder.imageText.setAlpha(alpha);
}
if (holder.paletteColorContainer != null) {
holder.paletteColorContainer.setAlpha(alpha);
}
}
@Override
public boolean onCheckCanStartDrag(ViewHolder holder, int position, int x, int y) {
return ViewUtil.hitTest(holder.imageText, x, y);
}
@Override
public ItemDraggableRange onGetItemDraggableRange(ViewHolder holder, int position) {
return null;
}
@Override
public void onMoveItem(int fromPosition, int toPosition) {
MusicPlayerRemote.moveSong(fromPosition, toPosition);
}
@Override
public boolean onCheckCanDrop(int draggingPosition, int dropPosition) {
return true;
}
@Override
public void onItemDragStarted(int position) {
notifyDataSetChanged();
}
@Override
public void onItemDragFinished(int fromPosition, int toPosition, boolean result) {
notifyDataSetChanged();
}
public class ViewHolder extends SongAdapter.ViewHolder implements DraggableItemViewHolder {
@DraggableItemStateFlags
private int mDragStateFlags;
public ViewHolder(@NonNull View itemView) {
super(itemView);
if (imageText != null) {
imageText.setVisibility(View.VISIBLE);
}
if (image != null) {
image.setVisibility(View.GONE);
}
}
@Override
protected int getSongMenuRes() {
return R.menu.menu_item_playing_queue_song;
}
@Override
protected boolean onSongMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_remove_from_queue:
MusicPlayerRemote.removeFromQueue(getAdapterPosition());
return true;
}
return super.onSongMenuItemClick(item);
}
@Override
public void setDragStateFlags(@DraggableItemStateFlags int flags) {
mDragStateFlags = flags;
}
@Override
@DraggableItemStateFlags
public int getDragStateFlags() {
return mDragStateFlags;
}
}
}

View file

@ -0,0 +1,94 @@
package com.dkanada.gramophone.adapter.song;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import androidx.appcompat.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
import com.kabouzeid.appthemehelper.ThemeStore;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.MusicUtil;
import com.dkanada.gramophone.util.NavigationUtil;
import java.util.ArrayList;
import java.util.List;
public class PlaylistSongAdapter extends AbsOffsetSongAdapter {
public PlaylistSongAdapter(AppCompatActivity activity, @NonNull List<Song> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, false);
setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection);
}
@Override
protected SongAdapter.ViewHolder createViewHolder(View view) {
return new PlaylistSongAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final SongAdapter.ViewHolder holder, int position) {
if (holder.getItemViewType() == OFFSET_ITEM) {
int textColor = ThemeStore.textColorSecondary(activity);
if (holder.title != null) {
holder.title.setText(MusicUtil.getPlaylistInfoString(activity, dataSet));
holder.title.setTextColor(textColor);
}
if (holder.text != null) {
holder.text.setVisibility(View.GONE);
}
if (holder.menu != null) {
holder.menu.setVisibility(View.GONE);
}
if (holder.image != null) {
final int padding = activity.getResources().getDimensionPixelSize(R.dimen.default_item_margin) / 2;
holder.image.setPadding(padding, padding, padding, padding);
holder.image.setColorFilter(textColor);
holder.image.setImageResource(R.drawable.ic_timer_white_24dp);
}
if (holder.dragView != null) {
holder.dragView.setVisibility(View.GONE);
}
if (holder.separator != null) {
holder.separator.setVisibility(View.VISIBLE);
}
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.GONE);
}
} else {
super.onBindViewHolder(holder, position - 1);
}
}
public class ViewHolder extends AbsOffsetSongAdapter.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
protected int getSongMenuRes() {
return R.menu.menu_item_cannot_delete_single_songs_playlist_song;
}
@Override
protected boolean onSongMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.action_go_to_album) {
Pair[] albumPairs = new Pair[]{Pair.create(image, activity.getString(R.string.transition_album_art))};
NavigationUtil.goToAlbum(activity, new Album(dataSet.get(getAdapterPosition() - 1)), albumPairs);
return true;
}
return super.onSongMenuItemClick(item);
}
}
}

View file

@ -0,0 +1,82 @@
package com.dkanada.gramophone.adapter.song;
import android.graphics.Typeface;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import com.kabouzeid.appthemehelper.ThemeStore;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.helper.MusicPlayerRemote;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Song;
import java.util.ArrayList;
import java.util.List;
public class ShuffleButtonSongAdapter extends AbsOffsetSongAdapter {
public ShuffleButtonSongAdapter(AppCompatActivity activity, List<Song> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
}
@Override
protected SongAdapter.ViewHolder createViewHolder(View view) {
return new ShuffleButtonSongAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final SongAdapter.ViewHolder holder, int position) {
if (holder.getItemViewType() == OFFSET_ITEM) {
int accentColor = ThemeStore.accentColor(activity);
if (holder.title != null) {
holder.title.setText(activity.getResources().getString(R.string.action_shuffle_all).toUpperCase());
holder.title.setTextColor(accentColor);
holder.title.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL));
}
if (holder.text != null) {
holder.text.setVisibility(View.GONE);
}
if (holder.menu != null) {
holder.menu.setVisibility(View.GONE);
}
if (holder.image != null) {
final int padding = activity.getResources().getDimensionPixelSize(R.dimen.default_item_margin) / 2;
holder.image.setPadding(padding, padding, padding, padding);
holder.image.setColorFilter(accentColor);
holder.image.setImageResource(R.drawable.ic_shuffle_white_24dp);
}
if (holder.separator != null) {
holder.separator.setVisibility(View.VISIBLE);
}
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.GONE);
}
} else {
super.onBindViewHolder(holder, position - 1);
}
}
public class ViewHolder extends AbsOffsetSongAdapter.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
public void onClick(View v) {
if (getItemViewType() == OFFSET_ITEM) {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true);
return;
}
super.onClick(v);
}
}
}

View file

@ -0,0 +1,276 @@
package com.dkanada.gramophone.adapter.song;
import android.graphics.drawable.Drawable;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import com.afollestad.materialcab.MaterialCab;
import com.bumptech.glide.Glide;
import com.kabouzeid.appthemehelper.util.ColorUtil;
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.base.AbsMultiSelectAdapter;
import com.dkanada.gramophone.adapter.base.MediaEntryViewHolder;
import com.dkanada.gramophone.glide.CustomGlideRequest;
import com.dkanada.gramophone.glide.CustomPaletteTarget;
import com.dkanada.gramophone.helper.MusicPlayerRemote;
import com.dkanada.gramophone.helper.menu.SongMenuHelper;
import com.dkanada.gramophone.helper.menu.SongsMenuHelper;
import com.dkanada.gramophone.helper.sort.SortMethod;
import com.dkanada.gramophone.interfaces.CabHolder;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.MusicUtil;
import com.dkanada.gramophone.util.NavigationUtil;
import com.dkanada.gramophone.util.PreferenceUtil;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.List;
public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song> implements MaterialCab.Callback, FastScrollRecyclerView.SectionedAdapter {
protected final AppCompatActivity activity;
protected List<Song> dataSet;
protected int itemLayoutRes;
protected boolean usePalette;
protected boolean showSectionName;
public SongAdapter(AppCompatActivity activity, List<Song> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
this(activity, dataSet, itemLayoutRes, usePalette, cabHolder, true);
}
public SongAdapter(AppCompatActivity activity, List<Song> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, boolean showSectionName) {
super(activity, cabHolder, R.menu.menu_media_selection);
this.activity = activity;
this.dataSet = dataSet;
this.itemLayoutRes = itemLayoutRes;
this.usePalette = usePalette;
this.showSectionName = showSectionName;
setHasStableIds(true);
}
public void swapDataSet(List<Song> dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
public void usePalette(boolean usePalette) {
this.usePalette = usePalette;
notifyDataSetChanged();
}
public List<Song> getDataSet() {
return dataSet;
}
@Override
public long getItemId(int position) {
return dataSet.get(position).hashCode();
}
@Override
@NonNull
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return createViewHolder(view);
}
protected ViewHolder createViewHolder(View view) {
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
final Song song = dataSet.get(position);
boolean isChecked = isChecked(song);
holder.itemView.setActivated(isChecked);
if (holder.getAdapterPosition() == getItemCount() - 1) {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.GONE);
}
} else {
if (holder.shortSeparator != null) {
holder.shortSeparator.setVisibility(View.VISIBLE);
}
}
if (holder.title != null) {
holder.title.setText(getSongTitle(song));
}
if (holder.text != null) {
holder.text.setText(getSongText(song));
}
loadAlbumCover(song, holder);
}
private void setColors(int color, ViewHolder holder) {
if (holder.paletteColorContainer != null) {
holder.paletteColorContainer.setBackgroundColor(color);
if (holder.title != null) {
holder.title.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color)));
}
if (holder.text != null) {
holder.text.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color)));
}
}
}
protected void loadAlbumCover(Song song, final ViewHolder holder) {
if (holder.image == null) return;
CustomGlideRequest.Builder
.from(Glide.with(activity), song.primary)
.generatePalette(activity).build()
.into(new CustomPaletteTarget(holder.image) {
@Override
public void onLoadCleared(Drawable placeholder) {
super.onLoadCleared(placeholder);
setColors(getDefaultFooterColor(), holder);
}
@Override
public void onColorReady(int color) {
if (usePalette) {
setColors(color, holder);
} else {
setColors(getDefaultFooterColor(), holder);
}
}
});
}
protected String getSongTitle(Song song) {
return song.title;
}
protected String getSongText(Song song) {
return MusicUtil.getSongInfoString(song);
}
@Override
public int getItemCount() {
return dataSet.size();
}
@Override
protected Song getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected String getName(Song song) {
return song.title;
}
@Override
protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List<Song> selection) {
SongsMenuHelper.handleMenuClick(activity, selection, menuItem.getItemId());
}
@NonNull
@Override
public String getSectionName(int position) {
if (!showSectionName) {
return "";
}
@Nullable String sectionName = null;
switch (PreferenceUtil.getInstance(activity).getSongSortMethod()) {
case SortMethod.NAME:
sectionName = dataSet.get(position).title;
break;
case SortMethod.ALBUM:
sectionName = dataSet.get(position).albumName;
break;
case SortMethod.ARTIST:
sectionName = dataSet.get(position).artistName;
break;
case SortMethod.YEAR:
return MusicUtil.getYearString(dataSet.get(position).year);
case SortMethod.RANDOM:
return activity.getResources().getString(R.string.random);
}
return MusicUtil.getSectionName(sectionName);
}
public class ViewHolder extends MediaEntryViewHolder {
protected int DEFAULT_MENU_RES = SongMenuHelper.MENU_RES;
public ViewHolder(@NonNull View itemView) {
super(itemView);
setImageTransitionName(activity.getString(R.string.transition_album_art));
if (menu == null) {
return;
}
menu.setOnClickListener(new SongMenuHelper.OnClickSongMenu(activity) {
@Override
public Song getSong() {
return ViewHolder.this.getSong();
}
@Override
public int getMenuRes() {
return getSongMenuRes();
}
@Override
public boolean onMenuItemClick(MenuItem item) {
return onSongMenuItemClick(item) || super.onMenuItemClick(item);
}
});
}
protected Song getSong() {
return dataSet.get(getAdapterPosition());
}
protected int getSongMenuRes() {
return DEFAULT_MENU_RES;
}
protected boolean onSongMenuItemClick(MenuItem item) {
if (image != null && image.getVisibility() == View.VISIBLE) {
switch (item.getItemId()) {
case R.id.action_go_to_album:
Pair[] albumPairs = new Pair[]{Pair.create(image, activity.getResources().getString(R.string.transition_album_art))};
NavigationUtil.goToAlbum(activity, new Album(getSong()), albumPairs);
return true;
}
}
return false;
}
@Override
public void onClick(View v) {
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
MusicPlayerRemote.openQueue(dataSet, getAdapterPosition(), true);
}
}
@Override
public boolean onLongClick(View view) {
return toggleChecked(getAdapterPosition());
}
}
}