Skip to content

Commit

Permalink
Merge pull request #20607 from wordpress-mobile/issue/20164-conflict-…
Browse files Browse the repository at this point in the history
…resolution-dialog

Offline mode: Post conflict resolution overlay
  • Loading branch information
pantstamp authored Apr 12, 2024
2 parents 508fefc + 0f4f175 commit 0f6f547
Show file tree
Hide file tree
Showing 28 changed files with 1,324 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import org.wordpress.android.ui.posts.PostDatePickerDialogFragment;
import org.wordpress.android.ui.posts.PostListFragment;
import org.wordpress.android.ui.posts.PostNotificationScheduleTimeDialogFragment;
import org.wordpress.android.ui.posts.PostResolutionOverlayFragment;
import org.wordpress.android.ui.posts.PostSettingsListDialogFragment;
import org.wordpress.android.ui.posts.PostSettingsTagsFragment;
import org.wordpress.android.ui.posts.PostTimePickerDialogFragment;
Expand Down Expand Up @@ -555,4 +556,6 @@ public interface AppComponent {
void inject(WeekWidgetBlockListProviderFactory object);

void inject(WPMainNavigationView object);

void inject(PostResolutionOverlayFragment object);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.wordpress.android.ui.posts.EditorBloggingPromptsViewModel;
import org.wordpress.android.ui.posts.EditorJetpackSocialViewModel;
import org.wordpress.android.ui.posts.PostListMainViewModel;
import org.wordpress.android.ui.posts.PostResolutionOverlayViewModel;
import org.wordpress.android.ui.posts.editor.StorePostViewModel;
import org.wordpress.android.ui.posts.prepublishing.PrepublishingViewModel;
import org.wordpress.android.ui.posts.prepublishing.categories.PrepublishingCategoriesViewModel;
Expand Down Expand Up @@ -539,4 +540,9 @@ abstract class ViewModelModule {
@IntoMap
@ViewModelKey(EditorJetpackSocialViewModel.class)
abstract ViewModel editorJetpackSocialViewModel(EditorJetpackSocialViewModel viewModel);

@Binds
@IntoMap
@ViewModelKey(PostResolutionOverlayViewModel.class)
abstract ViewModel postResolutionOverlayViewModel(PostResolutionOverlayViewModel viewModel);
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ import org.wordpress.android.util.analytics.AnalyticsUtils
import org.wordpress.android.util.analytics.AnalyticsUtils.BlockEditorEnabledSource
import org.wordpress.android.util.config.ContactSupportFeatureConfig
import org.wordpress.android.util.config.GlobalStyleSupportFeatureConfig
import org.wordpress.android.util.config.SyncPublishingFeatureConfig
import org.wordpress.android.util.config.PostConflictResolutionFeatureConfig
import org.wordpress.android.util.extensions.setLiftOnScrollTargetViewIdAndRequestLayout
import org.wordpress.android.util.helpers.MediaFile
import org.wordpress.android.util.helpers.MediaGallery
Expand Down Expand Up @@ -403,7 +403,7 @@ class EditPostActivity : LocaleAwareActivity(), EditorFragmentActivity, EditorIm

@Inject lateinit var contactSupportFeatureConfig: ContactSupportFeatureConfig

@Inject lateinit var syncPublishingFeatureConfig: SyncPublishingFeatureConfig
@Inject lateinit var postConflictResolutionFeatureConfig: PostConflictResolutionFeatureConfig

@Inject lateinit var storePostViewModel: StorePostViewModel
@Inject lateinit var storageUtilsViewModel: StorageUtilsViewModel
Expand Down Expand Up @@ -593,7 +593,7 @@ class EditPostActivity : LocaleAwareActivity(), EditorFragmentActivity, EditorIm
updatingPostArea = findViewById(R.id.updating)

// check if post content needs updating
if (syncPublishingFeatureConfig.isEnabled()) {
if (postConflictResolutionFeatureConfig.isEnabled()) {
storePostViewModel.checkIfUpdatedPostVersionExists((editPostRepository), siteModel)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class PostActionHandler(
private val showToast: (ToastMessageHolder) -> Unit,
private val triggerPreviewStateUpdate: (PostListRemotePreviewState, PostInfoType) -> Unit,
private val copyPost: (SiteModel, PostModel, Boolean) -> Unit,
private val syncPublishingFeatureUtils: SyncPublishingFeatureUtils
private val postConflictResolutionFeatureUtils: PostConflictResolutionFeatureUtils
) {
private val criticalPostActionTracker = CriticalPostActionTracker(onStateChanged = {
invalidateList.invoke()
Expand Down Expand Up @@ -209,7 +209,7 @@ class PostActionHandler(
}
post.setStatus(DRAFT.toString())
dispatcher.dispatch(PostActionBuilder.newPushPostAction(
syncPublishingFeatureUtils.getRemotePostPayloadForPush(RemotePostPayload(post, site))
postConflictResolutionFeatureUtils.getRemotePostPayloadForPush(RemotePostPayload(post, site))
))

val localPostId = LocalId(post.id)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package org.wordpress.android.ui.posts

import org.wordpress.android.fluxc.store.PostStore.RemotePostPayload
import org.wordpress.android.util.config.SyncPublishingFeatureConfig
import org.wordpress.android.util.config.PostConflictResolutionFeatureConfig
import javax.inject.Inject

class SyncPublishingFeatureUtils @Inject constructor(
private val syncPublishingFeatureConfig: SyncPublishingFeatureConfig
class PostConflictResolutionFeatureUtils @Inject constructor(
private val postConflictResolutionFeatureConfig: PostConflictResolutionFeatureConfig
) {
private fun isSyncPublishingEnabled(): Boolean {
return syncPublishingFeatureConfig.isEnabled()
fun isPostConflictResolutionEnabled(): Boolean {
return postConflictResolutionFeatureConfig.isEnabled()
}

/**
Expand All @@ -21,7 +21,7 @@ class SyncPublishingFeatureUtils @Inject constructor(
* the remote version.
*/
fun getRemotePostPayloadForPush(payload: RemotePostPayload): RemotePostPayload {
if (isSyncPublishingEnabled().not()) {
if (isPostConflictResolutionEnabled().not()) {
payload.shouldSkipConflictResolutionCheck = true
}
return payload
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ private const val POST_TYPE = "post_type"
class PostListDialogHelper(
private val showDialog: (DialogHolder) -> Unit,
private val checkNetworkConnection: () -> Boolean,
private val analyticsTracker: AnalyticsTrackerWrapper
private val analyticsTracker: AnalyticsTrackerWrapper,
private val showConflictResolutionOverlay: ((PostResolutionOverlayActionEvent.ShowDialogAction) -> Unit)? = null,
private val isPostConflictResolutionEnabled: Boolean
) {
// Since we are using DialogFragments we need to hold onto which post will be published or trashed / resolved
private var localPostIdForDeleteDialog: Int? = null
Expand Down Expand Up @@ -115,28 +117,45 @@ class PostListDialogHelper(
}

fun showConflictedPostResolutionDialog(post: PostModel) {
val dialogHolder = DialogHolder(
tag = CONFIRM_ON_CONFLICT_LOAD_REMOTE_POST_DIALOG_TAG,
title = UiStringRes(R.string.dialog_confirm_load_remote_post_title),
message = UiStringText(PostUtils.getConflictedPostCustomStringForDialog(post)),
positiveButton = UiStringRes(R.string.dialog_confirm_load_remote_post_discard_local),
negativeButton = UiStringRes(R.string.dialog_confirm_load_remote_post_discard_web)
)
localPostIdForConflictResolutionDialog = post.id
showDialog.invoke(dialogHolder)
if (isPostConflictResolutionEnabled) {
showConflictResolutionOverlay?.invoke(
PostResolutionOverlayActionEvent.ShowDialogAction(
post,
PostResolutionType.SYNC_CONFLICT
)
)
} else {
val dialogHolder = DialogHolder(
tag = CONFIRM_ON_CONFLICT_LOAD_REMOTE_POST_DIALOG_TAG,
title = UiStringRes(R.string.dialog_confirm_load_remote_post_title),
message = UiStringText(PostUtils.getConflictedPostCustomStringForDialog(post)),
positiveButton = UiStringRes(R.string.dialog_confirm_load_remote_post_discard_local),
negativeButton = UiStringRes(R.string.dialog_confirm_load_remote_post_discard_web)
)
showDialog.invoke(dialogHolder)
}
}

fun showAutoSaveRevisionDialog(post: PostModel) {
analyticsTracker.track(UNPUBLISHED_REVISION_DIALOG_SHOWN, mapOf(POST_TYPE to "post"))
val dialogHolder = DialogHolder(
tag = CONFIRM_ON_AUTOSAVE_REVISION_DIALOG_TAG,
title = UiStringRes(R.string.dialog_confirm_autosave_title),
message = PostUtils.getCustomStringForAutosaveRevisionDialog(post),
positiveButton = UiStringRes(R.string.dialog_confirm_autosave_restore_button),
negativeButton = UiStringRes(R.string.dialog_confirm_autosave_dont_restore_button)
)
localPostIdForAutosaveRevisionResolutionDialog = post.id
showDialog.invoke(dialogHolder)
if (isPostConflictResolutionEnabled) {
showConflictResolutionOverlay?.invoke(
PostResolutionOverlayActionEvent.ShowDialogAction(
post, PostResolutionType.AUTOSAVE_REVISION_CONFLICT
)
)
} else {
analyticsTracker.track(UNPUBLISHED_REVISION_DIALOG_SHOWN, mapOf(POST_TYPE to "post"))
val dialogHolder = DialogHolder(
tag = CONFIRM_ON_AUTOSAVE_REVISION_DIALOG_TAG,
title = UiStringRes(R.string.dialog_confirm_autosave_title),
message = PostUtils.getCustomStringForAutosaveRevisionDialog(post),
positiveButton = UiStringRes(R.string.dialog_confirm_autosave_restore_button),
negativeButton = UiStringRes(R.string.dialog_confirm_autosave_dont_restore_button)
)
showDialog.invoke(dialogHolder)
}
}

fun showCopyConflictDialog(post: PostModel) {
Expand Down Expand Up @@ -256,4 +275,71 @@ class PostListDialogHelper(
)
}
}

fun onPostResolutionConfirmed(
event: PostResolutionOverlayActionEvent.PostResolutionConfirmationEvent,
updateConflictedPostWithRemoteVersion: (Int) -> Unit,
editRestoredAutoSavePost: (Int) -> Unit,
editLocalPost: (Int) -> Unit,
updateConflictedPostWithLocalVersion: (Int) -> Unit
) {
when (event.postResolutionType) {
PostResolutionType.AUTOSAVE_REVISION_CONFLICT -> {
handleAutosaveRevisionConflict(event, editRestoredAutoSavePost, editLocalPost)
}

PostResolutionType.SYNC_CONFLICT -> {
handleSyncRevisionConflict(
event,
updateConflictedPostWithLocalVersion,
updateConflictedPostWithRemoteVersion
)
}
}
}

private fun handleAutosaveRevisionConflict(
event: PostResolutionOverlayActionEvent.PostResolutionConfirmationEvent,
editRestoredAutoSavePost: (Int) -> Unit,
editLocalPost: (Int) -> Unit
) {
when (event.postResolutionConfirmationType) {
PostResolutionConfirmationType.CONFIRM_LOCAL -> {
localPostIdForAutosaveRevisionResolutionDialog?.let {
// open the editor with the local post (don't use the auto save version)
editLocalPost(it)
}
}

PostResolutionConfirmationType.CONFIRM_OTHER -> {
localPostIdForAutosaveRevisionResolutionDialog?.let {
// open the editor with the restored auto save
localPostIdForAutosaveRevisionResolutionDialog = null
editRestoredAutoSavePost(it)
}
}
}
}

private fun handleSyncRevisionConflict(
event: PostResolutionOverlayActionEvent.PostResolutionConfirmationEvent,
updateConflictedPostWithLocalVersion: (Int) -> Unit,
updateConflictedPostWithRemoteVersion: (Int) -> Unit
) {
when (event.postResolutionConfirmationType) {
PostResolutionConfirmationType.CONFIRM_LOCAL -> {
localPostIdForConflictResolutionDialog?.let {
updateConflictedPostWithLocalVersion(it)
}
}

PostResolutionConfirmationType.CONFIRM_OTHER -> {
localPostIdForConflictResolutionDialog?.let {
localPostIdForConflictResolutionDialog = null
// here load version from remote
updateConflictedPostWithRemoteVersion(it)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@ class PostListMainViewModel @Inject constructor(
@Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher,
@Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher,
private val uploadStarter: UploadStarter,
private val syncPublishingFeatureUtils: SyncPublishingFeatureUtils
private val postConflictResolutionFeatureUtils: PostConflictResolutionFeatureUtils
) : ViewModel(), CoroutineScope {
private var isStarted = false

private val lifecycleOwner = object : LifecycleOwner {
val lifecycleRegistry = LifecycleRegistry(this)
override val lifecycle: Lifecycle = lifecycleRegistry
Expand Down Expand Up @@ -128,6 +130,10 @@ class PostListMainViewModel @Inject constructor(
private val _dialogAction = SingleLiveEvent<DialogHolder>()
val dialogAction: LiveData<DialogHolder> = _dialogAction

private val _conflictResolutionAction = SingleLiveEvent<PostResolutionOverlayActionEvent.ShowDialogAction>()
val conflictResolutionAction: LiveData<PostResolutionOverlayActionEvent.ShowDialogAction> =
_conflictResolutionAction

private val _postUploadAction = SingleLiveEvent<PostUploadAction>()
val postUploadAction: LiveData<PostUploadAction> = _postUploadAction

Expand All @@ -150,8 +156,10 @@ class PostListMainViewModel @Inject constructor(
private val postListDialogHelper: PostListDialogHelper by lazy {
PostListDialogHelper(
showDialog = { _dialogAction.postValue(it) },
showConflictResolutionOverlay = { _conflictResolutionAction.postValue(it) },
checkNetworkConnection = this::checkNetworkConnection,
analyticsTracker = analyticsTracker
analyticsTracker = analyticsTracker,
isPostConflictResolutionEnabled = postConflictResolutionFeatureUtils.isPostConflictResolutionEnabled()
)
}

Expand Down Expand Up @@ -186,7 +194,7 @@ class PostListMainViewModel @Inject constructor(
showToast = { _toastMessage.postValue(it) },
triggerPreviewStateUpdate = this::updatePreviewAndDialogState,
copyPost = this::copyPost,
syncPublishingFeatureUtils = syncPublishingFeatureUtils
postConflictResolutionFeatureUtils = postConflictResolutionFeatureUtils
)
}

Expand Down Expand Up @@ -235,6 +243,7 @@ class PostListMainViewModel @Inject constructor(
currentBottomSheetPostId: LocalId,
editPostRepository: EditPostRepository
) {
if (isStarted) return
this.site = site
this.editPostRepository = editPostRepository

Expand Down Expand Up @@ -294,6 +303,8 @@ class PostListMainViewModel @Inject constructor(
savePostToDbUseCase.savePostToDb(editPostRepository, site)
})
}

isStarted = true
}

override fun onCleared() {
Expand Down Expand Up @@ -478,6 +489,17 @@ class PostListMainViewModel @Inject constructor(
)
}

// Post Resolution Overlay Actions
fun onPostResolutionConfirmed(event: PostResolutionOverlayActionEvent.PostResolutionConfirmationEvent) {
postListDialogHelper.onPostResolutionConfirmed(
event = event,
updateConflictedPostWithRemoteVersion = postConflictResolver::updateConflictedPostWithRemoteVersion,
editRestoredAutoSavePost = this::editRestoredAutoSavePost,
editLocalPost = this::editLocalPost,
updateConflictedPostWithLocalVersion = postConflictResolver::updateConflictedPostWithLocalVersion
)
}

private fun showPrepublishingBottomSheet(post: PostModel) {
currentBottomSheetPostId = LocalId(post.id)
editPostRepository.loadPostByLocalPostId(post.id)
Expand Down
Loading

0 comments on commit 0f6f547

Please sign in to comment.