/*
* Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner,
* Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain,
* Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter,
* Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann,
* Samuel Zweifel
*
* This file is part of Jukefox.
*
* Jukefox 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 any later version. Jukefox 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
* Jukefox. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.ethz.dcg.pancho3.tablet.view.queue;
import java.util.List;
import android.database.DataSetObservable;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import ch.ethz.dcg.jukefox.commons.utils.Log;
import ch.ethz.dcg.jukefox.controller.player.AndroidPlayerController;
import ch.ethz.dcg.jukefox.model.collection.BaseAlbum;
import ch.ethz.dcg.jukefox.model.collection.BaseArtist;
import ch.ethz.dcg.jukefox.model.collection.IReadOnlyPlaylist;
import ch.ethz.dcg.jukefox.model.collection.Playlist;
import ch.ethz.dcg.jukefox.model.collection.PlaylistSong;
import ch.ethz.dcg.jukefox.model.commons.EmptyPlaylistException;
import ch.ethz.dcg.jukefox.model.commons.NoNextSongException;
import ch.ethz.dcg.jukefox.model.commons.PlaylistPositionOutOfRangeException;
import ch.ethz.dcg.jukefox.playmode.MagicPlayMode;
import ch.ethz.dcg.pancho3.model.JukefoxApplication;
import ch.ethz.dcg.pancho3.tablet.view.ViewFactory;
import ch.ethz.dcg.pancho3.tablet.widget.MagicListAdapter.MagicListInnerAdapter;
import ch.ethz.dcg.pancho3.tablet.widget.QueueItem;
/**
* An adapter that is used to display the contents of a playlist. The top song
* which is displayed is always the one playing; the songs before are not
* displayed by this adapter.
*
* This adapter needs to be used with MagicPlaylistController which contains the
* corresponding logic.
*/
public class PlaylistAdapter implements
MagicListInnerAdapter<PlaylistSong<BaseArtist, BaseAlbum>> {
private static final String TAG = PlaylistAdapter.class.getSimpleName();
// Used to notify data set changes.
private final DataSetObservable dataSetObservable = new DataSetObservable();
// Used to obtain views for the songs.
private final ViewFactory viewFactory;
// We make changes to the playlist only via the playlist controller.
private final MagicPlayMode magicPlaylistController;
private final AndroidPlayerController playerController;
// The current playlist which this adapter is displaying.
// We start with a dummy playlist to avoid having a null value.
private IReadOnlyPlaylist playlist = new Playlist();
// The index of the song is currently playing or how many
// songs are not displayed (since they are above the current song).
// This value is the same as magicListController.getCurrentSongIndex()
// or 0, if the current playlist is empty.
private int playlistOffset = 0;
public PlaylistAdapter(ViewFactory viewFactory,
MagicPlayMode magicPlaylistController) {
this.viewFactory = viewFactory;
this.magicPlaylistController = magicPlaylistController;
this.playerController = JukefoxApplication.getPlayerController();
}
/**
* This is called whenever the playlist changed with either a new playlist
* or also the same playlist object which is already in this adapter. If a
* new playlist object is provided, it is played from the beginning, if it's
* the same playlist object, then we only adjust the display and change the
* song if the top song position changed.
*/
public void playlistChanged(IReadOnlyPlaylist playlist) {
// TODO: what do we actually need to do here.
if (this.playlist != playlist) {
// We have a new playlist and start fresh.
this.playlist = playlist;
playlistOffset = 0;
try {
playlistOffset = playerController.getCurrentSongIndex();
} catch (EmptyPlaylistException e) {
Log.w(TAG, e);
}
}
// We need to update the displayed items.
notifyDataSetChanged();
}
public boolean clearPlaylistExceptPlayingSong() {
return magicPlaylistController.clearPlaylistExceptPlayingSong(playerController);
}
public boolean shuffle() {
return magicPlaylistController.shuffle(playerController);
}
public void undoClear() {
magicPlaylistController.undoClear(playerController);
}
/**
* Needs to be called when the current song changes so the view can react
* accordingly.
*/
public void currentSongChanged() {
try {
playlistOffset = playerController.getCurrentSongIndex();
} catch (EmptyPlaylistException e) {
playlistOffset = 0;
Log.w(TAG, e);
}
notifyDataSetChanged();
}
@Override
public PlaylistSong<BaseArtist, BaseAlbum> getItem(int position) {
try {
return playlist.getSongAtPosition(position + playlistOffset);
} catch (PlaylistPositionOutOfRangeException e) {
Log.w(TAG, e);
throw new RuntimeException("Playlist position out of range exception.");
}
}
@Override
public void appendItem(PlaylistSong<BaseArtist, BaseAlbum> song) {
playerController.appendSongAtEnd(song);
}
@Override
public void moveItem(int startPosition, int endPosition) {
try {
magicPlaylistController.moveSong(playerController, startPosition + playlistOffset,
endPosition + playlistOffset);
} catch (PlaylistPositionOutOfRangeException e) {
Log.w(TAG, e);
}
}
@Override
public void removeItem(int position) {
try {
if (position == 0) {
playerController.playNext();
} else {
magicPlaylistController.removeSongFromPlaylist(playerController, position + playlistOffset);
}
} catch (PlaylistPositionOutOfRangeException e) {
Log.w(TAG, e);
} catch (EmptyPlaylistException e) {
Log.w(TAG, e);
} catch (NoNextSongException e) {
Log.w(TAG, e);
}
}
@Override
public QueueItem getView(int position, View convertView, ViewGroup parent) {
QueueItem queueItemConvertView = null;
if (convertView instanceof QueueItem) {
queueItemConvertView = (QueueItem) convertView;
}
try {
return viewFactory.getSongViewQueue(playlist.getSongAtPosition(position + playlistOffset),
queueItemConvertView, parent, position);
} catch (PlaylistPositionOutOfRangeException e) {
return null;
}
}
@Override
public View getDraggingView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
@Override
public void notifyDataSetChanged() {
dataSetObservable.notifyChanged();
}
@Override
public boolean areAllItemsEnabled() {
return true;
}
@Override
public boolean isEnabled(int position) {
return true;
}
@Override
public int getCount() {
return playlist.getPlaylistSize() - playlistOffset;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public int getItemViewType(int position) {
return 0;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isEmpty() {
return playlist.getPlaylistSize() - playlistOffset == 0;
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
dataSetObservable.registerObserver(observer);
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
dataSetObservable.unregisterObserver(observer);
}
@Override
public void insertItemsAndRemoveLast(List<PlaylistSong<BaseArtist, BaseAlbum>> items,
int insertPosition) {
magicPlaylistController.insertSongsAndRemoveLast(playerController, items, insertPosition + playlistOffset);
}
}