Fixes two bugs:

-One where deletion causes statuses to lose track of where they are in timelines, so subsequent deletion and other actions are performed on the wrong status.
-It's was possible to infinitely open copies of the same thread, account page, and tag page by just continuously clicking on the status, avatar, or hash tag respectively.
This commit is contained in:
Vavassor 2017-03-02 19:25:35 -05:00
parent c18186f135
commit 9e49da64bf
9 changed files with 48 additions and 59 deletions

View File

@ -18,6 +18,7 @@ package com.keylesspalace.tusky;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -27,7 +28,6 @@ import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.util.TypedValue;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@ -105,10 +105,11 @@ public class AccountActivity extends BaseActivity {
}; };
adapter.setPageTitles(pageTitles); adapter.setPageTitles(pageTitles);
ViewPager viewPager = (ViewPager) findViewById(R.id.pager); ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
int pageMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, int pageMargin = getResources().getDimensionPixelSize(R.dimen.tab_page_margin);
getResources().getDisplayMetrics());
viewPager.setPageMargin(pageMargin); viewPager.setPageMargin(pageMargin);
viewPager.setPageMarginDrawable(R.drawable.tab_page_margin_dark); Drawable pageMarginDrawable = ThemeUtils.getDrawable(this, R.attr.tab_page_margin_drawable,
R.drawable.tab_page_margin_dark);
viewPager.setPageMarginDrawable(pageMarginDrawable);
viewPager.setAdapter(adapter); viewPager.setAdapter(adapter);
tabLayout = (TabLayout) findViewById(R.id.tab_layout); tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager); tabLayout.setupWithViewPager(viewPager);

View File

@ -75,7 +75,7 @@ public class MainActivity extends BaseActivity {
viewPager.setPageMargin(pageMargin); viewPager.setPageMargin(pageMargin);
Drawable pageMarginDrawable = ThemeUtils.getDrawable(this, R.attr.tab_page_margin_drawable, Drawable pageMarginDrawable = ThemeUtils.getDrawable(this, R.attr.tab_page_margin_drawable,
R.drawable.tab_page_margin_dark); R.drawable.tab_page_margin_dark);
viewPager.setPageMarginDrawable(pageMarginDrawable); viewPager.setPageMarginDrawable(pageMarginDrawable);
viewPager.setAdapter(adapter); viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager); tabLayout.setupWithViewPager(viewPager);

View File

@ -103,8 +103,7 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
FollowViewHolder holder = (FollowViewHolder) viewHolder; FollowViewHolder holder = (FollowViewHolder) viewHolder;
holder.setMessage(notification.getDisplayName(), notification.getUsername(), holder.setMessage(notification.getDisplayName(), notification.getUsername(),
notification.getAvatar()); notification.getAvatar());
holder.setupButtons(followListener, notification.getAccountId(), holder.setupButtons(followListener, notification.getAccountId());
notification.getUsername());
break; break;
} }
} }
@ -186,7 +185,7 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
} }
interface FollowListener { interface FollowListener {
void onViewAccount(String id, String username); void onViewAccount(String id);
void onFollow(String id); void onFollow(String id);
} }
@ -224,12 +223,11 @@ class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRe
avatar.setImageUrl(avatarUrl, VolleySingleton.getInstance(context).getImageLoader()); avatar.setImageUrl(avatarUrl, VolleySingleton.getInstance(context).getImageLoader());
} }
void setupButtons(final FollowListener listener, final String accountId, void setupButtons(final FollowListener listener, final String accountId) {
final String username) {
avatar.setOnClickListener(new View.OnClickListener() { avatar.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
listener.onViewAccount(accountId, username); listener.onViewAccount(accountId);
} }
}); });
follow.setOnClickListener(new View.OnClickListener() { follow.setOnClickListener(new View.OnClickListener() {

View File

@ -257,15 +257,8 @@ public class NotificationsFragment extends SFragment implements
super.viewTag(tag); super.viewTag(tag);
} }
public void onViewAccount(String id, String username) { public void onViewAccount(String id) {
super.viewAccount(id, username); super.viewAccount(id);
}
public void onViewAccount(int position) {
Status status = adapter.getItem(position).getStatus();
String id = status.getAccountId();
String username = status.getUsername();
super.viewAccount(id, username);
} }
public void onFollow(String id) { public void onFollow(String id) {

View File

@ -267,18 +267,17 @@ public class SFragment extends Fragment {
startActivity(intent); startActivity(intent);
} }
protected void viewAccount(String id, String username) { protected void viewAccount(String id) {
Intent intent = new Intent(getContext(), AccountActivity.class); Intent intent = new Intent(getContext(), AccountActivity.class);
intent.putExtra("id", id); intent.putExtra("id", id);
intent.putExtra("username", username);
startActivity(intent); startActivity(intent);
} }
protected void openReportPage(String accountId, String accoundUsername, String statusId, protected void openReportPage(String accountId, String accountUsername, String statusId,
Spanned statusContent) { Spanned statusContent) {
Intent intent = new Intent(getContext(), ReportActivity.class); Intent intent = new Intent(getContext(), ReportActivity.class);
intent.putExtra("account_id", accountId); intent.putExtra("account_id", accountId);
intent.putExtra("account_username", accoundUsername); intent.putExtra("account_username", accountUsername);
intent.putExtra("status_id", statusId); intent.putExtra("status_id", statusId);
intent.putExtra("status_content", HtmlUtils.toHtml(statusContent)); intent.putExtra("status_content", HtmlUtils.toHtml(statusContent));
startActivity(intent); startActivity(intent);

View File

@ -25,6 +25,5 @@ interface StatusActionListener {
void onViewMedia(String url, Status.MediaAttachment.Type type); void onViewMedia(String url, Status.MediaAttachment.Type type);
void onViewThread(int position); void onViewThread(int position);
void onViewTag(String tag); void onViewTag(String tag);
void onViewAccount(String id, String username); void onViewAccount(String id);
void onViewAccount(int position);
} }

View File

@ -98,7 +98,7 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
displayName.setText(name); displayName.setText(name);
} }
void setUsername(String name) { private void setUsername(String name) {
Context context = username.getContext(); Context context = username.getContext();
String format = context.getString(R.string.status_username_format); String format = context.getString(R.string.status_username_format);
String usernameText = String.format(format, name); String usernameText = String.format(format, name);
@ -139,7 +139,7 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
ClickableSpan newSpan = new ClickableSpan() { ClickableSpan newSpan = new ClickableSpan() {
@Override @Override
public void onClick(View widget) { public void onClick(View widget) {
listener.onViewAccount(accountId, accountUsername); listener.onViewAccount(accountId);
} }
}; };
builder.removeSpan(span); builder.removeSpan(span);
@ -294,35 +294,35 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
content.setVisibility(View.VISIBLE); content.setVisibility(View.VISIBLE);
} }
private void setupButtons(final StatusActionListener listener, final int position) { private void setupButtons(final StatusActionListener listener, final String accountId) {
avatar.setOnClickListener(new View.OnClickListener() { avatar.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
listener.onViewAccount(position); listener.onViewAccount(accountId);
} }
}); });
replyButton.setOnClickListener(new View.OnClickListener() { replyButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
listener.onReply(position); listener.onReply(getAdapterPosition());
} }
}); });
reblogButton.setOnClickListener(new View.OnClickListener() { reblogButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
listener.onReblog(!reblogged, position); listener.onReblog(!reblogged, getAdapterPosition());
} }
}); });
favouriteButton.setOnClickListener(new View.OnClickListener() { favouriteButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
listener.onFavourite(!favourited, position); listener.onFavourite(!favourited, getAdapterPosition());
} }
}); });
moreButton.setOnClickListener(new View.OnClickListener() { moreButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
listener.onMore(v, position); listener.onMore(v, getAdapterPosition());
} }
}); });
/* Even though the content TextView is a child of the container, it won't respond to clicks /* Even though the content TextView is a child of the container, it won't respond to clicks
@ -332,7 +332,7 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
View.OnClickListener viewThreadListener = new View.OnClickListener() { View.OnClickListener viewThreadListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
listener.onViewThread(position); listener.onViewThread(getAdapterPosition());
} }
}; };
content.setOnClickListener(viewThreadListener); content.setOnClickListener(viewThreadListener);
@ -361,7 +361,7 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
if (!sensitive || attachments.length == 0) { if (!sensitive || attachments.length == 0) {
hideSensitiveMediaWarning(); hideSensitiveMediaWarning();
} }
setupButtons(listener, position); setupButtons(listener, status.getAccountId());
setRebloggingEnabled(status.getVisibility() != Status.Visibility.PRIVATE); setRebloggingEnabled(status.getVisibility() != Status.Visibility.PRIVATE);
if (status.getSpoilerText().isEmpty()) { if (status.getSpoilerText().isEmpty()) {
hideSpoilerText(); hideSpoilerText();

View File

@ -312,20 +312,19 @@ public class TimelineFragment extends SFragment implements
} }
public void onViewTag(String tag) { public void onViewTag(String tag) {
if (kind == Kind.TAG && hashtagOrId.equals(tag)) {
// If already viewing a tag page, then ignore any request to view that tag again.
return;
}
super.viewTag(tag); super.viewTag(tag);
} }
public void onViewAccount(String id, String username) { public void onViewAccount(String id) {
super.viewAccount(id, username); if (kind == Kind.USER && hashtagOrId.equals(id)) {
} /* If already viewing an account page, then any requests to view that account page
* should be ignored. */
public void onViewAccount(int position) { return;
Status status = adapter.getItem(position);
Assert.expect(status != null);
if (status != null) {
String id = status.getAccountId();
String username = status.getUsername();
super.viewAccount(id, username);
} }
super.viewAccount(id);
} }
} }

View File

@ -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.Snackbar; import android.support.design.widget.Snackbar;
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;
@ -40,6 +39,7 @@ import java.util.List;
public class ViewThreadFragment extends SFragment implements StatusActionListener { public class ViewThreadFragment extends SFragment implements StatusActionListener {
private RecyclerView recyclerView; private RecyclerView recyclerView;
private ThreadAdapter adapter; private ThreadAdapter adapter;
private String thisThreadsStatusId;
public static ViewThreadFragment newInstance(String id) { public static ViewThreadFragment newInstance(String id) {
Bundle arguments = new Bundle(); Bundle arguments = new Bundle();
@ -62,7 +62,8 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
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);
adapter = new ThreadAdapter(this); adapter = new ThreadAdapter(this);
@ -71,6 +72,7 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
String id = getArguments().getString("id"); String id = getArguments().getString("id");
sendStatusRequest(id); sendStatusRequest(id);
sendThreadRequest(id); sendThreadRequest(id);
thisThreadsStatusId = id;
return rootView; return rootView;
} }
@ -159,21 +161,19 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
} }
public void onViewThread(int position) { public void onViewThread(int position) {
super.viewThread(adapter.getItem(position)); Status status = adapter.getItem(position);
if (thisThreadsStatusId.equals(status.getId())) {
// If already viewing this thread, don't reopen it.
return;
}
super.viewThread(status);
} }
public void onViewTag(String tag) { public void onViewTag(String tag) {
super.viewTag(tag); super.viewTag(tag);
} }
public void onViewAccount(String id, String username) { public void onViewAccount(String id) {
super.viewAccount(id, username); super.viewAccount(id);
}
public void onViewAccount(int position) {
Status status = adapter.getItem(position);
String id = status.getAccountId();
String username = status.getUsername();
super.viewAccount(id, username);
} }
} }