diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index 6e7301a3698b..102a7b2eb846 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -3231,6 +3231,27 @@ private void requestTemporaryPermissions(DragEvent dragEvent) { requestDragAndDropPermissions(dragEvent); } + @Override + public void onMediaRetryAllClicked(Set failedMediaIds) { + UploadService.cancelFinalNotification(this, mPost); + UploadService.cancelFinalNotificationForMedia(this, mSite); + + ArrayList failedMediaList = new ArrayList<>(); + for (String mediaId : failedMediaIds) { + failedMediaList.add(mMediaStore.getMediaWithLocalId(Integer.valueOf(mediaId))); + } + + if (!failedMediaList.isEmpty()) { + for (MediaModel mediaModel : failedMediaList) { + mediaModel.setUploadState(MediaUploadState.QUEUED); + mDispatcher.dispatch(MediaActionBuilder.newUpdateMediaAction(mediaModel)); + } + startUploadService(failedMediaList); + } + + AnalyticsTracker.track(Stat.EDITOR_UPLOAD_MEDIA_RETRIED); + } + @Override public boolean onMediaRetryClicked(final String mediaId) { if (TextUtils.isEmpty(mediaId)) { @@ -3300,10 +3321,25 @@ public void onMediaUploadCancelClicked(String localMediaId) { @Override public void onMediaDeleted(String localMediaId) { if (!TextUtils.isEmpty(localMediaId)) { - mAztecBackspaceDeletedMediaItemIds.add(localMediaId); - UploadService.setDeletedMediaItemIds(mAztecBackspaceDeletedMediaItemIds); - // passing false here as we need to keep the media item in case the user wants to undo - cancelMediaUpload(StringUtils.stringToInt(localMediaId), false); + if (mShowAztecEditor) { + mAztecBackspaceDeletedMediaItemIds.add(localMediaId); + UploadService.setDeletedMediaItemIds(mAztecBackspaceDeletedMediaItemIds); + // passing false here as we need to keep the media item in case the user wants to undo + cancelMediaUpload(StringUtils.stringToInt(localMediaId), false); + } else if (mShowGutenbergEditor) { + MediaModel mediaModel = mMediaStore.getMediaWithLocalId(StringUtils.stringToInt(localMediaId)); + if (mediaModel == null) { + return; + } + + // also make sure it's not being uploaded anywhere else (maybe on some other Post, + // simultaneously) + if (mediaModel.getUploadState() != null + && MediaUtils.isLocalFile(mediaModel.getUploadState().toLowerCase(Locale.ROOT)) + && !UploadService.isPendingOrInProgressMediaUpload(mediaModel)) { + mDispatcher.dispatch(MediaActionBuilder.newRemoveMediaAction(mediaModel)); + } + } } } @@ -3482,6 +3518,18 @@ public void onJavaScriptAlert(String url, String message) { } }); } + + // probably here is best for Gutenberg to start interacting with + if (mShowGutenbergEditor && mEditorFragment instanceof GutenbergEditorFragment) { + List failedMedia = mMediaStore.getMediaForPostWithState(mPost, MediaUploadState.FAILED); + if (failedMedia != null && !failedMedia.isEmpty()) { + HashSet mediaIds = new HashSet<>(); + for (MediaModel media : failedMedia) { + mediaIds.add(media.getId()); + } + ((GutenbergEditorFragment) mEditorFragment).resetUploadingMediaToFailed(mediaIds); + } + } } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java index f59ff6ae6d28..2972c8e9d7a4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java @@ -244,12 +244,16 @@ private void unpackPostIntent(@NonNull Intent intent) { } if (intent.getBooleanExtra(KEY_SHOULD_RETRY, false)) { - if (AppPrefs.isAztecEditorEnabled()) { + if (AppPrefs.isAztecEditorEnabled() || AppPrefs.isGutenbergEditorEnabled()) { if (!NetworkUtils.isNetworkAvailable(this)) { rebuildNotificationError(post, getString(R.string.no_network_message)); return; } - aztecRetryUpload(post); + boolean postHasGutenbergBlocks = PostUtils.contentContainsGutenbergBlocks(post.getContent()); + boolean processWithAztec = + AppPrefs.isAztecEditorEnabled() && !AppPrefs.isGutenbergEditorEnabled() + && !postHasGutenbergBlocks; + retryUpload(post, processWithAztec); } else { ToastUtils.showToast(this, R.string.retry_needs_aztec); } @@ -706,7 +710,7 @@ private void rebuildNotificationError(PostModel post, String errorMessage) { errorMessage, 0); } - private void registerFailedMediaForThisPost(PostModel post) { + private void aztecRegisterFailedMediaForThisPost(PostModel post) { // there could be failed media in the post, that has not been registered in the UploadStore because // the media was being uploaded separately (i.e. the user included media, started uploading within // the editor, and such media failed _before_ exiting the eidtor, thus the registration never happened. @@ -740,10 +744,12 @@ private void registerFailedMediaForThisPost(PostModel post) { } } - private void aztecRetryUpload(PostModel post) { + private void retryUpload(PostModel post, boolean processWithAztec) { AnalyticsTracker.track(AnalyticsTracker.Stat.NOTIFICATION_UPLOAD_POST_ERROR_RETRY); - registerFailedMediaForThisPost(post); + if (processWithAztec) { + aztecRegisterFailedMediaForThisPost(post); + } Set failedMedia = mUploadStore.getFailedMediaForPost(post); ArrayList mediaToRetry = new ArrayList<>(failedMedia); @@ -755,11 +761,13 @@ private void aztecRetryUpload(PostModel post) { mDispatcher.dispatch(MediaActionBuilder.newUpdateMediaAction(media)); } - // do the same within the Post content itself - String postContentWithRestartedUploads = - AztecEditorFragment.restartFailedMediaToUploading(this, post.getContent()); - post.setContent(postContentWithRestartedUploads); - mDispatcher.dispatch(PostActionBuilder.newUpdatePostAction(post)); + if (processWithAztec) { + // do the same within the Post content itself + String postContentWithRestartedUploads = + AztecEditorFragment.restartFailedMediaToUploading(this, post.getContent()); + post.setContent(postContentWithRestartedUploads); + mDispatcher.dispatch(PostActionBuilder.newUpdatePostAction(post)); + } // no retry uploading the media items for (MediaModel media : mediaToRetry) { diff --git a/libs/editor/WordPressEditor/src/androidTest/java/org.wordpress.android.editor/MockEditorActivity.java b/libs/editor/WordPressEditor/src/androidTest/java/org.wordpress.android.editor/MockEditorActivity.java index 929d572ab05b..77e045e20b78 100644 --- a/libs/editor/WordPressEditor/src/androidTest/java/org.wordpress.android.editor/MockEditorActivity.java +++ b/libs/editor/WordPressEditor/src/androidTest/java/org.wordpress.android.editor/MockEditorActivity.java @@ -14,6 +14,7 @@ import org.wordpress.android.util.helpers.MediaFile; import java.util.ArrayList; +import java.util.Set; public class MockEditorActivity extends AppCompatActivity implements EditorFragmentListener, EditorDragAndDropListener { @@ -57,6 +58,10 @@ public boolean onMediaRetryClicked(String mediaId) { return true; } + @Override + public void onMediaRetryAllClicked(Set mediaIdSet) { + } + @Override public void onMediaUploadCancelClicked(String mediaId) { } diff --git a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java index d8d44af3c231..64d9795b1f85 100644 --- a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java +++ b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.Set; public abstract class EditorFragmentAbstract extends Fragment { public abstract void setTitle(CharSequence text); @@ -182,6 +183,7 @@ public interface EditorFragmentListener { void onAddPhotoClicked(); void onCapturePhotoClicked(); boolean onMediaRetryClicked(String mediaId); + void onMediaRetryAllClicked(Set mediaIdSet); void onMediaUploadCancelClicked(String mediaId); void onMediaDeleted(String mediaId); void onUndoMediaCheck(String undoedContent); diff --git a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/GutenbergEditorFragment.java b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/GutenbergEditorFragment.java index 26077d9f191d..7f4ed36f3b2e 100644 --- a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/GutenbergEditorFragment.java +++ b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/GutenbergEditorFragment.java @@ -3,14 +3,18 @@ import android.app.Activity; import android.arch.lifecycle.LiveData; import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.text.Editable; import android.text.Spanned; +import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -124,10 +128,19 @@ public void onUploadMediaButtonClicked() { public void onCapturePhotoButtonClicked() { checkAndRequestCameraAndStoragePermissions(); } + + @Override public void onRetryUploadForMediaClicked(int mediaId) { + showRetryMediaUploadDialog(mediaId); + } + + @Override public void onCancelUploadForMediaClicked(int mediaId) { + showCancelMediaUploadDialog(mediaId); + } }, new OnReattachQueryListener() { @Override public void onQueryCurrentProgressForUploadingMedia() { + updateFailedMediaState(); updateMediaProgress(); } }, @@ -170,13 +183,29 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis } } + public void resetUploadingMediaToFailed(Set failedMediaIds) { + // get all media failed for this post, and represent it on tje UI + if (failedMediaIds != null && !failedMediaIds.isEmpty()) { + for (Integer mediaId : failedMediaIds) { + // and keep track of failed ids around + mFailedMediaIds.add(String.valueOf(mediaId)); + } + } + } + + private void updateFailedMediaState() { + for (String mediaId : mFailedMediaIds) { + mWPAndroidGlueCode.mediaFileUploadFailed(Integer.valueOf(mediaId)); + } + } + private void updateMediaProgress() { for (String mediaId : mUploadingMediaProgressMax.keySet()) { mWPAndroidGlueCode.mediaFileUploadProgress(Integer.valueOf(mediaId), mUploadingMediaProgressMax.get(mediaId)); } } - + private void checkAndRequestCameraAndStoragePermissions() { if (PermissionUtils.checkAndRequestCameraAndStoragePermissions(this, CAPTURE_PHOTO_PERMISSION_REQUEST_CODE)) { @@ -184,6 +213,78 @@ private void checkAndRequestCameraAndStoragePermissions() { } } + private void showCancelMediaUploadDialog(final int localMediaId) { + // Display 'cancel upload' dialog + AlertDialog.Builder builder = new AlertDialog.Builder( + new ContextThemeWrapper(getActivity(), R.style.Calypso_Dialog_Alert)); + builder.setTitle(getString(R.string.stop_upload_dialog_title)); + builder.setPositiveButton(R.string.stop_upload_dialog_button_yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + if (mUploadingMediaProgressMax.containsKey(String.valueOf(localMediaId))) { + mEditorFragmentListener.onMediaUploadCancelClicked(String.valueOf(localMediaId)); + // remove from editor + mEditorFragmentListener.onMediaDeleted(String.valueOf(localMediaId)); + mWPAndroidGlueCode.clearMediaFileURL(localMediaId); + mUploadingMediaProgressMax.remove(localMediaId); + } else { + ToastUtils.showToast(getActivity(), R.string.upload_finished_toast).show(); + } + dialog.dismiss(); + } + }); + + builder.setNegativeButton(R.string.stop_upload_dialog_button_no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.dismiss(); + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + private void showRetryMediaUploadDialog(final int mediaId) { + // Display 'retry upload' dialog + AlertDialog.Builder builder = new AlertDialog.Builder( + new ContextThemeWrapper(getActivity(), R.style.Calypso_Dialog_Alert)); + builder.setTitle(getString(R.string.retry_failed_upload_title)); + builder.setPositiveButton(R.string.retry_failed_upload_yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.dismiss(); + boolean successfullyRetried = true; + if (mFailedMediaIds.contains(String.valueOf(mediaId))) { + successfullyRetried = mEditorFragmentListener.onMediaRetryClicked(String.valueOf(mediaId)); + } + if (successfullyRetried) { + mFailedMediaIds.remove(String.valueOf(mediaId)); + mUploadingMediaProgressMax.put(String.valueOf(mediaId), 0f); + mWPAndroidGlueCode.mediaFileUploadProgress(mediaId, + mUploadingMediaProgressMax.get(String.valueOf(mediaId))); + } + } + }); + + builder.setNeutralButton(R.string.retry_failed_upload_retry_all, new OnClickListener() { + @Override public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + mEditorFragmentListener.onMediaRetryAllClicked(mFailedMediaIds); + } + }); + + builder.setNegativeButton(R.string.retry_failed_upload_remove, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.dismiss(); + mEditorFragmentListener.onMediaDeleted(String.valueOf(mediaId)); + mWPAndroidGlueCode.clearMediaFileURL(mediaId); + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + @Override public void onPause() { super.onPause(); diff --git a/libs/editor/WordPressEditor/src/main/res/values/strings.xml b/libs/editor/WordPressEditor/src/main/res/values/strings.xml index f1d0ea718b0a..8622f8b5a6bc 100644 --- a/libs/editor/WordPressEditor/src/main/res/values/strings.xml +++ b/libs/editor/WordPressEditor/src/main/res/values/strings.xml @@ -128,4 +128,10 @@ Yes No + Retry uploading? + Retry + Remove + Retry all + + diff --git a/libs/gutenberg-mobile b/libs/gutenberg-mobile index b02d0addaeae..bd206005e0c6 160000 --- a/libs/gutenberg-mobile +++ b/libs/gutenberg-mobile @@ -1 +1 @@ -Subproject commit b02d0addaeae3baf59ad175f7fbe56f23589725c +Subproject commit bd206005e0c6ce6b0eca2eefb6195f5d2e1f18eb