package org.wordpress.android.ui.posts; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Serializable; import java.lang.reflect.Type; import java.net.URL; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Vector; import android.app.Activity; import android.app.AlertDialog; import android.app.DatePickerDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.app.TimePickerDialog; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.provider.MediaStore; import android.text.Editable; import android.text.Html; import android.text.Layout; import android.text.Selection; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextWatcher; import android.text.format.DateUtils; import android.text.method.ArrowKeyMovementMethod; import android.text.style.AlignmentSpan; import android.text.style.QuoteSpan; import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; import android.text.style.URLSpan; import android.view.ContextMenu; import android.view.Display; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnFocusChangeListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.WindowManager; import android.view.animation.AlphaAnimation; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.DatePicker; import android.widget.EditText; import android.widget.ImageButton; import android.widget.RelativeLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.Spinner; import android.widget.TextView; import android.widget.TimePicker; import android.widget.Toast; import android.widget.ToggleButton; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockActivity; import com.actionbarsherlock.view.MenuInflater; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.justsystems.hpb.pad.R; import com.justsystems.hpb.pad.seo.SeoResultActivity; import org.xmlrpc.android.ApiHelper; import org.wordpress.android.Constants; import org.wordpress.android.WordPress; import org.wordpress.android.lockmanager.AppLockManager; import org.wordpress.android.models.Blog; import org.wordpress.android.models.Post; import org.wordpress.android.models.Postable; import org.wordpress.android.ui.accounts.NewAccountActivity; import org.wordpress.android.util.DeviceUtils; import org.wordpress.android.util.ImageHelper; import org.wordpress.android.util.PostUploadService; import org.wordpress.android.util.StringUtils; import org.wordpress.android.util.WPEditText; import org.wordpress.android.util.WPHtml; import org.wordpress.android.util.WPImageSpan; import org.wordpress.android.util.WPUnderlineSpan; public abstract class AbsEditActivity extends SherlockActivity implements OnClickListener, OnTouchListener, TextWatcher, WPEditText.OnSelectionChangedListener, OnFocusChangeListener, WPEditText.EditTextImeBackListener { private static final int AUTOSAVE_DELAY_MILLIS = 60000; protected static final int ACTIVITY_REQUEST_CODE_PICTURE_LIBRARY = 0; protected static final int ACTIVITY_REQUEST_CODE_TAKE_PHOTO = 1; protected static final int ACTIVITY_REQUEST_CODE_VIDEO_LIBRARY = 2; protected static final int ACTIVITY_REQUEST_CODE_TAKE_VIDEO = 3; protected static final int ACTIVITY_REQUEST_CODE_CREATE_LINK = 4; protected static final int ACTIVITY_REQUEST_CODE_SELECT_CATEGORIES = 5; private static final int ID_DIALOG_DATE = 0; private static final int ID_DIALOG_TIME = 1; private static final int ID_DIALOG_LOADING = 2; private static final int ID_DIALOG_DOWNLOAD = 3; private static final int ID_DIALOG_SEO_ALERT = 4; private static final String CATEGORY_PREFIX_TAG = "category-"; protected Blog mBlog; protected Postable mPostable; // Used to restore post content if 'Discard' is chosen when leaving the editor. private Post mOriginalPost; protected ArrayList<String> mCategories; protected WPEditText mContentEditText; protected ImageButton mAddPictureButton; protected Spinner mStatusSpinner; protected EditText mTitleEditText, mPasswordEditText, mTagsEditText, mExcerptEditText; protected TextView mLocationText, mPubDateText; private ToggleButton mBoldToggleButton, mEmToggleButton, mBquoteToggleButton; private ToggleButton mUnderlineToggleButton, mStrikeToggleButton; private Button mPubDateButton, mLinkButton, mMoreButton, seoButton; private RelativeLayout mFormatBar; private Handler mAutoSaveHandler; protected boolean mIsPage = false; protected boolean mIsNew = false; protected String typeName; protected boolean mLocalDraft = false; protected boolean mIsCustomPubDate = false; private boolean mIsBackspace = false; private boolean mScrollDetected = false; protected List<String> mSelectedCategories; private String mAccountName = ""; protected int mQuickMediaType = -1; private String mMediaCapturePath = ""; protected String[] mPostFormats = null; private String[] mPostFormatTitles = null; protected int mBlogID = -1; protected long mPostID = -1; protected long mCustomPubDate = 0; private int mYear, mMonth, mDay, mHour, mMinute; private int mStyleStart, mSelectionStart, mSelectionEnd; private int mLastPosition = -1; private int mCurrentActivityRequest = -1; private float mLastYPos = 0; private boolean calledFromList; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle extras = getIntent().getExtras(); ActionBar actionBar = getSupportActionBar(); actionBar.setHomeButtonEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true); Calendar c = Calendar.getInstance(); mYear = c.get(Calendar.YEAR); mMonth = c.get(Calendar.MONTH); mDay = c.get(Calendar.DAY_OF_MONTH); mHour = c.get(Calendar.HOUR_OF_DAY); mMinute = c.get(Calendar.MINUTE); mAutoSaveHandler = new Handler(); String action = getIntent().getAction(); if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) { // we arrived here from a share action if (!selectBlogForShareAction()) return; } else { initBlog(); if (extras != null) { mAccountName = StringUtils.unescapeHTML(extras .getString("accountName")); mPostID = extras.getLong("postID"); mLocalDraft = extras.getBoolean("localDraft", false); mIsPage = extras.getBoolean("isPage", false); mIsNew = extras.getBoolean("isNew", false); calledFromList = extras.getBoolean("fromList", true); typeName = getIntent().getStringExtra("type_name"); if (savedInstanceState != null) { mCurrentActivityRequest = savedInstanceState .getInt("currentActivityRequest"); if (savedInstanceState.getString("mediaCapturePath") != null) mMediaCapturePath = savedInstanceState .getString("mediaCapturePath"); } else { mQuickMediaType = extras.getInt("quick-media", -1); } if (extras.getBoolean("isQuickPress")) { mBlogID = extras.getInt("id"); } else { mBlogID = WordPress.currentBlog.getId(); } try { mBlog = new Blog(mBlogID); WordPress.currentBlog = mBlog; } catch (Exception e) { showBlogErrorAndFinish(); return; } if (!mIsNew) { try { mPostable = createPost(); if (mPostable == null) { // big oopsie Toast.makeText( this, getResources().getText( R.string.post_not_found), Toast.LENGTH_LONG).show(); finish(); return; } else { WordPress.setCurrentPost(mPostable); mOriginalPost = new Post(mBlogID, mPostID, mIsPage); } } catch (Exception e) { e.printStackTrace(); finish(); } } } if (mIsNew) { mLocalDraft = true; setTitle(StringUtils.unescapeHTML(WordPress.getCurrentBlog() .getBlogName()) + " - " + getString((mIsPage) ? R.string.new_page : R.string.new_post)); } else { setTitle(StringUtils.unescapeHTML(WordPress.getCurrentBlog() .getBlogName()) + " - " + getString((mIsPage) ? R.string.edit_page : R.string.edit_post)); } } setContentView(R.layout.edit); mContentEditText = (WPEditText) findViewById(R.id.postContent); mTitleEditText = (EditText) findViewById(R.id.title); mExcerptEditText = (EditText) findViewById(R.id.postExcerpt); mPasswordEditText = (EditText) findViewById(R.id.post_password); mLocationText = (TextView) findViewById(R.id.locationText); mBoldToggleButton = (ToggleButton) findViewById(R.id.bold); mEmToggleButton = (ToggleButton) findViewById(R.id.em); mBquoteToggleButton = (ToggleButton) findViewById(R.id.bquote); mUnderlineToggleButton = (ToggleButton) findViewById(R.id.underline); mStrikeToggleButton = (ToggleButton) findViewById(R.id.strike); mAddPictureButton = (ImageButton) findViewById(R.id.addPictureButton); mPubDateButton = (Button) findViewById(R.id.pubDateButton); mPubDateText = (TextView) findViewById(R.id.pubDate); seoButton = (Button) findViewById(R.id.seoButton); mLinkButton = (Button) findViewById(R.id.link); mMoreButton = (Button) findViewById(R.id.more); mStatusSpinner = (Spinner) findViewById(R.id.status); mFormatBar = (RelativeLayout) findViewById(R.id.formatBar); // Set header labels to upper case ((TextView) findViewById(R.id.categoryLabel)).setText(getResources() .getString(R.string.categories).toUpperCase()); ((TextView) findViewById(R.id.statusLabel)).setText(getResources() .getString(R.string.status).toUpperCase()); ((TextView) findViewById(R.id.postFormatLabel)).setText(getResources() .getString(R.string.post_format).toUpperCase()); ((TextView) findViewById(R.id.pubDateLabel)).setText(getResources() .getString(R.string.publish_date).toUpperCase()); if (mIsPage) { // remove post specific views mExcerptEditText.setVisibility(View.GONE); (findViewById(R.id.sectionTags)).setVisibility(View.GONE); (findViewById(R.id.sectionCategories)).setVisibility(View.GONE); (findViewById(R.id.sectionLocation)).setVisibility(View.GONE); (findViewById(R.id.postFormatLabel)).setVisibility(View.GONE); (findViewById(R.id.postFormat)).setVisibility(View.GONE); } else { if (mBlog.getPostFormats().equals("")) { List<Object> args = new Vector<Object>(); args.add(mBlog); args.add(this); new ApiHelper.getPostFormatsTask().execute(args); mPostFormatTitles = getResources().getStringArray( R.array.post_formats_array); String defaultPostFormatTitles[] = { "aside", "audio", "chat", "gallery", "image", "link", "quote", "standard", "status", "video" }; mPostFormats = defaultPostFormatTitles; } else { try { Gson gson = new Gson(); Type type = new TypeToken<Map<String, String>>() { }.getType(); Map<String, String> jsonPostFormats = gson.fromJson( mBlog.getPostFormats(), type); mPostFormats = new String[jsonPostFormats.size()]; mPostFormatTitles = new String[jsonPostFormats.size()]; int i = 0; for (Map.Entry<String, String> entry : jsonPostFormats .entrySet()) { String key = entry.getKey(); String val = entry.getValue(); mPostFormats[i] = key; mPostFormatTitles[i] = val; i++; } } catch (Exception e) { e.printStackTrace(); } } Spinner pfSpinner = (Spinner) findViewById(R.id.postFormat); ArrayAdapter<String> pfAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, mPostFormatTitles); pfAdapter .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); pfSpinner.setAdapter(pfAdapter); String activePostFormat = "standard"; if (!mIsNew) { try { if (!mPostable.getPostFormat().equals("")) activePostFormat = mPostable.getPostFormat(); } catch (Exception e) { e.printStackTrace(); } } for (int i = 0; i < mPostFormats.length; i++) { if (mPostFormats[i].equals(activePostFormat)) pfSpinner.setSelection(i); } if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) setContent(); } String[] items = new String[] { getResources().getString(R.string.publish_post), getResources().getString(R.string.draft), getResources().getString(R.string.pending_review), getResources().getString(R.string.post_private) }; ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, items); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mStatusSpinner.setAdapter(adapter); if (mIsNew) { if (mQuickMediaType >= 0) { // User selected a 'Quick (media type)' option in the menu // drawer if (mQuickMediaType == Constants.QUICK_POST_PHOTO_CAMERA) launchCamera(); else if (mQuickMediaType == Constants.QUICK_POST_PHOTO_LIBRARY) launchPictureLibrary(); else if (mQuickMediaType == Constants.QUICK_POST_VIDEO_CAMERA) launchVideoCamera(); else if (mQuickMediaType == Constants.QUICK_POST_VIDEO_LIBRARY) launchVideoLibrary(); mLocalDraft = extras.getBoolean("localDraft"); } } else { mTitleEditText.setText(mPostable.getTitle()); mExcerptEditText.setText(mPostable.getExcerpt()); if (mPostable.isUploaded()) { items = new String[] { getResources().getString(R.string.publish_post), getResources().getString(R.string.draft), getResources().getString(R.string.pending_review), getResources().getString(R.string.post_private) }; adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, items); mStatusSpinner.setAdapter(adapter); } String contentHTML = getContentHTML(mPostable); try { if (mPostable.isLocalDraft()) mContentEditText.setText(WPHtml.fromHtml( contentHTML.replaceAll("\uFFFC", ""), AbsEditActivity.this, mPostable)); else mContentEditText.setText(contentHTML.replaceAll("\uFFFC", "")); } catch (Exception e) { e.printStackTrace(); } long pubDate = mPostable.getDate_created_gmt(); if (pubDate != 0) { try { int flags = 0; flags |= android.text.format.DateUtils.FORMAT_SHOW_DATE; flags |= android.text.format.DateUtils.FORMAT_ABBREV_MONTH; flags |= android.text.format.DateUtils.FORMAT_SHOW_YEAR; flags |= android.text.format.DateUtils.FORMAT_SHOW_TIME; String formattedDate = DateUtils.formatDateTime( AbsEditActivity.this, pubDate, flags); mPubDateText.setText(formattedDate); } catch (Exception e) { e.printStackTrace(); } } if (mPostable.getPassword() != null) mPasswordEditText.setText(mPostable.getPassword()); if (mPostable.getPostStatus() != null) { String status = mPostable.getPostStatus(); if (status.equals("publish")) { mStatusSpinner.setSelection(0, true); } else if (status.equals("draft")) { mStatusSpinner.setSelection(1, true); } else if (status.equals("pending")) { mStatusSpinner.setSelection(2, true); } else if (status.equals("private")) { mStatusSpinner.setSelection(3, true); } else if (status.equals("localdraft")) { mStatusSpinner.setSelection(0, true); } } } registerForContextMenu(mAddPictureButton); mContentEditText.setOnSelectionChangedListener(this); mContentEditText.setOnEditTextImeBackListener(this); mContentEditText.setOnTouchListener(this); mContentEditText.addTextChangedListener(this); mContentEditText.setOnFocusChangeListener(this); mAddPictureButton.setOnClickListener(this); mPubDateButton.setOnClickListener(this); seoButton.setOnClickListener(this); mBoldToggleButton.setOnClickListener(this); mLinkButton.setOnClickListener(this); mEmToggleButton.setOnClickListener(this); mUnderlineToggleButton.setOnClickListener(this); mStrikeToggleButton.setOnClickListener(this); mBquoteToggleButton.setOnClickListener(this); mMoreButton.setOnClickListener(this); } protected abstract Postable createPost(); protected abstract String getContentHTML(Postable post); @Override protected void onResume() { super.onResume(); if (mAutoSaveHandler != null) mAutoSaveHandler.postDelayed(autoSaveRunnable, 60000); } @Override protected void onPause() { super.onPause(); if (mAutoSaveHandler != null) mAutoSaveHandler.removeCallbacks(autoSaveRunnable); } @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putInt("currentActivityRequest", mCurrentActivityRequest); if (!mMediaCapturePath.equals("")) savedInstanceState.putString("mediaCapturePath", mMediaCapturePath); } public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { menu.add(0, 0, 0, getResources().getText(R.string.select_photo)); if (DeviceUtils.hasCamera(getApplicationContext())) { menu.add(0, 1, 0, getResources().getText(R.string.take_photo)); } menu.add(0, 2, 0, getResources().getText(R.string.select_video)); if (DeviceUtils.hasCamera(getApplicationContext())) { menu.add(0, 3, 0, getResources().getText(R.string.take_video)); } } @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case 0: launchPictureLibrary(); return true; case 1: launchCamera(); return true; case 2: launchVideoLibrary(); return true; case 3: launchVideoCamera(); return true; } return false; } @Override public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getSupportMenuInflater(); inflater.inflate(R.menu.edit, menu); return true; } // Menu actions @Override public boolean onOptionsItemSelected( com.actionbarsherlock.view.MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.menu_edit_post) { if (mAutoSaveHandler != null) mAutoSaveHandler.removeCallbacks(autoSaveRunnable); if (savePost(false, false)) { if (mQuickMediaType >= 0) { if (mQuickMediaType == Constants.QUICK_POST_PHOTO_CAMERA || mQuickMediaType == Constants.QUICK_POST_PHOTO_LIBRARY) mPostable.setQuickPostType("QuickPhoto"); else if (mQuickMediaType == Constants.QUICK_POST_VIDEO_CAMERA || mQuickMediaType == Constants.QUICK_POST_VIDEO_LIBRARY) mPostable.setQuickPostType("QuickVideo"); } WordPress.setCurrentPost(mPostable); PostUploadService.addPostToUpload(mPostable); startService(new Intent(this, PostUploadService.class)); if (!calledFromList) { startListActivity(); } else { Intent i = new Intent(); i.putExtra("shouldRefresh", true); setResult(RESULT_OK, i); } finish(); } return true; } else if (itemId == android.R.id.home) { showCancelAlert(true); return true; } return false; } protected abstract void startListActivity(); @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus && mFormatBar.getVisibility() != View.VISIBLE) showFormatBar(); else if (!hasFocus && mFormatBar.getVisibility() == View.VISIBLE) hideFormatBar(); } @Override public void onImeBack(WPEditText ctrl, String text) { if (mFormatBar.getVisibility() == View.VISIBLE) hideFormatBar(); } private void showFormatBar() { mFormatBar.setVisibility(View.VISIBLE); AlphaAnimation fadeInAnimation = new AlphaAnimation(0.0f, 1.0f); fadeInAnimation.setDuration(500); mFormatBar.startAnimation(fadeInAnimation); } private void hideFormatBar() { AlphaAnimation fadeOutAnimation = new AlphaAnimation(1.0f, 0.0f); fadeOutAnimation.setDuration(500); mFormatBar.startAnimation(fadeOutAnimation); mFormatBar.setVisibility(View.GONE); } @Override public void onClick(View v) { int id = v.getId(); if (id == R.id.bold) { formatBtnClick(mBoldToggleButton, "strong"); } else if (id == R.id.em) { formatBtnClick(mEmToggleButton, "em"); } else if (id == R.id.underline) { formatBtnClick(mUnderlineToggleButton, "u"); } else if (id == R.id.strike) { formatBtnClick(mStrikeToggleButton, "strike"); } else if (id == R.id.bquote) { formatBtnClick(mBquoteToggleButton, "blockquote"); } else if (id == R.id.more) { mSelectionEnd = mContentEditText.getSelectionEnd(); Editable str = mContentEditText.getText(); str.insert(mSelectionEnd, "\n<!--more-->\n"); } else if (id == R.id.link) { mSelectionStart = mContentEditText.getSelectionStart(); mStyleStart = mSelectionStart; mSelectionEnd = mContentEditText.getSelectionEnd(); if (mSelectionStart > mSelectionEnd) { int temp = mSelectionEnd; mSelectionEnd = mSelectionStart; mSelectionStart = temp; } Intent i = new Intent(AbsEditActivity.this, EditLinkActivity.class); if (mSelectionEnd > mSelectionStart) { String selectedText = mContentEditText.getText() .subSequence(mSelectionStart, mSelectionEnd).toString(); i.putExtra("selectedText", selectedText); } startActivityForResult(i, ACTIVITY_REQUEST_CODE_CREATE_LINK); } else if (id == R.id.addPictureButton) { mAddPictureButton.performLongClick(); } else if (id == R.id.pubDateButton) { showDialog(ID_DIALOG_DATE); } else if (id == R.id.post) { if (mAutoSaveHandler != null) mAutoSaveHandler.removeCallbacks(autoSaveRunnable); if (savePost(false, false)) { if (mPostable.isUploaded() || !mPostable.getPostStatus().equals("localdraft")) { if (mQuickMediaType >= 0) { if (mQuickMediaType == Constants.QUICK_POST_PHOTO_CAMERA || mQuickMediaType == Constants.QUICK_POST_PHOTO_LIBRARY) mPostable.setQuickPostType("QuickPhoto"); else if (mQuickMediaType == Constants.QUICK_POST_VIDEO_CAMERA || mQuickMediaType == Constants.QUICK_POST_VIDEO_LIBRARY) mPostable.setQuickPostType("QuickVideo"); } WordPress.setCurrentPost(mPostable); PostUploadService.addPostToUpload(mPostable); startService(new Intent(this, PostUploadService.class)); } finish(); } } else if (id == R.id.selectCategories) { startCategoryActivity(); } else if (id == R.id.categoryButton) { onCategoryButtonClick(v); } else if (id == R.id.seoButton) { goToSeo(); } } protected abstract void startCategoryActivity(); protected abstract void preparePost(); private void goToSeo() { String title = this.mTitleEditText.getText().toString(); String contents = mContentEditText.getText().toString(); if (title.length() > 0 && contents.length() > 0) { Intent i = new Intent(this, SeoResultActivity.class); i.putExtra("title", title); i.putExtra("contents", contents); String excerpt = mExcerptEditText.getText().toString(); if (excerpt.length() > 0) { i.putExtra("h1", excerpt); } startActivity(i); } else { showDialog(ID_DIALOG_SEO_ALERT); } } @Override public boolean onTouch(View v, MotionEvent event) { if (mFormatBar.getVisibility() != View.VISIBLE) showFormatBar(); float pos = event.getY(); if (event.getAction() == 0) mLastYPos = pos; if (event.getAction() > 1) { if (((mLastYPos - pos) > 2.0f) || ((pos - mLastYPos) > 2.0f)) mScrollDetected = true; } mLastYPos = pos; if (event.getAction() == 1 && !mScrollDetected) { Layout layout = ((TextView) v).getLayout(); int x = (int) event.getX(); int y = (int) event.getY(); x += v.getScrollX(); y += v.getScrollY(); if (layout != null) { int line = layout.getLineForVertical(y); int charPosition = layout.getOffsetForHorizontal(line, x); final Spannable s = mContentEditText.getText(); // check if image span was tapped WPImageSpan[] image_spans = s.getSpans(charPosition, charPosition, WPImageSpan.class); if (image_spans.length != 0) { final WPImageSpan span = image_spans[0]; if (!span.isVideo()) { LayoutInflater factory = LayoutInflater .from(AbsEditActivity.this); final View alertView = factory.inflate( R.layout.alert_image_options, null); final TextView imageWidthText = (TextView) alertView .findViewById(R.id.imageWidthText); final EditText titleText = (EditText) alertView .findViewById(R.id.title); // final EditText descText = (EditText) // alertView.findViewById(R.id.description); final EditText caption = (EditText) alertView .findViewById(R.id.caption); final CheckBox featuredCheckBox = (CheckBox) alertView .findViewById(R.id.featuredImage); final CheckBox featuredInPostCheckBox = (CheckBox) alertView .findViewById(R.id.featuredInPost); // show featured image checkboxes if theme support it if (WordPress.getCurrentBlog().isFeaturedImageCapable()) { featuredCheckBox.setVisibility(View.VISIBLE); featuredInPostCheckBox.setVisibility(View.VISIBLE); } featuredCheckBox .setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged( CompoundButton buttonView, boolean isChecked) { if (isChecked) { featuredInPostCheckBox .setVisibility(View.VISIBLE); } else { featuredInPostCheckBox .setVisibility(View.GONE); } } }); final SeekBar seekBar = (SeekBar) alertView .findViewById(R.id.imageWidth); final Spinner alignmentSpinner = (Spinner) alertView .findViewById(R.id.alignment_spinner); ArrayAdapter<CharSequence> adapter = ArrayAdapter .createFromResource(AbsEditActivity.this, R.array.alignment_array, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); alignmentSpinner.setAdapter(adapter); imageWidthText.setText(String.valueOf(span.getWidth()) + "px"); seekBar.setProgress(span.getWidth()); titleText.setText(span.getTitle()); // descText.setText(span.getDescription()); caption.setText(span.getCaption()); featuredCheckBox.setChecked(span.isFeatured()); if (span.isFeatured()) featuredInPostCheckBox.setVisibility(View.VISIBLE); else featuredInPostCheckBox.setVisibility(View.GONE); featuredInPostCheckBox.setChecked(span .isFeaturedInPost()); alignmentSpinner.setSelection( span.getHorizontalAlignment(), true); seekBar.setMax(span.getWidth() / 10); if (span.getWidth() != 0) seekBar.setProgress(span.getWidth() / 10); seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (progress == 0) progress = 1; imageWidthText.setText(progress * 10 + "px"); } }); AlertDialog ad = new AlertDialog.Builder( AbsEditActivity.this) .setTitle(getString(R.string.image_settings)) .setView(alertView) .setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, int whichButton) { span.setTitle(titleText .getText().toString()); // span.setDescription(descText.getText().toString()); span.setHorizontalAlignment(alignmentSpinner .getSelectedItemPosition()); span.setWidth(seekBar .getProgress() * 10); span.setCaption(caption .getText().toString()); span.setFeatured(featuredCheckBox .isChecked()); if (featuredCheckBox .isChecked()) { // remove featured flag from // all // other images WPImageSpan[] click_spans = s.getSpans( 0, s.length(), WPImageSpan.class); if (click_spans.length > 1) { for (int i = 0; i < click_spans.length; i++) { WPImageSpan verifySpan = click_spans[i]; if (verifySpan != span) { verifySpan .setFeatured(false); verifySpan .setFeaturedInPost(false); } } } } span.setFeaturedInPost(featuredInPostCheckBox .isChecked()); } }) .setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, int whichButton) { dialog.dismiss(); } }).create(); ad.getWindow() .setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); ad.show(); mScrollDetected = false; return true; } } else { mContentEditText.setMovementMethod(ArrowKeyMovementMethod .getInstance()); mContentEditText.setSelection(mContentEditText .getSelectionStart()); } } } else if (event.getAction() == 1) { mScrollDetected = false; } return false; } @Override public void onBackPressed() { showCancelAlert(false); } private void showCancelAlert(final boolean isUpPress) { // Empty post? Let's not prompt then. if (mIsNew && mContentEditText.getText().toString().equals("") && mTitleEditText.getText().toString().equals("")) { finish(); return; } AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); dialogBuilder.setTitle(getString((mIsPage) ? R.string.edit_page : R.string.edit_post)); dialogBuilder.setMessage(getString(R.string.prompt_save_changes)); dialogBuilder.setPositiveButton(getResources().getText(R.string.save), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { savePost(false, true); Intent i = new Intent(); i.putExtra("shouldRefresh", true); setResult(RESULT_OK, i); finish(); } }); dialogBuilder.setNeutralButton(getString(R.string.discard), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // When discard options is chosen, restore existing post or delete new post if it was autosaved. if (mOriginalPost != null) { mOriginalPost.update(); WordPress.setCurrentPost(mPostable); } else if (mPostable != null && mIsNew) { mPostable.delete(); WordPress.setCurrentPost(null); } if (!calledFromList) { startListActivity(); } finish(); } }); dialogBuilder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { dialog.dismiss(); } }); dialogBuilder.setCancelable(true); dialogBuilder.create().show(); } private void initBlog() { if (WordPress.getCurrentBlog() == null) showBlogErrorAndFinish(); } private boolean selectBlogForShareAction() { mIsNew = true; mLocalDraft = true; List<Map<String, Object>> accounts = WordPress.wpDB.getAccounts(); if (accounts.size() > 0) { final String blogNames[] = new String[accounts.size()]; final int accountIDs[] = new int[accounts.size()]; for (int i = 0; i < accounts.size(); i++) { Map<String, Object> curHash = accounts.get(i); try { blogNames[i] = StringUtils.unescapeHTML(curHash.get( "blogName").toString()); } catch (Exception e) { blogNames[i] = curHash.get("url").toString(); } accountIDs[i] = (Integer) curHash.get("id"); try { mBlog = new Blog(accountIDs[i]); } catch (Exception e) { showBlogErrorAndFinish(); return false; } } // Don't prompt if they have one blog only if (accounts.size() > 1) { AlertDialog.Builder builder = new AlertDialog.Builder( AbsEditActivity.this); builder.setCancelable(false); builder.setTitle(getResources().getText(R.string.select_a_blog)); builder.setItems(blogNames, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { mBlogID = accountIDs[item]; try { mBlog = new Blog(mBlogID); } catch (Exception e) { showBlogErrorAndFinish(); } WordPress.currentBlog = mBlog; WordPress.wpDB .updateLastBlogId(WordPress.currentBlog .getId()); mAccountName = blogNames[item]; setTitle(StringUtils.unescapeHTML(mAccountName) + " - " + getResources().getText( (mIsPage) ? R.string.new_page : R.string.new_post)); } }); AlertDialog alert = builder.create(); alert.show(); } else { mBlogID = accountIDs[0]; try { mBlog = new Blog(mBlogID); } catch (Exception e) { showBlogErrorAndFinish(); return false; } WordPress.currentBlog = mBlog; WordPress.wpDB.updateLastBlogId(WordPress.currentBlog.getId()); mAccountName = blogNames[0]; setTitle(StringUtils.unescapeHTML(mAccountName) + " - " + getResources().getText( (mIsPage) ? R.string.new_page : R.string.new_post)); } ; return true; } else { // no account, load main view to load new account view Toast.makeText(getApplicationContext(), getResources().getText(R.string.no_account), Toast.LENGTH_LONG).show(); startActivity(new Intent(this, NewAccountActivity.class)); finish(); return false; } } private void showBlogErrorAndFinish() { Toast.makeText(this, getResources().getText(R.string.blog_not_found), Toast.LENGTH_SHORT).show(); finish(); } private void formatBtnClick(ToggleButton toggleButton, String tag) { try { Spannable s = mContentEditText.getText(); int selectionStart = mContentEditText.getSelectionStart(); mStyleStart = selectionStart; int selectionEnd = mContentEditText.getSelectionEnd(); if (selectionStart > selectionEnd) { int temp = selectionEnd; selectionEnd = selectionStart; selectionStart = temp; } if (mLocalDraft) { if (selectionEnd > selectionStart) { Spannable str = mContentEditText.getText(); if (tag.equals("strong")) { StyleSpan[] ss = str.getSpans(selectionStart, selectionEnd, StyleSpan.class); boolean exists = false; for (int i = 0; i < ss.length; i++) { int style = ((StyleSpan) ss[i]).getStyle(); if (style == android.graphics.Typeface.BOLD) { str.removeSpan(ss[i]); exists = true; } } if (!exists) { str.setSpan(new StyleSpan( android.graphics.Typeface.BOLD), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } toggleButton.setChecked(false); } else if (tag.equals("em")) { StyleSpan[] ss = str.getSpans(selectionStart, selectionEnd, StyleSpan.class); boolean exists = false; for (int i = 0; i < ss.length; i++) { int style = ((StyleSpan) ss[i]).getStyle(); if (style == android.graphics.Typeface.ITALIC) { str.removeSpan(ss[i]); exists = true; } } if (!exists) { str.setSpan(new StyleSpan( android.graphics.Typeface.ITALIC), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } toggleButton.setChecked(false); } else if (tag.equals("u")) { WPUnderlineSpan[] ss = str.getSpans(selectionStart, selectionEnd, WPUnderlineSpan.class); boolean exists = false; for (int i = 0; i < ss.length; i++) { str.removeSpan(ss[i]); exists = true; } if (!exists) { str.setSpan(new WPUnderlineSpan(), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } toggleButton.setChecked(false); } else if (tag.equals("strike")) { StrikethroughSpan[] ss = str.getSpans(selectionStart, selectionEnd, StrikethroughSpan.class); boolean exists = false; for (int i = 0; i < ss.length; i++) { str.removeSpan(ss[i]); exists = true; } if (!exists) { str.setSpan(new StrikethroughSpan(), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } toggleButton.setChecked(false); } else if (tag.equals("blockquote")) { QuoteSpan[] ss = str.getSpans(selectionStart, selectionEnd, QuoteSpan.class); boolean exists = false; for (int i = 0; i < ss.length; i++) { str.removeSpan(ss[i]); exists = true; } if (!exists) { str.setSpan(new QuoteSpan(), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } toggleButton.setChecked(false); } } else if (!toggleButton.isChecked()) { if (tag.equals("strong") || tag.equals("em")) { StyleSpan[] ss = s.getSpans(mStyleStart - 1, mStyleStart, StyleSpan.class); for (int i = 0; i < ss.length; i++) { int tagStart = s.getSpanStart(ss[i]); int tagEnd = s.getSpanEnd(ss[i]); if (ss[i].getStyle() == android.graphics.Typeface.BOLD && tag.equals("strong")) { tagStart = s.getSpanStart(ss[i]); tagEnd = s.getSpanEnd(ss[i]); s.removeSpan(ss[i]); s.setSpan(new StyleSpan( android.graphics.Typeface.BOLD), tagStart, tagEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } if (ss[i].getStyle() == android.graphics.Typeface.ITALIC && tag.equals("em")) { tagStart = s.getSpanStart(ss[i]); tagEnd = s.getSpanEnd(ss[i]); s.removeSpan(ss[i]); s.setSpan(new StyleSpan( android.graphics.Typeface.ITALIC), tagStart, tagEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } else if (tag.equals("u")) { WPUnderlineSpan[] us = s.getSpans(mStyleStart - 1, mStyleStart, WPUnderlineSpan.class); for (int i = 0; i < us.length; i++) { int tagStart = s.getSpanStart(us[i]); int tagEnd = s.getSpanEnd(us[i]); s.removeSpan(us[i]); s.setSpan(new WPUnderlineSpan(), tagStart, tagEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } else if (tag.equals("strike")) { StrikethroughSpan[] ss = s.getSpans(mStyleStart - 1, mStyleStart, StrikethroughSpan.class); for (int i = 0; i < ss.length; i++) { int tagStart = s.getSpanStart(ss[i]); int tagEnd = s.getSpanEnd(ss[i]); s.removeSpan(ss[i]); s.setSpan(new StrikethroughSpan(), tagStart, tagEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } else if (tag.equals("blockquote")) { QuoteSpan[] ss = s.getSpans(mStyleStart - 1, mStyleStart, QuoteSpan.class); for (int i = 0; i < ss.length; i++) { int tagStart = s.getSpanStart(ss[i]); int tagEnd = s.getSpanEnd(ss[i]); s.removeSpan(ss[i]); s.setSpan(new QuoteSpan(), tagStart, tagEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } } else { String startTag = "<" + tag + ">"; String endTag = "</" + tag + ">"; Editable content = mContentEditText.getText(); if (selectionEnd > selectionStart) { content.insert(selectionStart, startTag); content.insert(selectionEnd + startTag.length(), endTag); toggleButton.setChecked(false); mContentEditText.setSelection(selectionEnd + startTag.length() + endTag.length()); } else if (toggleButton.isChecked()) { content.insert(selectionStart, startTag); mContentEditText.setSelection(selectionEnd + startTag.length()); } else if (!toggleButton.isChecked()) { content.insert(selectionEnd, endTag); mContentEditText.setSelection(selectionEnd + endTag.length()); } } } catch (Exception e) { e.printStackTrace(); } } private void launchPictureLibrary() { Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); photoPickerIntent.setType("image/*"); mCurrentActivityRequest = ACTIVITY_REQUEST_CODE_PICTURE_LIBRARY; startActivityForResult(photoPickerIntent, ACTIVITY_REQUEST_CODE_PICTURE_LIBRARY); AppLockManager.getInstance().setExtendedTimeout(); } private void launchCamera() { String state = android.os.Environment.getExternalStorageState(); if (!state.equals(android.os.Environment.MEDIA_MOUNTED)) { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder( AbsEditActivity.this); dialogBuilder.setTitle(getResources() .getText(R.string.sdcard_title)); dialogBuilder.setMessage(getResources().getText( R.string.sdcard_message)); dialogBuilder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { dialog.dismiss(); } }); dialogBuilder.setCancelable(true); dialogBuilder.create().show(); } else { String dcimFolderName = Environment.DIRECTORY_DCIM; if (dcimFolderName == null) dcimFolderName = "DCIM"; mMediaCapturePath = Environment.getExternalStorageDirectory() + File.separator + dcimFolderName + File.separator + "Camera" + File.separator + "wp-" + System.currentTimeMillis() + ".jpg"; Intent takePictureFromCameraIntent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE); takePictureFromCameraIntent.putExtra( android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mMediaCapturePath))); // make sure the directory we plan to store the recording in exists File directory = new File(mMediaCapturePath).getParentFile(); if (!directory.exists() && !directory.mkdirs()) { try { throw new IOException("Path to file could not be created."); } catch (IOException e) { e.printStackTrace(); } } mCurrentActivityRequest = ACTIVITY_REQUEST_CODE_TAKE_PHOTO; startActivityForResult(takePictureFromCameraIntent, ACTIVITY_REQUEST_CODE_TAKE_PHOTO); AppLockManager.getInstance().setExtendedTimeout(); } } private void launchVideoLibrary() { Intent videoPickerIntent = new Intent(Intent.ACTION_PICK); videoPickerIntent.setType("video/*"); mCurrentActivityRequest = ACTIVITY_REQUEST_CODE_VIDEO_LIBRARY; startActivityForResult(videoPickerIntent, ACTIVITY_REQUEST_CODE_VIDEO_LIBRARY); AppLockManager.getInstance().setExtendedTimeout(); } private void launchVideoCamera() { mCurrentActivityRequest = ACTIVITY_REQUEST_CODE_TAKE_VIDEO; startActivityForResult(new Intent(MediaStore.ACTION_VIDEO_CAPTURE), ACTIVITY_REQUEST_CODE_TAKE_VIDEO); AppLockManager.getInstance().setExtendedTimeout(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_CANCELED) { if (mQuickMediaType >= 0) { setResult(Activity.RESULT_CANCELED, new Intent()); finish(); } if (mFormatBar.getVisibility() == View.VISIBLE) hideFormatBar(); return; } if (data != null || ((requestCode == ACTIVITY_REQUEST_CODE_TAKE_PHOTO || requestCode == ACTIVITY_REQUEST_CODE_TAKE_VIDEO))) { Bundle extras; switch (requestCode) { case ACTIVITY_REQUEST_CODE_PICTURE_LIBRARY: Uri imageUri = data.getData(); verifyImage(imageUri); break; case ACTIVITY_REQUEST_CODE_TAKE_PHOTO: if (resultCode == Activity.RESULT_OK) { try { File f = new File(mMediaCapturePath); Uri capturedImageUri = Uri.fromFile(f); f = null; if (!addMedia(capturedImageUri, null)) Toast.makeText( this, getResources().getText( R.string.gallery_error), Toast.LENGTH_SHORT).show(); sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment .getExternalStorageDirectory()))); } catch (Exception e) { e.printStackTrace(); } catch (OutOfMemoryError e) { e.printStackTrace(); } } break; case ACTIVITY_REQUEST_CODE_VIDEO_LIBRARY: Uri videoUri = data.getData(); if (!addMedia(videoUri, null)) Toast.makeText(this, getResources().getText(R.string.gallery_error), Toast.LENGTH_SHORT).show(); break; case ACTIVITY_REQUEST_CODE_TAKE_VIDEO: if (resultCode == Activity.RESULT_OK) { Uri capturedVideoUri = data.getData(); if (!addMedia(capturedVideoUri, null)) Toast.makeText(this, getResources().getText(R.string.gallery_error), Toast.LENGTH_SHORT).show(); } break; case ACTIVITY_REQUEST_CODE_CREATE_LINK: try { extras = data.getExtras(); String linkURL = extras.getString("linkURL"); if (!linkURL.equals("http://") && !linkURL.equals("")) { if (mSelectionStart > mSelectionEnd) { int temp = mSelectionEnd; mSelectionEnd = mSelectionStart; mSelectionStart = temp; } Editable str = mContentEditText.getText(); if (mLocalDraft) { if (extras.getString("linkText") == null) { if (mSelectionStart < mSelectionEnd) str.delete(mSelectionStart, mSelectionEnd); str.insert(mSelectionStart, linkURL); str.setSpan(new URLSpan(linkURL), mSelectionStart, mSelectionStart + linkURL.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); mContentEditText.setSelection(mSelectionStart + linkURL.length()); } else { String linkText = extras.getString("linkText"); if (mSelectionStart < mSelectionEnd) str.delete(mSelectionStart, mSelectionEnd); str.insert(mSelectionStart, linkText); str.setSpan(new URLSpan(linkURL), mSelectionStart, mSelectionStart + linkText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); mContentEditText.setSelection(mSelectionStart + linkText.length()); } } else { if (extras.getString("linkText") == null) { if (mSelectionStart < mSelectionEnd) str.delete(mSelectionStart, mSelectionEnd); String urlHTML = "<a href=\"" + linkURL + "\">" + linkURL + "</a>"; str.insert(mSelectionStart, urlHTML); mContentEditText.setSelection(mSelectionStart + urlHTML.length()); } else { String linkText = extras.getString("linkText"); if (mSelectionStart < mSelectionEnd) str.delete(mSelectionStart, mSelectionEnd); String urlHTML = "<a href=\"" + linkURL + "\">" + linkText + "</a>"; str.insert(mSelectionStart, urlHTML); mContentEditText.setSelection(mSelectionStart + urlHTML.length()); } } } } catch (Exception e) { e.printStackTrace(); } break; } }// end null check } private void verifyImage(Uri imageUri) { if (isPicasaImage(imageUri)) { // Create an AsyncTask to download the file new DownloadImageTask().execute(imageUri); } else { // It is a regular local image file if (!addMedia(imageUri, null)) Toast.makeText(this, getResources().getText(R.string.gallery_error), Toast.LENGTH_SHORT).show(); } } private boolean isPicasaImage(Uri imageUri) { // Check if the imageUri returned is of picasa or not if (imageUri.toString().startsWith( "content://com.android.gallery3d.provider")) { // Use the com.google provider for devices prior to 3.0 imageUri = Uri.parse(imageUri.toString().replace( "com.android.gallery3d", "com.google.android.gallery3d")); } if (imageUri.toString().startsWith( "content://com.google.android.gallery3d")) return true; else return false; } private class DownloadImageTask extends AsyncTask<Uri, Integer, Uri> { @Override protected Uri doInBackground(Uri... uris) { Uri imageUri = uris[0]; return downloadExternalImage(imageUri); } @Override protected void onPreExecute() { showDialog(ID_DIALOG_DOWNLOAD); } protected void onPostExecute(Uri newUri) { dismissDialog(ID_DIALOG_DOWNLOAD); if (newUri != null) addMedia(newUri, null); else Toast.makeText(getApplicationContext(), getString(R.string.error_downloading_image), Toast.LENGTH_SHORT).show(); } } private Uri downloadExternalImage(Uri imageUri) { File cacheDir; // If the device has an SD card if (android.os.Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED)) cacheDir = new File( android.os.Environment.getExternalStorageDirectory() + "/WordPress/images"); else { // If no SD card cacheDir = getApplicationContext().getCacheDir(); } if (!cacheDir.exists()) cacheDir.mkdirs(); Random r = new Random(); final String path = "wp-" + r.nextInt(400) + r.nextInt(400) + ".jpg"; File f = new File(cacheDir, path); try { InputStream input; // Download the file if (imageUri.toString().startsWith( "content://com.google.android.gallery3d")) { input = getContentResolver().openInputStream(imageUri); } else { input = new URL(imageUri.toString()).openStream(); } OutputStream output = new FileOutputStream(f); byte data[] = new byte[1024]; int count; while ((count = input.read(data)) != -1) { output.write(data, 0, count); } output.flush(); output.close(); input.close(); Uri newUri = Uri.fromFile(f); return newUri; } catch (Exception e) { e.printStackTrace(); } return null; } private void onCategoryButtonClick(View v) { // Get category name by removing prefix from the tag boolean listChanged = false; String categoryName = (String) v.getTag(); categoryName = categoryName.replaceFirst(CATEGORY_PREFIX_TAG, ""); // Remove clicked category from list for (int i = 0; i < mCategories.size(); i++) { if (mCategories.get(i).equals(categoryName)) { mCategories.remove(i); listChanged = true; break; } } // Recreate category views if (listChanged) { populateSelectedCategories(); } } protected void populateSelectedCategories() { ViewGroup sectionCategories = ((ViewGroup) findViewById(R.id.sectionCategories)); // Remove previous category buttons if any + select category button List<View> viewsToRemove = new ArrayList<View>(); for (int i = 0; i < sectionCategories.getChildCount(); i++) { View v = sectionCategories.getChildAt(i); Object tag = v.getTag(); if (tag != null && tag.getClass() == String.class && (((String) tag).startsWith(CATEGORY_PREFIX_TAG) || tag .equals("select-category"))) { viewsToRemove.add(v); } } for (int i = 0; i < viewsToRemove.size(); i++) { sectionCategories.removeView(viewsToRemove.get(i)); } viewsToRemove.clear(); // New category buttons LayoutInflater layoutInflater = getLayoutInflater(); for (int i = 0; i < mCategories.size(); i++) { String categoryName = mCategories.get(i); Button buttonCategory = (Button) layoutInflater.inflate( R.layout.category_button, null); buttonCategory.setText(Html.fromHtml(categoryName)); buttonCategory.setTag(CATEGORY_PREFIX_TAG + categoryName); buttonCategory.setOnClickListener(this); sectionCategories.addView(buttonCategory); } // Add select category button Button selectCategory = (Button) layoutInflater.inflate( R.layout.category_select_button, null); selectCategory.setOnClickListener(this); sectionCategories.addView(selectCategory); } @Override protected Dialog onCreateDialog(int id) { switch (id) { case ID_DIALOG_DATE: DatePickerDialog dpd = new DatePickerDialog(this, mDateSetListener, mYear, mMonth, mDay); dpd.setTitle(""); return dpd; case ID_DIALOG_TIME: TimePickerDialog tpd = new TimePickerDialog(this, mTimeSetListener, mHour, mMinute, false); tpd.setTitle(""); return tpd; case ID_DIALOG_LOADING: ProgressDialog loadingDialog = new ProgressDialog(this); loadingDialog.setMessage(getResources().getText(R.string.loading)); loadingDialog.setIndeterminate(true); loadingDialog.setCancelable(true); return loadingDialog; case ID_DIALOG_SEO_ALERT: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.empty_fields); builder.setMessage(R.string.seo_error_message_input_empty); builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case DialogInterface.BUTTON_POSITIVE: dialog.dismiss(); break; } } }); return builder.create(); } return super.onCreateDialog(id); } protected abstract boolean savePost(boolean isAutoSave, boolean isDraftSave); protected void setContent() { Intent intent = getIntent(); String text = intent.getStringExtra(Intent.EXTRA_TEXT); String title = intent.getStringExtra(Intent.EXTRA_SUBJECT); if (text != null) { if (title != null) { mTitleEditText.setText(title); } if (text.contains("youtube_gdata")) { // Just use the URL for YouTube links for oEmbed support mContentEditText.setText(text); } else { // add link tag around URLs, trac #64 text = text.replaceAll("((http|https|ftp|mailto):\\S+)", "<a href=\"$1\">$1</a>"); mContentEditText.setText(WPHtml.fromHtml( StringUtils.addPTags(text), this, mPostable)); } } else { String action = intent.getAction(); final String type = intent.getType(); final ArrayList<Uri> multi_stream; if (Intent.ACTION_SEND_MULTIPLE.equals(action)) { multi_stream = intent .getParcelableArrayListExtra((Intent.EXTRA_STREAM)); } else { multi_stream = new ArrayList<Uri>(); multi_stream.add((Uri) intent .getParcelableExtra(Intent.EXTRA_STREAM)); } List<Serializable> params = new Vector<Serializable>(); params.add(multi_stream); params.add(type); new processAttachmentsTask().execute(params); } } private class processAttachmentsTask extends AsyncTask<List<?>, Void, SpannableStringBuilder> { protected void onPreExecute() { showDialog(ID_DIALOG_LOADING); } @Override protected SpannableStringBuilder doInBackground(List<?>... args) { ArrayList<?> multi_stream = (ArrayList<?>) args[0].get(0); String type = (String) args[0].get(1); SpannableStringBuilder ssb = new SpannableStringBuilder(); for (int i = 0; i < multi_stream.size(); i++) { Uri imageUri = (Uri) multi_stream.get(i); if (imageUri != null && type != null) { addMedia(imageUri, ssb); } } return ssb; } protected void onPostExecute(SpannableStringBuilder ssb) { dismissDialog(ID_DIALOG_LOADING); if (ssb != null) { if (ssb.length() > 0) { mContentEditText.setText(ssb); } } else { Toast.makeText(AbsEditActivity.this, getResources().getText(R.string.gallery_error), Toast.LENGTH_SHORT).show(); } } } //Calculate the minimun width between the blog setting and picture real width private void setWPImageSpanWidth(Uri curStream, WPImageSpan is) { String imageWidth = WordPress.getCurrentBlog().getMaxImageWidth(); int imageWidthBlogSetting = Integer.MAX_VALUE; if (!imageWidth.equals("Original Size")) { try { imageWidthBlogSetting = Integer.valueOf(imageWidth); } catch (NumberFormatException e) { e.printStackTrace(); } } int[] dimensions = ImageHelper.getImageSize(curStream, this); int imageWidthPictureSetting = dimensions[0] == 0 ? Integer.MAX_VALUE : dimensions[0]; if (Math.min(imageWidthPictureSetting, imageWidthBlogSetting) == Integer.MAX_VALUE) { is.setWidth(1024); //Default value in case of errors reading the picture size and the blog settings is set to Original size } else { is.setWidth(Math.min(imageWidthPictureSetting, imageWidthBlogSetting)); } } private boolean addMedia(Uri imageUri, SpannableStringBuilder ssb) { //if (mFormatBar.getVisibility() == View.VISIBLE) // hideFormatBar(); if (ssb != null && isPicasaImage(imageUri)) imageUri = downloadExternalImage(imageUri); if (imageUri == null) { return false; } Bitmap resizedBitmap = null; ImageHelper ih = new ImageHelper(); Display display = getWindowManager().getDefaultDisplay(); int width = display.getWidth(); int height = display.getHeight(); if (width > height) width = height; Map<String, Object> mediaData = ih.getImageBytesForPath( imageUri.getEncodedPath(), this); if (mediaData == null) { // data stream not returned return false; } BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; byte[] bytes = (byte[]) mediaData.get("bytes"); BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts); float conversionFactor = 0.25f; if (opts.outWidth > opts.outHeight) conversionFactor = 0.40f; byte[] finalBytes = ih.createThumbnail(bytes, String.valueOf((int) (width * conversionFactor)), (String) mediaData.get("orientation"), true); if (finalBytes == null) { //Toast.makeText(EditPostActivity.this, getResources().getText(R.string.out_of_memory), Toast.LENGTH_SHORT).show(); return false; } resizedBitmap = BitmapFactory.decodeByteArray(finalBytes, 0, finalBytes.length); if (ssb != null) { WPImageSpan is = new WPImageSpan(this, resizedBitmap, imageUri); setWPImageSpanWidth(imageUri, is); is.setTitle((String) mediaData.get("title")); is.setImageSource(imageUri); is.setVideo(imageUri.getEncodedPath().contains("video")); ssb.append(" "); ssb.setSpan(is, ssb.length() - 1, ssb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); AlignmentSpan.Standard as = new AlignmentSpan.Standard( Layout.Alignment.ALIGN_CENTER); ssb.setSpan(as, ssb.length() - 1, ssb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append("\n"); } else { int selectionStart = mContentEditText.getSelectionStart(); mStyleStart = selectionStart; int selectionEnd = mContentEditText.getSelectionEnd(); if (selectionStart > selectionEnd) { int temp = selectionEnd; selectionEnd = selectionStart; selectionStart = temp; } Editable s = mContentEditText.getText(); WPImageSpan is = new WPImageSpan(this, resizedBitmap, imageUri); setWPImageSpanWidth(imageUri, is); is.setTitle((String) mediaData.get("title")); is.setImageSource(imageUri); if (imageUri.getEncodedPath().contains("video")) { is.setVideo(true); } int line = 0, column = 0; try { line = mContentEditText.getLayout().getLineForOffset( selectionStart); column = mContentEditText.getSelectionStart() - mContentEditText.getLayout().getLineStart(line); } catch (Exception ex) { } WPImageSpan[] image_spans = s.getSpans(selectionStart, selectionEnd, WPImageSpan.class); if (image_spans.length != 0) { // insert a few line breaks if the cursor is already on an image s.insert(selectionEnd, "\n\n"); selectionStart = selectionStart + 2; selectionEnd = selectionEnd + 2; } else if (column != 0) { // insert one line break if the cursor is not at the first column s.insert(selectionEnd, "\n"); selectionStart = selectionStart + 1; selectionEnd = selectionEnd + 1; } s.insert(selectionStart, " "); s.setSpan(is, selectionStart, selectionEnd + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); AlignmentSpan.Standard as = new AlignmentSpan.Standard( Layout.Alignment.ALIGN_CENTER); s.setSpan(as, selectionStart, selectionEnd + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); s.insert(selectionEnd + 1, "\n\n"); try { mContentEditText.setSelection(s.length()); } catch (Exception e) { e.printStackTrace(); } } return true; } public SpannableStringBuilder addMediaFromShareAction(String imgPath, Uri curStream, SpannableStringBuilder ssb) { initBlog(); Bitmap resizedBitmap = null; String imageTitle = ""; ImageHelper ih = new ImageHelper(); Display display = getWindowManager().getDefaultDisplay(); int width = display.getWidth(); Map<String, Object> mediaData = ih.getImageBytesForPath(imgPath, AbsEditActivity.this); if (mediaData == null) { // data stream not returned return null; } BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; byte[] bytes = (byte[]) mediaData.get("bytes"); BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts); float conversionFactor = 0.25f; if (opts.outWidth > opts.outHeight) conversionFactor = 0.40f; byte[] finalBytes = ih.createThumbnail((byte[]) mediaData.get("bytes"), String.valueOf((int) (width * conversionFactor)), (String) mediaData.get("orientation"), true); if (finalBytes == null) { Toast.makeText(AbsEditActivity.this, getResources().getText(R.string.file_error_encountered), Toast.LENGTH_SHORT).show(); return null; } resizedBitmap = BitmapFactory.decodeByteArray(finalBytes, 0, finalBytes.length); WPImageSpan is = new WPImageSpan(AbsEditActivity.this, resizedBitmap, curStream); String imageWidth = WordPress.currentBlog.getMaxImageWidth(); if (!imageWidth.equals("Original Size")) { try { is.setWidth(Integer.valueOf(imageWidth)); } catch (NumberFormatException e) { e.printStackTrace(); } } is.setTitle(imageTitle); is.setImageSource(curStream); is.setVideo(imgPath.contains("video")); ssb.append(" "); ssb.setSpan(is, ssb.length() - 1, ssb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); AlignmentSpan.Standard as = new AlignmentSpan.Standard( Layout.Alignment.ALIGN_CENTER); ssb.setSpan(as, ssb.length() - 1, ssb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append("\n"); return ssb; } private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() { public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { mYear = year; mMonth = monthOfYear; mDay = dayOfMonth; showDialog(ID_DIALOG_TIME); } }; private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() { public void onTimeSet(TimePicker view, int hour, int minute) { mHour = hour; mMinute = minute; Date d = new Date(mYear - 1900, mMonth, mDay, mHour, mMinute); long timestamp = d.getTime(); try { int flags = 0; flags |= android.text.format.DateUtils.FORMAT_SHOW_DATE; flags |= android.text.format.DateUtils.FORMAT_ABBREV_MONTH; flags |= android.text.format.DateUtils.FORMAT_SHOW_YEAR; flags |= android.text.format.DateUtils.FORMAT_SHOW_TIME; String formattedDate = DateUtils.formatDateTime( AbsEditActivity.this, timestamp, flags); mCustomPubDate = timestamp; mPubDateText.setText(formattedDate); mIsCustomPubDate = true; } catch (Exception e) { e.printStackTrace(); } } }; private Runnable autoSaveRunnable = new Runnable() { @Override public void run() { savePost(true, false); mAutoSaveHandler.postDelayed(this, AUTOSAVE_DELAY_MILLIS); } }; @Override public void afterTextChanged(Editable s) { try { int position = Selection.getSelectionStart(mContentEditText .getText()); if ((mIsBackspace && position != 1) || mLastPosition == position || !mLocalDraft) return; if (position < 0) { position = 0; } mLastPosition = position; if (position > 0) { if (mStyleStart > position) { mStyleStart = position - 1; } boolean exists = false; if (mBoldToggleButton.isChecked()) { StyleSpan[] ss = s.getSpans(mStyleStart, position, StyleSpan.class); exists = false; for (int i = 0; i < ss.length; i++) { if (ss[i].getStyle() == android.graphics.Typeface.BOLD) { exists = true; } } if (!exists) s.setSpan( new StyleSpan(android.graphics.Typeface.BOLD), mStyleStart, position, Spannable.SPAN_INCLUSIVE_INCLUSIVE); } if (mEmToggleButton.isChecked()) { StyleSpan[] ss = s.getSpans(mStyleStart, position, StyleSpan.class); exists = false; for (int i = 0; i < ss.length; i++) { if (ss[i].getStyle() == android.graphics.Typeface.ITALIC) { exists = true; } } if (!exists) s.setSpan(new StyleSpan( android.graphics.Typeface.ITALIC), mStyleStart, position, Spannable.SPAN_INCLUSIVE_INCLUSIVE); } if (mEmToggleButton.isChecked()) { StyleSpan[] ss = s.getSpans(mStyleStart, position, StyleSpan.class); exists = false; for (int i = 0; i < ss.length; i++) { if (ss[i].getStyle() == android.graphics.Typeface.ITALIC) { exists = true; } } if (!exists) s.setSpan(new StyleSpan( android.graphics.Typeface.ITALIC), mStyleStart, position, Spannable.SPAN_INCLUSIVE_INCLUSIVE); } if (mUnderlineToggleButton.isChecked()) { WPUnderlineSpan[] ss = s.getSpans(mStyleStart, position, WPUnderlineSpan.class); exists = false; for (int i = 0; i < ss.length; i++) { exists = true; } if (!exists) s.setSpan(new WPUnderlineSpan(), mStyleStart, position, Spannable.SPAN_INCLUSIVE_INCLUSIVE); } if (mStrikeToggleButton.isChecked()) { StrikethroughSpan[] ss = s.getSpans(mStyleStart, position, StrikethroughSpan.class); exists = false; for (int i = 0; i < ss.length; i++) { exists = true; } if (!exists) s.setSpan(new StrikethroughSpan(), mStyleStart, position, Spannable.SPAN_INCLUSIVE_INCLUSIVE); } if (mBquoteToggleButton.isChecked()) { QuoteSpan[] ss = s.getSpans(mStyleStart, position, QuoteSpan.class); exists = false; for (int i = 0; i < ss.length; i++) { exists = true; } if (!exists) s.setSpan(new QuoteSpan(), mStyleStart, position, Spannable.SPAN_INCLUSIVE_INCLUSIVE); } } } catch (Exception e) { e.printStackTrace(); } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { if ((count - after == 1) || (s.length() == 0)) mIsBackspace = true; else mIsBackspace = false; } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void onSelectionChanged() { if (!mLocalDraft) return; final Spannable s = mContentEditText.getText(); // set toggle buttons if cursor is inside of a matching span mStyleStart = mContentEditText.getSelectionStart(); Object[] spans = s.getSpans(mContentEditText.getSelectionStart(), mContentEditText.getSelectionStart(), Object.class); mBoldToggleButton.setChecked(false); mEmToggleButton.setChecked(false); mBquoteToggleButton.setChecked(false); mUnderlineToggleButton.setChecked(false); mStrikeToggleButton.setChecked(false); for (Object span : spans) { if (span instanceof StyleSpan) { StyleSpan ss = (StyleSpan) span; if (ss.getStyle() == android.graphics.Typeface.BOLD) { mBoldToggleButton.setChecked(true); } if (ss.getStyle() == android.graphics.Typeface.ITALIC) { mEmToggleButton.setChecked(true); } } if (span instanceof QuoteSpan) { mBquoteToggleButton.setChecked(true); } if (span instanceof WPUnderlineSpan) { mUnderlineToggleButton.setChecked(true); } if (span instanceof StrikethroughSpan) { mStrikeToggleButton.setChecked(true); } } } }