Fixes rare crashes when viewing accounts and favouriting. Also, fixes content warning characters not counting toward the character limit. Closes #32

This commit is contained in:
Vavassor 2017-03-19 22:38:39 -04:00
parent 263d586a51
commit f2a400ab38
10 changed files with 88 additions and 31 deletions

View File

@ -61,7 +61,6 @@ public class AccountActivity extends BaseActivity {
private boolean blocking = false;
private boolean muting = false;
private boolean isSelf;
private String openInWebUrl;
private TabLayout tabLayout;
private Account loadedAccount;
@ -214,7 +213,6 @@ public class AccountActivity extends BaseActivity {
.placeholder(R.drawable.account_header_missing)
.into(header);
openInWebUrl = account.url;
java.text.NumberFormat nf = java.text.NumberFormat.getInstance();
// Add counts to the tabs in the TabLayout.
@ -489,7 +487,10 @@ public class AccountActivity extends BaseActivity {
return true;
}
case R.id.action_open_in_web: {
Uri uri = Uri.parse(openInWebUrl);
if (loadedAccount == null) {
return false;
}
Uri uri = Uri.parse(loadedAccount.url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
return true;

View File

@ -21,7 +21,6 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

View File

@ -22,6 +22,7 @@ import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.Spanned;
@ -50,6 +51,8 @@ import retrofit2.converter.gson.GsonConverterFactory;
* the most expedient way to accomplish this was to put it in a base class and just have every
* activity extend from it. */
public class BaseActivity extends AppCompatActivity {
private static final String TAG = "BaseActivity"; // logging tag
protected MastodonAPI mastodonAPI;
protected TuskyAPI tuskyAPI;
protected Dispatcher mastodonApiDispatcher;
@ -101,7 +104,7 @@ public class BaseActivity extends AppCompatActivity {
}
protected boolean arePushNotificationsEnabled() {
SharedPreferences preferences = getSharedPreferences(getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
return preferences.getBoolean("notificationsEnabled", true);
}
@ -175,12 +178,12 @@ public class BaseActivity extends AppCompatActivity {
tuskyAPI.register(getBaseUrl(), getAccessToken(), FirebaseInstanceId.getInstance().getToken()).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
Log.d(TAG, "Enable push notifications response: " + response.message());
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(TAG, "Enable push notifications failed: " + t.getMessage());
}
});
}
@ -189,12 +192,12 @@ public class BaseActivity extends AppCompatActivity {
tuskyAPI.unregister(getBaseUrl(), getAccessToken()).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
Log.d(TAG, "Disable push notifications response: " + response.message());
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(TAG, "Disable push notifications failed: " + t.getMessage());
}
});
}

View File

@ -422,7 +422,7 @@ public class ComposeActivity extends BaseActivity {
TextWatcher textEditorWatcher = new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int left = STATUS_CHARACTER_LIMIT - s.length();
int left = STATUS_CHARACTER_LIMIT - s.length() - contentWarningEditor.length();
charactersLeft.setText(String.format(Locale.getDefault(), "%d", left));
}
@ -453,6 +453,19 @@ public class ComposeActivity extends BaseActivity {
contentWarningBar = findViewById(R.id.compose_content_warning_bar);
contentWarningEditor = (EditText) findViewById(R.id.field_content_warning);
contentWarningEditor.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int left = STATUS_CHARACTER_LIMIT - s.length() - textEditor.length();
charactersLeft.setText(String.format(Locale.getDefault(), "%d", left));
}
@Override
public void afterTextChanged(Editable s) {}
});
showContentWarning(false);
statusAlreadyInFlight = false;
@ -504,15 +517,14 @@ public class ComposeActivity extends BaseActivity {
if (statusAlreadyInFlight) {
return;
}
Editable editable = textEditor.getText();
if (editable.length() <= STATUS_CHARACTER_LIMIT) {
String contentText = textEditor.getText().toString();
String spoilerText = "";
if (statusHideText) {
spoilerText = contentWarningEditor.getText().toString();
}
if (contentText.length() + spoilerText.length() <= STATUS_CHARACTER_LIMIT) {
statusAlreadyInFlight = true;
String spoilerText = "";
if (statusHideText) {
spoilerText = contentWarningEditor.getText().toString();
}
readyStatus(editable.toString(), statusVisibility, statusMarkSensitive,
spoilerText);
readyStatus(contentText, statusVisibility, statusMarkSensitive, spoilerText);
} else {
textEditor.setError(getString(R.string.error_compose_character_limit));
}

View File

@ -19,7 +19,7 @@ import android.os.Build;
import android.text.Html;
import android.text.Spanned;
class HtmlUtils {
public class HtmlUtils {
private static CharSequence trimTrailingWhitespace(CharSequence s) {
int i = s.length();
do {
@ -29,7 +29,7 @@ class HtmlUtils {
}
@SuppressWarnings("deprecation")
static Spanned fromHtml(String html) {
public static Spanned fromHtml(String html) {
Spanned result;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
result = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
@ -42,7 +42,7 @@ class HtmlUtils {
}
@SuppressWarnings("deprecation")
static String toHtml(Spanned text) {
public static String toHtml(Spanned text) {
String result;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
result = Html.toHtml(text, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE);

View File

@ -55,9 +55,9 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
Log.d(TAG, notificationId);
SharedPreferences preferences = getSharedPreferences(getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(
getApplicationContext());
boolean enabled = preferences.getBoolean("notificationsEnabled", true);
if (!enabled) {
return;
}

View File

@ -306,25 +306,37 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
replyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onReply(getAdapterPosition());
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onReply(position);
}
}
});
reblogButton.setEventListener(new SparkEventListener() {
@Override
public void onEvent(ImageView button, boolean buttonState) {
listener.onReblog(!reblogged, getAdapterPosition());
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onReblog(!reblogged, position);
}
}
});
favouriteButton.setEventListener(new SparkEventListener() {
@Override
public void onEvent(ImageView button, boolean buttonState) {
listener.onFavourite(!favourited, getAdapterPosition());
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onFavourite(!favourited, position);
}
}
});
moreButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onMore(v, getAdapterPosition());
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onMore(v, position);
}
}
});
/* Even though the content TextView is a child of the container, it won't respond to clicks
@ -334,7 +346,10 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
View.OnClickListener viewThreadListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onViewThread(getAdapterPosition());
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onViewThread(position);
}
}
};
content.setOnClickListener(viewThreadListener);

View File

@ -15,6 +15,7 @@
package com.keylesspalace.tusky;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;

View File

@ -116,7 +116,8 @@ class TimelineAdapter extends RecyclerView.Adapter implements AdapterItemRemover
notifyItemRemoved(position);
}
@Nullable Status getItem(int position) {
@Nullable
Status getItem(int position) {
if (position >= 0 && position < statuses.size()) {
return statuses.get(position);
}

View File

@ -20,6 +20,7 @@ import android.text.Spanned;
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion;
import com.google.gson.annotations.SerializedName;
import com.keylesspalace.tusky.HtmlUtils;
public class Account implements SearchSuggestion {
public String id;
@ -88,7 +89,18 @@ public class Account implements SearchSuggestion {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(localUsername);
dest.writeString(username);
dest.writeString(displayName);
dest.writeString(HtmlUtils.toHtml(note));
dest.writeString(url);
dest.writeString(avatar);
dest.writeString(header);
dest.writeBooleanArray(new boolean[] { locked });
dest.writeString(followersCount);
dest.writeString(followingCount);
dest.writeString(statusesCount);
}
public Account() {
@ -96,7 +108,20 @@ public class Account implements SearchSuggestion {
}
protected Account(Parcel in) {
id = in.readString();
localUsername = in.readString();
username = in.readString();
displayName = in.readString();
note = HtmlUtils.fromHtml(in.readString());
url = in.readString();
avatar = in.readString();
header = in.readString();
boolean[] lockedArray = new boolean[1];
in.readBooleanArray(lockedArray);
locked = lockedArray[0];
followersCount = in.readString();
followingCount = in.readString();
statusesCount = in.readString();
}
public static final Creator<Account> CREATOR = new Creator<Account>() {