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.
This commit is contained in:
parent
e59c0534c7
commit
9b6f5e63d3
12 changed files with 228 additions and 66 deletions
|
@ -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,17 +212,26 @@ 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)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
adapter.update(accounts);
|
adapter.update(accounts);
|
||||||
}
|
}
|
||||||
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) {
|
||||||
|
@ -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,17 +164,26 @@ 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)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
adapter.update(notifications);
|
adapter.update(notifications);
|
||||||
}
|
}
|
||||||
if (notifications.size() >= EXPECTED_NOTIFICATIONS_FETCHED) {
|
|
||||||
setFetchTimelineState(FooterViewHolder.State.LOADING);
|
|
||||||
} else {
|
|
||||||
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE);
|
|
||||||
}
|
|
||||||
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,17 +228,26 @@ 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)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
adapter.update(statuses);
|
adapter.update(statuses);
|
||||||
}
|
}
|
||||||
if (statuses.size() >= EXPECTED_STATUSES_FETCHED) {
|
|
||||||
setFetchTimelineState(FooterViewHolder.State.LOADING);
|
|
||||||
} else {
|
|
||||||
setFetchTimelineState(FooterViewHolder.State.END_OF_TIMELINE);
|
|
||||||
}
|
|
||||||
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) {
|
||||||
|
|
35
app/src/main/res/layout/activity_blocks.xml
Normal file
35
app/src/main/res/layout/activity_blocks.xml
Normal file
|
@ -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…
Reference in a new issue