package kr.kdev.dg1s.biowiki.ui.posts; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.text.TextUtils; import android.widget.Toast; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import org.wordpress.passcodelock.AppLockManager; import org.xmlpull.v1.XmlPullParserException; import org.xmlrpc.android.ApiHelper; import org.xmlrpc.android.XMLRPCClientInterface; import org.xmlrpc.android.XMLRPCException; import org.xmlrpc.android.XMLRPCFactory; import java.io.IOException; import java.util.Iterator; import kr.kdev.dg1s.biowiki.BioWiki; import kr.kdev.dg1s.biowiki.R; import kr.kdev.dg1s.biowiki.models.Blog; import kr.kdev.dg1s.biowiki.models.Post; import kr.kdev.dg1s.biowiki.models.PostStatus; import kr.kdev.dg1s.biowiki.ui.BWActionBarActivity; import kr.kdev.dg1s.biowiki.ui.MenuDrawerItem; import kr.kdev.dg1s.biowiki.ui.notifications.NotificationsActivity; import kr.kdev.dg1s.biowiki.util.AlertUtil; import kr.kdev.dg1s.biowiki.util.AppLog; import kr.kdev.dg1s.biowiki.util.BWAlertDialogFragment; import kr.kdev.dg1s.biowiki.util.BWMeShortlinks; import kr.kdev.dg1s.biowiki.util.BWMobileStatsUtil; public class PostsActivity extends BWActionBarActivity implements PostsListFragment.OnPostSelectedListener, PostsListFragment.OnSinglePostLoadedListener, PostsListFragment.OnPostActionListener, ViewPostFragment.OnDetailPostActionListener, BWAlertDialogFragment.OnDialogConfirmListener { public static final String EXTRA_VIEW_PAGES = "viewPages"; public static final String EXTRA_ERROR_MSG = "errorMessage"; public static final String EXTRA_ERROR_INFO_TITLE = "errorInfoTitle"; public static final String EXTRA_ERROR_INFO_LINK = "errorInfoLink"; public static final int POST_DELETE = 0, POST_SHARE = 1, POST_EDIT = 2, POST_CLEAR = 3, POST_VIEW = 5; public static final int ACTIVITY_EDIT_POST = 0; private static final int ID_DIALOG_DELETING = 1, ID_DIALOG_SHARE = 2; public ProgressDialog mLoadingDialog; public boolean mIsPage = false; public String mErrorMsg = ""; private PostsListFragment mPostList; private FragmentManager.OnBackStackChangedListener mOnBackStackChangedListener = new FragmentManager.OnBackStackChangedListener() { public void onBackStackChanged() { if (getSupportFragmentManager().getBackStackEntryCount() == 0) mMenuDrawer.setDrawerIndicatorEnabled(true); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Special check for a null database (see #507) if (BioWiki.wpDB == null) { Toast.makeText(this, R.string.fatal_db_error, Toast.LENGTH_LONG).show(); finish(); return; } // Check if we came from a notification, if so let's launch NotificationsActivity Bundle extras = getIntent().getExtras(); if (extras != null && extras.getBoolean(NotificationsActivity.FROM_NOTIFICATION_EXTRA)) { startNotificationsActivity(extras); return; } // Restore last selection on app creation if (BioWiki.shouldRestoreSelectedActivityBIOWIKI && BioWiki.getCurrentBlog() != null && !(this instanceof PagesActivity)) { // Refresh blog content when returning to the app new ApiHelper.RefreshBlogContentTask(this, BioWiki.getCurrentBlog(), new RefreshBlogContentCallback()) .execute(false); BioWiki.shouldRestoreSelectedActivityBIOWIKI = false; SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); int lastActivitySelection = settings.getInt(LAST_ACTIVITY_PREFERENCE, -1); if (lastActivitySelection > MenuDrawerItem.NO_ITEM_ID && lastActivitySelection != BWActionBarActivity.DASHBOARD_ACTIVITY) { Iterator<MenuDrawerItem> itemIterator = mMenuItems.iterator(); while (itemIterator.hasNext()) { MenuDrawerItem item = itemIterator.next(); // if we have a matching item id, and it's not selected and it's visible, call it if (item.hasItemId() && item.getItemId() == lastActivitySelection && !item.isSelected() && item.isVisible()) { mFirstLaunch = true; item.selectItem(); finish(); return; } } } } createMenuDrawer(R.layout.posts); ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayShowTitleEnabled(true); FragmentManager fm = getSupportFragmentManager(); fm.addOnBackStackChangedListener(mOnBackStackChangedListener); mPostList = (PostsListFragment) fm.findFragmentById(R.id.postList); if (extras != null) { mIsPage = extras.getBoolean(EXTRA_VIEW_PAGES); showErrorDialogIfNeeded(extras); } if (mIsPage) setTitle(getString(R.string.pages)); else setTitle(getString(R.string.posts)); BioWiki.currentPost = null; if (savedInstanceState != null) popPostDetail(); attemptToSelectPost(); BWMobileStatsUtil.trackEventForWPCom(statEventForViewOpening()); } private void showPostUploadErrorAlert(String errorMessage, String infoTitle, final String infoURL) { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(PostsActivity.this); dialogBuilder.setTitle(getResources().getText(R.string.error)); dialogBuilder.setMessage(errorMessage); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } } ); if (infoTitle != null && infoURL != null) { dialogBuilder.setNeutralButton(infoTitle, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(infoURL))); } } ); } dialogBuilder.setCancelable(true); if (!isFinishing()) dialogBuilder.create().show(); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Bundle extras = intent.getExtras(); if (extras != null) { // Check if we came from a notification, if so let's launch NotificationsActivity if (extras.getBoolean(NotificationsActivity.FROM_NOTIFICATION_EXTRA)) { startNotificationsActivity(extras); return; } } } private void showErrorDialogIfNeeded(Bundle extras) { if (extras == null) { return; } String errorMessage = extras.getString(EXTRA_ERROR_MSG); if (!TextUtils.isEmpty(errorMessage)) { String errorInfoTitle = extras.getString(EXTRA_ERROR_INFO_TITLE); String errorInfoLink = extras.getString(EXTRA_ERROR_INFO_LINK); showPostUploadErrorAlert(errorMessage, errorInfoTitle, errorInfoLink); } } private void startNotificationsActivity(Bundle extras) { // Manually set last selection to notifications SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences.Editor editor = settings.edit(); editor.putInt(LAST_ACTIVITY_PREFERENCE, NOTIFICATIONS_ACTIVITY); editor.commit(); Intent i = new Intent(this, NotificationsActivity.class); i.putExtras(extras); startActivity(i); finish(); } public boolean isRefreshing() { return mPostList.isRefreshing(); } public void setRefreshing(boolean refreshing) { mPostList.setRefreshing(refreshing); } public void checkForLocalChanges(boolean shouldPrompt) { if (BioWiki.getCurrentBlog() == null) { return; } boolean hasLocalChanges = BioWiki.wpDB.findLocalChanges(BioWiki.getCurrentBlog().getLocalTableBlogId(), mIsPage); if (hasLocalChanges) { if (!shouldPrompt) { return; } AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(PostsActivity.this); dialogBuilder.setTitle(getResources().getText(R.string.local_changes)); dialogBuilder.setMessage(getResources().getText(R.string.remote_changes)); dialogBuilder.setPositiveButton(getResources().getText(R.string.yes), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { popPostDetail(); attemptToSelectPost(); mPostList.requestPosts(false); } } ); dialogBuilder.setNegativeButton(getResources().getText(R.string.no), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { mPostList.setRefreshing(false); } }); dialogBuilder.setCancelable(true); if (!isFinishing()) { dialogBuilder.create().show(); } } else { popPostDetail(); mPostList.requestPosts(false); mPostList.setRefreshing(true); } } protected void popPostDetail() { FragmentManager fm = getSupportFragmentManager(); ViewPostFragment f = (ViewPostFragment) fm.findFragmentById(R.id.postDetail); if (f == null) { try { fm.popBackStack(); } catch (RuntimeException e) { AppLog.e(AppLog.T.POSTS, e); } } } @Override protected void onResume() { super.onResume(); if (BioWiki.isSignedIn(PostsActivity.this)) { // showReaderIfNoBlog(); } if (BioWiki.postsShouldRefresh) { checkForLocalChanges(false); mPostList.setRefreshing(true); BioWiki.postsShouldRefresh = false; } } @Override protected void onPause() { super.onPause(); } @Override protected void onDestroy() { BWMobileStatsUtil.trackEventForWPComWithSavedProperties(statEventForViewClosing()); super.onDestroy(); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getSupportMenuInflater(); inflater.inflate(R.menu.posts, menu); if (mIsPage) { menu.findItem(R.id.menu_new_post).setTitle(R.string.new_page); } return true; } public void newPost() { BWMobileStatsUtil.trackEventForWPCom(statEventForNewPost()); if (BioWiki.getCurrentBlog() == null) { if (!isFinishing()) Toast.makeText(this, R.string.blog_not_found, Toast.LENGTH_SHORT).show(); return; } // Create a new post object Post newPost = new Post(BioWiki.getCurrentBlog().getLocalTableBlogId(), mIsPage); BioWiki.wpDB.savePost(newPost); Intent i = new Intent(this, EditPostActivity.class); i.putExtra(EditPostActivity.EXTRA_POSTID, newPost.getLocalTablePostId()); i.putExtra(EditPostActivity.EXTRA_IS_PAGE, mIsPage); i.putExtra(EditPostActivity.EXTRA_IS_NEW_POST, true); startActivityForResult(i, ACTIVITY_EDIT_POST); } @Override public boolean onOptionsItemSelected(final MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.menu_new_post) { newPost(); return true; } else if (itemId == android.R.id.home) { FragmentManager fm = getSupportFragmentManager(); if (fm.getBackStackEntryCount() > 0) { popPostDetail(); return true; } } return super.onOptionsItemSelected(item); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (data != null) { if (requestCode == ACTIVITY_EDIT_POST && resultCode == RESULT_OK) { if (data.getBooleanExtra("shouldRefresh", false)) { mPostList.getPostListAdapter().loadPosts(); } } } super.onActivityResult(requestCode, resultCode, data); } protected void attemptToSelectPost() { FragmentManager fm = getSupportFragmentManager(); ViewPostFragment f = (ViewPostFragment) fm.findFragmentById(R.id.postDetail); if (f != null && f.isInLayout()) { mPostList.setShouldSelectFirstPost(true); } } @Override public void onPostSelected(Post post) { FragmentManager fm = getSupportFragmentManager(); ViewPostFragment f = (ViewPostFragment) fm .findFragmentById(R.id.postDetail); if (post != null) { BioWiki.currentPost = post; if (f == null || !f.isInLayout()) { FragmentTransaction ft = fm.beginTransaction(); ft.hide(mPostList); f = new ViewPostFragment(); ft.add(R.id.postDetailFragmentContainer, f); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); ft.addToBackStack(null); ft.commitAllowingStateLoss(); mMenuDrawer.setDrawerIndicatorEnabled(false); } else { f.loadPost(post); } } } @Override protected Dialog onCreateDialog(int id) { mLoadingDialog = new ProgressDialog(this); if (id == ID_DIALOG_DELETING) { mLoadingDialog.setMessage(getResources().getText( mIsPage ? R.string.deleting_page : R.string.deleting_post)); mLoadingDialog.setCancelable(false); return mLoadingDialog; } else if (id == ID_DIALOG_SHARE) { mLoadingDialog.setMessage(mIsPage ? getString(R.string.share_url_page) : getString( R.string.share_url_post)); mLoadingDialog.setCancelable(false); return mLoadingDialog; } return super.onCreateDialog(id); } protected String statEventForViewOpening() { return BWMobileStatsUtil.StatsEventPostsOpened; } protected String statEventForViewClosing() { return BWMobileStatsUtil.StatsEventPostsClosed; } protected String statEventForNewPost() { return BWMobileStatsUtil.StatsEventPostsClickedNewPost; } protected void refreshComments() { new refreshCommentsTask().execute(); } @Override public void onPostAction(int action, final Post post) { // No post? No service. if (post == null) { Toast.makeText(PostsActivity.this, R.string.post_not_found, Toast.LENGTH_SHORT).show(); return; } if (action == POST_DELETE) { BWMobileStatsUtil.flagProperty(statEventForViewClosing(), BWMobileStatsUtil.StatsPropertyPostDetailClickedDelete); if (post.isLocalDraft()) { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder( PostsActivity.this); dialogBuilder.setTitle(getResources().getText( R.string.delete_draft)); dialogBuilder.setMessage(getResources().getText( R.string.delete_sure) + " '" + post.getTitle() + "'?"); dialogBuilder.setPositiveButton( getResources().getText(R.string.yes), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { BioWiki.wpDB.deletePost(post); popPostDetail(); attemptToSelectPost(); mPostList.getPostListAdapter().loadPosts(); } } ); dialogBuilder.setNegativeButton( getResources().getText(R.string.no), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } } ); dialogBuilder.setCancelable(true); if (!isFinishing()) { dialogBuilder.create().show(); } } else { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder( PostsActivity.this); dialogBuilder.setTitle(getResources().getText( (post.isPage()) ? R.string.delete_page : R.string.delete_post )); dialogBuilder.setMessage(getResources().getText( (post.isPage()) ? R.string.delete_sure_page : R.string.delete_sure_post ) + " '" + post.getTitle() + "'?"); dialogBuilder.setPositiveButton( getResources().getText(R.string.yes), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { new deletePostTask().execute(post); } } ); dialogBuilder.setNegativeButton( getResources().getText(R.string.no), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } } ); dialogBuilder.setCancelable(true); if (!isFinishing()) { dialogBuilder.create().show(); } } } else if (action == POST_SHARE) { // Only share published posts if (post.getStatusEnum() != PostStatus.PUBLISHED && post.getStatusEnum() != PostStatus.SCHEDULED) { AlertUtil.showAlert(this, R.string.error, post.isPage() ? R.string.page_not_published : R.string.post_not_published); return; } Intent share = new Intent(Intent.ACTION_SEND); share.setType("text/plain"); share.putExtra(Intent.EXTRA_SUBJECT, post.getTitle()); String shortlink = BWMeShortlinks.getPostShortlink(BioWiki.getCurrentBlog(), post); share.putExtra(Intent.EXTRA_TEXT, shortlink != null ? shortlink : post.getPermaLink()); startActivity(Intent.createChooser(share, getResources() .getText(R.string.share_url))); AppLockManager.getInstance().setExtendedTimeout(); BWMobileStatsUtil.flagProperty(statEventForViewClosing(), BWMobileStatsUtil.StatsPropertyPostDetailClickedShare); } else if (action == POST_CLEAR) { FragmentManager fm = getSupportFragmentManager(); ViewPostFragment f = (ViewPostFragment) fm .findFragmentById(R.id.postDetail); if (f != null) { f.clearContent(); } } else if (action == POST_EDIT) { BWMobileStatsUtil.flagProperty(statEventForViewClosing(), BWMobileStatsUtil.StatsPropertyPostDetailClickedEdit); } else if (action == POST_VIEW) { BWMobileStatsUtil.flagProperty(statEventForViewClosing(), BWMobileStatsUtil.StatsPropertyPostDetailClickedPreview); } } @Override public void onDetailPostAction(int action, Post post) { onPostAction(action, post); } @Override public void onDialogConfirm() { mPostList.requestPosts(true); mPostList.setRefreshing(true); } @Override public void onSinglePostLoaded() { popPostDetail(); } @Override public void onSaveInstanceState(Bundle outState) { if (outState.isEmpty()) { outState.putBoolean("bug_19917_fix", true); } super.onSaveInstanceState(outState); } @Override public void onBlogChanged() { super.onBlogChanged(); popPostDetail(); attemptToSelectPost(); mPostList.clear(); mPostList.getPostListAdapter().loadPosts(); new ApiHelper.RefreshBlogContentTask(this, BioWiki.getCurrentBlog(), null).execute(false); mPostList.onBlogChanged(); } public class deletePostTask extends AsyncTask<Post, Void, Boolean> { Post post; @Override protected void onPreExecute() { // pop out of the detail view if on a smaller screen popPostDetail(); showDialog(ID_DIALOG_DELETING); } @Override protected void onPostExecute(Boolean result) { dismissDialog(ID_DIALOG_DELETING); attemptToSelectPost(); if (result) { Toast.makeText(PostsActivity.this, getResources().getText((mIsPage) ? R.string.page_deleted : R.string.post_deleted), Toast.LENGTH_SHORT ).show(); checkForLocalChanges(false); BioWiki.wpDB.deletePost(post); mPostList.requestPosts(false); mPostList.setRefreshing(true); } else { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(PostsActivity.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); dialogBuilder.setMessage(mErrorMsg); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } } ); dialogBuilder.setCancelable(true); if (!isFinishing()) { dialogBuilder.create().show(); } } } @Override protected Boolean doInBackground(Post... params) { boolean result = false; post = params[0]; Blog blog = BioWiki.currentBlog; XMLRPCClientInterface client = XMLRPCFactory.instantiate(blog.getUri(), blog.getHttpuser(), blog.getHttppassword()); Object[] postParams = {"", post.getRemotePostId(), BioWiki.currentBlog.getUsername(), BioWiki.currentBlog.getPassword()}; Object[] pageParams = {BioWiki.currentBlog.getRemoteBlogId(), BioWiki.currentBlog.getUsername(), BioWiki.currentBlog.getPassword(), post.getRemotePostId()}; try { client.call((mIsPage) ? "wp.deletePage" : "blogger.deletePost", (mIsPage) ? pageParams : postParams); result = true; } catch (final XMLRPCException e) { mErrorMsg = prepareErrorMessage(e); } catch (IOException e) { mErrorMsg = prepareErrorMessage(e); } catch (XmlPullParserException e) { mErrorMsg = prepareErrorMessage(e); } return result; } private String prepareErrorMessage(Exception e) { AppLog.e(AppLog.T.POSTS, "Error while deleting post or page", e); return String.format(getResources().getString(R.string.error_delete_post), (mIsPage) ? getResources().getText(R.string.page) : getResources().getText(R.string.post) ); } } public class refreshCommentsTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { Object[] commentParams = {BioWiki.currentBlog.getRemoteBlogId(), BioWiki.currentBlog.getUsername(), BioWiki.currentBlog.getPassword()}; try { ApiHelper.refreshComments(PostsActivity.this, BioWiki.currentBlog, commentParams); } catch (final Exception e) { mErrorMsg = getResources().getText(R.string.error_generic).toString(); } return null; } } public class RefreshBlogContentCallback implements ApiHelper.GenericCallback { @Override public void onSuccess() { if (isFinishing()) { return; } updateMenuDrawer(); mPostList.setRefreshing(false); } @Override public void onFailure(ApiHelper.ErrorType errorType, String errorMessage, Throwable throwable) { if (isFinishing()) { return; } mPostList.setRefreshing(false); } } }