Fixed composer losing attachments and status options when changing configuration. Also, the composer remembers your last visibility choice.

This commit is contained in:
Vavassor 2017-02-17 17:56:31 -05:00
parent af4af94775
commit 9eb47a471d
3 changed files with 128 additions and 17 deletions

View file

@ -2,6 +2,8 @@
This is an android client for [Mastodon, a GNU Social-compatible microblogging server](https://mastodon.social). Presently, it is in active development and its current state does not represent the features or design of the final program.
It is currently available for alpha testing on the [Tusky Google Play store page](https://play.google.com/store/apps/details?id=com.keylesspalace.tusky).
Also, [my mastodon account is Vavassor@mastodon.social](https://mastodon.social/users/Vavassor).
## Building

View file

@ -24,10 +24,10 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.media.MediaMetadataRetriever;
import android.media.ThumbnailUtils;
import android.net.Uri;
@ -35,6 +35,7 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.OpenableColumns;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -46,7 +47,6 @@ import android.text.Spannable;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.util.TypedValue;
import android.view.View;
import android.webkit.MimeTypeMap;
import android.widget.Button;
@ -80,6 +80,7 @@ import java.util.Map;
import java.util.Random;
public class ComposeActivity extends BaseActivity {
private static final String TAG = "ComposeActivity"; // logging tag, and volley request tag
private static final int STATUS_CHARACTER_LIMIT = 500;
private static final int STATUS_MEDIA_SIZE_LIMIT = 4000000; // 4MB
private static final int MEDIA_PICK_RESULT = 1;
@ -91,7 +92,7 @@ public class ComposeActivity extends BaseActivity {
private EditText textEditor;
private ImageButton mediaPick;
private LinearLayout mediaPreviewBar;
private List<QueuedMedia> mediaQueued;
private ArrayList<QueuedMedia> mediaQueued;
private CountUpDownLatch waitForMediaLatch;
private boolean showMarkSensitive;
private String statusVisibility; // The current values of the options that will be applied
@ -107,23 +108,72 @@ public class ComposeActivity extends BaseActivity {
enum ReadyStage {
DOWNSIZING,
UPLOADING,
UPLOADING
}
Type type;
ImageView preview;
Uri uri;
String id;
Request uploadRequest;
ReadyStage readyStage;
byte[] content;
long mediaSize;
QueuedMedia(Type type, Uri uri, ImageView preview) {
QueuedMedia(Type type, Uri uri, ImageView preview, long mediaSize) {
this.type = type;
this.uri = uri;
this.preview = preview;
this.mediaSize = mediaSize;
}
}
/**This saves enough information to re-enqueue an attachment when restoring the activity. */
private static class SavedQueuedMedia implements Parcelable {
QueuedMedia.Type type;
Uri uri;
Bitmap preview;
long mediaSize;
SavedQueuedMedia(QueuedMedia.Type type, Uri uri, ImageView view, long mediaSize) {
this.type = type;
this.uri = uri;
this.preview = ((BitmapDrawable) view.getDrawable()).getBitmap();
this.mediaSize = mediaSize;
}
SavedQueuedMedia(Parcel parcel) {
type = (QueuedMedia.Type) parcel.readSerializable();
uri = parcel.readParcelable(Uri.class.getClassLoader());
preview = parcel.readParcelable(Bitmap.class.getClassLoader());
mediaSize = parcel.readLong();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(type);
dest.writeParcelable(uri, flags);
dest.writeParcelable(preview, flags);
dest.writeLong(mediaSize);
}
public static final Parcelable.Creator<SavedQueuedMedia> CREATOR
= new Parcelable.Creator<SavedQueuedMedia>() {
public SavedQueuedMedia createFromParcel(Parcel in) {
return new SavedQueuedMedia(in);
}
public SavedQueuedMedia[] newArray(int size) {
return new SavedQueuedMedia[size];
}
};
}
private void doErrorDialog(int descriptionId, int actionId, View.OnClickListener listener) {
Snackbar bar = Snackbar.make(findViewById(R.id.activity_compose), getString(descriptionId),
Snackbar.LENGTH_SHORT);
@ -247,6 +297,24 @@ public class ComposeActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_compose);
SharedPreferences preferences = getSharedPreferences(
getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
ArrayList<SavedQueuedMedia> savedMediaQueued = null;
if (savedInstanceState != null) {
showMarkSensitive = savedInstanceState.getBoolean("showMarkSensitive");
statusVisibility = savedInstanceState.getString("statusVisibility");
statusMarkSensitive = savedInstanceState.getBoolean("statusMarkSensitive");
statusHideText = savedInstanceState.getBoolean("statusHideText");
// Keep these until everything needed to put them in the queue is finished initializing.
savedMediaQueued = savedInstanceState.getParcelableArrayList("savedMediaQueued");
} else {
showMarkSensitive = false;
statusVisibility = preferences.getString("rememberedVisibility", "public");
statusMarkSensitive = false;
statusHideText = false;
}
Intent intent = getIntent();
String[] mentionedUsernames = null;
if (intent != null) {
@ -254,8 +322,6 @@ public class ComposeActivity extends BaseActivity {
mentionedUsernames = intent.getStringArrayExtra("mentioned_usernames");
}
SharedPreferences preferences = getSharedPreferences(
getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
domain = preferences.getString("domain", null);
accessToken = preferences.getString("accessToken", null);
@ -358,10 +424,48 @@ public class ComposeActivity extends BaseActivity {
fragment.show(getSupportFragmentManager(), null);
}
});
// These can only be added after everything affected by the media queue is initialized.
if (savedMediaQueued != null) {
for (SavedQueuedMedia item : savedMediaQueued) {
addMediaToQueue(item.type, item.preview, item.uri, item.mediaSize);
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
ArrayList<SavedQueuedMedia> savedMediaQueued = new ArrayList<>();
for (QueuedMedia item : mediaQueued) {
savedMediaQueued.add(new SavedQueuedMedia(item.type, item.uri, item.preview,
item.mediaSize));
}
outState.putParcelableArrayList("savedMediaQueued", savedMediaQueued);
outState.putBoolean("showMarkSensitive", showMarkSensitive);
outState.putString("statusVisibility", statusVisibility);
outState.putBoolean("statusMarkSensitive", statusMarkSensitive);
outState.putBoolean("statusHideText", statusHideText);
super.onSaveInstanceState(outState);
}
@Override
protected void onPause() {
super.onPause();
SharedPreferences preferences = getSharedPreferences(
getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("rememberedVisibility", statusVisibility);
editor.apply();
}
@Override
protected void onDestroy() {
super.onDestroy();
VolleySingleton.getInstance(this).cancelAll(TAG);
}
private void sendStatus(String content, String visibility, boolean sensitive,
String spoilerText) {
String spoilerText) {
String endpoint = getString(R.string.endpoint_status);
String url = "https://" + domain + endpoint;
JSONObject parameters = new JSONObject();
@ -373,12 +477,12 @@ public class ComposeActivity extends BaseActivity {
if (inReplyToId != null) {
parameters.put("in_reply_to_id", inReplyToId);
}
JSONArray media_ids = new JSONArray();
JSONArray mediaIds = new JSONArray();
for (QueuedMedia item : mediaQueued) {
media_ids.put(item.id);
mediaIds.put(item.id);
}
if (media_ids.length() > 0) {
parameters.put("media_ids", media_ids);
if (mediaIds.length() > 0) {
parameters.put("media_ids", mediaIds);
}
} catch (JSONException e) {
onSendFailure();
@ -531,7 +635,7 @@ public class ComposeActivity extends BaseActivity {
}
private void addMediaToQueue(QueuedMedia.Type type, Bitmap preview, Uri uri, long mediaSize) {
final QueuedMedia item = new QueuedMedia(type, uri, new ImageView(this));
final QueuedMedia item = new QueuedMedia(type, uri, new ImageView(this), mediaSize);
ImageView view = item.preview;
Resources resources = getResources();
int side = resources.getDimensionPixelSize(R.dimen.compose_media_preview_side);
@ -720,7 +824,8 @@ public class ComposeActivity extends BaseActivity {
return data;
}
};
request.addMarker("media_" + item.uri.toString());
request.setTag(TAG);
item.uploadRequest = request;
VolleySingleton.getInstance(this).addToRequestQueue(request);
}
@ -731,9 +836,13 @@ public class ComposeActivity extends BaseActivity {
private void cancelReadyingMedia(QueuedMedia item) {
if (item.readyStage == QueuedMedia.ReadyStage.UPLOADING) {
VolleySingleton.getInstance(this).cancelRequest("media_" + item.uri.toString());
item.uploadRequest.cancel();
}
if (item.id == null) {
/* The presence of an upload id is used to detect if it finished uploading or not, to
* prevent counting down twice on the same media item. */
waitForMediaLatch.countDown();
}
waitForMediaLatch.countDown();
}
@Override

View file

@ -69,7 +69,7 @@ public class VolleySingleton {
getRequestQueue().add(request);
}
public void cancelRequest(String tag) {
public void cancelAll(String tag) {
getRequestQueue().cancelAll(tag);
}