package eu.faircode.email; import android.graphics.Typeface; import android.text.SpannableString; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import android.text.style.URLSpan; import android.text.style.UnderlineSpan; import android.widget.EditText; import java.util.ArrayList; import java.util.List; public class StyleHelper { static boolean apply(int action, EditText etBody, Object... args) { Log.i("Style action=" + action); try { int start = etBody.getSelectionStart(); int end = etBody.getSelectionEnd(); if (start < 0) start = 0; if (end < 0) end = 0; if (start > end) { int tmp = start; start = end; end = tmp; } SpannableString ss = new SpannableString(etBody.getText()); switch (action) { case R.id.menu_bold: case R.id.menu_italic: { int style = (action == R.id.menu_bold ? Typeface.BOLD : Typeface.ITALIC); boolean has = false; for (StyleSpan span : ss.getSpans(start, end, StyleSpan.class)) if (span.getStyle() == style) { has = true; ss.removeSpan(span); } if (!has) ss.setSpan(new StyleSpan(style), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); etBody.setText(ss); etBody.setSelection(start, end); return true; } case R.id.menu_underline: { boolean has = false; for (UnderlineSpan span : ss.getSpans(start, end, UnderlineSpan.class)) { has = true; ss.removeSpan(span); } if (!has) ss.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); etBody.setText(ss); etBody.setSelection(start, end); return true; } case R.id.menu_size: { RelativeSizeSpan[] spans = ss.getSpans(start, end, RelativeSizeSpan.class); float size = (spans.length > 0 ? spans[0].getSizeChange() : 1.0f); // Match small/big if (size == 0.8f) size = 1.0f; else if (size == 1.0) size = 1.25f; else size = 0.8f; for (RelativeSizeSpan span : spans) ss.removeSpan(span); if (size != 1.0f) ss.setSpan(new RelativeSizeSpan(size), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); etBody.setText(ss); etBody.setSelection(start, end); return true; } case R.id.menu_color: { for (ForegroundColorSpan span : ss.getSpans(start, end, ForegroundColorSpan.class)) ss.removeSpan(span); ss.setSpan(new ForegroundColorSpan((int) args[0]), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); etBody.setText(ss); etBody.setSelection(start, end); return true; } case R.id.menu_link: { List spans = new ArrayList<>(); for (Object span : ss.getSpans(start, end, Object.class)) { if (!(span instanceof URLSpan)) spans.add(span); ss.removeSpan(span); } ss.setSpan(new URLSpan((String) args[0]), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); for (Object span : spans) ss.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); etBody.setText(ss); etBody.setSelection(end, end); return true; } case R.id.menu_clear: { boolean selected = (start != end); if (start == end) { start = 0; end = etBody.length(); } for (Object span : ss.getSpans(start, end, Object.class)) if (!(span instanceof ImageSpan)) ss.removeSpan(span); etBody.setText(ss); if (selected) etBody.setSelection(start, end); return true; } default: return false; } } catch (Throwable ex) { Log.e(ex); return false; } } }