Skip to content

Commit d03b198

Browse files
authored
Merge pull request #10319 from wordpress-mobile/issue/10174-update-changes-confirmed-at
Auto-upload/save all posts/pages with local changes
2 parents 437e6c6 + 5ce1ff7 commit d03b198

19 files changed

+540
-285
lines changed

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ XX.X
22
----
33
* Add Remote Preview support for posts and pages.
44
* Post List: Trashed post must now be restored before edit or preview.
5+
* All changes to posts and pages will be automatically synced with the server.
56

67
13.1
78
-----

WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,16 +1717,11 @@ private void setGutenbergEnabledIfNeeded() {
17171717
}
17181718
}
17191719

1720-
private void savePostOnlineAndFinishAsync(boolean isFirstTimePublish, boolean doFinishActivity) {
1721-
savePostOnlineAndFinishAsync(isFirstTimePublish, doFinishActivity, false);
1722-
}
1723-
17241720
private void savePostOnlineAndFinishAsync(
17251721
boolean isFirstTimePublish,
1726-
boolean doFinishActivity,
1727-
boolean isRemoteAutoSave
1722+
boolean doFinishActivity
17281723
) {
1729-
new SavePostOnlineAndFinishTask(isFirstTimePublish, doFinishActivity, isRemoteAutoSave)
1724+
new SavePostOnlineAndFinishTask(isFirstTimePublish, doFinishActivity)
17301725
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
17311726
}
17321727

@@ -2076,12 +2071,10 @@ private boolean userCanPublishPosts() {
20762071
private class SavePostOnlineAndFinishTask extends AsyncTask<Void, Void, Void> {
20772072
boolean mIsFirstTimePublish;
20782073
boolean mDoFinishActivity;
2079-
boolean mIsRemoteAutoSave;
20802074

2081-
SavePostOnlineAndFinishTask(boolean isFirstTimePublish, boolean doFinishActivity, boolean isRemoteAutoSave) {
2075+
SavePostOnlineAndFinishTask(boolean isFirstTimePublish, boolean doFinishActivity) {
20822076
this.mIsFirstTimePublish = isFirstTimePublish;
20832077
this.mDoFinishActivity = doFinishActivity;
2084-
this.mIsRemoteAutoSave = isRemoteAutoSave;
20852078
}
20862079

20872080
@Override
@@ -2106,11 +2099,7 @@ protected Void doInBackground(Void... params) {
21062099
PostUtils.trackSavePostAnalytics(mPost, mSiteStore.getSiteByLocalId(mPost.getLocalSiteId()));
21072100

21082101
UploadService.setLegacyMode(!isModernEditor());
2109-
if (mIsFirstTimePublish) {
2110-
UploadService.uploadPostAndTrackAnalytics(EditPostActivity.this, mPost, mIsRemoteAutoSave);
2111-
} else {
2112-
UploadService.uploadPost(EditPostActivity.this, mPost, mIsRemoteAutoSave);
2113-
}
2102+
UploadService.uploadPost(EditPostActivity.this, mPost, mIsFirstTimePublish);
21142103

21152104
PendingDraftsNotificationsUtils.cancelPendingDraftAlarms(EditPostActivity.this, mPost.getId());
21162105

@@ -2251,6 +2240,15 @@ public void run() {
22512240

22522241
boolean isPublishable = PostUtils.isPublishable(mPost);
22532242

2243+
boolean hasFailedMediaUploads = mEditorFragment.hasFailedMediaUploads()
2244+
|| mFeaturedImageHelper.getFailedFeaturedImageUpload(mPost) != null;
2245+
2246+
if (!hasFailedMediaUploads) {
2247+
AppLog.d(T.POSTS, "User explicitly confirmed changes. Post Title: " + mPost.getTitle());
2248+
// the user explicitly confirmed an intention to upload the post
2249+
mPost.setChangesConfirmedContentHashcode(mPost.contentHashcode());
2250+
}
2251+
22542252
// if post was modified or has unsaved local changes and is publishable, save it
22552253
saveResult(isPublishable, false, false);
22562254

@@ -2259,8 +2257,7 @@ public void run() {
22592257
if (isPublishable) {
22602258
if (NetworkUtils.isNetworkAvailable(getBaseContext())) {
22612259
// Show an Alert Dialog asking the user if they want to remove all failed media before upload
2262-
if (mEditorFragment.hasFailedMediaUploads()
2263-
|| mFeaturedImageHelper.getFailedFeaturedImageUpload(mPost) != null) {
2260+
if (hasFailedMediaUploads) {
22642261
EditPostActivity.this.runOnUiThread(new Runnable() {
22652262
@Override
22662263
public void run() {
@@ -2310,7 +2307,7 @@ private void savePostAndOptionallyFinish(final boolean doFinish) {
23102307
savePostAndOptionallyFinish(doFinish, false);
23112308
}
23122309

2313-
private void savePostAndOptionallyFinish(final boolean doFinish, final boolean isRemoteAutoSave) {
2310+
private void savePostAndOptionallyFinish(final boolean doFinish, final boolean forceSave) {
23142311
// Update post, save to db and post online in its own Thread, because 1. update can be pretty slow with a lot of
23152312
// text 2. better not to call `updatePostObject()` from the UI thread due to weird thread blocking behavior
23162313
// on API 16 (and 21) with the visual editor.
@@ -2329,8 +2326,8 @@ public void run() {
23292326

23302327
boolean isPublishable = PostUtils.isPublishable(mPost);
23312328

2332-
// if post was modified or has unpublished local changes, save it
2333-
boolean shouldSave = shouldSavePost() || isRemoteAutoSave;
2329+
// if post was modified during this editing session, save it
2330+
boolean shouldSave = shouldSavePost() || forceSave;
23342331

23352332
// if post is publishable or not new, sync it
23362333
boolean shouldSync = isPublishable || !isNewPost();
@@ -2342,17 +2339,22 @@ public void run() {
23422339
definitelyDeleteBackspaceDeletedMediaItems();
23432340

23442341
if (shouldSave) {
2345-
PostStatus status = PostStatus.fromPost(mPost);
23462342
boolean isNotRestarting = mRestartEditorOption == RestartEditorOptions.NO_RESTART;
2347-
if ((status == PostStatus.DRAFT || status == PostStatus.PENDING) && isPublishable
2348-
&& !hasFailedMedia() && NetworkUtils.isNetworkAvailable(getBaseContext())
2349-
&& isNotRestarting) {
2343+
/*
2344+
* Remote-auto-save isn't supported on self-hosted sites. We can save the post online (as draft)
2345+
* only when it doesn't exist in the remote yet. When it does exist in the remote, we can upload
2346+
* it only when the user explicitly confirms the changes - eg. clicks on save/publish/submit. The
2347+
* user didn't confirm the changes in this code path.
2348+
*/
2349+
boolean isWpComOrIsLocalDraft = mSite.isUsingWpComRestApi() || mPost.isLocalDraft();
2350+
if (isPublishable && !hasFailedMedia() && NetworkUtils.isNetworkAvailable(getBaseContext())
2351+
&& isNotRestarting && isWpComOrIsLocalDraft) {
23502352
mPostEditorAnalyticsSession.setOutcome(Outcome.SAVE);
2351-
savePostOnlineAndFinishAsync(isFirstTimePublish, doFinish, isRemoteAutoSave);
2353+
savePostOnlineAndFinishAsync(isFirstTimePublish, doFinish);
23522354
} else {
23532355
mPostEditorAnalyticsSession.setOutcome(Outcome.SAVE);
2354-
if (isRemoteAutoSave) {
2355-
savePostOnlineAndFinishAsync(false, false, isRemoteAutoSave);
2356+
if (forceSave) {
2357+
savePostOnlineAndFinishAsync(false, false);
23562358
} else {
23572359
savePostLocallyAndFinishAsync(doFinish);
23582360
}
@@ -2374,16 +2376,11 @@ public void run() {
23742376
}
23752377

23762378
private boolean shouldSavePost() {
2377-
boolean hasLocalChanges = mPost.isLocallyChanged() || mPost.isLocalDraft();
23782379
boolean hasChanges = PostUtils.postHasEdits(mPostSnapshotWhenEditorOpened, mPost);
23792380
boolean isPublishable = PostUtils.isPublishable(mPost);
2380-
boolean hasUnpublishedLocalDraftChanges = (PostStatus.fromPost(mPost) == PostStatus.DRAFT
2381-
|| PostStatus.fromPost(mPost) == PostStatus.PENDING)
2382-
&& isPublishable && hasLocalChanges;
23832381

2384-
// if post was modified or has unpublished local changes, save it
2385-
return (mPostSnapshotWhenEditorOpened != null && hasChanges)
2386-
|| hasUnpublishedLocalDraftChanges || (isPublishable && isNewPost());
2382+
// if post was modified during this editing session, save it
2383+
return (mPostSnapshotWhenEditorOpened != null && hasChanges) || (isPublishable && isNewPost());
23872384
}
23882385

23892386

WordPress/src/main/java/org/wordpress/android/ui/posts/PostListAction.kt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ sealed class PostListAction {
2626
) : PostListAction()
2727
class RetryUpload(
2828
val post: PostModel,
29-
val trackAnalytics: Boolean = PostUtils.isFirstTimePublish(post),
30-
val publish: Boolean = false,
31-
val retry: Boolean = true
29+
val trackAnalytics: Boolean = PostUtils.isFirstTimePublish(post)
3230
) : PostListAction()
3331

3432
class ViewStats(val site: SiteModel, val post: PostModel) : PostListAction()
@@ -63,12 +61,10 @@ fun handlePostListAction(
6361
}
6462
is PostListAction.RetryUpload -> {
6563
// restart the UploadService with retry parameters
66-
val intent = UploadService.getUploadPostServiceIntent(
64+
val intent = UploadService.getRetryUploadServiceIntent(
6765
activity,
6866
action.post,
69-
action.trackAnalytics,
70-
action.publish,
71-
action.retry
67+
action.trackAnalytics
7268
)
7369
activity.startService(intent)
7470
}

WordPress/src/main/java/org/wordpress/android/ui/posts/PostListEventListener.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,15 @@ class PostListEventListener(
128128
)
129129
}
130130
is CauseOfOnPostChanged.RemoteAutoSavePost -> {
131+
val post = postStore.getPostByLocalPostId((event.causeOfChange as RemoteAutoSavePost).localPostId)
131132
if (isRemotePreviewingFromPostsList.invoke()) {
132-
val post = postStore.getPostByLocalPostId((event.causeOfChange as RemoteAutoSavePost).localPostId)
133133
if (event.isError) {
134134
AppLog.d(T.POSTS, "REMOTE_AUTO_SAVE_POST failed: " +
135135
event.error.type + " - " + event.error.message)
136136
}
137137
handleRemoteAutoSave(post, event.isError)
138+
} else {
139+
uploadStatusChanged(post.id)
138140
}
139141
}
140142
}

WordPress/src/main/java/org/wordpress/android/ui/posts/PostListMainViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ import org.wordpress.android.ui.posts.PostListViewLayoutType.STANDARD
3939
import org.wordpress.android.ui.posts.PostListViewLayoutTypeMenuUiState.CompactViewLayoutTypeMenuUiState
4040
import org.wordpress.android.ui.posts.PostListViewLayoutTypeMenuUiState.StandardViewLayoutTypeMenuUiState
4141
import org.wordpress.android.ui.prefs.AppPrefsWrapper
42-
import org.wordpress.android.ui.uploads.UploadStarter
4342
import org.wordpress.android.util.AppLog
43+
import org.wordpress.android.ui.uploads.UploadStarter
4444
import org.wordpress.android.util.NetworkUtilsWrapper
4545
import org.wordpress.android.util.SiteUtils
4646
import org.wordpress.android.util.ToastUtils.Duration

WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ public static boolean postHasEdits(@Nullable PostModel oldPost, PostModel newPos
219219
&& oldPost.getCategoryIdList().containsAll(newPost.getCategoryIdList())
220220
&& newPost.getCategoryIdList().containsAll(oldPost.getCategoryIdList())
221221
&& PostLocation.equals(oldPost.getLocation(), newPost.getLocation())
222+
&& oldPost.getChangesConfirmedContentHashcode() == newPost
223+
.getChangesConfirmedContentHashcode()
222224
);
223225
}
224226

WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtilsWrapper.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ import javax.inject.Inject
1414
@Reusable
1515
class PostUtilsWrapper @Inject constructor() {
1616
fun isPublishable(post: PostModel) = PostUtils.isPublishable(post)
17+
18+
fun isPostInConflictWithRemote(post: PostModel) = PostUtils.isPostInConflictWithRemote(post)
1719
}

WordPress/src/main/java/org/wordpress/android/ui/posts/PreviewStateHelper.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class PreviewStateHelper @Inject constructor() {
5555
PostInfoType.PostNoInfo
5656
)
5757
if (!UploadService.isPostUploadingOrQueued(post)) {
58-
UploadService.uploadPost(activity, post, true)
58+
UploadService.uploadPost(activity, post, false)
5959
} else {
6060
AppLog.d(
6161
AppLog.T.POSTS,
@@ -68,7 +68,7 @@ class PreviewStateHelper @Inject constructor() {
6868
PostInfoType.PostNoInfo
6969
)
7070
if (!UploadService.isPostUploadingOrQueued(post)) {
71-
UploadService.uploadPost(activity, post)
71+
UploadService.uploadPost(activity, post, false)
7272
} else {
7373
AppLog.d(
7474
AppLog.T.POSTS,

WordPress/src/main/java/org/wordpress/android/ui/posts/RemotePreviewLogicHelper.kt

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ package org.wordpress.android.ui.posts
33
import android.app.Activity
44
import org.wordpress.android.fluxc.model.PostModel
55
import org.wordpress.android.fluxc.model.SiteModel
6-
import org.wordpress.android.fluxc.model.post.PostStatus
76
import org.wordpress.android.ui.ActivityLauncherWrapper
87
import org.wordpress.android.ui.WPWebViewUsageCategory
8+
import org.wordpress.android.ui.uploads.UploadUtils
9+
import org.wordpress.android.ui.uploads.UploadUtils.PostUploadAction
10+
import org.wordpress.android.ui.uploads.UploadUtils.PostUploadAction.REMOTE_AUTO_SAVE
11+
import org.wordpress.android.ui.uploads.UploadUtils.PostUploadAction.UPLOAD
12+
import org.wordpress.android.ui.uploads.UploadUtils.PostUploadAction.UPLOAD_AS_DRAFT
913
import org.wordpress.android.util.NetworkUtilsWrapper
1014
import javax.inject.Inject
1115
import javax.inject.Singleton
@@ -64,8 +68,10 @@ class RemotePreviewLogicHelper @Inject constructor(
6468
// (eg. during and editing session)
6569
val updatedPost = helperFunctions.updatePostIfNeeded() ?: post
6670

71+
val uploadAction = UploadUtils.getPostUploadAction(updatedPost)
72+
6773
return when {
68-
shouldUpload(updatedPost) -> {
74+
shouldUpload(updatedPost, uploadAction) -> {
6975
// We can't upload an unpublishable post (empty), we'll let the user know we can't preview it.
7076
if (!postUtilsWrapper.isPublishable(updatedPost)) {
7177
helperFunctions.notifyEmptyDraft()
@@ -74,7 +80,7 @@ class RemotePreviewLogicHelper @Inject constructor(
7480
helperFunctions.startUploading(false, updatedPost)
7581
PreviewLogicOperationResult.GENERATING_PREVIEW
7682
}
77-
shouldRemoteAutoSave(updatedPost) -> {
83+
shouldRemoteAutoSave(updatedPost, uploadAction) -> {
7884
// We don't support remote auto-save for self hosted sites (accessed via XMLRPC),
7985
// we make the preview unavailable in that case.
8086
if (!site.isUsingWpComRestApi) {
@@ -118,14 +124,11 @@ class RemotePreviewLogicHelper @Inject constructor(
118124
}
119125
}
120126

121-
private fun shouldUpload(post: PostModel): Boolean {
122-
val status = PostStatus.fromPost(post)
123-
return post.isLocalDraft ||
124-
(status == PostStatus.DRAFT && post.isLocallyChanged)
127+
private fun shouldUpload(post: PostModel, action: PostUploadAction): Boolean {
128+
return (post.isLocallyChanged || post.isLocalDraft) && (action == UPLOAD_AS_DRAFT || action == UPLOAD)
125129
}
126130

127-
private fun shouldRemoteAutoSave(post: PostModel): Boolean {
128-
val status = PostStatus.fromPost(post)
129-
return (status == PostStatus.PUBLISHED || status == PostStatus.SCHEDULED) && post.isLocallyChanged
131+
private fun shouldRemoteAutoSave(post: PostModel, action: PostUploadAction): Boolean {
132+
return post.isLocallyChanged && action == REMOTE_AUTO_SAVE
130133
}
131134
}

WordPress/src/main/java/org/wordpress/android/ui/uploads/PostUploadHandler.java

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
public class PostUploadHandler implements UploadHandler<PostModel> {
6666
private static ArrayList<PostModel> sQueuedPostsList = new ArrayList<>();
6767
private static Set<Integer> sFirstPublishPosts = new HashSet<>();
68-
private static Set<Integer> sShouldRemoteAutoSavePosts = new HashSet<>();
6968
private static PostModel sCurrentUploadingPost = null;
7069
private static Map<String, Object> sCurrentUploadingPostAnalyticsProperties;
7170

@@ -135,18 +134,6 @@ void unregisterPostForAnalyticsTracking(@NonNull PostModel post) {
135134
}
136135
}
137136

138-
void registerPostForRemoteAutoSave(@NonNull PostModel post) {
139-
synchronized (sShouldRemoteAutoSavePosts) {
140-
sShouldRemoteAutoSavePosts.add(post.getId());
141-
}
142-
}
143-
144-
void unregisterPostForRemoteAutoSave(@NonNull PostModel post) {
145-
synchronized (sShouldRemoteAutoSavePosts) {
146-
sShouldRemoteAutoSavePosts.remove(post.getId());
147-
}
148-
}
149-
150137
static void setLegacyMode(boolean enabled) {
151138
sUseLegacyMode = enabled;
152139
}
@@ -279,12 +266,26 @@ protected Boolean doInBackground(PostModel... posts) {
279266

280267
RemotePostPayload payload = new RemotePostPayload(mPost, mSite);
281268

282-
if (sShouldRemoteAutoSavePosts.contains(mPost.getId())) {
283-
mDispatcher.dispatch(PostActionBuilder.newRemoteAutoSavePostAction(payload));
284-
} else {
285-
mDispatcher.dispatch(PostActionBuilder.newPushPostAction(payload));
269+
switch (UploadUtils.getPostUploadAction(mPost)) {
270+
case UPLOAD:
271+
AppLog.d(T.POSTS,
272+
"Invoking newPushPostAction. Post: " + mPost.getTitle() + " status: " + mPost.getStatus());
273+
mDispatcher.dispatch(PostActionBuilder.newPushPostAction(payload));
274+
break;
275+
case UPLOAD_AS_DRAFT:
276+
mPost.setStatus(PostStatus.DRAFT.toString());
277+
AppLog.d(T.POSTS,
278+
"Invoking newPushPostAction - local draft. Post: " + mPost.getTitle() + " status: " + mPost
279+
.getStatus());
280+
mDispatcher.dispatch(PostActionBuilder.newPushPostAction(payload));
281+
break;
282+
case REMOTE_AUTO_SAVE:
283+
AppLog.d(T.POSTS,
284+
"Invoking newRemoteAutoSavePostAction. Post: " + mPost.getTitle() + " status: " + mPost
285+
.getStatus());
286+
mDispatcher.dispatch(PostActionBuilder.newRemoteAutoSavePostAction(payload));
287+
break;
286288
}
287-
288289
return true;
289290
}
290291

@@ -611,11 +612,9 @@ public void onPostUploaded(OnPostUploaded event) {
611612
mPostUploadNotifier.incrementUploadedPostCountFromForegroundNotification(event.post);
612613
mPostUploadNotifier.updateNotificationErrorForPost(event.post, site, notificationMessage, 0);
613614
sFirstPublishPosts.remove(event.post.getId());
614-
sShouldRemoteAutoSavePosts.remove(event.post.getId());
615615
} else {
616616
mPostUploadNotifier.incrementUploadedPostCountFromForegroundNotification(event.post);
617617
boolean isFirstTimePublish = sFirstPublishPosts.remove(event.post.getId());
618-
sShouldRemoteAutoSavePosts.remove(event.post.getId());
619618
mPostUploadNotifier.updateNotificationSuccessForPost(event.post, site, isFirstTimePublish);
620619
if (isFirstTimePublish) {
621620
if (sCurrentUploadingPostAnalyticsProperties != null) {
@@ -651,7 +650,6 @@ public void onPostChanged(OnPostChanged event) {
651650
int postLocalId = ((RemoteAutoSavePost) event.causeOfChange).getLocalPostId();
652651
PostModel post = mPostStore.getPostByLocalPostId(postLocalId);
653652
SiteModel site = mSiteStore.getSiteByLocalId(post.getLocalSiteId());
654-
sShouldRemoteAutoSavePosts.remove(postLocalId);
655653
mPostUploadNotifier.incrementUploadedPostCountFromForegroundNotification(post);
656654
mPostUploadNotifier.updateNotificationSuccessForPost(post, site, false);
657655
finishUpload();

0 commit comments

Comments
 (0)