diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java index 2c3e10b6..a7e675b2 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java @@ -1,11 +1,9 @@ package ml.docilealligator.infinityforreddit.activities; import android.content.ActivityNotFoundException; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; @@ -13,7 +11,6 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.provider.MediaStore; -import android.provider.OpenableColumns; import android.text.Spanned; import android.text.util.Linkify; import android.view.Menu; @@ -425,9 +422,11 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA Toast.makeText(CommentActivity.this, R.string.error_getting_image, Toast.LENGTH_LONG).show(); return; } - uploadImageToReddit(data.getData()); + Utils.uploadImageToReddit(this, mExecutor, mOauthRetrofit, mUploadMediaRetrofit, + mAccessToken, commentEditText, coordinatorLayout, data.getData(), uploadedImages); } else if (requestCode == CAPTURE_IMAGE_REQUEST_CODE) { - uploadImageToReddit(capturedImageUri); + Utils.uploadImageToReddit(this, mExecutor, mOauthRetrofit, mUploadMediaRetrofit, + mAccessToken, commentEditText, coordinatorLayout, capturedImageUri, uploadedImages); } } } @@ -441,7 +440,7 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA String imageUrlOrError = UploadImageUtils.uploadImage(mOauthRetrofit, mUploadMediaRetrofit, mAccessToken, bitmap); handler.post(() -> { if (imageUrlOrError != null && !imageUrlOrError.startsWith("Error: ")) { - String fileName = getFileName(imageUri); + String fileName = Utils.getFileName(this, imageUri); if (fileName == null) { fileName = imageUrlOrError; } @@ -491,25 +490,6 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA finish(); } - @Nullable - private String getFileName(Uri uri) { - ContentResolver contentResolver = getContentResolver(); - if (contentResolver != null) { - Cursor cursor = contentResolver.query(uri, null, null, null, null); - if (cursor != null) { - int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); - cursor.moveToFirst(); - String fileName = cursor.getString(nameIndex); - if(fileName != null && fileName.contains(".")) { - fileName = fileName.substring(0, fileName.lastIndexOf('.')); - } - return fileName; - } - } - - return null; - } - @Override public void uploadImage() { Intent intent = new Intent(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/PostTextActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/PostTextActivity.java index 1d256f00..f1cd11cc 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/PostTextActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/PostTextActivity.java @@ -1,24 +1,30 @@ package ml.docilealligator.infinityforreddit.activities; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.content.res.Resources; +import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; +import android.provider.MediaStore; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -33,6 +39,9 @@ import com.libRG.CustomTextView; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -45,19 +54,24 @@ import ml.docilealligator.infinityforreddit.Flair; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; +import ml.docilealligator.infinityforreddit.UploadImageEnabledActivity; +import ml.docilealligator.infinityforreddit.UploadedImage; import ml.docilealligator.infinityforreddit.adapters.MarkdownBottomBarRecyclerViewAdapter; import ml.docilealligator.infinityforreddit.asynctasks.LoadSubredditIcon; import ml.docilealligator.infinityforreddit.bottomsheetfragments.FlairBottomSheetFragment; +import ml.docilealligator.infinityforreddit.bottomsheetfragments.UploadedImagesBottomSheetFragment; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.events.SubmitTextOrLinkPostEvent; import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent; import ml.docilealligator.infinityforreddit.services.SubmitPostService; import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; +import ml.docilealligator.infinityforreddit.utils.Utils; import pl.droidsonroids.gif.GifImageView; import retrofit2.Retrofit; -public class PostTextActivity extends BaseActivity implements FlairBottomSheetFragment.FlairSelectionCallback { +public class PostTextActivity extends BaseActivity implements FlairBottomSheetFragment.FlairSelectionCallback, + UploadImageEnabledActivity { static final String EXTRA_SUBREDDIT_NAME = "ESN"; static final String EXTRA_CONTENT = "EC"; @@ -71,8 +85,11 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr private static final String FLAIR_STATE = "FS"; private static final String IS_SPOILER_STATE = "ISS"; private static final String IS_NSFW_STATE = "INS"; + private static final String UPLOADED_IMAGES_STATE = "UIS"; private static final int SUBREDDIT_SELECTION_REQUEST_CODE = 0; + private static final int PICK_IMAGE_REQUEST_CODE = 100; + private static final int CAPTURE_IMAGE_REQUEST_CODE = 200; @BindView(R.id.coordinator_layout_post_text_activity) CoordinatorLayout coordinatorLayout; @@ -111,6 +128,9 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr @Named("oauth") Retrofit mOauthRetrofit; @Inject + @Named("upload_media") + Retrofit mUploadMediaRetrofit; + @Inject RedditDataRoomDatabase mRedditDataRoomDatabase; @Inject @Named("default") @@ -144,6 +164,8 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr private RequestManager mGlide; private FlairBottomSheetFragment flairSelectionBottomSheetFragment; private Snackbar mPostingSnackbar; + private Uri capturedImageUri; + private ArrayList uploadedImages = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -186,6 +208,7 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr flair = savedInstanceState.getParcelable(FLAIR_STATE); isSpoiler = savedInstanceState.getBoolean(IS_SPOILER_STATE); isNSFW = savedInstanceState.getBoolean(IS_NSFW_STATE); + uploadedImages = savedInstanceState.getParcelableArrayList(UPLOADED_IMAGES_STATE); if (subredditName != null) { subredditNameTextView.setTextColor(primaryTextColor); @@ -320,7 +343,13 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr @Override public void onUploadImage() { - + Utils.hideKeyboard(PostTextActivity.this); + UploadedImagesBottomSheetFragment fragment = new UploadedImagesBottomSheetFragment(); + Bundle arguments = new Bundle(); + arguments.putParcelableArrayList(UploadedImagesBottomSheetFragment.EXTRA_UPLOADED_IMAGES, + uploadedImages); + fragment.setArguments(arguments); + fragment.show(getSupportFragmentManager(), fragment.getTag()); } }); @@ -499,13 +528,14 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr outState.putParcelable(FLAIR_STATE, flair); outState.putBoolean(IS_SPOILER_STATE, isSpoiler); outState.putBoolean(IS_NSFW_STATE, isNSFW); + outState.putParcelableArrayList(UPLOADED_IMAGES_STATE, uploadedImages); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == SUBREDDIT_SELECTION_REQUEST_CODE) { - if (resultCode == RESULT_OK) { + if (resultCode == RESULT_OK) { + if (requestCode == SUBREDDIT_SELECTION_REQUEST_CODE) { subredditName = data.getExtras().getString(SubredditSelectionActivity.EXTRA_RETURN_SUBREDDIT_NAME); iconUrl = data.getExtras().getString(SubredditSelectionActivity.EXTRA_RETURN_SUBREDDIT_ICON_URL); subredditSelected = true; @@ -520,8 +550,20 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr flairTextView.setTextColor(primaryTextColor); flairTextView.setText(getString(R.string.flair)); flair = null; + + } else if (requestCode == PICK_IMAGE_REQUEST_CODE) { + if (data == null) { + Toast.makeText(PostTextActivity.this, R.string.error_getting_image, Toast.LENGTH_LONG).show(); + return; + } + Utils.uploadImageToReddit(this, mExecutor, mOauthRetrofit, mUploadMediaRetrofit, + mAccessToken, contentEditText, coordinatorLayout, data.getData(), uploadedImages); + } else if (requestCode == CAPTURE_IMAGE_REQUEST_CODE) { + Utils.uploadImageToReddit(this, mExecutor, mOauthRetrofit, mUploadMediaRetrofit, + mAccessToken, contentEditText, coordinatorLayout, capturedImageUri, uploadedImages); } } + } @Override @@ -564,4 +606,37 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr } } } + + @Override + public void uploadImage() { + Intent intent = new Intent(); + intent.setType("image/*"); + intent.setAction(Intent.ACTION_GET_CONTENT); + startActivityForResult(Intent.createChooser(intent, + getResources().getString(R.string.select_from_gallery)), PICK_IMAGE_REQUEST_CODE); + } + + @Override + public void captureImage() { + Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + try { + capturedImageUri = FileProvider.getUriForFile(this, "ml.docilealligator.infinityforreddit.provider", + File.createTempFile("captured_image", ".jpg", getExternalFilesDir(Environment.DIRECTORY_PICTURES))); + pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageUri); + startActivityForResult(pictureIntent, CAPTURE_IMAGE_REQUEST_CODE); + } catch (IOException ex) { + Toast.makeText(this, R.string.error_creating_temp_file, Toast.LENGTH_SHORT).show(); + } catch (ActivityNotFoundException e) { + Toast.makeText(this, R.string.no_camera_available, Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void insertImageUrl(UploadedImage uploadedImage) { + int start = Math.max(contentEditText.getSelectionStart(), 0); + int end = Math.max(contentEditText.getSelectionEnd(), 0); + contentEditText.getText().replace(Math.min(start, end), Math.max(start, end), + "[" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")", + 0, "[]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length()); + } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java index 1044f49c..e01f41cd 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java @@ -1,32 +1,53 @@ package ml.docilealligator.infinityforreddit.utils; import android.app.Activity; +import android.content.ContentResolver; import android.content.Context; +import android.database.Cursor; +import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; +import android.net.Uri; import android.os.Build; +import android.os.Handler; +import android.provider.OpenableColumns; import android.text.Spannable; import android.util.DisplayMetrics; import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; import androidx.core.text.HtmlCompat; +import com.bumptech.glide.Glide; +import com.google.android.material.snackbar.Snackbar; + +import org.json.JSONException; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; import java.util.regex.Matcher; import java.util.regex.Pattern; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.SortType; +import ml.docilealligator.infinityforreddit.UploadedImage; +import retrofit2.Retrofit; public class Utils { public static final int NETWORK_TYPE_OTHER = -1; @@ -311,4 +332,61 @@ public class Utils { return null; } + + public static void uploadImageToReddit(Context context, Executor executor, Retrofit oauthRetrofit, + Retrofit uploadMediaRetrofit, String accessToken, EditText editText, + CoordinatorLayout coordinatorLayout, Uri imageUri, + ArrayListuploadedImages) { + Toast.makeText(context, R.string.uploading_image, Toast.LENGTH_SHORT).show(); + Handler handler = new Handler(); + executor.execute(() -> { + try { + Bitmap bitmap = Glide.with(context).asBitmap().load(imageUri).submit().get(); + String imageUrlOrError = UploadImageUtils.uploadImage(oauthRetrofit, uploadMediaRetrofit, accessToken, bitmap); + handler.post(() -> { + if (imageUrlOrError != null && !imageUrlOrError.startsWith("Error: ")) { + String fileName = Utils.getFileName(context, imageUri); + if (fileName == null) { + fileName = imageUrlOrError; + } + uploadedImages.add(new UploadedImage(fileName, imageUrlOrError)); + + int start = Math.max(editText.getSelectionStart(), 0); + int end = Math.max(editText.getSelectionEnd(), 0); + editText.getText().replace(Math.min(start, end), Math.max(start, end), + "[" + fileName + "](" + imageUrlOrError + ")", + 0, "[]()".length() + fileName.length() + imageUrlOrError.length()); + Snackbar.make(coordinatorLayout, R.string.upload_image_success, Snackbar.LENGTH_LONG).show(); + } else { + Toast.makeText(context, R.string.upload_image_failed, Toast.LENGTH_LONG).show(); + } + }); + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + handler.post(() -> Toast.makeText(context, R.string.get_image_bitmap_failed, Toast.LENGTH_LONG).show()); + } catch (XmlPullParserException | JSONException | IOException e) { + e.printStackTrace(); + handler.post(() -> Toast.makeText(context, R.string.error_processing_image, Toast.LENGTH_LONG).show()); + } + }); + } + + @Nullable + public static String getFileName(Context context, Uri uri) { + ContentResolver contentResolver = context.getContentResolver(); + if (contentResolver != null) { + Cursor cursor = contentResolver.query(uri, null, null, null, null); + if (cursor != null) { + int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + cursor.moveToFirst(); + String fileName = cursor.getString(nameIndex); + if(fileName != null && fileName.contains(".")) { + fileName = fileName.substring(0, fileName.lastIndexOf('.')); + } + return fileName; + } + } + + return null; + } }