|
|
@ -236,17 +236,17 @@ public class StyleHelper {
|
|
|
|
groupId == R.id.group_style_font_custom) {
|
|
|
|
groupId == R.id.group_style_font_custom) {
|
|
|
|
return setFont(item);
|
|
|
|
return setFont(item);
|
|
|
|
} else if (groupId == R.id.group_style_align) {
|
|
|
|
} else if (groupId == R.id.group_style_align) {
|
|
|
|
return setAlignment(item);
|
|
|
|
return setAlignment(item.getItemId(), etBody, start, end);
|
|
|
|
} else if (groupId == R.id.group_style_list) {
|
|
|
|
} else if (groupId == R.id.group_style_list) {
|
|
|
|
if (item.getItemId() == R.id.menu_style_list_increase ||
|
|
|
|
if (item.getItemId() == R.id.menu_style_list_increase ||
|
|
|
|
item.getItemId() == R.id.menu_style_list_decrease)
|
|
|
|
item.getItemId() == R.id.menu_style_list_decrease)
|
|
|
|
return setListLevel(item);
|
|
|
|
return setListLevel(item.getItemId(), etBody, start, end);
|
|
|
|
else
|
|
|
|
else
|
|
|
|
return setList(item);
|
|
|
|
return setList(item.getItemId(), etBody, start, end);
|
|
|
|
} else if (groupId == R.id.group_style_blockquote) {
|
|
|
|
|
|
|
|
return setBlockQuote(item);
|
|
|
|
|
|
|
|
} else if (groupId == R.id.group_style_indentation) {
|
|
|
|
} else if (groupId == R.id.group_style_indentation) {
|
|
|
|
return setIndentation(item);
|
|
|
|
return setIndentation(item.getItemId(), etBody, start, end);
|
|
|
|
|
|
|
|
} else if (groupId == R.id.group_style_blockquote) {
|
|
|
|
|
|
|
|
return setBlockQuote(etBody, start, end);
|
|
|
|
} else if (groupId == R.id.group_style_mark) {
|
|
|
|
} else if (groupId == R.id.group_style_mark) {
|
|
|
|
return setMark(item);
|
|
|
|
return setMark(item);
|
|
|
|
} else if (groupId == R.id.group_style_strikethrough) {
|
|
|
|
} else if (groupId == R.id.group_style_strikethrough) {
|
|
|
@ -418,121 +418,6 @@ public class StyleHelper {
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setAlignment(MenuItem item) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "alignment");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
|
|
|
|
if (paragraph == null)
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int s = paragraph.first;
|
|
|
|
|
|
|
|
int e = paragraph.second;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AlignmentSpan[] spans = edit.getSpans(s, e, AlignmentSpan.class);
|
|
|
|
|
|
|
|
for (AlignmentSpan span : spans)
|
|
|
|
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Layout.Alignment alignment = null;
|
|
|
|
|
|
|
|
boolean ltr = (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_LTR);
|
|
|
|
|
|
|
|
int itemId = item.getItemId();
|
|
|
|
|
|
|
|
if (itemId == R.id.menu_style_align_start) {
|
|
|
|
|
|
|
|
alignment = (ltr ? Layout.Alignment.ALIGN_NORMAL : Layout.Alignment.ALIGN_OPPOSITE);
|
|
|
|
|
|
|
|
} else if (itemId == R.id.menu_style_align_center) {
|
|
|
|
|
|
|
|
alignment = Layout.Alignment.ALIGN_CENTER;
|
|
|
|
|
|
|
|
} else if (itemId == R.id.menu_style_align_end) {
|
|
|
|
|
|
|
|
alignment = (ltr ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (alignment != null)
|
|
|
|
|
|
|
|
edit.setSpan(new AlignmentSpan.Standard(alignment),
|
|
|
|
|
|
|
|
s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setListLevel(MenuItem item) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "level");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Context context = etBody.getContext();
|
|
|
|
|
|
|
|
int add = (item.getItemId() == R.id.menu_style_list_increase ? 1 : -1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean renum = false;
|
|
|
|
|
|
|
|
BulletSpan[] spans = edit.getSpans(start, end, BulletSpan.class);
|
|
|
|
|
|
|
|
for (BulletSpan span : spans)
|
|
|
|
|
|
|
|
if (span instanceof BulletSpanEx) {
|
|
|
|
|
|
|
|
BulletSpanEx bs = (BulletSpanEx) span;
|
|
|
|
|
|
|
|
bs.setLevel(bs.getLevel() + add);
|
|
|
|
|
|
|
|
} else if (span instanceof NumberSpan) {
|
|
|
|
|
|
|
|
renum = true;
|
|
|
|
|
|
|
|
NumberSpan ns = (NumberSpan) span;
|
|
|
|
|
|
|
|
ns.setLevel(ns.getLevel() + add);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (renum)
|
|
|
|
|
|
|
|
renumber(edit, false, context);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setList(MenuItem item) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "list");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Context context = etBody.getContext();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int colorAccent = Helper.resolveColor(context, R.attr.colorAccent);
|
|
|
|
|
|
|
|
int bulletGap = context.getResources().getDimensionPixelSize(R.dimen.bullet_gap_size);
|
|
|
|
|
|
|
|
int bulletRadius = context.getResources().getDimensionPixelSize(R.dimen.bullet_radius_size);
|
|
|
|
|
|
|
|
int bulletIndent = context.getResources().getDimensionPixelSize(R.dimen.bullet_indent_size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
|
|
|
|
|
|
int message_zoom = prefs.getInt("message_zoom", 100);
|
|
|
|
|
|
|
|
float textSize = Helper.getTextSize(context, 0) * message_zoom / 100f;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
|
|
|
|
if (paragraph == null)
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int s = paragraph.first;
|
|
|
|
|
|
|
|
int e = paragraph.second;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove existing bullets
|
|
|
|
|
|
|
|
BulletSpan[] spans = edit.getSpans(s, e, BulletSpan.class);
|
|
|
|
|
|
|
|
for (BulletSpan span : spans)
|
|
|
|
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int i = s;
|
|
|
|
|
|
|
|
int j = s + 1;
|
|
|
|
|
|
|
|
int index = 1;
|
|
|
|
|
|
|
|
while (j < e) {
|
|
|
|
|
|
|
|
if (i > 0 && edit.charAt(i - 1) == '\n' && edit.charAt(j) == '\n') {
|
|
|
|
|
|
|
|
Log.i("Insert " + i + "..." + (j + 1) + " size=" + e);
|
|
|
|
|
|
|
|
if (item.getItemId() == R.id.menu_style_list_bullets)
|
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
|
|
|
|
|
|
|
edit.setSpan(new BulletSpanEx(bulletIndent, bulletGap, colorAccent, 0), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
edit.setSpan(new BulletSpanEx(bulletIndent, bulletGap, colorAccent, bulletRadius, 0), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
edit.setSpan(new NumberSpan(bulletIndent, bulletGap, colorAccent, textSize, 0, index++), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i = j + 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
j++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
renumber(edit, false, context);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setFont(MenuItem item) {
|
|
|
|
private boolean setFont(MenuItem item) {
|
|
|
|
Log.breadcrumb("style", "action", "font");
|
|
|
|
Log.breadcrumb("style", "action", "font");
|
|
|
|
return _setFont(item.getIntent().getStringExtra("face"));
|
|
|
|
return _setFont(item.getIntent().getStringExtra("face"));
|
|
|
@ -559,83 +444,6 @@ public class StyleHelper {
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setBlockQuote(MenuItem item) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "quote");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Context context = etBody.getContext();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary);
|
|
|
|
|
|
|
|
final int colorBlockquote = Helper.resolveColor(context, R.attr.colorBlockquote, colorPrimary);
|
|
|
|
|
|
|
|
int quoteGap = context.getResources().getDimensionPixelSize(R.dimen.quote_gap_size);
|
|
|
|
|
|
|
|
int quoteStripe = context.getResources().getDimensionPixelSize(R.dimen.quote_stripe_width);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
|
|
|
|
if (paragraph == null)
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QuoteSpan[] quotes = edit.getSpans(paragraph.first, paragraph.second, QuoteSpan.class);
|
|
|
|
|
|
|
|
for (QuoteSpan quote : quotes)
|
|
|
|
|
|
|
|
edit.removeSpan(quote);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (quotes.length == 1)
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IndentSpan[] indents = edit.getSpans(start, end, IndentSpan.class);
|
|
|
|
|
|
|
|
for (IndentSpan indent : indents)
|
|
|
|
|
|
|
|
edit.removeSpan(indent);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QuoteSpan q;
|
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
|
|
|
|
|
|
|
q = new QuoteSpan(colorBlockquote);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
q = new QuoteSpan(colorBlockquote, quoteStripe, quoteGap);
|
|
|
|
|
|
|
|
edit.setSpan(q, paragraph.first, paragraph.second, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(paragraph.first, paragraph.second);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setIndentation(MenuItem item) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "indent");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
|
|
|
|
if (paragraph == null)
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Context context = etBody.getContext();
|
|
|
|
|
|
|
|
int intentSize = context.getResources().getDimensionPixelSize(R.dimen.indent_size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QuoteSpan[] quotes = edit.getSpans(start, end, QuoteSpan.class);
|
|
|
|
|
|
|
|
for (QuoteSpan quote : quotes)
|
|
|
|
|
|
|
|
edit.removeSpan(quote);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int prev = paragraph.first;
|
|
|
|
|
|
|
|
int next = paragraph.first;
|
|
|
|
|
|
|
|
while (next < paragraph.second) {
|
|
|
|
|
|
|
|
while (next < paragraph.second && edit.charAt(next) != '\n')
|
|
|
|
|
|
|
|
next++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (item.getItemId() == R.id.menu_style_indentation_decrease) {
|
|
|
|
|
|
|
|
IndentSpan[] indents = edit.getSpans(prev, prev, IndentSpan.class);
|
|
|
|
|
|
|
|
if (indents.length > 0)
|
|
|
|
|
|
|
|
edit.removeSpan(indents[0]);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
IndentSpan is = new IndentSpan(intentSize);
|
|
|
|
|
|
|
|
edit.setSpan(is, prev, next + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
next++;
|
|
|
|
|
|
|
|
prev = next;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(paragraph.first, paragraph.second);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean setMark(MenuItem item) {
|
|
|
|
private boolean setMark(MenuItem item) {
|
|
|
|
Log.breadcrumb("style", "action", "strike");
|
|
|
|
Log.breadcrumb("style", "action", "strike");
|
|
|
|
|
|
|
|
|
|
|
@ -788,6 +596,202 @@ public class StyleHelper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static boolean setAlignment(int itemId, EditText etBody, int start, int end) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "alignment");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Editable edit = etBody.getText();
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
|
|
|
|
if (paragraph == null)
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int s = paragraph.first;
|
|
|
|
|
|
|
|
int e = paragraph.second;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AlignmentSpan[] spans = edit.getSpans(s, e, AlignmentSpan.class);
|
|
|
|
|
|
|
|
for (AlignmentSpan span : spans)
|
|
|
|
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Layout.Alignment alignment = null;
|
|
|
|
|
|
|
|
boolean ltr = (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_LTR);
|
|
|
|
|
|
|
|
if (itemId == R.id.menu_style_align_start) {
|
|
|
|
|
|
|
|
alignment = (ltr ? Layout.Alignment.ALIGN_NORMAL : Layout.Alignment.ALIGN_OPPOSITE);
|
|
|
|
|
|
|
|
} else if (itemId == R.id.menu_style_align_center) {
|
|
|
|
|
|
|
|
alignment = Layout.Alignment.ALIGN_CENTER;
|
|
|
|
|
|
|
|
} else if (itemId == R.id.menu_style_align_end) {
|
|
|
|
|
|
|
|
alignment = (ltr ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (alignment != null)
|
|
|
|
|
|
|
|
edit.setSpan(new AlignmentSpan.Standard(alignment),
|
|
|
|
|
|
|
|
s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static boolean setListLevel(int itemId, EditText etBody, int start, int end) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "level");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Context context = etBody.getContext();
|
|
|
|
|
|
|
|
Editable edit = etBody.getText();
|
|
|
|
|
|
|
|
int add = (itemId == R.id.menu_style_list_increase ? 1 : -1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean renum = false;
|
|
|
|
|
|
|
|
BulletSpan[] spans = edit.getSpans(start, end, BulletSpan.class);
|
|
|
|
|
|
|
|
for (BulletSpan span : spans)
|
|
|
|
|
|
|
|
if (span instanceof BulletSpanEx) {
|
|
|
|
|
|
|
|
BulletSpanEx bs = (BulletSpanEx) span;
|
|
|
|
|
|
|
|
bs.setLevel(bs.getLevel() + add);
|
|
|
|
|
|
|
|
} else if (span instanceof NumberSpan) {
|
|
|
|
|
|
|
|
renum = true;
|
|
|
|
|
|
|
|
NumberSpan ns = (NumberSpan) span;
|
|
|
|
|
|
|
|
ns.setLevel(ns.getLevel() + add);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (renum)
|
|
|
|
|
|
|
|
renumber(edit, false, context);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(start, end);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static boolean setList(int itemId, EditText etBody, int start, int end) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "list");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Context context = etBody.getContext();
|
|
|
|
|
|
|
|
Editable edit = etBody.getText();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int colorAccent = Helper.resolveColor(context, R.attr.colorAccent);
|
|
|
|
|
|
|
|
int bulletGap = context.getResources().getDimensionPixelSize(R.dimen.bullet_gap_size);
|
|
|
|
|
|
|
|
int bulletRadius = context.getResources().getDimensionPixelSize(R.dimen.bullet_radius_size);
|
|
|
|
|
|
|
|
int bulletIndent = context.getResources().getDimensionPixelSize(R.dimen.bullet_indent_size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
|
|
|
|
|
|
int message_zoom = prefs.getInt("message_zoom", 100);
|
|
|
|
|
|
|
|
float textSize = Helper.getTextSize(context, 0) * message_zoom / 100f;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
|
|
|
|
if (paragraph == null)
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int s = paragraph.first;
|
|
|
|
|
|
|
|
int e = paragraph.second;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove existing bullets
|
|
|
|
|
|
|
|
BulletSpan[] spans = edit.getSpans(s, e, BulletSpan.class);
|
|
|
|
|
|
|
|
for (BulletSpan span : spans)
|
|
|
|
|
|
|
|
edit.removeSpan(span);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int i = s;
|
|
|
|
|
|
|
|
int j = s + 1;
|
|
|
|
|
|
|
|
int index = 1;
|
|
|
|
|
|
|
|
while (j < e) {
|
|
|
|
|
|
|
|
if (i > 0 && edit.charAt(i - 1) == '\n' && edit.charAt(j) == '\n') {
|
|
|
|
|
|
|
|
Log.i("Insert " + i + "..." + (j + 1) + " size=" + e);
|
|
|
|
|
|
|
|
if (itemId == R.id.menu_style_list_bullets)
|
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
|
|
|
|
|
|
|
edit.setSpan(new BulletSpanEx(bulletIndent, bulletGap, colorAccent, 0), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
edit.setSpan(new BulletSpanEx(bulletIndent, bulletGap, colorAccent, bulletRadius, 0), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
edit.setSpan(new NumberSpan(bulletIndent, bulletGap, colorAccent, textSize, 0, index++), i, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_PARAGRAPH);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i = j + 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
j++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
renumber(edit, false, context);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(s, e);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static boolean setIndentation(int itemId, EditText etBody, int start, int end) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "indent");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Editable edit = etBody.getText();
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
|
|
|
|
if (paragraph == null)
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Context context = etBody.getContext();
|
|
|
|
|
|
|
|
int intentSize = context.getResources().getDimensionPixelSize(R.dimen.indent_size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QuoteSpan[] quotes = edit.getSpans(start, end, QuoteSpan.class);
|
|
|
|
|
|
|
|
for (QuoteSpan quote : quotes)
|
|
|
|
|
|
|
|
edit.removeSpan(quote);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int prev = paragraph.first;
|
|
|
|
|
|
|
|
int next = paragraph.first;
|
|
|
|
|
|
|
|
while (next < paragraph.second) {
|
|
|
|
|
|
|
|
while (next < paragraph.second && edit.charAt(next) != '\n')
|
|
|
|
|
|
|
|
next++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (itemId == R.id.menu_style_indentation_decrease) {
|
|
|
|
|
|
|
|
IndentSpan[] indents = edit.getSpans(prev, prev, IndentSpan.class);
|
|
|
|
|
|
|
|
if (indents.length > 0)
|
|
|
|
|
|
|
|
edit.removeSpan(indents[0]);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
IndentSpan is = new IndentSpan(intentSize);
|
|
|
|
|
|
|
|
edit.setSpan(is, prev, next + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
next++;
|
|
|
|
|
|
|
|
prev = next;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(paragraph.first, paragraph.second);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static boolean setBlockQuote(EditText etBody, int start, int end) {
|
|
|
|
|
|
|
|
Log.breadcrumb("style", "action", "quote");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Context context = etBody.getContext();
|
|
|
|
|
|
|
|
Editable edit = etBody.getText();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary);
|
|
|
|
|
|
|
|
final int colorBlockquote = Helper.resolveColor(context, R.attr.colorBlockquote, colorPrimary);
|
|
|
|
|
|
|
|
int quoteGap = context.getResources().getDimensionPixelSize(R.dimen.quote_gap_size);
|
|
|
|
|
|
|
|
int quoteStripe = context.getResources().getDimensionPixelSize(R.dimen.quote_stripe_width);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pair<Integer, Integer> paragraph = ensureParagraph(edit, start, end);
|
|
|
|
|
|
|
|
if (paragraph == null)
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QuoteSpan[] quotes = edit.getSpans(paragraph.first, paragraph.second, QuoteSpan.class);
|
|
|
|
|
|
|
|
for (QuoteSpan quote : quotes)
|
|
|
|
|
|
|
|
edit.removeSpan(quote);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (quotes.length == 1)
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IndentSpan[] indents = edit.getSpans(start, end, IndentSpan.class);
|
|
|
|
|
|
|
|
for (IndentSpan indent : indents)
|
|
|
|
|
|
|
|
edit.removeSpan(indent);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QuoteSpan q;
|
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
|
|
|
|
|
|
|
|
q = new QuoteSpan(colorBlockquote);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
q = new QuoteSpan(colorBlockquote, quoteStripe, quoteGap);
|
|
|
|
|
|
|
|
edit.setSpan(q, paragraph.first, paragraph.second, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
etBody.setText(edit);
|
|
|
|
|
|
|
|
etBody.setSelection(paragraph.first, paragraph.second);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static boolean splitSpan(Editable edit, int start, int end, int s, int e, int f, boolean extend, Object span1, Object span2) {
|
|
|
|
static boolean splitSpan(Editable edit, int start, int end, int s, int e, int f, boolean extend, Object span1, Object span2) {
|
|
|
|
if (start < 0 || end < 0) {
|
|
|
|
if (start < 0 || end < 0) {
|
|
|
|
Log.e(span1 + " invalid selection=" + start + "..." + end);
|
|
|
|
Log.e(span1 + " invalid selection=" + start + "..." + end);
|
|
|
@ -888,6 +892,53 @@ public class StyleHelper {
|
|
|
|
return new Pair<>(start, end);
|
|
|
|
return new Pair<>(start, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Pair<Integer, Integer> getParagraph(EditText etBody) {
|
|
|
|
|
|
|
|
return getParagraph(etBody, false);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Pair<Integer, Integer> getParagraph(EditText etBody, boolean block) {
|
|
|
|
|
|
|
|
int start = etBody.getSelectionStart();
|
|
|
|
|
|
|
|
int end = etBody.getSelectionEnd();
|
|
|
|
|
|
|
|
Editable edit = etBody.getText();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (start < 0 || end < 0)
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (start > end) {
|
|
|
|
|
|
|
|
int tmp = start;
|
|
|
|
|
|
|
|
start = end;
|
|
|
|
|
|
|
|
end = tmp;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Expand selection at start
|
|
|
|
|
|
|
|
while (start > 0 &&
|
|
|
|
|
|
|
|
(edit.charAt(start - 1) != '\n' ||
|
|
|
|
|
|
|
|
(block && start - 1 > 0 && edit.charAt(start - 2) != '\n')))
|
|
|
|
|
|
|
|
start--;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (start == end && end < edit.length())
|
|
|
|
|
|
|
|
end++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Expand selection at end
|
|
|
|
|
|
|
|
while (end > 0 && end < edit.length() &&
|
|
|
|
|
|
|
|
(edit.charAt(end - 1) != '\n' ||
|
|
|
|
|
|
|
|
(block && end - 1 > 0 && edit.charAt(end - 2) != '\n')))
|
|
|
|
|
|
|
|
end++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Trim start
|
|
|
|
|
|
|
|
while (start < edit.length() - 1 && edit.charAt(start) == '\n')
|
|
|
|
|
|
|
|
start++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Trim end
|
|
|
|
|
|
|
|
while (end > 0 && edit.charAt(end - 1) == '\n')
|
|
|
|
|
|
|
|
end--;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (start < end)
|
|
|
|
|
|
|
|
return new Pair(start, end);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static <T extends ParagraphStyle> T clone(Object span, Class<T> type, Context context) {
|
|
|
|
static <T extends ParagraphStyle> T clone(Object span, Class<T> type, Context context) {
|
|
|
|
if (QuoteSpan.class.isAssignableFrom(type)) {
|
|
|
|
if (QuoteSpan.class.isAssignableFrom(type)) {
|
|
|
|
QuoteSpan q = (QuoteSpan) span;
|
|
|
|
QuoteSpan q = (QuoteSpan) span;
|
|
|
|