From c6d1d1e444450be5a02a53fd0d5602bc48262bf2 Mon Sep 17 00:00:00 2001 From: str4d Date: Mon, 12 Jan 2015 22:34:09 +0000 Subject: [PATCH] Loading and empty views for emails list --- app/build.gradle | 1 + .../i2p/bote/android/EmailListAdapter.java | 32 +++++-- .../i2p/bote/android/EmailListFragment.java | 10 ++- .../android/util/LoadingRecyclerView.java | 89 +++++++++++++++++++ .../main/res/layout/fragment_list_emails.xml | 28 +++++- .../fragment_list_emails_with_refresh.xml | 28 +++++- app/src/main/res/layout/listitem_empty.xml | 6 ++ 7 files changed, 175 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/i2p/bote/android/util/LoadingRecyclerView.java create mode 100644 app/src/main/res/layout/listitem_empty.xml diff --git a/app/build.gradle b/app/build.gradle index 470f33a..4b37271 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,6 +55,7 @@ dependencies { compile 'com.google.zxing:core:3.1.0' compile 'com.google.zxing:android-integration:3.1.0' compile 'com.androidplot:androidplot-core:0.6.1' + compile 'com.pnikosis:materialish-progress:1.2' // Testing-only dependencies androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0' diff --git a/app/src/main/java/i2p/bote/android/EmailListAdapter.java b/app/src/main/java/i2p/bote/android/EmailListAdapter.java index 629896c..97b3b21 100644 --- a/app/src/main/java/i2p/bote/android/EmailListAdapter.java +++ b/app/src/main/java/i2p/bote/android/EmailListAdapter.java @@ -41,8 +41,8 @@ public class EmailListAdapter extends MultiSelectionUtil.SelectableAdapter mEmails; private int mIncompleteEmails; - public static class IncompleteEmailViewHolder extends RecyclerView.ViewHolder { - public IncompleteEmailViewHolder(View itemView) { + public static class SimpleViewHolder extends RecyclerView.ViewHolder { + public SimpleViewHolder(View itemView) { super(itemView); } } @@ -140,6 +140,9 @@ public class EmailListAdapter extends MultiSelectionUtil.SelectableAdapter 0) position--; @@ -152,11 +155,10 @@ public class EmailListAdapter extends MultiSelectionUtil.SelectableAdapter 0 ? mEmails.size() + 1 : mEmails.size(); - return 0; + if (mEmails == null || mEmails.isEmpty()) + return 1; + + return mIncompleteEmails > 0 ? mEmails.size() + 1 : mEmails.size(); } public long getItemId(int position) { + if (mEmails == null || mEmails.isEmpty()) + return 0; + Email email = getEmail(position); - return email == null ? 0 : email.getMessageID().hashCode(); + return email == null ? 1 : email.getMessageID().hashCode(); } } diff --git a/app/src/main/java/i2p/bote/android/EmailListFragment.java b/app/src/main/java/i2p/bote/android/EmailListFragment.java index d8483b1..024b20e 100644 --- a/app/src/main/java/i2p/bote/android/EmailListFragment.java +++ b/app/src/main/java/i2p/bote/android/EmailListFragment.java @@ -22,6 +22,8 @@ import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.Toast; +import com.pnikosis.materialishprogress.ProgressWheel; + import net.i2p.I2PAppContext; import net.i2p.util.Log; @@ -37,6 +39,7 @@ import i2p.bote.android.util.AuthenticatedFragment; import i2p.bote.android.util.BetterAsyncTaskLoader; import i2p.bote.android.util.BoteHelper; import i2p.bote.android.util.DividerItemDecoration; +import i2p.bote.android.util.LoadingRecyclerView; import i2p.bote.android.util.MoveToDialogFragment; import i2p.bote.android.util.MultiSelectionUtil; import i2p.bote.android.util.MultiSwipeRefreshLayout; @@ -58,7 +61,7 @@ public class EmailListFragment extends AuthenticatedFragment implements private MultiSwipeRefreshLayout mSwipeRefreshLayout; private AsyncTask mCheckingTask; - private RecyclerView mEmailsList; + private LoadingRecyclerView mEmailsList; private EmailListAdapter mAdapter; private EmailFolder mFolder; @@ -107,7 +110,10 @@ public class EmailListFragment extends AuthenticatedFragment implements isInbox ? R.layout.fragment_list_emails_with_refresh : R.layout.fragment_list_emails, container, false); - mEmailsList = (RecyclerView) v.findViewById(R.id.emails_list); + mEmailsList = (LoadingRecyclerView) v.findViewById(R.id.emails_list); + View empty = v.findViewById(R.id.empty); + ProgressWheel loading = (ProgressWheel) v.findViewById(R.id.loading); + mEmailsList.setLoadingView(empty, loading); mNewEmail = (ImageButton) v.findViewById(R.id.promoted_action); mNewEmail.setOnClickListener(new View.OnClickListener() { diff --git a/app/src/main/java/i2p/bote/android/util/LoadingRecyclerView.java b/app/src/main/java/i2p/bote/android/util/LoadingRecyclerView.java new file mode 100644 index 0000000..989ebf5 --- /dev/null +++ b/app/src/main/java/i2p/bote/android/util/LoadingRecyclerView.java @@ -0,0 +1,89 @@ +package i2p.bote.android.util; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.View; + +import com.pnikosis.materialishprogress.ProgressWheel; + +public class LoadingRecyclerView extends RecyclerView { + private View mLoadingView; + private ProgressWheel mLoadingWheel; + private boolean mLoading; + final private AdapterDataObserver observer = new AdapterDataObserver() { + @Override + public void onChanged() { + mLoading = false; + updateLoading(); + } + + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + mLoading = false; + updateLoading(); + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + mLoading = false; + updateLoading(); + } + }; + + public LoadingRecyclerView(Context context) { + super(context); + } + + public LoadingRecyclerView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LoadingRecyclerView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + private void updateLoading() { + if (mLoadingView != null) { + mLoadingView.setVisibility(mLoading ? VISIBLE : GONE); + setVisibility(mLoading ? GONE : VISIBLE); + if (mLoadingWheel != null) { + if (mLoading && !mLoadingWheel.isSpinning()) + mLoadingWheel.spin(); + else if (!mLoading && mLoadingWheel.isSpinning()) + mLoadingWheel.stopSpinning(); + } + } + } + + @Override + public void setAdapter(Adapter adapter) { + final Adapter oldAdapter = getAdapter(); + if (oldAdapter != null) { + oldAdapter.unregisterAdapterDataObserver(observer); + } + super.setAdapter(adapter); + if (adapter != null) { + adapter.registerAdapterDataObserver(observer); + } + } + + /** + * Set the views to use for showing state. + *

+ * This method also sets the state to "loading". + * + * @param loadingView The view to show in place of the RecyclerView while loading. + * @param progressWheel The indeterminate ProgressWheel to spin while loading, if any. + */ + public void setLoadingView(View loadingView, ProgressWheel progressWheel) { + mLoadingView = loadingView; + mLoadingWheel = progressWheel; + setLoading(true); + } + + public void setLoading(boolean loading) { + mLoading = loading; + updateLoading(); + } +} diff --git a/app/src/main/res/layout/fragment_list_emails.xml b/app/src/main/res/layout/fragment_list_emails.xml index de1fdc0..c1f7f8c 100644 --- a/app/src/main/res/layout/fragment_list_emails.xml +++ b/app/src/main/res/layout/fragment_list_emails.xml @@ -5,11 +5,31 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:layout_height="match_parent"> + + + + + + + + - + android:layout_height="match_parent"> + + + + + + + + + \ No newline at end of file