diff options
author | Stefan Niedermann <info@niedermann.it> | 2020-12-19 17:45:07 +0300 |
---|---|---|
committer | Niedermann IT-Dienstleistungen <stefan-niedermann@users.noreply.github.com> | 2020-12-21 13:49:02 +0300 |
commit | e068f6406526f309b1cec71e2b981b80bfd64ac7 (patch) | |
tree | b96eb2ad1eca9c56e85b1bbc659e65c09e64fdb4 | |
parent | cf31fe6ba34b6adb73242aad0f8c480b9179024a (diff) |
Enhance search highlighting
Signed-off-by: Stefan Niedermann <info@niedermann.it>
9 files changed, 74 insertions, 50 deletions
diff --git a/markdown/src/main/java/it/niedermann/android/markdown/MarkdownEditor.java b/markdown/src/main/java/it/niedermann/android/markdown/MarkdownEditor.java index 6b08cfd82..e9d97500e 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/MarkdownEditor.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/MarkdownEditor.java @@ -1,6 +1,7 @@ package it.niedermann.android.markdown; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.lifecycle.LiveData; import java.util.Map; @@ -31,4 +32,8 @@ public interface MarkdownEditor { LiveData<CharSequence> getMarkdownString(); void setEnabled(boolean enabled); + + default void setSearchText(@Nullable CharSequence searchText) { + // Optional + } }
\ No newline at end of file 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 410cacc0d..a27dd524f 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 @@ -2,7 +2,9 @@ package it.niedermann.android.markdown.markwon; import android.content.Context; import android.os.Build; +import android.text.TextWatcher; import android.util.AttributeSet; +import android.util.Log; import android.widget.EditText; import androidx.annotation.NonNull; @@ -24,10 +26,14 @@ 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.CombinedTextWatcher; +import it.niedermann.android.markdown.markwon.textwatcher.SearchHighlightTextWatcher; public class MarkwonMarkdownEditor extends AppCompatEditText implements MarkdownEditor { + private static final String TAG = MarkwonMarkdownEditor.class.getSimpleName(); + private final MutableLiveData<CharSequence> unrenderedText$ = new MutableLiveData<>(); + private final CombinedTextWatcher combinedWatcher; public MarkwonMarkdownEditor(@NonNull Context context) { this(context, null); @@ -49,7 +55,8 @@ public class MarkwonMarkdownEditor extends AppCompatEditText implements Markdown .useEditHandler(new BlockQuoteEditHandler()) .useEditHandler(new HeadingEditHandler()) .build(); - addTextChangedListener(new CombinedTextWatcher(editor, this)); + combinedWatcher = new CombinedTextWatcher(editor, this); + addTextChangedListener(combinedWatcher); setCustomSelectionActionModeCallback(new ContextBasedRangeFormattingCallback(this)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { setCustomInsertionActionModeCallback(new ContextBasedFormattingCallback(this)); @@ -57,6 +64,17 @@ public class MarkwonMarkdownEditor extends AppCompatEditText implements Markdown } @Override + public void setSearchText(@Nullable CharSequence searchText) { + final SearchHighlightTextWatcher searchHighlightTextWatcher = combinedWatcher.get(SearchHighlightTextWatcher.class); + if (searchHighlightTextWatcher == null) { + Log.w(TAG, SearchHighlightTextWatcher.class.getSimpleName() + " is not a registered " + TextWatcher.class.getSimpleName()); + } else { + searchHighlightTextWatcher.setSearchText(searchText); + post(() -> setMarkdownString(unrenderedText$.getValue())); + } + } + + @Override public void setMarkdownString(CharSequence text) { setText(text); setMarkdownStringModel(text); 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 86629bb0e..14539fb7a 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 @@ -30,7 +30,6 @@ import io.noties.prism4j.Prism4j; import io.noties.prism4j.annotations.PrismBundle; 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; @@ -58,8 +57,7 @@ public class MarkwonMarkdownUtil { .usePlugin(StrikethroughPlugin.create()) .usePlugin(SimpleExtPlugin.create()) .usePlugin(ImagesPlugin.create()) - .usePlugin(MarkwonInlineParserPlugin.create()) - .usePlugin(SearchHighlightPlugin.create()); + .usePlugin(MarkwonInlineParserPlugin.create()); } public static Markwon.Builder initMarkwonViewer(@NonNull Context context) { diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownViewer.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownViewer.java index aa6bcc8f9..70d11194c 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownViewer.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownViewer.java @@ -1,6 +1,9 @@ package it.niedermann.android.markdown.markwon; import android.content.Context; +import android.graphics.Color; +import android.text.Editable; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.util.AttributeSet; @@ -20,9 +23,12 @@ import it.niedermann.android.markdown.MarkdownEditor; import static androidx.lifecycle.Transformations.distinctUntilChanged; import static it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil.initMarkwonViewer; +import static it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil.searchAndColor; public class MarkwonMarkdownViewer extends AppCompatTextView implements MarkdownEditor { + private static final String TAG = MarkwonMarkdownViewer.class.getSimpleName(); + private Markwon markwon; private final MutableLiveData<CharSequence> unrenderedText$ = new MutableLiveData<>(); private final ExecutorService renderService; @@ -60,6 +66,15 @@ public class MarkwonMarkdownViewer extends AppCompatTextView implements Markdown } @Override + public void setSearchText(@Nullable CharSequence searchText) { + this.renderService.execute(() -> { + final Editable content = new SpannableStringBuilder(getText()); + searchAndColor(content, searchText, getContext(), 0, Color.BLUE, Color.YELLOW); + post(() -> setText(content, BufferType.SPANNABLE)); + }); + } + + @Override public void setMarkdownString(CharSequence text, @NonNull Map<String, String> mentions) { this.markwon = initMarkwonViewer(getContext(), mentions).build(); setMarkdownString(text); 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 deleted file mode 100644 index c297b3782..000000000 --- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/plugins/SearchHighlightPlugin.java +++ /dev/null @@ -1,28 +0,0 @@ -package it.niedermann.android.markdown.markwon.plugins; - -import android.graphics.Color; -import android.text.Editable; -import android.text.SpannableStringBuilder; -import android.widget.TextView; - -import androidx.annotation.NonNull; - -import io.noties.markwon.AbstractMarkwonPlugin; -import io.noties.markwon.MarkwonPlugin; - -import static it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil.searchAndColor; - -public class SearchHighlightPlugin extends AbstractMarkwonPlugin { - - public static MarkwonPlugin create() { - return new SearchHighlightPlugin(); - } - - @Override - public void afterSetText(@NonNull TextView textView) { - super.afterSetText(textView); - final Editable coloredContent = new SpannableStringBuilder(textView.getText()); - searchAndColor(coloredContent, "new", textView.getContext(), 0, Color.BLUE, Color.YELLOW); - textView.setText(coloredContent, TextView.BufferType.SPANNABLE); - } -} 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 136eccea6..44bde738d 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 @@ -31,11 +31,6 @@ public class AutoContinuationTextWatcher extends InterceptorTextWatcher { } @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - originalWatcher.beforeTextChanged(s, start, count, after); - } - - @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (count == 1 && s.charAt(start) == '\n') { handleNewlineInserted(s, start, count); 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 index 56a9a8abb..20cb2fcfa 100644 --- 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 @@ -4,23 +4,32 @@ import android.text.Editable; import android.text.TextWatcher; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.HashMap; 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 { +public class CombinedTextWatcher extends HashMap<Class<?>, TextWatcher> implements TextWatcher { private final TextWatcher watcher; + @SuppressWarnings("ConstantConditions") 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); + put(MarkwonEditorTextWatcher.class, MarkwonEditorTextWatcher.withPreRender(editor, Executors.newSingleThreadExecutor(), editText)); + put(AutoContinuationTextWatcher.class, new AutoContinuationTextWatcher(get(MarkwonEditorTextWatcher.class), editText)); + put(SearchHighlightTextWatcher.class, new SearchHighlightTextWatcher(get(AutoContinuationTextWatcher.class), editText)); + watcher = get(SearchHighlightTextWatcher.class); } + @SuppressWarnings({"unchecked"}) + @Nullable + public <T> T get(@Nullable Class<T> key) { + return (T) super.get(key); + } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { 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 index 4b5e9d5f3..479e38862 100644 --- 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 @@ -1,5 +1,6 @@ package it.niedermann.android.markdown.markwon.textwatcher; +import android.text.Editable; import android.text.TextWatcher; import androidx.annotation.NonNull; @@ -12,4 +13,19 @@ abstract public class InterceptorTextWatcher implements TextWatcher { public InterceptorTextWatcher(@NonNull TextWatcher originalWatcher) { this.originalWatcher = originalWatcher; } + + @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) { + this.originalWatcher.afterTextChanged(s); + } } 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 index 896be9610..1956a7e73 100644 --- 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 @@ -5,6 +5,7 @@ import android.text.Editable; import android.text.TextWatcher; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import it.niedermann.android.markdown.markwon.MarkwonMarkdownEditor; import it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil; @@ -12,25 +13,20 @@ import it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil; public class SearchHighlightTextWatcher extends InterceptorTextWatcher { private final MarkwonMarkdownEditor editText; + private CharSequence searchText; 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); + public void setSearchText(@Nullable CharSequence searchText) { + this.searchText = searchText; } @Override public void afterTextChanged(Editable s) { originalWatcher.afterTextChanged(s); - MarkwonMarkdownUtil.searchAndColor(s, "new", editText.getContext(), 0, Color.MAGENTA, Color.GREEN); + MarkwonMarkdownUtil.searchAndColor(s, searchText, editText.getContext(), 0, Color.MAGENTA, Color.GREEN); } } |