End of timelines are now detected correctly. Also, duplicate notifications/accounts are prevented.

This commit is contained in:
Vavassor 2017-02-07 16:47:05 -05:00
parent 5f39da27b3
commit 33883aca3d
11 changed files with 103 additions and 19 deletions

View file

@ -73,4 +73,20 @@ public class Account {
} }
return accounts; 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);
}
} }

View file

@ -71,6 +71,7 @@ public class AccountAdapter extends RecyclerView.Adapter {
FooterViewHolder holder = (FooterViewHolder) viewHolder; FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.setupButton(footerActionListener); holder.setupButton(footerActionListener);
holder.setRetryMessage(R.string.footer_retry_accounts); holder.setRetryMessage(R.string.footer_retry_accounts);
holder.setEndOfTimelineMessage(R.string.footer_end_of_accounts);
} }
} }

View file

@ -46,6 +46,7 @@ import java.util.Map;
public class AccountFragment extends Fragment implements AccountActionListener, public class AccountFragment extends Fragment implements AccountActionListener,
FooterActionListener { FooterActionListener {
private static final String TAG = "Account"; private static final String TAG = "Account";
private static int EXPECTED_ACCOUNTS_FETCHED = 20;
public enum Type { public enum Type {
FOLLOWS, FOLLOWS,
@ -200,20 +201,24 @@ public class AccountFragment extends Fragment implements AccountActionListener,
} else { } else {
adapter.update(accounts); 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) { private void onFetchAccountsFailure(Exception exception) {
showFetchAccountsRetry(true); setFetchTimelineState(FooterViewHolder.State.RETRY);
Log.e(TAG, "Fetch failure: " + exception.getMessage()); Log.e(TAG, "Fetch failure: " + exception.getMessage());
} }
private void showFetchAccountsRetry(boolean show) { private void setFetchTimelineState(FooterViewHolder.State state) {
RecyclerView.ViewHolder viewHolder = RecyclerView.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1);
if (viewHolder != null) { if (viewHolder != null) {
FooterViewHolder holder = (FooterViewHolder) viewHolder; FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.showRetry(show); holder.setState(state);
} }
} }

View file

@ -27,6 +27,13 @@ public class FooterViewHolder extends RecyclerView.ViewHolder {
private TextView retryMessage; private TextView retryMessage;
private Button retry; private Button retry;
private ProgressBar progressBar; private ProgressBar progressBar;
private TextView endOfTimelineMessage;
enum State {
LOADING,
RETRY,
END_OF_TIMELINE,
}
public FooterViewHolder(View itemView) { public FooterViewHolder(View itemView) {
super(itemView); super(itemView);
@ -35,6 +42,7 @@ public class FooterViewHolder extends RecyclerView.ViewHolder {
retry = (Button) itemView.findViewById(R.id.footer_retry_button); retry = (Button) itemView.findViewById(R.id.footer_retry_button);
progressBar = (ProgressBar) itemView.findViewById(R.id.footer_progress_bar); progressBar = (ProgressBar) itemView.findViewById(R.id.footer_progress_bar);
progressBar.setIndeterminate(true); progressBar.setIndeterminate(true);
endOfTimelineMessage = (TextView) itemView.findViewById(R.id.footer_end_of_timeline_text);
} }
public void setupButton(final FooterActionListener listener) { public void setupButton(final FooterActionListener listener) {
@ -50,13 +58,30 @@ public class FooterViewHolder extends RecyclerView.ViewHolder {
retryMessage.setText(messageId); retryMessage.setText(messageId);
} }
public void showRetry(boolean show) { public void setEndOfTimelineMessage(int messageId) {
if (!show) { endOfTimelineMessage.setText(messageId);
}
public void setState(State state) {
switch (state) {
case LOADING: {
retryBar.setVisibility(View.GONE); retryBar.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
} else { endOfTimelineMessage.setVisibility(View.GONE);
break;
}
case RETRY: {
retryBar.setVisibility(View.VISIBLE); retryBar.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE); 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;
}
} }
} }
} }

View file

@ -91,4 +91,20 @@ public class Notification {
} }
return notifications; 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);
}
} }

View file

@ -102,6 +102,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
FooterViewHolder holder = (FooterViewHolder) viewHolder; FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.setupButton(footerListener); holder.setupButton(footerListener);
holder.setRetryMessage(R.string.footer_retry_notifications); holder.setRetryMessage(R.string.footer_retry_notifications);
holder.setEndOfTimelineMessage(R.string.footer_end_of_notifications);
} }
} }

View file

@ -43,6 +43,7 @@ import java.util.Map;
public class NotificationsFragment extends SFragment implements public class NotificationsFragment extends SFragment implements
SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener { SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener {
private static final String TAG = "Notifications"; // logging tag private static final String TAG = "Notifications"; // logging tag
private static final int EXPECTED_NOTIFICATIONS_FETCHED = 10;
private SwipeRefreshLayout swipeRefreshLayout; private SwipeRefreshLayout swipeRefreshLayout;
private RecyclerView recyclerView; private RecyclerView recyclerView;
@ -139,22 +140,26 @@ public class NotificationsFragment extends SFragment implements
} else { } else {
adapter.update(notifications); 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); swipeRefreshLayout.setRefreshing(false);
} }
private void onFetchNotificationsFailure(Exception exception) { private void onFetchNotificationsFailure(Exception exception) {
showFetchTimelineRetry(true); setFetchTimelineState(FooterViewHolder.State.RETRY);
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
Log.e(TAG, "Fetch failure: " + exception.getMessage()); Log.e(TAG, "Fetch failure: " + exception.getMessage());
} }
private void showFetchTimelineRetry(boolean show) { private void setFetchTimelineState(FooterViewHolder.State state) {
RecyclerView.ViewHolder viewHolder = RecyclerView.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1);
if (viewHolder != null) { if (viewHolder != null) {
FooterViewHolder holder = (FooterViewHolder) viewHolder; FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.showRetry(show); holder.setState(state);
} }
} }

View file

@ -67,6 +67,7 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
FooterViewHolder holder = (FooterViewHolder) viewHolder; FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.setupButton(footerListener); holder.setupButton(footerListener);
holder.setRetryMessage(R.string.footer_retry_statuses); holder.setRetryMessage(R.string.footer_retry_statuses);
holder.setEndOfTimelineMessage(R.string.footer_end_of_statuses);
} }
} }

View file

@ -43,6 +43,7 @@ import java.util.Map;
public class TimelineFragment extends SFragment implements public class TimelineFragment extends SFragment implements
SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener { SwipeRefreshLayout.OnRefreshListener, StatusActionListener, FooterActionListener {
private static final String TAG = "Timeline"; // logging tag private static final String TAG = "Timeline"; // logging tag
private static final int EXPECTED_STATUSES_FETCHED = 20;
public enum Kind { public enum Kind {
HOME, HOME,
@ -229,22 +230,26 @@ public class TimelineFragment extends SFragment implements
} else { } else {
adapter.update(statuses); 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); swipeRefreshLayout.setRefreshing(false);
} }
public void onFetchTimelineFailure(Exception exception) { public void onFetchTimelineFailure(Exception exception) {
showFetchTimelineRetry(true); setFetchTimelineState(FooterViewHolder.State.RETRY);
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
Log.e(TAG, exception.getMessage()); Log.e(TAG, exception.getMessage());
} }
private void showFetchTimelineRetry(boolean show) { private void setFetchTimelineState(FooterViewHolder.State state) {
RecyclerView.ViewHolder viewHolder = RecyclerView.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1);
if (viewHolder != null) { if (viewHolder != null) {
FooterViewHolder holder = (FooterViewHolder) viewHolder; FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.showRetry(show); holder.setState(state);
} }
} }

View file

@ -36,6 +36,12 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/footer_end_of_timeline_text"
android:visibility="gone" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View file

@ -74,6 +74,9 @@
<string name="footer_retry_statuses">Could not load the rest of the statuses.</string> <string name="footer_retry_statuses">Could not load the rest of the statuses.</string>
<string name="footer_retry_notifications">Could not load the rest of the statuses.</string> <string name="footer_retry_notifications">Could not load the rest of the statuses.</string>
<string name="footer_retry_accounts">Could not load the rest of the accounts.</string> <string name="footer_retry_accounts">Could not load the rest of the accounts.</string>
<string name="footer_end_of_statuses">end of the statuses</string>
<string name="footer_end_of_notifications">end of the notifications</string>
<string name="footer_end_of_accounts">end of the accounts</string>
<string name="notification_reblog_format">%s boosted your status</string> <string name="notification_reblog_format">%s boosted your status</string>
<string name="notification_favourite_format">%s favourited your status</string> <string name="notification_favourite_format">%s favourited your status</string>