package org.wordpress.android.ui.posts;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.wordpress.android.R;
import org.wordpress.android.WordPress;
import org.wordpress.android.analytics.AnalyticsTracker;
import org.wordpress.android.analytics.AnalyticsTracker.Stat;
import org.wordpress.android.fluxc.Dispatcher;
import org.wordpress.android.fluxc.generated.PostActionBuilder;
import org.wordpress.android.fluxc.model.PostModel;
import org.wordpress.android.fluxc.model.SiteModel;
import org.wordpress.android.fluxc.model.post.PostStatus;
import org.wordpress.android.fluxc.store.PostStore;
import org.wordpress.android.fluxc.store.PostStore.OnPostChanged;
import org.wordpress.android.fluxc.store.PostStore.OnPostUploaded;
import org.wordpress.android.fluxc.store.PostStore.RemotePostPayload;
import org.wordpress.android.ui.ActivityLauncher;
import org.wordpress.android.ui.posts.services.PostEvents;
import org.wordpress.android.ui.posts.services.PostUploadService;
import org.wordpress.android.util.AnalyticsUtils;
import org.wordpress.android.util.AniUtils;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.NetworkUtils;
import org.wordpress.android.util.ToastUtils;
import javax.inject.Inject;
import de.greenrobot.event.EventBus;
public class PostPreviewActivity extends AppCompatActivity {
public static final String EXTRA_POST = "postModel";
private boolean mIsUpdatingPost;
private PostModel mPost;
private SiteModel mSite;
@Inject Dispatcher mDispatcher;
@Inject PostStore mPostStore;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((WordPress) getApplication()).component().inject(this);
setContentView(R.layout.post_preview_activity);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
}
if (savedInstanceState != null) {
mPost = (PostModel) savedInstanceState.getSerializable(EXTRA_POST);
} else {
mPost = (PostModel) getIntent().getSerializableExtra(EXTRA_POST);
}
if (savedInstanceState == null) {
mSite = (SiteModel) getIntent().getSerializableExtra(WordPress.SITE);
} else {
mSite = (SiteModel) savedInstanceState.getSerializable(WordPress.SITE);
}
if (mSite == null || mPost == null) {
ToastUtils.showToast(this, R.string.blog_not_found, ToastUtils.Duration.SHORT);
finish();
return;
}
setTitle(mPost.isPage() ? getString(R.string.preview_page) : getString(R.string.preview_post));
}
@Override
protected void onResume() {
super.onResume();
EventBus.getDefault().register(this);
mDispatcher.register(this);
if (mPost == null || (mPost = mPostStore.getPostByLocalPostId(mPost.getId())) == null) {
finish();
return;
}
if (hasPreviewFragment()) {
refreshPreview();
} else {
showPreviewFragment();
}
showMessageViewIfNecessary();
}
@Override
protected void onPause() {
EventBus.getDefault().unregister(this);
mDispatcher.unregister(this);
super.onPause();
}
private void showPreviewFragment() {
FragmentManager fm = getFragmentManager();
fm.executePendingTransactions();
String tagForFragment = getString(R.string.fragment_tag_post_preview);
Fragment fragment = PostPreviewFragment.newInstance(mSite, mPost);
fm.beginTransaction()
.replace(R.id.fragment_container, fragment, tagForFragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commitAllowingStateLoss();
}
private boolean hasPreviewFragment() {
return (getPreviewFragment() != null);
}
private PostPreviewFragment getPreviewFragment() {
String tagForFragment = getString(R.string.fragment_tag_post_preview);
Fragment fragment = getFragmentManager().findFragmentByTag(tagForFragment);
if (fragment != null) {
return (PostPreviewFragment) fragment;
} else {
return null;
}
}
private void refreshPreview() {
if (!isFinishing()) {
PostPreviewFragment fragment = getPreviewFragment();
if (fragment != null) {
fragment.setPost(mPost);
fragment.refreshPreview();
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putSerializable(WordPress.SITE, mSite);
outState.putSerializable(EXTRA_POST, mPost);
super.onSaveInstanceState(outState);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.post_preview, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
} else if (item.getItemId() == R.id.menu_edit) {
ActivityLauncher.editPostOrPageForResult(this, mSite, mPost);
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
/*
* if this is a local draft or has local changes, show the message explaining what these
* states mean, and hook up the publish and revert buttons
*/
private void showMessageViewIfNecessary() {
final ViewGroup messageView = (ViewGroup) findViewById(R.id.message_container);
if (mPost == null
|| mIsUpdatingPost
|| PostUploadService.isPostUploading(mPost)
|| (!mPost.isLocallyChanged() && !mPost.isLocalDraft())
&& PostStatus.fromPost(mPost) != PostStatus.DRAFT) {
messageView.setVisibility(View.GONE);
return;
}
TextView messageText = (TextView) messageView.findViewById(R.id.message_text);
if (mPost.isLocallyChanged()) {
messageText.setText(R.string.local_changes_explainer);
} else if (mPost.isLocalDraft()) {
messageText.setText(R.string.local_draft_explainer);
} else if (PostStatus.fromPost(mPost) == PostStatus.DRAFT) {
messageText.setText(R.string.draft_explainer);
}
// publish applies to both local draft and local changes
View btnPublish = messageView.findViewById(R.id.btn_publish);
btnPublish.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AniUtils.animateBottomBar(messageView, false);
publishPost();
}
});
// revert applies to only local changes
View btnRevert = messageView.findViewById(R.id.btn_revert);
btnRevert.setVisibility(mPost.isLocallyChanged() ? View.VISIBLE : View.GONE);
if (mPost.isLocallyChanged()) {
btnRevert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AniUtils.animateBottomBar(messageView, false);
revertPost();
AnalyticsTracker.track(Stat.EDITOR_DISCARDED_CHANGES);
}
});
}
// if both buttons are visible, show them below the message instead of to the right of it
if (mPost.isLocallyChanged()) {
RelativeLayout.LayoutParams paramsMessage = (RelativeLayout.LayoutParams) messageText.getLayoutParams();
// passing "0" removes the param (necessary since removeRule() is API 17+)
paramsMessage.addRule(RelativeLayout.LEFT_OF, 0);
paramsMessage.addRule(RelativeLayout.CENTER_VERTICAL, 0);
ViewGroup.MarginLayoutParams marginsMessage = (ViewGroup.MarginLayoutParams) messageText.getLayoutParams();
marginsMessage.bottomMargin = getResources().getDimensionPixelSize(R.dimen.margin_small);
ViewGroup buttonsView = (ViewGroup) messageView.findViewById(R.id.layout_buttons);
RelativeLayout.LayoutParams paramsButtons = (RelativeLayout.LayoutParams) buttonsView.getLayoutParams();
paramsButtons.addRule(RelativeLayout.BELOW, R.id.message_text);
ViewGroup.MarginLayoutParams marginsButtons = (ViewGroup.MarginLayoutParams) buttonsView.getLayoutParams();
marginsButtons.bottomMargin = getResources().getDimensionPixelSize(R.dimen.margin_large);
}
// first set message bar to invisible so it takes up space, then animate it in
// after a brief delay to give time for preview to render first
messageView.setVisibility(View.INVISIBLE);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (!isFinishing() && messageView.getVisibility() != View.VISIBLE) {
AniUtils.animateBottomBar(messageView, true);
}
}
}, 1000);
}
/*
* reverts local changes for this post, replacing it with the latest version from the server
*/
private void revertPost() {
if (isFinishing() || !NetworkUtils.checkConnection(this)) {
return;
}
if (mIsUpdatingPost) {
AppLog.d(AppLog.T.POSTS, "post preview > already updating post");
} else {
mIsUpdatingPost = true;
showProgress();
RemotePostPayload payload = new RemotePostPayload(mPost, mSite);
mDispatcher.dispatch(PostActionBuilder.newFetchPostAction(payload));
}
}
private void publishPost() {
if (!isFinishing() && NetworkUtils.checkConnection(this)) {
if (!mPost.isLocalDraft()) {
AnalyticsUtils.trackWithSiteDetails(AnalyticsTracker.Stat.EDITOR_UPDATED_POST, mSite);
}
if (PostStatus.fromPost(mPost) == PostStatus.DRAFT) {
// Remote draft being published
mPost.setStatus(PostStatus.PUBLISHED.toString());
PostUploadService.addPostToUploadAndTrackAnalytics(mPost);
} else if (mPost.isLocalDraft() && PostStatus.fromPost(mPost) == PostStatus.PUBLISHED) {
// Local draft being published
PostUploadService.addPostToUploadAndTrackAnalytics(mPost);
} else {
// Not a first-time publish
PostUploadService.addPostToUpload(mPost);
}
startService(new Intent(this, PostUploadService.class));
}
}
@SuppressWarnings("unused")
public void onEventMainThread(PostEvents.PostUploadStarted event) {
if (event.mLocalBlogId == mSite.getId()) {
showProgress();
}
}
private void showProgress() {
if (!isFinishing()) {
findViewById(R.id.progress).setVisibility(View.VISIBLE);
}
}
private void hideProgress() {
if (!isFinishing()) {
findViewById(R.id.progress).setVisibility(View.GONE);
}
}
@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPostChanged(OnPostChanged event) {
switch (event.causeOfChange) {
case UPDATE_POST:
mIsUpdatingPost = false;
hideProgress();
if (event.isError()) {
// TODO: Report error to user
AppLog.e(AppLog.T.POSTS, "UPDATE_POST failed: " + event.error.type + " - " + event.error.message);
} else {
mPost = mPostStore.getPostByLocalPostId(mPost.getId());
refreshPreview();
}
}
}
@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPostUploaded(OnPostUploaded event) {
if (event.post.getLocalSiteId() == mSite.getId()) {
hideProgress();
refreshPreview();
}
}
}