(ComposeActivity) clean up, automatique format and implementation of

- Share a link and extract the title, images, author's name #136
This commit is contained in:
torrentcome 2017-05-16 10:43:32 +02:00
parent 6dd2aba3c6
commit b1bbcb39d5
1 changed files with 177 additions and 149 deletions

View File

@ -24,7 +24,6 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor; import android.content.res.AssetFileDescriptor;
import android.content.res.Resources; import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
@ -39,10 +38,8 @@ import android.os.Environment;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.support.annotation.AttrRes; import android.support.annotation.AttrRes;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes; import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v13.view.inputmethod.InputConnectionCompat; import android.support.v13.view.inputmethod.InputConnectionCompat;
@ -56,6 +53,7 @@ import android.support.v7.widget.Toolbar;
import android.text.Editable; import android.text.Editable;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.text.style.URLSpan; import android.text.style.URLSpan;
import android.view.MenuItem; import android.view.MenuItem;
@ -72,15 +70,17 @@ import android.widget.TextView;
import com.keylesspalace.tusky.entity.Media; import com.keylesspalace.tusky.entity.Media;
import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.entity.Status;
import com.keylesspalace.tusky.fragment.ComposeOptionsFragment; import com.keylesspalace.tusky.fragment.ComposeOptionsFragment;
import com.keylesspalace.tusky.util.DownsizeImageTask;
import com.keylesspalace.tusky.view.EditTextTyped;
import com.keylesspalace.tusky.util.CountUpDownLatch; import com.keylesspalace.tusky.util.CountUpDownLatch;
import com.keylesspalace.tusky.util.DownsizeImageTask;
import com.keylesspalace.tusky.util.IOUtils; import com.keylesspalace.tusky.util.IOUtils;
import com.keylesspalace.tusky.util.Log; import com.keylesspalace.tusky.util.Log;
import com.keylesspalace.tusky.util.MediaUtils;
import com.keylesspalace.tusky.util.ParserUtils;
import com.keylesspalace.tusky.util.SpanUtils; import com.keylesspalace.tusky.util.SpanUtils;
import com.keylesspalace.tusky.util.ThemeUtils; import com.keylesspalace.tusky.util.ThemeUtils;
import com.keylesspalace.tusky.view.EditTextTyped;
import com.squareup.picasso.Picasso;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@ -92,7 +92,6 @@ import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Random;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
@ -103,17 +102,43 @@ import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
public class ComposeActivity extends BaseActivity implements ComposeOptionsFragment.Listener { import static com.keylesspalace.tusky.util.MediaUtils.MEDIA_SIZE_UNKNOWN;
import static com.keylesspalace.tusky.util.MediaUtils.getMediaSize;
import static com.keylesspalace.tusky.util.MediaUtils.inputStreamGetBytes;
import static com.keylesspalace.tusky.util.StringUtils.carriageReturn;
import static com.keylesspalace.tusky.util.StringUtils.randomAlphanumericString;
public class ComposeActivity extends BaseActivity implements ComposeOptionsFragment.Listener, ParserUtils.ParserListener {
private static final String TAG = "ComposeActivity"; // logging tag private static final String TAG = "ComposeActivity"; // logging tag
private static final int STATUS_CHARACTER_LIMIT = 500; private static final int STATUS_CHARACTER_LIMIT = 500;
private static final int STATUS_MEDIA_SIZE_LIMIT = 4000000; // 4MB private static final int STATUS_MEDIA_SIZE_LIMIT = 4000000; // 4MB
private static final int MEDIA_PICK_RESULT = 1; private static final int MEDIA_PICK_RESULT = 1;
private static final int MEDIA_TAKE_PHOTO_RESULT = 2; private static final int MEDIA_TAKE_PHOTO_RESULT = 2;
private static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1; private static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;
private static final int MEDIA_SIZE_UNKNOWN = -1;
private static final int COMPOSE_SUCCESS = -1; private static final int COMPOSE_SUCCESS = -1;
private static final int THUMBNAIL_SIZE = 128; // pixels private static final int THUMBNAIL_SIZE = 128; // pixels
@BindView(R.id.compose_edit_field)
EditTextTyped textEditor;
@BindView(R.id.compose_media_preview_bar)
LinearLayout mediaPreviewBar;
@BindView(R.id.compose_content_warning_bar)
View contentWarningBar;
@BindView(R.id.field_content_warning)
EditText contentWarningEditor;
@BindView(R.id.characters_left)
TextView charactersLeft;
@BindView(R.id.floating_btn)
Button floatingBtn;
@BindView(R.id.compose_photo_pick)
ImageButton pickBtn;
@BindView(R.id.compose_photo_take)
ImageButton takeBtn;
@BindView(R.id.action_toggle_nsfw)
Button nsfwBtn;
@BindView(R.id.postProgress)
ProgressBar postProgress;
@BindView(R.id.action_toggle_visibility)
ImageButton visibilityBtn;
private String inReplyToId; private String inReplyToId;
private ArrayList<QueuedMedia> mediaQueued; private ArrayList<QueuedMedia> mediaQueued;
private CountUpDownLatch waitForMediaLatch; private CountUpDownLatch waitForMediaLatch;
@ -127,93 +152,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
private Uri photoUploadUri; private Uri photoUploadUri;
// this only exists when a status is trying to be sent, but uploads are still occurring // this only exists when a status is trying to be sent, but uploads are still occurring
private ProgressDialog finishingUploadDialog; private ProgressDialog finishingUploadDialog;
@BindView(R.id.compose_edit_field)
EditTextTyped textEditor;
@BindView(R.id.compose_media_preview_bar) LinearLayout mediaPreviewBar;
@BindView(R.id.compose_content_warning_bar) View contentWarningBar;
@BindView(R.id.field_content_warning) EditText contentWarningEditor;
@BindView(R.id.characters_left) TextView charactersLeft;
@BindView(R.id.floating_btn) Button floatingBtn;
@BindView(R.id.compose_photo_pick) ImageButton pickBtn;
@BindView(R.id.compose_photo_take) ImageButton takeBtn;
@BindView(R.id.action_toggle_nsfw) Button nsfwBtn;
@BindView(R.id.postProgress) ProgressBar postProgress;
@BindView(R.id.action_toggle_visibility) ImageButton visibilityBtn;
private static class QueuedMedia {
enum Type {
IMAGE,
VIDEO
}
enum ReadyStage {
DOWNSIZING,
UPLOADING
}
Type type;
ImageView preview;
Uri uri;
String id;
Call<Media> uploadRequest;
URLSpan uploadUrl;
ReadyStage readyStage;
byte[] content;
long mediaSize;
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];
}
};
}
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -337,6 +276,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
postProgress.setVisibility(View.INVISIBLE); postProgress.setVisibility(View.INVISIBLE);
updateNsfwButtonColor(); updateNsfwButtonColor();
final ParserUtils parser = new ParserUtils(this);
// Setup the main text field. // Setup the main text field.
setEditTextMimeTypes(null); // new String[] { "image/gif", "image/webp" } setEditTextMimeTypes(null); // new String[] { "image/gif", "image/webp" }
final int mentionColour = ThemeUtils.getColor(this, R.attr.compose_mention_color); final int mentionColour = ThemeUtils.getColor(this, R.attr.compose_mention_color);
@ -348,7 +289,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
} }
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {} public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override @Override
public void afterTextChanged(Editable editable) { public void afterTextChanged(Editable editable) {
@ -356,6 +298,13 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
} }
}); });
textEditor.addOnPasteListener(new EditTextTyped.OnPasteListener() {
@Override
public void onPaste() {
parser.getPastedURLText(ComposeActivity.this);
}
});
// Add any mentions to the text field when a reply is first composed. // Add any mentions to the text field when a reply is first composed.
if (mentionedUsernames != null) { if (mentionedUsernames != null) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@ -371,7 +320,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
// Initialise the content warning editor. // Initialise the content warning editor.
contentWarningEditor.addTextChangedListener(new TextWatcher() { contentWarningEditor.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {} public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) { public void onTextChanged(CharSequence s, int start, int before, int count) {
@ -379,10 +329,11 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
} }
@Override @Override
public void afterTextChanged(Editable s) {} public void afterTextChanged(Editable s) {
}
}); });
showContentWarning(startingHideText); showContentWarning(startingHideText);
if(startingContentWarning != null){ if (startingContentWarning != null) {
contentWarningEditor.setText(startingContentWarning); contentWarningEditor.setText(startingContentWarning);
} }
@ -637,7 +588,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
} }
private boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, private boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags,
String[] mimeTypes) { String[] mimeTypes) {
try { try {
if (currentInputContentInfo != null) { if (currentInputContentInfo != null) {
currentInputContentInfo.releasePermission(); currentInputContentInfo.releasePermission();
@ -816,9 +767,9 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
private void onMediaPick() { private void onMediaPick() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN &&
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) { != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, ActivityCompat.requestPermissions(this,
new String[] { Manifest.permission.READ_EXTERNAL_STORAGE }, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE); PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
} else { } else {
initiateMediaPicking(); initiateMediaPicking();
@ -827,7 +778,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) { @NonNull int[] grantResults) {
switch (requestCode) { switch (requestCode) {
case PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: { case PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: {
if (grantResults.length > 0 if (grantResults.length > 0
@ -888,7 +839,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
intent.setType("image/* video/*"); intent.setType("image/* video/*");
} else { } else {
String[] mimeTypes = new String[] { "image/*", "video/*" }; String[] mimeTypes = new String[]{"image/*", "video/*"};
intent.setType("*/*"); intent.setType("*/*");
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes); intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
} }
@ -986,7 +937,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
} }
private void removeAllMediaFromQueue() { private void removeAllMediaFromQueue() {
for (Iterator<QueuedMedia> it = mediaQueued.iterator(); it.hasNext();) { for (Iterator<QueuedMedia> it = mediaQueued.iterator(); it.hasNext(); ) {
QueuedMedia item = it.next(); QueuedMedia item = it.next();
it.remove(); it.remove();
removeMediaFromQueue(item); removeMediaFromQueue(item);
@ -1008,7 +959,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
public void onFailure() { public void onFailure() {
onMediaDownsizeFailure(item); onMediaDownsizeFailure(item);
} }
}).execute(item.uri); }).execute(item.uri);
} }
private void onMediaDownsizeFailure(QueuedMedia item) { private void onMediaDownsizeFailure(QueuedMedia item) {
@ -1016,32 +967,6 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
removeMediaFromQueue(item); removeMediaFromQueue(item);
} }
private static String randomAlphanumericString(int count) {
char[] chars = new char[count];
Random random = new Random();
final String POSSIBLE_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < count; i++) {
chars[i] = POSSIBLE_CHARS.charAt(random.nextInt(POSSIBLE_CHARS.length()));
}
return new String(chars);
}
@Nullable
private static byte[] inputStreamGetBytes(InputStream stream) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int read;
byte[] data = new byte[16384];
try {
while ((read = stream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, read);
}
buffer.flush();
} catch (IOException e) {
return null;
}
return buffer.toByteArray();
}
private void uploadMedia(final QueuedMedia item) { private void uploadMedia(final QueuedMedia item) {
item.readyStage = QueuedMedia.ReadyStage.UPLOADING; item.readyStage = QueuedMedia.ReadyStage.UPLOADING;
@ -1136,20 +1061,6 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
} }
} }
private static long getMediaSize(ContentResolver contentResolver, Uri uri) {
long mediaSize;
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null) {
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
cursor.moveToFirst();
mediaSize = cursor.getLong(sizeIndex);
cursor.close();
} else {
mediaSize = MEDIA_SIZE_UNKNOWN;
}
return mediaSize;
}
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
@ -1228,12 +1139,12 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
void showMarkSensitive(boolean show) { void showMarkSensitive(boolean show) {
showMarkSensitive = show; showMarkSensitive = show;
if(!showMarkSensitive) { if (!showMarkSensitive) {
statusMarkSensitive = false; statusMarkSensitive = false;
nsfwBtn.setTextColor(ThemeUtils.getColor(this, R.attr.compose_nsfw_button_color)); nsfwBtn.setTextColor(ThemeUtils.getColor(this, R.attr.compose_nsfw_button_color));
} }
if(show) { if (show) {
nsfwBtn.setVisibility(View.VISIBLE); nsfwBtn.setVisibility(View.VISIBLE);
} else { } else {
nsfwBtn.setVisibility(View.GONE); nsfwBtn.setVisibility(View.GONE);
@ -1260,4 +1171,121 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@Override
public void onReceiveHeaderInfo(ParserUtils.HeaderInfo headerInfo) {
if (!TextUtils.isEmpty(headerInfo.title)) {
cleanBaseUrl(headerInfo);
textEditor.append(headerInfo.title);
textEditor.append(carriageReturn);
textEditor.append(headerInfo.baseUrl);
}
if (!TextUtils.isEmpty(headerInfo.image)) {
Picasso.with(this).load(headerInfo.image).into(MediaUtils.picassoImageTarget(getApplicationContext(), new MediaUtils.MediaListener() {
@Override
public void onCallback(final Uri headerInfo) {
if (headerInfo != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
long mediaSize = getMediaSize(getContentResolver(), headerInfo);
pickMedia(headerInfo, mediaSize);
}
});
}
}
}));
}
}
// remove the precedent paste from the edit text
private void cleanBaseUrl(ParserUtils.HeaderInfo headerInfo) {
int lengthBaseUrl = headerInfo.baseUrl.length();
int total = textEditor.getText().length();
int indexSubString = total - lengthBaseUrl;
String text = textEditor.getText().toString();
text = text.substring(0, indexSubString);
textEditor.setText(text);
}
@Override
public void onErrorHeaderInfo() {
displayTransientError(R.string.error_generic);
}
private static class QueuedMedia {
Type type;
ImageView preview;
Uri uri;
String id;
Call<Media> uploadRequest;
URLSpan uploadUrl;
ReadyStage readyStage;
byte[] content;
long mediaSize;
QueuedMedia(Type type, Uri uri, ImageView preview, long mediaSize) {
this.type = type;
this.uri = uri;
this.preview = preview;
this.mediaSize = mediaSize;
}
enum Type {
IMAGE,
VIDEO
}
enum ReadyStage {
DOWNSIZING,
UPLOADING
}
}
/**
* This saves enough information to re-enqueue an attachment when restoring the activity.
*/
private static class SavedQueuedMedia implements Parcelable {
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];
}
};
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);
}
}
} }