diff options
author | mzorz <mariozorz@gmail.com> | 2016-09-26 20:12:18 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-26 20:12:18 -0300 |
commit | 5221e927aa7745183693b6f5606506db042071a3 (patch) | |
tree | c33c9bf2aaa903a531142154830adc11e77cce8b | |
parent | 8726084f865537f8e11754b3b4f618ad4b4c5bef (diff) | |
parent | 4a8d269ca526ff3f261274a8535e53e8397fa0fe (diff) | |
download | gradle-perf-android-medium-5221e927aa7745183693b6f5606506db042071a3.tar.gz |
Merge pull request #4537 from wordpress-mobile/issue/4523-comment-pn-actions-context-aware
Issue/4523 comment pn actions context aware
7 files changed, 264 insertions, 45 deletions
diff --git a/WordPress/src/main/java/org/wordpress/android/GCMMessageService.java b/WordPress/src/main/java/org/wordpress/android/GCMMessageService.java index 06ee0e38f..de0e92aa9 100644 --- a/WordPress/src/main/java/org/wordpress/android/GCMMessageService.java +++ b/WordPress/src/main/java/org/wordpress/android/GCMMessageService.java @@ -16,12 +16,15 @@ import android.support.v4.util.ArrayMap; import android.text.TextUtils; import com.google.android.gms.gcm.GcmListenerService; +import com.simperium.client.BucketObjectMissingException; import org.apache.commons.lang.StringEscapeUtils; import org.wordpress.android.analytics.AnalyticsTracker; import org.wordpress.android.analytics.AnalyticsTracker.Stat; import org.wordpress.android.analytics.AnalyticsTrackerMixpanel; import org.wordpress.android.models.AccountHelper; +import org.wordpress.android.models.CommentStatus; +import org.wordpress.android.models.Note; import org.wordpress.android.ui.main.WPMainActivity; import org.wordpress.android.ui.notifications.NotificationDismissBroadcastReceiver; import org.wordpress.android.ui.notifications.NotificationEvents; @@ -70,6 +73,11 @@ public class GCMMessageService extends GcmListenerService { private static final String PUSH_TYPE_PUSH_AUTH = "push_auth"; private static final String PUSH_TYPE_BADGE_RESET = "badge-reset"; + private static final String KEY_CATEGORY_COMMENT_LIKE = "comment-like"; + private static final String KEY_CATEGORY_COMMENT_REPLY = "comment-reply"; + private static final String KEY_CATEGORY_COMMENT_MODERATE = "comment-moderate"; + + // Add to the analytics properties map a subset of the push notification payload. private static String[] propertiesToCopyIntoAnalytics = {PUSH_ARG_NOTE_ID, PUSH_ARG_TYPE, "blog_id", "post_id", "comment_id"}; @@ -207,13 +215,47 @@ public class GCMMessageService extends GcmListenerService { private void addActionsForCommentNotification(NotificationCompat.Builder builder, String noteId) { // Add some actions if this is a comment notification - Intent commentReplyIntent = new Intent(this, WPMainActivity.class); - commentReplyIntent.putExtra(WPMainActivity.ARG_OPENED_FROM_PUSH, true); - commentReplyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_CLEAR_TASK); - commentReplyIntent.setAction("android.intent.action.MAIN"); - commentReplyIntent.addCategory("android.intent.category.LAUNCHER"); - commentReplyIntent.addCategory("comment-reply"); + + boolean areActionsSet = false; + + if (SimperiumUtils.getNotesBucket() != null) { + try { + Note note = SimperiumUtils.getNotesBucket().get(noteId); + if (note != null) { + //if note can be replied to, we'll always add this action first + if (note.canReply()) { + addCommentReplyActionForCommentNotification(builder, noteId); + } + + // if the comment is lacking approval, offer moderation actions + if (note.getCommentStatus().equals(CommentStatus.UNAPPROVED)) { + if (note.canModerate()) { + addCommentApproveActionForCommentNotification(builder, noteId); + } + } else { + //else offer REPLY / LIKE actions + if (note.canLike()) { + addCommentLikeActionForCommentNotification(builder, noteId); + } + } + } + areActionsSet = true; + } catch (BucketObjectMissingException e) { + e.printStackTrace(); + } + } + + // if we could not set the actions, set the default ones REPLY / LIKE + if (!areActionsSet) { + addCommentReplyActionForCommentNotification(builder, noteId); + addCommentLikeActionForCommentNotification(builder, noteId); + } + } + + private void addCommentReplyActionForCommentNotification(NotificationCompat.Builder builder, String noteId) { + // adding comment reply action + Intent commentReplyIntent = getCommentActionIntent(); + commentReplyIntent.addCategory(KEY_CATEGORY_COMMENT_REPLY); commentReplyIntent.putExtra(NotificationsListFragment.NOTE_INSTANT_REPLY_EXTRA, true); if (noteId != null) { commentReplyIntent.putExtra(NotificationsListFragment.NOTE_ID_EXTRA, noteId); @@ -224,6 +266,44 @@ public class GCMMessageService extends GcmListenerService { commentReplyPendingIntent); } + private void addCommentLikeActionForCommentNotification(NotificationCompat.Builder builder, String noteId) { + // adding comment like action + Intent commentLikeIntent = getCommentActionIntent(); + commentLikeIntent.addCategory(KEY_CATEGORY_COMMENT_LIKE); + commentLikeIntent.putExtra(NotificationsListFragment.NOTE_INSTANT_LIKE_EXTRA, true); + if (noteId != null) { + commentLikeIntent.putExtra(NotificationsListFragment.NOTE_ID_EXTRA, noteId); + } + PendingIntent commentLikePendingIntent = PendingIntent.getActivity(this, 0, commentLikeIntent, + PendingIntent.FLAG_CANCEL_CURRENT); + builder.addAction(R.drawable.ic_action_like, getText(R.string.like), + commentLikePendingIntent); + } + + private void addCommentApproveActionForCommentNotification(NotificationCompat.Builder builder, String noteId) { + // adding comment approve action + Intent commentApproveIntent = getCommentActionIntent(); + commentApproveIntent.addCategory(KEY_CATEGORY_COMMENT_MODERATE); + commentApproveIntent.putExtra(NotificationsListFragment.NOTE_INSTANT_APPROVE_EXTRA, true); + if (noteId != null) { + commentApproveIntent.putExtra(NotificationsListFragment.NOTE_ID_EXTRA, noteId); + } + PendingIntent commentApprovePendingIntent = PendingIntent.getActivity(this, 0, commentApproveIntent, + PendingIntent.FLAG_CANCEL_CURRENT); + builder.addAction(R.drawable.ic_action_approve, getText(R.string.approve), + commentApprovePendingIntent); + } + + private Intent getCommentActionIntent(){ + Intent intent = new Intent(this, WPMainActivity.class); + intent.putExtra(WPMainActivity.ARG_OPENED_FROM_PUSH, true); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); + intent.setAction("android.intent.action.MAIN"); + intent.addCategory("android.intent.category.LAUNCHER"); + return intent; + } + private Bitmap getLargeIconBitmap(String iconUrl, boolean shouldCircularizeIcon){ Bitmap largeIconBitmap = null; if (iconUrl != null) { @@ -444,7 +524,7 @@ public class GCMMessageService extends GcmListenerService { return; } - removeNotificationWithNoteIdFromSystemBar(this, data); + removeNotificationWithNoteIdFromSystemBar(this, data.getString(PUSH_ARG_NOTE_ID, "")); //now that we cleared the specific notif, we can check and make any visual updates if (sActiveNotificationsMap.size() > 0) { rebuildAndUpdateNotificationsOnSystemBar(data); @@ -572,13 +652,8 @@ public class GCMMessageService extends GcmListenerService { } // Removes a specific notification from the system bar - public static synchronized void removeNotificationWithNoteIdFromSystemBar(Context context, Bundle data) { - if (context == null || data == null || !hasNotifications()) { - return; - } - - String noteID = data.getString(PUSH_ARG_NOTE_ID, ""); - if (TextUtils.isEmpty(noteID)) { + public static synchronized void removeNotificationWithNoteIdFromSystemBar(Context context, String noteID) { + if (context == null || TextUtils.isEmpty(noteID) || !hasNotifications()) { return; } diff --git a/WordPress/src/main/java/org/wordpress/android/models/Note.java b/WordPress/src/main/java/org/wordpress/android/models/Note.java index 78fe414d9..7dc1a463b 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/Note.java +++ b/WordPress/src/main/java/org/wordpress/android/models/Note.java @@ -148,6 +148,37 @@ public class Note extends Syncable { return isLikeType() || isCommentLikeType() || isFollowType() || isReblogType(); } + /* + * does user have permission to moderate/reply/spam this comment? + */ + public boolean canModerate() { + EnumSet<EnabledActions> enabledActions = getEnabledActions(); + return enabledActions != null && (enabledActions.contains(EnabledActions.ACTION_APPROVE) || enabledActions.contains(EnabledActions.ACTION_UNAPPROVE)); + } + + public boolean canMarkAsSpam() { + EnumSet<EnabledActions> enabledActions = getEnabledActions(); + return (enabledActions != null && enabledActions.contains(EnabledActions.ACTION_SPAM)); + } + + public boolean canReply() { + EnumSet<EnabledActions> enabledActions = getEnabledActions(); + return (enabledActions != null && enabledActions.contains(EnabledActions.ACTION_REPLY)); + } + + public boolean canTrash() { + return canModerate(); + } + + public boolean canEdit(int localBlogId) { + return (localBlogId > 0 && canModerate()); + } + + public boolean canLike() { + EnumSet<EnabledActions> enabledActions = getEnabledActions(); + return (enabledActions != null && enabledActions.contains(EnabledActions.ACTION_LIKE)); + } + private String getLocalStatus() { return StringUtils.notNullStr(mLocalStatus); } 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 e1a7b9eb0..eafe02723 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 @@ -112,10 +112,13 @@ public class CommentDetailFragment extends Fragment implements NotificationFragm private String mRestoredNoteId; private boolean mIsUsersBlog = false; private boolean mShouldFocusReplyField; + private boolean mShouldLikeInstantly; + private boolean mShouldApproveInstantly; + /* - * Used to request a comment from a note using its site and comment ids, rather than build - * the comment with the content in the note. See showComment() - */ + * Used to request a comment from a note using its site and comment ids, rather than build + * the comment with the content in the note. See showComment() + */ private boolean mShouldRequestCommentFromNote = false; private boolean mIsSubmittingReply = false; private NotificationsDetailListFragment mNotificationsDetailListFragment; @@ -149,6 +152,26 @@ public class CommentDetailFragment extends Fragment implements NotificationFragm } /* + * used when called from a comment notification 'like' action + */ + public static CommentDetailFragment newInstanceForInstantLike(final String noteId) { + CommentDetailFragment fragment = newInstance(noteId); + //here tell the fragment to trigger the Like action when ready + fragment.setLikeCommentWhenReady(); + return fragment; + } + + /* + * used when called from a comment notification 'approve' action + */ + public static CommentDetailFragment newInstanceForInstantApprove(final String noteId) { + CommentDetailFragment fragment = newInstance(noteId); + //here tell the fragment to trigger the Like action when ready + fragment.setApproveCommentWhenReady(); + return fragment; + } + + /* * used when called from notifications to load a comment that doesn't already exist in the note */ public static CommentDetailFragment newInstanceForRemoteNoteComment(final String noteId) { @@ -311,7 +334,7 @@ public class CommentDetailFragment extends Fragment implements NotificationFragm mBtnLikeComment.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - likeComment(); + likeComment(false); } }); @@ -330,6 +353,15 @@ public class CommentDetailFragment extends Fragment implements NotificationFragm setNoteWithNoteId(mRestoredNoteId); mRestoredNoteId = null; } + + if (mShouldLikeInstantly) { + mShouldLikeInstantly = false; + likeComment(true); + } else if (mShouldApproveInstantly) { + mShouldApproveInstantly = false; + performModerateAction(); + } + } private void setupSuggestionServiceAndAdapter() { @@ -776,7 +808,9 @@ public class CommentDetailFragment extends Fragment implements NotificationFragm public void onActionResult(CommentActionResult result) { if (!isAdded()) return; - if (!result.isSuccess()) { + if (result.isSuccess()) { + ToastUtils.showToast(getActivity(), R.string.comment_moderated_approved, ToastUtils.Duration.SHORT); + } else { mComment.setStatus(CommentStatus.toString(oldStatus)); updateStatusViews(); ToastUtils.showToast(getActivity(), R.string.error_moderate_comment); @@ -916,19 +950,7 @@ public class CommentDetailFragment extends Fragment implements NotificationFragm mBtnModerateComment.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (!hasComment() || !isAdded() || !NetworkUtils.checkConnection(getActivity())) { - return; - } - - CommentStatus newStatus = CommentStatus.APPROVED; - if (mComment.getStatusEnum() == CommentStatus.APPROVED) { - newStatus = CommentStatus.UNAPPROVED; - } - - mComment.setStatus(newStatus.toString()); - setModerateButtonForStatus(newStatus); - AniUtils.startAnimation(mBtnModerateIcon, R.anim.notifications_button_scale); - moderateComment(newStatus); + performModerateAction(); } }); mBtnModerateComment.setVisibility(View.VISIBLE); @@ -964,6 +986,22 @@ public class CommentDetailFragment extends Fragment implements NotificationFragm mLayoutButtons.setVisibility(View.VISIBLE); } + private void performModerateAction(){ + if (!hasComment() || !isAdded() || !NetworkUtils.checkConnection(getActivity())) { + return; + } + + CommentStatus newStatus = CommentStatus.APPROVED; + if (mComment.getStatusEnum() == CommentStatus.APPROVED) { + newStatus = CommentStatus.UNAPPROVED; + } + + mComment.setStatus(newStatus.toString()); + setModerateButtonForStatus(newStatus); + AniUtils.startAnimation(mBtnModerateIcon, R.anim.notifications_button_scale); + moderateComment(newStatus); + } + private void setModerateButtonForStatus(CommentStatus status) { if (status == CommentStatus.APPROVED) { mBtnModerateIcon.setImageResource(R.drawable.ic_action_approve_active); @@ -1058,9 +1096,19 @@ public class CommentDetailFragment extends Fragment implements NotificationFragm getFragmentManager().invalidateOptionsMenu(); } + private void setLikeCommentWhenReady() { + mShouldLikeInstantly = true; + } + + private void setApproveCommentWhenReady() { + mShouldApproveInstantly = true; + } + // Like or unlike a comment via the REST API - private void likeComment() { + private void likeComment(boolean forceLike) { if (mNote == null) return; + if (!isAdded()) return; + if (forceLike && mBtnLikeComment.isActivated()) return; toggleLikeButton(!mBtnLikeComment.isActivated()); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java index 0e41c200f..a29e624f1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java @@ -265,19 +265,29 @@ public class WPMainActivity extends AppCompatActivity implements Bucket.Listener mViewPager.setCurrentItem(WPMainTabAdapter.TAB_NOTIFS); - boolean shouldShowKeyboard = getIntent().getBooleanExtra(NotificationsListFragment.NOTE_INSTANT_REPLY_EXTRA, false); if (GCMMessageService.getNotificationsCount() == 1) { String noteId = getIntent().getStringExtra(NotificationsListFragment.NOTE_ID_EXTRA); if (!TextUtils.isEmpty(noteId)) { GCMMessageService.bumpPushNotificationsTappedAnalytics(noteId); - NotificationsListFragment.openNote(this, noteId, shouldShowKeyboard); + boolean doLikeNote = getIntent().getBooleanExtra(NotificationsListFragment.NOTE_INSTANT_LIKE_EXTRA, false); + if (doLikeNote) { + NotificationsListFragment.openNoteForLike(this, noteId); + } else { + boolean doApproveNote = getIntent().getBooleanExtra(NotificationsListFragment.NOTE_INSTANT_APPROVE_EXTRA, false); + if (doApproveNote) { + NotificationsListFragment.openNoteForApprove(this, noteId); + } else { + boolean shouldShowKeyboard = getIntent().getBooleanExtra(NotificationsListFragment.NOTE_INSTANT_REPLY_EXTRA, false); + NotificationsListFragment.openNoteForReply(this, noteId, shouldShowKeyboard); + } + } } } else { // mark all tapped here GCMMessageService.bumpPushNotificationsTappedAllAnalytics(); } - GCMMessageService.clearNotifications(); + GCMMessageService.removeAllNotifications(this); } @Override 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 4326e0ae6..408194613 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 @@ -90,6 +90,9 @@ public class NotificationsDetailActivity extends AppCompatActivity implements return; } } + + GCMMessageService.removeNotificationWithNoteIdFromSystemBar(this, noteId);//clearNotifications(); + } else if (savedInstanceState.containsKey(ARG_TITLE) && getSupportActionBar() != null) { getSupportActionBar().setTitle(StringUtils.notNullStr(savedInstanceState.getString(ARG_TITLE))); } @@ -99,7 +102,6 @@ public class NotificationsDetailActivity extends AppCompatActivity implements getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); } - GCMMessageService.clearNotifications(); } @Override @@ -138,7 +140,13 @@ public class NotificationsDetailActivity extends AppCompatActivity implements Fragment fragment; if (note.isCommentType()) { // show comment detail for comment notifications - fragment = CommentDetailFragment.newInstance(note.getId()); + boolean isInstantLike = getIntent().getBooleanExtra(NotificationsListFragment.NOTE_INSTANT_LIKE_EXTRA, false); + boolean isInstantApprove = getIntent().getBooleanExtra(NotificationsListFragment.NOTE_INSTANT_APPROVE_EXTRA, false); + fragment = isInstantLike ? + CommentDetailFragment.newInstanceForInstantLike(note.getId()) : + isInstantApprove ? + CommentDetailFragment.newInstanceForInstantApprove(note.getId()) : + CommentDetailFragment.newInstance(note.getId()); } else if (note.isAutomattcherType()) { // show reader post detail for automattchers about posts - note that comment // automattchers are handled by note.isCommentType() above diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListFragment.java index 716b52389..8ad48256c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListFragment.java @@ -40,6 +40,8 @@ public class NotificationsListFragment extends Fragment WPMainActivity.OnScrollToTopListener, RadioGroup.OnCheckedChangeListener { public static final String NOTE_ID_EXTRA = "noteId"; public static final String NOTE_INSTANT_REPLY_EXTRA = "instantReply"; + public static final String NOTE_INSTANT_LIKE_EXTRA = "instantLike"; + public static final String NOTE_INSTANT_APPROVE_EXTRA = "instantApprove"; public static final String NOTE_MODERATE_ID_EXTRA = "moderateNoteId"; public static final String NOTE_MODERATE_STATUS_EXTRA = "moderateNoteStatus"; @@ -175,16 +177,23 @@ public class NotificationsListFragment extends Fragment // open the latest version of this note just in case it has changed - this can // happen if the note was tapped from the list fragment after it was updated // by another fragment (such as NotificationCommentLikeFragment) - openNote(getActivity(), noteId, false); + openNoteForReply(getActivity(), noteId, false); } }; + private static Intent getOpenNoteIntent(Activity activity, + String noteId) { + Intent detailIntent = new Intent(activity, NotificationsDetailActivity.class); + detailIntent.putExtra(NOTE_ID_EXTRA, noteId); + return detailIntent; + } + /** * Open a note fragment based on the type of note */ - public static void openNote(Activity activity, - String noteId, - boolean shouldShowKeyboard) { + public static void openNoteForReply(Activity activity, + String noteId, + boolean shouldShowKeyboard) { if (noteId == null || activity == null) { return; } @@ -193,12 +202,47 @@ public class NotificationsListFragment extends Fragment return; } - Intent detailIntent = new Intent(activity, NotificationsDetailActivity.class); - detailIntent.putExtra(NOTE_ID_EXTRA, noteId); + Intent detailIntent = getOpenNoteIntent(activity, noteId); detailIntent.putExtra(NOTE_INSTANT_REPLY_EXTRA, shouldShowKeyboard); activity.startActivityForResult(detailIntent, RequestCodes.NOTE_DETAIL); } + /** + * Open a note fragment based on the type of note, signaling to issue a like action immediately + */ + public static void openNoteForLike(Activity activity, + String noteId) { + if (noteId == null || activity == null) { + return; + } + + if (activity.isFinishing()) { + return; + } + + Intent detailIntent = getOpenNoteIntent(activity, noteId); + detailIntent.putExtra(NOTE_INSTANT_LIKE_EXTRA, true); + activity.startActivityForResult(detailIntent, RequestCodes.NOTE_DETAIL); + } + + /** + * Open a note fragment based on the type of note, signaling to issue a moderate:approve action immediately + */ + public static void openNoteForApprove(Activity activity, + String noteId) { + if (noteId == null || activity == null) { + return; + } + + if (activity.isFinishing()) { + return; + } + + Intent detailIntent = getOpenNoteIntent(activity, noteId); + detailIntent.putExtra(NOTE_INSTANT_APPROVE_EXTRA, true); + activity.startActivityForResult(detailIntent, RequestCodes.NOTE_DETAIL); + } + private void setNoteIsHidden(String noteId, boolean isHidden) { if (mNotesAdapter == null) return; diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index dd335a5a3..b56572cbd 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -324,6 +324,9 @@ <!-- comment actions --> <string name="reply">Reply</string> <string name="trash">Trash</string> + <string name="like">Like</string> + <string name="approve">Approve</string> + <string name="comment_moderated_approved">Comment approved!</string> <!-- edit comment view --> <string name="author_name">Author name</string> |