Skip to content

Commit

Permalink
Merge pull request #6763 from wordpress-mobile/mzorz/post-error-succe…
Browse files Browse the repository at this point in the history
…ss-notifications

Async notifications: Post error / success notifications (part II):
  • Loading branch information
nbradbury authored Oct 25, 2017
2 parents 98939b0 + 158f6b8 commit 02bd896
Show file tree
Hide file tree
Showing 10 changed files with 332 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.wordpress.android.ui.prefs.AppPrefs;
import org.wordpress.android.ui.stats.service.StatsService;
import org.wordpress.android.ui.themes.ThemeBrowserActivity;
import org.wordpress.android.ui.uploads.UploadService;
import org.wordpress.android.ui.uploads.UploadUtils;
import org.wordpress.android.util.AniUtils;
import org.wordpress.android.util.CoreEvents;
Expand Down Expand Up @@ -497,6 +498,20 @@ public void onEventMainThread(CoreEvents.MainViewPagerScrolled event) {
mFabView.setTranslationY(mFabTargetYTranslation * event.mXOffset);
}

@SuppressWarnings("unused")
public void onEventMainThread(UploadService.UploadErrorEvent event) {
SiteModel site = getSelectedSite();
if (site != null && event.post != null) {
if (event.post.getLocalSiteId() == site.getId()) {
UploadUtils.onPostUploadedSnackbarHandler(getActivity(),
getActivity().findViewById(R.id.coordinator), true,
event.post, event.errorMessage, site, mDispatcher);
}
}
}


// FluxC events
@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onSiteChanged(OnSiteChanged event) {
Expand All @@ -509,13 +524,13 @@ public void onSiteChanged(OnSiteChanged event) {
@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPostUploaded(PostStore.OnPostUploaded event) {
final PostModel post = event.post;
if (isAdded() && event.post != null) {
SiteModel site = getSelectedSite();
if (site != null) {
if (event.post.getLocalSiteId() == site.getId()) {
UploadUtils.onPostUploadedSnackbarHandler(getActivity(),
getActivity().findViewById(R.id.coordinator), event, site, mDispatcher);
getActivity().findViewById(R.id.coordinator),
event.isError(), event.post, null, site, mDispatcher);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,10 @@ protected void onCreate(Bundle savedInstanceState) {
if (mIsNewPost) {
trackEditorCreatedPost(action, getIntent());
} else {
// if we are opening a Post for which an error notification exists, we need to remove
// it from the dashboard to prevent the user from tapping RETRY on a Post that is
// being currently edited
UploadService.cancelFinalNotification(mPost);
resetUploadingMediaToFailedIfPostHasNotMediaInProgressOrQueued();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,9 @@ static boolean updatePostContentIfDifferent(PostModel post, String newContent) {
}
return false;
}

public static boolean isFirstTimePublish(PostModel post) {
return PostStatus.fromPost(post) == PostStatus.DRAFT
|| (PostStatus.fromPost(post) == PostStatus.PUBLISHED && post.isLocalDraft());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,8 @@ public void onSaveInstanceState(Bundle outState) {
mRVScrollPositionSaver.onSaveInstanceState(outState, mRecyclerView);
}

// FluxC events

@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPostChanged(OnPostChanged event) {
Expand Down Expand Up @@ -682,7 +684,8 @@ public void onPostUploaded(OnPostUploaded event) {
if (isAdded() && event.post != null && event.post.getLocalSiteId() == mSite.getId()) {
loadPosts(LoadMode.FORCED);
UploadUtils.onPostUploadedSnackbarHandler(getActivity(),
getActivity().findViewById(R.id.coordinator), event, mSite, mDispatcher);
getActivity().findViewById(R.id.coordinator),
event.isError(), event.post, null, mSite, mDispatcher);
}
}

Expand Down Expand Up @@ -738,4 +741,10 @@ public void onEventMainThread(VideoOptimizer.ProgressEvent event) {
}
}
}

@SuppressWarnings("unused")
public void onEventMainThread(UploadService.UploadErrorEvent event) {
UploadUtils.onPostUploadedSnackbarHandler(getActivity(),
getActivity().findViewById(R.id.coordinator), true, event.post, event.errorMessage, mSite, mDispatcher);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,6 @@ private String processPostMedia(String postContent) {
}

mediaItemCount++;
mPostUploadNotifier.updateNotificationIcon(mPost, imageIcon);
mPostUploadNotifier.addMediaInfoToForegroundNotification(mediaModel);

String mediaUploadOutput;
Expand Down Expand Up @@ -565,6 +564,7 @@ public void onPostUploaded(OnPostUploaded event) {
Context context = WordPress.getContext();
String errorMessage = UploadUtils.getErrorMessageFromPostError(context, event.post, event.error);
String notificationMessage = UploadUtils.getErrorMessage(context, event.post, errorMessage, false);
mPostUploadNotifier.incrementUploadedPostCountFromForegroundNotification(event.post);
mPostUploadNotifier.updateNotificationError(event.post, site, notificationMessage);
sFirstPublishPosts.remove(event.post.getId());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
Expand All @@ -18,17 +17,22 @@
import org.wordpress.android.fluxc.model.SiteModel;
import org.wordpress.android.fluxc.model.post.PostStatus;
import org.wordpress.android.ui.notifications.ShareAndDismissNotificationReceiver;
import org.wordpress.android.ui.posts.PostUtils;
import org.wordpress.android.ui.posts.PostsListActivity;
import org.wordpress.android.ui.prefs.AppPrefs;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.CrashlyticsUtils;
import org.wordpress.android.util.SystemServiceFactory;
import org.wordpress.android.util.WPMeShortlinks;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import de.greenrobot.event.EventBus;

class PostUploadNotifier {
private final Context mContext;
private final UploadService mService;
Expand All @@ -48,6 +52,7 @@ private class NotificationData {
int totalPageItemsIncludedInPostCount;
int currentPostItem;
final Map<Integer, Float> mediaItemToProgressMap = new HashMap<>();
final List<PostModel> mUploadedPostsCounted = new ArrayList<>();;
}

PostUploadNotifier(Context context, UploadService service) {
Expand Down Expand Up @@ -108,6 +113,22 @@ private synchronized void startOrUpdateForegroundNotification(@Nullable PostMode
}
}

void prepareForegroundNotificationForRetry(@NonNull PostModel post, @Nullable List<MediaModel> media) {
removePostInfoFromForegroundNotificationData(post, media);
}

private void removePostInfoFromForegroundNotificationData(@NonNull PostModel post, @Nullable List<MediaModel> media) {
if (sNotificationData.totalPostItems > 0) {
sNotificationData.totalPostItems--;
if (post.isPage()) {
sNotificationData.totalPageItemsIncludedInPostCount--;
}
}
if (media != null) {
removeMediaInfoFromForegroundNotification(media);
}
}

// Post could have initial media, or not (nullable)
void addPostInfoToForegroundNotification(@NonNull PostModel post, @Nullable List<MediaModel> media) {
sNotificationData.totalPostItems++;
Expand All @@ -120,6 +141,12 @@ void addPostInfoToForegroundNotification(@NonNull PostModel post, @Nullable List
startOrUpdateForegroundNotification(post);
}

void removeMediaInfoFromForegroundNotification(@NonNull List<MediaModel> mediaList) {
if (sNotificationData.totalMediaItems >= mediaList.size()) {
sNotificationData.totalMediaItems -= mediaList.size();
}
}

void addMediaInfoToForegroundNotification(@NonNull List<MediaModel> mediaList) {
sNotificationData.totalMediaItems += mediaList.size();
// setup progresses for each media item
Expand All @@ -136,19 +163,16 @@ void addMediaInfoToForegroundNotification(@NonNull MediaModel media) {
startOrUpdateForegroundNotification(null);
}

void updateNotificationIcon(PostModel post, Bitmap icon) {
// TODO MEDIA reimplement or remove completely

// NotificationData notificationData = sPostIdToNotificationData.get(post.getId());
//
// if (icon != null) {
// notificationData.latestIcon = icon;
// mNotificationBuilder.setLargeIcon(notificationData.latestIcon);
// }
// doNotify(sPostIdToNotificationData.get(post.getId()).notificationId, mNotificationBuilder.build());
}

void incrementUploadedPostCountFromForegroundNotification(@NonNull PostModel post) {
// first we need to check that we only count this post once as "ended" (either successfully or with error)
// for every error we get. We'll then try to increment the Post count as it's been cancelled/failed because the
// related media was cancelled or has failed too (i.e. we can't upload a Post with failed media, therefore
// it needs to be cancelled).
if (isPostAlreadyInPostCount(post)) {
return;
} else {
addPostToPostCount(post);
}
sNotificationData.currentPostItem++;

// update Notification now
Expand All @@ -157,7 +181,7 @@ void incrementUploadedPostCountFromForegroundNotification(@NonNull PostModel pos
}
}

void incrementUploadedMediaCountFromProgressNotificationOrFinish(int mediaId) {
void incrementUploadedMediaCountFromProgressNotification(int mediaId) {
sNotificationData.currentMediaItem++;
if (!removeNotificationAndStopForegroundServiceIfNoItemsInQueue()) {
// update Notification now
Expand Down Expand Up @@ -185,6 +209,20 @@ private void resetNotificationCounters() {
sNotificationData.totalPostItems = 0;
sNotificationData.totalPageItemsIncludedInPostCount = 0;
sNotificationData.mediaItemToProgressMap.clear();
sNotificationData.mUploadedPostsCounted.clear();
}

private boolean isPostAlreadyInPostCount(@NonNull PostModel post){
for (PostModel onePost : sNotificationData.mUploadedPostsCounted) {
if (onePost.getId() == post.getId()) {
return true;
}
}
return false;
}

private void addPostToPostCount(@NonNull PostModel post) {
sNotificationData.mUploadedPostsCounted.add(post);
}

// cancels the error or success notification (only one of these exist per Post at any given
Expand Down Expand Up @@ -264,7 +302,8 @@ void updateNotificationSuccess(@NonNull PostModel post, @NonNull SiteModel site,

// add draft Publish action for drafts
if (PostStatus.fromPost(post) == PostStatus.DRAFT) {
Intent publishIntent = UploadService.getUploadPostServiceIntent(mContext, post, isFirstTimePublish, notificationId, true);
Intent publishIntent = UploadService.getUploadPostServiceIntent(mContext, post,
isFirstTimePublish, true, false);
PendingIntent pendingIntent = PendingIntent.getService(mContext, 0, publishIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
notificationBuilder.addAction(R.drawable.ic_posts_grey_24dp, mContext.getString(R.string.button_publish),
Expand All @@ -274,7 +313,7 @@ void updateNotificationSuccess(@NonNull PostModel post, @NonNull SiteModel site,
doNotify(notificationId, notificationBuilder.build());
}

private long getNotificationIdForPost(PostModel post) {
public static long getNotificationIdForPost(PostModel post) {
long remotePostId = post.getRemotePostId();
// We can't use the local table post id here because it can change between first post (local draft) to
// first edit (post pulled from the server)
Expand All @@ -301,17 +340,59 @@ void updateNotificationError(@NonNull PostModel post, @NonNull SiteModel site, S
(int)notificationId,
notificationIntent, PendingIntent.FLAG_ONE_SHOT);

notificationBuilder.setSmallIcon(android.R.drawable.stat_notify_error);
notificationBuilder.setSmallIcon(R.drawable.ic_my_sites_24dp);
notificationBuilder.setColor(mContext.getResources().getColor(R.color.blue_wordpress));

String postTitle = TextUtils.isEmpty(post.getTitle()) ? mContext.getString(R.string.untitled) : post.getTitle();
String notificationTitle = String.format(mContext.getString(R.string.upload_failed_param), postTitle);
notificationBuilder.setContentTitle(notificationTitle);

notificationBuilder.setContentText(errorMessage);
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(errorMessage));
// first we build a summary of what failed and what went OK, like this:
// i.e. "1 post, 3 media files not uploaded (9 successfully uploaded)"
String newErrorMessage = "";
int postItemsNotUploaded = sNotificationData.totalPostItems > 0 ? sNotificationData.totalPostItems - getCurrentPostItem() : 0;
int mediaItemsNotUploaded = sNotificationData.totalMediaItems - getCurrentMediaItem();
if (postItemsNotUploaded > 0) {
newErrorMessage += postItemsNotUploaded + " " + getPagesAndOrPostsString(postItemsNotUploaded);
if (mediaItemsNotUploaded > 0) {
newErrorMessage += ", ";
}
}

if (mediaItemsNotUploaded > 0) {
newErrorMessage += String.format(mContext.getString(R.string.media_files_not_uploaded), mediaItemsNotUploaded);
if (mediaItemsNotUploaded <= sNotificationData.currentMediaItem) {
// some media items were uploaded successfully
newErrorMessage += " " + String.format(mContext.getString(R.string.media_files_uploaded_succcessfully),
sNotificationData.currentMediaItem);
}
}

// now append the detailed error message below
String snackbarMessage = new String(newErrorMessage);
if (newErrorMessage.length() > 0) {
newErrorMessage += "\n" + errorMessage;
} else {
newErrorMessage = errorMessage;
}

notificationBuilder.setContentTitle(notificationTitle);
notificationBuilder.setContentText(newErrorMessage);
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(newErrorMessage));
notificationBuilder.setContentIntent(pendingIntent);
notificationBuilder.setAutoCancel(true);

// Add RETRY action - only available on Aztec
if ( AppPrefs.isAztecEditorEnabled()) {
Intent publishIntent = UploadService.getUploadPostServiceIntent(mContext, post,
PostUtils.isFirstTimePublish(post), false, true);
PendingIntent actionPendingIntent = PendingIntent.getService(mContext, 0, publishIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
notificationBuilder.addAction(0, mContext.getString(R.string.retry),
actionPendingIntent).setColor(mContext.getResources().getColor(R.color.orange_jazzy));
}

EventBus.getDefault().post(new UploadService.UploadErrorEvent(post, snackbarMessage));

doNotify(notificationId, notificationBuilder.build());
}

Expand Down Expand Up @@ -375,7 +456,13 @@ private synchronized void doNotify(long id, Notification notification) {
}

void setTotalMediaItems(PostModel post, int totalMediaItems) {
sNotificationData.totalMediaItems+=totalMediaItems;
if (post != null) {
sNotificationData.totalPostItems = 1;
if (post.isPage()) {
sNotificationData.totalPageItemsIncludedInPostCount = 1;
}
}
sNotificationData.totalMediaItems = totalMediaItems;
}

private String buildNotificationTitleForPost(PostModel post) {
Expand Down
Loading

0 comments on commit 02bd896

Please sign in to comment.