Refactoring

pull/209/head
M66B 2 years ago
parent 35e495cec1
commit 1163c68e24

@ -27,11 +27,9 @@ import android.content.res.Resources;
import android.graphics.Paint; import android.graphics.Paint;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.text.Editable;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.style.RelativeSizeSpan; import android.text.style.RelativeSizeSpan;
import android.util.Pair;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.CheckBox; import android.widget.CheckBox;
@ -157,45 +155,6 @@ public class DeepL {
} }
} }
public static Pair<Integer, Integer> getParagraph(EditText etBody) {
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')
start--;
if (start == end && end < edit.length())
end++;
// Expand selection at end
while (end > 0 && end < edit.length() && edit.charAt(end - 1) != '\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;
}
public static Translation translate(CharSequence text, boolean html, String target, Context context) throws IOException, JSONException { public static Translation translate(CharSequence text, boolean html, String target, Context context) throws IOException, JSONException {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean deepl_formal = prefs.getBoolean("deepl_formal", true); boolean deepl_formal = prefs.getBoolean("deepl_formal", true);

@ -2310,7 +2310,7 @@ public class FragmentCompose extends FragmentBase {
if (languages == null) if (languages == null)
languages = new ArrayList<>(); languages = new ArrayList<>();
Pair<Integer, Integer> paragraph = DeepL.getParagraph(etBody); Pair<Integer, Integer> paragraph = StyleHelper.getParagraph(etBody);
boolean canTranslate = (DeepL.canTranslate(context) && paragraph != null); boolean canTranslate = (DeepL.canTranslate(context) && paragraph != null);
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, getViewLifecycleOwner(), anchor); PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, getViewLifecycleOwner(), anchor);
@ -2355,7 +2355,7 @@ public class FragmentCompose extends FragmentBase {
} }
private void onMenuTranslate(String target) { private void onMenuTranslate(String target) {
final Pair<Integer, Integer> paragraph = DeepL.getParagraph(etBody); final Pair<Integer, Integer> paragraph = StyleHelper.getParagraph(etBody);
if (paragraph == null) if (paragraph == null)
return; return;

@ -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;

@ -113,19 +113,10 @@
</menu> </menu>
</item> </item>
<group
android:id="@+id/group_style_blockquote"
android:orderInCategory="7">
<item
android:id="@+id/menu_style_blockquote"
android:icon="@drawable/twotone_format_quote_24"
android:title="@string/title_style_blockquote" />
</group>
<item <item
android:id="@+id/menu_style_indentation" android:id="@+id/menu_style_indentation"
android:icon="@drawable/twotone_format_indent_increase_24" android:icon="@drawable/twotone_format_indent_increase_24"
android:orderInCategory="8" android:orderInCategory="7"
android:title="@string/title_style_indentation"> android:title="@string/title_style_indentation">
<menu> <menu>
<group android:id="@+id/group_style_indentation"> <group android:id="@+id/group_style_indentation">
@ -141,6 +132,15 @@
</menu> </menu>
</item> </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 <group
android:id="@+id/group_style_mark" android:id="@+id/group_style_mark"
android:orderInCategory="9"> android:orderInCategory="9">

Loading…
Cancel
Save