|
|
@ -66,57 +66,55 @@ public class StyleHelper {
|
|
|
|
Log.i("Style action=" + action);
|
|
|
|
Log.i("Style action=" + action);
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
int start = etBody.getSelectionStart();
|
|
|
|
int _start = etBody.getSelectionStart();
|
|
|
|
int end = etBody.getSelectionEnd();
|
|
|
|
int _end = etBody.getSelectionEnd();
|
|
|
|
|
|
|
|
|
|
|
|
if (start < 0)
|
|
|
|
if (_start < 0)
|
|
|
|
start = 0;
|
|
|
|
_start = 0;
|
|
|
|
if (end < 0)
|
|
|
|
if (_end < 0)
|
|
|
|
end = 0;
|
|
|
|
_end = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (start > end) {
|
|
|
|
if (_start > _end) {
|
|
|
|
int tmp = start;
|
|
|
|
int tmp = _start;
|
|
|
|
start = end;
|
|
|
|
_start = _end;
|
|
|
|
end = tmp;
|
|
|
|
_end = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SpannableString ss = new SpannableString(etBody.getText());
|
|
|
|
final Editable edit = etBody.getText();
|
|
|
|
|
|
|
|
final int start = _start;
|
|
|
|
|
|
|
|
final int end = _end;
|
|
|
|
|
|
|
|
|
|
|
|
if (action == R.id.menu_bold || action == R.id.menu_italic) {
|
|
|
|
if (action == R.id.menu_bold || action == R.id.menu_italic) {
|
|
|
|
int style = (action == R.id.menu_bold ? Typeface.BOLD : Typeface.ITALIC);
|
|
|
|
int style = (action == R.id.menu_bold ? Typeface.BOLD : Typeface.ITALIC);
|
|
|
|
boolean has = false;
|
|
|
|
boolean has = false;
|
|
|
|
for (StyleSpan span : ss.getSpans(start, end, StyleSpan.class))
|
|
|
|
for (StyleSpan span : edit.getSpans(start, end, StyleSpan.class))
|
|
|
|
if (span.getStyle() == style) {
|
|
|
|
if (span.getStyle() == style) {
|
|
|
|
has = true;
|
|
|
|
has = true;
|
|
|
|
ss.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!has)
|
|
|
|
if (!has)
|
|
|
|
ss.setSpan(new StyleSpan(style), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
edit.setSpan(new StyleSpan(style), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(ss);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
} else if (action == R.id.menu_underline) {
|
|
|
|
} else if (action == R.id.menu_underline) {
|
|
|
|
boolean has = false;
|
|
|
|
boolean has = false;
|
|
|
|
for (UnderlineSpan span : ss.getSpans(start, end, UnderlineSpan.class)) {
|
|
|
|
for (UnderlineSpan span : edit.getSpans(start, end, UnderlineSpan.class)) {
|
|
|
|
has = true;
|
|
|
|
has = true;
|
|
|
|
ss.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!has)
|
|
|
|
if (!has)
|
|
|
|
ss.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
edit.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(ss);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
} else if (action == R.id.menu_style) {
|
|
|
|
} else if (action == R.id.menu_style) {
|
|
|
|
final int s = start;
|
|
|
|
|
|
|
|
final int e = end;
|
|
|
|
|
|
|
|
final SpannableStringBuilder t = new SpannableStringBuilder(ss);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(anchor.getContext(), owner, anchor);
|
|
|
|
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(anchor.getContext(), owner, anchor);
|
|
|
|
popupMenu.inflate(R.menu.popup_style);
|
|
|
|
popupMenu.inflate(R.menu.popup_style);
|
|
|
|
|
|
|
|
|
|
|
@ -156,9 +154,9 @@ public class StyleHelper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setSize(MenuItem item) {
|
|
|
|
private boolean setSize(MenuItem item) {
|
|
|
|
RelativeSizeSpan[] spans = t.getSpans(s, e, RelativeSizeSpan.class);
|
|
|
|
RelativeSizeSpan[] spans = edit.getSpans(start, end, RelativeSizeSpan.class);
|
|
|
|
for (RelativeSizeSpan span : spans)
|
|
|
|
for (RelativeSizeSpan span : spans)
|
|
|
|
t.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
Float size;
|
|
|
|
Float size;
|
|
|
|
if (item.getItemId() == R.id.menu_style_size_small)
|
|
|
|
if (item.getItemId() == R.id.menu_style_size_small)
|
|
|
@ -169,10 +167,10 @@ public class StyleHelper {
|
|
|
|
size = null;
|
|
|
|
size = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (size != null)
|
|
|
|
if (size != null)
|
|
|
|
t.setSpan(new RelativeSizeSpan(size), s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
edit.setSpan(new RelativeSizeSpan(size), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(t);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -210,24 +208,24 @@ public class StyleHelper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void _setColor(Integer color) {
|
|
|
|
private void _setColor(Integer color) {
|
|
|
|
for (ForegroundColorSpan span : t.getSpans(s, e, ForegroundColorSpan.class))
|
|
|
|
for (ForegroundColorSpan span : edit.getSpans(start, end, ForegroundColorSpan.class))
|
|
|
|
t.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
if (color != null)
|
|
|
|
if (color != null)
|
|
|
|
t.setSpan(new ForegroundColorSpan(color), s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
edit.setSpan(new ForegroundColorSpan(color), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(t);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setAlignment(MenuItem item) {
|
|
|
|
private boolean setAlignment(MenuItem item) {
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(t, s, e);
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
int start = paragraph.first;
|
|
|
|
int s = paragraph.first;
|
|
|
|
int end = paragraph.second;
|
|
|
|
int e = paragraph.second;
|
|
|
|
|
|
|
|
|
|
|
|
AlignmentSpan[] spans = t.getSpans(start, end, AlignmentSpan.class);
|
|
|
|
AlignmentSpan[] spans = edit.getSpans(s, e, AlignmentSpan.class);
|
|
|
|
for (AlignmentSpan span : spans)
|
|
|
|
for (AlignmentSpan span : spans)
|
|
|
|
t.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
Layout.Alignment alignment = null;
|
|
|
|
Layout.Alignment alignment = null;
|
|
|
|
boolean ltr = (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_LTR);
|
|
|
|
boolean ltr = (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_LTR);
|
|
|
@ -241,11 +239,11 @@ public class StyleHelper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (alignment != null)
|
|
|
|
if (alignment != null)
|
|
|
|
t.setSpan(new AlignmentSpan.Standard(alignment),
|
|
|
|
edit.setSpan(new AlignmentSpan.Standard(alignment),
|
|
|
|
start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(t);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -261,54 +259,54 @@ public class StyleHelper {
|
|
|
|
int message_zoom = prefs.getInt("message_zoom", 100);
|
|
|
|
int message_zoom = prefs.getInt("message_zoom", 100);
|
|
|
|
float textSize = Helper.getTextSize(context, 0) * message_zoom / 100f;
|
|
|
|
float textSize = Helper.getTextSize(context, 0) * message_zoom / 100f;
|
|
|
|
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(t, s, e);
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
int start = paragraph.first;
|
|
|
|
int s = paragraph.first;
|
|
|
|
int end = paragraph.second;
|
|
|
|
int e = paragraph.second;
|
|
|
|
|
|
|
|
|
|
|
|
// Remove existing bullets
|
|
|
|
// Remove existing bullets
|
|
|
|
BulletSpan[] spans = t.getSpans(start, end, BulletSpan.class);
|
|
|
|
BulletSpan[] spans = edit.getSpans(s, e, BulletSpan.class);
|
|
|
|
for (BulletSpan span : spans)
|
|
|
|
for (BulletSpan span : spans)
|
|
|
|
t.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
int i = start;
|
|
|
|
int i = s;
|
|
|
|
int j = start + 1;
|
|
|
|
int j = s + 1;
|
|
|
|
int index = 1;
|
|
|
|
int index = 1;
|
|
|
|
while (j < end) {
|
|
|
|
while (j < e) {
|
|
|
|
if (i > 0 && t.charAt(i - 1) == '\n' && t.charAt(j) == '\n') {
|
|
|
|
if (i > 0 && edit.charAt(i - 1) == '\n' && edit.charAt(j) == '\n') {
|
|
|
|
Log.i("Insert " + i + "..." + (j + 1) + " size=" + end);
|
|
|
|
Log.i("Insert " + i + "..." + (j + 1) + " size=" + e);
|
|
|
|
if (item.getItemId() == R.id.menu_style_list_bullets)
|
|
|
|
if (item.getItemId() == R.id.menu_style_list_bullets)
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
|
|
|
t.setSpan(new BulletSpan(dp6, colorAccent), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
edit.setSpan(new BulletSpan(dp6, colorAccent), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
else
|
|
|
|
else
|
|
|
|
t.setSpan(new BulletSpan(dp6, colorAccent, dp3), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
edit.setSpan(new BulletSpan(dp6, colorAccent, dp3), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
else
|
|
|
|
else
|
|
|
|
t.setSpan(new NumberSpan(dp6, colorAccent, textSize, index++), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
edit.setSpan(new NumberSpan(dp6, colorAccent, textSize, index++), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
|
|
|
|
i = j + 1;
|
|
|
|
i = j + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(t);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setFont(MenuItem item) {
|
|
|
|
private boolean setFont(MenuItem item) {
|
|
|
|
TypefaceSpan[] spans = t.getSpans(s, e, TypefaceSpan.class);
|
|
|
|
TypefaceSpan[] spans = edit.getSpans(start, end, TypefaceSpan.class);
|
|
|
|
for (TypefaceSpan span : spans)
|
|
|
|
for (TypefaceSpan span : spans)
|
|
|
|
t.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
int id = item.getItemId();
|
|
|
|
int id = item.getItemId();
|
|
|
|
String[] names = anchor.getResources().getStringArray(R.array.fontNameValues);
|
|
|
|
String[] names = anchor.getResources().getStringArray(R.array.fontNameValues);
|
|
|
|
String face = (id < names.length ? names[id] : null);
|
|
|
|
String face = (id < names.length ? names[id] : null);
|
|
|
|
|
|
|
|
|
|
|
|
if (face != null)
|
|
|
|
if (face != null)
|
|
|
|
t.setSpan(new TypefaceSpan(face), s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
edit.setSpan(new TypefaceSpan(face), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(t);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -320,66 +318,65 @@ public class StyleHelper {
|
|
|
|
int dp3 = Helper.dp2pixels(context, 3);
|
|
|
|
int dp3 = Helper.dp2pixels(context, 3);
|
|
|
|
int dp6 = Helper.dp2pixels(context, 6);
|
|
|
|
int dp6 = Helper.dp2pixels(context, 6);
|
|
|
|
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(t, s, e);
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
int start = paragraph.first;
|
|
|
|
int s = paragraph.first;
|
|
|
|
int end = paragraph.second;
|
|
|
|
int e = paragraph.second;
|
|
|
|
|
|
|
|
|
|
|
|
QuoteSpan[] spans = t.getSpans(s, e, QuoteSpan.class);
|
|
|
|
QuoteSpan[] spans = edit.getSpans(s, e, QuoteSpan.class);
|
|
|
|
for (QuoteSpan span : spans)
|
|
|
|
for (QuoteSpan span : spans)
|
|
|
|
t.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
QuoteSpan q;
|
|
|
|
QuoteSpan q;
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
|
|
|
q = new QuoteSpan(colorPrimary);
|
|
|
|
q = new QuoteSpan(colorPrimary);
|
|
|
|
else
|
|
|
|
else
|
|
|
|
q = new QuoteSpan(colorPrimary, dp3, dp6);
|
|
|
|
q = new QuoteSpan(colorPrimary, dp3, dp6);
|
|
|
|
t.setSpan(q, start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
|
|
edit.setSpan(q, s, e, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(t);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setStrikeThrough(MenuItem item) {
|
|
|
|
private boolean setStrikeThrough(MenuItem item) {
|
|
|
|
boolean has = false;
|
|
|
|
boolean has = false;
|
|
|
|
for (StrikethroughSpan span : t.getSpans(s, e, StrikethroughSpan.class)) {
|
|
|
|
for (StrikethroughSpan span : edit.getSpans(start, end, StrikethroughSpan.class)) {
|
|
|
|
has = true;
|
|
|
|
has = true;
|
|
|
|
t.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!has)
|
|
|
|
if (!has)
|
|
|
|
t.setSpan(new StrikethroughSpan(), s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
edit.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(t);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean clear(MenuItem item) {
|
|
|
|
private boolean clear(MenuItem item) {
|
|
|
|
int start = s;
|
|
|
|
int e = end;
|
|
|
|
int end = e;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Expand to paragraph (block quotes)
|
|
|
|
// Expand to paragraph (block quotes)
|
|
|
|
if (end + 1 < t.length() && t.charAt(end) == '\n')
|
|
|
|
if (e + 1 < edit.length() && edit.charAt(e) == '\n')
|
|
|
|
end++;
|
|
|
|
e++;
|
|
|
|
|
|
|
|
|
|
|
|
for (Object span : t.getSpans(start, end, Object.class))
|
|
|
|
for (Object span : edit.getSpans(start, e, Object.class))
|
|
|
|
if (!(span instanceof ImageSpan)) {
|
|
|
|
if (!(span instanceof ImageSpan)) {
|
|
|
|
int sstart = t.getSpanStart(span);
|
|
|
|
int sstart = edit.getSpanStart(span);
|
|
|
|
int send = t.getSpanEnd(span);
|
|
|
|
int send = edit.getSpanEnd(span);
|
|
|
|
int flags = t.getSpanFlags(span);
|
|
|
|
int flags = edit.getSpanFlags(span);
|
|
|
|
if (sstart < start && send > start)
|
|
|
|
if (sstart < start && send > start)
|
|
|
|
setSpan(t, span, sstart, start, flags, etBody.getContext());
|
|
|
|
setSpan(edit, span, sstart, start, flags, etBody.getContext());
|
|
|
|
if (sstart < end && send > end)
|
|
|
|
if (sstart < end && send > end)
|
|
|
|
setSpan(t, span, end, send, flags, etBody.getContext());
|
|
|
|
setSpan(edit, span, e, send, flags, etBody.getContext());
|
|
|
|
|
|
|
|
|
|
|
|
t.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(t);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
etBody.setSelection(start, e);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -392,36 +389,36 @@ public class StyleHelper {
|
|
|
|
String url = (String) args[0];
|
|
|
|
String url = (String) args[0];
|
|
|
|
|
|
|
|
|
|
|
|
List<Object> spans = new ArrayList<>();
|
|
|
|
List<Object> spans = new ArrayList<>();
|
|
|
|
for (Object span : ss.getSpans(start, end, Object.class)) {
|
|
|
|
for (Object span : edit.getSpans(start, end, Object.class)) {
|
|
|
|
if (!(span instanceof URLSpan))
|
|
|
|
if (!(span instanceof URLSpan))
|
|
|
|
spans.add(span);
|
|
|
|
spans.add(span);
|
|
|
|
ss.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (url != null) {
|
|
|
|
if (url != null) {
|
|
|
|
|
|
|
|
int e = end;
|
|
|
|
if (start == end) {
|
|
|
|
if (start == end) {
|
|
|
|
etBody.getText().insert(start, url);
|
|
|
|
etBody.getText().insert(start, url);
|
|
|
|
end += url.length();
|
|
|
|
e += url.length();
|
|
|
|
ss = new SpannableString(etBody.getText());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ss.setSpan(new URLSpan(url), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
edit.setSpan(new URLSpan(url), start, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Restore other spans
|
|
|
|
// Restore other spans
|
|
|
|
for (Object span : spans)
|
|
|
|
for (Object span : spans)
|
|
|
|
ss.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
edit.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(ss);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(end, end);
|
|
|
|
etBody.setSelection(end, end);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
} else if (action == R.id.menu_clear) {
|
|
|
|
} else if (action == R.id.menu_clear) {
|
|
|
|
for (Object span : ss.getSpans(0, etBody.length(), Object.class))
|
|
|
|
for (Object span : edit.getSpans(0, etBody.length(), Object.class))
|
|
|
|
if (!(span instanceof ImageSpan))
|
|
|
|
if (!(span instanceof ImageSpan))
|
|
|
|
ss.removeSpan(span);
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(ss);
|
|
|
|
etBody.setText(edit);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
@ -433,26 +430,26 @@ public class StyleHelper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void setSpan(SpannableStringBuilder ss, Object span, int start, int end, int flags, Context context) {
|
|
|
|
static void setSpan(Editable edit, Object span, int start, int end, int flags, Context context) {
|
|
|
|
if (span instanceof CharacterStyle)
|
|
|
|
if (span instanceof CharacterStyle)
|
|
|
|
ss.setSpan(CharacterStyle.wrap((CharacterStyle) span), start, end, flags);
|
|
|
|
edit.setSpan(CharacterStyle.wrap((CharacterStyle) span), start, end, flags);
|
|
|
|
else if (span instanceof QuoteSpan) {
|
|
|
|
else if (span instanceof QuoteSpan) {
|
|
|
|
ParagraphStyle ps = (ParagraphStyle) span;
|
|
|
|
ParagraphStyle ps = (ParagraphStyle) span;
|
|
|
|
Pair<Integer, Integer> p = ensureParagraph(ss, start, end);
|
|
|
|
Pair<Integer, Integer> p = ensureParagraph(edit, start, end);
|
|
|
|
ss.setSpan(clone(span, ps.getClass(), context), p.first, p.second, flags);
|
|
|
|
edit.setSpan(clone(span, ps.getClass(), context), p.first, p.second, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static private Pair<Integer, Integer> ensureParagraph(SpannableStringBuilder t, int s, int e) {
|
|
|
|
static private Pair<Integer, Integer> ensureParagraph(Editable edit, int s, int e) {
|
|
|
|
int start = s;
|
|
|
|
int start = s;
|
|
|
|
int end = e;
|
|
|
|
int end = e;
|
|
|
|
|
|
|
|
|
|
|
|
// Expand selection at start
|
|
|
|
// Expand selection at start
|
|
|
|
while (start > 0 && t.charAt(start - 1) != '\n')
|
|
|
|
while (start > 0 && edit.charAt(start - 1) != '\n')
|
|
|
|
start--;
|
|
|
|
start--;
|
|
|
|
|
|
|
|
|
|
|
|
// Expand selection at end
|
|
|
|
// Expand selection at end
|
|
|
|
while (end > 0 && end < t.length() && t.charAt(end - 1) != '\n')
|
|
|
|
while (end > 0 && end < edit.length() && edit.charAt(end - 1) != '\n')
|
|
|
|
end++;
|
|
|
|
end++;
|
|
|
|
|
|
|
|
|
|
|
|
// Nothing to do
|
|
|
|
// Nothing to do
|
|
|
@ -460,20 +457,20 @@ public class StyleHelper {
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
// Create paragraph at start
|
|
|
|
// Create paragraph at start
|
|
|
|
if (start == 0 && t.charAt(start) != '\n') {
|
|
|
|
if (start == 0 && edit.charAt(start) != '\n') {
|
|
|
|
t.insert(0, "\n");
|
|
|
|
edit.insert(0, "\n");
|
|
|
|
start++;
|
|
|
|
start++;
|
|
|
|
end++;
|
|
|
|
end++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create paragraph at end
|
|
|
|
// Create paragraph at end
|
|
|
|
if (end == t.length() && t.charAt(end - 1) != '\n') {
|
|
|
|
if (end == edit.length() && edit.charAt(end - 1) != '\n') {
|
|
|
|
t.append("\n");
|
|
|
|
edit.append("\n");
|
|
|
|
end++;
|
|
|
|
end++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (end == t.length())
|
|
|
|
if (end == edit.length())
|
|
|
|
t.append("\n"); // workaround Android bug
|
|
|
|
edit.append("\n"); // workaround Android bug
|
|
|
|
|
|
|
|
|
|
|
|
return new Pair(start, end);
|
|
|
|
return new Pair(start, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|