Skip to content

Commit

Permalink
Bath remove favourite songs, improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
indywidualny committed Jun 4, 2016
1 parent 7a7f837 commit 56c1f50
Show file tree
Hide file tree
Showing 22 changed files with 304 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,10 @@ protected void onStart() {

@Override
public void onResume() {
super.onResume(); // Always call the superclass method first
super.onResume();

// schedule RDS updates
rdsLatest = null;
rdsHandler.post(rdsRunnable);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,27 @@
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.FrameLayout;

import org.indywidualni.centrumfm.R;
import org.indywidualni.centrumfm.activity.SongsActivity;
import org.indywidualni.centrumfm.rest.adapter.SongsAdapter;
import org.indywidualni.centrumfm.rest.model.Song;
import org.indywidualni.centrumfm.util.database.AsyncWrapper;
import org.indywidualni.centrumfm.util.database.DataSource;
import org.indywidualni.centrumfm.util.ui.AnimatedLayoutManager;
import org.indywidualni.centrumfm.util.ui.RecyclerViewEmptySupport;
import org.indywidualni.centrumfm.util.ui.SlidingTabLayout;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -41,8 +44,12 @@ public class FavouriteSongsFragment extends Fragment implements SearchView.OnQue
@BindView(R.id.empty_view) View emptyView;
private Unbinder unbinder;

private SlidingTabLayout slidingTabLayout;

private IFragmentToActivity mCallback;
private List<Song> songs = new ArrayList<>();
private ActionModeCallback actionModeCallback = new ActionModeCallback();
private ActionMode actionMode;
private SongsAdapter adapter;

@Override
Expand Down Expand Up @@ -73,6 +80,7 @@ public void onDetach() {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_song_favourite, container, false);
slidingTabLayout = ButterKnife.findById(getActivity(), R.id.tabs);
unbinder = ButterKnife.bind(this, view);
return view;
}
Expand All @@ -85,10 +93,11 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
songs = DataSource.getInstance().getFavouriteSongs();
Collections.sort(songs);
adapter = new SongsAdapter(this, songs);
adapter.setHasStableIds(true);

mRecyclerView.setHasFixedSize(true);
mRecyclerView.setEmptyView(emptyView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.setLayoutManager(new AnimatedLayoutManager(getActivity()));
mRecyclerView.setAdapter(adapter);
}

Expand Down Expand Up @@ -193,20 +202,29 @@ public boolean onQueryTextSubmit(String query) {
}

@Override
public void onContentClick(LinearLayout caller, int position) {
SongsActivity.currentPosition = position;
getActivity().openContextMenu(caller);
public void onContentClick(FrameLayout caller, int position) {
if (actionMode != null)
toggleSelection(position);
else {
SongsActivity.currentPosition = position;
getActivity().openContextMenu(caller);
}
}

@Override
public boolean onContentLongClick(int position) {
Log.e("Long Click", "Item: " + position);
if (actionMode == null) {
actionMode = ((AppCompatActivity) getActivity())
.startSupportActionMode(actionModeCallback);
}
toggleSelection(position);
return true;
}

@Override
public void onDestroyView() {
super.onDestroyView();
slidingTabLayout = null;
unbinder.unbind();
}

Expand All @@ -216,4 +234,69 @@ public interface IFragmentToActivity {
void shareSong(Song song);
}

/**
* Toggle the selection state of an item.
*
* If the item was the last one in the selection and is unselected, the selection is stopped.
* Note that the selection must already be started (actionMode must not be null).
*
* @param position Position of the item to toggle the selection state
*/
private void toggleSelection(int position) {
adapter.toggleSelection(position);
int count = adapter.getSelectedItemCount();

if (count == 0) {
actionMode.finish();
} else {
actionMode.setTitle(getResources().getQuantityString(R.plurals.songs_n_selected,
count, count));
actionMode.invalidate();
}
}

private class ActionModeCallback implements ActionMode.Callback {
@SuppressWarnings("unused")
private final String TAG = ActionModeCallback.class.getSimpleName();

@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate (R.menu.menu_actionmode_selected, menu);
slidingTabLayout.setVisibility(View.GONE);
return true;
}

@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}

@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete_selected:
List<Integer> selected = adapter.getSelectedItems();
List<Song> toRemove = new ArrayList<>();
for (int position : selected)
toRemove.add(adapter.getDataset().get(position));
songs.removeAll(toRemove);
adapter.getDataset().removeAll(toRemove);
adapter.notifyDataSetChanged();
AsyncWrapper.removeFavouriteSongs(toRemove);
mode.finish();
return true;

default:
return false;
}
}

@Override
public void onDestroyActionMode(ActionMode mode) {
adapter.clearSelection();
actionMode = null;
slidingTabLayout.setVisibility(View.VISIBLE);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.FrameLayout;

import org.indywidualni.centrumfm.R;
import org.indywidualni.centrumfm.activity.SongsActivity;
Expand Down Expand Up @@ -358,7 +358,7 @@ public void fabClicked() {
}

@Override
public void onContentClick(LinearLayout caller, int position) {
public void onContentClick(FrameLayout caller, int position) {
SongsActivity.currentPosition = position;
getActivity().openContextMenu(caller);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.indywidualni.centrumfm.rest.adapter;

import android.support.v7.widget.RecyclerView;
import android.util.SparseBooleanArray;

import java.util.ArrayList;
import java.util.List;

@SuppressWarnings("unused")
public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {

private static final String TAG = SelectableAdapter.class.getSimpleName();

private SparseBooleanArray selectedItems;

public SelectableAdapter() {
selectedItems = new SparseBooleanArray();
}

/**
* Indicates if the item at position position is selected
* @param position Position of the item to check
* @return true if the item is selected, false otherwise
*/
public boolean isSelected(int position) {
return getSelectedItems().contains(position);
}

/**
* Toggle the selection status of the item at a given position
* @param position Position of the item to toggle the selection status for
*/
public void toggleSelection(int position) {
if (selectedItems.get(position, false)) {
selectedItems.delete(position);
} else {
selectedItems.put(position, true);
}
notifyItemChanged(position);
}

/**
* Clear the selection status for all items
*/
public void clearSelection() {
List<Integer> selection = getSelectedItems();
selectedItems.clear();
for (Integer i : selection) {
notifyItemChanged(i);
}
}

/**
* Count the selected items
* @return Selected items count
*/
public int getSelectedItemCount() {
return selectedItems.size();
}

/**
* Indicates the list of selected items
* @return List of selected items ids
*/
public List<Integer> getSelectedItems() {
List<Integer> items = new ArrayList<>(selectedItems.size());
for (int i = 0; i < selectedItems.size(); ++i) {
items.add(selectedItems.keyAt(i));
}
return items;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.FrameLayout;
import android.widget.TextView;

import org.indywidualni.centrumfm.MyApplication;
Expand All @@ -16,7 +16,7 @@
import java.util.ArrayList;
import java.util.List;

public class SongsAdapter extends RecyclerView.Adapter<SongsAdapter.ViewHolder> {
public class SongsAdapter extends SelectableAdapter<SongsAdapter.ViewHolder> {

private List<Song> mDataset;
private ViewHolder.IViewHolderClicks viewHolderClicks;
Expand Down Expand Up @@ -53,6 +53,9 @@ else if (!TextUtils.isEmpty(mDataset.get(position).getSum()))
.getString(R.string.played_n_times, mDataset.get(position).getSum()));
else
viewHolder.getPlayed().setVisibility(View.GONE);

viewHolder.getSelectedOverlay().setVisibility(isSelected(position)
? View.VISIBLE : View.INVISIBLE);
}

// return the size of a dataset (invoked by the layout manager)
Expand All @@ -61,6 +64,12 @@ public int getItemCount() {
return mDataset.size();
}

// to use setHasStableIds(true)
@Override
public long getItemId(int position) {
return mDataset.get(position).hashCode();
}

// get current dataset
public final List<Song> getDataset() {
return mDataset;
Expand Down Expand Up @@ -128,34 +137,37 @@ private void applyAndAnimateMovedItems(List<Song> newModels) {
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,
View.OnLongClickListener {

private final LinearLayout linearLayout;
private final FrameLayout frameLayout;
private final TextView id;
private final TextView title;
private final TextView artist;
private final TextView played;
private final TextView duration;
private final View selectedOverlay;

private IViewHolderClicks mListener;

public ViewHolder(View v, IViewHolderClicks listener) {
super(v);
mListener = listener;

linearLayout = (LinearLayout) v.findViewById(R.id.element);
frameLayout = (FrameLayout) v.findViewById(R.id.element);
id = (TextView) v.findViewById(R.id.id);
title = (TextView) v.findViewById(R.id.title);
artist = (TextView) v.findViewById(R.id.artist);
played = (TextView) v.findViewById(R.id.played);
duration = (TextView) v.findViewById(R.id.duration);
selectedOverlay = v.findViewById(R.id.selectedOverlay);

linearLayout.setOnClickListener(this);
linearLayout.setOnLongClickListener(this);
frameLayout.setOnClickListener(this);
frameLayout.setOnLongClickListener(this);
}

@Override
public void onClick(View v) {
if (mListener != null) {
if (v instanceof LinearLayout)
mListener.onContentClick((LinearLayout) v, getAdapterPosition());
if (v instanceof FrameLayout)
mListener.onContentClick((FrameLayout) v, getAdapterPosition());
}
}

Expand Down Expand Up @@ -184,8 +196,12 @@ public TextView getDuration() {
return duration;
}

public View getSelectedOverlay() {
return selectedOverlay;
}

public interface IViewHolderClicks {
void onContentClick(LinearLayout caller, int position);
void onContentClick(FrameLayout caller, int position);
boolean onContentLongClick(int position);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,15 @@ protected Void doInBackground(Void... arg0) {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}

public static void removeFavouriteSongs(final List<Song> songs) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... arg0) {
for (Song song : songs)
DataSource.getInstance().removeFavouriteSong(song.getDbId());
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}

}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 56c1f50

Please sign in to comment.