OSDN Git Service

Eleven: Add loading dialogs to all fragments
authorlinus_lee <llee@cyngn.com>
Thu, 2 Oct 2014 19:41:23 +0000 (12:41 -0700)
committerlinus_lee <llee@cyngn.com>
Thu, 20 Nov 2014 20:03:04 +0000 (12:03 -0800)
Some fragments intentionally don't show the loading dialog on recreate to prevent a split second flash on the screen
Loading is delayed by 300ms for better user experience
Fixed a small bug in the RecentStore

https://cyanogen.atlassian.net/browse/MUSIC-63

Change-Id: I5bd7ee25234d0146887f152bbcb57fed6bbb2c01

26 files changed:
res/layout/activity_album_detail.xml
res/layout/activity_artist_detail.xml
res/layout/grid_base.xml
res/layout/list_base.xml
res/layout/loading_empty_container.xml [new file with mode: 0644]
res/layout/playlist_detail.xml
src/com/cyngn/eleven/adapters/AlbumDetailSongAdapter.java
src/com/cyngn/eleven/adapters/ArtistDetailSongAdapter.java
src/com/cyngn/eleven/adapters/DetailSongAdapter.java
src/com/cyngn/eleven/adapters/IEmptyAdapterCallback.java [deleted file]
src/com/cyngn/eleven/provider/RecentStore.java
src/com/cyngn/eleven/sectionadapter/SectionAdapter.java
src/com/cyngn/eleven/ui/activities/SearchActivity.java
src/com/cyngn/eleven/ui/fragments/AlbumDetailFragment.java
src/com/cyngn/eleven/ui/fragments/AlbumFragment.java
src/com/cyngn/eleven/ui/fragments/ArtistDetailFragment.java
src/com/cyngn/eleven/ui/fragments/ArtistFragment.java
src/com/cyngn/eleven/ui/fragments/PlaylistDetailFragment.java
src/com/cyngn/eleven/ui/fragments/PlaylistFragment.java
src/com/cyngn/eleven/ui/fragments/QueueFragment.java
src/com/cyngn/eleven/ui/fragments/RecentFragment.java
src/com/cyngn/eleven/ui/fragments/SongFragment.java
src/com/cyngn/eleven/ui/fragments/profile/BasicSongFragment.java
src/com/cyngn/eleven/ui/fragments/profile/LastAddedFragment.java
src/com/cyngn/eleven/ui/fragments/profile/TopTracksFragment.java
src/com/cyngn/eleven/widgets/LoadingEmptyContainer.java [new file with mode: 0644]

index 4cd98a0..2f4a060 100644 (file)
@@ -90,6 +90,9 @@
             android:textColor="@color/default_text_color" />
     </RelativeLayout>
 
+    <include
+        layout="@layout/loading_empty_container" />
+
     <ListView
         android:id="@+id/songs"
         android:layout_width="match_parent"
index b4b82cf..adad1bd 100644 (file)
@@ -3,6 +3,9 @@
     android:layout_height="match_parent"
     android:background="@color/background_color" >
 
+    <include
+        layout="@layout/loading_empty_container" />
+
     <ListView
         android:id="@+id/songs"
         android:layout_width="match_parent"
index 8d5ee5f..446f901 100644 (file)
@@ -23,7 +23,7 @@
     android:paddingTop="@dimen/list_preferred_item_padding">
 
     <include
-        layout="@layout/no_results_message" />
+        layout="@layout/loading_empty_container" />
 
     <GridView
         android:id="@+id/grid_base"
index ca9338e..9ace9d9 100644 (file)
@@ -20,7 +20,7 @@
     android:layout_height="match_parent">
 
     <include
-        layout="@layout/no_results_message" />
+        layout="@layout/loading_empty_container" />
 
     <com.cyngn.eleven.dragdrop.DragSortListView
         android:id="@+id/list_base"
diff --git a/res/layout/loading_empty_container.xml b/res/layout/loading_empty_container.xml
new file mode 100644 (file)
index 0000000..b4c3b9d
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2014 Cyanogen, Inc.
+-->
+
+<com.cyngn.eleven.widgets.LoadingEmptyContainer
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/loading_empty_container"
+    android:gravity="center"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_centerInParent="true"
+    android:layout_gravity="center">
+
+    <ProgressBar
+        android:id="@+id/progressbar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center" />
+
+    <include
+        layout="@layout/no_results_message" />
+</com.cyngn.eleven.widgets.LoadingEmptyContainer>
index 0ec4e50..1a43d3d 100644 (file)
@@ -7,13 +7,6 @@
     android:layout_height="match_parent">
 
     <include
-        layout="@layout/no_results_message" />
-
-    <include
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
         layout="@layout/list_base" />
 
     <include
index 32f9f3a..c7dd899 100644 (file)
@@ -17,7 +17,7 @@ import com.cyngn.eleven.utils.MusicUtils;
 
 import java.util.List;
 
-public class AlbumDetailSongAdapter extends DetailSongAdapter {
+public abstract class AlbumDetailSongAdapter extends DetailSongAdapter {
     private AlbumDetailFragment mFragment;
 
     public AlbumDetailSongAdapter(Activity activity, AlbumDetailFragment fragment) {
@@ -29,6 +29,7 @@ public class AlbumDetailSongAdapter extends DetailSongAdapter {
 
     @Override // LoaderCallbacks
     public Loader<List<Song>> onCreateLoader(int id, Bundle args) {
+        onLoading();
         return new AlbumSongLoader(mActivity, args.getLong(Config.ID));
     }
 
index c24ba7e..384aa9a 100644 (file)
@@ -15,7 +15,7 @@ import com.cyngn.eleven.model.Song;
 
 import java.util.List;
 
-public class ArtistDetailSongAdapter extends DetailSongAdapter {
+public abstract class ArtistDetailSongAdapter extends DetailSongAdapter {
 
     public ArtistDetailSongAdapter(Activity activity) {
         super(activity);
@@ -25,6 +25,7 @@ public class ArtistDetailSongAdapter extends DetailSongAdapter {
 
     @Override // LoaderCallbacks
     public Loader<List<Song>> onCreateLoader(int id, Bundle args) {
+        onLoading();
         return new ArtistSongLoader(mActivity, args.getLong(Config.ID));
     }
 
index a3b2df2..bed1956 100644 (file)
@@ -23,13 +23,12 @@ import java.util.Collections;
 import java.util.List;
 
 public abstract class DetailSongAdapter extends BaseAdapter
-implements LoaderCallbacks<List<Song>>, OnItemClickListener, IPopupMenuCallback {
+        implements LoaderCallbacks<List<Song>>, OnItemClickListener, IPopupMenuCallback {
     protected final Activity mActivity;
     private final ImageFetcher mImageFetcher;
     private final LayoutInflater mInflater;
     private List<Song> mSongs = Collections.emptyList();
     private IListener mListener;
-    private IEmptyAdapterCallback mEmptyCallback;
 
     public DetailSongAdapter(final Activity activity) {
         mActivity = activity;
@@ -64,6 +63,8 @@ implements LoaderCallbacks<List<Song>>, OnItemClickListener, IPopupMenuCallback
     }
 
     protected abstract int rowLayoutId();
+    protected abstract void onLoading();
+    protected abstract void onNoResults();
 
     @Override // OnItemClickListener
     public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
@@ -81,10 +82,7 @@ implements LoaderCallbacks<List<Song>>, OnItemClickListener, IPopupMenuCallback
     @Override // LoaderCallbacks
     public void onLoadFinished(Loader<List<Song>> loader, List<Song> songs) {
         if (songs.isEmpty()) {
-            if (mEmptyCallback != null) {
-                mEmptyCallback.onEmptyAdapter();
-            }
-
+            onNoResults();
             return;
         }
         mSongs = songs;
@@ -103,10 +101,6 @@ implements LoaderCallbacks<List<Song>>, OnItemClickListener, IPopupMenuCallback
         mListener = listener;
     }
 
-    public void setOnEmptyAdapterListener(IEmptyAdapterCallback callback) {
-        mEmptyCallback = callback;
-    }
-
     protected abstract Holder newHolder(View root, ImageFetcher fetcher);
 
     protected static abstract class Holder {
diff --git a/src/com/cyngn/eleven/adapters/IEmptyAdapterCallback.java b/src/com/cyngn/eleven/adapters/IEmptyAdapterCallback.java
deleted file mode 100644 (file)
index 11b9228..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Copyright (C) 2014 Cyanogen, Inc.
- */
-package com.cyngn.eleven.adapters;
-
-public interface IEmptyAdapterCallback {
-    public void onEmptyAdapter();
-}
index 285d53e..860c6e3 100644 (file)
@@ -90,7 +90,7 @@ public class RecentStore {
             // if our db is too large, delete the extra items
             Cursor oldest = null;
             try {
-                database.query(RecentStoreColumns.NAME,
+                oldest = database.query(RecentStoreColumns.NAME,
                         new String[]{RecentStoreColumns.TIMEPLAYED}, null, null, null, null,
                         RecentStoreColumns.TIMEPLAYED + " ASC");
 
index 1a7f872..3af7245 100644 (file)
@@ -360,6 +360,7 @@ public class SectionAdapter<TItem,
      * unloads the underlying adapter
      */
     public void unload() {
+        mSections.clear();
         mUnderlyingAdapter.unload();
         notifyDataSetChanged();
     }
@@ -373,6 +374,7 @@ public class SectionAdapter<TItem,
     }
 
     public void clear() {
+        mSections.clear();
         mUnderlyingAdapter.clear();
         mSections.clear();
     }
index 8494319..20d558e 100644 (file)
@@ -67,6 +67,7 @@ import com.cyngn.eleven.utils.PopupMenuHelper;
 import com.cyngn.eleven.utils.SectionCreatorUtils;
 import com.cyngn.eleven.utils.SectionCreatorUtils.IItemCompare;
 import com.cyngn.eleven.widgets.IPopupMenuCallback;
+import com.cyngn.eleven.widgets.LoadingEmptyContainer;
 import com.cyngn.eleven.widgets.NoResultsContainer;
 
 import java.util.ArrayList;
@@ -127,9 +128,9 @@ public class SearchActivity extends FragmentActivity implements
     private InputMethodManager mImm;
 
     /**
-     * The view that container the no search results text
+     * The view that container the no search results text and the loading progress bar
      */
-    private NoResultsContainer mNoResultsContainer;
+    private LoadingEmptyContainer mLoadingEmptyContainer;
 
     /**
      * List view adapter
@@ -269,10 +270,11 @@ public class SearchActivity extends FragmentActivity implements
             }
         });
 
+        mLoadingEmptyContainer = (LoadingEmptyContainer) findViewById(R.id.loading_empty_container);
         // setup the no results container
-        mNoResultsContainer = (NoResultsContainer)findViewById(R.id.no_results_container);
-        mNoResultsContainer.setMainText(R.string.empty_search);
-        mNoResultsContainer.setSecondaryText(R.string.empty_search_check);
+        NoResultsContainer noResults = mLoadingEmptyContainer.getNoResultsContainer();
+        noResults.setMainText(R.string.empty_search);
+        noResults.setSecondaryText(R.string.empty_search_check);
 
         initListView();
 
@@ -355,10 +357,10 @@ public class SearchActivity extends FragmentActivity implements
         mListView.setOnScrollListener(this);
         // sets the touch listener
         mListView.setOnTouchListener(this);
-        // If we setEmptyView with noResultsContainer it causes a crash in DragSortListView
+        // If we setEmptyView with mLoadingEmptyContainer it causes a crash in DragSortListView
         // when updating the search.  For now let's manually toggle visibility and come back
         // to this later
-        //mListView.setEmptyView(mNoResultsContainer);
+        //mListView.setEmptyView(mLoadingEmptyContainer);
 
         // load the search history list view
         mSearchHistoryListView = (ListView)findViewById(R.id.list_search_history);
@@ -384,7 +386,8 @@ public class SearchActivity extends FragmentActivity implements
         setLoading();
 
         // set the no results string ahead of time in case the user changes the string whiel loading
-        mNoResultsContainer.setMainHighlightText("\"" + mFilterString + "\"");
+        NoResultsContainer noResults = mLoadingEmptyContainer.getNoResultsContainer();
+        noResults.setMainHighlightText("\"" + mFilterString + "\"");
 
         // if we are at the top level, create a comparator to separate the different types into
         // their own sections (artists, albums, etc)
@@ -519,6 +522,7 @@ public class SearchActivity extends FragmentActivity implements
      */
     @Override
     public void onLoaderReset(final Loader<SectionListContainer<SearchResult>> loader) {
+        mAdapter.unload();
     }
 
     /**
@@ -593,7 +597,7 @@ public class SearchActivity extends FragmentActivity implements
 
         mSearchHistoryListView.setVisibility(View.INVISIBLE);
         mListView.setVisibility(View.INVISIBLE);
-        mNoResultsContainer.setVisibility(View.INVISIBLE);
+        mLoadingEmptyContainer.setVisibility(View.INVISIBLE);
 
         switch (mCurrentState) {
             case SearchHistory:
@@ -603,11 +607,12 @@ public class SearchActivity extends FragmentActivity implements
                 mListView.setVisibility(View.VISIBLE);
                 break;
             case Empty:
-                mNoResultsContainer.setVisibility(View.VISIBLE);
+                mLoadingEmptyContainer.setVisibility(View.VISIBLE);
+                mLoadingEmptyContainer.showNoResults();
                 break;
-            default:
-                // Don't show anything for now - we need a loading screen
-                // see bug: https://cyanogen.atlassian.net/browse/MUSIC-63
+            case Loading:
+                mLoadingEmptyContainer.setVisibility(View.VISIBLE);
+                mLoadingEmptyContainer.showLoading();
                 break;
         }
     }
@@ -972,7 +977,7 @@ public class SearchActivity extends FragmentActivity implements
 
         @Override
         public void onLoaderReset(Loader<ArrayAdapter<String>> cursorAdapterLoader) {
-
+            ((ArrayAdapter)mSearchHistoryListView.getAdapter()).clear();
         }
     }
 
index def092d..40de324 100644 (file)
@@ -19,6 +19,7 @@ import com.cyngn.eleven.utils.GenreFetcher;
 import com.cyngn.eleven.utils.PopupMenuHelper;
 import com.cyngn.eleven.utils.SongPopupMenuHelper;
 import com.cyngn.eleven.widgets.IPopupMenuCallback;
+import com.cyngn.eleven.widgets.LoadingEmptyContainer;
 import com.cyngn.eleven.widgets.PopupMenuButton;
 
 import java.util.List;
@@ -36,6 +37,7 @@ public class AlbumDetailFragment extends BaseFragment {
     private long mAlbumId;
     private String mArtistName;
     private String mAlbumName;
+    private LoadingEmptyContainer mLoadingEmptyContainer;
 
     @Override
     protected int getLayoutToInflate() {
@@ -123,7 +125,17 @@ public class AlbumDetailFragment extends BaseFragment {
 
     private void setupSongList() {
         mSongs = (ListView)mRootView.findViewById(R.id.songs);
-        mSongAdapter = new AlbumDetailSongAdapter(getActivity(), this);
+        mSongAdapter = new AlbumDetailSongAdapter(getActivity(), this) {
+            @Override
+            protected void onLoading() {
+                mLoadingEmptyContainer.showLoading();
+            }
+
+            @Override
+            protected void onNoResults() {
+                getContainingActivity().postRemoveFragment(AlbumDetailFragment.this);
+            }
+        };
         mSongAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() {
             @Override
             public void onPopupMenuClicked(View v, int position) {
@@ -132,6 +144,9 @@ public class AlbumDetailFragment extends BaseFragment {
         });
         mSongs.setAdapter(mSongAdapter);
         mSongs.setOnItemClickListener(mSongAdapter);
+        mLoadingEmptyContainer =
+                (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container);
+        mSongs.setEmptyView(mLoadingEmptyContainer);
     }
 
     /** called back by song loader */
@@ -143,10 +158,7 @@ public class AlbumDetailFragment extends BaseFragment {
 
         /** use the first song on the album to get a genre */
         if(!songs.isEmpty()) {
-            GenreFetcher.fetch(getActivity(), (int)songs.get(0).mSongId, mGenre);
-        } else {
-            // no songs, remove from stack
-            getContainingActivity().postRemoveFragment(this);
+            GenreFetcher.fetch(getActivity(), (int) songs.get(0).mSongId, mGenre);
         }
     }
 
index ea0e12e..cbb148d 100644 (file)
@@ -42,6 +42,7 @@ import com.cyngn.eleven.utils.MusicUtils;
 import com.cyngn.eleven.utils.NavUtils;
 import com.cyngn.eleven.utils.PopupMenuHelper;
 import com.cyngn.eleven.widgets.IPopupMenuCallback;
+import com.cyngn.eleven.widgets.LoadingEmptyContainer;
 import com.cyngn.eleven.widgets.NoResultsContainer;
 import com.viewpagerindicator.TitlePageIndicator;
 
@@ -79,6 +80,11 @@ public class AlbumFragment extends MusicBrowserFragment implements
      */
     private PopupMenuHelper mPopupMenuHelper;
 
+    /**
+     * This holds the loading progress bar as well as the no results message
+     */
+    private LoadingEmptyContainer mLoadingEmptyContainer;
+
     @Override
     public int getLoaderId() {
         return PagerAdapter.MusicFragments.ALBUM.ordinal();
@@ -183,6 +189,7 @@ public class AlbumFragment extends MusicBrowserFragment implements
      */
     @Override
     public Loader<SectionListContainer<Album>> onCreateLoader(final int id, final Bundle args) {
+        mLoadingEmptyContainer.showLoading();
         // if we ever decide to add section headers for grid items, we can pass a compartor
         // instead of null
         return new SectionCreator<Album>(getActivity(), new AlbumLoader(getActivity()), null);
@@ -196,9 +203,7 @@ public class AlbumFragment extends MusicBrowserFragment implements
                                final SectionListContainer<Album> data) {
         // Check for any errors
         if (data.mListResults.isEmpty()) {
-            // Set the empty text
-            final NoResultsContainer empty = (NoResultsContainer)mRootView.findViewById(R.id.no_results_container);
-            mGridView.setEmptyView(empty);
+            mLoadingEmptyContainer.showNoResults();
             return;
         }
 
@@ -253,7 +258,7 @@ public class AlbumFragment extends MusicBrowserFragment implements
     public void refresh() {
         // Wait a moment for the preference to change.
         SystemClock.sleep(10);
-        restartLoader(null, this);
+        restartLoader();
     }
 
     /**
@@ -316,5 +321,9 @@ public class AlbumFragment extends MusicBrowserFragment implements
         } else {
             mGridView.setNumColumns(TWO);
         }
+
+        // Show progress bar
+        mLoadingEmptyContainer = (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container);
+        mGridView.setEmptyView(mLoadingEmptyContainer);
     }
 }
index 25d6c39..7b0c049 100644 (file)
@@ -14,15 +14,14 @@ import com.cyngn.eleven.Config;
 import com.cyngn.eleven.R;
 import com.cyngn.eleven.adapters.ArtistDetailAlbumAdapter;
 import com.cyngn.eleven.adapters.ArtistDetailSongAdapter;
-import com.cyngn.eleven.adapters.IEmptyAdapterCallback;
 import com.cyngn.eleven.cache.ImageFetcher;
-import com.cyngn.eleven.lastfm.Artist;
 import com.cyngn.eleven.menu.FragmentMenuItems;
 import com.cyngn.eleven.model.Album;
 import com.cyngn.eleven.model.Song;
 import com.cyngn.eleven.utils.AlbumPopupMenuHelper;
 import com.cyngn.eleven.utils.SongPopupMenuHelper;
 import com.cyngn.eleven.widgets.IPopupMenuCallback;
+import com.cyngn.eleven.widgets.LoadingEmptyContainer;
 
 import java.util.TreeSet;
 
@@ -41,6 +40,8 @@ public class ArtistDetailFragment extends DetailFragment {
     private SongPopupMenuHelper mSongPopupMenuHelper;
     private AlbumPopupMenuHelper mAlbumPopupMenuHelper;
 
+    private LoadingEmptyContainer mLoadingEmptyContainer;
+
     @Override
     protected int getLayoutToInflate() { return R.layout.activity_artist_detail; }
 
@@ -94,15 +95,19 @@ public class ArtistDetailFragment extends DetailFragment {
                 inflate(R.layout.artist_detail_header, mSongs, false);
         mSongs.addHeaderView(mHeader);
         mSongs.setOnScrollListener(this);
-        mSongAdapter = new ArtistDetailSongAdapter(getActivity());
-        mSongAdapter.setOnEmptyAdapterListener(new IEmptyAdapterCallback() {
+        mSongAdapter = new ArtistDetailSongAdapter(getActivity()) {
+            @Override
+            protected void onLoading() {
+                mLoadingEmptyContainer.showLoading();
+            }
+
             @Override
-            public void onEmptyAdapter() {
+            protected void onNoResults() {
                 // no results - because the user deleted the last item - pop our fragment
                 // from the stack
                 getContainingActivity().postRemoveFragment(ArtistDetailFragment.this);
             }
-        });
+        };
         mSongAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() {
             @Override
             public void onPopupMenuClicked(View v, int position) {
@@ -111,6 +116,9 @@ public class ArtistDetailFragment extends DetailFragment {
         });
         mSongs.setAdapter(mSongAdapter);
         mSongs.setOnItemClickListener(mSongAdapter);
+        mLoadingEmptyContainer =
+                (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container);
+        mSongs.setEmptyView(mLoadingEmptyContainer);
     }
 
     private void setupPopupMenuHelpers() {
index 20cae3d..e1507a2 100644 (file)
@@ -45,6 +45,7 @@ import com.cyngn.eleven.utils.PopupMenuHelper;
 import com.cyngn.eleven.utils.SectionCreatorUtils;
 import com.cyngn.eleven.utils.SectionCreatorUtils.IItemCompare;
 import com.cyngn.eleven.widgets.IPopupMenuCallback;
+import com.cyngn.eleven.widgets.LoadingEmptyContainer;
 import com.cyngn.eleven.widgets.NoResultsContainer;
 import com.viewpagerindicator.TitlePageIndicator;
 
@@ -78,6 +79,11 @@ public class ArtistFragment extends MusicBrowserFragment implements
     private PopupMenuHelper mPopupMenuHelper;
 
     /**
+     * Loading container and no results container
+     */
+    private LoadingEmptyContainer mLoadingEmptyContainer;
+
+    /**
      * Empty constructor as per the {@link Fragment} documentation
      */
     public ArtistFragment() {
@@ -209,6 +215,7 @@ public class ArtistFragment extends MusicBrowserFragment implements
      */
     @Override
     public Loader<SectionListContainer<Artist>> onCreateLoader(final int id, final Bundle args) {
+        mLoadingEmptyContainer.showLoading();
         final Context context = getActivity();
         IItemCompare<Artist> comparator = SectionCreatorUtils.createArtistComparison(context);
         return new SectionCreator<Artist>(getActivity(), new ArtistLoader(context), comparator);
@@ -222,9 +229,7 @@ public class ArtistFragment extends MusicBrowserFragment implements
                                final SectionListContainer<Artist> data) {
         // Check for any errors
         if (data.mListResults.isEmpty()) {
-            // Set the empty text
-            final NoResultsContainer empty = (NoResultsContainer)mRootView.findViewById(R.id.no_results_container);
-            mListView.setEmptyView(empty);
+            mLoadingEmptyContainer.showNoResults();
             return;
         }
 
@@ -279,7 +284,7 @@ public class ArtistFragment extends MusicBrowserFragment implements
     public void refresh() {
         // Wait a moment for the preference to change.
         SystemClock.sleep(10);
-        restartLoader(null, this);
+        restartLoader();
     }
 
     /**
@@ -335,6 +340,9 @@ public class ArtistFragment extends MusicBrowserFragment implements
         mListView = (ListView)mRootView.findViewById(R.id.list_base);
         // Set the data behind the list
         mListView.setAdapter(mAdapter);
+        // set the loading and empty view container
+        mLoadingEmptyContainer = (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container);
+        mListView.setEmptyView(mLoadingEmptyContainer);
         // Set up the helpers
         initAbsListView(mListView);
     }
index 8584486..0afec03 100644 (file)
@@ -30,6 +30,7 @@ import com.cyngn.eleven.utils.MusicUtils;
 import com.cyngn.eleven.utils.PopupMenuHelper;
 import com.cyngn.eleven.utils.SongPopupMenuHelper;
 import com.cyngn.eleven.widgets.IPopupMenuCallback;
+import com.cyngn.eleven.widgets.LoadingEmptyContainer;
 import com.cyngn.eleven.widgets.NoResultsContainer;
 
 import java.util.ArrayList;
@@ -51,7 +52,7 @@ public class PlaylistDetailFragment extends DetailFragment implements
     private View mHeaderContainer;
     private ImageView mPlaylistImageView;
 
-    private NoResultsContainer mNoResultsContainer;
+    private LoadingEmptyContainer mLoadingEmptyContainer;
 
     private TextView mNumberOfSongs;
     private TextView mDurationOfPlaylist;
@@ -82,7 +83,6 @@ public class PlaylistDetailFragment extends DetailFragment implements
 
         setupHero();
         setupSongList();
-        setupNoResultsContainer();
     }
 
     @Override
@@ -167,12 +167,21 @@ public class PlaylistDetailFragment extends DetailFragment implements
         mListView.setVerticalScrollBarEnabled(false);
         mListView.setFastScrollEnabled(false);
         mListView.setPadding(0, 0, 0, 0);
+
+        // Adjust the progress bar padding to account for the header
+        int padTop = getResources().getDimensionPixelSize(R.dimen.playlist_detail_header_height);
+        mRootView.findViewById(R.id.progressbar).setPadding(0, padTop, 0, 0);
+
+        // set the loading and empty view container
+        mLoadingEmptyContainer =
+                (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container);
+        setupNoResultsContainer(mLoadingEmptyContainer.getNoResultsContainer());
+        mListView.setEmptyView(mLoadingEmptyContainer);
     }
 
-    private void setupNoResultsContainer() {
-        mNoResultsContainer = (NoResultsContainer)mRootView.findViewById(R.id.no_results_container);
-        mNoResultsContainer.setMainText(R.string.empty_playlist_main);
-        mNoResultsContainer.setSecondaryText(R.string.empty_playlist_secondary);
+    private void setupNoResultsContainer(final NoResultsContainer container) {
+        container.setMainText(R.string.empty_playlist_main);
+        container.setSecondaryText(R.string.empty_playlist_secondary);
     }
 
     /**
@@ -256,18 +265,18 @@ public class PlaylistDetailFragment extends DetailFragment implements
 
     @Override
     public Loader<List<Song>> onCreateLoader(int i, Bundle bundle) {
+        mLoadingEmptyContainer.showLoading();
+
         return new PlaylistSongLoader(getActivity(), mPlaylistId);
     }
 
     @Override
     public void onLoadFinished(final Loader<List<Song>> loader, final List<Song> data) {
         if (data.isEmpty()) {
-            // set the empty view - only do it here so we don't see the empty view by default
-            // while the list is loading
-            mListView.setEmptyView(mNoResultsContainer);
+            mLoadingEmptyContainer.showNoResults();
 
             // hide the header container
-            mHeaderContainer.setVisibility(View.GONE);
+            mHeaderContainer.setVisibility(View.INVISIBLE);
 
             // Return the correct count
             mAdapter.setCount(new ArrayList<Song>());
@@ -308,6 +317,9 @@ public class PlaylistDetailFragment extends DetailFragment implements
 
     @Override
     public void restartLoader() {
+        // unload the adapter - this will also get the loading progress bar to show
+        mAdapter.unload();
+
         getLoaderManager().restartLoader(0, getArguments(), this);
     }
 }
\ No newline at end of file
index b8c639b..81bf19a 100644 (file)
@@ -42,6 +42,7 @@ import com.cyngn.eleven.utils.MusicUtils;
 import com.cyngn.eleven.utils.NavUtils;
 import com.cyngn.eleven.utils.PopupMenuHelper;
 import com.cyngn.eleven.widgets.IPopupMenuCallback;
+import com.cyngn.eleven.widgets.LoadingEmptyContainer;
 
 import java.util.List;
 
@@ -70,6 +71,11 @@ public class PlaylistFragment extends MusicBrowserFragment implements
     private PopupMenuHelper mPopupMenuHelper;
 
     /**
+     * This holds the loading progress bar as well as the no results message
+     */
+    private LoadingEmptyContainer mLoadingEmptyContainer;
+
+    /**
      * Empty constructor as per the {@link Fragment} documentation
      */
     public PlaylistFragment() {
@@ -149,6 +155,10 @@ public class PlaylistFragment extends MusicBrowserFragment implements
         mListView.setRecyclerListener(new RecycleHolder());
         // Play the selected song
         mListView.setOnItemClickListener(this);
+        // Setup the loading and empty state
+        mLoadingEmptyContainer =
+                (LoadingEmptyContainer)rootView.findViewById(R.id.loading_empty_container);
+        mListView.setEmptyView(mLoadingEmptyContainer);
 
         // Register the music status listener
         ((BaseActivity)getActivity()).setMusicStateListenerListener(this);
@@ -197,6 +207,8 @@ public class PlaylistFragment extends MusicBrowserFragment implements
      */
     @Override
     public Loader<List<Playlist>> onCreateLoader(final int id, final Bundle args) {
+        // show the loading progress bar
+        mLoadingEmptyContainer.showLoading();
         return new PlaylistLoader(getActivity());
     }
 
@@ -207,6 +219,7 @@ public class PlaylistFragment extends MusicBrowserFragment implements
     public void onLoadFinished(final Loader<List<Playlist>> loader, final List<Playlist> data) {
         // Check for any errors
         if (data.isEmpty()) {
+            mLoadingEmptyContainer.showNoResults();
             return;
         }
 
index c42972f..2fc5117 100644 (file)
@@ -29,6 +29,7 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ProgressBar;
 
 import com.cyngn.eleven.MusicPlaybackService;
 import com.cyngn.eleven.R;
@@ -47,6 +48,7 @@ import com.cyngn.eleven.utils.MusicUtils;
 import com.cyngn.eleven.utils.PopupMenuHelper;
 import com.cyngn.eleven.widgets.IPopupMenuCallback;
 import com.cyngn.eleven.widgets.NoResultsContainer;
+import com.cyngn.eleven.widgets.LoadingEmptyContainer;
 import com.cyngn.eleven.widgets.PlayPauseProgressButton;
 
 import java.lang.ref.WeakReference;
@@ -90,9 +92,17 @@ public class QueueFragment extends Fragment implements LoaderCallbacks<List<Song
      */
     private PopupMenuHelper mPopupMenuHelper;
 
+    /**
+     * Root view
+     */
     private ViewGroup mRootView;
 
     /**
+     * This holds the loading progress bar as well as the no results message
+     */
+    private LoadingEmptyContainer mLoadingEmptyContainer;
+
+    /**
      * Empty constructor as per the {@link Fragment} documentation
      */
     public QueueFragment() {
@@ -184,6 +194,12 @@ public class QueueFragment extends Fragment implements LoaderCallbacks<List<Song
         mListView.setDragScrollProfile(this);
         // Enable fast scroll bars
         mListView.setFastScrollEnabled(true);
+        // Setup the loading and empty state
+        mLoadingEmptyContainer =
+                (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container);
+        // Setup the container strings
+        setupNoResultsContainer(mLoadingEmptyContainer.getNoResultsContainer());
+        mListView.setEmptyView(mLoadingEmptyContainer);
         return mRootView;
     }
 
@@ -252,8 +268,8 @@ public class QueueFragment extends Fragment implements LoaderCallbacks<List<Song
                  i <= mListView.getLastVisiblePosition(); i++) {
                 View childView = mListView.getChildAt(i);
                 if (childView != null) {
-                    PlayPauseProgressButton button = (PlayPauseProgressButton) childView.findViewById(R.id.playPauseProgressButton);
-
+                    PlayPauseProgressButton button =
+                            (PlayPauseProgressButton) childView.findViewById(R.id.playPauseProgressButton);
                     // pause or resume based on the flag
                     if (pause) {
                         button.pause();
@@ -298,6 +314,7 @@ public class QueueFragment extends Fragment implements LoaderCallbacks<List<Song
      */
     @Override
     public Loader<List<Song>> onCreateLoader(final int id, final Bundle args) {
+        mLoadingEmptyContainer.showLoading();
         return new QueueLoader(getActivity());
     }
 
@@ -309,13 +326,7 @@ public class QueueFragment extends Fragment implements LoaderCallbacks<List<Song
         mAdapter.unload(); // Start fresh
 
         if (data.isEmpty()) {
-            // No songs found, bring up the empty view
-            final NoResultsContainer empty =
-                    (NoResultsContainer)mRootView.findViewById(R.id.no_results_container);
-            // Setup the container strings
-            setupNoResultsContainer(empty);
-            // set the empty view into the list view
-            mListView.setEmptyView(empty);
+            mLoadingEmptyContainer.showNoResults();
             mAdapter.setCurrentlyPlayingSongId(SongAdapter.NOTHING_PLAYING);
             ((SlidingPanelActivity)getActivity()).clearMetaInfo();
         } else {
index 663a9ee..a8b01f8 100644 (file)
@@ -51,6 +51,9 @@ public class RecentFragment extends BasicSongFragment implements ISetupActionBar
      */
     @Override
     public Loader<SectionListContainer<Song>> onCreateLoader(final int id, final Bundle args) {
+        // show the loading progress bar
+        mLoadingEmptyContainer.showLoading();
+
         TopTracksLoader loader = new TopTracksLoader(getActivity(),
                 TopTracksLoader.QueryType.RecentSongs);
         return new SectionCreator<Song>(getActivity(), loader, null);
@@ -62,7 +65,7 @@ public class RecentFragment extends BasicSongFragment implements ISetupActionBar
     @Override
     public void onMetaChanged() {
         // refresh the list since a track playing means it should be recently played
-        getLoaderManager().restartLoader(LOADER, null, this);
+        restartLoader();
     }
 
     @Override
index aaaa37f..0024314 100644 (file)
@@ -51,6 +51,9 @@ public class SongFragment extends BasicSongFragment {
      */
     @Override
     public Loader<SectionListContainer<Song>> onCreateLoader(final int id, final Bundle args) {
+        // show the loading progress bar
+        mLoadingEmptyContainer.showLoading();
+
         // get the context
         Context context = getActivity();
 
index 830033e..1b8b781 100644 (file)
@@ -37,6 +37,7 @@ import com.cyngn.eleven.ui.activities.BaseActivity;
 import com.cyngn.eleven.utils.PopupMenuHelper;
 import com.cyngn.eleven.utils.SongPopupMenuHelper;
 import com.cyngn.eleven.widgets.IPopupMenuCallback;
+import com.cyngn.eleven.widgets.LoadingEmptyContainer;
 import com.cyngn.eleven.widgets.NoResultsContainer;
 
 import java.util.TreeSet;
@@ -67,7 +68,12 @@ public abstract class BasicSongFragment extends Fragment implements
     /**
      * Pop up menu helper
      */
-    private PopupMenuHelper mPopupMenuHelper;
+    protected PopupMenuHelper mPopupMenuHelper;
+
+    /**
+     * This holds the loading progress bar as well as the no results message
+     */
+    protected LoadingEmptyContainer mLoadingEmptyContainer;
 
     /**
      * Empty constructor as per the {@link Fragment} documentation
@@ -146,6 +152,12 @@ public abstract class BasicSongFragment extends Fragment implements
             }
         });
 
+        // Show progress bar
+        mLoadingEmptyContainer = (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container);
+        // Setup the container strings
+        setupNoResultsContainer(mLoadingEmptyContainer.getNoResultsContainer());
+        mListView.setEmptyView(mLoadingEmptyContainer);
+
         // Register the music status listener
         ((BaseActivity)getActivity()).setMusicStateListenerListener(this);
 
@@ -194,13 +206,7 @@ public abstract class BasicSongFragment extends Fragment implements
                                final SectionListContainer<Song> data) {
         // Check for any errors
         if (data.mListResults.isEmpty()) {
-            // Set the empty text
-            final NoResultsContainer empty =
-                    (NoResultsContainer)mRootView.findViewById(R.id.no_results_container);
-            // Setup the container strings
-            setupNoResultsContainer(empty);
-            // set the empty view into the list view
-            mListView.setEmptyView(empty);
+            mLoadingEmptyContainer.showNoResults();
             return;
         }
 
@@ -214,7 +220,7 @@ public abstract class BasicSongFragment extends Fragment implements
     public void refresh() {
         // Wait a moment for the preference to change.
         SystemClock.sleep(10);
-        getFragmentLoaderManager().restartLoader(getLoaderId(), null, this);
+        restartLoader();
     }
 
     /**
index 07e4e69..92493ad 100644 (file)
@@ -44,6 +44,9 @@ public class LastAddedFragment extends BasicSongFragment implements ISetupAction
      */
     @Override
     public Loader<SectionListContainer<Song>> onCreateLoader(final int id, final Bundle args) {
+        // show the loading progress bar
+        mLoadingEmptyContainer.showLoading();
+
         LastAddedLoader loader = new LastAddedLoader(getActivity());
         return new SectionCreator<Song>(getActivity(), loader, null);
     }
index 0460f40..7fbf413 100644 (file)
@@ -49,6 +49,9 @@ public class TopTracksFragment extends BasicSongFragment implements ISetupAction
      */
     @Override
     public Loader<SectionListContainer<Song>> onCreateLoader(final int id, final Bundle args) {
+        // show the loading progress bar
+        mLoadingEmptyContainer.showLoading();
+
         TopTracksLoader loader = new TopTracksLoader(getActivity(),
                 TopTracksLoader.QueryType.TopTracks);
         return new SectionCreator<Song>(getActivity(), loader, null);
diff --git a/src/com/cyngn/eleven/widgets/LoadingEmptyContainer.java b/src/com/cyngn/eleven/widgets/LoadingEmptyContainer.java
new file mode 100644 (file)
index 0000000..0522439
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 Cyanogen, Inc.
+ */
+package com.cyngn.eleven.widgets;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.cyngn.eleven.R;
+
+/**
+ * This class is the default empty state view for most listviews/fragments
+ * It allows the ability to set a main text, a main highlight text and a secondary text
+ * By default this container has some strings loaded, but other classes can call the apis to change
+ * the text
+ */
+public class LoadingEmptyContainer extends FrameLayout {
+    private static final int LOADING_DELAY = 300;
+
+    private Handler mHandler;
+    private Runnable mShowLoadingRunnable;
+
+    public LoadingEmptyContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mHandler = new Handler();
+        mShowLoadingRunnable = new Runnable() {
+            @Override
+            public void run() {
+                findViewById(R.id.progressbar).setVisibility(View.VISIBLE);
+                getNoResultsContainer().setVisibility(View.INVISIBLE);
+            }
+        };
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        hideAll();
+    }
+
+    public void hideAll() {
+        findViewById(R.id.progressbar).setVisibility(View.INVISIBLE);
+        getNoResultsContainer().setVisibility(View.INVISIBLE);
+    }
+
+    public void showLoading() {
+        hideAll();
+
+        if (!mHandler.hasCallbacks(mShowLoadingRunnable)) {
+            mHandler.postDelayed(mShowLoadingRunnable, LOADING_DELAY);
+        }
+    }
+
+    public void showNoResults() {
+        mHandler.removeCallbacks(mShowLoadingRunnable);
+
+        findViewById(R.id.progressbar).setVisibility(View.INVISIBLE);
+        getNoResultsContainer().setVisibility(View.VISIBLE);
+    }
+
+    public NoResultsContainer getNoResultsContainer() {
+        return (NoResultsContainer)findViewById(R.id.no_results_container);
+    }
+}