From 33883aca3d4c5b56622c867d44b25e668bbf9148 Mon Sep 17 00:00:00 2001 From: Vavassor Date: Tue, 7 Feb 2017 16:47:05 -0500 Subject: [PATCH] End of timelines are now detected correctly. Also, duplicate notifications/accounts are prevented. --- .../java/com/keylesspalace/tusky/Account.java | 16 ++++++++ .../keylesspalace/tusky/AccountAdapter.java | 1 + .../keylesspalace/tusky/AccountFragment.java | 13 +++++-- .../keylesspalace/tusky/FooterViewHolder.java | 39 +++++++++++++++---- .../com/keylesspalace/tusky/Notification.java | 16 ++++++++ .../tusky/NotificationsAdapter.java | 1 + .../tusky/NotificationsFragment.java | 13 +++++-- .../keylesspalace/tusky/TimelineAdapter.java | 1 + .../keylesspalace/tusky/TimelineFragment.java | 13 +++++-- app/src/main/res/layout/item_footer.xml | 6 +++ app/src/main/res/values/strings.xml | 3 ++ 11 files changed, 103 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/Account.java b/app/src/main/java/com/keylesspalace/tusky/Account.java index 8cb45b37..c22eab6f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/Account.java +++ b/app/src/main/java/com/keylesspalace/tusky/Account.java @@ -73,4 +73,20 @@ public class Account { } return accounts; } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (this.id == null) { + return this == other; + } else if (!(other instanceof Account)) { + return false; + } + Account account = (Account) other; + return account.id.equals(this.id); + } } diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountAdapter.java b/app/src/main/java/com/keylesspalace/tusky/AccountAdapter.java index efc0a02b..35c2cf87 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/AccountAdapter.java @@ -71,6 +71,7 @@ public class AccountAdapter extends RecyclerView.Adapter { FooterViewHolder holder = (FooterViewHolder) viewHolder; holder.setupButton(footerActionListener); holder.setRetryMessage(R.string.footer_retry_accounts); + holder.setEndOfTimelineMessage(R.string.footer_end_of_accounts); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountFragment.java b/app/src/main/java/com/keylesspalace/tusky/AccountFragment.java index af619231..3eb3868b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/AccountFragment.java @@ -46,6 +46,7 @@ import java.util.Map; public class AccountFragment extends Fragment implements AccountActionListener, FooterActionListener { private static final String TAG = "Account"; + private static int EXPECTED_ACCOUNTS_FETCHED = 20; public enum Type { FOLLOWS, @@ -200,20 +201,24 @@ public class AccountFragment extends Fragment implements AccountActionListener, } else { adapter.update(accounts); } - showFetchAccountsRetry(false); + if (accounts.size() >= EXPECTED_ACCOUNTS_FETCHED) { + setFetchTimelineState(FooterViewHolder.State.LOADING); + } else { + setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE); + } } private void onFetchAccountsFailure(Exception exception) { - showFetchAccountsRetry(true); + setFetchTimelineState(FooterViewHolder.State.RETRY); Log.e(TAG, "Fetch failure: " + exception.getMessage()); } - private void showFetchAccountsRetry(boolean show) { + private void setFetchTimelineState(FooterViewHolder.State state) { RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); if (viewHolder != null) { FooterViewHolder holder = (FooterViewHolder) viewHolder; - holder.showRetry(show); + holder.setState(state); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/FooterViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/FooterViewHolder.java index cb68cb95..247e4e5a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/FooterViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/FooterViewHolder.java @@ -27,6 +27,13 @@ public class FooterViewHolder extends RecyclerView.ViewHolder { private TextView retryMessage; private Button retry; private ProgressBar progressBar; + private TextView endOfTimelineMessage; + + enum State { + LOADING, + RETRY, + END_OF_TIMELINE, + } public FooterViewHolder(View itemView) { super(itemView); @@ -35,6 +42,7 @@ public class FooterViewHolder extends RecyclerView.ViewHolder { retry = (Button) itemView.findViewById(R.id.footer_retry_button); progressBar = (ProgressBar) itemView.findViewById(R.id.footer_progress_bar); progressBar.setIndeterminate(true); + endOfTimelineMessage = (TextView) itemView.findViewById(R.id.footer_end_of_timeline_text); } public void setupButton(final FooterActionListener listener) { @@ -50,13 +58,30 @@ public class FooterViewHolder extends RecyclerView.ViewHolder { retryMessage.setText(messageId); } - public void showRetry(boolean show) { - if (!show) { - retryBar.setVisibility(View.GONE); - progressBar.setVisibility(View.VISIBLE); - } else { - retryBar.setVisibility(View.VISIBLE); - progressBar.setVisibility(View.GONE); + public void setEndOfTimelineMessage(int messageId) { + endOfTimelineMessage.setText(messageId); + } + + public void setState(State state) { + switch (state) { + case LOADING: { + retryBar.setVisibility(View.GONE); + progressBar.setVisibility(View.VISIBLE); + endOfTimelineMessage.setVisibility(View.GONE); + break; + } + case RETRY: { + retryBar.setVisibility(View.VISIBLE); + progressBar.setVisibility(View.GONE); + endOfTimelineMessage.setVisibility(View.GONE); + break; + } + case END_OF_TIMELINE: { + retryBar.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + endOfTimelineMessage.setVisibility(View.VISIBLE); + break; + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/Notification.java b/app/src/main/java/com/keylesspalace/tusky/Notification.java index d5fbacf3..6dce737c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/Notification.java +++ b/app/src/main/java/com/keylesspalace/tusky/Notification.java @@ -91,4 +91,20 @@ public class Notification { } return notifications; } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (this.id == null) { + return this == other; + } else if (!(other instanceof Notification)) { + return false; + } + Notification notification = (Notification) other; + return notification.getId().equals(this.id); + } } diff --git a/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java index 13b3bd42..f8dcfa3d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java @@ -102,6 +102,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte FooterViewHolder holder = (FooterViewHolder) viewHolder; holder.setupButton(footerListener); holder.setRetryMessage(R.string.footer_retry_notifications); + holder.setEndOfTimelineMessage(R.string.footer_end_of_notifications); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/NotificationsFragment.java index 9209b1eb..b815a7cd 100644 --- a/app/src/main/java/com/keylesspalace/tusky/NotificationsFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/NotificationsFragment.java @@ -43,6 +43,7 @@ import java.util.Map; public class NotificationsFragment extends SFragment implements SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener { private static final String TAG = "Notifications"; // logging tag + private static final int EXPECTED_NOTIFICATIONS_FETCHED = 10; private SwipeRefreshLayout swipeRefreshLayout; private RecyclerView recyclerView; @@ -139,22 +140,26 @@ public class NotificationsFragment extends SFragment implements } else { adapter.update(notifications); } - showFetchTimelineRetry(false); + if (notifications.size() >= EXPECTED_NOTIFICATIONS_FETCHED) { + setFetchTimelineState(FooterViewHolder.State.LOADING); + } else { + setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE); + } swipeRefreshLayout.setRefreshing(false); } private void onFetchNotificationsFailure(Exception exception) { - showFetchTimelineRetry(true); + setFetchTimelineState(FooterViewHolder.State.RETRY); swipeRefreshLayout.setRefreshing(false); Log.e(TAG, "Fetch failure: " + exception.getMessage()); } - private void showFetchTimelineRetry(boolean show) { + private void setFetchTimelineState(FooterViewHolder.State state) { RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); if (viewHolder != null) { FooterViewHolder holder = (FooterViewHolder) viewHolder; - holder.showRetry(show); + holder.setState(state); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java b/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java index 96295db0..d14e9ec6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java @@ -67,6 +67,7 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem FooterViewHolder holder = (FooterViewHolder) viewHolder; holder.setupButton(footerListener); holder.setRetryMessage(R.string.footer_retry_statuses); + holder.setEndOfTimelineMessage(R.string.footer_end_of_statuses); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/TimelineFragment.java b/app/src/main/java/com/keylesspalace/tusky/TimelineFragment.java index 5cebce5e..dcef6553 100644 --- a/app/src/main/java/com/keylesspalace/tusky/TimelineFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/TimelineFragment.java @@ -43,6 +43,7 @@ import java.util.Map; public class TimelineFragment extends SFragment implements SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener { private static final String TAG = "Timeline"; // logging tag + private static final int EXPECTED_STATUSES_FETCHED = 20; public enum Kind { HOME, @@ -229,22 +230,26 @@ public class TimelineFragment extends SFragment implements } else { adapter.update(statuses); } - showFetchTimelineRetry(false); + if (statuses.size() >= EXPECTED_STATUSES_FETCHED) { + setFetchTimelineState(FooterViewHolder.State.LOADING); + } else { + setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE); + } swipeRefreshLayout.setRefreshing(false); } public void onFetchTimelineFailure(Exception exception) { - showFetchTimelineRetry(true); + setFetchTimelineState(FooterViewHolder.State.RETRY); swipeRefreshLayout.setRefreshing(false); Log.e(TAG, exception.getMessage()); } - private void showFetchTimelineRetry(boolean show) { + private void setFetchTimelineState(FooterViewHolder.State state) { RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); if (viewHolder != null) { FooterViewHolder holder = (FooterViewHolder) viewHolder; - holder.showRetry(show); + holder.setState(state); } } diff --git a/app/src/main/res/layout/item_footer.xml b/app/src/main/res/layout/item_footer.xml index c07c8e96..44e8d6f6 100644 --- a/app/src/main/res/layout/item_footer.xml +++ b/app/src/main/res/layout/item_footer.xml @@ -36,6 +36,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" /> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 31f4c4b3..83220dc6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -74,6 +74,9 @@ Could not load the rest of the statuses. Could not load the rest of the statuses. Could not load the rest of the accounts. + end of the statuses + end of the notifications + end of the accounts %s boosted your status %s favourited your status