diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostGalleryGridLayoutItemDecoration.kt b/app/src/main/java/ml/docilealligator/infinityforreddit/PostGalleryGridLayoutItemDecoration.kt new file mode 100644 index 00000000..eb068dde --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostGalleryGridLayoutItemDecoration.kt @@ -0,0 +1,56 @@ +package ml.docilealligator.infinityforreddit + +import android.content.Context +import android.graphics.Rect +import android.view.View +import androidx.annotation.DimenRes +import androidx.annotation.OptIn +import androidx.media3.common.util.UnstableApi +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ItemDecoration + +class PostGalleryGridLayoutItemDecoration( + itemOffset: Int, + var spanCount: Int +) : ItemDecoration() { + private val mHalfOffset: Int = itemOffset / 2 + + internal constructor(context: Context, @DimenRes itemOffsetId: Int, spanCount: Int) : this( + context.resources.getDimensionPixelSize(itemOffsetId), spanCount + ) + + @OptIn(markerClass = [UnstableApi::class]) + override fun getItemOffsets( + outRect: Rect, view: View, parent: RecyclerView, + state: RecyclerView.State + ) { + super.getItemOffsets(outRect, view, parent, state) + if (parent.layoutManager is GridLayoutManager) { + val layoutParams = view.layoutParams as GridLayoutManager.LayoutParams + val spanIndex = layoutParams.spanIndex + val rowIndex = parent.getChildAdapterPosition(view) / spanCount + val topMargin = if (rowIndex == 0) 0 else mHalfOffset + + if (spanCount == 2) { + if (spanIndex == 0) { + outRect.set(mHalfOffset, topMargin, 0, 0) + } else { + outRect.set(mHalfOffset, topMargin, 0, 0) + } + } else if (spanCount == 3) { + when (spanIndex) { + 0 -> { + outRect.set(mHalfOffset, topMargin, 0, 0) + } + 1 -> { + outRect.set(mHalfOffset, topMargin, 0, 0) + } + else -> { + outRect.set(mHalfOffset, topMargin, 0, 0) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostGalleryTypeImageRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostGalleryTypeImageRecyclerViewAdapter.java index 089a63b3..8f19f86e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostGalleryTypeImageRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostGalleryTypeImageRecyclerViewAdapter.java @@ -16,7 +16,9 @@ import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.RequestManager; import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.MultiTransformation; import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.Target; @@ -25,6 +27,7 @@ import java.util.ArrayList; import io.noties.markwon.Markwon; import jp.wasabeef.glide.transformations.BlurTransformation; +import jp.wasabeef.glide.transformations.RoundedCornersTransformation; import ml.docilealligator.infinityforreddit.SaveMemoryCenterInisdeDownsampleStrategy; import ml.docilealligator.infinityforreddit.databinding.ItemGalleryImageInPostFeedBinding; import ml.docilealligator.infinityforreddit.post.Post; @@ -43,6 +46,7 @@ public class PostGalleryTypeImageRecyclerViewAdapter extends RecyclerView.Adapte private boolean blurImage; private float ratio; private final boolean showCaption; + private boolean isGridLayout; public PostGalleryTypeImageRecyclerViewAdapter(RequestManager glide, Typeface typeface, SaveMemoryCenterInisdeDownsampleStrategy saveMemoryCenterInisdeDownsampleStrategy, @@ -80,11 +84,15 @@ public class PostGalleryTypeImageRecyclerViewAdapter extends RecyclerView.Adapte @Override public void onBindViewHolder(@NonNull ImageViewHolder holder, int position) { - if (ratio < 0) { + if (isGridLayout) { + holder.binding.imageViewItemGalleryImageInPostFeed.setScaleType(ImageView.ScaleType.CENTER_CROP); + holder.binding.imageViewItemGalleryImageInPostFeed.setRatio(1); + } else if (ratio < 0) { int height = (int) (400 * mScale); holder.binding.imageViewItemGalleryImageInPostFeed.setScaleType(ImageView.ScaleType.CENTER_CROP); holder.binding.imageViewItemGalleryImageInPostFeed.getLayoutParams().height = height; } else { + holder.binding.imageViewItemGalleryImageInPostFeed.setScaleType(ImageView.ScaleType.FIT_XY); holder.binding.imageViewItemGalleryImageInPostFeed.setRatio(ratio); } holder.binding.errorTextViewItemGalleryImageInPostFeed.setVisibility(View.GONE); @@ -157,10 +165,22 @@ public class PostGalleryTypeImageRecyclerViewAdapter extends RecyclerView.Adapte } }); if (blurImage) { - imageRequestBuilder.apply(RequestOptions.bitmapTransform(new BlurTransformation(50, 10))) - .into(holder.binding.imageViewItemGalleryImageInPostFeed); + if (isGridLayout) { + imageRequestBuilder + .apply(RequestOptions.bitmapTransform(new MultiTransformation<>(new CenterCrop(), new RoundedCornersTransformation(32, 0), new BlurTransformation(50, 2)))) + .into(holder.binding.imageViewItemGalleryImageInPostFeed); + } else { + imageRequestBuilder.apply(RequestOptions.bitmapTransform(new BlurTransformation(50, 10))) + .into(holder.binding.imageViewItemGalleryImageInPostFeed); + } } else { - imageRequestBuilder.centerInside().downsample(saveMemoryCenterInisdeDownsampleStrategy).into(holder.binding.imageViewItemGalleryImageInPostFeed); + if (isGridLayout) { + imageRequestBuilder + .apply(RequestOptions.bitmapTransform(new MultiTransformation<>(new CenterCrop(), new RoundedCornersTransformation(32, 0)))) + .downsample(saveMemoryCenterInisdeDownsampleStrategy).into(holder.binding.imageViewItemGalleryImageInPostFeed); + } else { + imageRequestBuilder.centerInside().downsample(saveMemoryCenterInisdeDownsampleStrategy).into(holder.binding.imageViewItemGalleryImageInPostFeed); + } } } @@ -207,6 +227,10 @@ public class PostGalleryTypeImageRecyclerViewAdapter extends RecyclerView.Adapte this.ratio = ratio; } + public void setIsGridLayout(boolean isGridLayout) { + this.isGridLayout = isGridLayout; + } + class ImageViewHolder extends RecyclerView.ViewHolder { ItemGalleryImageInPostFeedBinding binding; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostRecyclerViewAdapter.java index 4a27ab89..258b4dd1 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostRecyclerViewAdapter.java @@ -48,6 +48,7 @@ import androidx.media3.ui.TrackSelectionDialogBuilder; import androidx.paging.ItemSnapshotList; import androidx.paging.PagingDataAdapter; import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.PagerSnapHelper; import androidx.recyclerview.widget.RecyclerView; @@ -76,6 +77,7 @@ import javax.inject.Provider; import jp.wasabeef.glide.transformations.BlurTransformation; import jp.wasabeef.glide.transformations.RoundedCornersTransformation; import ml.docilealligator.infinityforreddit.FetchVideoLinkListener; +import ml.docilealligator.infinityforreddit.PostGalleryGridLayoutItemDecoration; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; import ml.docilealligator.infinityforreddit.SaveMemoryCenterInisdeDownsampleStrategy; @@ -1024,12 +1026,13 @@ public class PostRecyclerViewAdapter extends PagingDataAdapter 0) { + RecyclerView.ItemDecoration itemDecoration = ((PostBaseGalleryTypeViewHolder) holder).galleryRecyclerView.getItemDecorationAt(0); + if (itemDecoration instanceof PostGalleryGridLayoutItemDecoration) { + ((PostGalleryGridLayoutItemDecoration) itemDecoration).setSpanCount(spanCount); + } + } + + ((PostBaseGalleryTypeViewHolder) holder).galleryRecyclerView.setPadding(0, 0, (int) (8 * mScale), 0); + ((PostBaseGalleryTypeViewHolder) holder).adapter.setIsGridLayout(true); + ((PostBaseGalleryTypeViewHolder) holder).imageIndexTextView.setVisibility(View.GONE); + } else { + ((PostBaseGalleryTypeViewHolder) holder).galleryRecyclerView.setPadding(0, 0, 0, 0); + ((PostBaseGalleryTypeViewHolder) holder).adapter.setIsGridLayout(false); + ((PostBaseGalleryTypeViewHolder) holder).imageIndexTextView.setVisibility(View.VISIBLE); + } } else if (holder instanceof PostTextTypeViewHolder) { if (!mHideTextPostContent && !post.isSpoiler() && post.getSelfTextPlainTrimmed() != null && !post.getSelfTextPlainTrimmed().isEmpty()) { ((PostTextTypeViewHolder) holder).contentTextView.setVisibility(View.VISIBLE); @@ -3209,7 +3232,7 @@ public class PostRecyclerViewAdapter extends PagingDataAdapter= 0) { postOptionsBottomSheetFragment = PostOptionsBottomSheetFragment.newInstance(post, - getBindingAdapterPosition(), - ((LinearLayoutManagerBugFixed) ((PostBaseGalleryTypeViewHolder) this).galleryRecyclerView.getLayoutManager()).findFirstVisibleItemPosition()); + getBindingAdapterPosition(), currentGalleryItemPosition); } else { postOptionsBottomSheetFragment = PostOptionsBottomSheetFragment.newInstance(post, getBindingAdapterPosition()); } @@ -3599,7 +3621,7 @@ public class PostRecyclerViewAdapter extends PagingDataAdapter { if (mLongPressPostMediaAction.equals(SharedPreferencesUtils.LONG_PRESS_POST_VALUE_SHOW_POST_OPTIONS)) { - showPostOptions(); + showPostOptions(-1); return true; } else if (mLongPressPostMediaAction.equals(SharedPreferencesUtils.LONG_PRESS_POST_VALUE_PREVIEW_IN_FULLSCREEN)) { markPostRead(post, true); @@ -3721,8 +3743,13 @@ public class PostRecyclerViewAdapter extends PagingDataAdapter= longClickThreshold) { + View itemView = galleryRecyclerView.findChildViewUnder(e.getX(), e.getY()); + int currentItemPosition = -1; + if (itemView != null) { + currentItemPosition = galleryRecyclerView.getChildAdapterPosition(itemView); + } if (mLongPressPostMediaAction.equals(SharedPreferencesUtils.LONG_PRESS_POST_VALUE_SHOW_POST_OPTIONS)) { galleryRecyclerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - showPostOptions(); + showPostOptions(currentItemPosition); longPressed = true; } else if (mLongPressPostMediaAction.equals(SharedPreferencesUtils.LONG_PRESS_POST_VALUE_PREVIEW_IN_FULLSCREEN)) { galleryRecyclerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); markPostRead(post, true); - openMedia(post, layoutManager.findFirstVisibleItemPosition(), true); + openMedia(post, currentItemPosition, true); longPressed = true; } } @@ -3799,7 +3835,12 @@ public class PostRecyclerViewAdapter extends PagingDataAdapter= 0) { if (post != null) { markPostRead(post, true); - openMedia(post, layoutManager.findFirstVisibleItemPosition(), false); + View itemView = galleryRecyclerView.findChildViewUnder(e.getX(), e.getY()); + int currentItemPosition = -1; + if (itemView != null) { + currentItemPosition = galleryRecyclerView.getChildAdapterPosition(itemView); + } + openMedia(post, Math.max(currentItemPosition, 0), false); } } } @@ -3847,11 +3888,11 @@ public class PostRecyclerViewAdapter extends PagingDataAdapter { if (mLongPressPostMediaAction.equals(SharedPreferencesUtils.LONG_PRESS_POST_VALUE_SHOW_POST_OPTIONS)) { - showPostOptions(); + showPostOptions(-1); return true; } else if (mLongPressPostMediaAction.equals(SharedPreferencesUtils.LONG_PRESS_POST_VALUE_PREVIEW_IN_FULLSCREEN)) { markPostRead(post, true); - openMedia(post, layoutManager.findFirstVisibleItemPosition(), true); + openMedia(post, true); return true; } return false; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/PostOptionsBottomSheetFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/PostOptionsBottomSheetFragment.java index d70bf5f3..6ff9c457 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/PostOptionsBottomSheetFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/PostOptionsBottomSheetFragment.java @@ -123,8 +123,10 @@ public class PostOptionsBottomSheetFragment extends LandscapeExpandedRoundedBott switch (mPost.getPostType()) { case Post.IMAGE_TYPE: case Post.GALLERY_TYPE: - binding.downloadTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE); - binding.downloadTextViewPostOptionsBottomSheetFragment.setText(R.string.download_image); + if (getArguments().getInt(EXTRA_GALLERY_INDEX, -1) >= 0) { + binding.downloadTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE); + binding.downloadTextViewPostOptionsBottomSheetFragment.setText(R.string.download_image); + } break; case Post.GIF_TYPE: binding.downloadTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragmentBase.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragmentBase.java index a53cb225..4f2775bc 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragmentBase.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragmentBase.java @@ -996,7 +996,7 @@ public abstract class PostFragmentBase extends Fragment { protected static class StaggeredGridLayoutManagerItemOffsetDecoration extends RecyclerView.ItemDecoration { private final int mHalfOffset; - private final int mQuaterOffset; + private final int mQuarterOffset; private final int mCard3HorizontalSpace; private final int mCard3VerticalSpace; private final int mNColumns; @@ -1006,7 +1006,7 @@ public abstract class PostFragmentBase extends Fragment { mCard3HorizontalSpace = -itemOffset / 4 * 3; mCard3VerticalSpace = -itemOffset / 4; mHalfOffset = itemOffset / 2; - mQuaterOffset = itemOffset / 4; + mQuarterOffset = itemOffset / 4; } StaggeredGridLayoutManagerItemOffsetDecoration(@NonNull Context context, @DimenRes int itemOffsetId, int nColumns) { @@ -1051,17 +1051,17 @@ public abstract class PostFragmentBase extends Fragment { if (mNColumns == 2) { if (spanIndex == 0) { - outRect.set(mHalfOffset, 0, mQuaterOffset, 0); + outRect.set(mHalfOffset, 0, mQuarterOffset, 0); } else { - outRect.set(mQuaterOffset, 0, mHalfOffset, 0); + outRect.set(mQuarterOffset, 0, mHalfOffset, 0); } } else if (mNColumns == 3) { if (spanIndex == 0) { - outRect.set(mHalfOffset, 0, mQuaterOffset, 0); + outRect.set(mHalfOffset, 0, mQuarterOffset, 0); } else if (spanIndex == 1) { - outRect.set(mQuaterOffset, 0, mQuaterOffset, 0); + outRect.set(mQuarterOffset, 0, mQuarterOffset, 0); } else { - outRect.set(mQuaterOffset, 0, mHalfOffset, 0); + outRect.set(mQuarterOffset, 0, mHalfOffset, 0); } } }