OSDN Git Service

Repackaged com.andrew.apollo to com.cyngn.eleven
[android-x86/packages-apps-Eleven.git] / src / com / cyngn / eleven / ui / fragments / SongFragment.java
1 /*
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.
10  */
11
12 package com.cyngn.eleven.ui.fragments;
13
14 import android.app.Activity;
15 import android.database.Cursor;
16 import android.os.Bundle;
17 import android.os.SystemClock;
18 import android.support.v4.app.Fragment;
19 import android.support.v4.app.LoaderManager.LoaderCallbacks;
20 import android.support.v4.content.Loader;
21 import android.text.TextUtils;
22 import android.view.ContextMenu;
23 import android.view.ContextMenu.ContextMenuInfo;
24 import android.view.LayoutInflater;
25 import android.view.Menu;
26 import android.view.SubMenu;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.AdapterView;
30 import android.widget.AdapterView.AdapterContextMenuInfo;
31 import android.widget.AdapterView.OnItemClickListener;
32 import android.widget.ListView;
33 import android.widget.TextView;
34
35 import com.cyngn.eleven.MusicStateListener;
36 import com.cyngn.eleven.R;
37 import com.cyngn.eleven.adapters.SongAdapter;
38 import com.cyngn.eleven.loaders.SongLoader;
39 import com.cyngn.eleven.menu.CreateNewPlaylist;
40 import com.cyngn.eleven.menu.DeleteDialog;
41 import com.cyngn.eleven.menu.FragmentMenuItems;
42 import com.cyngn.eleven.model.Song;
43 import com.cyngn.eleven.provider.FavoritesStore;
44 import com.cyngn.eleven.recycler.RecycleHolder;
45 import com.cyngn.eleven.ui.activities.BaseActivity;
46 import com.cyngn.eleven.utils.MusicUtils;
47 import com.cyngn.eleven.utils.NavUtils;
48 import com.viewpagerindicator.TitlePageIndicator;
49
50 import java.util.List;
51
52 /**
53  * This class is used to display all of the songs on a user's device.
54  * 
55  * @author Andrew Neal (andrewdneal@gmail.com)
56  */
57 public class SongFragment extends Fragment implements LoaderCallbacks<List<Song>>,
58         OnItemClickListener, MusicStateListener {
59
60     /**
61      * Used to keep context menu items from bleeding into other fragments
62      */
63     private static final int GROUP_ID = 4;
64
65     /**
66      * LoaderCallbacks identifier
67      */
68     private static final int LOADER = 0;
69
70     /**
71      * Fragment UI
72      */
73     private ViewGroup mRootView;
74
75     /**
76      * The adapter for the list
77      */
78     private SongAdapter mAdapter;
79
80     /**
81      * The list view
82      */
83     private ListView mListView;
84
85     /**
86      * Represents a song
87      */
88     private Song mSong;
89
90     /**
91      * Position of a context menu item
92      */
93     private int mSelectedPosition;
94
95     /**
96      * Id of a context menu item
97      */
98     private long mSelectedId;
99
100     /**
101      * Song, album, and artist name used in the context menu
102      */
103     private String mSongName, mAlbumName, mArtistName;
104
105     /**
106      * True if the list should execute {@code #restartLoader()}.
107      */
108     private boolean mShouldRefresh = false;
109
110     /**
111      * Empty constructor as per the {@link Fragment} documentation
112      */
113     public SongFragment() {
114     }
115
116     /**
117      * {@inheritDoc}
118      */
119     @Override
120     public void onAttach(final Activity activity) {
121         super.onAttach(activity);
122         // Register the music status listener
123         ((BaseActivity)activity).setMusicStateListenerListener(this);
124     }
125
126     /**
127      * {@inheritDoc}
128      */
129     @Override
130     public void onCreate(final Bundle savedInstanceState) {
131         super.onCreate(savedInstanceState);
132         // Create the adpater
133         mAdapter = new SongAdapter(getActivity(), R.layout.list_item_simple);
134     }
135
136     /**
137      * {@inheritDoc}
138      */
139     @Override
140     public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
141             final Bundle savedInstanceState) {
142         // The View for the fragment's UI
143         mRootView = (ViewGroup)inflater.inflate(R.layout.list_base, null);
144         // Initialize the list
145         mListView = (ListView)mRootView.findViewById(R.id.list_base);
146         // Set the data behind the list
147         mListView.setAdapter(mAdapter);
148         // Release any references to the recycled Views
149         mListView.setRecyclerListener(new RecycleHolder());
150         // Listen for ContextMenus to be created
151         mListView.setOnCreateContextMenuListener(this);
152         // Play the selected song
153         mListView.setOnItemClickListener(this);
154         return mRootView;
155     }
156
157     /**
158      * {@inheritDoc}
159      */
160     @Override
161     public void onActivityCreated(final Bundle savedInstanceState) {
162         super.onActivityCreated(savedInstanceState);
163         // Enable the options menu
164         setHasOptionsMenu(true);
165         // Start the loader
166         getLoaderManager().initLoader(LOADER, null, this);
167     }
168
169     /**
170      * {@inheritDoc}
171      */
172     @Override
173     public void onCreateContextMenu(final ContextMenu menu, final View v,
174             final ContextMenuInfo menuInfo) {
175         super.onCreateContextMenu(menu, v, menuInfo);
176         // Get the position of the selected item
177         final AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
178         mSelectedPosition = info.position;
179         // Creat a new song
180         mSong = mAdapter.getItem(mSelectedPosition);
181         mSelectedId = mSong.mSongId;
182         mSongName = mSong.mSongName;
183         mAlbumName = mSong.mAlbumName;
184         mArtistName = mSong.mArtistName;
185
186         // Play the song
187         menu.add(GROUP_ID, FragmentMenuItems.PLAY_SELECTION, Menu.NONE,
188                 getString(R.string.context_menu_play_selection));
189
190         // Play next
191         menu.add(GROUP_ID, FragmentMenuItems.PLAY_NEXT, Menu.NONE,
192                 getString(R.string.context_menu_play_next));
193
194         // Add the song to the queue
195         menu.add(GROUP_ID, FragmentMenuItems.ADD_TO_QUEUE, Menu.NONE,
196                 getString(R.string.add_to_queue));
197
198         // Add the song to a playlist
199         final SubMenu subMenu = menu.addSubMenu(GROUP_ID, FragmentMenuItems.ADD_TO_PLAYLIST,
200                 Menu.NONE, R.string.add_to_playlist);
201         MusicUtils.makePlaylistMenu(getActivity(), GROUP_ID, subMenu, true);
202
203         // View more content by the song artist
204         menu.add(GROUP_ID, FragmentMenuItems.MORE_BY_ARTIST, Menu.NONE,
205                 getString(R.string.context_menu_more_by_artist));
206
207         // Make the song a ringtone
208         menu.add(GROUP_ID, FragmentMenuItems.USE_AS_RINGTONE, Menu.NONE,
209                 getString(R.string.context_menu_use_as_ringtone));
210
211         // Delete the song
212         menu.add(GROUP_ID, FragmentMenuItems.DELETE, Menu.NONE,
213                 getString(R.string.context_menu_delete));
214     }
215
216     @Override
217     public boolean onContextItemSelected(final android.view.MenuItem item) {
218         if (item.getGroupId() == GROUP_ID) {
219             switch (item.getItemId()) {
220                 case FragmentMenuItems.PLAY_SELECTION:
221                     MusicUtils.playAll(getActivity(), new long[] {
222                         mSelectedId
223                     }, 0, false);
224                     return true;
225                 case FragmentMenuItems.PLAY_NEXT:
226                     MusicUtils.playNext(new long[] {
227                         mSelectedId
228                     });
229                     return true;
230                 case FragmentMenuItems.ADD_TO_QUEUE:
231                     MusicUtils.addToQueue(getActivity(), new long[] {
232                         mSelectedId
233                     });
234                     return true;
235                 case FragmentMenuItems.ADD_TO_FAVORITES:
236                     FavoritesStore.getInstance(getActivity()).addSongId(
237                             mSelectedId, mSongName, mAlbumName, mArtistName);
238                     return true;
239                 case FragmentMenuItems.NEW_PLAYLIST:
240                     CreateNewPlaylist.getInstance(new long[] {
241                         mSelectedId
242                     }).show(getFragmentManager(), "CreatePlaylist");
243                     return true;
244                 case FragmentMenuItems.PLAYLIST_SELECTED:
245                     final long mPlaylistId = item.getIntent().getLongExtra("playlist", 0);
246                     MusicUtils.addToPlaylist(getActivity(), new long[] {
247                         mSelectedId
248                     }, mPlaylistId);
249                     return true;
250                 case FragmentMenuItems.MORE_BY_ARTIST:
251                     NavUtils.openArtistProfile(getActivity(), mArtistName);
252                     return true;
253                 case FragmentMenuItems.USE_AS_RINGTONE:
254                     MusicUtils.setRingtone(getActivity(), mSelectedId);
255                     return true;
256                 case FragmentMenuItems.DELETE:
257                     mShouldRefresh = true;
258                     DeleteDialog.newInstance(mSong.mSongName, new long[] {
259                         mSelectedId
260                     }, null).show(getFragmentManager(), "DeleteDialog");
261                     return true;
262                 default:
263                     break;
264             }
265         }
266         return super.onContextItemSelected(item);
267     }
268
269     /**
270      * {@inheritDoc}
271      */
272     @Override
273     public void onItemClick(final AdapterView<?> parent, final View view, final int position,
274             final long id) {
275         Cursor cursor = SongLoader.makeSongCursor(getActivity());
276         final long[] list = MusicUtils.getSongListForCursor(cursor);
277         MusicUtils.playAll(getActivity(), list, position, false);
278         cursor.close();
279         cursor = null;
280     }
281
282     /**
283      * {@inheritDoc}
284      */
285     @Override
286     public Loader<List<Song>> onCreateLoader(final int id, final Bundle args) {
287         return new SongLoader(getActivity());
288     }
289
290     /**
291      * {@inheritDoc}
292      */
293     @Override
294     public void onLoadFinished(final Loader<List<Song>> loader, final List<Song> data) {
295         // Check for any errors
296         if (data.isEmpty()) {
297             // Set the empty text
298             final TextView empty = (TextView)mRootView.findViewById(R.id.empty);
299             empty.setText(getString(R.string.empty_music));
300             mListView.setEmptyView(empty);
301             return;
302         }
303
304         // Start fresh
305         mAdapter.unload();
306         // Add the data to the adpater
307         for (final Song song : data) {
308             mAdapter.add(song);
309         }
310         // Build the cache
311         mAdapter.buildCache();
312     }
313
314     /**
315      * {@inheritDoc}
316      */
317     @Override
318     public void onLoaderReset(final Loader<List<Song>> loader) {
319         // Clear the data in the adapter
320         mAdapter.unload();
321     }
322
323     /**
324      * Scrolls the list to the currently playing song when the user touches the
325      * header in the {@link TitlePageIndicator}.
326      */
327     public void scrollToCurrentSong() {
328         final int currentSongPosition = getItemPositionBySong();
329
330         if (currentSongPosition != 0) {
331             mListView.setSelection(currentSongPosition);
332         }
333     }
334
335     /**
336      * @return The position of an item in the list based on the name of the
337      *         currently playing song.
338      */
339     private int getItemPositionBySong() {
340         final long trackId = MusicUtils.getCurrentAudioId();
341         if (mAdapter == null) {
342             return 0;
343         }
344         for (int i = 0; i < mAdapter.getCount(); i++) {
345             if (mAdapter.getItem(i).mSongId == trackId) {
346                 return i;
347             }
348         }
349         return 0;
350     }
351
352     /**
353      * Restarts the loader.
354      */
355     public void refresh() {
356         // Wait a moment for the preference to change.
357         SystemClock.sleep(10);
358         getLoaderManager().restartLoader(LOADER, null, this);
359     }
360
361     /**
362      * {@inheritDoc}
363      */
364     @Override
365     public void restartLoader() {
366         // Update the list when the user deletes any items
367         if (mShouldRefresh) {
368             getLoaderManager().restartLoader(LOADER, null, this);
369         }
370         mShouldRefresh = false;
371     }
372
373     /**
374      * {@inheritDoc}
375      */
376     @Override
377     public void onMetaChanged() {
378         // Nothing to do
379     }
380 }