package org.goodev.discourse.ui; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.CursorAdapter; import android.text.Editable; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import org.goodev.discourse.ActivityUtils; import org.goodev.discourse.App; import org.goodev.discourse.R; import org.goodev.discourse.api.Api; import org.goodev.discourse.api.data.Post; import org.goodev.discourse.api.data.Topic; import org.goodev.discourse.contentprovider.Provider; import org.goodev.discourse.ui.dialog.ConfirmDialogFragment; import org.goodev.discourse.ui.dialog.ConfirmDialogFragment.ConfirmListener; import org.goodev.discourse.ui.dialog.PreviewDialogFragment; import org.goodev.discourse.utils.HttpRequest; import org.goodev.discourse.utils.L; import org.goodev.discourse.utils.Utils; import org.goodev.widget.AddLinkFragment; import org.goodev.widget.AddLinkFragment.OnAddLinkListener; import org.goodev.widget.Selection; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.net.HttpURLConnection; import java.util.Stack; import static org.goodev.discourse.database.tables.CategoriesTable.COLOR; import static org.goodev.discourse.database.tables.CategoriesTable.DESCRIPTION; import static org.goodev.discourse.database.tables.CategoriesTable.DESCRIPTION_EXCERPT; import static org.goodev.discourse.database.tables.CategoriesTable.ID; import static org.goodev.discourse.database.tables.CategoriesTable.NAME; import static org.goodev.discourse.database.tables.CategoriesTable.SLUG; import static org.goodev.discourse.database.tables.CategoriesTable.TEXT_COLOR; import static org.goodev.discourse.database.tables.CategoriesTable.TOPIC_COUNT; import static org.goodev.discourse.database.tables.CategoriesTable.UID; /** * 标题不得少于15个字符 帖子内容不得少于20个字符 */ public class EditorFragment extends Fragment implements LoaderCallbacks<Cursor>, ConfirmListener, OnClickListener, OnAddLinkListener { private static final int TITLE_MIN_LENGTH = 5; private static final int CONTENT_MIN_LENGTH = 5; private static final int LOADER_ID_CATEGORY = 0; private static final String[] CATEGORY_COLUMNS = new String[]{ID, UID, NAME, COLOR, TEXT_COLOR, SLUG, TOPIC_COUNT, DESCRIPTION, DESCRIPTION_EXCERPT}; private static final int INDEX_UID = 1; private static final int INDEX_NAME = 2; private static final int INDEX_COLOR = 3; private static final int INDEX_TEXT_COLOR = 4; private static final int INDEX_SLUG = 5; private static final int INDEX_TOPIC_COUNT = 6; /** * 引用整个帖子 full:为true, 否则为 full:false */ private static final String QUOTE_POST = "[quote=\"%s, post:%d, topic:%d, full:true\"]\n%s\n[/quote]\n"; private static final char[] BOLD1 = {'*', '*'}; private static final char[] BOLD22 = {'*', '*', '*', '*'}; private static final String KEY_LINK = "key_s1"; private static final String KEY_UPLOAD = "key_s2"; private static final String KEY_MD_ACTION_ID = "key_s3"; private static final String KEY_SECTION = "key_s4"; private static final String KEY_HIS_TXT = "key_s5"; private static final String KEY_HIS_SELECTION = "key_s6"; private static final String KEY_HIS_ACTIONS = "key_s7"; private static final String DIVIDER = "\n\n----------\n"; private static final String ENTER = "\n"; private static final char ENTER_CHAR = '\n'; private static final char CODE_CHAR = '`'; private static final String CODE = "`"; private static final String CODE2 = "``"; private static final String QUOTE_START = "\n> "; private static final String QUOTE_START2 = "\n\n> "; private static final String QUOTE = "> "; private static final String NUMBER_SIGN = "#"; private static final String ASTERISK = "*"; private static final String ASTERISK2 = "**"; private static final String ASTERISK4 = "****"; private static final String NUM_LIST = "\n %d. "; private static final String BULLETED_LIST = "\n - "; private static final String SB = "["; private static final String SB2 = "]"; private static final String MARKDOWN_IMG = "![%s](%s)"; private final TextWatcher mTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { clearHistory(); } }; private TextView mPostTitle; private EditText mTitleET; private Spinner mCategoriesSpinner; private EditText mContentET; private String mTitle; private String mContent; private int mCategoryIndex; private CursorAdapter mCategoryAdapter; private Topic mTopic; private int mPostNum = -1; private String mUsername; private boolean mIsEditPost; private boolean mIsPrivateMsg; private long mPostId = -1; private PostTask mPostTask; private ProgressFragment mProgressFragment; // ------------------------ Markdown 按钮功能实现 private View mQuoteView; private String mPostRaw; private int mListIndex; /** * 记录历史编辑内容 */ private Stack<Editable> mHistories = new Stack<Editable>(); /** * 记录历史光标位置 */ private Stack<Selection> mHistoriesSelection = new Stack<Selection>(); private Stack<Integer> mHistoriyActions = new Stack<Integer>(); /** * 记录最近一次操作:加粗、斜体等... */ private int mLastAction; private Selection mLastSelection; private Selection mLinkSelection; private Selection mUploadSelection; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); mCategoryAdapter = new CategoryAdapter(getActivity(), null); if (savedInstanceState != null) { mTitle = savedInstanceState.getString(Utils.EXTRA_TITLE, null); mContent = savedInstanceState.getString(Utils.EXTRA_MSG, null); mCategoryIndex = savedInstanceState.getInt(Utils.EXTRA_CAT_INDEX, 0); restoreMdStatus(savedInstanceState); } Bundle args = getArguments(); mTopic = (Topic) args.getSerializable(Utils.EXTRA_OBJ); mPostNum = args.getInt(Utils.EXTRA_NUMBER, -1); mUsername = args.getString(Utils.EXTRA_NAME); mIsEditPost = args.getBoolean(Utils.EXTRA_IS_EDIT_POST, false); mIsPrivateMsg = args.getBoolean(Utils.EXTRA_IS_PRIVATE_MSG, false); mPostId = args.getLong(Utils.EXTRA_ID); if (mIsEditPost) { } } private boolean isReplyTopic() { return mTopic != null && mPostNum == -1; } private boolean isReplyPost() { return mPostNum > -1 && mTopic != null; } private boolean isNewTopic() { return mTopic == null && mPostNum == -1; } private boolean isEditPost() { return mIsEditPost; } private boolean isPrivateMsg() { return mIsPrivateMsg; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_editor, container, false); mPostTitle = (TextView) view.findViewById(R.id.post_title); mTitleET = (EditText) view.findViewById(R.id.edit_title); mTitleET.setText(mTitle); mContentET = (EditText) view.findViewById(R.id.edit_content); mContentET.setText(mContent); mCategoriesSpinner = (Spinner) view.findViewById(R.id.edit_categories_spinner); mCategoriesSpinner.setAdapter(mCategoryAdapter); setupMarkdownViews(view); if (isPrivateMsg()) { mCategoriesSpinner.setVisibility(View.GONE); mPostTitle.setText(getString(R.string.send_private_msg_title, mUsername)); } else if (isNewTopic()) { mPostTitle.setVisibility(View.GONE); } else if (isReplyTopic()) { mTitleET.setVisibility(View.GONE); mCategoriesSpinner.setVisibility(View.GONE); mPostTitle.setText(getString(R.string.reply_topic_title, mTopic.title)); } else if (isReplyPost()) { mTitleET.setVisibility(View.GONE); mCategoriesSpinner.setVisibility(View.GONE); mPostTitle.setText(getString(R.string.reply_post_title, mPostNum, mUsername)); } else if (isEditPost()) { mTitleET.setVisibility(View.GONE); mCategoriesSpinner.setVisibility(View.GONE); mPostTitle.setText(getString(R.string.edit_post_title, mPostNum, mUsername)); mContentET.setText(R.string.loading_post_text); } return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (isNewTopic()) { getLoaderManager().initLoader(LOADER_ID_CATEGORY, null, this); } else if (isEditPost()) { loadingPostData(); } setTitle(); } private void setTitle() { int titleId = R.string.title_activity_editor; if (isPrivateMsg()) { titleId = R.string.private_msg_title; } else if (isNewTopic()) { titleId = R.string.title_activity_editor; } else if (isEditPost()) { titleId = R.string.title_activity_edit_post; } else if (isReplyPost()) { titleId = R.string.title_activity_reply_post; } else if (isReplyTopic()) { titleId = R.string.title_activity_reply_topic; } getActivity().setTitle(titleId); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); String title = mTitleET.getText().toString(); if (!TextUtils.isEmpty(title)) { outState.putString(Utils.EXTRA_TITLE, title); } String content = mContentET.getText().toString(); if (!TextUtils.isEmpty(content)) { outState.putString(Utils.EXTRA_MSG, content); } int index = mCategoriesSpinner.getSelectedItemPosition(); outState.putInt(Utils.EXTRA_CAT_INDEX, index); if (mLinkSelection != null) { outState.putSerializable(KEY_LINK, mLinkSelection); } if (mUploadSelection != null) { outState.putSerializable(KEY_UPLOAD, mUploadSelection); } if (mLastSelection != null) { outState.putSerializable(KEY_SECTION, mLastSelection); } if (!mHistories.isEmpty()) { outState.putSerializable(KEY_HIS_TXT, mHistories); } if (!mHistoriesSelection.isEmpty()) { outState.putSerializable(KEY_HIS_SELECTION, mHistoriesSelection); } if (!mHistoriyActions.isEmpty()) { outState.putSerializable(KEY_HIS_ACTIONS, mHistoriyActions); } outState.putInt(KEY_MD_ACTION_ID, mLastAction); } private void restoreMdStatus(Bundle state) { mLinkSelection = (Selection) state.getSerializable(KEY_LINK); mUploadSelection = (Selection) state.getSerializable(KEY_UPLOAD); mLastSelection = (Selection) state.getSerializable(KEY_SECTION); if (state.containsKey(KEY_HIS_ACTIONS)) { mHistoriyActions = (Stack<Integer>) state.getSerializable(KEY_HIS_ACTIONS); } if (state.containsKey(KEY_HIS_TXT)) { mHistories = (Stack<Editable>) state.getSerializable(KEY_HIS_TXT); } if (state.containsKey(KEY_HIS_SELECTION)) { mHistoriesSelection = (Stack<Selection>) state.getSerializable(KEY_HIS_SELECTION); } mLastAction = state.getInt(KEY_MD_ACTION_ID); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.fragment_editor, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_preview: preview(); return true; case R.id.action_discard: discard(); return true; case R.id.action_send: saveTopic(); return true; } return super.onOptionsItemSelected(item); } private void discard() { String msg = getString(R.string.discard_post_msg); ConfirmDialogFragment f = ConfirmDialogFragment.newInstance(null, msg); f.show(getChildFragmentManager(), "discard_confirm"); } private void saveTopic() { if (isEditPost()) { saveEditPost(); return; } boolean hasTitle = isNewTopic() || isPrivateMsg(); String title = null; boolean titleError = false; boolean contentError = false; if (hasTitle) { title = mTitleET.getText().toString().trim(); if (title.length() < TITLE_MIN_LENGTH) { mTitleET.setError(getResources().getString(R.string.e_title_length_error)); titleError = true; } else { mTitleET.setError(null); } } String content = mContentET.getText().toString().trim(); if (content.length() < CONTENT_MIN_LENGTH) { mContentET.setError(getResources().getString(R.string.e_conent_length_error)); contentError = true; } else { mContentET.setError(null); } if (contentError || titleError) { return; } long catId = -1; long tid = -1; String username = null; if (isPrivateMsg()) { username = mUsername; mPostTask = new PostTask(title, content, Api.ARCHETYPE_PRIVATE_MSG, username); mPostTask.execute(); return; } else if (isNewTopic()) { Cursor c = (Cursor) mCategoriesSpinner.getSelectedItem(); if (c != null) { catId = c.getLong(INDEX_UID); } } else { tid = mTopic.id; catId = mTopic.category_id; } int postNumber = isReplyPost() ? mPostNum : -1; mPostTask = new PostTask(catId, title, content, tid, postNumber); mPostTask.execute(); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { return new CursorLoader(getActivity(), Provider.CATEGORIES_CONTENT_URI, CATEGORY_COLUMNS, null, null, UID + " ASC"); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { mCategoryAdapter.swapCursor(data); if (mCategoryIndex > 0 && mCategoryIndex < mCategoryAdapter.getCount()) { mCategoriesSpinner.setSelection(mCategoryIndex); } } @Override public void onLoaderReset(Loader<Cursor> loader) { } private void loadingPostData() { new GetPostTask().execute(); } private void showActonBarProgress() { Activity a = getActivity(); if (a != null) { a.setProgressBarIndeterminateVisibility(Boolean.TRUE); } } private void hideActonBarProgress() { Activity a = getActivity(); if (a != null) { a.setProgressBarIndeterminateVisibility(Boolean.FALSE); } } private void saveEditPost() { String content = mContentET.getText().toString().trim(); boolean contentError = false; if (content.length() < CONTENT_MIN_LENGTH) { mContentET.setError(getResources().getString(R.string.e_conent_length_error)); contentError = true; } else { mContentET.setError(null); } if (contentError) { return; } new EditPostTask(content).execute(); } public void finish(String result) { Activity a = getActivity(); if (a == null) { return; } Intent data = new Intent(); data.putExtra(Utils.EXTRA_MSG, result); a.setResult(Activity.RESULT_OK, data); a.finish(); } public void editPostError() { int res = R.string.saving_post_failure; Toast.makeText(getActivity(), res, Toast.LENGTH_SHORT).show(); } @Override public void onConfirmClicked() { getActivity().finish(); } private void setupMarkdownViews(View view) { mQuoteView = view.findViewById(R.id.e_quote_post); mQuoteView.setOnClickListener(this); view.findViewById(R.id.e_bold).setOnClickListener(this); view.findViewById(R.id.e_code).setOnClickListener(this); view.findViewById(R.id.e_divider).setOnClickListener(this); view.findViewById(R.id.e_header).setOnClickListener(this); view.findViewById(R.id.e_italic).setOnClickListener(this); view.findViewById(R.id.e_link).setOnClickListener(this); view.findViewById(R.id.e_list_ol).setOnClickListener(this); view.findViewById(R.id.e_list_ul).setOnClickListener(this); view.findViewById(R.id.e_upload).setOnClickListener(this); view.findViewById(R.id.e_quote).setOnClickListener(this); L.i("."); if (!isEditPost() && !isNewTopic()) { L.i("..."); mQuoteView.setVisibility(View.VISIBLE); } } @Override public void onClick(View v) { if (!mContentET.isFocused()) { mContentET.requestFocus(); } mContentET.removeTextChangedListener(mTextWatcher); final int id = v.getId(); if (id != R.id.e_header && id != R.id.e_quote_post && mLastAction == id && getContentSelection().equals(mLastSelection)) { undo(); return; } pushToStack(id); switch (id) { case R.id.e_quote_post: markdownQuotePost(); break; case R.id.e_link: markdownLink(); break; case R.id.e_upload: markdownUpload(); break; case R.id.e_quote: markdownQuote(); break; case R.id.e_bold: markdownBold(); break; case R.id.e_italic: markdownItalic(); break; case R.id.e_code: markdownCode(); break; case R.id.e_list_ol: if (mLastAction == R.id.e_list_ol) { mListIndex++; } else { mListIndex = 1; } markdownNumberedList(); break; case R.id.e_list_ul: markdownBulletedList(); break; case R.id.e_header: markdownHeader(); break; case R.id.e_divider: markdownDivider(); break; } mLastAction = id; mLastSelection = getContentSelection(); mContentET.addTextChangedListener(mTextWatcher); } private void markdownQuotePost() { if (mPostRaw == null) { new GetPostTask() { @Override protected void onPostExecute(String result) { hideActonBarProgress(); try { JSONObject obj = new JSONObject(result); Post p = Api.getPost(obj); mPostRaw = p.raw; quotePost(mPostRaw); } catch (JSONException e) { int res = R.string.get_post_content_failure; Toast.makeText(getActivity(), res, Toast.LENGTH_SHORT).show(); } } }.execute(); } else { quotePost(mPostRaw); } } private void quotePost(String raw) { final EditText et = mContentET; Editable editable = et.getText(); int start = et.getSelectionStart(); editable.insert(start, String.format(QUOTE_POST, mUsername, mPostNum, mTopic.id, mPostRaw)); } private void markdownDivider() { final EditText et = mContentET; Editable editable = et.getText(); int start = et.getSelectionStart(); int diff = DIVIDER.length(); if (et.hasSelection()) { int end = et.getSelectionEnd(); editable.replace(start, end, DIVIDER); et.setSelection(start + diff); } else { editable.insert(start, DIVIDER); et.setSelection(start + diff); } } private void markdownHeader() { final EditText et = mContentET; Editable editable = et.getText(); int start = et.getSelectionStart(); int diff = NUMBER_SIGN.length(); if (et.hasSelection()) { int end = et.getSelectionEnd(); editable.insert(start, NUMBER_SIGN); et.setSelection(start + diff, end + diff); } else { editable.insert(start, NUMBER_SIGN); et.setSelection(start + diff); } } private void markdownBulletedList() { final EditText et = mContentET; Editable editable = et.getText(); int start = et.getSelectionStart(); int diff = BULLETED_LIST.length(); if (et.hasSelection()) { int end = et.getSelectionEnd(); editable.insert(end, ENTER); editable.insert(start, BULLETED_LIST); et.setSelection(start + diff, end + diff); } else { editable.insert(start, BULLETED_LIST); et.setSelection(start + diff); } } private void markdownNumberedList() { final EditText et = mContentET; Editable editable = et.getText(); int start = et.getSelectionStart(); String list = String.format(NUM_LIST, mListIndex); int diff = list.length(); if (et.hasSelection()) { int end = et.getSelectionEnd(); editable.insert(end, ENTER); editable.insert(start, list); et.setSelection(start + diff, end + diff); } else { editable.insert(start, list); et.setSelection(start + diff); } } private void markdownCode() { final EditText et = mContentET; Editable editable = et.getText(); int start = et.getSelectionStart(); if (et.hasSelection()) { int end = et.getSelectionEnd(); editable.insert(end, CODE); editable.insert(start, CODE); et.setSelection(start + 1, end + 1); } else { editable.insert(start, CODE2); et.setSelection(start + 1); } } private void pushToStack(int id) { Editable editable = mContentET.getText(); mHistories.push(new SpannableStringBuilder(editable)); L.d(mContentET.getText().toString()); mHistoriesSelection.push(getContentSelection()); mHistoriyActions.push(mLastAction); } private void undo() { if (mHistoriyActions.isEmpty()) { return; } mLastAction = mHistoriyActions.pop(); mLastSelection = mHistoriesSelection.pop(); Editable editable = mHistories.pop(); L.d(editable.toString()); mContentET.setText(editable.toString()); mContentET.setSelection(mLastSelection.start, mLastSelection.end); } private Selection getContentSelection() { return new Selection(mContentET); } protected void clearHistory() { mHistories.clear(); mHistoriesSelection.clear(); mHistoriyActions.clear(); if (mLastAction != R.id.e_list_ol) { mLastAction = 0; } mLastSelection = null; } private void markdownBold() { final EditText et = mContentET; Editable editable = et.getText(); if (et.hasSelection()) { int start = et.getSelectionStart(); int end = et.getSelectionEnd(); editable.insert(end, ASTERISK2); editable.insert(start, ASTERISK2); et.setSelection(start + 2, end + 2); } else { int start = et.getSelectionStart(); editable.insert(start, ASTERISK4); et.setSelection(start + 2); } } private void markdownItalic() { final EditText et = mContentET; Editable editable = et.getText(); if (et.hasSelection()) { int start = et.getSelectionStart(); int end = et.getSelectionEnd(); editable.insert(end, ASTERISK); editable.insert(start, ASTERISK); et.setSelection(start + 1, end + 1); } else { int start = et.getSelectionStart(); editable.insert(start, ASTERISK2); et.setSelection(start + 1); } } private void markdownQuote() { final EditText et = mContentET; Editable editable = et.getText(); int start = et.getSelectionStart(); String quoteStart = null; if (start == 0 || editable.charAt(start - 1) == ENTER_CHAR) { quoteStart = QUOTE_START; } else { quoteStart = QUOTE_START2; } int diff = quoteStart.length(); if (et.hasSelection()) { int end = et.getSelectionEnd(); editable.insert(end, ENTER); editable.insert(start, quoteStart); et.setSelection(start + diff, end + diff); } else { editable.insert(start, quoteStart); et.setSelection(start + diff); } } private void markdownLink() { final EditText et = mContentET; Editable editable = et.getText(); mLinkSelection = new Selection(et); CharSequence des = null; if (!mLinkSelection.isEmpty()) { des = editable.subSequence(mLinkSelection.start, mLinkSelection.end); } AddLinkFragment.newInstance(des).show(getChildFragmentManager(), "add_link_tag"); } private void insertMarkdownLink(String des, String url) { final EditText et = mContentET; Editable editable = et.getText(); int start = et.getSelectionStart(); int desL = des.length(); int sbL = 1; // 当弹出对话框的时候, 文本的选择状态会消失。 if (mLinkSelection.isEmpty()) { editable.insert(start, SB + des + SB2 + "(" + url + ")"); } else { start = mLinkSelection.start; int end = mLinkSelection.end; editable.replace(start, end, SB + des + SB2 + "(" + url + ")"); // editable.insert(start, SB); // editable.insert(start + desL + sbL, SB2); // editable.insert(start + desL + sbL + sbL, "(" + url + ")"); et.setSelection(start + sbL, start + sbL + desL); } } private void markdownUpload() { final EditText et = mContentET; Editable editable = et.getText(); mUploadSelection = new Selection(et); CharSequence des = null; if (!mUploadSelection.isEmpty()) { des = editable.subSequence(mUploadSelection.start, mUploadSelection.end); } AddLinkFragment.newInstance(des, AddLinkFragment.MD_IMG).show(getChildFragmentManager(), "add_link_tag"); } private void insertMarkdownPicture(String des, String url) { final EditText et = mContentET; Editable editable = et.getText(); int start = et.getSelectionStart(); int desL = des.length(); int sbL = 1; // 当弹出对话框的时候, 文本的选择状态会消失。 if (mUploadSelection.isEmpty()) { editable.insert(start, String.format(MARKDOWN_IMG, des, url)); } else { start = mUploadSelection.start; int end = mUploadSelection.end; editable.replace(start, end, String.format(MARKDOWN_IMG, des, url)); // editable.insert(start, SB); // editable.insert(start + desL + sbL, SB2); // editable.insert(start + desL + sbL + sbL, "(" + url + ")"); et.setSelection(start + sbL, start + sbL + desL); } } @Override public void add(int type, String des, String url) { if (TextUtils.isEmpty(url)) { return; } boolean isLink = type == AddLinkFragment.MD_URL; if (isLink && TextUtils.isEmpty(des)) { des = url; } if (isLink) { insertMarkdownLink(des, url); } else if (type == AddLinkFragment.MD_IMG) { insertMarkdownPicture(des, url); } } // TODO --------------- priview private void preview() { PreviewDialogFragment.newInstance(mContentET.getText().toString()).show(getChildFragmentManager(), "preview_tag"); } class PostTask extends AsyncTask<Void, Void, String> { private final static String ARCHETYPE = "archetype"; private final static String CATEGORY = "category"; private final static String RAW = "raw"; private final static String TITLE = "title"; private final static String TOPIC_ID = "topic_id"; private final static String TARGET_USERNAMES = "target_usernames"; private final static String REPLY_TO_POST_NUMBER = "reply_to_post_number"; private final long mCategoryId; private final String mTitle; private final String mContent; private final String mArchetype; private final long mReplyId; private final int mPostNum; private String mUsername; public PostTask(long categoryId, String title, String content) { this(categoryId, title, content, Api.ARCHETYPE_REGULAR, -1, -1); } public PostTask(long categoryId, String title, String content, long replyId, int postNum) { this(categoryId, title, content, Api.ARCHETYPE_REGULAR, replyId, postNum); } public PostTask(String title, String content, String archetype, String username) { this(-1, title, content, archetype, -1, -1); mUsername = username; } public PostTask(long categoryId, String title, String content, String archetype, long replyId, int postNum) { L.i("posts %d title %s content %s", categoryId, title, content); this.mCategoryId = categoryId; this.mTitle = title; this.mContent = content; this.mArchetype = archetype; this.mReplyId = replyId; mPostNum = postNum; } @Override protected String doInBackground(Void... params) { L.d("%s -- %s ", mArchetype, mUsername); try { String url = App.getSiteUrl() + Api.POSTS; HttpRequest hr = HttpRequest.post(url); HttpURLConnection connection = hr.getConnection(); if (App.isLogin()) { App.getCookieManager().setCookies(connection); } hr.form(ARCHETYPE, mArchetype).form(RAW, mContent); if (mCategoryId != -1) { hr.form(CATEGORY, String.valueOf(mCategoryId)); } if (!TextUtils.isEmpty(mTitle)) { hr.form(TITLE, mTitle); } if (mReplyId != -1) { hr.form(TOPIC_ID, String.valueOf(mReplyId)); } if (mPostNum != -1) { hr.form(REPLY_TO_POST_NUMBER, String.valueOf(mPostNum)); } if (mUsername != null) { hr.form(TARGET_USERNAMES, mUsername); } int code = hr.code(); L.i("%s star code %d ", url, code); String body = hr.body(); L.i(body); return body; } catch (Exception e) { L.e(e); return null; } } @Override protected void onPreExecute() { super.onPreExecute(); L.i("posts topic 1"); mProgressFragment = new ProgressFragment(); Bundle args = new Bundle(); args.putString(Utils.EXTRA_MSG, getString(R.string.sending_post)); mProgressFragment.setArguments(args); mProgressFragment.show(getFragmentManager(), "progress"); } @Override protected void onPostExecute(String result) { super.onPostExecute(result); L.i("posts topic 2"); getFragmentManager().beginTransaction().remove(mProgressFragment).commit(); mProgressFragment = null; long topicId = -1; String topicSlug = null; try { JSONObject topic = new JSONObject(result); if (topic.has(Api.K_errors)) { try { JSONArray errors = topic.getJSONArray(Api.K_errors); Toast.makeText(getActivity(), errors.toString(), Toast.LENGTH_LONG).show(); } catch (Exception e) { e.printStackTrace(); } return; } if (topic.has(Api.K_topic_id)) { topicId = topic.getLong(Api.K_topic_id); } if (topic.has(Api.K_topic_slug)) { topicSlug = topic.getString(Api.K_topic_slug); } // {"errors":["Title is too short (minimum is 15 characters)","Title is invalid; try to be a little more descriptive"]} ActivityUtils.startTopicActivity(getActivity(), topicSlug, topicId); getActivity().finish(); } catch (Exception e) { Toast.makeText(getActivity(), R.string.create_post_error, Toast.LENGTH_LONG).show(); L.e(e, "create posts error: " + result); } } } class CategoryAdapter extends CursorAdapter { LayoutInflater mLayoutInflater; Context mContext; public CategoryAdapter(Context context, Cursor c) { super(context, c, false); mContext = context; mLayoutInflater = LayoutInflater.from(context); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return mLayoutInflater.inflate(R.layout.editor_category_item, parent, false); } @Override public void bindView(View view, Context context, Cursor cursor) { TextView category = (TextView) view.findViewById(R.id.category_name); String name = cursor.getString(INDEX_NAME); category.setText(name); // String bgColor = cursor.getString(INDEX_COLOR); // String textColor = cursor.getString(INDEX_TEXT_COLOR); // Utils.setCategoryView(category, name, bgColor, textColor); } public void bindDropDownView(View view, Context context, Cursor cursor) { TextView category = (TextView) view.findViewById(R.id.category_name); TextView topicCount = (TextView) view.findViewById(R.id.category_topic_count); String name = cursor.getString(INDEX_NAME); String bgColor = cursor.getString(INDEX_COLOR); String textColor = cursor.getString(INDEX_TEXT_COLOR); Utils.setCategoryView(category, name, bgColor, textColor); long count = cursor.getLong(INDEX_TOPIC_COUNT); topicCount.setText(mContext.getString(R.string.editor_category_count, count)); } @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { if (mDataValid) { mCursor.moveToPosition(position); View v; if (convertView == null) { v = newDropDownView(mContext, mCursor, parent); } else { v = convertView; } bindDropDownView(v, mContext, mCursor); return v; } else { return null; } } @Override public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) { return mLayoutInflater.inflate(R.layout.editor_category_dropdown_item, parent, false); } } class GetPostTask extends AsyncTask<Void, Void, String> { @Override protected void onPreExecute() { super.onPreExecute(); showActonBarProgress(); } @Override protected String doInBackground(Void... params) { try { String url = App.getSiteUrl() + String.format(Api.GET_POST, mPostId); HttpRequest hr = HttpRequest.get(url); HttpURLConnection connection = hr.getConnection(); if (App.isLogin()) { App.getCookieManager().setCookies(connection); } int code = hr.code(); L.i("%s star code %d ", url, code); String body = hr.body(); L.i(body); return body; } catch (Exception e) { L.e(e); return null; } } @Override protected void onPostExecute(String result) { super.onPostExecute(result); hideActonBarProgress(); try { JSONObject obj = new JSONObject(result); Post p = Api.getPost(obj); mContentET.setText(p.raw); } catch (JSONException e) { int res = R.string.get_post_content_failure; Toast.makeText(getActivity(), res, Toast.LENGTH_SHORT).show(); } } } class EditPostTask extends AsyncTask<Void, Void, String> { private static final String RAW_PARAM = "post[raw]"; private final String mRaw; public EditPostTask(String raw) { mRaw = raw; } @Override protected String doInBackground(Void... params) { try { String url = App.getSiteUrl() + String.format(Api.GET_POST, mPostId); HttpRequest hr = HttpRequest.put(url); HttpURLConnection connection = hr.getConnection(); if (App.isLogin()) { App.getCookieManager().setCookies(connection); } hr.form(RAW_PARAM, mRaw); int code = hr.code(); L.i("%s star code %d ", url, code); String body = hr.body(); return body; } catch (Exception e) { L.e(e); return null; } } @Override protected void onPreExecute() { super.onPreExecute(); L.i("posts topic 1"); mProgressFragment = new ProgressFragment(); Bundle args = new Bundle(); args.putString(Utils.EXTRA_MSG, getString(R.string.sending_post)); mProgressFragment.setArguments(args); mProgressFragment.show(getFragmentManager(), "progress"); } @Override protected void onPostExecute(String result) { super.onPostExecute(result); L.i("posts topic 2"); getFragmentManager().beginTransaction().remove(mProgressFragment).commit(); mProgressFragment = null; try { JSONObject obj = new JSONObject(result); if (obj.has(Api.K_errors)) { try { JSONArray errors = obj.getJSONArray(Api.K_errors); Toast.makeText(getActivity(), errors.toString(), Toast.LENGTH_LONG).show(); } catch (Exception e) { e.printStackTrace(); } return; } if (obj.has(Api.K_post)) { finish(result); } else { editPostError(); } } catch (JSONException e) { editPostError(); } } } }