/*
* Copyright (C) 2014 Fastboot Mobile, LLC.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, see <http://www.gnu.org/licenses>.
*/
package com.fastbootmobile.encore.app.adapters;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.fastbootmobile.encore.framework.PluginsLookup;
import com.fastbootmobile.encore.model.Playlist;
import com.fastbootmobile.encore.model.Song;
import com.fastbootmobile.encore.providers.IMusicProvider;
import com.fastbootmobile.encore.providers.ProviderAggregator;
import com.fastbootmobile.encore.providers.ProviderConnection;
import com.fastbootmobile.encore.providers.ProviderIdentifier;
import java.util.ArrayList;
import java.util.List;
/**
* Adapter showing playlists songs in a ListView. This is a derivative
* of {@link com.fastbootmobile.encore.app.adapters.SongsListAdapter} as the core display is similar,
* except PlaylistAdapter supports drag, drop and deletion of items.
*/
public class PlaylistAdapter extends SongsListAdapter {
private static final String TAG = "PlaylistAdapter";
private List<Integer> mVisible;
private List<Integer> mIds;
private Playlist mPlaylist;
/**
* Default constructor
*/
public PlaylistAdapter() {
super(true);
mVisible = new ArrayList<>();
mIds = new ArrayList<>();
}
/**
* Sets the playlist to display. This will call automatically {@link #notifyDataSetChanged()}.
* @param playlist The playlist to display
*/
public void setPlaylist(Playlist playlist) {
mPlaylist = playlist;
notifyDataSetChanged();
}
/**
* Calls the proper handler to update the playlist order
* @param oldPosition The old/current position of the item to move
* @param newPosition The new position of the item
*/
public void updatePlaylist(int oldPosition, int newPosition) {
final ProviderIdentifier providerIdentifier = mPlaylist.getProvider();
try {
ProviderConnection connection = PluginsLookup.getDefault().getProvider(providerIdentifier);
if (connection != null) {
IMusicProvider binder = connection.getBinder();
if (binder != null) {
binder.onUserSwapPlaylistItem(oldPosition, newPosition, mPlaylist.getRef());
}
}
} catch (RemoteException e) {
Log.e(TAG, "Error: " + e.getMessage());
}
}
/**
* Removes the provided item from the playlist on the view and from the playlist on the provider
* @param id The ID of the playlist
*/
public void delete(int id) {
final ProviderIdentifier providerIdentifier = mPlaylist.getProvider();
try {
ProviderConnection connection = PluginsLookup.getDefault().getProvider(providerIdentifier);
if (connection != null) {
IMusicProvider binder = connection.getBinder();
if (binder != null) {
binder.deleteSongFromPlaylist(id, mPlaylist.getRef());
}
}
mSongs.remove(id);
mIds.remove(id);
mVisible.remove(id);
resetIds();
} catch (RemoteException e) {
Log.e(TAG, "Error: " + e.getMessage());
}
}
private void resetIds() {
for (int i = 0; i < mIds.size(); i++) {
mIds.set(i, i);
}
}
/**
* Swaps two elements and their properties
* @param original The original position of the element
* @param newPosition The new position of the item
*/
public void swap(int original, int newPosition) {
Song temp = mSongs.get(original);
Song newSong = mSongs.get(newPosition);
mSongs.set(original, newSong);
mSongs.set(newPosition, temp);
int tempVis = mVisible.get(original);
mVisible.set(original, mVisible.get(newPosition));
mVisible.set(newPosition, tempVis);
int tempId = mIds.get(original);
mIds.set(original, mIds.get(newPosition));
mIds.set(newPosition, tempId);
super.notifyDataSetChanged();
}
/**
* Sets the visibility of a selected element to visibility
* Save the visibility to remember when the view is recycled
* @param position The position of the item
* @param visibility The visibility flag (View)
*/
public void setVisibility(int position, int visibility) {
if (position >= 0 && position < mVisible.size()) {
mVisible.set(position, visibility);
}
}
/**
* {@inheritDoc}
*/
@Override
public void notifyDataSetChanged() {
// We reload the songs from the playlist associated with this adapter
mSongs.clear();
mIds.clear();
mVisible.clear();
final List<String> it = new ArrayList<>(mPlaylist.songsList());
final ProviderIdentifier id = mPlaylist.getProvider();
final ProviderAggregator aggregator = ProviderAggregator.getDefault();
for (String songRef : it) {
Song s = aggregator.retrieveSong(songRef, id);
if (s == null) {
Log.e(TAG, "Retrieved a null song from the playlist!");
} else {
put(s);
}
}
// And we notify the list that something changed
super.notifyDataSetChanged();
}
/**
* {@inheritDoc}
*/
@Override
public void put(Song p) {
super.put(p);
mVisible.add(View.VISIBLE);
mIds.add(mSongs.size() - 1);
}
/**
* {@inheritDoc}
*/
@Override
public int getCount() {
return mSongs.size();
}
/**
* {@inheritDoc}
*/
@Override
public Song getItem(int position) {
return mSongs.get(position);
}
/**
* {@inheritDoc}
*/
@Override
public long getItemId(int position) {
if (position >= 0 && position < mIds.size()) {
return mIds.get(position);
}
Log.e(TAG, "Item ID out of bounds: " + position);
return -1;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("ResourceType")
@Override
public View getView(int position, View convertView, final ViewGroup parent) {
View root = super.getView(position, convertView, parent);
root.setVisibility(mVisible.get(position));
return root;
}
}