(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.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
@ -39,10 +38,8 @@ import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar;
import android.support.v13.view.inputmethod.InputConnectionCompat;
@ -56,6 +53,7 @@ import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.URLSpan;
import android.view.MenuItem;
@ -72,15 +70,17 @@ import android.widget.TextView;
import com.keylesspalace.tusky.entity.Media;
import com.keylesspalace.tusky.entity.Status;
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.DownsizeImageTask;
import com.keylesspalace.tusky.util.IOUtils;
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.ThemeUtils;
import com.keylesspalace.tusky.view.EditTextTyped;
import com.squareup.picasso.Picasso;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -92,7 +92,6 @@ import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import butterknife.BindView;
import butterknife.ButterKnife;
@ -103,17 +102,43 @@ import retrofit2.Call;
import retrofit2.Callback;
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 int STATUS_CHARACTER_LIMIT = 500;
private static final int STATUS_MEDIA_SIZE_LIMIT = 4000000; // 4MB
private static final int MEDIA_PICK_RESULT = 1;
private static final int MEDIA_TAKE_PHOTO_RESULT = 2;
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 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 ArrayList<QueuedMedia> mediaQueued;
private CountUpDownLatch waitForMediaLatch;
@ -127,93 +152,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
private Uri photoUploadUri;
// this only exists when a status is trying to be sent, but uploads are still occurring
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
public void onCreate(Bundle savedInstanceState) {
@ -337,6 +276,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
postProgress.setVisibility(View.INVISIBLE);
updateNsfwButtonColor();
final ParserUtils parser = new ParserUtils(this);
// Setup the main text field.
setEditTextMimeTypes(null); // new String[] { "image/gif", "image/webp" }
final int mentionColour = ThemeUtils.getColor(this, R.attr.compose_mention_color);
@ -348,7 +289,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
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.
if (mentionedUsernames != null) {
StringBuilder builder = new StringBuilder();
@ -371,7 +320,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
// Initialise the content warning editor.
contentWarningEditor.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
@ -379,10 +329,11 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
}
@Override
public void afterTextChanged(Editable s) {}
public void afterTextChanged(Editable s) {
}
});
showContentWarning(startingHideText);
if(startingContentWarning != null){
if (startingContentWarning != null) {
contentWarningEditor.setText(startingContentWarning);
}
@ -637,7 +588,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
}
private boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags,
String[] mimeTypes) {
String[] mimeTypes) {
try {
if (currentInputContentInfo != null) {
currentInputContentInfo.releasePermission();
@ -816,9 +767,9 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
private void onMediaPick() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN &&
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
} else {
initiateMediaPicking();
@ -827,7 +778,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
@NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: {
if (grantResults.length > 0
@ -888,7 +839,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
intent.setType("image/* video/*");
} else {
String[] mimeTypes = new String[] { "image/*", "video/*" };
String[] mimeTypes = new String[]{"image/*", "video/*"};
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
}
@ -986,7 +937,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
}
private void removeAllMediaFromQueue() {
for (Iterator<QueuedMedia> it = mediaQueued.iterator(); it.hasNext();) {
for (Iterator<QueuedMedia> it = mediaQueued.iterator(); it.hasNext(); ) {
QueuedMedia item = it.next();
it.remove();
removeMediaFromQueue(item);
@ -1008,7 +959,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
public void onFailure() {
onMediaDownsizeFailure(item);
}
}).execute(item.uri);
}).execute(item.uri);
}
private void onMediaDownsizeFailure(QueuedMedia item) {
@ -1016,32 +967,6 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
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) {
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
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@ -1228,12 +1139,12 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
void showMarkSensitive(boolean show) {
showMarkSensitive = show;
if(!showMarkSensitive) {
if (!showMarkSensitive) {
statusMarkSensitive = false;
nsfwBtn.setTextColor(ThemeUtils.getColor(this, R.attr.compose_nsfw_button_color));
}
if(show) {
if (show) {
nsfwBtn.setVisibility(View.VISIBLE);
} else {
nsfwBtn.setVisibility(View.GONE);
@ -1260,4 +1171,121 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag
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);
}
}
}