From 852282bbfaafb72cc5a0b57eb6beceb491f32919 Mon Sep 17 00:00:00 2001 From: Jarvis Lin Date: Fri, 7 Jun 2024 11:40:42 +0200 Subject: [PATCH 1/4] Add the implementation of trash action --- .../ui/comments/CommentDetailViewModel.kt | 12 +++--- .../comments/SharedCommentDetailFragment.kt | 17 ++++++++- WordPress/src/main/res/drawable/trash_24.xml | 9 +++++ .../res/layout/comment_detail_fragment.xml | 7 ++++ .../src/main/res/layout/comment_trash.xml | 38 +++++++++++++++++++ WordPress/src/main/res/values/strings.xml | 2 + 6 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 WordPress/src/main/res/drawable/trash_24.xml create mode 100644 WordPress/src/main/res/layout/comment_trash.xml diff --git a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt index 4fd4ad0d4de0..44eac8b22ee1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt @@ -57,15 +57,17 @@ class CommentDetailViewModel @Inject constructor( } /** - * Dispatch a moderation action to the server, it does not include [CommentStatus.DELETED] status + * Dispatch a moderation action to the server */ fun dispatchModerationAction(site: SiteModel, comment: CommentModel, status: CommentStatus) { - commentsStoreAdapter.dispatch( + comment.apply { this.status = status.toString() } + if (status == CommentStatus.DELETED) { + CommentActionBuilder.newDeleteCommentAction(CommentStore.RemoteCommentPayload(site, comment)) + } else { CommentActionBuilder.newPushCommentAction(CommentStore.RemoteCommentPayload(site, comment)) - ) + } - comment.apply { this.status = status.toString() } - .let { _updatedComment.postValue(it) } + _updatedComment.postValue(comment) } /** diff --git a/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt index 4e6e61b5c192..cf9f4de175f7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt @@ -16,6 +16,7 @@ import org.wordpress.android.R import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.databinding.CommentApprovedBinding import org.wordpress.android.databinding.CommentPendingBinding +import org.wordpress.android.databinding.CommentTrashBinding import org.wordpress.android.fluxc.model.CommentModel import org.wordpress.android.fluxc.model.CommentStatus import org.wordpress.android.fluxc.model.SiteModel @@ -79,13 +80,14 @@ abstract class SharedCommentDetailFragment : CommentDetailFragment() { // reset visibilities mBinding?.layoutCommentPending?.root?.isVisible = false mBinding?.layoutCommentApproved?.root?.isVisible = false + mBinding?.layoutCommentTrash?.root?.isVisible = false val commentStatus = CommentStatus.fromString(comment.status) when (commentStatus) { CommentStatus.APPROVED -> mBinding?.layoutCommentApproved?.bindApprovedView() CommentStatus.UNAPPROVED -> mBinding?.layoutCommentPending?.bindPendingView() CommentStatus.SPAM -> {} - CommentStatus.TRASH -> {} + CommentStatus.TRASH -> mBinding?.layoutCommentTrash?.bindTrashView() CommentStatus.DELETED -> {} CommentStatus.ALL -> {} CommentStatus.UNREPLIED -> {} @@ -94,6 +96,17 @@ abstract class SharedCommentDetailFragment : CommentDetailFragment() { } } + private fun CommentTrashBinding.bindTrashView() { + root.isVisible = true + buttonDeleteTrash.setOnClickListener { + viewModel.dispatchModerationAction( + site, + comment, + CommentStatus.DELETED + ) + } + } + private fun CommentPendingBinding.bindPendingView() { root.isVisible = true buttonApproveComment.setOnClickListener { @@ -169,6 +182,8 @@ abstract class SharedCommentDetailFragment : CommentDetailFragment() { ) ).apply { onApprovedClicked = { viewModel.dispatchModerationAction(site, comment, CommentStatus.APPROVED) } + onPendingClicked = { viewModel.dispatchModerationAction(site, comment, CommentStatus.UNAPPROVED) } + onTrashClicked = { viewModel.dispatchModerationAction(site, comment, CommentStatus.TRASH) } }.show(childFragmentManager, ModerationBottomSheetDialogFragment.TAG) } } diff --git a/WordPress/src/main/res/drawable/trash_24.xml b/WordPress/src/main/res/drawable/trash_24.xml new file mode 100644 index 000000000000..1608306c67d6 --- /dev/null +++ b/WordPress/src/main/res/drawable/trash_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/WordPress/src/main/res/layout/comment_detail_fragment.xml b/WordPress/src/main/res/layout/comment_detail_fragment.xml index 282733f2f9ab..e26ec29c670f 100644 --- a/WordPress/src/main/res/layout/comment_detail_fragment.xml +++ b/WordPress/src/main/res/layout/comment_detail_fragment.xml @@ -31,6 +31,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="gone"/> + + + + + + + + + + diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index c3eb0cd2d39e..2a3f1524f47d 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -465,8 +465,10 @@ Change status Comment pending moderation + Comment in Trash Comment Approved Approve comment + Delete permanently More options Choose status Approved From d537c35cc9dd7a2991a4720d663b2e73d1660624 Mon Sep 17 00:00:00 2001 From: Jarvis Lin Date: Fri, 7 Jun 2024 16:14:46 +0200 Subject: [PATCH 2/4] Fix the flow of dispatching moderation actions --- .../ui/comments/CommentDetailFragment.java | 2 +- .../ui/comments/CommentDetailViewModel.kt | 12 ++++---- .../comments/SharedCommentDetailFragment.kt | 30 +++++++++++-------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailFragment.java index 7d9856428fcc..3a387a3f3b8a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailFragment.java @@ -655,7 +655,7 @@ private void trackModerationEvent(final CommentStatus newStatus) { /* * approve, disapprove, spam, or trash the current comment */ - private void moderateComment( + protected void moderateComment( @NonNull SiteModel site, @NonNull CommentModel comment, @Nullable Note note, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt index 44eac8b22ee1..7024ea3d327e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt @@ -61,11 +61,13 @@ class CommentDetailViewModel @Inject constructor( */ fun dispatchModerationAction(site: SiteModel, comment: CommentModel, status: CommentStatus) { comment.apply { this.status = status.toString() } - if (status == CommentStatus.DELETED) { - CommentActionBuilder.newDeleteCommentAction(CommentStore.RemoteCommentPayload(site, comment)) - } else { - CommentActionBuilder.newPushCommentAction(CommentStore.RemoteCommentPayload(site, comment)) - } + commentsStoreAdapter.dispatch( + if (status == CommentStatus.DELETED) { + CommentActionBuilder.newDeleteCommentAction(CommentStore.RemoteCommentPayload(site, comment)) + } else { + CommentActionBuilder.newPushCommentAction(CommentStore.RemoteCommentPayload(site, comment)) + } + ) _updatedComment.postValue(comment) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt index cf9f4de175f7..26270ae14f65 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt @@ -8,6 +8,7 @@ import android.widget.TextView import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.fragment.app.viewModels +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.gravatar.AvatarQueryOptions import com.gravatar.AvatarUrl import com.gravatar.types.Email @@ -99,22 +100,25 @@ abstract class SharedCommentDetailFragment : CommentDetailFragment() { private fun CommentTrashBinding.bindTrashView() { root.isVisible = true buttonDeleteTrash.setOnClickListener { - viewModel.dispatchModerationAction( - site, - comment, - CommentStatus.DELETED - ) + showDeleteCommentDialog() } } + private fun showDeleteCommentDialog() { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.delete) + .setMessage(R.string.dlg_sure_to_delete_comment) + .setPositiveButton(R.string.yes) { _, _ -> + moderateComment(site, comment, mNote, CommentStatus.DELETED) + } + .setNegativeButton(R.string.no) { _, _ -> } + .show() + } + private fun CommentPendingBinding.bindPendingView() { root.isVisible = true buttonApproveComment.setOnClickListener { - viewModel.dispatchModerationAction( - site, - comment, - CommentStatus.APPROVED - ) + moderateComment(site, comment, mNote, CommentStatus.APPROVED) } textMoreOptions.setOnClickListener { showModerationBottomSheet() } } @@ -181,9 +185,9 @@ abstract class SharedCommentDetailFragment : CommentDetailFragment() { canTrash = enabledActions.canTrash(), ) ).apply { - onApprovedClicked = { viewModel.dispatchModerationAction(site, comment, CommentStatus.APPROVED) } - onPendingClicked = { viewModel.dispatchModerationAction(site, comment, CommentStatus.UNAPPROVED) } - onTrashClicked = { viewModel.dispatchModerationAction(site, comment, CommentStatus.TRASH) } + onApprovedClicked = { moderateComment(site, comment, mNote, CommentStatus.APPROVED) } + onPendingClicked = { moderateComment(site, comment, mNote, CommentStatus.UNAPPROVED) } + onTrashClicked = { moderateComment(site, comment, mNote, CommentStatus.TRASH) } }.show(childFragmentManager, ModerationBottomSheetDialogFragment.TAG) } } From 1735251b2e5c058b2f01a01922ca24ff44503058 Mon Sep 17 00:00:00 2001 From: Jarvis Lin Date: Fri, 7 Jun 2024 17:17:19 +0200 Subject: [PATCH 3/4] Handle spam action --- .../ui/comments/SharedCommentDetailFragment.kt | 18 ++++++++++-------- .../src/main/res/layout/comment_trash.xml | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt index 26270ae14f65..219e737399ce 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/comments/SharedCommentDetailFragment.kt @@ -87,19 +87,20 @@ abstract class SharedCommentDetailFragment : CommentDetailFragment() { when (commentStatus) { CommentStatus.APPROVED -> mBinding?.layoutCommentApproved?.bindApprovedView() CommentStatus.UNAPPROVED -> mBinding?.layoutCommentPending?.bindPendingView() - CommentStatus.SPAM -> {} - CommentStatus.TRASH -> mBinding?.layoutCommentTrash?.bindTrashView() - CommentStatus.DELETED -> {} - CommentStatus.ALL -> {} - CommentStatus.UNREPLIED -> {} - CommentStatus.UNSPAM -> {} - CommentStatus.UNTRASH -> {} + CommentStatus.SPAM, CommentStatus.TRASH -> mBinding?.layoutCommentTrash?.bindTrashView() + CommentStatus.DELETED, + CommentStatus.ALL, + CommentStatus.UNREPLIED, + CommentStatus.UNSPAM, + CommentStatus.UNTRASH -> { + // do nothing + } } } private fun CommentTrashBinding.bindTrashView() { root.isVisible = true - buttonDeleteTrash.setOnClickListener { + buttonDeleteComment.setOnClickListener { showDeleteCommentDialog() } } @@ -188,6 +189,7 @@ abstract class SharedCommentDetailFragment : CommentDetailFragment() { onApprovedClicked = { moderateComment(site, comment, mNote, CommentStatus.APPROVED) } onPendingClicked = { moderateComment(site, comment, mNote, CommentStatus.UNAPPROVED) } onTrashClicked = { moderateComment(site, comment, mNote, CommentStatus.TRASH) } + onSpamClicked = { moderateComment(site, comment, mNote, CommentStatus.SPAM) } }.show(childFragmentManager, ModerationBottomSheetDialogFragment.TAG) } } diff --git a/WordPress/src/main/res/layout/comment_trash.xml b/WordPress/src/main/res/layout/comment_trash.xml index 20583a6f9d53..24488d918a64 100644 --- a/WordPress/src/main/res/layout/comment_trash.xml +++ b/WordPress/src/main/res/layout/comment_trash.xml @@ -24,7 +24,7 @@ android:textSize="@dimen/text_sz_small" /> Date: Mon, 10 Jun 2024 17:35:56 +0200 Subject: [PATCH 4/4] Make some refactors --- .../ui/comments/CommentDetailFragment.java | 26 ++++--------------- .../ui/comments/CommentDetailViewModel.kt | 2 ++ .../NotificationsDetailActivity.java | 5 +++- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailFragment.java index 3a387a3f3b8a..e0402ce91640 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailFragment.java @@ -14,6 +14,7 @@ import androidx.core.content.res.ResourcesCompat; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.ViewModelProvider; import com.gravatar.AvatarQueryOptions; import com.gravatar.AvatarUrl; @@ -138,6 +139,8 @@ public abstract class CommentDetailFragment extends ViewPagerFragment implements @Nullable protected CommentDetailFragmentBinding mBinding = null; + private CommentDetailViewModel mViewModel; + private final OnActionClickListener mOnActionClickListener = new OnActionClickListener() { @Override public void onEditCommentClicked() { editComment(); @@ -168,7 +171,7 @@ public abstract class CommentDetailFragment extends ViewPagerFragment implements public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ((WordPress) requireActivity().getApplication()).component().inject(this); - + mViewModel = new ViewModelProvider(this).get(CommentDetailViewModel.class); mCommentSource = (CommentSource) requireArguments().getSerializable(KEY_MODE); setHasOptionsMenu(true); } @@ -687,7 +690,7 @@ protected void moderateComment( // Fire the appropriate listener if we have one if (note != null && mOnNoteCommentActionListener != null) { mOnNoteCommentActionListener.onModerateCommentForNote(note, newStatus); - dispatchModerationAction(site, comment, newStatus); + mViewModel.dispatchModerationAction(site, comment, newStatus); } else if (mOnCommentActionListener != null) { mOnCommentActionListener.onModerateComment(comment, newStatus); // Sad, but onModerateComment does the moderation itself (due to the undo bar), this should be refactored, @@ -695,25 +698,6 @@ protected void moderateComment( } } - private void dispatchModerationAction( - @NonNull SiteModel site, - @NonNull CommentModel comment, - CommentStatus newStatus - ) { - if (newStatus == CommentStatus.DELETED) { - // For deletion, we need to dispatch a specific action. - mCommentsStoreAdapter.dispatch( - CommentActionBuilder.newDeleteCommentAction(new RemoteCommentPayload(site, comment)) - ); - } else { - // Actual moderation (push the modified comment). - comment.setStatus(newStatus.toString()); - mCommentsStoreAdapter.dispatch( - CommentActionBuilder.newPushCommentAction(new RemoteCommentPayload(site, comment)) - ); - } - } - /* * display the comment associated with the passed notification */ diff --git a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt index 7024ea3d327e..70d5c45b04e8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/comments/CommentDetailViewModel.kt @@ -63,8 +63,10 @@ class CommentDetailViewModel @Inject constructor( comment.apply { this.status = status.toString() } commentsStoreAdapter.dispatch( if (status == CommentStatus.DELETED) { + // For deletion, we need to dispatch a specific action. CommentActionBuilder.newDeleteCommentAction(CommentStore.RemoteCommentPayload(site, comment)) } else { + // Actual moderation (push the modified comment). CommentActionBuilder.newPushCommentAction(CommentStore.RemoteCommentPayload(site, comment)) } ) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java index 8cc91abeb3e2..c95c62b91051 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java @@ -568,7 +568,10 @@ public void onModerateCommentForNote(@NonNull Note note, @NonNull CommentStatus resultIntent.putExtra(NotificationsListFragment.NOTE_MODERATE_STATUS_EXTRA, newStatus.toString()); setResult(RESULT_OK, resultIntent); - finish(); + + if (newStatus == CommentStatus.DELETED) { + finish(); + } } @SuppressWarnings("unused")