Prepare to add moderation tools for comments. Rename ModerationActionBottomSheetFragment to PostModerationActionBottomSheetFragment.

This commit is contained in:
Docile-Alligator 2025-07-28 23:43:34 -04:00
parent b3cbe38b57
commit 37fe4eb551
13 changed files with 279 additions and 14 deletions

View File

@ -0,0 +1,9 @@
package ml.docilealligator.infinityforreddit
import ml.docilealligator.infinityforreddit.comment.Comment
interface CommentModerationActionHandler {
fun approveComment(comment: Comment, position: Int)
fun removeComment(comment: Comment, position: Int, isSpam: Boolean)
fun toggleLock(comment: Comment, position: Int)
}

View File

@ -34,6 +34,7 @@ import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.core.MarkwonTheme;
import ml.docilealligator.infinityforreddit.NetworkState;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.fragments.CommentsListingFragment;
import ml.docilealligator.infinityforreddit.thing.SaveThing;
import ml.docilealligator.infinityforreddit.thing.VoteThing;
import ml.docilealligator.infinityforreddit.account.Account;
@ -82,6 +83,7 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment
}
};
private final BaseActivity mActivity;
private final CommentsListingFragment mFragment;
private final Retrofit mOauthRetrofit;
private final Locale mLocale;
private final EmoteCloseBracketInlineProcessor mEmoteCloseBracketInlineProcessor;
@ -114,13 +116,15 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment
private NetworkState networkState;
private final RetryLoadingMoreCallback mRetryLoadingMoreCallback;
public CommentsListingRecyclerViewAdapter(BaseActivity activity, Retrofit oauthRetrofit,
public CommentsListingRecyclerViewAdapter(BaseActivity activity, CommentsListingFragment fragment,
Retrofit oauthRetrofit,
CustomThemeWrapper customThemeWrapper, Locale locale,
SharedPreferences sharedPreferences, String accessToken,
@NonNull String accountName, String username,
RetryLoadingMoreCallback retryLoadingMoreCallback) {
super(DIFF_CALLBACK);
mActivity = activity;
mFragment = fragment;
mOauthRetrofit = oauthRetrofit;
mCommentColor = customThemeWrapper.getCommentColor();
int commentSpoilerBackgroundColor = mCommentColor | 0xFF000000;
@ -550,7 +554,7 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment
bundle.putInt(CommentMoreBottomSheetFragment.EXTRA_POSITION, getBindingAdapterPosition());
CommentMoreBottomSheetFragment commentMoreBottomSheetFragment = new CommentMoreBottomSheetFragment();
commentMoreBottomSheetFragment.setArguments(bundle);
commentMoreBottomSheetFragment.show(mActivity.getSupportFragmentManager(), commentMoreBottomSheetFragment.getTag());
commentMoreBottomSheetFragment.show(mFragment.getChildFragmentManager(), commentMoreBottomSheetFragment.getTag());
}
});

View File

@ -1482,7 +1482,7 @@ public class CommentsRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerVi
}
CommentMoreBottomSheetFragment commentMoreBottomSheetFragment = new CommentMoreBottomSheetFragment();
commentMoreBottomSheetFragment.setArguments(bundle);
commentMoreBottomSheetFragment.show(mActivity.getSupportFragmentManager(), commentMoreBottomSheetFragment.getTag());
commentMoreBottomSheetFragment.show(mFragment.getChildFragmentManager(), commentMoreBottomSheetFragment.getTag());
}
});

View File

@ -0,0 +1,88 @@
package ml.docilealligator.infinityforreddit.bottomsheetfragments
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.content.res.AppCompatResources
import ml.docilealligator.infinityforreddit.CommentModerationActionHandler
import ml.docilealligator.infinityforreddit.R
import ml.docilealligator.infinityforreddit.comment.Comment
import ml.docilealligator.infinityforreddit.customviews.LandscapeExpandedRoundedBottomSheetDialogFragment
import ml.docilealligator.infinityforreddit.databinding.FragmentCommentModerationActionBottomSheetBinding
private const val EXTRA_COMMENT = "EP"
private const val EXTRA_POSITION = "EPO"
/**
* A simple [Fragment] subclass.
* Use the [CommentModerationActionBottomSheetFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class CommentModerationActionBottomSheetFragment : LandscapeExpandedRoundedBottomSheetDialogFragment() {
private var comment: Comment? = null
private var position: Int = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
comment = it.getParcelable(EXTRA_COMMENT)
position = it.getInt(EXTRA_POSITION)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
val binding = FragmentCommentModerationActionBottomSheetBinding.inflate(
inflater,
container,
false
)
comment?.let { comment ->
binding.approveTextViewCommentModerationActionBottomSheetFragment.setOnClickListener {
(parentFragment as CommentModerationActionHandler).approveComment(comment, position)
dismiss()
}
binding.removeTextViewCommentModerationActionBottomSheetFragment.setOnClickListener {
(parentFragment as CommentModerationActionHandler).removeComment(comment, position, false)
dismiss()
}
binding.spamTextViewCommentModerationActionBottomSheetFragment.setOnClickListener {
(parentFragment as CommentModerationActionHandler).removeComment(comment, position, true)
dismiss()
}
activity?.let {
binding.toggleLockTextViewCommentModerationActionBottomSheetFragment.setCompoundDrawablesWithIntrinsicBounds(
AppCompatResources.getDrawable(it, if (comment.isLocked) R.drawable.ic_unlock_24dp else R.drawable.ic_lock_day_night_24dp), null, null, null
)
}
binding.toggleLockTextViewCommentModerationActionBottomSheetFragment.setText(if (comment.isLocked) R.string.unlock else R.string.lock)
binding.toggleLockTextViewCommentModerationActionBottomSheetFragment.setOnClickListener {
(parentFragment as CommentModerationActionHandler).toggleLock(comment, position)
dismiss()
}
}
return binding.root
}
companion object {
@JvmStatic
fun newInstance(comment: Comment, position: Int) =
CommentModerationActionBottomSheetFragment().apply {
arguments = Bundle().apply {
putParcelable(EXTRA_COMMENT, comment)
putInt(EXTRA_POSITION, position)
}
}
}
}

View File

@ -212,6 +212,20 @@ public class CommentMoreBottomSheetFragment extends LandscapeExpandedRoundedBott
});
}
if (comment.isCanModComment()) {
binding.modCommentMoreBottomSheetFragment.setVisibility(View.VISIBLE);
binding.modCommentMoreBottomSheetFragment.setOnClickListener(view -> {
CommentModerationActionBottomSheetFragment commentModerationActionBottomSheetFragment = CommentModerationActionBottomSheetFragment.newInstance(comment, bundle.getInt(EXTRA_POSITION));
Fragment parentFragment = getParentFragment();
if (parentFragment != null) {
commentModerationActionBottomSheetFragment.show(parentFragment.getChildFragmentManager(), commentModerationActionBottomSheetFragment.getTag());
} else {
commentModerationActionBottomSheetFragment.show(activity.getSupportFragmentManager(), commentModerationActionBottomSheetFragment.getTag());
}
dismiss();
});
}
if (activity.typeface != null) {
Utils.setFontToAllTextViews(binding.getRoot(), activity.typeface);
}

View File

@ -11,7 +11,6 @@ import ml.docilealligator.infinityforreddit.R
import ml.docilealligator.infinityforreddit.customviews.LandscapeExpandedRoundedBottomSheetDialogFragment
import ml.docilealligator.infinityforreddit.databinding.FragmentModerationActionBottomSheetBinding
import ml.docilealligator.infinityforreddit.post.Post
import org.checkerframework.checker.units.qual.A
private const val EXTRA_POST = "EP"
@ -19,10 +18,10 @@ private const val EXTRA_POSITION = "EPO"
/**
* A simple [Fragment] subclass.
* Use the [ModerationActionBottomSheetFragment.newInstance] factory method to
* Use the [PostModerationActionBottomSheetFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class ModerationActionBottomSheetFragment : LandscapeExpandedRoundedBottomSheetDialogFragment() {
class PostModerationActionBottomSheetFragment : LandscapeExpandedRoundedBottomSheetDialogFragment() {
private var post: Post? = null
private var position: Int = -1
@ -113,7 +112,7 @@ class ModerationActionBottomSheetFragment : LandscapeExpandedRoundedBottomSheetD
companion object {
@JvmStatic
fun newInstance(post: Post, position: Int) =
ModerationActionBottomSheetFragment().apply {
PostModerationActionBottomSheetFragment().apply {
arguments = Bundle().apply {
putParcelable(EXTRA_POST, post)
putInt(EXTRA_POSITION, position)

View File

@ -34,6 +34,7 @@ import ml.docilealligator.infinityforreddit.post.HidePost;
import ml.docilealligator.infinityforreddit.post.Post;
import ml.docilealligator.infinityforreddit.services.DownloadMediaService;
import ml.docilealligator.infinityforreddit.services.DownloadRedditVideoService;
import ml.docilealligator.infinityforreddit.utils.Utils;
import retrofit2.Retrofit;
/**
@ -280,12 +281,12 @@ public class PostOptionsBottomSheetFragment extends LandscapeExpandedRoundedBott
if (mPost.isCanModPost()) {
binding.modTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE);
binding.modTextViewPostOptionsBottomSheetFragment.setOnClickListener(view -> {
ModerationActionBottomSheetFragment moderationActionBottomSheetFragment = ModerationActionBottomSheetFragment.newInstance(mPost, getArguments().getInt(EXTRA_POST_LIST_POSITION, 0));
PostModerationActionBottomSheetFragment postModerationActionBottomSheetFragment = PostModerationActionBottomSheetFragment.newInstance(mPost, getArguments().getInt(EXTRA_POST_LIST_POSITION, 0));
Fragment parentFragment = getParentFragment();
if (parentFragment != null) {
moderationActionBottomSheetFragment.show(parentFragment.getChildFragmentManager(), moderationActionBottomSheetFragment.getTag());
postModerationActionBottomSheetFragment.show(parentFragment.getChildFragmentManager(), postModerationActionBottomSheetFragment.getTag());
} else {
moderationActionBottomSheetFragment.show(mBaseActivity.getSupportFragmentManager(), moderationActionBottomSheetFragment.getTag());
postModerationActionBottomSheetFragment.show(mBaseActivity.getSupportFragmentManager(), postModerationActionBottomSheetFragment.getTag());
}
dismiss();
});
@ -293,6 +294,10 @@ public class PostOptionsBottomSheetFragment extends LandscapeExpandedRoundedBott
}
}
if (mBaseActivity.typeface != null) {
Utils.setFontToAllTextViews(binding.getRoot(), mBaseActivity.typeface);
}
return binding.getRoot();
}

View File

@ -54,6 +54,8 @@ public class Comment implements Parcelable {
private boolean scoreHidden;
private boolean saved;
private boolean sendReplies;
private boolean locked;
private boolean canModComment;
private boolean isExpanded;
private boolean hasExpandedBefore;
private boolean isFilteredOut;
@ -71,7 +73,8 @@ public class Comment implements Parcelable {
String linkId, String subredditName, String parentId, int score,
int voteType, boolean isSubmitter, String distinguished, String permalink,
int depth, boolean collapsed, boolean hasReply,
boolean scoreHidden, boolean saved, boolean sendReplies, long edited, Map<String, MediaMetadata> mediaMetadataMap) {
boolean scoreHidden, boolean saved, boolean sendReplies, boolean locked, boolean canModComment,
long edited, Map<String, MediaMetadata> mediaMetadataMap) {
this.id = id;
this.fullName = fullName;
this.author = author;
@ -96,6 +99,8 @@ public class Comment implements Parcelable {
this.scoreHidden = scoreHidden;
this.saved = saved;
this.sendReplies = sendReplies;
this.locked = locked;
this.canModComment = canModComment;
this.isExpanded = false;
this.hasExpandedBefore = false;
this.editedTimeMillis = edited;
@ -147,6 +152,8 @@ public class Comment implements Parcelable {
scoreHidden = in.readByte() != 0;
saved = in.readByte() != 0;
sendReplies = in.readByte() != 0;
locked = in.readByte() != 0;
canModComment = in.readByte() != 0;
isExpanded = in.readByte() != 0;
hasExpandedBefore = in.readByte() != 0;
isFilteredOut = in.readByte() != 0;
@ -312,6 +319,18 @@ public class Comment implements Parcelable {
sendReplies = !sendReplies;
}
public boolean isLocked() {
return locked;
}
public void setLocked(boolean locked) {
this.locked = locked;
}
public boolean isCanModComment() {
return canModComment;
}
public boolean isExpanded() {
return isExpanded;
}
@ -470,6 +489,8 @@ public class Comment implements Parcelable {
parcel.writeByte((byte) (scoreHidden ? 1 : 0));
parcel.writeByte((byte) (saved ? 1 : 0));
parcel.writeByte((byte) (sendReplies ? 1 : 0));
parcel.writeByte((byte) (locked ? 1 : 0));
parcel.writeByte((byte) (canModComment ? 1 : 0));
parcel.writeByte((byte) (isExpanded ? 1 : 0));
parcel.writeByte((byte) (hasExpandedBefore ? 1 : 0));
parcel.writeByte((byte) (isFilteredOut ? 1 : 0));

View File

@ -311,6 +311,8 @@ public class ParseComment {
boolean scoreHidden = singleCommentData.getBoolean(JSONUtils.SCORE_HIDDEN_KEY);
boolean saved = singleCommentData.getBoolean(JSONUtils.SAVED_KEY);
boolean sendReplies = singleCommentData.getBoolean(JSONUtils.SEND_REPLIES_KEY);
boolean locked = singleCommentData.getBoolean(JSONUtils.LOCKED_KEY);
boolean canModComment = singleCommentData.getBoolean(JSONUtils.CAN_MOD_POST_KEY);
if (singleCommentData.has(JSONUtils.DEPTH_KEY)) {
depth = singleCommentData.getInt(JSONUtils.DEPTH_KEY);
@ -325,8 +327,8 @@ public class ParseComment {
return new Comment(id, fullName, author, authorFullname, authorFlair, authorFlairHTMLBuilder.toString(),
linkAuthor, submitTime, commentMarkdown, commentRawText,
linkId, subredditName, parentId, score, voteType, isSubmitter, distinguished,
permalink, depth, collapsed, hasReply, scoreHidden, saved, sendReplies, edited,
mediaMetadataMap);
permalink, depth, collapsed, hasReply, scoreHidden, saved, sendReplies, locked, canModComment,
edited, mediaMetadataMap);
}
@Nullable

View File

@ -281,7 +281,7 @@ public class CommentsListingFragment extends Fragment implements FragmentCommuni
sortType = new SortType(SortType.Type.valueOf(sort.toUpperCase()));
}
mAdapter = new CommentsListingRecyclerViewAdapter(mActivity, mOauthRetrofit, customThemeWrapper,
mAdapter = new CommentsListingRecyclerViewAdapter(mActivity, this, mOauthRetrofit, customThemeWrapper,
getResources().getConfiguration().locale, mSharedPreferences,
mActivity.accessToken, mActivity.accountName,
username, () -> mCommentViewModel.retryLoadingMore());

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
android:paddingBottom="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/approve_text_view_comment_moderation_action_bottom_sheet_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:drawableStart="@drawable/ic_approve_24dp"
android:drawablePadding="48dp"
android:focusable="true"
android:fontFamily="?attr/font_family"
android:paddingStart="32dp"
android:paddingTop="16dp"
android:paddingEnd="32dp"
android:paddingBottom="16dp"
android:text="@string/approve"
android:textColor="?attr/primaryTextColor"
android:textSize="?attr/font_default"
app:drawableTint="?attr/primaryTextColor" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/remove_text_view_comment_moderation_action_bottom_sheet_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:drawableStart="@drawable/ic_remove_24dp"
android:drawablePadding="48dp"
android:focusable="true"
android:fontFamily="?attr/font_family"
android:paddingStart="32dp"
android:paddingTop="16dp"
android:paddingEnd="32dp"
android:paddingBottom="16dp"
android:text="@string/remove"
android:textColor="?attr/primaryTextColor"
android:textSize="?attr/font_default"
app:drawableTint="?attr/primaryTextColor" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/spam_text_view_comment_moderation_action_bottom_sheet_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:drawableStart="@drawable/ic_spam_24dp"
android:drawablePadding="48dp"
android:focusable="true"
android:fontFamily="?attr/font_family"
android:paddingStart="32dp"
android:paddingTop="16dp"
android:paddingEnd="32dp"
android:paddingBottom="16dp"
android:text="@string/mark_as_spam"
android:textColor="?attr/primaryTextColor"
android:textSize="?attr/font_default"
app:drawableTint="?attr/primaryTextColor" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/toggle_lock_text_view_comment_moderation_action_bottom_sheet_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:drawablePadding="48dp"
android:focusable="true"
android:fontFamily="?attr/font_family"
android:paddingStart="32dp"
android:paddingTop="16dp"
android:paddingEnd="32dp"
android:paddingBottom="16dp"
android:textColor="?attr/primaryTextColor"
android:textSize="?attr/font_default"
app:drawableTint="?attr/primaryTextColor" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -224,6 +224,27 @@
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_keyboard_double_arrow_up_day_night_24dp" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/mod_comment_more_bottom_sheet_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:drawableStart="@drawable/ic_mod_24dp"
android:drawablePadding="48dp"
android:focusable="true"
android:fontFamily="?attr/font_family"
android:paddingStart="32dp"
android:paddingTop="16dp"
android:paddingEnd="32dp"
android:paddingBottom="16dp"
android:text="@string/moderation"
android:textColor="?attr/primaryTextColor"
android:textSize="?attr/font_default"
android:visibility="gone"
app:drawableTint="?attr/primaryTextColor" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -11,6 +11,10 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/approve_text_view_moderation_action_bottom_sheet_fragment"
android:layout_width="match_parent"