diff options
Diffstat (limited to 'app/src')
8 files changed, 378 insertions, 29 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/UploadImageEnabledActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/UploadImageEnabledActivity.java new file mode 100644 index 00000000..aecde88f --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/UploadImageEnabledActivity.java @@ -0,0 +1,7 @@ +package ml.docilealligator.infinityforreddit; + +public interface UploadImageEnabledActivity { + void uploadImage(); + void captureImage(); + void insertImageUrl(UploadedImage uploadedImage); +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/UploadedImage.java b/app/src/main/java/ml/docilealligator/infinityforreddit/UploadedImage.java new file mode 100644 index 00000000..e3d28734 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/UploadedImage.java @@ -0,0 +1,42 @@ +package ml.docilealligator.infinityforreddit; + +import android.os.Parcel; +import android.os.Parcelable; + +public class UploadedImage implements Parcelable { + public String imageName; + public String imageUrl; + + public UploadedImage(String imageName, String imageUrl) { + this.imageName = imageName; + this.imageUrl = imageUrl; + } + + protected UploadedImage(Parcel in) { + imageName = in.readString(); + imageUrl = in.readString(); + } + + public static final Creator<UploadedImage> CREATOR = new Creator<UploadedImage>() { + @Override + public UploadedImage createFromParcel(Parcel in) { + return new UploadedImage(in); + } + + @Override + public UploadedImage[] newArray(int size) { + return new UploadedImage[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(imageName); + parcel.writeString(imageUrl); + } +} 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 9262eea2..93e4e2a8 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java @@ -1,13 +1,19 @@ 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; 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; @@ -22,6 +28,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.content.FileProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -36,7 +43,9 @@ import org.greenrobot.eventbus.Subscribe; import org.json.JSONException; import org.xmlpull.v1.XmlPullParserException; +import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; @@ -57,8 +66,11 @@ import io.noties.markwon.recycler.table.TableEntry; import io.noties.markwon.recycler.table.TableEntryPlugin; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.UploadImageEnabledActivity; +import ml.docilealligator.infinityforreddit.UploadedImage; import ml.docilealligator.infinityforreddit.adapters.MarkdownBottomBarRecyclerViewAdapter; import ml.docilealligator.infinityforreddit.bottomsheetfragments.CopyTextBottomSheetFragment; +import ml.docilealligator.infinityforreddit.bottomsheetfragments.UploadedImagesBottomSheetFragment; import ml.docilealligator.infinityforreddit.comment.Comment; import ml.docilealligator.infinityforreddit.comment.SendComment; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; @@ -68,7 +80,7 @@ import ml.docilealligator.infinityforreddit.utils.UploadImageUtils; import ml.docilealligator.infinityforreddit.utils.Utils; import retrofit2.Retrofit; -public class CommentActivity extends BaseActivity { +public class CommentActivity extends BaseActivity implements UploadImageEnabledActivity { public static final String EXTRA_COMMENT_PARENT_TEXT_KEY = "ECPTK"; public static final String EXTRA_COMMENT_PARENT_TEXT_MARKDOWN_KEY = "ECPTMK"; @@ -81,6 +93,8 @@ public class CommentActivity extends BaseActivity { public static final String RETURN_EXTRA_COMMENT_DATA_KEY = "RECDK"; public static final int WRITE_COMMENT_REQUEST_CODE = 1; private static final int PICK_IMAGE_REQUEST_CODE = 100; + private static final int CAPTURE_IMAGE_REQUEST_CODE = 200; + private static final String UPLOADED_IMAGES_STATE = "UIS"; @BindView(R.id.coordinator_layout_comment_activity) CoordinatorLayout coordinatorLayout; @@ -121,6 +135,8 @@ public class CommentActivity extends BaseActivity { private boolean isSubmitting = false; private boolean isReplying; private int markdownColor; + private Uri capturedImageUri; + private ArrayList<UploadedImage> uploadedImages = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -247,6 +263,10 @@ public class CommentActivity extends BaseActivity { setSupportActionBar(toolbar); + if (savedInstanceState != null) { + uploadedImages = savedInstanceState.getParcelableArrayList(UPLOADED_IMAGES_STATE); + } + MarkdownBottomBarRecyclerViewAdapter adapter = new MarkdownBottomBarRecyclerViewAdapter( mCustomThemeWrapper, new MarkdownBottomBarRecyclerViewAdapter.ItemClickListener() { @Override @@ -257,11 +277,13 @@ public class CommentActivity extends BaseActivity { @Override public void onUploadImage() { - 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); + Utils.hideKeyboard(CommentActivity.this); + UploadedImagesBottomSheetFragment fragment = new UploadedImagesBottomSheetFragment(); + Bundle arguments = new Bundle(); + arguments.putParcelableArrayList(UploadedImagesBottomSheetFragment.EXTRA_UPLOADED_IMAGES, + uploadedImages); + fragment.setArguments(arguments); + fragment.show(getSupportFragmentManager(), fragment.getTag()); } }); @@ -277,6 +299,12 @@ public class CommentActivity extends BaseActivity { } @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelableArrayList(UPLOADED_IMAGES_STATE, uploadedImages); + } + + @Override public SharedPreferences getDefaultSharedPreferences() { return mSharedPreferences; } @@ -397,32 +425,44 @@ public class CommentActivity extends BaseActivity { Toast.makeText(CommentActivity.this, R.string.error_getting_image, Toast.LENGTH_LONG).show(); return; } - Handler handler = new Handler(); - mExecutor.execute(() -> { - try { - Bitmap bitmap = Glide.with(CommentActivity.this).asBitmap().load(data.getData()).submit().get(); - String imageUrlOrError = UploadImageUtils.uploadImage(mOauthRetrofit, mUploadMediaRetrofit, mAccessToken, bitmap); - handler.post(() -> { - if (imageUrlOrError != null && !imageUrlOrError.startsWith("Error: ")) { - int start = Math.max(commentEditText.getSelectionStart(), 0); - int end = Math.max(commentEditText.getSelectionEnd(), 0); - commentEditText.getText().replace(Math.min(start, end), Math.max(start, end), - "[" + imageUrlOrError + "](" + imageUrlOrError + ")", - 0, "[]()".length() + imageUrlOrError.length() + imageUrlOrError.length()); - } else { - Toast.makeText(CommentActivity.this, R.string.upload_image_failed, Toast.LENGTH_LONG).show(); - } - }); - } catch (ExecutionException | InterruptedException e) { - e.printStackTrace(); - handler.post(() -> Toast.makeText(CommentActivity.this, R.string.get_image_bitmap_failed, Toast.LENGTH_LONG).show()); - } catch (XmlPullParserException | JSONException | IOException e) { - e.printStackTrace(); - handler.post(() -> Toast.makeText(CommentActivity.this, R.string.error_processing_image, Toast.LENGTH_LONG).show()); + uploadImageToReddit(data.getData()); + } else if (requestCode == CAPTURE_IMAGE_REQUEST_CODE) { + uploadImageToReddit(capturedImageUri); + } + } + } + + private void uploadImageToReddit(Uri imageUri) { + Handler handler = new Handler(); + mExecutor.execute(() -> { + try { + Bitmap bitmap = Glide.with(CommentActivity.this).asBitmap().load(imageUri).submit().get(); + String imageUrlOrError = UploadImageUtils.uploadImage(mOauthRetrofit, mUploadMediaRetrofit, mAccessToken, bitmap); + handler.post(() -> { + if (imageUrlOrError != null && !imageUrlOrError.startsWith("Error: ")) { + String fileName = getFileName(imageUri); + if (fileName == null) { + fileName = imageUrlOrError; + } + uploadedImages.add(new UploadedImage(fileName, imageUrlOrError)); + + int start = Math.max(commentEditText.getSelectionStart(), 0); + int end = Math.max(commentEditText.getSelectionEnd(), 0); + commentEditText.getText().replace(Math.min(start, end), Math.max(start, end), + "[" + imageUrlOrError + "](" + imageUrlOrError + ")", + 0, "[]()".length() + imageUrlOrError.length() + imageUrlOrError.length()); + } else { + Toast.makeText(CommentActivity.this, R.string.upload_image_failed, Toast.LENGTH_LONG).show(); } }); + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + handler.post(() -> Toast.makeText(CommentActivity.this, R.string.get_image_bitmap_failed, Toast.LENGTH_LONG).show()); + } catch (XmlPullParserException | JSONException | IOException e) { + e.printStackTrace(); + handler.post(() -> Toast.makeText(CommentActivity.this, R.string.error_processing_image, Toast.LENGTH_LONG).show()); } - } + }); } @Override @@ -448,4 +488,52 @@ public class CommentActivity extends BaseActivity { public void onAccountSwitchEvent(SwitchAccountEvent event) { 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(); + return cursor.getString(nameIndex); + } + } + + return null; + } + + @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(commentEditText.getSelectionStart(), 0); + int end = Math.max(commentEditText.getSelectionEnd(), 0); + commentEditText.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/adapters/UploadedImagesRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/UploadedImagesRecyclerViewAdapter.java new file mode 100644 index 00000000..eebd6482 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/UploadedImagesRecyclerViewAdapter.java @@ -0,0 +1,61 @@ +package ml.docilealligator.infinityforreddit.adapters; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; + +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.UploadedImage; + +public class UploadedImagesRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { + private ArrayList<UploadedImage> uploadedImages; + private ItemClickListener itemClickListener; + + public UploadedImagesRecyclerViewAdapter(ArrayList<UploadedImage> uploadedImages, ItemClickListener itemClickListener) { + this.uploadedImages = uploadedImages; + this.itemClickListener = itemClickListener; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new UploadedImageViewHolder(LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_uploaded_image, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + ((UploadedImageViewHolder) holder).imageNameTextView.setText(uploadedImages.get(position).imageName); + ((UploadedImageViewHolder) holder).imageUrlTextView.setText(uploadedImages.get(position).imageUrl); + } + + @Override + public int getItemCount() { + return uploadedImages == null ? 0 : uploadedImages.size(); + } + + private class UploadedImageViewHolder extends RecyclerView.ViewHolder { + TextView imageNameTextView; + TextView imageUrlTextView; + + public UploadedImageViewHolder(@NonNull View itemView) { + super(itemView); + imageNameTextView = itemView.findViewById(R.id.image_name_item_uploaded_image); + imageUrlTextView = itemView.findViewById(R.id.image_url_item_uploaded_image); + + itemView.setOnClickListener(view -> { + itemClickListener.onClick(uploadedImages.get(getBindingAdapterPosition())); + }); + } + } + + public interface ItemClickListener { + void onClick(UploadedImage uploadedImage); + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/UploadedImagesBottomSheetFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/UploadedImagesBottomSheetFragment.java new file mode 100644 index 00000000..cc100c79 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/UploadedImagesBottomSheetFragment.java @@ -0,0 +1,67 @@ +package ml.docilealligator.infinityforreddit.bottomsheetfragments; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.deishelon.roundedbottomsheet.RoundedBottomSheetDialogFragment; +import com.google.android.material.button.MaterialButton; + +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.UploadImageEnabledActivity; +import ml.docilealligator.infinityforreddit.adapters.UploadedImagesRecyclerViewAdapter; + +public class UploadedImagesBottomSheetFragment extends RoundedBottomSheetDialogFragment { + + public static final String EXTRA_UPLOADED_IMAGES = "EUI"; + + private MaterialButton uploadButton; + private MaterialButton captureButton; + private RecyclerView uploadedImagesRecyclerView; + private UploadedImagesRecyclerViewAdapter adapter; + private UploadImageEnabledActivity activity; + + public UploadedImagesBottomSheetFragment() { + // Required empty public constructor + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View rootView = inflater.inflate(R.layout.fragment_uploaded_images_bottom_sheet, container, false); + uploadButton = rootView.findViewById(R.id.upload_button_uploaded_images_bottom_sheet_fragment); + captureButton = rootView.findViewById(R.id.capture_button_uploaded_images_bottom_sheet_fragment); + + uploadButton.setOnClickListener(view -> { + activity.uploadImage(); + dismiss(); + }); + + captureButton.setOnClickListener(view -> { + activity.captureImage(); + dismiss(); + }); + + uploadedImagesRecyclerView = rootView.findViewById(R.id.recycler_view_uploaded_images_bottom_sheet); + adapter = new UploadedImagesRecyclerViewAdapter( + getArguments().getParcelableArrayList(EXTRA_UPLOADED_IMAGES), uploadedImage -> { + activity.insertImageUrl(uploadedImage); + dismiss(); + }); + uploadedImagesRecyclerView.setAdapter(adapter); + + return rootView; + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + this.activity = (UploadImageEnabledActivity) context; + } +}
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_uploaded_images_bottom_sheet.xml b/app/src/main/res/layout/fragment_uploaded_images_bottom_sheet.xml new file mode 100644 index 00000000..4eb8005c --- /dev/null +++ b/app/src/main/res/layout/fragment_uploaded_images_bottom_sheet.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:orientation="vertical" + tools:context=".bottomsheetfragments.UploadedImagesBottomSheetFragment"> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingTop="8dp" + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:text="@string/uploaded_images" + android:fontFamily="?attr/font_family" + android:textSize="?attr/font_18" + android:textColor="?attr/primaryTextColor" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="end"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/capture_button_uploaded_images_bottom_sheet_fragment" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:backgroundTint="@color/colorPrimary" + android:textColor="#FFFFFF" + android:text="@string/capture" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/upload_button_uploaded_images_bottom_sheet_fragment" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:backgroundTint="@color/colorPrimary" + android:textColor="#FFFFFF" + android:text="@string/upload" /> + + </LinearLayout> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recycler_view_uploaded_images_bottom_sheet" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> + +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/item_uploaded_image.xml b/app/src/main/res/layout/item_uploaded_image.xml new file mode 100644 index 00000000..6fb4b589 --- /dev/null +++ b/app/src/main/res/layout/item_uploaded_image.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="16dp" + android:clickable="true" + android:focusable="true" + android:background="?attr/selectableItemBackground"> + + <TextView + android:id="@+id/image_name_item_uploaded_image" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fontFamily="?attr/font_family" + android:textSize="?attr/font_16" + android:textColor="?attr/primaryTextColor" /> + + <TextView + android:id="@+id/image_url_item_uploaded_image" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:fontFamily="?attr/font_family" + android:textSize="?attr/font_12" + android:textColor="?attr/secondaryTextColor" /> + +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cf4d8871..468d7d6d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1118,6 +1118,9 @@ <string name="reply">Reply</string> + <string name="uploaded_images">Uploaded Images</string> + <string name="upload">Upload</string> + <string name="capture">Capture</string> <string name="get_image_bitmap_failed">Unable to get the bitmap of the image</string> <string name="upload_image_failed">Unable to upload the image</string> |