Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile Stories block #12939

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
7f4912a
added WPANdroid bridge interface OnStoryCreatorRequestListener
mzorz Sep 10, 2020
0735ef6
adapted the gutenberg bridge usage to receive Story block's mediaFile…
mzorz Sep 11, 2020
ae9a0c3
introducing StoriesPrefs to save serialized Stories slides so these c…
mzorz Sep 15, 2020
eaca337
fixed merge conflict
mzorz Sep 15, 2020
3298f03
added logic in onStoryComposerLoadRequested() to load a Story in the …
mzorz Sep 15, 2020
d5ba9a3
removed unused import
mzorz Sep 15, 2020
556c7cc
fixed bug that had the Activity start as many times as slides where a…
mzorz Sep 16, 2020
667a8db
removed unused import, removed comment
mzorz Sep 16, 2020
34f858e
fixed loading flattened slides for editing
mzorz Sep 16, 2020
e27fea5
fixed and added new test for onStoryDiscarded
mzorz Sep 16, 2020
a7be9d3
updated stories lib hash
mzorz Sep 16, 2020
2bc41c9
using site localid for slide retrieval from StoriesPrefs
mzorz Sep 16, 2020
9ad4a87
updated stories lib commit hash
mzorz Sep 16, 2020
e755a74
introducing LocalMediaId and RemoteMediaId data classes to enforce me…
mzorz Sep 16, 2020
9c032f6
using setUseTempCaptureFile on the stories library to keep captured m…
mzorz Sep 16, 2020
0232b7c
converting intent extra KEY_LAUNCHED_FROM_GUTENBERG to stories KEY_ST…
mzorz Sep 16, 2020
a35d6c2
implemented the GenericAnnouncementDialogProvider interface and showi…
mzorz Sep 16, 2020
3f5da8d
updated stories lib hash
mzorz Sep 16, 2020
8fa059d
initializing request codes right away in onCreate before calling supe…
mzorz Sep 18, 2020
df91b54
refactored code, introducing LoadStoryFromStoriesPrefsUseCase
mzorz Sep 18, 2020
448dffd
added path for story media not fetched locally
mzorz Sep 18, 2020
190b1b7
updated stories lib hash
mzorz Sep 18, 2020
4698ade
removed unused imports
mzorz Sep 18, 2020
143eb2e
updated dialog OK button label
mzorz Sep 18, 2020
587960f
fixed lint warnings
mzorz Sep 18, 2020
95903d9
updated commit hash for mobile gutenberg
mzorz Oct 1, 2020
8311a30
updated gutenbeg-mobile commit hash
mzorz Oct 1, 2020
91c81bc
udpated with develop, fixed merge conflicts
mzorz Oct 1, 2020
111378b
added missing method declaration
mzorz Oct 1, 2020
0f4d87c
refactored onStoryComposerLoadRequested logic into LoadStoryFromStori…
mzorz Oct 7, 2020
834be35
Update WordPress/src/main/java/org/wordpress/android/ui/posts/EditPos…
mzorz Oct 7, 2020
10a8a9e
Update WordPress/src/main/java/org/wordpress/android/ui/posts/editor/…
mzorz Oct 7, 2020
f6d92d2
made StoriesPrefs a @Singleton annotated injectable class
mzorz Oct 7, 2020
34d4eff
kotlinified expression
mzorz Oct 7, 2020
a0faf8a
Update WordPress/src/main/java/org/wordpress/android/ui/stories/prefs…
mzorz Oct 7, 2020
34631b7
Update WordPress/src/main/java/org/wordpress/android/ui/stories/useca…
mzorz Oct 7, 2020
aba2177
fixed method signature
mzorz Oct 7, 2020
df5b594
Update WordPress/src/main/java/org/wordpress/android/ui/stories/useca…
mzorz Oct 7, 2020
99efe00
using implicit getter
mzorz Oct 7, 2020
ddcda8b
using FluxC's LocalOrRemoteId sealed class variants
mzorz Oct 7, 2020
2c54019
made MediaUploadReadyProcessor injectable, and injecting SaveStoryGut…
mzorz Oct 8, 2020
cadf22b
modified comment
mzorz Oct 8, 2020
62fec15
adding specific error dialogs in case we dont find the backing media …
mzorz Oct 8, 2020
437c44b
Update WordPress/src/main/res/values/strings.xml
mzorz Oct 9, 2020
13e5bfd
removed comment
mzorz Oct 9, 2020
9f2ac0b
Merge branch 'try/jetpack-stories-block' of https://github.com/wordpr…
mzorz Oct 9, 2020
f74f63b
udpated gutenberg-mobile and submodules
mzorz Oct 9, 2020
0d193db
updated gutenberg-mobile hash
mzorz Oct 9, 2020
1f91b0f
updated gutenberg-mobile hash
mzorz Oct 9, 2020
78ed9db
updated gutenberg mobile commit hash to fix initial html data setup
mzorz Oct 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@
import org.wordpress.android.ui.themes.ThemeBrowserActivity;
import org.wordpress.android.ui.themes.ThemeBrowserFragment;
import org.wordpress.android.ui.uploads.MediaUploadHandler;
import org.wordpress.android.ui.uploads.MediaUploadReadyProcessor;
import org.wordpress.android.ui.uploads.PostUploadHandler;
import org.wordpress.android.ui.uploads.UploadService;
import org.wordpress.android.ui.whatsnew.FeatureAnnouncementDialogFragment;
Expand Down Expand Up @@ -584,6 +585,8 @@ public interface AppComponent extends AndroidInjector<WordPress> {

void inject(MediaPickerFragment object);

void inject(MediaUploadReadyProcessor object);

// Allows us to inject the application without having to instantiate any modules, and provides the Application
// in the app graph
@Component.Builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import java.util.List;
import java.util.Map;

import static com.wordpress.stories.util.BundleUtilsKt.KEY_STORY_INDEX;
import static org.wordpress.android.analytics.AnalyticsTracker.ACTIVITY_LOG_ACTIVITY_ID_KEY;
import static org.wordpress.android.analytics.AnalyticsTracker.Stat.POST_LIST_ACCESS_ERROR;
import static org.wordpress.android.analytics.AnalyticsTracker.Stat.READER_ARTICLE_DETAIL_REBLOGGED;
Expand All @@ -101,6 +102,8 @@
import static org.wordpress.android.login.LoginMode.WPCOM_LOGIN_ONLY;
import static org.wordpress.android.ui.media.MediaBrowserActivity.ARG_BROWSER_TYPE;
import static org.wordpress.android.ui.pages.PagesActivityKt.EXTRA_PAGE_REMOTE_ID_KEY;
import static org.wordpress.android.ui.stories.StoryComposerActivity.KEY_ALL_UNFLATTENED_LOADED_SLIDES;
import static org.wordpress.android.ui.stories.StoryComposerActivity.KEY_LAUNCHED_FROM_GUTENBERG;
import static org.wordpress.android.viewmodel.activitylog.ActivityLogDetailViewModelKt.ACTIVITY_LOG_ID_KEY;

public class ActivityLauncher {
Expand Down Expand Up @@ -719,6 +722,41 @@ public static void addNewStoryWithMediaUrisForResult(
activity.startActivityForResult(intent, RequestCodes.CREATE_STORY);
}

public static void editStoryWithMediaIdsForResult(
jd-alexander marked this conversation as resolved.
Show resolved Hide resolved
Activity activity,
SiteModel site,
long[] mediaIds,
boolean launchingFromGutenberg
) {
if (site == null) {
return;
}

Intent intent = new Intent(activity, StoryComposerActivity.class);
intent.putExtra(WordPress.SITE, site);
intent.putExtra(MediaBrowserActivity.RESULT_IDS, mediaIds);
activity.startActivityForResult(intent, RequestCodes.EDIT_STORY);
}

public static void editStoryForResult(
Activity activity,
SiteModel site,
int storyIndex,
boolean allStorySlidesAreEditable,
boolean launchedFromGutenberg
) {
if (site == null) {
return;
}

Intent intent = new Intent(activity, StoryComposerActivity.class);
intent.putExtra(WordPress.SITE, site);
intent.putExtra(KEY_STORY_INDEX, storyIndex);
intent.putExtra(KEY_LAUNCHED_FROM_GUTENBERG, launchedFromGutenberg);
intent.putExtra(KEY_ALL_UNFLATTENED_LOADED_SLIDES, allStorySlidesAreEditable);
activity.startActivityForResult(intent, RequestCodes.EDIT_STORY);
}

public static void editPostOrPageForResult(Activity activity, SiteModel site, PostModel post) {
editPostOrPageForResult(new Intent(activity, EditPostActivity.class), activity, site, post.getId(), false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,5 @@ public class RequestCodes {

// Story creator
public static final int CREATE_STORY = 8000;
public static final int EDIT_STORY = 8001;
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import org.wordpress.android.fluxc.action.AccountAction;
import org.wordpress.android.fluxc.generated.AccountActionBuilder;
import org.wordpress.android.fluxc.generated.EditorThemeActionBuilder;
import org.wordpress.android.fluxc.generated.MediaActionBuilder;
import org.wordpress.android.fluxc.generated.PostActionBuilder;
import org.wordpress.android.fluxc.generated.SiteActionBuilder;
import org.wordpress.android.fluxc.model.AccountModel;
Expand All @@ -94,9 +95,11 @@
import org.wordpress.android.fluxc.store.EditorThemeStore.FetchEditorThemePayload;
import org.wordpress.android.fluxc.store.EditorThemeStore.OnEditorThemeChanged;
import org.wordpress.android.fluxc.store.MediaStore;
import org.wordpress.android.fluxc.store.MediaStore.FetchMediaListPayload;
import org.wordpress.android.fluxc.store.MediaStore.MediaError;
import org.wordpress.android.fluxc.store.MediaStore.MediaErrorType;
import org.wordpress.android.fluxc.store.MediaStore.OnMediaChanged;
import org.wordpress.android.fluxc.store.MediaStore.OnMediaListFetched;
import org.wordpress.android.fluxc.store.MediaStore.OnMediaUploaded;
import org.wordpress.android.fluxc.store.PostStore;
import org.wordpress.android.fluxc.store.PostStore.OnPostChanged;
Expand Down Expand Up @@ -159,6 +162,8 @@
import org.wordpress.android.ui.prefs.SiteSettingsInterface;
import org.wordpress.android.ui.reader.utils.ReaderUtilsWrapper;
import org.wordpress.android.ui.stockmedia.StockMediaPickerActivity;
import org.wordpress.android.ui.stories.usecase.LoadStoryFromStoriesPrefsUseCase;
import org.wordpress.android.ui.stories.usecase.LoadStoryFromStoriesPrefsUseCase.ReCreateStoryResult;
import org.wordpress.android.ui.uploads.PostEvents;
import org.wordpress.android.ui.uploads.UploadService;
import org.wordpress.android.ui.uploads.UploadUtils;
Expand All @@ -180,6 +185,7 @@
import org.wordpress.android.util.LocaleManager;
import org.wordpress.android.util.LocaleManagerWrapper;
import org.wordpress.android.util.MediaUtils;
import org.wordpress.android.util.NetworkUtils;
import org.wordpress.android.util.PermissionUtils;
import org.wordpress.android.util.ReblogUtils;
import org.wordpress.android.util.ShortcutUtils;
Expand Down Expand Up @@ -384,13 +390,16 @@ enum RestartEditorOptions {
@Inject ModalLayoutPickerFeatureConfig mModalLayoutPickerFeatureConfig;
@Inject CrashLogging mCrashLogging;
@Inject MediaPickerLauncher mMediaPickerLauncher;
@Inject LoadStoryFromStoriesPrefsUseCase mLoadStoryFromStoriesPrefsUseCase;

private StorePostViewModel mViewModel;

private SiteModel mSite;
private SiteSettingsInterface mSiteSettings;
private boolean mIsJetpackSsoEnabled;

private boolean mNetworkErrorOnLastMediaFetchAttempt = false;

public static boolean checkToRestart(@NonNull Intent data) {
return data.hasExtra(EditPostActivity.EXTRA_RESTART_EDITOR)
&& RestartEditorOptions.valueOf(data.getStringExtra(EditPostActivity.EXTRA_RESTART_EDITOR))
Expand Down Expand Up @@ -613,6 +622,13 @@ protected void onCreate(Bundle savedInstanceState) {
}

if (!mIsNewPost) {
// if we are opening an existing Post, and it contains a Story block, pre-fetch the media in case
jd-alexander marked this conversation as resolved.
Show resolved Hide resolved
// the user wants to edit the block (we'll need to download it first if the slides images weren't
// created on this device)
if (PostUtils.contentContainsWPStoryGutenbergBlocks(mEditPostRepository.getPost().getContent())) {
fetchMediaList();
}

// 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(this, mEditPostRepository.getPost());
Expand Down Expand Up @@ -2108,7 +2124,8 @@ public Fragment getItem(int position) {
mIsNewPost,
gutenbergWebViewAuthorizationData,
mTenorFeatureConfig.isEnabled(),
gutenbergPropsBuilder
gutenbergPropsBuilder,
RequestCodes.EDIT_STORY
);
} else {
// If gutenberg editor is not selected, default to Aztec.
Expand Down Expand Up @@ -3049,6 +3066,44 @@ public void onTrackableEvent(TrackableEvent event, Map<String, String> propertie
mEditorTracker.trackEditorEvent(event, mEditorFragment.getEditorName(), properties);
}

@Override public void onStoryComposerLoadRequested(ArrayList<Object> mediaFiles, String blockId) {
jd-alexander marked this conversation as resolved.
Show resolved Hide resolved
ReCreateStoryResult result = mLoadStoryFromStoriesPrefsUseCase
.loadStoryFromMemoryOrRecreateFromPrefs(mSite, mediaFiles);
if (!result.getNoSlidesLoaded()) {
// Story instance loaded or re-created! Load it
ActivityLauncher.editStoryForResult(
this, mSite, result.getStoryIndex(), result.getAllStorySlidesAreEditable(), true
);
} else {
// unfortunately we couldn't even load the remote media Ids indicated by the StoryBlock so we can't allow
// editing at this time :(
if (mNetworkErrorOnLastMediaFetchAttempt) {
// there was an error fetching media when we were loading the editor,
// we *may* still have a possibility, tell the user they may try refreshing the media again
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(getString(R.string.dialog_edit_story_unavailable_title));
builder.setMessage(getString(R.string.dialog_edit_story_unavailable_message));
builder.setPositiveButton(R.string.dialog_button_ok, (dialog, id) -> {
// try another fetchMedia request
fetchMediaList();
dialog.dismiss();
});
AlertDialog dialog = builder.create();
dialog.show();
} else {
// unrecoverable error, nothing we can do, inform the user :(.
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(getString(R.string.dialog_edit_story_unrecoverable_title));
builder.setMessage(getString(R.string.dialog_edit_story_unrecoverable_message));
builder.setPositiveButton(R.string.dialog_button_ok, (dialog, id) -> {
dialog.dismiss();
});
AlertDialog dialog = builder.create();
dialog.show();
}
}
}

// FluxC events

@SuppressWarnings("unused")
Expand Down Expand Up @@ -3081,6 +3136,14 @@ public void onMediaUploaded(OnMediaUploaded event) {

// FluxC events

@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMediaListFetched(OnMediaListFetched event) {
jd-alexander marked this conversation as resolved.
Show resolved Hide resolved
if (event != null) {
mNetworkErrorOnLastMediaFetchAttempt = event.isError();
}
}

@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPostChanged(OnPostChanged event) {
Expand Down Expand Up @@ -3206,6 +3269,18 @@ private void refreshEditorTheme() {
mDispatcher.dispatch(EditorThemeActionBuilder.newFetchEditorThemeAction(payload));
}

private void fetchMediaList() {
// do not refresh if there is no network
if (!NetworkUtils.isNetworkAvailable(this)) {
jd-alexander marked this conversation as resolved.
Show resolved Hide resolved
mNetworkErrorOnLastMediaFetchAttempt = true;
return;
}
FetchMediaListPayload payload =
new FetchMediaListPayload(mSite, MediaStore.DEFAULT_NUM_MEDIA_PER_FETCH, false);
mDispatcher.dispatch(MediaActionBuilder.newFetchMediaListAction(payload));
}


@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onEditorThemeChanged(OnEditorThemeChanged event) {
Expand Down Expand Up @@ -3275,6 +3350,11 @@ public void syncPostObjectWithUiAndSaveIt(@Nullable OnPostUpdatedFromUIListener
WPMediaUtils.advertiseImageOptimization(this, listener::invoke);
}

@Override
public void onMediaModelsCreatedFromOptimizedUris(@NotNull Map<Uri, ? extends MediaModel> oldUriToMediaModels) {
// no op - we're not doing any special handling on MediaModels in EditPostActivity
}

@Override
public Consumer<Exception> getExceptionLogger() {
return (Exception e) -> AppLog.e(T.EDITOR, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ class AddLocalMediaToPostUseCase @Inject constructor(
optimizeMediaResult.optimizedMediaUris
)

// here we pass a map of "old" (before optimisation) Uris to the new MediaModels which contain
// both the mediaModel ids and the optimized media URLs.
// this way, the listener will be able to process from other models pointing to the old URLs
// and make any needed updates
editorMediaListener.onMediaModelsCreatedFromOptimizedUris(
uriList.zip(createMediaModelsResult.mediaModels).toMap()
)

// Add media to editor and optionally initiate upload
addToEditorAndOptionallyUpload(createMediaModelsResult.mediaModels, editorMediaListener, doUploadAfterAdding)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.wordpress.android.ui.posts.editor.media

import android.net.Uri
import org.wordpress.android.fluxc.model.MediaModel
import org.wordpress.android.fluxc.model.PostImmutableModel
import org.wordpress.android.ui.posts.EditPostActivity.OnPostUpdatedFromUIListener
import org.wordpress.android.util.helpers.MediaFile
Expand All @@ -8,5 +10,6 @@ interface EditorMediaListener {
fun appendMediaFiles(mediaFiles: Map<String, MediaFile>)
fun syncPostObjectWithUiAndSaveIt(listener: OnPostUpdatedFromUIListener? = null)
fun advertiseImageOptimization(listener: () -> Unit)
fun onMediaModelsCreatedFromOptimizedUris(oldUriToMediaFiles: Map<Uri, MediaModel>)
fun getImmutablePost(): PostImmutableModel
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package org.wordpress.android.ui.stories

import com.google.gson.Gson
import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId
import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId
import org.wordpress.android.fluxc.model.PostModel
import org.wordpress.android.ui.posts.EditPostRepository
import org.wordpress.android.ui.stories.prefs.StoriesPrefs
import org.wordpress.android.util.StringUtils
import org.wordpress.android.util.helpers.MediaFile
import javax.inject.Inject

class SaveStoryGutenbergBlockUseCase @Inject constructor() {
class SaveStoryGutenbergBlockUseCase @Inject constructor(
private val storiesPrefs: StoriesPrefs
) {
fun buildJetpackStoryBlockInPost(
editPostRepository: EditPostRepository,
mediaFiles: Map<String, MediaFile>
Expand Down Expand Up @@ -57,6 +62,27 @@ class SaveStoryGutenbergBlockUseCase @Inject constructor() {
id = mediaFile.mediaId.toInt()
link = mediaFile.fileURL
url = mediaFile.fileURL

// look for the slide saved with the local id key (mediaFile.id), and re-convert to mediaId.
val localIdKey = mediaFile.id.toInt()
val remoteIdKey = mediaFile.mediaId.toLong()
val localSiteId = post.localSiteId.toLong()
storiesPrefs.getSlideWithLocalId(
localSiteId,
LocalId(localIdKey)
)?.let {
it.id = mediaFile.mediaId // update the StoryFrameItem id to hold the same value as the remote mediaID
storiesPrefs.saveSlideWithRemoteId(
localSiteId,
RemoteId(remoteIdKey), // use the new mediaId as key
it
)
// now delete the old entry
storiesPrefs.deleteSlideWithLocalId(
localSiteId,
LocalId(localIdKey)
)
}
}
post.setContent(createGBStoryBlockStringFromJson(requireNotNull(storyBlockData)))
}
Expand Down
Loading