/* == This file is part of Tomahawk Player - <http://tomahawk-player.org> === * * Copyright 2016, Enno Gottschalk <mrmaffen@googlemail.com> * * Tomahawk 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. * * Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>. */ package org.tomahawk.tomahawk_android.utils; import org.tomahawk.libtomahawk.collection.Cacheable; import org.tomahawk.libtomahawk.collection.Playlist; import org.tomahawk.libtomahawk.collection.PlaylistEntry; import org.tomahawk.libtomahawk.collection.StationPlaylist; import org.tomahawk.libtomahawk.collection.Track; import org.tomahawk.libtomahawk.resolver.Query; import android.util.Log; import java.util.List; public class PlaybackManager extends Cacheable { public static final String TAG = PlaybackManager.class.getSimpleName(); public static final int NOT_REPEATING = 0; public static final int REPEAT_ALL = 1; public static final int REPEAT_ONE = 2; public static final int NOT_SHUFFLED = 0; public static final int SHUFFLED = 1; private int mRepeatMode = NOT_REPEATING; private int mShuffleMode = NOT_SHUFFLED; private Playlist mPlaylist = Playlist.fromEmptyList(IdGenerator.getLifetimeUniqueStringId(), ""); private Playlist mQueue = Playlist.fromEmptyList(IdGenerator.getLifetimeUniqueStringId(), ""); private int mQueueStartPos = 0; private PlaylistEntry mCurrentEntry; private int mCurrentIndex = -1; private String mId; private Callback mCallback; public interface Callback { void onPlaylistChanged(); void onCurrentEntryChanged(); void onShuffleModeChanged(); void onRepeatModeChanged(); } private PlaybackManager(String id) { super(PlaybackManager.class, id); mId = id; } public static PlaybackManager get(String id) { Cacheable cacheable = get(PlaybackManager.class, id); return cacheable != null ? (PlaybackManager) cacheable : new PlaybackManager(id); } public static PlaybackManager getByKey(String id) { return (PlaybackManager) get(PlaybackManager.class, id); } public String getId() { return mId; } public void setCallback(Callback callback) { mCallback = callback; } public Playlist getPlaylist() { return mPlaylist; } public void setPlaylist(Playlist playlist) { setPlaylist(playlist, null); } public void setPlaylist(StationPlaylist playlist) { PlaylistEntry currentEntry = null; if (playlist.size() > 0) { currentEntry = playlist.getEntryAtPos(playlist.size() - 1); } setPlaylist(playlist, currentEntry); } public void setPlaylist(Playlist playlist, PlaylistEntry currentEntry) { if (mCallback == null || playlist == null) { Log.e(TAG, "setPlaylist failed: " + playlist); return; } mRepeatMode = NOT_REPEATING; mShuffleMode = NOT_SHUFFLED; if (playlist instanceof StationPlaylist) { mPlaylist = playlist; } else { mPlaylist = playlist.copy( Playlist.get("playback_playlist" + IdGenerator.getSessionUniqueStringId())); } if (currentEntry == null) { currentEntry = mPlaylist.getEntryAtPos(0); } setCurrentEntry(currentEntry, false); mCallback.onPlaylistChanged(); } /** * @param position int containing the position in the current playback list * @return the {@link PlaylistEntry} which has been found at the given position */ public PlaylistEntry getPlaybackListEntry(int position) { if (position < mQueueStartPos) { // The requested entry is positioned before the queue return mPlaylist.getEntryAtPos(position, mShuffleMode == SHUFFLED); } else if (position < mQueueStartPos + mQueue.size()) { // Getting the entry from the queue return mQueue.getEntryAtPos(position - mQueueStartPos); } else { // The requested entry is positioned after the queue return mPlaylist.getEntryAtPos(position - mQueue.size(), mShuffleMode == SHUFFLED); } } /** * @param entry The {@link PlaylistEntry} to get the index for * @return an int containing the index of the given {@link PlaylistEntry} inside the current * playback list */ public int getPlaybackListIndex(PlaylistEntry entry) { int index = mQueue.getIndexOfEntry(entry); if (index >= 0) { // Found entry in queue return index + mQueueStartPos; } else { index = mPlaylist.getIndexOfEntry(entry, mShuffleMode == SHUFFLED); if (index < 0) { if (entry != null) { Log.e(TAG, "getPlaybackListIndex - Couldn't find given entry in mQueue or" + " mPlaylist: " + entry.getQuery().getName()); } return -1; } if (index < mQueueStartPos) { // Found entry and its positioned before the queue return index; } else { // Found entry and its positioned after the queue return index + mQueue.size(); } } } public boolean isPartOfQueue(int position) { return position >= mQueueStartPos && position < mQueueStartPos + mQueue.size(); } public int getNumeration(int position) { int numeration; if (position < mQueueStartPos) { // Positioned before the queue numeration = position; } else if (position < mQueueStartPos + mQueue.size()) { // From the queue numeration = position - mQueueStartPos; } else { // Positioned after the queue numeration = position - mQueue.size(); } return numeration - mCurrentIndex; } public int getPlaybackListSize() { return mQueue.size() + mPlaylist.size(); } public void setCurrentEntry(PlaylistEntry currentEntry) { setCurrentEntry(currentEntry, true); } private void setCurrentEntry(PlaylistEntry currentEntry, boolean callback) { if (mCallback == null) { Log.e(TAG, "setCurrentEntry failed: " + currentEntry); return; } PlaylistEntry lastEntry = mCurrentEntry; mCurrentEntry = currentEntry; // Delete the last entry from the queue boolean playlistChanged = mQueue.deleteEntry(lastEntry); if (currentEntry == null) { mCurrentIndex = 0; if (mPlaylist.size() > 0) { mQueueStartPos = mCurrentIndex + 1; } else { mQueueStartPos = 0; } playlistChanged = true; } else if (mPlaylist.containsEntry(currentEntry)) { // We have a PlaylistEntry that is not part of the Queue mCurrentIndex = mPlaylist.getIndexOfEntry(currentEntry, mShuffleMode == SHUFFLED); mQueueStartPos = mCurrentIndex + 1; playlistChanged = true; } else { // We have a PlaylistEntry that is part of the Queue mCurrentIndex = mQueue.getIndexOfEntry(currentEntry) + mQueueStartPos; } if (callback) { if (playlistChanged) { mCallback.onPlaylistChanged(); } else { mCallback.onCurrentEntryChanged(); } } } public PlaylistEntry getCurrentEntry() { return mCurrentEntry; } public int getCurrentIndex() { return mCurrentIndex; } public Query getCurrentQuery() { if (mCurrentEntry != null) { return mCurrentEntry.getQuery(); } return null; } public Track getCurrentTrack() { if (mCurrentEntry != null) { return mCurrentEntry.getQuery().getPreferredTrack(); } return null; } public void addToPlaylist(Query query) { Log.d(TAG, "addToPlaylist: " + query); if (mCallback == null) { Log.e(TAG, "addToPlaylist failed: " + query); return; } mPlaylist.addQuery(mPlaylist.size(), query); if (getCurrentEntry() == null) { setCurrentEntry(getPlaybackListEntry(0), false); } mCallback.onPlaylistChanged(); } public void addToQueue(Query query) { Log.d(TAG, "addToQueue: " + query); if (mCallback == null) { Log.e(TAG, "addToQueue failed: " + query); return; } mQueue.addQuery(mQueue.size(), query); if (getCurrentEntry() == null) { setCurrentEntry(mQueue.getEntryAtPos(0), false); } mCallback.onPlaylistChanged(); } public void addToQueue(List<Query> queries) { Log.d(TAG, "addToQueue: queries.size()= " + queries.size()); if (mCallback == null) { Log.e(TAG, "addToQueue failed: queries.size()= " + queries.size()); return; } int counter = 0; for (Query query : queries) { mQueue.addQuery(counter++, query); } if (getCurrentEntry() == null) { setCurrentEntry(getPlaybackListEntry(0), false); } mCallback.onPlaylistChanged(); } public void deleteFromQueue(PlaylistEntry entry) { Log.d(TAG, "deleteFromQueue: " + entry); if (mCallback == null) { Log.e(TAG, "deleteFromQueue failed: " + entry); return; } if (mQueue.deleteEntry(entry)) { mCallback.onPlaylistChanged(); } } public PlaylistEntry getNextEntry() { return getNextEntry(mCurrentEntry); } public PlaylistEntry getNextEntry(PlaylistEntry entry) { if (entry == null) { return null; } if (mRepeatMode == REPEAT_ONE) { return entry; } int index = getPlaybackListIndex(entry); PlaylistEntry nextEntry = getPlaybackListEntry(index + 1); if (nextEntry == null && mRepeatMode == REPEAT_ALL) { nextEntry = getPlaybackListEntry(0); } return nextEntry; } public boolean hasNextEntry() { return hasNextEntry(mCurrentEntry); } public boolean hasNextEntry(PlaylistEntry entry) { return mRepeatMode == REPEAT_ONE || getNextEntry(entry) != null; } public PlaylistEntry getPreviousEntry() { return getPreviousEntry(mCurrentEntry); } public PlaylistEntry getPreviousEntry(PlaylistEntry entry) { if (entry == null) { return null; } if (mRepeatMode == REPEAT_ONE) { return entry; } int index = getPlaybackListIndex(entry); PlaylistEntry previousEntry = getPlaybackListEntry(index - 1); if (previousEntry == null && mRepeatMode == REPEAT_ALL) { previousEntry = getPlaybackListEntry(getPlaybackListSize() - 1); } return previousEntry; } public boolean hasPreviousEntry() { return hasPreviousEntry(mCurrentEntry); } public boolean hasPreviousEntry(PlaylistEntry entry) { return mRepeatMode == REPEAT_ONE || getPreviousEntry(entry) != null; } public int getRepeatMode() { return mRepeatMode; } public void setRepeatMode(int repeatingMode) { Log.d(TAG, "repeat from " + mRepeatMode + " to " + repeatingMode); if (mCallback == null) { Log.e(TAG, "setRepeatMode failed: " + repeatingMode); return; } if (mRepeatMode != repeatingMode) { mRepeatMode = repeatingMode; mCallback.onRepeatModeChanged(); } } public int getShuffleMode() { return mShuffleMode; } /** * Set whether or not to enable shuffle mode on the current playlist. */ public void setShuffleMode(int shuffleMode) { Log.d(TAG, "shuffle from " + mShuffleMode + " to " + shuffleMode); if (mCallback == null) { Log.e(TAG, "setShuffleMode failed: " + shuffleMode); return; } if (mShuffleMode != shuffleMode) { mShuffleMode = shuffleMode; if (mShuffleMode == SHUFFLED) { int currentIndex = -1; if (!mQueue.containsEntry(mCurrentEntry)) { // We have a PlaylistEntry that is not part of the Queue currentIndex = mPlaylist.getIndexOfEntry(mCurrentEntry); } mPlaylist.buildShuffledIndex(currentIndex); } if (!mQueue.containsEntry(mCurrentEntry)) { // mCurrentEntry not part of queue, refresh mCurrentIndex setCurrentEntry(mCurrentEntry); } else { // mCurrentEntry is part of queue, put the queue at the very top mQueueStartPos = 0; } mCallback.onPlaylistChanged(); mCallback.onShuffleModeChanged(); } } }