Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2020-12-19 16:47:26 +0300
committerNiedermann IT-Dienstleistungen <stefan-niedermann@users.noreply.github.com>2020-12-21 13:49:02 +0300
commitcf31fe6ba34b6adb73242aad0f8c480b9179024a (patch)
tree4c48218b799e591ebf75c9804bea1a68d28ee1cb
parente0f1052db42a77e1310abff49eed8745dc1e3355 (diff)
PoC SearchHighlight for editor
Signed-off-by: Stefan Niedermann <info@niedermann.it>
-rw-r--r--markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownEditor.java4
-rw-r--r--markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java30
-rw-r--r--markdown/src/main/java/it/niedermann/android/markdown/markwon/plugins/SearchHighlightPlugin.java108
-rw-r--r--markdown/src/main/java/it/niedermann/android/markdown/markwon/span/SearchSpan.java74
-rw-r--r--markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcher.java12
-rw-r--r--markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/CombinedTextWatcher.java39
-rw-r--r--markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/InterceptorTextWatcher.java15
-rw-r--r--markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/SearchHighlightTextWatcher.java36
8 files changed, 205 insertions, 113 deletions
diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownEditor.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownEditor.java
index 345a75347..410cacc0d 100644
--- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownEditor.java
+++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownEditor.java
@@ -23,7 +23,7 @@ import it.niedermann.android.markdown.markwon.handler.CodeBlockEditHandler;
import it.niedermann.android.markdown.markwon.handler.CodeEditHandler;
import it.niedermann.android.markdown.markwon.handler.HeadingEditHandler;
import it.niedermann.android.markdown.markwon.handler.StrikethroughEditHandler;
-import it.niedermann.android.markdown.markwon.textwatcher.AutoContinuationTextWatcher;
+import it.niedermann.android.markdown.markwon.textwatcher.CombinedTextWatcher;
public class MarkwonMarkdownEditor extends AppCompatEditText implements MarkdownEditor {
@@ -49,7 +49,7 @@ public class MarkwonMarkdownEditor extends AppCompatEditText implements Markdown
.useEditHandler(new BlockQuoteEditHandler())
.useEditHandler(new HeadingEditHandler())
.build();
- addTextChangedListener(new AutoContinuationTextWatcher(editor, this));
+ addTextChangedListener(new CombinedTextWatcher(editor, this));
setCustomSelectionActionModeCallback(new ContextBasedRangeFormattingCallback(this));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setCustomInsertionActionModeCallback(new ContextBasedFormattingCallback(this));
diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java
index ffc67cb2f..86629bb0e 100644
--- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java
+++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java
@@ -2,8 +2,10 @@ package it.niedermann.android.markdown.markwon;
import android.content.Context;
import android.text.Editable;
+import android.text.Spannable;
import android.text.TextUtils;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
@@ -30,6 +32,7 @@ import it.niedermann.android.markdown.markwon.model.EListType;
import it.niedermann.android.markdown.markwon.plugins.NextcloudMentionsPlugin;
import it.niedermann.android.markdown.markwon.plugins.SearchHighlightPlugin;
import it.niedermann.android.markdown.markwon.plugins.ThemePlugin;
+import it.niedermann.android.markdown.markwon.span.SearchSpan;
@RestrictTo(value = RestrictTo.Scope.LIBRARY)
@PrismBundle(
@@ -252,4 +255,31 @@ public class MarkwonMarkdownUtil {
}
return false;
}
+
+ public static void searchAndColor(@NonNull Editable editable, @Nullable CharSequence searchText, @NonNull Context context, @Nullable Integer current, @ColorInt int mainColor, @ColorInt int textColor) {
+ resetSearchSpans(editable);
+ if (TextUtils.isEmpty(searchText)) {
+ return;
+ }
+
+ //noinspection ConstantConditions
+ final Matcher m = Pattern.compile(searchText.toString(), Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
+ .matcher(editable);
+
+ int i = 1;
+ while (m.find()) {
+ int start = m.start();
+ int end = m.end();
+ editable.setSpan(new SearchSpan(context, mainColor, textColor, (current != null && i == current)), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ i++;
+ }
+ }
+
+ private static void resetSearchSpans(@NonNull Editable editable) {
+ final Object[] spansToRemove = editable.getSpans(0, editable.length(), Object.class);
+ for (Object span : spansToRemove) {
+ if (span.getClass() == SearchSpan.class)
+ editable.removeSpan(span);
+ }
+ }
}
diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/plugins/SearchHighlightPlugin.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/plugins/SearchHighlightPlugin.java
index 9bde67aa9..c297b3782 100644
--- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/plugins/SearchHighlightPlugin.java
+++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/plugins/SearchHighlightPlugin.java
@@ -1,25 +1,16 @@
package it.niedermann.android.markdown.markwon.plugins;
-import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Color;
-import android.text.Spannable;
+import android.text.Editable;
import android.text.SpannableStringBuilder;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.text.style.MetricAffectingSpan;
import android.widget.TextView;
-import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.MarkwonPlugin;
-import it.niedermann.android.util.ColorUtil;
+
+import static it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil.searchAndColor;
public class SearchHighlightPlugin extends AbstractMarkwonPlugin {
@@ -30,97 +21,8 @@ public class SearchHighlightPlugin extends AbstractMarkwonPlugin {
@Override
public void afterSetText(@NonNull TextView textView) {
super.afterSetText(textView);
- Spannable coloredContent = searchAndColor(textView.getText(), "new", textView.getContext(), 0, Color.BLUE, Color.YELLOW);
+ final Editable coloredContent = new SpannableStringBuilder(textView.getText());
+ searchAndColor(coloredContent, "new", textView.getContext(), 0, Color.BLUE, Color.YELLOW);
textView.setText(coloredContent, TextView.BufferType.SPANNABLE);
}
-
- public static Spannable searchAndColor(CharSequence sequence, CharSequence searchText, @NonNull Context context, @Nullable Integer current, @ColorInt int mainColor, @ColorInt int textColor) {
- SpannableStringBuilder spannable = new SpannableStringBuilder(sequence);
- CharSequence text = spannable.toString();
-
- Object[] spansToRemove = spannable.getSpans(0, text.length(), Object.class);
- for (Object span : spansToRemove) {
- if (span instanceof SearchSpan)
- spannable.removeSpan(span);
- }
-
- if (TextUtils.isEmpty(text) || TextUtils.isEmpty(searchText)) {
- return spannable;
- }
-
- Matcher m = Pattern.compile(searchText.toString(), Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
- .matcher(text);
-
- int i = 1;
- while (m.find()) {
- int start = m.start();
- int end = m.end();
- spannable.setSpan(new SearchSpan(context, mainColor, textColor, (current != null && i == current)), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- i++;
- }
-
- return spannable;
- }
-
- static class SearchSpan extends MetricAffectingSpan {
-
- private final boolean current;
- @NonNull
- Context context;
- @ColorInt
- private final int mainColor;
- @ColorInt
- private final int textColor;
- @ColorInt
- private final int highlightColor;
-
- SearchSpan(@NonNull Context context, @ColorInt int mainColor, @ColorInt int textColor, boolean current) {
- this.context = context;
- this.mainColor = mainColor;
- this.textColor = textColor;
- this.current = current;
- this.highlightColor = Color.RED;// context.getResources().getColor(R.color.bg_highlighted);
- }
-
- @Override
- public void updateDrawState(TextPaint tp) {
- if (current) {
- if (isDarkThemeActive(context)) {
- if (ColorUtil.INSTANCE.isColorDark(mainColor)) {
- tp.bgColor = Color.WHITE;
- tp.setColor(mainColor);
- } else {
- tp.bgColor = mainColor;
- tp.setColor(Color.BLACK);
- }
- } else {
- if (ColorUtil.INSTANCE.isColorDark(mainColor)) {
- tp.bgColor = mainColor;
- tp.setColor(Color.WHITE);
- } else {
-// if (NotesColorUtil.contrastRatioIsSufficient(mainColor, highlightColor)) {
-// tp.bgColor = highlightColor;
-// } else {
- tp.bgColor = Color.BLACK;
-// }
- tp.setColor(mainColor);
- }
- }
- } else {
- tp.bgColor = highlightColor;
- tp.setColor(/*BrandingUtil.getSecondaryForegroundColorDependingOnTheme(context, */mainColor/*)*/);
- }
- tp.setFakeBoldText(true);
- }
-
- @Override
- public void updateMeasureState(@NonNull TextPaint tp) {
- tp.setFakeBoldText(true);
- }
- }
-
- private static boolean isDarkThemeActive(Context context) {
- int uiMode = context.getResources().getConfiguration().uiMode;
- return (uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
- }
}
diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/span/SearchSpan.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/span/SearchSpan.java
new file mode 100644
index 000000000..857d54267
--- /dev/null
+++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/span/SearchSpan.java
@@ -0,0 +1,74 @@
+package it.niedermann.android.markdown.markwon.span;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.text.TextPaint;
+import android.text.style.MetricAffectingSpan;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+
+import it.niedermann.android.util.ColorUtil;
+
+public class SearchSpan extends MetricAffectingSpan {
+
+ private final boolean current;
+ @NonNull
+ Context context;
+ @ColorInt
+ private final int mainColor;
+ @ColorInt
+ private final int textColor;
+ @ColorInt
+ private final int highlightColor;
+
+ public SearchSpan(@NonNull Context context, @ColorInt int mainColor, @ColorInt int textColor, boolean current) {
+ this.context = context;
+ this.mainColor = mainColor;
+ this.textColor = textColor;
+ this.current = current;
+ this.highlightColor = Color.GRAY; //context.getResources().getColor(R.color.bg_highlighted);
+ }
+
+ @Override
+ public void updateDrawState(TextPaint tp) {
+ if (current) {
+ if (isDarkThemeActive(context)) {
+ if (ColorUtil.INSTANCE.isColorDark(mainColor)) {
+ tp.bgColor = Color.WHITE;
+ tp.setColor(mainColor);
+ } else {
+ tp.bgColor = mainColor;
+ tp.setColor(Color.BLACK);
+ }
+ } else {
+ if (ColorUtil.INSTANCE.isColorDark(mainColor)) {
+ tp.bgColor = mainColor;
+ tp.setColor(Color.WHITE);
+ } else {
+ if (true /*NotesColorUtil.contrastRatioIsSufficient(mainColor, highlightColor)*/) {
+ tp.bgColor = highlightColor;
+ } else {
+ tp.bgColor = Color.BLACK;
+ }
+ tp.setColor(mainColor);
+ }
+ }
+ } else {
+ tp.bgColor = highlightColor;
+ tp.setColor(mainColor /*BrandingUtil.getSecondaryForegroundColorDependingOnTheme(context, mainColor)*/);
+ }
+ tp.setFakeBoldText(true);
+ }
+
+ @Override
+ public void updateMeasureState(@NonNull TextPaint tp) {
+ tp.setFakeBoldText(true);
+ }
+
+ private static boolean isDarkThemeActive(Context context) {
+ int uiMode = context.getResources().getConfiguration().uiMode;
+ return (uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+ }
+} \ No newline at end of file
diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcher.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcher.java
index f01e62b40..136eccea6 100644
--- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcher.java
+++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcher.java
@@ -5,10 +5,6 @@ import android.text.TextWatcher;
import androidx.annotation.NonNull;
-import java.util.concurrent.Executors;
-
-import io.noties.markwon.editor.MarkwonEditor;
-import io.noties.markwon.editor.MarkwonEditorTextWatcher;
import it.niedermann.android.markdown.markwon.MarkwonMarkdownEditor;
import it.niedermann.android.markdown.markwon.model.EListType;
@@ -20,18 +16,18 @@ import static it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil.lineSta
/**
* Automatically continues lists and checkbox lists when pressing enter
*/
-public class AutoContinuationTextWatcher implements TextWatcher {
+public class AutoContinuationTextWatcher extends InterceptorTextWatcher {
- private final MarkwonEditorTextWatcher originalWatcher;
+ @NonNull
private final MarkwonMarkdownEditor editText;
private CharSequence customText = null;
private boolean isInsert = true;
private int sequenceStart = 0;
- public AutoContinuationTextWatcher(@NonNull MarkwonEditor editor, @NonNull MarkwonMarkdownEditor editText) {
+ public AutoContinuationTextWatcher(@NonNull TextWatcher originalWatcher, @NonNull MarkwonMarkdownEditor editText) {
+ super(originalWatcher);
this.editText = editText;
- originalWatcher = MarkwonEditorTextWatcher.withPreRender(editor, Executors.newSingleThreadExecutor(), editText);
}
@Override
diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/CombinedTextWatcher.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/CombinedTextWatcher.java
new file mode 100644
index 000000000..56a9a8abb
--- /dev/null
+++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/CombinedTextWatcher.java
@@ -0,0 +1,39 @@
+package it.niedermann.android.markdown.markwon.textwatcher;
+
+import android.text.Editable;
+import android.text.TextWatcher;
+
+import androidx.annotation.NonNull;
+
+import java.util.concurrent.Executors;
+
+import io.noties.markwon.editor.MarkwonEditor;
+import io.noties.markwon.editor.MarkwonEditorTextWatcher;
+import it.niedermann.android.markdown.markwon.MarkwonMarkdownEditor;
+
+public class CombinedTextWatcher implements TextWatcher {
+
+ private final TextWatcher watcher;
+
+ public CombinedTextWatcher(@NonNull MarkwonEditor editor, @NonNull MarkwonMarkdownEditor editText) {
+ final TextWatcher markwonTextWatcher = MarkwonEditorTextWatcher.withPreRender(editor, Executors.newSingleThreadExecutor(), editText);
+ final TextWatcher autoContinuationTextWatcher = new AutoContinuationTextWatcher(markwonTextWatcher, editText);
+ watcher = new SearchHighlightTextWatcher(autoContinuationTextWatcher, editText);
+ }
+
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ watcher.beforeTextChanged(s, start, count, after);
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ watcher.onTextChanged(s, start, before, count);
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ watcher.afterTextChanged(s);
+ }
+}
diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/InterceptorTextWatcher.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/InterceptorTextWatcher.java
new file mode 100644
index 000000000..4b5e9d5f3
--- /dev/null
+++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/InterceptorTextWatcher.java
@@ -0,0 +1,15 @@
+package it.niedermann.android.markdown.markwon.textwatcher;
+
+import android.text.TextWatcher;
+
+import androidx.annotation.NonNull;
+
+abstract public class InterceptorTextWatcher implements TextWatcher {
+
+ @NonNull
+ protected final TextWatcher originalWatcher;
+
+ public InterceptorTextWatcher(@NonNull TextWatcher originalWatcher) {
+ this.originalWatcher = originalWatcher;
+ }
+}
diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/SearchHighlightTextWatcher.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/SearchHighlightTextWatcher.java
new file mode 100644
index 000000000..896be9610
--- /dev/null
+++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/SearchHighlightTextWatcher.java
@@ -0,0 +1,36 @@
+package it.niedermann.android.markdown.markwon.textwatcher;
+
+import android.graphics.Color;
+import android.text.Editable;
+import android.text.TextWatcher;
+
+import androidx.annotation.NonNull;
+
+import it.niedermann.android.markdown.markwon.MarkwonMarkdownEditor;
+import it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil;
+
+public class SearchHighlightTextWatcher extends InterceptorTextWatcher {
+
+ private final MarkwonMarkdownEditor editText;
+
+ public SearchHighlightTextWatcher(@NonNull TextWatcher originalWatcher, @NonNull MarkwonMarkdownEditor editText) {
+ super(originalWatcher);
+ this.editText = editText;
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ this.originalWatcher.beforeTextChanged(s, start, count, after);
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ this.originalWatcher.onTextChanged(s, start, before, count);
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ originalWatcher.afterTextChanged(s);
+ MarkwonMarkdownUtil.searchAndColor(s, "new", editText.getContext(), 0, Color.MAGENTA, Color.GREEN);
+ }
+}