Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-notes.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/it/niedermann/owncloud/notes/edit/format/ContextBasedRangeFormattingCallback.java')
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/format/ContextBasedRangeFormattingCallback.java150
1 files changed, 150 insertions, 0 deletions
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/format/ContextBasedRangeFormattingCallback.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/format/ContextBasedRangeFormattingCallback.java
new file mode 100644
index 00000000..91f3b9f3
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/format/ContextBasedRangeFormattingCallback.java
@@ -0,0 +1,150 @@
+package it.niedermann.owncloud.notes.edit.format;
+
+import android.graphics.Typeface;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.StyleSpan;
+import android.util.SparseIntArray;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.EditText;
+
+import it.niedermann.owncloud.notes.R;
+
+import static it.niedermann.owncloud.notes.shared.util.ClipboardUtil.getClipboardURLorNull;
+
+public class ContextBasedRangeFormattingCallback implements ActionMode.Callback {
+
+ private static final String TAG = ContextBasedRangeFormattingCallback.class.getSimpleName();
+
+ private final EditText editText;
+
+ public ContextBasedRangeFormattingCallback(EditText editText) {
+ this.editText = editText;
+ }
+
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ mode.getMenuInflater().inflate(R.menu.context_based_range_formatting, menu);
+
+ SparseIntArray styleFormatMap = new SparseIntArray();
+ styleFormatMap.append(R.id.bold, Typeface.BOLD);
+ styleFormatMap.append(R.id.italic, Typeface.ITALIC);
+
+ MenuItem item;
+ CharSequence title;
+ SpannableStringBuilder ssb;
+
+ for (int i = 0; i < styleFormatMap.size(); i++) {
+ item = menu.findItem(styleFormatMap.keyAt(i));
+ title = item.getTitle();
+ ssb = new SpannableStringBuilder(title);
+ ssb.setSpan(new StyleSpan(styleFormatMap.valueAt(i)), 0, title.length(), 0);
+ item.setTitle(ssb);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ // TODO hide actions if not available?
+ return false;
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ int start = editText.getSelectionStart();
+ int end = editText.getSelectionEnd();
+ SpannableStringBuilder ssb = new SpannableStringBuilder(editText.getText());
+ final String markdown;
+
+
+ switch (item.getItemId()) {
+ case R.id.bold:
+ markdown = "**";
+ if (hasAlreadyMarkdown(start, end, markdown)) {
+ this.removeMarkdown(ssb, start, end, markdown);
+ } else {
+ this.addMarkdown(ssb, start, end, markdown, Typeface.BOLD);
+ }
+ editText.setText(ssb);
+ editText.setSelection(end + markdown.length() * 2);
+ return true;
+ case R.id.italic:
+ markdown = "*";
+ if (hasAlreadyMarkdown(start, end, markdown)) {
+ this.removeMarkdown(ssb, start, end, markdown);
+ } else {
+ this.addMarkdown(ssb, start, end, markdown, Typeface.ITALIC);
+ }
+ editText.setText(ssb);
+ editText.setSelection(end + markdown.length() * 2);
+ return true;
+ case R.id.link:
+ boolean textToFormatIsLink = TextUtils.indexOf(editText.getText().subSequence(start, end), "http") == 0;
+ if (textToFormatIsLink) {
+ ssb.insert(end, ")");
+ ssb.insert(start, "[](");
+ } else {
+ String clipboardURL = getClipboardURLorNull(editText.getContext());
+ if (clipboardURL != null) {
+ ssb.insert(end, "](" + clipboardURL + ")");
+ end += clipboardURL.length();
+ } else {
+ ssb.insert(end, "]()");
+ }
+ ssb.insert(start, "[");
+ }
+ end++;
+ ssb.setSpan(new StyleSpan(Typeface.NORMAL), start, end, 1);
+ editText.setText(ssb);
+ if (textToFormatIsLink) {
+ editText.setSelection(start + 1);
+ } else {
+ editText.setSelection(end + 2); // after <end>](
+ }
+ return true;
+ case android.R.id.cut:
+ // https://github.com/stefan-niedermann/nextcloud-notes/issues/604
+ // https://github.com/stefan-niedermann/nextcloud-notes/issues/477
+ try {
+ editText.onTextContextMenuItem(item.getItemId());
+ return true;
+ } catch (IndexOutOfBoundsException e) {
+ e.printStackTrace();
+ editText.setSelection(0, 0);
+ editText.clearFocus();
+ return true;
+ }
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ // Nothing to do here...
+ }
+
+ private boolean hasAlreadyMarkdown(int start, int end, String markdown) {
+ return start > markdown.length() && markdown.contentEquals(editText.getText().subSequence(start - markdown.length(), start)) &&
+ editText.getText().length() > end + markdown.length() && markdown.contentEquals(editText.getText().subSequence(end, end + markdown.length()));
+ }
+
+ private void removeMarkdown(SpannableStringBuilder ssb, int start, int end, String markdown) {
+ // FIXME disabled, because it does not work properly and might cause data loss
+ // ssb.delete(start - markdown.length(), start);
+ // ssb.delete(end - markdown.length(), end);
+ // ssb.setSpan(new StyleSpan(Typeface.NORMAL), start, end, 1);
+ }
+
+ private void addMarkdown(SpannableStringBuilder ssb, int start, int end, String markdown, int typeface) {
+ ssb.insert(end, markdown);
+ ssb.insert(start, markdown);
+ editText.getText().charAt(start);
+ editText.getText().charAt(start + 1);
+ ssb.setSpan(new StyleSpan(typeface), start, end + markdown.length() * 2, 1);
+ }
+}