From afa21f5a5c89e670e75fab16142da606ecc00c10 Mon Sep 17 00:00:00 2001 From: Vavassor Date: Sat, 1 Jul 2017 23:23:42 -0400 Subject: [PATCH] Makes end of list footers have zero height. --- .../tusky/adapter/FooterViewHolder.java | 10 +++++++ .../tusky/adapter/TimelineAdapter.java | 4 +++ .../tusky/fragment/AccountListFragment.java | 28 ++++++++----------- .../tusky/fragment/NotificationsFragment.java | 28 ++++++++----------- .../tusky/fragment/TimelineFragment.java | 28 ++++++++----------- 5 files changed, 47 insertions(+), 51 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/FooterViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/FooterViewHolder.java index baa68d53..04ecf972 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/FooterViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/FooterViewHolder.java @@ -21,6 +21,7 @@ import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; +import android.support.v7.widget.RecyclerView.LayoutParams; import com.keylesspalace.tusky.R; @@ -51,18 +52,27 @@ public class FooterViewHolder extends RecyclerView.ViewHolder { public void setState(State state) { switch (state) { case LOADING: { + RecyclerView.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT); + container.setLayoutParams(layoutParams); container.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE); endMessage.setVisibility(View.GONE); break; } case END: { + RecyclerView.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT); + container.setLayoutParams(layoutParams); container.setVisibility(View.GONE); progressBar.setVisibility(View.GONE); endMessage.setVisibility(View.GONE); break; } case EMPTY: { + RecyclerView.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT); + container.setLayoutParams(layoutParams); container.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); endMessage.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/TimelineAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/TimelineAdapter.java index 84105f7b..fa92e32f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/TimelineAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/TimelineAdapter.java @@ -175,7 +175,11 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem } public void setFooterState(FooterViewHolder.State newFooterState) { + FooterViewHolder.State oldValue = footerState; footerState = newFooterState; + if (footerState != oldValue) { + notifyItemChanged(statuses.size()); + } } public void setMediaPreviewEnabled(boolean enabled) { diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java index 075026b4..35713ae4 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java @@ -407,7 +407,15 @@ public class AccountListFragment extends BaseFragment implements AccountActionLi } if (fromId != null || adapter.getItemCount() <= 1) { - setFooterState(FooterViewHolder.State.LOADING); + /* When this is called by the EndlessScrollListener it cannot refresh the footer state + * using adapter.notifyItemChanged. So its necessary to postpone doing so until a + * convenient time for the UI thread using a Runnable. */ + recyclerView.post(new Runnable() { + @Override + public void run() { + adapter.setFooterState(FooterViewHolder.State.LOADING); + } + }); } Callback> cb = new Callback>() { @@ -468,9 +476,9 @@ public class AccountListFragment extends BaseFragment implements AccountActionLi } fulfillAnyQueuedFetches(fetchEnd); if (accounts.size() == 0 && adapter.getItemCount() == 1) { - setFooterState(FooterViewHolder.State.EMPTY); + adapter.setFooterState(FooterViewHolder.State.EMPTY); } else { - setFooterState(FooterViewHolder.State.END); + adapter.setFooterState(FooterViewHolder.State.END); } } @@ -479,20 +487,6 @@ public class AccountListFragment extends BaseFragment implements AccountActionLi fulfillAnyQueuedFetches(fetchEnd); } - /* This needs to be called from the endless scroll listener, which does not allow notifying the - * adapter during the callback. So, this is the workaround. */ - private void setFooterState(FooterViewHolder.State state) { - // Set the adapter to set its state when it's bound, if the current Footer is offscreen. - adapter.setFooterState(state); - // Check if it's onscreen, and update it directly if it is. - RecyclerView.ViewHolder viewHolder = - recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); - if (viewHolder != null) { - FooterViewHolder holder = (FooterViewHolder) viewHolder; - holder.setState(state); - } - } - private void onRefresh() { fetchAccounts(null, adapter.getTopId(), FetchEnd.TOP); } diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java index 133ad5ca..4f128b18 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java @@ -275,7 +275,15 @@ public class NotificationsFragment extends SFragment implements } if (fromId != null || adapter.getItemCount() <= 1) { - setFooterState(FooterViewHolder.State.LOADING); + /* When this is called by the EndlessScrollListener it cannot refresh the footer state + * using adapter.notifyItemChanged. So its necessary to postpone doing so until a + * convenient time for the UI thread using a Runnable. */ + recyclerView.post(new Runnable() { + @Override + public void run() { + adapter.setFooterState(FooterViewHolder.State.LOADING); + } + }); } Call> call = mastodonApi.notifications(fromId, uptoId, null); @@ -342,9 +350,9 @@ public class NotificationsFragment extends SFragment implements } fulfillAnyQueuedFetches(fetchEnd); if (notifications.size() == 0 && adapter.getItemCount() == 1) { - setFooterState(FooterViewHolder.State.EMPTY); + adapter.setFooterState(FooterViewHolder.State.EMPTY); } else { - setFooterState(FooterViewHolder.State.END); + adapter.setFooterState(FooterViewHolder.State.END); } swipeRefreshLayout.setRefreshing(false); } @@ -355,20 +363,6 @@ public class NotificationsFragment extends SFragment implements fulfillAnyQueuedFetches(fetchEnd); } - /* This needs to be called from the endless scroll listener, which does not allow notifying the - * adapter during the callback. So, this is the workaround. */ - private void setFooterState(FooterViewHolder.State state) { - // Set the adapter to set its state when it's bound, if the current Footer is offscreen. - adapter.setFooterState(state); - // Check if it's onscreen, and update it directly if it is. - RecyclerView.ViewHolder viewHolder = - recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); - if (viewHolder != null) { - FooterViewHolder holder = (FooterViewHolder) viewHolder; - holder.setState(state); - } - } - private void fulfillAnyQueuedFetches(FetchEnd fetchEnd) { switch (fetchEnd) { case BOTTOM: { diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java index 759780c2..01346139 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java @@ -360,7 +360,15 @@ public class TimelineFragment extends SFragment implements } if (fromId != null || adapter.getItemCount() <= 1) { - setFooterState(FooterViewHolder.State.LOADING); + /* When this is called by the EndlessScrollListener it cannot refresh the footer state + * using adapter.notifyItemChanged. So its necessary to postpone doing so until a + * convenient time for the UI thread using a Runnable. */ + recyclerView.post(new Runnable() { + @Override + public void run() { + adapter.setFooterState(FooterViewHolder.State.LOADING); + } + }); } Callback> callback = new Callback>() { @@ -423,9 +431,9 @@ public class TimelineFragment extends SFragment implements } fulfillAnyQueuedFetches(fetchEnd); if (statuses.size() == 0 && adapter.getItemCount() == 1) { - setFooterState(FooterViewHolder.State.EMPTY); + adapter.setFooterState(FooterViewHolder.State.EMPTY); } else { - setFooterState(FooterViewHolder.State.END); + adapter.setFooterState(FooterViewHolder.State.END); } swipeRefreshLayout.setRefreshing(false); } @@ -436,20 +444,6 @@ public class TimelineFragment extends SFragment implements fulfillAnyQueuedFetches(fetchEnd); } - /* This needs to be called from the endless scroll listener, which does not allow notifying the - * adapter during the callback. So, this is the workaround. */ - private void setFooterState(FooterViewHolder.State state) { - // Set the adapter to set its state when it's bound, if the current Footer is offscreen. - adapter.setFooterState(state); - // Check if it's onscreen, and update it directly if it is. - RecyclerView.ViewHolder viewHolder = - recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); - if (viewHolder != null) { - FooterViewHolder holder = (FooterViewHolder) viewHolder; - holder.setState(state); - } - } - private void fulfillAnyQueuedFetches(FetchEnd fetchEnd) { switch (fetchEnd) { case BOTTOM: {