Viewing your block list is now possible on the main menu.

Also, changed how end-of-timeline behaviour is handled on all timelines. It should detect it more reliably now.
main
Vavassor 8 years ago
parent e59c0534c7
commit 9b6f5e63d3
  1. 1
      app/src/main/AndroidManifest.xml
  2. 7
      app/src/main/java/com/keylesspalace/tusky/AccountAdapter.java
  3. 95
      app/src/main/java/com/keylesspalace/tusky/AccountFragment.java
  4. 43
      app/src/main/java/com/keylesspalace/tusky/BlocksActivity.java
  5. 11
      app/src/main/java/com/keylesspalace/tusky/MainActivity.java
  6. 7
      app/src/main/java/com/keylesspalace/tusky/NotificationsAdapter.java
  7. 33
      app/src/main/java/com/keylesspalace/tusky/NotificationsFragment.java
  8. 7
      app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java
  9. 30
      app/src/main/java/com/keylesspalace/tusky/TimelineFragment.java
  10. 35
      app/src/main/res/layout/activity_blocks.xml
  11. 17
      app/src/main/res/menu/main_toolbar.xml
  12. 8
      app/src/main/res/values/strings.xml

@ -38,6 +38,7 @@
<activity android:name=".AccountActivity" /> <activity android:name=".AccountActivity" />
<activity android:name=".PreferencesActivity" /> <activity android:name=".PreferencesActivity" />
<activity android:name=".FavouritesActivity" /> <activity android:name=".FavouritesActivity" />
<activity android:name=".BlocksActivity" />
<service <service
android:name=".PullNotificationService" android:name=".PullNotificationService"
android:description="@string/notification_service_description" android:description="@string/notification_service_description"

@ -35,6 +35,7 @@ public class AccountAdapter extends RecyclerView.Adapter {
private List<Account> accounts; private List<Account> accounts;
private AccountActionListener accountActionListener; private AccountActionListener accountActionListener;
private FooterActionListener footerActionListener; private FooterActionListener footerActionListener;
private FooterViewHolder.State footerState;
public AccountAdapter(AccountActionListener accountActionListener, public AccountAdapter(AccountActionListener accountActionListener,
FooterActionListener footerActionListener) { FooterActionListener footerActionListener) {
@ -42,6 +43,7 @@ public class AccountAdapter extends RecyclerView.Adapter {
accounts = new ArrayList<>(); accounts = new ArrayList<>();
this.accountActionListener = accountActionListener; this.accountActionListener = accountActionListener;
this.footerActionListener = footerActionListener; this.footerActionListener = footerActionListener;
footerState = FooterViewHolder.State.LOADING;
} }
@Override @Override
@ -69,6 +71,7 @@ public class AccountAdapter extends RecyclerView.Adapter {
holder.setupActionListener(accountActionListener); holder.setupActionListener(accountActionListener);
} else { } else {
FooterViewHolder holder = (FooterViewHolder) viewHolder; FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.setState(footerState);
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); holder.setEndOfTimelineMessage(R.string.footer_end_of_accounts);
@ -116,6 +119,10 @@ public class AccountAdapter extends RecyclerView.Adapter {
return null; return null;
} }
public void setFooterState(FooterViewHolder.State state) {
this.footerState = state;
}
private static class AccountViewHolder extends RecyclerView.ViewHolder { private static class AccountViewHolder extends RecyclerView.ViewHolder {
private View container; private View container;
private TextView username; private TextView username;

@ -23,7 +23,6 @@ import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout; import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
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;
@ -45,12 +44,12 @@ 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"; // logging tag
private static int EXPECTED_ACCOUNTS_FETCHED = 20;
public enum Type { public enum Type {
FOLLOWS, FOLLOWS,
FOLLOWERS, FOLLOWERS,
BLOCKS,
} }
private Type type; private Type type;
@ -63,6 +62,14 @@ public class AccountFragment extends Fragment implements AccountActionListener,
private AccountAdapter adapter; private AccountAdapter adapter;
private TabLayout.OnTabSelectedListener onTabSelectedListener; private TabLayout.OnTabSelectedListener onTabSelectedListener;
public static AccountFragment newInstance(Type type) {
Bundle arguments = new Bundle();
AccountFragment fragment = new AccountFragment();
arguments.putString("type", type.name());
fragment.setArguments(arguments);
return fragment;
}
public static AccountFragment newInstance(Type type, String accountId) { public static AccountFragment newInstance(Type type, String accountId) {
Bundle arguments = new Bundle(); Bundle arguments = new Bundle();
AccountFragment fragment = new AccountFragment(); AccountFragment fragment = new AccountFragment();
@ -99,7 +106,8 @@ public class AccountFragment extends Fragment implements AccountActionListener,
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
DividerItemDecoration divider = new DividerItemDecoration( DividerItemDecoration divider = new DividerItemDecoration(
context, layoutManager.getOrientation()); context, layoutManager.getOrientation());
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.status_divider_dark); Drawable drawable = ThemeUtils.getDrawable(context, R.attr.status_divider_drawable,
R.drawable.status_divider_dark);
divider.setDrawable(drawable); divider.setDrawable(drawable);
recyclerView.addItemDecoration(divider); recyclerView.addItemDecoration(divider);
scrollListener = new EndlessOnScrollListener(layoutManager) { scrollListener = new EndlessOnScrollListener(layoutManager) {
@ -118,45 +126,54 @@ public class AccountFragment extends Fragment implements AccountActionListener,
adapter = new AccountAdapter(this, this); adapter = new AccountAdapter(this, this);
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
TabLayout layout = (TabLayout) getActivity().findViewById(R.id.tab_layout); if (jumpToTopAllowed()) {
onTabSelectedListener = new TabLayout.OnTabSelectedListener() { TabLayout layout = (TabLayout) getActivity().findViewById(R.id.tab_layout);
@Override onTabSelectedListener = new TabLayout.OnTabSelectedListener() {
public void onTabSelected(TabLayout.Tab tab) {} @Override
public void onTabSelected(TabLayout.Tab tab) {
}
@Override @Override
public void onTabUnselected(TabLayout.Tab tab) {} public void onTabUnselected(TabLayout.Tab tab) {
}
@Override @Override
public void onTabReselected(TabLayout.Tab tab) { public void onTabReselected(TabLayout.Tab tab) {
jumpToTop(); jumpToTop();
} }
}; };
layout.addOnTabSelectedListener(onTabSelectedListener); layout.addOnTabSelectedListener(onTabSelectedListener);
}
return rootView; return rootView;
} }
@Override @Override
public void onDestroyView() { public void onDestroyView() {
TabLayout tabLayout = (TabLayout) getActivity().findViewById(R.id.tab_layout); if (jumpToTopAllowed()) {
tabLayout.removeOnTabSelectedListener(onTabSelectedListener); TabLayout tabLayout = (TabLayout) getActivity().findViewById(R.id.tab_layout);
tabLayout.removeOnTabSelectedListener(onTabSelectedListener);
}
super.onDestroyView(); super.onDestroyView();
} }
private void fetchAccounts(final String fromId) { private void fetchAccounts(final String fromId) {
int endpointId; String endpoint;
switch (type) { switch (type) {
default: default:
case FOLLOWS: { case FOLLOWS: {
endpointId = R.string.endpoint_following; endpoint = String.format(getString(R.string.endpoint_following), accountId);
break; break;
} }
case FOLLOWERS: { case FOLLOWERS: {
endpointId = R.string.endpoint_followers; endpoint = String.format(getString(R.string.endpoint_followers), accountId);
break;
}
case BLOCKS: {
endpoint = getString(R.string.endpoint_blocks);
break; break;
} }
} }
String endpoint = String.format(getString(endpointId), accountId);
String url = "https://" + domain + endpoint; String url = "https://" + domain + endpoint;
if (fromId != null) { if (fromId != null) {
url += "?max_id=" + fromId; url += "?max_id=" + fromId;
@ -172,7 +189,7 @@ public class AccountFragment extends Fragment implements AccountActionListener,
onFetchAccountsFailure(e); onFetchAccountsFailure(e);
return; return;
} }
onFetchAccountsSuccess(accounts, fromId != null); onFetchAccountsSuccess(accounts, fromId);
} }
}, },
new Response.ErrorListener() { new Response.ErrorListener() {
@ -195,16 +212,25 @@ public class AccountFragment extends Fragment implements AccountActionListener,
fetchAccounts(null); fetchAccounts(null);
} }
private void onFetchAccountsSuccess(List<Account> accounts, boolean added) { private static boolean findAccount(List<Account> accounts, String id) {
if (added) { for (Account account : accounts) {
adapter.addItems(accounts); if (account.id.equals(id)) {
} else { return true;
adapter.update(accounts); }
} }
if (accounts.size() >= EXPECTED_ACCOUNTS_FETCHED) { return false;
setFetchTimelineState(FooterViewHolder.State.LOADING); }
private void onFetchAccountsSuccess(List<Account> accounts, String fromId) {
if (fromId != null) {
if (accounts.size() > 0 && !findAccount(accounts, fromId)) {
setFetchTimelineState(FooterViewHolder.State.LOADING);
adapter.addItems(accounts);
} else {
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE);
}
} else { } else {
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE); adapter.update(accounts);
} }
} }
@ -214,6 +240,9 @@ public class AccountFragment extends Fragment implements AccountActionListener,
} }
private void setFetchTimelineState(FooterViewHolder.State state) { private void setFetchTimelineState(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.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1);
if (viewHolder != null) { if (viewHolder != null) {
@ -237,6 +266,10 @@ public class AccountFragment extends Fragment implements AccountActionListener,
startActivity(intent); startActivity(intent);
} }
private boolean jumpToTopAllowed() {
return type != Type.BLOCKS;
}
private void jumpToTop() { private void jumpToTop() {
layoutManager.scrollToPositionWithOffset(0, 0); layoutManager.scrollToPositionWithOffset(0, 0);
scrollListener.reset(); scrollListener.reset();

@ -0,0 +1,43 @@
/* Copyright 2017 Andrew Dawson
*
* This file is part of Tusky.
*
* Tusky is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky. If not, see
* <http://www.gnu.org/licenses/>. */
package com.keylesspalace.tusky;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
public class BlocksActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_blocks);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar bar = getSupportActionBar();
if (bar != null) {
bar.setTitle(getString(R.string.title_blocks));
}
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment fragment = AccountFragment.newInstance(AccountFragment.Type.BLOCKS);
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
}

@ -175,22 +175,27 @@ public class MainActivity extends BaseActivity {
startActivity(intent); startActivity(intent);
return true; return true;
} }
case R.id.action_profile: { case R.id.action_view_profile: {
Intent intent = new Intent(this, AccountActivity.class); Intent intent = new Intent(this, AccountActivity.class);
intent.putExtra("id", loggedInAccountId); intent.putExtra("id", loggedInAccountId);
startActivity(intent); startActivity(intent);
return true; return true;
} }
case R.id.action_preferences: { case R.id.action_view_preferences: {
Intent intent = new Intent(this, PreferencesActivity.class); Intent intent = new Intent(this, PreferencesActivity.class);
startActivity(intent); startActivity(intent);
return true; return true;
} }
case R.id.action_favourites: { case R.id.action_view_favourites: {
Intent intent = new Intent(this, FavouritesActivity.class); Intent intent = new Intent(this, FavouritesActivity.class);
startActivity(intent); startActivity(intent);
return true; return true;
} }
case R.id.action_view_blocks: {
Intent intent = new Intent(this, BlocksActivity.class);
startActivity(intent);
return true;
}
case R.id.action_logout: { case R.id.action_logout: {
if (notificationServiceEnabled) { if (notificationServiceEnabled) {
alarmManager.cancel(serviceAlarmIntent); alarmManager.cancel(serviceAlarmIntent);

@ -37,6 +37,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
private List<Notification> notifications; private List<Notification> notifications;
private StatusActionListener statusListener; private StatusActionListener statusListener;
private FooterActionListener footerListener; private FooterActionListener footerListener;
private FooterViewHolder.State footerState;
public NotificationsAdapter(StatusActionListener statusListener, public NotificationsAdapter(StatusActionListener statusListener,
FooterActionListener footerListener) { FooterActionListener footerListener) {
@ -44,6 +45,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
notifications = new ArrayList<>(); notifications = new ArrayList<>();
this.statusListener = statusListener; this.statusListener = statusListener;
this.footerListener = footerListener; this.footerListener = footerListener;
footerState = FooterViewHolder.State.LOADING;
} }
@Override @Override
@ -100,6 +102,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
} }
} else { } else {
FooterViewHolder holder = (FooterViewHolder) viewHolder; FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.setState(footerState);
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); holder.setEndOfTimelineMessage(R.string.footer_end_of_notifications);
@ -170,6 +173,10 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
notifyItemChanged(position); notifyItemChanged(position);
} }
public void setFooterState(FooterViewHolder.State state) {
footerState = state;
}
public static class FollowViewHolder extends RecyclerView.ViewHolder { public static class FollowViewHolder extends RecyclerView.ViewHolder {
private TextView message; private TextView message;

@ -20,7 +20,6 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout; import android.support.design.widget.TabLayout;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout; 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;
@ -44,7 +43,6 @@ 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;
@ -77,7 +75,8 @@ public class NotificationsFragment extends SFragment implements
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
DividerItemDecoration divider = new DividerItemDecoration( DividerItemDecoration divider = new DividerItemDecoration(
context, layoutManager.getOrientation()); context, layoutManager.getOrientation());
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.status_divider_dark); Drawable drawable = ThemeUtils.getDrawable(context, R.attr.status_divider_drawable,
R.drawable.status_divider_dark);
divider.setDrawable(drawable); divider.setDrawable(drawable);
recyclerView.addItemDecoration(divider); recyclerView.addItemDecoration(divider);
scrollListener = new EndlessOnScrollListener(layoutManager) { scrollListener = new EndlessOnScrollListener(layoutManager) {
@ -140,7 +139,7 @@ public class NotificationsFragment extends SFragment implements
public void onResponse(JSONArray response) { public void onResponse(JSONArray response) {
try { try {
List<Notification> notifications = Notification.parse(response); List<Notification> notifications = Notification.parse(response);
onFetchNotificationsSuccess(notifications, fromId != null); onFetchNotificationsSuccess(notifications, fromId);
} catch (JSONException e) { } catch (JSONException e) {
onFetchNotificationsFailure(e); onFetchNotificationsFailure(e);
} }
@ -165,16 +164,25 @@ public class NotificationsFragment extends SFragment implements
sendFetchNotificationsRequest(null); sendFetchNotificationsRequest(null);
} }
private void onFetchNotificationsSuccess(List<Notification> notifications, boolean added) { private static boolean findNotification(List<Notification> notifications, String id) {
if (added) { for (Notification notification : notifications) {
adapter.addItems(notifications); if (notification.getId().equals(id)) {
} else { return true;
adapter.update(notifications); }
} }
if (notifications.size() >= EXPECTED_NOTIFICATIONS_FETCHED) { return false;
setFetchTimelineState(FooterViewHolder.State.LOADING); }
private void onFetchNotificationsSuccess(List<Notification> notifications, String fromId) {
if (fromId != null) {
if (notifications.size() > 0 && !findNotification(notifications, fromId)) {
setFetchTimelineState(FooterViewHolder.State.LOADING);
adapter.addItems(notifications);
} else {
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE);
}
} else { } else {
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE); adapter.update(notifications);
} }
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
@ -186,6 +194,7 @@ public class NotificationsFragment extends SFragment implements
} }
private void setFetchTimelineState(FooterViewHolder.State state) { private void setFetchTimelineState(FooterViewHolder.State state) {
adapter.setFooterState(state);
RecyclerView.ViewHolder viewHolder = RecyclerView.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1);
if (viewHolder != null) { if (viewHolder != null) {

@ -31,6 +31,7 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
private List<Status> statuses; private List<Status> statuses;
private StatusActionListener statusListener; private StatusActionListener statusListener;
private FooterActionListener footerListener; private FooterActionListener footerListener;
private FooterViewHolder.State footerState;
public TimelineAdapter(StatusActionListener statusListener, public TimelineAdapter(StatusActionListener statusListener,
FooterActionListener footerListener) { FooterActionListener footerListener) {
@ -38,6 +39,7 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
statuses = new ArrayList<>(); statuses = new ArrayList<>();
this.statusListener = statusListener; this.statusListener = statusListener;
this.footerListener = footerListener; this.footerListener = footerListener;
footerState = FooterViewHolder.State.LOADING;
} }
@Override @Override
@ -65,6 +67,7 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
holder.setupWithStatus(status, statusListener, position); holder.setupWithStatus(status, statusListener, position);
} else { } else {
FooterViewHolder holder = (FooterViewHolder) viewHolder; FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.setState(footerState);
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); holder.setEndOfTimelineMessage(R.string.footer_end_of_statuses);
@ -121,4 +124,8 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
} }
return null; return null;
} }
public void setFooterState(FooterViewHolder.State state) {
footerState = state;
}
} }

@ -19,7 +19,6 @@ import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.support.design.widget.TabLayout; import android.support.design.widget.TabLayout;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout; 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;
@ -43,7 +42,6 @@ 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,
@ -207,7 +205,7 @@ public class TimelineFragment extends SFragment implements
onFetchTimelineFailure(e); onFetchTimelineFailure(e);
} }
if (statuses != null) { if (statuses != null) {
onFetchTimelineSuccess(statuses, fromId != null); onFetchTimelineSuccess(statuses, fromId);
} }
} }
}, new Response.ErrorListener() { }, new Response.ErrorListener() {
@ -230,16 +228,25 @@ public class TimelineFragment extends SFragment implements
sendFetchTimelineRequest(null); sendFetchTimelineRequest(null);
} }
public void onFetchTimelineSuccess(List<Status> statuses, boolean added) { private static boolean findStatus(List<Status> statuses, String id) {
if (added) { for (Status status : statuses) {
adapter.addItems(statuses); if (status.getId().equals(id)) {
} else { return true;
adapter.update(statuses); }
} }
if (statuses.size() >= EXPECTED_STATUSES_FETCHED) { return false;
setFetchTimelineState(FooterViewHolder.State.LOADING); }
public void onFetchTimelineSuccess(List<Status> statuses, String fromId) {
if (fromId != null) {
if (statuses.size() > 0 && !findStatus(statuses, fromId)) {
setFetchTimelineState(FooterViewHolder.State.LOADING);
adapter.addItems(statuses);
} else {
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE);
}
} else { } else {
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE); adapter.update(statuses);
} }
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
@ -251,6 +258,7 @@ public class TimelineFragment extends SFragment implements
} }
private void setFetchTimelineState(FooterViewHolder.State state) { private void setFetchTimelineState(FooterViewHolder.State state) {
adapter.setFooterState(state);
RecyclerView.ViewHolder viewHolder = RecyclerView.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1); recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1);
if (viewHolder != null) { if (viewHolder != null) {

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_view_thread"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.keylesspalace.tusky.BlocksActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
android:background="?attr/toolbar_background_color" />
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<FrameLayout
android:id="@+id/overlay_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</RelativeLayout>

@ -10,18 +10,23 @@
app:showAsAction="always" /> app:showAsAction="always" />
<item <item
android:id="@+id/action_profile" android:id="@+id/action_view_profile"
android:title="@string/action_profile" android:title="@string/action_view_profile"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_preferences" android:id="@+id/action_view_preferences"
android:title="@string/action_preferences" android:title="@string/action_view_preferences"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_favourites" android:id="@+id/action_view_favourites"
android:title="@string/action_favourites" android:title="@string/action_view_favourites"
app:showAsAction="never" />
<item
android:id="@+id/action_view_blocks"
android:title="@string/action_view_blocks"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item

@ -65,6 +65,7 @@
<string name="title_follows">Follows</string> <string name="title_follows">Follows</string>
<string name="title_followers">Followers</string> <string name="title_followers">Followers</string>
<string name="title_favourites">Favourites</string> <string name="title_favourites">Favourites</string>
<string name="title_blocks">Blocked Users</string>
<string name="status_username_format">\@%s</string> <string name="status_username_format">\@%s</string>
<string name="status_boosted_format">%s boosted</string> <string name="status_boosted_format">%s boosted</string>
@ -100,11 +101,12 @@
<string name="action_cancel">Cancel</string> <string name="action_cancel">Cancel</string>
<string name="action_close">Close</string> <string name="action_close">Close</string>
<string name="action_back">Back</string> <string name="action_back">Back</string>
<string name="action_profile">Profile</string> <string name="action_view_profile">Profile</string>
<string name="action_view_preferences">Preferences</string>
<string name="action_view_favourites">Favourites</string>
<string name="action_view_blocks">Blocked Users</string>
<string name="action_open_in_web">Open In Web</string> <string name="action_open_in_web">Open In Web</string>
<string name="action_preferences">Preferences</string>
<string name="action_set_time">Set</string> <string name="action_set_time">Set</string>
<string name="action_favourites">Favourites</string>
<string name="confirmation_send">Toot!</string> <string name="confirmation_send">Toot!</string>

Loading…
Cancel
Save