mirror of https://github.com/M66B/FairEmail.git
Use text watcher for answer/signature editor
This commit is contained in:
parent
4ddc6f2130
commit
bf67eb6d38
|
@ -104,6 +104,8 @@ public class ActivitySignature extends ActivityBase {
|
|||
}
|
||||
});
|
||||
|
||||
etText.addTextChangedListener(StyleHelper.getTextWatcher(etText));
|
||||
|
||||
etText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
@ -124,6 +126,8 @@ public class ActivitySignature extends ActivityBase {
|
|||
}
|
||||
});
|
||||
|
||||
StyleHelper.wire(this, view, etText);
|
||||
|
||||
ibFull.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
@ -139,8 +143,6 @@ public class ActivitySignature extends ActivityBase {
|
|||
}
|
||||
});
|
||||
|
||||
StyleHelper.wire(this, view, etText);
|
||||
|
||||
bottom_navigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
||||
|
|
|
@ -158,6 +158,8 @@ public class FragmentAnswer extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
etText.addTextChangedListener(StyleHelper.getTextWatcher(etText));
|
||||
|
||||
StyleHelper.wire(getViewLifecycleOwner(), view, etText);
|
||||
|
||||
bottom_navigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
|
||||
|
|
|
@ -639,7 +639,8 @@ public class FragmentCompose extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
// https://developer.android.com/reference/android/text/TextWatcher
|
||||
etBody.addTextChangedListener(StyleHelper.getTextWatcher(etBody));
|
||||
|
||||
etBody.addTextChangedListener(new TextWatcher() {
|
||||
private boolean save = false;
|
||||
private Integer added = null;
|
||||
|
@ -649,25 +650,7 @@ public class FragmentCompose extends FragmentBase {
|
|||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence text, int start, int count, int after) {
|
||||
if (count == 1 && after == 0 && (start == 0 || text.charAt(start) == '\n')) {
|
||||
Log.i("Removed=" + start);
|
||||
removed = start;
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG && count - after == 1 && start + after > 0) {
|
||||
int replaced = start + after;
|
||||
Spanned spanned = ((Spanned) text);
|
||||
StyleHelper.InsertedSpan[] spans =
|
||||
spanned.getSpans(replaced, replaced, StyleHelper.InsertedSpan.class);
|
||||
for (StyleHelper.InsertedSpan span : spans) {
|
||||
int end = spanned.getSpanEnd(span);
|
||||
Log.i("Replaced=" + replaced);
|
||||
if (end - 1 == replaced) {
|
||||
inserted = end - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -681,6 +664,7 @@ public class FragmentCompose extends FragmentBase {
|
|||
if (count - before == 1 && index > 0) {
|
||||
char c = text.charAt(index);
|
||||
char b = text.charAt(index - 1);
|
||||
|
||||
save = (auto_save_paragraph && c == '\n' && b != '\n') ||
|
||||
(auto_save_dot && Helper.isDot(c) && !Helper.isDot(b));
|
||||
if (save)
|
||||
|
@ -698,119 +682,8 @@ public class FragmentCompose extends FragmentBase {
|
|||
if (etBody == null)
|
||||
return;
|
||||
|
||||
LogPrinter lp = null;
|
||||
if (BuildConfig.DEBUG &&
|
||||
(added != null || removed != null))
|
||||
lp = new LogPrinter(android.util.Log.INFO, "FairEmail");
|
||||
|
||||
if (lp != null)
|
||||
TextUtils.dumpSpans(text, new LogPrinter(android.util.Log.INFO, "FairEmail"), "---before>");
|
||||
|
||||
if (added != null)
|
||||
try {
|
||||
// break block quotes
|
||||
boolean broken = false;
|
||||
QuoteSpan[] spans = text.getSpans(added + 1, added + 1, QuoteSpan.class);
|
||||
for (QuoteSpan span : spans) {
|
||||
int s = text.getSpanStart(span);
|
||||
int e = text.getSpanEnd(span);
|
||||
int f = text.getSpanFlags(span);
|
||||
Log.i(span + " " + s + "..." + e + " added=" + added);
|
||||
|
||||
if (s > 0 && added - s > 0 && e - (added + 1) > 0 &&
|
||||
text.charAt(s - 1) == '\n' && text.charAt(added - 1) == '\n' &&
|
||||
text.charAt(added) == '\n' && text.charAt(e - 1) == '\n') {
|
||||
broken = true;
|
||||
|
||||
QuoteSpan q1 = StyleHelper.clone(span, QuoteSpan.class, etBody.getContext());
|
||||
text.setSpan(q1, s, added, f);
|
||||
Log.i(span + " " + s + "..." + added);
|
||||
|
||||
QuoteSpan q2 = StyleHelper.clone(span, QuoteSpan.class, etBody.getContext());
|
||||
text.setSpan(q2, added + 1, e, f);
|
||||
Log.i(span + " " + (added + 1) + "..." + e);
|
||||
|
||||
text.removeSpan(span);
|
||||
}
|
||||
}
|
||||
|
||||
if (broken) {
|
||||
CharacterStyle[] sspan = text.getSpans(added + 1, added + 1, CharacterStyle.class);
|
||||
for (CharacterStyle span : sspan) {
|
||||
int s = text.getSpanStart(span);
|
||||
int e = text.getSpanEnd(span);
|
||||
int f = text.getSpanFlags(span);
|
||||
Log.i(span + " " + s + "..." + e + " start=" + added);
|
||||
|
||||
if (s <= added && added + 1 <= e) {
|
||||
CharacterStyle s1 = CharacterStyle.wrap(span);
|
||||
text.setSpan(s1, s, added, f);
|
||||
Log.i(span + " " + s + "..." + added);
|
||||
|
||||
CharacterStyle s2 = CharacterStyle.wrap(span);
|
||||
text.setSpan(s2, added + 1, e, f);
|
||||
Log.i(span + " " + (added + 1) + "..." + e);
|
||||
|
||||
text.removeSpan(span);
|
||||
}
|
||||
}
|
||||
|
||||
etBody.setSelection(added);
|
||||
}
|
||||
|
||||
// Escape indent at end
|
||||
IndentSpan[] indents = text.getSpans(added + 1, added + 1, IndentSpan.class);
|
||||
for (IndentSpan indent : indents) {
|
||||
int s = text.getSpanStart(indent);
|
||||
int e = text.getSpanEnd(indent);
|
||||
int f = text.getSpanFlags(indent);
|
||||
if (e - 1 > s && added + 1 == e) {
|
||||
text.removeSpan(indent);
|
||||
text.setSpan(new IndentSpan(indent.getLeadingMargin(true)), s, e - 1, f);
|
||||
}
|
||||
}
|
||||
|
||||
boolean renum = false;
|
||||
BulletSpan[] bullets = text.getSpans(added + 1, added + 1, BulletSpan.class);
|
||||
|
||||
int len = 0;
|
||||
BulletSpan shortest = null;
|
||||
for (BulletSpan span : bullets) {
|
||||
int s = text.getSpanStart(span);
|
||||
int e = text.getSpanEnd(span);
|
||||
if (shortest == null || e - s < len) {
|
||||
shortest = span;
|
||||
len = e - s;
|
||||
}
|
||||
}
|
||||
|
||||
if (shortest != null) {
|
||||
int s = text.getSpanStart(shortest);
|
||||
int e = text.getSpanEnd(shortest);
|
||||
int f = text.getSpanFlags(shortest) | Spanned.SPAN_PARAGRAPH;
|
||||
Log.i(shortest + " " + s + "..." + e + " added=" + added);
|
||||
|
||||
if (s > 0 &&
|
||||
added + 1 > s && e > added + 1 &&
|
||||
text.charAt(s - 1) == '\n' && text.charAt(e - 1) == '\n') {
|
||||
if (e - s > 2) {
|
||||
BulletSpan b1 = StyleHelper.clone(shortest, shortest.getClass(), etBody.getContext());
|
||||
text.setSpan(b1, s, added + 1, f);
|
||||
Log.i(shortest + " " + s + "..." + (added + 1));
|
||||
|
||||
BulletSpan b2 = StyleHelper.clone(b1, shortest.getClass(), etBody.getContext());
|
||||
text.setSpan(b2, added + 1, e, f);
|
||||
Log.i(shortest + " " + (added + 1) + "..." + e);
|
||||
}
|
||||
|
||||
renum = true;
|
||||
text.removeSpan(shortest);
|
||||
}
|
||||
}
|
||||
|
||||
if (renum)
|
||||
StyleHelper.renumber(text, false, etBody.getContext());
|
||||
|
||||
if (lt_auto) {
|
||||
int start = added;
|
||||
while (start > 0 && text.charAt(start - 1) != '\n')
|
||||
|
@ -824,38 +697,6 @@ public class FragmentCompose extends FragmentBase {
|
|||
added = null;
|
||||
}
|
||||
|
||||
if (removed != null)
|
||||
try {
|
||||
ParagraphStyle[] ps = text.getSpans(removed, removed + 1, ParagraphStyle.class);
|
||||
if (ps != null)
|
||||
for (ParagraphStyle p : ps) {
|
||||
int start = text.getSpanStart(p);
|
||||
int end = text.getSpanEnd(p);
|
||||
if (start >= removed && end <= removed + 1)
|
||||
text.removeSpan(p);
|
||||
}
|
||||
|
||||
StyleHelper.renumber(text, true, etBody.getContext());
|
||||
} finally {
|
||||
removed = null;
|
||||
}
|
||||
|
||||
if (inserted != null)
|
||||
try {
|
||||
StyleHelper.InsertedSpan[] spans =
|
||||
text.getSpans(inserted, inserted, StyleHelper.InsertedSpan.class);
|
||||
for (StyleHelper.InsertedSpan span : spans) {
|
||||
int start = text.getSpanStart(span);
|
||||
int end = text.getSpanEnd(span);
|
||||
if (end == inserted) {
|
||||
text.delete(start, end);
|
||||
text.removeSpan(span);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
inserted = null;
|
||||
}
|
||||
|
||||
if (save)
|
||||
try {
|
||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
|
||||
|
@ -873,10 +714,6 @@ public class FragmentCompose extends FragmentBase {
|
|||
} finally {
|
||||
lt = null;
|
||||
}
|
||||
|
||||
|
||||
if (lp != null)
|
||||
TextUtils.dumpSpans(text, lp, "---after>");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import android.text.SpannableStringBuilder;
|
|||
import android.text.Spanned;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.style.AlignmentSpan;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.BulletSpan;
|
||||
|
@ -47,6 +48,7 @@ import android.text.style.StyleSpan;
|
|||
import android.text.style.TypefaceSpan;
|
||||
import android.text.style.URLSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import android.util.LogPrinter;
|
||||
import android.util.Pair;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
|
@ -139,6 +141,210 @@ public class StyleHelper {
|
|||
}
|
||||
}
|
||||
|
||||
static TextWatcher getTextWatcher(EditText etBody) {
|
||||
// https://developer.android.com/reference/android/text/TextWatcher
|
||||
return new TextWatcher() {
|
||||
private Integer added = null;
|
||||
private Integer removed = null;
|
||||
private Integer inserted = null;
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence text, int start, int count, int after) {
|
||||
if (count == 1 && after == 0 && (start == 0 || text.charAt(start) == '\n')) {
|
||||
Log.i("Removed=" + start);
|
||||
removed = start;
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG && count - after == 1 && start + after > 0) {
|
||||
int replaced = start + after;
|
||||
Spanned spanned = ((Spanned) text);
|
||||
StyleHelper.InsertedSpan[] spans =
|
||||
spanned.getSpans(replaced, replaced, StyleHelper.InsertedSpan.class);
|
||||
for (StyleHelper.InsertedSpan span : spans) {
|
||||
int end = spanned.getSpanEnd(span);
|
||||
Log.i("Replaced=" + replaced);
|
||||
if (end - 1 == replaced) {
|
||||
inserted = end - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence text, int start, int before, int count) {
|
||||
int index = start + before;
|
||||
|
||||
if (count - before == 1 && index > 0) {
|
||||
char c = text.charAt(index);
|
||||
if (c == '\n') {
|
||||
Log.i("Added=" + index);
|
||||
added = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable text) {
|
||||
if (etBody == null)
|
||||
return;
|
||||
|
||||
LogPrinter lp = null;
|
||||
if (BuildConfig.DEBUG &&
|
||||
(added != null || removed != null))
|
||||
lp = new LogPrinter(android.util.Log.INFO, "FairEmail");
|
||||
|
||||
if (lp != null)
|
||||
TextUtils.dumpSpans(text, new LogPrinter(android.util.Log.INFO, "FairEmail"), "---before>");
|
||||
|
||||
if (added != null)
|
||||
try {
|
||||
// break block quotes
|
||||
boolean broken = false;
|
||||
QuoteSpan[] spans = text.getSpans(added + 1, added + 1, QuoteSpan.class);
|
||||
for (QuoteSpan span : spans) {
|
||||
int s = text.getSpanStart(span);
|
||||
int e = text.getSpanEnd(span);
|
||||
int f = text.getSpanFlags(span);
|
||||
Log.i(span + " " + s + "..." + e + " added=" + added);
|
||||
|
||||
if (s > 0 && added - s > 0 && e - (added + 1) > 0 &&
|
||||
text.charAt(s - 1) == '\n' && text.charAt(added - 1) == '\n' &&
|
||||
text.charAt(added) == '\n' && text.charAt(e - 1) == '\n') {
|
||||
broken = true;
|
||||
|
||||
QuoteSpan q1 = StyleHelper.clone(span, QuoteSpan.class, etBody.getContext());
|
||||
text.setSpan(q1, s, added, f);
|
||||
Log.i(span + " " + s + "..." + added);
|
||||
|
||||
QuoteSpan q2 = StyleHelper.clone(span, QuoteSpan.class, etBody.getContext());
|
||||
text.setSpan(q2, added + 1, e, f);
|
||||
Log.i(span + " " + (added + 1) + "..." + e);
|
||||
|
||||
text.removeSpan(span);
|
||||
}
|
||||
}
|
||||
|
||||
if (broken) {
|
||||
CharacterStyle[] sspan = text.getSpans(added + 1, added + 1, CharacterStyle.class);
|
||||
for (CharacterStyle span : sspan) {
|
||||
int s = text.getSpanStart(span);
|
||||
int e = text.getSpanEnd(span);
|
||||
int f = text.getSpanFlags(span);
|
||||
Log.i(span + " " + s + "..." + e + " start=" + added);
|
||||
|
||||
if (s <= added && added + 1 <= e) {
|
||||
CharacterStyle s1 = CharacterStyle.wrap(span);
|
||||
text.setSpan(s1, s, added, f);
|
||||
Log.i(span + " " + s + "..." + added);
|
||||
|
||||
CharacterStyle s2 = CharacterStyle.wrap(span);
|
||||
text.setSpan(s2, added + 1, e, f);
|
||||
Log.i(span + " " + (added + 1) + "..." + e);
|
||||
|
||||
text.removeSpan(span);
|
||||
}
|
||||
}
|
||||
|
||||
etBody.setSelection(added);
|
||||
}
|
||||
|
||||
// Escape indent at end
|
||||
IndentSpan[] indents = text.getSpans(added + 1, added + 1, IndentSpan.class);
|
||||
for (IndentSpan indent : indents) {
|
||||
int s = text.getSpanStart(indent);
|
||||
int e = text.getSpanEnd(indent);
|
||||
int f = text.getSpanFlags(indent);
|
||||
if (e - 1 > s && added + 1 == e) {
|
||||
text.removeSpan(indent);
|
||||
text.setSpan(new IndentSpan(indent.getLeadingMargin(true)), s, e - 1, f);
|
||||
}
|
||||
}
|
||||
|
||||
boolean renum = false;
|
||||
BulletSpan[] bullets = text.getSpans(added + 1, added + 1, BulletSpan.class);
|
||||
|
||||
int len = 0;
|
||||
BulletSpan shortest = null;
|
||||
for (BulletSpan span : bullets) {
|
||||
int s = text.getSpanStart(span);
|
||||
int e = text.getSpanEnd(span);
|
||||
if (shortest == null || e - s < len) {
|
||||
shortest = span;
|
||||
len = e - s;
|
||||
}
|
||||
}
|
||||
|
||||
if (shortest != null) {
|
||||
int s = text.getSpanStart(shortest);
|
||||
int e = text.getSpanEnd(shortest);
|
||||
int f = text.getSpanFlags(shortest) | Spanned.SPAN_PARAGRAPH;
|
||||
Log.i(shortest + " " + s + "..." + e + " added=" + added);
|
||||
|
||||
if (s > 0 &&
|
||||
added + 1 > s && e > added + 1 &&
|
||||
text.charAt(s - 1) == '\n' && text.charAt(e - 1) == '\n') {
|
||||
if (e - s > 2) {
|
||||
BulletSpan b1 = StyleHelper.clone(shortest, shortest.getClass(), etBody.getContext());
|
||||
text.setSpan(b1, s, added + 1, f);
|
||||
Log.i(shortest + " " + s + "..." + (added + 1));
|
||||
|
||||
BulletSpan b2 = StyleHelper.clone(b1, shortest.getClass(), etBody.getContext());
|
||||
text.setSpan(b2, added + 1, e, f);
|
||||
Log.i(shortest + " " + (added + 1) + "..." + e);
|
||||
}
|
||||
|
||||
renum = true;
|
||||
text.removeSpan(shortest);
|
||||
}
|
||||
}
|
||||
|
||||
if (renum)
|
||||
StyleHelper.renumber(text, false, etBody.getContext());
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
} finally {
|
||||
added = null;
|
||||
}
|
||||
|
||||
if (removed != null)
|
||||
try {
|
||||
ParagraphStyle[] ps = text.getSpans(removed, removed + 1, ParagraphStyle.class);
|
||||
if (ps != null)
|
||||
for (ParagraphStyle p : ps) {
|
||||
int start = text.getSpanStart(p);
|
||||
int end = text.getSpanEnd(p);
|
||||
if (start >= removed && end <= removed + 1)
|
||||
text.removeSpan(p);
|
||||
}
|
||||
|
||||
StyleHelper.renumber(text, true, etBody.getContext());
|
||||
} finally {
|
||||
removed = null;
|
||||
}
|
||||
|
||||
if (inserted != null)
|
||||
try {
|
||||
StyleHelper.InsertedSpan[] spans =
|
||||
text.getSpans(inserted, inserted, StyleHelper.InsertedSpan.class);
|
||||
for (StyleHelper.InsertedSpan span : spans) {
|
||||
int start = text.getSpanStart(span);
|
||||
int end = text.getSpanEnd(span);
|
||||
if (end == inserted) {
|
||||
text.delete(start, end);
|
||||
text.removeSpan(span);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
inserted = null;
|
||||
}
|
||||
|
||||
if (lp != null)
|
||||
TextUtils.dumpSpans(text, lp, "---after>");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static boolean apply(int groupId, int itemId, LifecycleOwner owner, View anchor, EditText etBody, Object... args) {
|
||||
Log.i("Style action=" + groupId + ":" + itemId);
|
||||
|
||||
|
|
Loading…
Reference in New Issue