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.cyngn.eleven.ui.fragments;
14 import android.app.Activity;
15 import android.content.Context;
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.AbsListView;
30 import android.widget.AbsListView.OnScrollListener;
31 import android.widget.AdapterView;
32 import android.widget.AdapterView.AdapterContextMenuInfo;
33 import android.widget.AdapterView.OnItemClickListener;
34 import android.widget.GridView;
35 import android.widget.ListView;
36 import android.widget.TextView;
38 import com.cyngn.eleven.MusicStateListener;
39 import com.cyngn.eleven.R;
40 import com.cyngn.eleven.adapters.ArtistAdapter;
41 import com.cyngn.eleven.loaders.ArtistLoader;
42 import com.cyngn.eleven.menu.CreateNewPlaylist;
43 import com.cyngn.eleven.menu.DeleteDialog;
44 import com.cyngn.eleven.menu.FragmentMenuItems;
45 import com.cyngn.eleven.model.Artist;
46 import com.cyngn.eleven.recycler.RecycleHolder;
47 import com.cyngn.eleven.sectionadapter.SectionAdapter;
48 import com.cyngn.eleven.sectionadapter.SectionCreator;
49 import com.cyngn.eleven.sectionadapter.SectionListContainer;
50 import com.cyngn.eleven.ui.activities.BaseActivity;
51 import com.cyngn.eleven.utils.ApolloUtils;
52 import com.cyngn.eleven.utils.MusicUtils;
53 import com.cyngn.eleven.utils.NavUtils;
54 import com.cyngn.eleven.utils.PreferenceUtils;
55 import com.cyngn.eleven.utils.SectionCreatorUtils;
56 import com.cyngn.eleven.utils.SectionCreatorUtils.IItemCompare;
57 import com.viewpagerindicator.TitlePageIndicator;
59 import java.util.List;
62 * This class is used to display all of the artists on a user's device.
64 * @author Andrew Neal (andrewdneal@gmail.com)
66 public class ArtistFragment extends Fragment implements LoaderCallbacks<SectionListContainer<Artist>>,
67 OnScrollListener, OnItemClickListener, MusicStateListener {
70 * Used to keep context menu items from bleeding into other fragments
72 private static final int GROUP_ID = 2;
75 * Grid view column count. ONE - list, TWO - normal grid, FOUR - landscape
77 private static final int ONE = 1, TWO = 2, FOUR = 4;
80 * LoaderCallbacks identifier
82 private static final int LOADER = 0;
87 private ViewGroup mRootView;
90 * The adapter for the grid
92 private SectionAdapter<Artist, ArtistAdapter> mAdapter;
97 private GridView mGridView;
102 private ListView mListView;
107 private long[] mArtistList;
110 * Represents an artist
112 private Artist mArtist;
115 * True if the list should execute {@code #restartLoader()}.
117 private boolean mShouldRefresh = false;
120 * Empty constructor as per the {@link Fragment} documentation
122 public ArtistFragment() {
129 public void onAttach(final Activity activity) {
130 super.onAttach(activity);
131 // Register the music status listener
132 ((BaseActivity)activity).setMusicStateListenerListener(this);
139 public void onCreate(final Bundle savedInstanceState) {
140 super.onCreate(savedInstanceState);
141 // Create the adpater
142 final int layout = R.layout.list_item_normal;
143 ArtistAdapter adapter = new ArtistAdapter(getActivity(), layout);
144 mAdapter = new SectionAdapter<Artist, ArtistAdapter>(getActivity(), adapter);
151 public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
152 final Bundle savedInstanceState) {
153 // The View for the fragment's UI
154 mRootView = (ViewGroup)inflater.inflate(R.layout.list_base, null);
163 public void onActivityCreated(final Bundle savedInstanceState) {
164 super.onActivityCreated(savedInstanceState);
165 // Enable the options menu
166 setHasOptionsMenu(true);
168 getLoaderManager().initLoader(LOADER, null, this);
175 public void onPause() {
184 public void onCreateContextMenu(final ContextMenu menu, final View v,
185 final ContextMenuInfo menuInfo) {
186 super.onCreateContextMenu(menu, v, menuInfo);
188 // Get the position of the selected item
189 final AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
191 mArtist = mAdapter.getTItem(info.position);
192 // Create a list of the artist's songs
193 mArtistList = MusicUtils.getSongListForArtist(getActivity(), mArtist.mArtistId);
196 menu.add(GROUP_ID, FragmentMenuItems.PLAY_SELECTION, Menu.NONE,
197 getString(R.string.context_menu_play_selection));
199 // Add the artist to the queue
200 menu.add(GROUP_ID, FragmentMenuItems.ADD_TO_QUEUE, Menu.NONE,
201 getString(R.string.add_to_queue));
203 // Add the artist to a playlist
204 final SubMenu subMenu = menu.addSubMenu(GROUP_ID, FragmentMenuItems.ADD_TO_PLAYLIST,
205 Menu.NONE, R.string.add_to_playlist);
206 MusicUtils.makePlaylistMenu(getActivity(), GROUP_ID, subMenu);
209 menu.add(GROUP_ID, FragmentMenuItems.DELETE, Menu.NONE,
210 getString(R.string.context_menu_delete));
217 public boolean onContextItemSelected(final android.view.MenuItem item) {
218 // Avoid leaking context menu selections
219 if (item.getGroupId() == GROUP_ID) {
220 switch (item.getItemId()) {
221 case FragmentMenuItems.PLAY_SELECTION:
222 MusicUtils.playAll(getActivity(), mArtistList, 0, true);
224 case FragmentMenuItems.ADD_TO_QUEUE:
225 MusicUtils.addToQueue(getActivity(), mArtistList);
227 case FragmentMenuItems.NEW_PLAYLIST:
228 CreateNewPlaylist.getInstance(mArtistList).show(getFragmentManager(),
231 case FragmentMenuItems.PLAYLIST_SELECTED:
232 final long id = item.getIntent().getLongExtra("playlist", 0);
233 MusicUtils.addToPlaylist(getActivity(), mArtistList, id);
235 case FragmentMenuItems.DELETE:
236 mShouldRefresh = true;
237 final String artist = mArtist.mArtistName;
238 DeleteDialog.newInstance(artist, mArtistList, artist).show(
239 getFragmentManager(), "DeleteDialog");
245 return super.onContextItemSelected(item);
252 public void onScrollStateChanged(final AbsListView view, final int scrollState) {
253 // Pause disk cache access to ensure smoother scrolling
254 if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING
255 || scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
256 mAdapter.getUnderlyingAdapter().setPauseDiskCache(true);
258 mAdapter.getUnderlyingAdapter().setPauseDiskCache(false);
259 mAdapter.notifyDataSetChanged();
267 public void onItemClick(final AdapterView<?> parent, final View view, final int position,
269 mArtist = mAdapter.getTItem(position);
270 NavUtils.openArtistProfile(getActivity(), mArtist.mArtistName);
277 public Loader<SectionListContainer<Artist>> onCreateLoader(final int id, final Bundle args) {
278 final Context context = getActivity();
279 IItemCompare<Artist> comparator = SectionCreatorUtils.createArtistComparison(context);
280 return new SectionCreator<Artist>(getActivity(), new ArtistLoader(context), comparator);
287 public void onLoadFinished(final Loader<SectionListContainer<Artist>> loader,
288 final SectionListContainer<Artist> data) {
289 // Check for any errors
290 if (data.mListResults.isEmpty()) {
291 // Set the empty text
292 final TextView empty = (TextView)mRootView.findViewById(R.id.empty);
293 empty.setText(getString(R.string.empty_music));
294 mListView.setEmptyView(empty);
299 mAdapter.setData(data);
306 public void onLoaderReset(final Loader<SectionListContainer<Artist>> loader) {
307 // Clear the data in the adapter
312 * Scrolls the list to the currently playing artist when the user touches
313 * the header in the {@link TitlePageIndicator}.
315 public void scrollToCurrentArtist() {
316 final int currentArtistPosition = getItemPositionByArtist();
318 if (currentArtistPosition != 0) {
319 mListView.setSelection(currentArtistPosition);
324 * @return The position of an item in the list or grid based on the name of
325 * the currently playing artist.
327 private int getItemPositionByArtist() {
328 final long artistId = MusicUtils.getCurrentArtistId();
329 if (mAdapter == null) {
333 int position = mAdapter.getItemPosition(artistId);
335 // if for some reason we don't find the item, just jump to the top
344 * Restarts the loader.
346 public void refresh() {
347 // Wait a moment for the preference to change.
348 SystemClock.sleep(10);
349 getLoaderManager().restartLoader(LOADER, null, this);
356 public void onScroll(final AbsListView view, final int firstVisibleItem,
357 final int visibleItemCount, final int totalItemCount) {
365 public void restartLoader() {
366 // Update the list when the user deletes any items
367 if (mShouldRefresh) {
368 getLoaderManager().restartLoader(LOADER, null, this);
370 mShouldRefresh = false;
377 public void onMetaChanged() {
382 * Sets up various helpers for both the list and grid
384 * @param list The list or grid
386 private void initAbsListView(final AbsListView list) {
387 // Release any references to the recycled Views
388 list.setRecyclerListener(new RecycleHolder());
389 // Listen for ContextMenus to be created
390 list.setOnCreateContextMenuListener(this);
391 // Show the albums and songs from the selected artist
392 list.setOnItemClickListener(this);
393 // To help make scrolling smooth
394 list.setOnScrollListener(this);
398 * Sets up the list view
400 private void initListView() {
401 // Initialize the grid
402 mListView = (ListView)mRootView.findViewById(R.id.list_base);
403 // Set the data behind the list
404 mListView.setAdapter(mAdapter);
405 // Set up the helpers
406 initAbsListView(mListView);