Allow pull-to-refresh in thread view (closes #73)

This commit is contained in:
Raphael Michel 2017-04-15 12:28:22 +02:00
parent 69c1b88ff4
commit f4109f38a8
3 changed files with 53 additions and 12 deletions

View file

@ -65,20 +65,43 @@ class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
notifyItemRemoved(position); notifyItemRemoved(position);
} }
int insertStatus(Status status) { int setStatus(Status status) {
if (statuses.size() > 0 && statuses.get(statusIndex).equals(status)) {
// Do not add this status on refresh, it's already in there.
statuses.set(statusIndex, status);
return statusIndex;
}
int i = statusIndex; int i = statusIndex;
statuses.add(i, status); statuses.add(i, status);
notifyItemInserted(i); notifyItemInserted(i);
return i; return i;
} }
void addAncestors(List<Status> ancestors) { void setContext(List<Status> ancestors, List<Status> descendants) {
Status mainStatus = null;
// In case of refresh, remove old ancestors and descendants first. We'll remove all blindly,
// as we have no guarantee on their order to be the same as before
int old_size = statuses.size();
if (old_size > 0) {
mainStatus = statuses.get(statusIndex);
statuses.clear();
notifyItemRangeRemoved(0, old_size);
}
// Insert newly fetched ancestors
statusIndex = ancestors.size(); statusIndex = ancestors.size();
statuses.addAll(0, ancestors); statuses.addAll(0, ancestors);
notifyItemRangeInserted(0, statusIndex); notifyItemRangeInserted(0, statusIndex);
if (mainStatus != null) {
// In case we needed to delete everything (which is way easier than deleting
// everything except one), re-insert the remaining status here.
statuses.add(statusIndex, mainStatus);
notifyItemInserted(statusIndex);
} }
void addDescendants(List<Status> descendants) { // Insert newly fetched descendants
int end = statuses.size(); int end = statuses.size();
statuses.addAll(descendants); statuses.addAll(descendants);
notifyItemRangeInserted(end, descendants.size()); notifyItemRangeInserted(end, descendants.size());

View file

@ -21,6 +21,7 @@ import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
@ -34,9 +35,11 @@ import com.keylesspalace.tusky.entity.StatusContext;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
public class ViewThreadFragment extends SFragment implements StatusActionListener { public class ViewThreadFragment extends SFragment implements
SwipeRefreshLayout.OnRefreshListener, StatusActionListener {
private static final String TAG = "ViewThreadFragment"; private static final String TAG = "ViewThreadFragment";
private SwipeRefreshLayout swipeRefreshLayout;
private RecyclerView recyclerView; private RecyclerView recyclerView;
private ThreadAdapter adapter; private ThreadAdapter adapter;
private String thisThreadsStatusId; private String thisThreadsStatusId;
@ -56,6 +59,9 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
View rootView = inflater.inflate(R.layout.fragment_view_thread, container, false); View rootView = inflater.inflate(R.layout.fragment_view_thread, container, false);
Context context = getContext(); Context context = getContext();
swipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_refresh_layout);
swipeRefreshLayout.setOnRefreshListener(this);
recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view); recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true); recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(context); LinearLayoutManager layoutManager = new LinearLayoutManager(context);
@ -86,7 +92,7 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
@Override @Override
public void onResponse(Call<Status> call, retrofit2.Response<Status> response) { public void onResponse(Call<Status> call, retrofit2.Response<Status> response) {
if (response.isSuccessful()) { if (response.isSuccessful()) {
int position = adapter.insertStatus(response.body()); int position = adapter.setStatus(response.body());
recyclerView.scrollToPosition(position); recyclerView.scrollToPosition(position);
} else { } else {
onThreadRequestFailure(id); onThreadRequestFailure(id);
@ -109,10 +115,10 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
@Override @Override
public void onResponse(Call<StatusContext> call, retrofit2.Response<StatusContext> response) { public void onResponse(Call<StatusContext> call, retrofit2.Response<StatusContext> response) {
if (response.isSuccessful()) { if (response.isSuccessful()) {
swipeRefreshLayout.setRefreshing(false);
StatusContext context = response.body(); StatusContext context = response.body();
adapter.addAncestors(context.ancestors); adapter.setContext(context.ancestors, context.descendants);
adapter.addDescendants(context.descendants);
} else { } else {
onThreadRequestFailure(id); onThreadRequestFailure(id);
} }
@ -128,6 +134,7 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
private void onThreadRequestFailure(final String id) { private void onThreadRequestFailure(final String id) {
View view = getView(); View view = getView();
swipeRefreshLayout.setRefreshing(false);
if (view != null) { if (view != null) {
Snackbar.make(view, R.string.error_generic, Snackbar.LENGTH_LONG) Snackbar.make(view, R.string.error_generic, Snackbar.LENGTH_LONG)
.setAction(R.string.action_retry, new View.OnClickListener() { .setAction(R.string.action_retry, new View.OnClickListener() {
@ -143,6 +150,11 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
} }
} }
public void onRefresh() {
sendStatusRequest(thisThreadsStatusId);
sendThreadRequest(thisThreadsStatusId);
}
public void onReply(int position) { public void onReply(int position) {
super.reply(adapter.getItem(position)); super.reply(adapter.getItem(position));
} }

View file

@ -1,7 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:scrollbars="vertical" /> android:scrollbars="vertical" />
</android.support.v4.widget.SwipeRefreshLayout>