From f2a400ab3893f9168fcc7c412ef4e109457ad9cd Mon Sep 17 00:00:00 2001 From: Vavassor Date: Sun, 19 Mar 2017 22:38:39 -0400 Subject: [PATCH] Fixes rare crashes when viewing accounts and favouriting. Also, fixes content warning characters not counting toward the character limit. Closes #32 --- .../keylesspalace/tusky/AccountActivity.java | 7 +++-- .../keylesspalace/tusky/AccountFragment.java | 1 - .../com/keylesspalace/tusky/BaseActivity.java | 13 ++++---- .../keylesspalace/tusky/ComposeActivity.java | 30 +++++++++++++------ .../com/keylesspalace/tusky/HtmlUtils.java | 6 ++-- .../tusky/MyFirebaseMessagingService.java | 4 +-- .../keylesspalace/tusky/StatusViewHolder.java | 25 ++++++++++++---- .../keylesspalace/tusky/ThreadAdapter.java | 1 + .../keylesspalace/tusky/TimelineAdapter.java | 3 +- .../keylesspalace/tusky/entity/Account.java | 29 ++++++++++++++++-- 10 files changed, 88 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java index 22b417d1..e7379361 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.java @@ -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; diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountFragment.java b/app/src/main/java/com/keylesspalace/tusky/AccountFragment.java index 758a0c5b..4ed2e72d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/AccountFragment.java @@ -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; diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java index eb81596d..8df566c6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java @@ -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() { @Override public void onResponse(Call call, retrofit2.Response response) { - + Log.d(TAG, "Enable push notifications response: " + response.message()); } @Override public void onFailure(Call 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() { @Override public void onResponse(Call call, retrofit2.Response response) { - + Log.d(TAG, "Disable push notifications response: " + response.message()); } @Override public void onFailure(Call call, Throwable t) { - + Log.d(TAG, "Disable push notifications failed: " + t.getMessage()); } }); } diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java index 82d77e93..487878b3 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java @@ -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)); } diff --git a/app/src/main/java/com/keylesspalace/tusky/HtmlUtils.java b/app/src/main/java/com/keylesspalace/tusky/HtmlUtils.java index 81b72835..4999c957 100644 --- a/app/src/main/java/com/keylesspalace/tusky/HtmlUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/HtmlUtils.java @@ -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); diff --git a/app/src/main/java/com/keylesspalace/tusky/MyFirebaseMessagingService.java b/app/src/main/java/com/keylesspalace/tusky/MyFirebaseMessagingService.java index aa934251..b54fc056 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MyFirebaseMessagingService.java +++ b/app/src/main/java/com/keylesspalace/tusky/MyFirebaseMessagingService.java @@ -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; } diff --git a/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java index 619b187c..38c03df1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/StatusViewHolder.java @@ -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); diff --git a/app/src/main/java/com/keylesspalace/tusky/ThreadAdapter.java b/app/src/main/java/com/keylesspalace/tusky/ThreadAdapter.java index 4cc2dc48..ea2c6faa 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ThreadAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/ThreadAdapter.java @@ -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; diff --git a/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java b/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java index 41dfeab7..9e54e349 100644 --- a/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/TimelineAdapter.java @@ -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); } diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Account.java b/app/src/main/java/com/keylesspalace/tusky/entity/Account.java index 76574b94..9e1166e0 100644 --- a/app/src/main/java/com/keylesspalace/tusky/entity/Account.java +++ b/app/src/main/java/com/keylesspalace/tusky/entity/Account.java @@ -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 CREATOR = new Creator() {