2 * Copyright (C) 2012 Andrew Neal Licensed under the Apache License, Version 2.0
3 * (the "License"); you may not use this file except in compliance with the
4 * License. You may obtain a copy of the License at
5 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
6 * or agreed to in writing, software distributed under the License is
7 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 * KIND, either express or implied. See the License for the specific language
9 * governing permissions and limitations under the License.
12 package com.andrew.apollo.ui.fragments;
14 import android.os.Bundle;
15 import android.support.v4.app.Fragment;
16 import android.support.v4.app.LoaderManager.LoaderCallbacks;
17 import android.support.v4.content.Loader;
18 import android.text.TextUtils;
19 import android.view.ContextMenu;
20 import android.view.ContextMenu.ContextMenuInfo;
21 import android.view.LayoutInflater;
22 import android.view.Menu;
23 import android.view.MenuInflater;
24 import android.view.MenuItem;
25 import android.view.SubMenu;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.widget.AdapterView;
29 import android.widget.AdapterView.AdapterContextMenuInfo;
30 import android.widget.AdapterView.OnItemClickListener;
32 import com.andrew.apollo.R;
33 import com.andrew.apollo.adapters.SongAdapter;
34 import com.andrew.apollo.dragdrop.DragSortListView;
35 import com.andrew.apollo.dragdrop.DragSortListView.DragScrollProfile;
36 import com.andrew.apollo.dragdrop.DragSortListView.DropListener;
37 import com.andrew.apollo.dragdrop.DragSortListView.RemoveListener;
38 import com.andrew.apollo.loaders.NowPlayingCursor;
39 import com.andrew.apollo.loaders.QueueLoader;
40 import com.andrew.apollo.menu.CreateNewPlaylist;
41 import com.andrew.apollo.menu.DeleteDialog;
42 import com.andrew.apollo.menu.FragmentMenuItems;
43 import com.andrew.apollo.model.Song;
44 import com.andrew.apollo.provider.FavoritesStore;
45 import com.andrew.apollo.recycler.RecycleHolder;
46 import com.andrew.apollo.utils.MusicUtils;
47 import com.andrew.apollo.utils.NavUtils;
48 import com.viewpagerindicator.TitlePageIndicator;
50 import java.util.List;
53 * This class is used to display all of the songs in the queue.
55 * @author Andrew Neal (andrewdneal@gmail.com)
57 public class QueueFragment extends Fragment implements LoaderCallbacks<List<Song>>,
58 OnItemClickListener, DropListener, RemoveListener, DragScrollProfile {
61 * Used to keep context menu items from bleeding into other fragments
63 private static final int GROUP_ID = 13;
66 * LoaderCallbacks identifier
68 private static final int LOADER = 0;
71 * The adapter for the list
73 private SongAdapter mAdapter;
78 private DragSortListView mListView;
86 * Position of a context menu item
88 private int mSelectedPosition;
91 * Id of a context menu item
93 private long mSelectedId;
96 * Song, album, and artist name used in the context menu
98 private String mSongName, mAlbumName, mArtistName;
101 * Empty constructor as per the {@link Fragment} documentation
103 public QueueFragment() {
110 public void onCreate(final Bundle savedInstanceState) {
111 super.onCreate(savedInstanceState);
112 // Create the adpater
113 mAdapter = new SongAdapter(getActivity(), R.layout.edit_track_list_item);
120 public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
121 final Bundle savedInstanceState) {
122 // The View for the fragment's UI
123 final ViewGroup rootView = (ViewGroup)inflater.inflate(R.layout.list_base, null);
124 // Initialize the list
125 mListView = (DragSortListView)rootView.findViewById(R.id.list_base);
126 // Set the data behind the list
127 mListView.setAdapter(mAdapter);
128 // Release any references to the recycled Views
129 mListView.setRecyclerListener(new RecycleHolder());
130 // Listen for ContextMenus to be created
131 mListView.setOnCreateContextMenuListener(this);
132 // Play the selected song
133 mListView.setOnItemClickListener(this);
134 // Set the drop listener
135 mListView.setDropListener(this);
136 // Set the swipe to remove listener
137 mListView.setRemoveListener(this);
138 // Quick scroll while dragging
139 mListView.setDragScrollProfile(this);
147 public void onActivityCreated(final Bundle savedInstanceState) {
148 super.onActivityCreated(savedInstanceState);
149 // Enable the options menu
150 setHasOptionsMenu(true);
152 getLoaderManager().initLoader(LOADER, null, this);
159 public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
160 inflater.inflate(R.menu.queue, menu);
161 super.onCreateOptionsMenu(menu, inflater);
168 public boolean onOptionsItemSelected(final MenuItem item) {
169 switch (item.getItemId()) {
170 case R.id.menu_save_queue:
171 NowPlayingCursor queue = (NowPlayingCursor)QueueLoader
172 .makeQueueCursor(getActivity());
173 CreateNewPlaylist.getInstance(MusicUtils.getSongListForCursor(queue)).show(
174 getFragmentManager(), "CreatePlaylist");
178 case R.id.menu_clear_queue:
179 MusicUtils.clearQueue();
180 NavUtils.goHome(getActivity());
185 return super.onOptionsItemSelected(item);
192 public void onCreateContextMenu(final ContextMenu menu, final View v,
193 final ContextMenuInfo menuInfo) {
194 super.onCreateContextMenu(menu, v, menuInfo);
195 // Get the position of the selected item
196 final AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
197 mSelectedPosition = info.position;
199 mSong = mAdapter.getItem(mSelectedPosition);
200 mSelectedId = mSong.mSongId;
201 mSongName = mSong.mSongName;
202 mAlbumName = mSong.mAlbumName;
203 mArtistName = mSong.mArtistName;
205 // Play the song next
206 menu.add(GROUP_ID, FragmentMenuItems.PLAY_NEXT, Menu.NONE,
207 getString(R.string.context_menu_play_next));
209 // Add the song to a playlist
210 final SubMenu subMenu = menu.addSubMenu(GROUP_ID, FragmentMenuItems.ADD_TO_PLAYLIST,
211 Menu.NONE, R.string.add_to_playlist);
212 MusicUtils.makePlaylistMenu(getActivity(), GROUP_ID, subMenu, true);
214 // Remove the song from the queue
215 menu.add(GROUP_ID, FragmentMenuItems.REMOVE_FROM_QUEUE, Menu.NONE,
216 getString(R.string.remove_from_queue));
218 // View more content by the song artist
219 menu.add(GROUP_ID, FragmentMenuItems.MORE_BY_ARTIST, Menu.NONE,
220 getString(R.string.context_menu_more_by_artist));
222 // Make the song a ringtone
223 menu.add(GROUP_ID, FragmentMenuItems.USE_AS_RINGTONE, Menu.NONE,
224 getString(R.string.context_menu_use_as_ringtone));
227 menu.add(GROUP_ID, FragmentMenuItems.DELETE, Menu.NONE,
228 getString(R.string.context_menu_delete));
235 public boolean onContextItemSelected(final android.view.MenuItem item) {
236 if (item.getGroupId() == GROUP_ID) {
237 switch (item.getItemId()) {
238 case FragmentMenuItems.PLAY_NEXT:
239 NowPlayingCursor queue = (NowPlayingCursor)QueueLoader
240 .makeQueueCursor(getActivity());
241 queue.removeItem(mSelectedPosition);
244 MusicUtils.playNext(new long[] {
249 case FragmentMenuItems.REMOVE_FROM_QUEUE:
250 MusicUtils.removeTrack(mSelectedId);
253 case FragmentMenuItems.ADD_TO_FAVORITES:
254 FavoritesStore.getInstance(getActivity()).addSongId(
255 mSelectedId, mSongName, mAlbumName, mArtistName);
257 case FragmentMenuItems.NEW_PLAYLIST:
258 CreateNewPlaylist.getInstance(new long[] {
260 }).show(getFragmentManager(), "CreatePlaylist");
262 case FragmentMenuItems.PLAYLIST_SELECTED:
263 final long mPlaylistId = item.getIntent().getLongExtra("playlist", 0);
264 MusicUtils.addToPlaylist(getActivity(), new long[] {
268 case FragmentMenuItems.MORE_BY_ARTIST:
269 NavUtils.openArtistProfile(getActivity(), mArtistName);
271 case FragmentMenuItems.USE_AS_RINGTONE:
272 MusicUtils.setRingtone(getActivity(), mSelectedId);
274 case FragmentMenuItems.DELETE:
275 DeleteDialog.newInstance(mSong.mSongName, new long[] {
277 }, null).show(getFragmentManager(), "DeleteDialog");
283 return super.onContextItemSelected(item);
290 public void onItemClick(final AdapterView<?> parent, final View view, final int position,
292 // When selecting a track from the queue, just jump there instead of
293 // reloading the queue. This is both faster, and prevents accidentally
294 // dropping out of party shuffle.
295 MusicUtils.setQueuePosition(position);
302 public Loader<List<Song>> onCreateLoader(final int id, final Bundle args) {
303 return new QueueLoader(getActivity());
310 public void onLoadFinished(final Loader<List<Song>> loader, final List<Song> data) {
311 // Check for any errors
312 if (data.isEmpty()) {
318 // Add the data to the adpater
319 for (final Song song : data) {
323 mAdapter.buildCache();
330 public void onLoaderReset(final Loader<List<Song>> loader) {
331 // Clear the data in the adapter
339 public float getSpeed(final float w, final long t) {
341 return mAdapter.getCount() / 0.001f;
351 public void remove(final int which) {
352 mSong = mAdapter.getItem(which);
353 mAdapter.remove(mSong);
354 mAdapter.notifyDataSetChanged();
355 MusicUtils.removeTrack(mSong.mSongId);
357 mAdapter.buildCache();
364 public void drop(final int from, final int to) {
365 mSong = mAdapter.getItem(from);
366 mAdapter.remove(mSong);
367 mAdapter.insert(mSong, to);
368 mAdapter.notifyDataSetChanged();
369 MusicUtils.moveQueueItem(from, to);
371 mAdapter.buildCache();
375 * Scrolls the list to the currently playing song when the user touches the
376 * header in the {@link TitlePageIndicator}.
378 public void scrollToCurrentSong() {
379 final int currentSongPosition = getItemPositionBySong();
381 if (currentSongPosition != 0) {
382 mListView.setSelection(currentSongPosition);
387 * @return The position of an item in the list based on the name of the
388 * currently playing song.
390 private int getItemPositionBySong() {
391 final long trackId = MusicUtils.getCurrentAudioId();
392 if (mAdapter == null) {
395 for (int i = 0; i < mAdapter.getCount(); i++) {
396 if (mAdapter.getItem(i).mSongId == trackId) {
404 * Called to restart the loader callbacks
406 public void refreshQueue() {
408 getLoaderManager().restartLoader(LOADER, null, this);