package com.simplecity.amp_library.ui.fragments;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback;
import com.bignerdranch.android.multiselector.MultiSelector;
import com.simplecity.amp_library.R;
import com.simplecity.amp_library.model.AdaptableItem;
import com.simplecity.amp_library.model.Playlist;
import com.simplecity.amp_library.model.Song;
import com.simplecity.amp_library.sql.databases.BlacklistHelper;
import com.simplecity.amp_library.ui.adapters.SongAdapter;
import com.simplecity.amp_library.ui.modelviews.EmptyView;
import com.simplecity.amp_library.ui.modelviews.ShuffleView;
import com.simplecity.amp_library.ui.modelviews.SongView;
import com.simplecity.amp_library.utils.ColorUtils;
import com.simplecity.amp_library.utils.DataManager;
import com.simplecity.amp_library.utils.DialogUtils;
import com.simplecity.amp_library.utils.MenuUtils;
import com.simplecity.amp_library.utils.MusicUtils;
import com.simplecity.amp_library.utils.PermissionUtils;
import com.simplecity.amp_library.utils.PlaylistUtils;
import com.simplecity.amp_library.utils.ShuttleUtils;
import com.simplecity.amp_library.utils.SortManager;
import com.simplecity.amp_library.utils.ThemeUtils;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.Collections;
import java.util.List;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
public class SongFragment extends BaseFragment implements
MusicUtils.Defs,
RecyclerView.RecyclerListener,
SongAdapter.SongListener {
private static final String TAG = "SongFragment";
private static final String ARG_PAGE_TITLE = "page_title";
private SharedPreferences mPrefs;
private FastScrollRecyclerView mRecyclerView;
private SongAdapter songsAdapter;
MultiSelector multiSelector = new MultiSelector();
ActionMode actionMode;
boolean inActionMode = false;
private BroadcastReceiver mReceiver;
private SharedPreferences.OnSharedPreferenceChangeListener mSharedPreferenceChangeListener;
private boolean sortOrderChanged = false;
private Subscription subscription;
private ShuffleView shuffleView;
public SongFragment() {
}
public static SongFragment newInstance(String pageTitle) {
SongFragment fragment = new SongFragment();
Bundle args = new Bundle();
args.putString(ARG_PAGE_TITLE, pageTitle);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(final Bundle icicle) {
super.onCreate(icicle);
setHasOptionsMenu(true);
songsAdapter = new SongAdapter();
songsAdapter.setListener(this);
mPrefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals("restartLoader")) {
refreshAdapterItems();
}
}
};
mSharedPreferenceChangeListener = (sharedPreferences, key) -> {
if (key.equals("pref_theme_highlight_color") || key.equals("pref_theme_accent_color") || key.equals("pref_theme_white_accent")) {
songsAdapter.notifyItemRangeChanged(0, songsAdapter.getItemCount());
themeUIComponents();
} else if (key.equals("songWhitelist")) {
refreshAdapterItems();
}
};
mPrefs.registerOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
shuffleView = new ShuffleView();
}
private void themeUIComponents() {
ThemeUtils.themeRecyclerView(mRecyclerView);
mRecyclerView.setThumbColor(ColorUtils.getAccentColor());
mRecyclerView.setPopupBgColor(ColorUtils.getAccentColor());
mRecyclerView.setPopupTextColor(ColorUtils.getAccentColorSensitiveTextColor(getContext()));
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
ThemeUtils.themeRecyclerView(recyclerView);
super.onScrollStateChanged(recyclerView, newState);
}
});
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (mRecyclerView == null) {
mRecyclerView = (FastScrollRecyclerView) inflater.inflate(R.layout.fragment_recycler, container, false);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerView.setRecyclerListener(this);
mRecyclerView.setAdapter(songsAdapter);
themeUIComponents();
}
return mRecyclerView;
}
@Override
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("restartLoader");
getActivity().registerReceiver(mReceiver, filter);
refreshAdapterItems();
}
void refreshAdapterItems() {
PermissionUtils.RequestStoragePermissions(() -> {
if (getActivity() != null && isAdded()) {
boolean ascending = SortManager.getInstance().getSongsAscending();
subscription = DataManager.getInstance().getSongsRelay()
.flatMap(songs -> {
//Sort
SortManager.getInstance().sortSongs(songs);
//Reverse if required
if (!ascending) {
Collections.reverse(songs);
}
return Observable.from(songs)
.map(song -> (AdaptableItem) new SongView(song, multiSelector, null))
.toList();
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(items -> {
if (items.isEmpty()) {
songsAdapter.setEmpty(new EmptyView(R.string.empty_songlist));
} else {
items.add(0, shuffleView);
songsAdapter.setItems(items);
}
//Move the RV back to the top if we've had a sort order change.
if (sortOrderChanged) {
mRecyclerView.scrollToPosition(0);
}
sortOrderChanged = false;
});
}
}
);
}
@Override
public void onPause() {
if (mReceiver != null) {
getActivity().unregisterReceiver(mReceiver);
}
if (subscription != null) {
subscription.unsubscribe();
}
super.onPause();
}
@Override
public void onDestroy() {
mPrefs.unregisterOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
super.onDestroy();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_sort_songs, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
int sortOrder = SortManager.getInstance().getSongsSortOrder();
switch (sortOrder) {
case SortManager.SongSort.DEFAULT:
menu.findItem(R.id.sort_default).setChecked(true);
break;
case SortManager.SongSort.NAME:
menu.findItem(R.id.sort_song_name).setChecked(true);
break;
case SortManager.SongSort.TRACK_NUMBER:
menu.findItem(R.id.sort_song_track_number).setChecked(true);
break;
case SortManager.SongSort.DURATION:
menu.findItem(R.id.sort_song_duration).setChecked(true);
break;
case SortManager.SongSort.DATE:
menu.findItem(R.id.sort_song_date).setChecked(true);
break;
case SortManager.SongSort.YEAR:
menu.findItem(R.id.sort_song_year).setChecked(true);
break;
case SortManager.SongSort.ALBUM_NAME:
menu.findItem(R.id.sort_song_album_name).setChecked(true);
break;
case SortManager.SongSort.ARTIST_NAME:
menu.findItem(R.id.sort_song_artist_name).setChecked(true);
break;
}
menu.findItem(R.id.sort_ascending).setChecked(SortManager.getInstance().getSongsAscending());
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.sort_default:
SortManager.getInstance().setSongsSortOrder(SortManager.SongSort.DEFAULT);
sortOrderChanged = true;
break;
case R.id.sort_song_name:
SortManager.getInstance().setSongsSortOrder(SortManager.SongSort.NAME);
sortOrderChanged = true;
break;
case R.id.sort_song_track_number:
SortManager.getInstance().setSongsSortOrder(SortManager.SongSort.TRACK_NUMBER);
sortOrderChanged = true;
break;
case R.id.sort_song_duration:
SortManager.getInstance().setSongsSortOrder(SortManager.SongSort.DURATION);
sortOrderChanged = true;
break;
case R.id.sort_song_year:
SortManager.getInstance().setSongsSortOrder(SortManager.SongSort.YEAR);
sortOrderChanged = true;
break;
case R.id.sort_song_date:
SortManager.getInstance().setSongsSortOrder(SortManager.SongSort.DATE);
sortOrderChanged = true;
break;
case R.id.sort_song_album_name:
SortManager.getInstance().setSongsSortOrder(SortManager.SongSort.ALBUM_NAME);
sortOrderChanged = true;
break;
case R.id.sort_song_artist_name:
SortManager.getInstance().setSongsSortOrder(SortManager.SongSort.ARTIST_NAME);
sortOrderChanged = true;
break;
case R.id.sort_ascending:
SortManager.getInstance().setSongsAscending(!item.isChecked());
sortOrderChanged = true;
break;
}
if (sortOrderChanged) {
refreshAdapterItems();
getActivity().supportInvalidateOptionsMenu();
}
return super.onOptionsItemSelected(item);
}
@Override
public void onItemClick(View v, int position, Song song) {
if (inActionMode) {
multiSelector.setSelected(position, songsAdapter.getItemId(position), !multiSelector.isSelected(position, songsAdapter.getItemId(position)));
if (multiSelector.getSelectedPositions().size() == 0) {
if (actionMode != null) {
actionMode.finish();
}
}
updateActionModeSelectionCount();
} else {
List<Song> songs = Stream.of(songsAdapter.items)
.filter(adaptableItem -> adaptableItem instanceof SongView)
.map(adaptableItem -> ((SongView) adaptableItem).song)
.collect(Collectors.toList());
int pos = songs.indexOf(song);
MusicUtils.playAll(songs, pos, () -> {
final String message = getContext().getString(R.string.emptyplaylist);
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
});
}
}
@Override
public void onOverflowClick(View v, int position, final Song song) {
PopupMenu menu = new PopupMenu(SongFragment.this.getActivity(), v);
MenuUtils.addSongMenuOptions(getActivity(), menu);
MenuUtils.addClickHandler((AppCompatActivity) getActivity(), menu, song, item -> {
switch (item.getItemId()) {
case BLACKLIST: {
BlacklistHelper.addToBlacklist(song);
return true;
}
}
return false;
});
menu.show();
}
@Override
public void onLongClick(View v, int position, Song song) {
if (inActionMode) {
return;
}
if (multiSelector.getSelectedPositions().size() == 0) {
actionMode = ((AppCompatActivity) getActivity()).startSupportActionMode(mActionModeCallback);
inActionMode = true;
}
multiSelector.setSelected(position, songsAdapter.getItemId(position), !multiSelector.isSelected(position, songsAdapter.getItemId(position)));
updateActionModeSelectionCount();
}
@Override
public void onShuffleClick() {
MusicUtils.shuffleAll(getContext());
}
@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
//Nothing to do.
}
private void updateActionModeSelectionCount() {
if (actionMode != null && multiSelector != null) {
actionMode.setTitle(getString(R.string.action_mode_selection_count, multiSelector.getSelectedPositions().size()));
}
}
private ActionMode.Callback mActionModeCallback = new ModalMultiSelectorCallback(multiSelector) {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
ThemeUtils.themeContextualActionBar(getActivity());
inActionMode = true;
getActivity().getMenuInflater().inflate(R.menu.context_menu_songs, menu);
SubMenu sub = menu.getItem(0).getSubMenu();
PlaylistUtils.makePlaylistMenu(getActivity(), sub, SONG_FRAGMENT_GROUP_ID);
return true;
}
@Override
public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
final List<Song> checkedSongs = getCheckedSongs();
if (checkedSongs == null || checkedSongs.size() == 0) {
return true;
}
switch (item.getItemId()) {
case NEW_PLAYLIST:
PlaylistUtils.createPlaylistDialog(getActivity(), checkedSongs);
break;
case PLAYLIST_SELECTED:
Playlist playlist = (Playlist) item.getIntent().getSerializableExtra(ShuttleUtils.ARG_PLAYLIST);
PlaylistUtils.addToPlaylist(getContext(), playlist, checkedSongs);
break;
case R.id.delete:
new DialogUtils.DeleteDialogBuilder()
.context(getContext())
.singleMessageId(R.string.delete_song_desc)
.multipleMessage(R.string.delete_song_desc_multiple)
.itemNames(Stream.of(checkedSongs)
.map(song -> song.name)
.collect(Collectors.toList()))
.songsToDelete(Observable.just(checkedSongs))
.build()
.show();
mode.finish();
break;
case R.id.menu_add_to_queue:
MusicUtils.addToQueue(SongFragment.this.getActivity(), checkedSongs);
break;
}
return true;
}
@Override
public void onDestroyActionMode(ActionMode actionMode) {
super.onDestroyActionMode(actionMode);
inActionMode = false;
SongFragment.this.actionMode = null;
multiSelector.clearSelections();
}
};
List<Song> getCheckedSongs() {
return Stream.of(multiSelector.getSelectedPositions())
.map(i -> songsAdapter.getSong(i))
.collect(Collectors.toList());
}
@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
if (holder.getAdapterPosition() != -1) {
songsAdapter.items.get(holder.getAdapterPosition()).recycle(holder);
}
}
@Override
protected String screenName() {
return TAG;
}
}