Kitchensink cleanup

pull/210/head
M66B 2 years ago
parent ce12d21a35
commit 8a92c0a238

@ -110,6 +110,13 @@ public class StyleHelper {
R.id.menu_style_clear R.id.menu_style_clear
}; };
private static final int group_style_size = 1;
private static final int group_style_font_standard = 2;
private static final int group_style_font_custom = 3;
private static final int group_style_align = 4;
private static final int group_style_list = 5;
private static final int group_style_indentation = 6;
static void wire(LifecycleOwner owner, View view, EditText etBody) { static void wire(LifecycleOwner owner, View view, EditText etBody) {
View.OnClickListener styleListener = new View.OnClickListener() { View.OnClickListener styleListener = new View.OnClickListener() {
@Override @Override
@ -136,258 +143,104 @@ public class StyleHelper {
Log.i("Style action=" + groupId + ":" + itemId); Log.i("Style action=" + groupId + ":" + itemId);
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;
} }
if (_start == _end && if (start == end &&
itemId != R.id.menu_clear && itemId != R.id.menu_clear &&
itemId != R.id.menu_style_align && groupId != R.id.group_style_align && itemId != R.id.menu_style_align && groupId != group_style_align &&
itemId != R.id.menu_style_list && groupId != R.id.group_style_list && itemId != R.id.menu_style_list && groupId != group_style_list &&
itemId != R.id.menu_style_indentation && groupId != R.id.group_style_indentation && itemId != R.id.menu_style_indentation && groupId != group_style_indentation &&
itemId != R.id.menu_style_blockquote && groupId != R.id.group_style_blockquote) { itemId != R.id.menu_style_blockquote) {
Pair<Integer, Integer> word = getWord(etBody); Pair<Integer, Integer> word = getWord(etBody);
if (word == null) if (word == null)
return false; return false;
_start = word.first; start = word.first;
_end = word.second; end = word.second;
} }
final Editable edit = etBody.getText(); if (groupId < 0) {
final int start = _start; if (itemId == R.id.menu_bold || itemId == R.id.menu_italic)
final int end = _end; return setBoldItalic(itemId, etBody, start, end, false);
else if (itemId == R.id.menu_underline)
if (itemId == R.id.menu_bold || itemId == R.id.menu_italic) { return setUnderline(etBody, start, end, false);
String name = (itemId == R.id.menu_bold ? "bold" : "italic"); else if (itemId == R.id.menu_style_size)
Log.breadcrumb("style", "action", name); return selectSize(owner, anchor, etBody);
else if (itemId == R.id.menu_style_background)
boolean has = false; return selectBackground(etBody, start, end);
int style = (itemId == R.id.menu_bold ? Typeface.BOLD : Typeface.ITALIC); else if (itemId == R.id.menu_style_color)
StyleSpan[] spans = edit.getSpans(start, end, StyleSpan.class); return selectColor(etBody, start, end);
for (StyleSpan span : spans) else if (itemId == R.id.menu_style_font)
if (span.getStyle() == style) { return selectFont(owner, anchor, etBody, start, end);
int s = edit.getSpanStart(span); else if (itemId == R.id.menu_style_align)
int e = edit.getSpanEnd(span); return selectAlignment(owner, anchor, etBody, start, end);
int f = edit.getSpanFlags(span); else if (itemId == R.id.menu_style_list)
edit.removeSpan(span); return selectList(owner, anchor, etBody, start, end);
if (splitSpan(edit, start, end, s, e, f, true, else if (itemId == R.id.menu_style_indentation)
new StyleSpan(style), new StyleSpan(style))) return selectIndentation(owner, anchor, etBody, start, end);
has = true; else if (itemId == R.id.menu_style_blockquote) {
} if (start == end) {
Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true);
if (!has) if (block == null)
edit.setSpan(new StyleSpan(style), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return false;
return StyleHelper.setBlockQuote(etBody, block.first, block.second, false);
etBody.setText(edit); } else
etBody.setSelection(start, end); return setBlockQuote(etBody, start, end, true);
} else if (itemId == R.id.menu_style_mark)
return true; return setMark(etBody, start, end, false);
} else if (itemId == R.id.menu_underline) { else if (itemId == R.id.menu_style_subscript)
Log.breadcrumb("style", "action", "underline"); return setSubscript(etBody, start, end, false);
else if (itemId == R.id.menu_style_superscript)
boolean has = false; return setSuperscript(etBody, start, end, false);
UnderlineSpan[] spans = edit.getSpans(start, end, UnderlineSpan.class); else if (itemId == R.id.menu_style_strikethrough)
for (UnderlineSpan span : spans) { return setStrikeThrough(etBody, start, end, false);
int s = edit.getSpanStart(span); else if (itemId == R.id.menu_style_password)
int e = edit.getSpanEnd(span); return setPassword(owner, etBody, start, end);
int f = edit.getSpanFlags(span); else if (itemId == R.id.menu_style_code) {
edit.removeSpan(span); Log.breadcrumb("style", "action", "code");
if (splitSpan(edit, start, end, s, e, f, true, setSize(etBody, start, end, HtmlHelper.FONT_SMALL);
new UnderlineSpan(), new UnderlineSpan())) setFont(etBody, start, end, "monospace");
has = true;
}
if (!has)
edit.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
etBody.setText(edit);
etBody.setSelection(start, end);
return true; return true;
} else if (itemId == R.id.menu_style_size) { } else if (itemId == R.id.menu_link)
Context context = anchor.getContext(); return setLink(etBody, start, end, args);
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor); else if (itemId == R.id.menu_style_clear)
return clear(etBody, start, end);
int[] ids = new int[]{ else if (itemId == R.id.menu_clear)
R.id.menu_style_size_xsmall, return clearAll(etBody, start, end);
R.id.menu_style_size_small, } else {
R.id.menu_style_size_medium, switch (groupId) {
R.id.menu_style_size_large, case group_style_size: {
R.id.menu_style_size_xlarge
};
int[] titles = new int[]{
R.string.title_style_size_xsmall,
R.string.title_style_size_small,
R.string.title_style_size_medium,
R.string.title_style_size_large,
R.string.title_style_size_xlarge};
float[] sizes = new float[]{
HtmlHelper.FONT_XSMALL,
HtmlHelper.FONT_SMALL,
1.0f,
HtmlHelper.FONT_LARGE,
HtmlHelper.FONT_XLARGE};
for (int i = 0; i < ids.length; i++) {
SpannableStringBuilder ssb = new SpannableStringBuilderEx(context.getString(titles[i]));
ssb.setSpan(new RelativeSizeSpan(sizes[i]), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
popupMenu.getMenu().add(R.id.group_style_size, ids[i], i, ssb);
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return StyleHelper.apply(R.id.group_style_size, item.getItemId(), owner, anchor, etBody);
}
});
popupMenu.show();
} else if (groupId == R.id.group_style_size) {
Float size; Float size;
if (itemId == R.id.menu_style_size_xsmall) if (itemId == 1)
size = HtmlHelper.FONT_XSMALL; size = HtmlHelper.FONT_XSMALL;
else if (itemId == R.id.menu_style_size_small) else if (itemId == 2)
size = HtmlHelper.FONT_SMALL; size = HtmlHelper.FONT_SMALL;
else if (itemId == R.id.menu_style_size_large) else if (itemId == 4)
size = HtmlHelper.FONT_LARGE; size = HtmlHelper.FONT_LARGE;
else if (itemId == R.id.menu_style_size_xlarge) else if (itemId == 5)
size = HtmlHelper.FONT_XLARGE; size = HtmlHelper.FONT_XLARGE;
else else
size = null; size = null;
return setSize(etBody, start, end, size); return setSize(etBody, start, end, size);
} else if (itemId == R.id.menu_style_background) {
Helper.hideKeyboard(etBody);
Context context = etBody.getContext();
int editTextColor = Helper.resolveColor(context, android.R.attr.editTextColor);
ColorPickerDialogBuilder builder = ColorPickerDialogBuilder
.with(context)
.setTitle(R.string.title_background)
.showColorEdit(true)
.setColorEditTextColor(editTextColor)
.wheelType(ColorPickerView.WHEEL_TYPE.FLOWER)
.density(6)
//.lightnessSliderOnly()
.setPositiveButton(android.R.string.ok, new ColorPickerClickListener() {
@Override
public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) {
setBackground(etBody, start, end, selectedColor);
}
})
.setNegativeButton(R.string.title_reset, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setBackground(etBody, start, end, null);
}
});
BackgroundColorSpan[] spans = edit.getSpans(start, end, BackgroundColorSpan.class);
if (spans != null && spans.length == 1)
builder.initialColor(spans[0].getBackgroundColor());
builder.build().show();
return true;
} else if (itemId == R.id.menu_style_color) {
Helper.hideKeyboard(etBody);
Context context = etBody.getContext();
int editTextColor = Helper.resolveColor(context, android.R.attr.editTextColor);
ColorPickerDialogBuilder builder = ColorPickerDialogBuilder
.with(context)
.setTitle(R.string.title_color)
.showColorEdit(true)
.setColorEditTextColor(editTextColor)
.wheelType(ColorPickerView.WHEEL_TYPE.FLOWER)
.density(6)
//.lightnessSliderOnly()
.setPositiveButton(android.R.string.ok, new ColorPickerClickListener() {
@Override
public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) {
setColor(etBody, start, end, selectedColor);
} }
})
.setNegativeButton(R.string.title_reset, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setColor(etBody, start, end, null);
}
});
ForegroundColorSpan[] spans = edit.getSpans(start, end, ForegroundColorSpan.class);
if (spans != null && spans.length == 1)
builder.initialColor(spans[0].getForegroundColor());
builder.build().show();
return true;
} else if (itemId == R.id.menu_style_font) {
Context context = anchor.getContext();
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor);
List<FontDescriptor> fonts = getFonts(context, false);
for (int i = 0; i < fonts.size(); i++) {
FontDescriptor font = fonts.get(i);
SpannableStringBuilder ssb = new SpannableStringBuilderEx(font.toString());
ssb.setSpan(getTypefaceSpan(font.type, context), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
popupMenu.getMenu().add(font.custom ? R.id.group_style_font_custom : R.id.group_style_font_standard, i, 0, ssb)
.setIntent(new Intent().putExtra("face", font.type));
}
popupMenu.getMenu().add(R.id.group_style_font_standard, fonts.size(), 0, R.string.title_style_font_default)
.setIntent(new Intent());
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return setFont(etBody, start, end, item.getIntent().getStringExtra("face"));
}
});
popupMenu.show();
} else if (groupId == R.id.group_style_font_standard || case group_style_font_standard:
groupId == R.id.group_style_font_custom) { case group_style_font_custom:
return setFont(etBody, start, end, (String) args[0]); return setFont(etBody, start, end, (String) args[0]);
} else if (itemId == R.id.menu_style_align) { case group_style_align: {
Context context = anchor.getContext();
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor);
popupMenu.inflate(R.menu.popup_style_alignment);
if (start == end) {
Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true);
if (block == null)
return false;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return StyleHelper.apply(R.id.group_style_align, item.getItemId(), owner, anchor, etBody);
}
});
popupMenu.insertIcons(context);
popupMenu.show();
} else if (groupId == R.id.group_style_align) {
if (start == end) { if (start == end) {
Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true); Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true);
if (block == null) if (block == null)
@ -395,258 +248,134 @@ public class StyleHelper {
return setAlignment(itemId, etBody, block.first, block.second, false); return setAlignment(itemId, etBody, block.first, block.second, false);
} else } else
return setAlignment(itemId, etBody, start, end, true); return setAlignment(itemId, etBody, start, end, true);
} else if (itemId == R.id.menu_style_list) {
Context context = anchor.getContext();
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor);
popupMenu.inflate(R.menu.popup_style_list);
int s = start;
int e = end;
if (s == e) {
Pair<Integer, Integer> p = StyleHelper.getParagraph(etBody, false);
if (p == null)
return false;
s = p.first;
e = p.second;
}
Integer maxLevel = getMaxListLevel(edit, s, e);
IndentSpan[] indents = edit.getSpans(s, e, IndentSpan.class);
popupMenu.getMenu().findItem(R.id.menu_style_list_bullets).setEnabled(indents.length == 0);
popupMenu.getMenu().findItem(R.id.menu_style_list_numbered).setEnabled(indents.length == 0);
popupMenu.getMenu().findItem(R.id.menu_style_list_increase).setEnabled(indents.length == 0 && maxLevel != null);
popupMenu.getMenu().findItem(R.id.menu_style_list_decrease).setEnabled(indents.length == 0 && maxLevel != null && maxLevel > 0);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return StyleHelper.apply(R.id.group_style_list, item.getItemId(), owner, anchor, etBody);
} }
});
popupMenu.insertIcons(context);
popupMenu.show();
} else if (groupId == R.id.group_style_list) { case group_style_list: {
boolean level = (itemId == R.id.menu_style_list_decrease || itemId == R.id.menu_style_list_increase); boolean level = (itemId == R.id.menu_style_list_decrease || itemId == R.id.menu_style_list_increase);
if (start == end) { if (start == end) {
Pair<Integer, Integer> p = StyleHelper.getParagraph(etBody, false); Pair<Integer, Integer> p = StyleHelper.getParagraph(etBody, false);
if (p == null) if (p == null)
return false; return false;
if (level) if (level)
StyleHelper.setListLevel(itemId, etBody, p.first, p.second, false); return StyleHelper.setListLevel(itemId, etBody, p.first, p.second, false);
else else
StyleHelper.setList(itemId, etBody, p.first, p.second, false); return StyleHelper.setList(itemId, etBody, p.first, p.second, false);
return true;
} else { } else {
if (level) if (level)
return setListLevel(itemId, etBody, start, end, true); return setListLevel(itemId, etBody, start, end, true);
else else
return setList(itemId, etBody, start, end, true); return setList(itemId, etBody, start, end, true);
} }
}
} else if (itemId == R.id.menu_style_indentation) { case group_style_indentation: {
Context context = anchor.getContext(); if (start == end) {
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor);
popupMenu.inflate(R.menu.popup_style_indentation);
int s = start;
int e = end;
if (s == e) {
Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true); Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true);
if (block == null) if (block == null)
return false; return false;
s = block.first; return StyleHelper.setIndentation(itemId, etBody, block.first, block.second, false);
e = block.second; } else
return setIndentation(itemId, etBody, start, end, true);
}
}
}
} catch (Throwable ex) {
Log.e(ex);
} }
Integer maxLevel = getMaxListLevel(edit, s, e); return false;
IndentSpan[] indents = edit.getSpans(s, e, IndentSpan.class); }
popupMenu.getMenu().findItem(R.id.menu_style_indentation_increase).setEnabled(maxLevel == null); static boolean setBoldItalic(int itemId, EditText etBody, int start, int end, boolean select) {
popupMenu.getMenu().findItem(R.id.menu_style_indentation_decrease).setEnabled(indents.length > 0); String name = (itemId == R.id.menu_bold ? "bold" : "italic");
Log.breadcrumb("style", "action", name);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { boolean has = false;
@Override Editable edit = etBody.getText();
public boolean onMenuItemClick(MenuItem item) { int style = (itemId == R.id.menu_bold ? Typeface.BOLD : Typeface.ITALIC);
return StyleHelper.apply(R.id.group_style_indentation, item.getItemId(), owner, anchor, etBody); StyleSpan[] spans = edit.getSpans(start, end, StyleSpan.class);
for (StyleSpan span : spans)
if (span.getStyle() == style) {
int s = edit.getSpanStart(span);
int e = edit.getSpanEnd(span);
int f = edit.getSpanFlags(span);
edit.removeSpan(span);
if (splitSpan(edit, start, end, s, e, f, true,
new StyleSpan(style), new StyleSpan(style)))
has = true;
} }
});
popupMenu.insertIcons(context); if (!has)
edit.setSpan(new StyleSpan(style), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
popupMenu.show();
} else if (groupId == R.id.group_style_indentation) { etBody.setText(edit);
if (start == end) { etBody.setSelection(select ? start : end, end);
Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true);
if (block == null)
return false;
StyleHelper.setIndentation(itemId, etBody, block.first, block.second, false);
} else
return setIndentation(itemId, etBody, start, end, true);
} else if (itemId == R.id.menu_style_blockquote || groupId == R.id.group_style_blockquote) {
if (start == end) {
Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true);
if (block == null)
return false;
StyleHelper.setBlockQuote(etBody, block.first, block.second, false);
return true; return true;
} else }
return setBlockQuote(etBody, start, end, true);
} else if (itemId == R.id.menu_style_mark || groupId == R.id.group_style_mark) {
return setMark(etBody, start, end, itemId == R.id.menu_style_mark);
} else if (itemId == R.id.menu_style_subscript || groupId == R.id.group_style_subscript) { static boolean setUnderline(EditText etBody, int start, int end, boolean select) {
return setSubscript(etBody, start, end, itemId == R.id.menu_style_subscript); Log.breadcrumb("style", "action", "underline");
} else if (itemId == R.id.menu_style_superscript || groupId == R.id.group_style_superscript) { boolean has = false;
return setSuperscript(etBody, start, end, itemId == R.id.menu_style_superscript); Editable edit = etBody.getText();
UnderlineSpan[] spans = edit.getSpans(start, end, UnderlineSpan.class);
for (UnderlineSpan span : spans) {
int s = edit.getSpanStart(span);
int e = edit.getSpanEnd(span);
int f = edit.getSpanFlags(span);
edit.removeSpan(span);
if (splitSpan(edit, start, end, s, e, f, true,
new UnderlineSpan(), new UnderlineSpan()))
has = true;
}
} else if (itemId == R.id.menu_style_strikethrough || groupId == R.id.group_style_strikethrough) { if (!has)
return setStrikeThrough(etBody, start, end, itemId == R.id.menu_style_strikethrough); edit.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (itemId == R.id.menu_style_password || groupId == R.id.group_style_password) { etBody.setText(edit);
return setPassword(owner, etBody, start, end); etBody.setSelection(select ? start : end, end);
} else if (itemId == R.id.menu_style_code || groupId == R.id.group_style_code) {
Log.breadcrumb("style", "action", "code");
setSize(etBody, start, end, HtmlHelper.FONT_SMALL);
setFont(etBody, start, end, "monospace");
return true; return true;
}
} else if (itemId == R.id.menu_style_clear || groupId == R.id.group_style_clear) { static boolean selectSize(LifecycleOwner owner, View anchor, EditText etBody) {
return clear(etBody, start, end); Log.breadcrumb("style", "action", "selectSize");
} else if (itemId == R.id.menu_style) { Context context = anchor.getContext();
final Context context = anchor.getContext();
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor); PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor);
popupMenu.inflate(R.menu.popup_style);
{
SubMenu smenu = popupMenu.getMenu().findItem(R.id.menu_style_size).getSubMenu();
smenu.clear();
int[] ids = new int[]{
R.id.menu_style_size_xsmall,
R.id.menu_style_size_small,
R.id.menu_style_size_medium,
R.id.menu_style_size_large,
R.id.menu_style_size_xlarge
};
int[] titles = new int[]{ int[] titles = new int[]{
R.string.title_style_size_xsmall, R.string.title_style_size_xsmall,
R.string.title_style_size_small, R.string.title_style_size_small,
R.string.title_style_size_medium, R.string.title_style_size_medium,
R.string.title_style_size_large, R.string.title_style_size_large,
R.string.title_style_size_xlarge}; R.string.title_style_size_xlarge};
float[] sizes = new float[]{ float[] sizes = new float[]{
HtmlHelper.FONT_XSMALL, HtmlHelper.FONT_XSMALL,
HtmlHelper.FONT_SMALL, HtmlHelper.FONT_SMALL,
1.0f, 1.0f,
HtmlHelper.FONT_LARGE, HtmlHelper.FONT_LARGE,
HtmlHelper.FONT_XLARGE}; HtmlHelper.FONT_XLARGE};
for (int i = 0; i < ids.length; i++) {
for (int i = 0; i < titles.length; i++) {
SpannableStringBuilder ssb = new SpannableStringBuilderEx(context.getString(titles[i])); SpannableStringBuilder ssb = new SpannableStringBuilderEx(context.getString(titles[i]));
ssb.setSpan(new RelativeSizeSpan(sizes[i]), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.setSpan(new RelativeSizeSpan(sizes[i]), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
smenu.add(R.id.group_style_size, ids[i], i, ssb); popupMenu.getMenu().add(group_style_size, i + 1, i, ssb);
} }
}
List<FontDescriptor> fonts = getFonts(context, false);
SubMenu smenu = popupMenu.getMenu().findItem(R.id.menu_style_font).getSubMenu();
for (int i = 0; i < fonts.size(); i++) {
FontDescriptor font = fonts.get(i);
SpannableStringBuilder ssb = new SpannableStringBuilderEx(font.toString());
ssb.setSpan(getTypefaceSpan(font.type, context), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
smenu.add(font.custom ? R.id.group_style_font_custom : R.id.group_style_font_standard, i, 0, ssb)
.setIntent(new Intent().putExtra("face", font.type));
}
smenu.add(R.id.group_style_font_standard, fonts.size(), 0, R.string.title_style_font_default)
.setIntent(new Intent());
Integer maxLevel = getMaxListLevel(edit, start, end);
IndentSpan[] indents = edit.getSpans(start, end, IndentSpan.class);
popupMenu.getMenu().findItem(R.id.menu_style_list_bullets).setEnabled(indents.length == 0);
popupMenu.getMenu().findItem(R.id.menu_style_list_numbered).setEnabled(indents.length == 0);
popupMenu.getMenu().findItem(R.id.menu_style_list_increase).setEnabled(indents.length == 0 && maxLevel != null);
popupMenu.getMenu().findItem(R.id.menu_style_list_decrease).setEnabled(indents.length == 0 && maxLevel != null && maxLevel > 0);
popupMenu.getMenu().findItem(R.id.menu_style_indentation_increase).setEnabled(maxLevel == null);
popupMenu.getMenu().findItem(R.id.menu_style_indentation_decrease).setEnabled(indents.length > 0);
popupMenu.getMenu().findItem(R.id.menu_style_password)
.setVisible(!BuildConfig.PLAY_STORE_RELEASE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O);
popupMenu.getMenu().findItem(R.id.menu_style_code).setEnabled(BuildConfig.DEBUG);
popupMenu.insertIcons(context);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getGroupId() == R.id.group_style_font_standard ||
item.getGroupId() == R.id.group_style_font_custom)
return apply(item.getGroupId(), item.getItemId(), owner, anchor, etBody,
item.getIntent().getStringExtra("face"));
else
return apply(item.getGroupId(), item.getItemId(), owner, anchor, etBody);
}
});
popupMenu.show();
return true;
} else if (itemId == R.id.menu_link) {
Log.breadcrumb("style", "action", "link");
String url = (String) args[0];
String title = (String) args[1];
URLSpan[] spans = edit.getSpans(start, end, URLSpan.class);
for (URLSpan span : spans)
edit.removeSpan(span);
if (!TextUtils.isEmpty(url)) {
if (TextUtils.isEmpty(title))
title = url;
if (start == end)
edit.insert(start, title);
else if (!title.equals(edit.subSequence(start, end).toString()))
edit.replace(start, end, title);
edit.setSpan(new URLSpan(url), start, start + title.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
etBody.setText(edit);
etBody.setSelection(start + title.length());
return true;
} else if (itemId == R.id.menu_clear) {
Log.breadcrumb("style", "action", "clear/all");
for (Object span : edit.getSpans(0, etBody.length(), Object.class)) { popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
if (!CLEAR_STYLES.contains(span.getClass())) @Override
continue; public boolean onMenuItemClick(MenuItem item) {
edit.removeSpan(span); return StyleHelper.apply(group_style_size, item.getItemId(), owner, anchor, etBody);
} }
});
etBody.setText(edit); popupMenu.show();
etBody.setSelection(start, end);
return true; return true;
} }
return false;
} catch (Throwable ex) {
Log.e(ex);
return false;
}
}
static boolean setSize(EditText etBody, int start, int end, Float size) { static boolean setSize(EditText etBody, int start, int end, Float size) {
Log.breadcrumb("style", "action", "size"); Log.breadcrumb("style", "action", "size");
@ -672,6 +401,44 @@ public class StyleHelper {
return true; return true;
} }
static boolean selectBackground(EditText etBody, int start, int end) {
Log.breadcrumb("style", "action", "selectBackground");
Helper.hideKeyboard(etBody);
Context context = etBody.getContext();
int editTextColor = Helper.resolveColor(context, android.R.attr.editTextColor);
ColorPickerDialogBuilder builder = ColorPickerDialogBuilder
.with(context)
.setTitle(R.string.title_background)
.showColorEdit(true)
.setColorEditTextColor(editTextColor)
.wheelType(ColorPickerView.WHEEL_TYPE.FLOWER)
.density(6)
//.lightnessSliderOnly()
.setPositiveButton(android.R.string.ok, new ColorPickerClickListener() {
@Override
public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) {
setBackground(etBody, start, end, selectedColor);
}
})
.setNegativeButton(R.string.title_reset, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setBackground(etBody, start, end, null);
}
});
BackgroundColorSpan[] spans = etBody.getText().getSpans(start, end, BackgroundColorSpan.class);
if (spans != null && spans.length == 1)
builder.initialColor(spans[0].getBackgroundColor());
builder.build().show();
return true;
}
static void setBackground(EditText etBody, int start, int end, Integer color) { static void setBackground(EditText etBody, int start, int end, Integer color) {
Log.breadcrumb("style", "action", "background"); Log.breadcrumb("style", "action", "background");
@ -694,6 +461,44 @@ public class StyleHelper {
etBody.setSelection(start, end); etBody.setSelection(start, end);
} }
static boolean selectColor(EditText etBody, int start, int end) {
Log.breadcrumb("style", "action", "selectColor");
Helper.hideKeyboard(etBody);
Context context = etBody.getContext();
int editTextColor = Helper.resolveColor(context, android.R.attr.editTextColor);
ColorPickerDialogBuilder builder = ColorPickerDialogBuilder
.with(context)
.setTitle(R.string.title_color)
.showColorEdit(true)
.setColorEditTextColor(editTextColor)
.wheelType(ColorPickerView.WHEEL_TYPE.FLOWER)
.density(6)
//.lightnessSliderOnly()
.setPositiveButton(android.R.string.ok, new ColorPickerClickListener() {
@Override
public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) {
setColor(etBody, start, end, selectedColor);
}
})
.setNegativeButton(R.string.title_reset, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setColor(etBody, start, end, null);
}
});
ForegroundColorSpan[] spans = etBody.getText().getSpans(start, end, ForegroundColorSpan.class);
if (spans != null && spans.length == 1)
builder.initialColor(spans[0].getForegroundColor());
builder.build().show();
return true;
}
static void setColor(EditText etBody, int start, int end, Integer color) { static void setColor(EditText etBody, int start, int end, Integer color) {
Log.breadcrumb("style", "action", "color"); Log.breadcrumb("style", "action", "color");
@ -716,6 +521,35 @@ public class StyleHelper {
etBody.setSelection(start, end); etBody.setSelection(start, end);
} }
static boolean selectFont(LifecycleOwner owner, View anchor, EditText etBody, int start, int end) {
Log.breadcrumb("style", "action", "selectFont");
Context context = anchor.getContext();
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor);
List<FontDescriptor> fonts = getFonts(context, false);
for (int i = 0; i < fonts.size(); i++) {
FontDescriptor font = fonts.get(i);
SpannableStringBuilder ssb = new SpannableStringBuilderEx(font.toString());
ssb.setSpan(getTypefaceSpan(font.type, context), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
popupMenu.getMenu().add(font.custom ? group_style_font_custom : group_style_font_standard, i, 0, ssb)
.setIntent(new Intent().putExtra("face", font.type));
}
popupMenu.getMenu().add(group_style_font_standard, fonts.size(), 0, R.string.title_style_font_default)
.setIntent(new Intent());
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return setFont(etBody, start, end, item.getIntent().getStringExtra("face"));
}
});
popupMenu.show();
return true;
}
static boolean setFont(EditText etBody, int start, int end, String face) { static boolean setFont(EditText etBody, int start, int end, String face) {
Log.breadcrumb("style", "action", "font"); Log.breadcrumb("style", "action", "font");
@ -742,6 +576,33 @@ public class StyleHelper {
return true; return true;
} }
static boolean selectAlignment(LifecycleOwner owner, View anchor, EditText etBody, int start, int end) {
Log.breadcrumb("style", "action", "selectAlignment");
Context context = anchor.getContext();
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor);
popupMenu.inflate(R.menu.popup_style_alignment);
if (start == end) {
Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true);
if (block == null)
return false;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return StyleHelper.apply(group_style_align, item.getItemId(), owner, anchor, etBody);
}
});
popupMenu.insertIcons(context);
popupMenu.show();
return true;
}
static boolean setAlignment(int itemId, EditText etBody, int start, int end, boolean select) { static boolean setAlignment(int itemId, EditText etBody, int start, int end, boolean select) {
Log.breadcrumb("style", "action", "alignment"); Log.breadcrumb("style", "action", "alignment");
@ -777,14 +638,54 @@ public class StyleHelper {
return true; return true;
} }
static boolean selectList(LifecycleOwner owner, View anchor, EditText etBody, int start, int end) {
Log.breadcrumb("style", "action", "selectList");
Context context = anchor.getContext();
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor);
popupMenu.inflate(R.menu.popup_style_list);
int s = start;
int e = end;
if (s == e) {
Pair<Integer, Integer> p = StyleHelper.getParagraph(etBody, false);
if (p == null)
return false;
s = p.first;
e = p.second;
}
Editable edit = etBody.getText();
Integer maxLevel = getMaxListLevel(edit, s, e);
IndentSpan[] indents = edit.getSpans(s, e, IndentSpan.class);
popupMenu.getMenu().findItem(R.id.menu_style_list_bullets).setEnabled(indents.length == 0);
popupMenu.getMenu().findItem(R.id.menu_style_list_numbered).setEnabled(indents.length == 0);
popupMenu.getMenu().findItem(R.id.menu_style_list_increase).setEnabled(indents.length == 0 && maxLevel != null);
popupMenu.getMenu().findItem(R.id.menu_style_list_decrease).setEnabled(indents.length == 0 && maxLevel != null && maxLevel > 0);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return StyleHelper.apply(group_style_list, item.getItemId(), owner, anchor, etBody);
}
});
popupMenu.insertIcons(context);
popupMenu.show();
return true;
}
static boolean setListLevel(int itemId, EditText etBody, int start, int end, boolean select) { static boolean setListLevel(int itemId, EditText etBody, int start, int end, boolean select) {
Log.breadcrumb("style", "action", "level"); Log.breadcrumb("style", "action", "level");
Context context = etBody.getContext(); Context context = etBody.getContext();
Editable edit = etBody.getText();
int add = (itemId == R.id.menu_style_list_increase ? 1 : -1); int add = (itemId == R.id.menu_style_list_increase ? 1 : -1);
boolean renum = false; boolean renum = false;
Editable edit = etBody.getText();
BulletSpan[] spans = edit.getSpans(start, end, BulletSpan.class); BulletSpan[] spans = edit.getSpans(start, end, BulletSpan.class);
for (BulletSpan span : spans) for (BulletSpan span : spans)
if (span instanceof BulletSpanEx) { if (span instanceof BulletSpanEx) {
@ -859,6 +760,44 @@ public class StyleHelper {
return true; return true;
} }
static boolean selectIndentation(LifecycleOwner owner, View anchor, EditText etBody, int start, int end) {
Log.breadcrumb("style", "action", "selectIndentation");
Context context = anchor.getContext();
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, owner, anchor);
popupMenu.inflate(R.menu.popup_style_indentation);
int s = start;
int e = end;
if (s == e) {
Pair<Integer, Integer> block = StyleHelper.getParagraph(etBody, true);
if (block == null)
return false;
s = block.first;
e = block.second;
}
Editable edit = etBody.getText();
Integer maxLevel = getMaxListLevel(edit, s, e);
IndentSpan[] indents = edit.getSpans(s, e, IndentSpan.class);
popupMenu.getMenu().findItem(R.id.menu_style_indentation_increase).setEnabled(maxLevel == null);
popupMenu.getMenu().findItem(R.id.menu_style_indentation_decrease).setEnabled(indents.length > 0);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return StyleHelper.apply(group_style_indentation, item.getItemId(), owner, anchor, etBody);
}
});
popupMenu.insertIcons(context);
popupMenu.show();
return true;
}
static boolean setIndentation(int itemId, EditText etBody, int start, int end, boolean select) { static boolean setIndentation(int itemId, EditText etBody, int start, int end, boolean select) {
Log.breadcrumb("style", "action", "indent"); Log.breadcrumb("style", "action", "indent");
@ -1067,6 +1006,36 @@ public class StyleHelper {
return true; return true;
} }
static boolean setLink(EditText etBody, int start, int end, Object... args) {
Log.breadcrumb("style", "action", "link");
String url = (String) args[0];
String title = (String) args[1];
Editable edit = etBody.getText();
URLSpan[] spans = edit.getSpans(start, end, URLSpan.class);
for (URLSpan span : spans)
edit.removeSpan(span);
if (!TextUtils.isEmpty(url)) {
if (TextUtils.isEmpty(title))
title = url;
if (start == end)
edit.insert(start, title);
else if (!title.equals(edit.subSequence(start, end).toString()))
edit.replace(start, end, title);
edit.setSpan(new URLSpan(url), start, start + title.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
etBody.setText(edit);
etBody.setSelection(start + title.length());
return true;
}
static boolean clear(EditText etBody, int start, int end) { static boolean clear(EditText etBody, int start, int end) {
Log.breadcrumb("style", "action", "clear"); Log.breadcrumb("style", "action", "clear");
@ -1105,6 +1074,23 @@ public class StyleHelper {
return true; return true;
} }
static boolean clearAll(EditText etBody, int start, int end) {
Log.breadcrumb("style", "action", "clear/all");
Editable edit = etBody.getText();
for (Object span : edit.getSpans(0, etBody.length(), Object.class)) {
if (!CLEAR_STYLES.contains(span.getClass()))
continue;
edit.removeSpan(span);
}
etBody.setText(edit);
etBody.setSelection(start, end);
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);

@ -1,206 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_style_size"
android:icon="@drawable/twotone_format_size_24"
android:orderInCategory="1"
android:title="@string/title_style_size">
<menu>
<group android:id="@+id/group_style_size">
<item
android:id="@+id/menu_style_size_xsmall"
android:title="@string/title_style_size_xsmall" />
<item
android:id="@+id/menu_style_size_small"
android:title="@string/title_style_size_small" />
<item
android:id="@+id/menu_style_size_medium"
android:title="@string/title_style_size_medium" />
<item
android:id="@+id/menu_style_size_large"
android:title="@string/title_style_size_large" />
<item
android:id="@+id/menu_style_size_xlarge"
android:title="@string/title_style_size_xlarge" />
</group>
</menu>
</item>
<item
android:id="@+id/menu_style_background"
android:icon="@drawable/twotone_format_paint_24"
android:orderInCategory="2"
android:title="@string/title_background">
<menu>
<group android:id="@+id/group_style_background" />
</menu>
</item>
<item
android:id="@+id/menu_style_color"
android:icon="@drawable/twotone_palette_24"
android:orderInCategory="3"
android:title="@string/title_color">
<menu>
<group android:id="@+id/group_style_color" />
</menu>
</item>
<item
android:id="@+id/menu_style_font"
android:icon="@drawable/twotone_text_format_24"
android:orderInCategory="4"
android:title="@string/title_style_font">
<menu>
<group android:id="@+id/group_style_font_standard" />
<group android:id="@+id/group_style_font_custom" />
</menu>
</item>
<item
android:id="@+id/menu_style_align"
android:icon="@drawable/twotone_format_align_center_24"
android:orderInCategory="5"
android:title="@string/title_style_align">
<menu>
<group android:id="@+id/group_style_align">
<item
android:id="@+id/menu_style_align_start"
android:icon="@drawable/twotone_format_align_left_24"
android:title="@string/title_style_align_start" />
<item
android:id="@+id/menu_style_align_center"
android:icon="@drawable/twotone_format_align_center_24"
android:title="@string/title_style_align_center" />
<item
android:id="@+id/menu_style_align_end"
android:icon="@drawable/twotone_format_align_right_24"
android:title="@string/title_style_align_end" />
</group>
</menu>
</item>
<item
android:id="@+id/menu_style_list"
android:icon="@drawable/twotone_format_list_bulleted_24"
android:orderInCategory="6"
android:title="@string/title_style_list">
<menu>
<group android:id="@+id/group_style_list">
<item
android:id="@+id/menu_style_list_bullets"
android:icon="@drawable/twotone_format_list_bulleted_24"
android:title="@string/title_style_list_bullets" />
<item
android:id="@+id/menu_style_list_numbered"
android:icon="@drawable/twotone_format_list_numbered_24"
android:title="@string/title_style_list_numbered" />
<item
android:id="@+id/menu_style_list_increase"
android:icon="@drawable/twotone_format_indent_increase_24"
android:title="@string/title_style_list_level_increase" />
<item
android:id="@+id/menu_style_list_decrease"
android:icon="@drawable/twotone_format_indent_decrease_24"
android:title="@string/title_style_list_level_decrease" />
</group>
</menu>
</item>
<item
android:id="@+id/menu_style_indentation"
android:icon="@drawable/twotone_format_indent_increase_24"
android:orderInCategory="7"
android:title="@string/title_style_indentation">
<menu>
<group android:id="@+id/group_style_indentation">
<item
android:id="@+id/menu_style_indentation_increase"
android:icon="@drawable/twotone_format_indent_increase_24"
android:title="@string/title_style_list_level_increase" />
<item
android:id="@+id/menu_style_indentation_decrease"
android:icon="@drawable/twotone_format_indent_decrease_24"
android:title="@string/title_style_list_level_decrease" />
</group>
</menu>
</item>
<group
android:id="@+id/group_style_blockquote"
android:orderInCategory="8">
<item
android:id="@+id/menu_style_blockquote"
android:icon="@drawable/twotone_format_quote_24"
android:title="@string/title_style_blockquote" />
</group>
<group
android:id="@+id/group_style_mark"
android:orderInCategory="9">
<item
android:id="@+id/menu_style_mark"
android:icon="@drawable/twotone_border_color_24"
android:title="@string/title_style_mark" />
</group>
<group
android:id="@+id/group_style_subscript"
android:orderInCategory="10">
<item
android:id="@+id/menu_style_subscript"
android:icon="@drawable/twotone_subscript_24"
android:title="@string/title_style_subscript" />
</group>
<group
android:id="@+id/group_style_superscript"
android:orderInCategory="11">
<item
android:id="@+id/menu_style_superscript"
android:icon="@drawable/twotone_superscript_24"
android:title="@string/title_style_superscript" />
</group>
<group
android:id="@+id/group_style_strikethrough"
android:orderInCategory="12">
<item
android:id="@+id/menu_style_strikethrough"
android:icon="@drawable/twotone_format_strikethrough_24"
android:title="@string/title_style_strikethrough" />
</group>
<group
android:id="@+id/group_style_password"
android:orderInCategory="13">
<item
android:id="@+id/menu_style_password"
android:icon="@drawable/twotone_lock_24"
android:title="@string/title_style_protect" />
</group>
<group
android:id="@+id/group_style_code"
android:orderInCategory="14">
<item
android:id="@+id/menu_style_code"
android:icon="@drawable/twotone_code_24"
android:title="@string/title_style_code" />
</group>
<group
android:id="@+id/group_style_clear"
android:orderInCategory="15">
<item
android:id="@+id/menu_style_clear"
android:icon="@drawable/twotone_format_clear_24"
android:title="@string/title_style_clear" />
</group>
</menu>
Loading…
Cancel
Save