Loading and empty views for emails list

This commit is contained in:
str4d
2015-01-12 22:34:09 +00:00
parent 20c2b1eb87
commit c6d1d1e444
7 changed files with 175 additions and 19 deletions

View File

@@ -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'

View File

@@ -41,8 +41,8 @@ public class EmailListAdapter extends MultiSelectionUtil.SelectableAdapter<Recyc
private List<Email> 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<Recyc
@Override
public int getItemViewType(int position) {
if (mEmails == null || mEmails.isEmpty())
return R.layout.listitem_empty;
if (mIncompleteEmails > 0)
position--;
@@ -152,11 +155,10 @@ public class EmailListAdapter extends MultiSelectionUtil.SelectableAdapter<Recyc
View v = LayoutInflater.from(parent.getContext())
.inflate(viewType, parent, false);
switch (viewType) {
case R.layout.listitem_incomplete:
return new IncompleteEmailViewHolder(v);
case R.layout.listitem_email:
default:
return new EmailViewHolder(v);
default:
return new SimpleViewHolder(v);
}
}
@@ -164,6 +166,11 @@ public class EmailListAdapter extends MultiSelectionUtil.SelectableAdapter<Recyc
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case R.layout.listitem_empty:
((TextView) holder.itemView).setText(
mCtx.getResources().getString(R.string.folder_empty));
break;
case R.layout.listitem_incomplete:
((TextView) holder.itemView).setText(
mCtx.getResources().getQuantityString(R.plurals.incomplete_emails,
@@ -278,6 +285,9 @@ public class EmailListAdapter extends MultiSelectionUtil.SelectableAdapter<Recyc
}
evh.content.setText(email.getText());
break;
default:
break;
}
}
@@ -293,13 +303,17 @@ public class EmailListAdapter extends MultiSelectionUtil.SelectableAdapter<Recyc
// Return the size of the dataset (invoked by the layout manager)
@Override
public int getItemCount() {
if (mEmails != null)
return mIncompleteEmails > 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();
}
}

View File

@@ -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<Void, Void, Void> 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() {

View File

@@ -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.
* <p/>
* 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();
}
}

View File

@@ -5,11 +5,31 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/emails_list"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"/>
android:layout_height="match_parent">
<i2p.bote.android.util.LoadingRecyclerView
android:id="@+id/emails_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"/>
<RelativeLayout
android:id="@+id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.pnikosis.materialishprogress.ProgressWheel
android:id="@+id/loading"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
app:barColor="@color/accent"
app:progressIndeterminate="true"/>
</RelativeLayout>
</FrameLayout>
<net.i2p.android.ext.floatingactionbutton.FloatingActionButton
android:id="@+id/promoted_action"

View File

@@ -10,11 +10,31 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/emails_list"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"/>
android:layout_height="match_parent">
<i2p.bote.android.util.LoadingRecyclerView
android:id="@+id/emails_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"/>
<RelativeLayout
android:id="@+id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.pnikosis.materialishprogress.ProgressWheel
android:id="@+id/loading"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
app:barColor="@color/accent"
app:progressIndeterminate="true"/>
</RelativeLayout>
</FrameLayout>
<net.i2p.android.ext.floatingactionbutton.FloatingActionButton
android:id="@+id/promoted_action"

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_height_one_line"
android:gravity="center"/>