Fixes crash due to unexpected GIFV attachments.

Also when composing a reply it defaults the visibility to the status being replied to. Also, public timeline visibility is no longer in the options list when replying, it never had an effect and was just erroneously left there.
This commit is contained in:
Vavassor 2017-03-05 19:58:36 -05:00
parent b0b84509cd
commit 96d9444e0b
4 changed files with 52 additions and 6 deletions

View file

@ -89,6 +89,7 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
@ -345,6 +346,12 @@ public class ComposeActivity extends BaseActivity {
String[] mentionedUsernames = null; String[] mentionedUsernames = null;
if (intent != null) { if (intent != null) {
inReplyToId = intent.getStringExtra("in_reply_to_id"); inReplyToId = intent.getStringExtra("in_reply_to_id");
String replyVisibility = intent.getStringExtra("reply_visibility");
if (replyVisibility != null) {
/* Override any remembered visibilty and instead adopt the visibility of the status
* to which this replies. */
statusVisibility = replyVisibility;
}
mentionedUsernames = intent.getStringArrayExtra("mentioned_usernames"); mentionedUsernames = intent.getStringArrayExtra("mentioned_usernames");
} }
@ -363,7 +370,7 @@ public class ComposeActivity extends BaseActivity {
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) { 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();
charactersLeft.setText(Integer.toString(left)); charactersLeft.setText(String.format(Locale.getDefault(), "%d", left));
} }
@Override @Override
@ -435,7 +442,7 @@ public class ComposeActivity extends BaseActivity {
public void onClick(View v) { public void onClick(View v) {
ComposeOptionsFragment fragment = ComposeOptionsFragment.newInstance( ComposeOptionsFragment fragment = ComposeOptionsFragment.newInstance(
statusVisibility, statusMarkSensitive, statusHideText, statusVisibility, statusMarkSensitive, statusHideText,
showMarkSensitive, showMarkSensitive, inReplyToId != null,
new ComposeOptionsFragment.Listener() { new ComposeOptionsFragment.Listener() {
@Override @Override
public int describeContents() { public int describeContents() {
@ -498,6 +505,11 @@ public class ComposeActivity extends BaseActivity {
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
if (inReplyToId != null) {
/* Don't save the visibility setting for replies because they adopt the visibility of
* the status they reply to and that behaviour needs to be kept separate. */
return;
}
SharedPreferences preferences = getSharedPreferences( SharedPreferences preferences = getSharedPreferences(
getString(R.string.preferences_file_key), Context.MODE_PRIVATE); getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit(); SharedPreferences.Editor editor = preferences.edit();

View file

@ -9,6 +9,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.RadioGroup; import android.widget.RadioGroup;
public class ComposeOptionsFragment extends BottomSheetDialogFragment { public class ComposeOptionsFragment extends BottomSheetDialogFragment {
@ -21,7 +22,7 @@ public class ComposeOptionsFragment extends BottomSheetDialogFragment {
private Listener listener; private Listener listener;
public static ComposeOptionsFragment newInstance(String visibility, boolean markSensitive, public static ComposeOptionsFragment newInstance(String visibility, boolean markSensitive,
boolean hideText, boolean showMarkSensitive, Listener listener) { boolean hideText, boolean showMarkSensitive, boolean isReply, Listener listener) {
Bundle arguments = new Bundle(); Bundle arguments = new Bundle();
ComposeOptionsFragment fragment = new ComposeOptionsFragment(); ComposeOptionsFragment fragment = new ComposeOptionsFragment();
arguments.putParcelable("listener", listener); arguments.putParcelable("listener", listener);
@ -29,6 +30,7 @@ public class ComposeOptionsFragment extends BottomSheetDialogFragment {
arguments.putBoolean("markSensitive", markSensitive); arguments.putBoolean("markSensitive", markSensitive);
arguments.putBoolean("hideText", hideText); arguments.putBoolean("hideText", hideText);
arguments.putBoolean("showMarkSensitive", showMarkSensitive); arguments.putBoolean("showMarkSensitive", showMarkSensitive);
arguments.putBoolean("isReply", isReply);
fragment.setArguments(arguments); fragment.setArguments(arguments);
return fragment; return fragment;
} }
@ -45,9 +47,15 @@ public class ComposeOptionsFragment extends BottomSheetDialogFragment {
boolean statusMarkSensitive = arguments.getBoolean("markSensitive"); boolean statusMarkSensitive = arguments.getBoolean("markSensitive");
boolean statusHideText = arguments.getBoolean("hideText"); boolean statusHideText = arguments.getBoolean("hideText");
boolean showMarkSensitive = arguments.getBoolean("showMarkSensitive"); boolean showMarkSensitive = arguments.getBoolean("showMarkSensitive");
boolean isReply = arguments.getBoolean("isReply");
RadioGroup radio = (RadioGroup) rootView.findViewById(R.id.radio_visibility); RadioGroup radio = (RadioGroup) rootView.findViewById(R.id.radio_visibility);
int radioCheckedId = R.id.radio_public; int radioCheckedId;
if (!isReply) {
radioCheckedId = R.id.radio_public;
} else {
radioCheckedId = R.id.radio_unlisted;
}
if (statusVisibility != null) { if (statusVisibility != null) {
if (statusVisibility.equals("unlisted")) { if (statusVisibility.equals("unlisted")) {
radioCheckedId = R.id.radio_unlisted; radioCheckedId = R.id.radio_unlisted;
@ -78,6 +86,10 @@ public class ComposeOptionsFragment extends BottomSheetDialogFragment {
listener.onVisibilityChanged(visibility); listener.onVisibilityChanged(visibility);
} }
}); });
if (isReply) {
RadioButton publicButton = (RadioButton) rootView.findViewById(R.id.radio_public);
publicButton.setEnabled(false);
}
CheckBox markSensitive = (CheckBox) rootView.findViewById(R.id.compose_mark_sensitive); CheckBox markSensitive = (CheckBox) rootView.findViewById(R.id.compose_mark_sensitive);
if (showMarkSensitive) { if (showMarkSensitive) {

View file

@ -121,6 +121,7 @@ public class SFragment extends Fragment {
mentionedUsernames.remove(loggedInUsername); mentionedUsernames.remove(loggedInUsername);
Intent intent = new Intent(getContext(), ComposeActivity.class); Intent intent = new Intent(getContext(), ComposeActivity.class);
intent.putExtra("in_reply_to_id", inReplyToId); intent.putExtra("in_reply_to_id", inReplyToId);
intent.putExtra("reply_visibility", status.getVisibility().toString().toLowerCase());
intent.putExtra("mentioned_usernames", mentionedUsernames.toArray(new String[0])); intent.putExtra("mentioned_usernames", mentionedUsernames.toArray(new String[0]));
startActivity(intent); startActivity(intent);
} }
@ -252,6 +253,12 @@ public class SFragment extends Fragment {
startActivity(intent); startActivity(intent);
break; break;
} }
case UNKNOWN: {
/* Intentionally do nothing. This case is here is to handle when new attachment
* types are added to the API before code is added here to handle them. So, the
* best fallback is to just show the preview and ignore requests to view them. */
break;
}
} }
} }

View file

@ -15,6 +15,7 @@
package com.keylesspalace.tusky; package com.keylesspalace.tusky;
import android.support.annotation.Nullable;
import android.text.Spanned; import android.text.Spanned;
import org.json.JSONArray; import org.json.JSONArray;
@ -177,6 +178,8 @@ public class Status {
return status.id.equals(this.id); return status.id.equals(this.id);
} }
@SuppressWarnings("SimpleDateFormat") // UTC needs to not specify a Locale
@Nullable
private static Date parseDate(String dateTime) { private static Date parseDate(String dateTime) {
Date date; Date date;
String s = dateTime.replace("Z", "+00:00"); String s = dateTime.replace("Z", "+00:00");
@ -190,6 +193,18 @@ public class Status {
return date; return date;
} }
private static MediaAttachment.Type parseMediaType(@Nullable String type) {
if (type == null) {
return MediaAttachment.Type.UNKNOWN;
}
switch (type.toUpperCase()) {
case "IMAGE": return MediaAttachment.Type.IMAGE;
case "GIFV":
case "VIDEO": return MediaAttachment.Type.VIDEO;
default: return MediaAttachment.Type.UNKNOWN;
}
}
public static Status parse(JSONObject object, boolean isReblog) throws JSONException { public static Status parse(JSONObject object, boolean isReblog) throws JSONException {
String id = object.getString("id"); String id = object.getString("id");
String content = object.getString("content"); String content = object.getString("content");
@ -239,8 +254,7 @@ public class Status {
String url = attachment.getString("url"); String url = attachment.getString("url");
String previewUrl = attachment.getString("preview_url"); String previewUrl = attachment.getString("preview_url");
String type = attachment.getString("type"); String type = attachment.getString("type");
attachments[i] = new MediaAttachment(url, previewUrl, attachments[i] = new MediaAttachment(url, previewUrl, parseMediaType(type));
MediaAttachment.Type.valueOf(type.toUpperCase()));
} }
} }
@ -289,6 +303,7 @@ public class Status {
enum Type { enum Type {
IMAGE, IMAGE,
VIDEO, VIDEO,
UNKNOWN,
} }
private String url; private String url;