diff options
22 files changed, 284 insertions, 205 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/ItemCommentViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/ItemCommentViewHolder.java index 4ee74d3a7..56230d3c3 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/ItemCommentViewHolder.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/ItemCommentViewHolder.java @@ -15,7 +15,6 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; -import it.niedermann.android.markdown.MarkdownEditor; import it.niedermann.android.util.ClipboardUtil; import it.niedermann.android.util.DimensionUtil; import it.niedermann.nextcloud.deck.R; @@ -30,19 +29,17 @@ import static it.niedermann.nextcloud.deck.util.ViewUtil.setupMentions; public class ItemCommentViewHolder extends RecyclerView.ViewHolder { private final ItemCommentBinding binding; - private final MarkdownEditor markdownViewer; private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM); @SuppressWarnings("WeakerAccess") public ItemCommentViewHolder(ItemCommentBinding binding) { super(binding.getRoot()); this.binding = binding; - this.markdownViewer = this.binding.message; } public void bind(@NonNull FullDeckComment comment, @NonNull Account account, @ColorInt int mainColor, @NonNull MenuInflater inflater, @NonNull CommentDeletedListener deletedListener, @NonNull CommentSelectAsReplyListener selectAsReplyListener, @NonNull FragmentManager fragmentManager) { ViewUtil.addAvatar(binding.avatar, account.getUrl(), comment.getComment().getActorId(), DimensionUtil.INSTANCE.dpToPx(binding.avatar.getContext(), R.dimen.icon_size_details), R.drawable.ic_person_grey600_24dp); - this.markdownViewer.setMarkdownString(comment.getComment().getMessage()); + binding.message.setMarkdownString(comment.getComment().getMessage()); binding.actorDisplayName.setText(comment.getComment().getActorDisplayName()); binding.creationDateTime.setText(DateUtil.getRelativeDateTimeString(binding.creationDateTime.getContext(), comment.getComment().getCreationDateTime().toEpochMilli())); itemView.setOnClickListener(View::showContextMenu); @@ -79,7 +76,7 @@ public class ItemCommentViewHolder extends RecyclerView.ViewHolder { binding.notSyncedYet.setVisibility(DBStatus.LOCAL_EDITED.equals(comment.getStatusEnum()) ? View.VISIBLE : View.GONE); TooltipCompat.setTooltipText(binding.creationDateTime, comment.getComment().getCreationDateTime().atZone(ZoneId.systemDefault()).format(dateFormatter)); - setupMentions(account, comment.getComment().getMentions(), binding.message); + setupMentions(account, binding.message.getContext(), comment.getComment().getMessage(), comment.getComment().getMentions(), this.binding.message); if (comment.getParent() == null) { binding.parentContainer.setVisibility(View.GONE); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java index c82ed654a..1422620a7 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java @@ -35,7 +35,6 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; -import it.niedermann.android.markdown.MarkdownEditor; import it.niedermann.android.util.ColorUtil; import it.niedermann.android.util.DimensionUtil; import it.niedermann.nextcloud.deck.DeckLog; @@ -70,7 +69,6 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM); private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT); private AppCompatActivity activity; - private MarkdownEditor description; @Override public void onAttach(@NonNull Context context) { @@ -91,7 +89,6 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis ViewGroup container, Bundle savedInstanceState) { binding = FragmentCardEditTabDetailsBinding.inflate(inflater, container, false); - this.description = binding.description; viewModel = new ViewModelProvider(activity).get(EditCardViewModel.class); // This might be a zombie fragment with an empty EditCardViewModel after Android killed the activity (but not the fragment instance @@ -103,8 +100,7 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis syncManager = new SyncManager(requireContext()); - @Px - final int avatarSize = DimensionUtil.INSTANCE.dpToPx(requireContext(), R.dimen.avatar_size); + @Px final int avatarSize = DimensionUtil.INSTANCE.dpToPx(requireContext(), R.dimen.avatar_size); final LinearLayout.LayoutParams avatarLayoutParams = new LinearLayout.LayoutParams(avatarSize, avatarSize); avatarLayoutParams.setMargins(0, 0, DimensionUtil.INSTANCE.dpToPx(requireContext(), R.dimen.spacer_1x), 0); @@ -113,7 +109,6 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis setupDueDate(); setupDescription(); setupProjects(); - description.setMarkdownString(viewModel.getFullCard().getCard().getDescription()); return binding.getRoot(); } @@ -143,14 +138,17 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis } private void setupDescription() { + binding.description.setMarkdownString(viewModel.getFullCard().getCard().getDescription()); if (viewModel.canEdit()) { - description.setTextChangedListener((newText) -> { + binding.description.getMarkdownString().observe(getViewLifecycleOwner(), (newText) -> { if (viewModel.getFullCard() != null) { - viewModel.getFullCard().getCard().setDescription(newText); + viewModel.getFullCard().getCard().setDescription(newText == null ? "" : newText.toString()); + } else { + DeckLog.logError(new IllegalStateException("FullCard was empty when trying to setup description")); } }); } else { - description.setEnabled(false); + binding.description.setEnabled(false); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java index c7870ddd7..ffc06e33d 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java @@ -98,11 +98,10 @@ public final class ViewUtil { * * @param account {@link Account} where the users of those mentions belong to * @param mentions {@link List} of all mentions that should be substituted - * @param textView target {@link TextView} + * @param target target {@link TextView} */ - public static void setupMentions(@NonNull Account account, @NonNull List<Mention> mentions, MarkdownEditor textView) { - Context context = textView.getContext(); - SpannableStringBuilder messageBuilder = new SpannableStringBuilder(textView.getText()); + public static void setupMentions(@NonNull Account account, @NonNull Context context, String text, @NonNull List<Mention> mentions, MarkdownEditor target) { + SpannableStringBuilder messageBuilder = new SpannableStringBuilder(text); // Step 1 // Add avatar icons and display names @@ -116,7 +115,7 @@ public final class ViewUtil { index = messageBuilder.toString().substring(0, index).lastIndexOf(mentionId); } } - textView.setMarkdownString(messageBuilder); + target.setMarkdownString(messageBuilder); // Step 2 // Replace avatar icons with real avatars @@ -142,7 +141,7 @@ public final class ViewUtil { } }); } - textView.setMarkdownString(messageBuilder); + target.setMarkdownString(messageBuilder); } public static void setImageColor(@NonNull Context context, @NonNull ImageView imageView, @ColorRes int colorRes) { diff --git a/app/src/main/res/layout/fragment_card_edit_tab_details.xml b/app/src/main/res/layout/fragment_card_edit_tab_details.xml index 2a178570a..8aaabf475 100644 --- a/app/src/main/res/layout/fragment_card_edit_tab_details.xml +++ b/app/src/main/res/layout/fragment_card_edit_tab_details.xml @@ -130,7 +130,7 @@ app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" tools:listitem="@tools:sample/avatars" /> - <it.niedermann.android.markdown.MarkwonMarkdownEditor + <it.niedermann.android.markdown.MarkdownEditorImpl android:id="@+id/description" android:layout_width="match_parent" android:layout_height="wrap_content" /> diff --git a/app/src/main/res/layout/item_comment.xml b/app/src/main/res/layout/item_comment.xml index 303662a2b..2863699a5 100644 --- a/app/src/main/res/layout/item_comment.xml +++ b/app/src/main/res/layout/item_comment.xml @@ -94,7 +94,7 @@ tools:text="@tools:sample/date/day_of_week" /> </LinearLayout> - <it.niedermann.android.markdown.MarkwonMarkdownViewer + <it.niedermann.android.markdown.MarkdownViewerImpl android:id="@+id/message" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/markdown/build.gradle b/markdown/build.gradle index dc4f065ec..f5c805dfb 100644 --- a/markdown/build.gradle +++ b/markdown/build.gradle @@ -31,6 +31,7 @@ android { dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' + implementation "androidx.lifecycle:lifecycle-livedata:2.2.0" implementation "io.noties.markwon:core:4.6.0" implementation "io.noties.markwon:editor:4.6.0" diff --git a/markdown/src/main/java/it/niedermann/android/markdown/AbstractMarkdownEditor.java b/markdown/src/main/java/it/niedermann/android/markdown/AbstractMarkdownEditor.java new file mode 100644 index 000000000..08f5e2a43 --- /dev/null +++ b/markdown/src/main/java/it/niedermann/android/markdown/AbstractMarkdownEditor.java @@ -0,0 +1,52 @@ +package it.niedermann.android.markdown; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; +import androidx.lifecycle.LiveData; + +@RestrictTo(value = RestrictTo.Scope.LIBRARY) +public abstract class AbstractMarkdownEditor<T extends View & MarkdownEditor> extends FrameLayout implements MarkdownEditor { + private MarkdownEditor editor; + + + public AbstractMarkdownEditor(@NonNull Context context, T impl) { + super(context); + init(impl); + } + + public AbstractMarkdownEditor(@NonNull Context context, @Nullable AttributeSet attrs, T impl) { + super(context, attrs); + init(impl); + } + + public AbstractMarkdownEditor(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, T impl) { + super(context, attrs, defStyleAttr); + init(impl); + } + + private void init(T markdownEditor) { + this.editor = markdownEditor; + addView(markdownEditor); + } + + @Override + public void setMarkdownString(CharSequence text) { + editor.setMarkdownString(text); + } + + @Override + public LiveData<CharSequence> getMarkdownString() { + return editor.getMarkdownString(); + } + + @Override + public void setEnabled(boolean enabled) { + editor.setEnabled(enabled); + } +} diff --git a/markdown/src/main/java/it/niedermann/android/markdown/WebViewMarkdownEditor.java b/markdown/src/main/java/it/niedermann/android/markdown/AbstractWebViewMarkdownEditor.java index ab8dfe187..4238a4ff0 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/WebViewMarkdownEditor.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/AbstractWebViewMarkdownEditor.java @@ -2,7 +2,6 @@ package it.niedermann.android.markdown; import android.annotation.SuppressLint; import android.content.Context; -import android.os.Build; import android.util.AttributeSet; import android.webkit.JavascriptInterface; import android.webkit.WebView; @@ -10,41 +9,35 @@ import android.webkit.WebViewClient; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; -import androidx.core.util.Consumer; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import static androidx.lifecycle.Transformations.distinctUntilChanged; @RestrictTo(value = RestrictTo.Scope.LIBRARY) -abstract class WebViewMarkdownEditor extends WebView implements MarkdownEditor { +public abstract class AbstractWebViewMarkdownEditor extends WebView implements MarkdownEditor { + private final MutableLiveData<CharSequence> lastText$ = new MutableLiveData<>(); protected boolean pageFinished = false; protected CharSequence textToSetOnPageFinished; protected boolean enabledStateOnPageFinished = true; - @Nullable - protected Consumer<String> listener; - private CharSequence lastText = ""; - public WebViewMarkdownEditor(@NonNull Context context) { + public AbstractWebViewMarkdownEditor(@NonNull Context context) { super(context); init(); } - public WebViewMarkdownEditor(@NonNull Context context, @Nullable AttributeSet attrs) { + public AbstractWebViewMarkdownEditor(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } - public WebViewMarkdownEditor(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + public AbstractWebViewMarkdownEditor(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public WebViewMarkdownEditor(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - init(); - } - @SuppressLint({"SetJavaScriptEnabled", "JavascriptInterface"}) private void init() { getSettings().setJavaScriptEnabled(true); @@ -64,26 +57,17 @@ abstract class WebViewMarkdownEditor extends WebView implements MarkdownEditor { abstract protected String getUrlToIndex(); @Override - public CharSequence getText() { - return lastText; - } - - @Override public void setMarkdownString(CharSequence textToSetOnPageFinished) { if (pageFinished) { final String escapedText = this.textToSetOnPageFinished == null ? "" : this.textToSetOnPageFinished.toString().replace("`", "\\`"); evaluateJavascript("setText(`" + escapedText + "`);", null); + lastText$.setValue(this.textToSetOnPageFinished); } else { this.textToSetOnPageFinished = textToSetOnPageFinished; } } @Override - public void setTextChangedListener(@Nullable Consumer<String> listener) { - this.listener = listener; - } - - @Override public void setEnabled(boolean enabled) { if (pageFinished) { evaluateJavascript("setEnabled(" + this.enabledStateOnPageFinished + ");", null); @@ -92,11 +76,14 @@ abstract class WebViewMarkdownEditor extends WebView implements MarkdownEditor { } } + @Override + public LiveData<CharSequence> getMarkdownString() { + return distinctUntilChanged(lastText$); + } + + @RestrictTo(RestrictTo.Scope.SUBCLASSES) @JavascriptInterface public void onTextChanged(String newText) { - if (this.listener != null) { - this.listener.accept(newText); - } - lastText = newText; + lastText$.setValue(newText); } } 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 80ec36ede..df20dcf2b 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/MarkdownEditor.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/MarkdownEditor.java @@ -1,9 +1,6 @@ package it.niedermann.android.markdown; -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.core.util.Consumer; +import androidx.lifecycle.LiveData; /** * Can be used for editors and viewers as well. @@ -12,21 +9,14 @@ import androidx.core.util.Consumer; public interface MarkdownEditor { /** - * The given {@link CharSequence} will be parsed and rendered + * The given {@link String} will be parsed and rendered */ void setMarkdownString(CharSequence text); /** - * @return the source {@link CharSequence} of the currently rendered markdown - */ - CharSequence getText(); - - Context getContext(); - - /** - * @param listener will be notified when something changed from within the current {@link MarkdownEditor} + * @return the source {@link String} of the currently rendered markdown */ - void setTextChangedListener(@NonNull Consumer<String> listener); + LiveData<CharSequence> getMarkdownString(); void setEnabled(boolean enabled); }
\ No newline at end of file diff --git a/markdown/src/main/java/it/niedermann/android/markdown/MarkdownEditorImpl.java b/markdown/src/main/java/it/niedermann/android/markdown/MarkdownEditorImpl.java new file mode 100644 index 000000000..10c7eee53 --- /dev/null +++ b/markdown/src/main/java/it/niedermann/android/markdown/MarkdownEditorImpl.java @@ -0,0 +1,24 @@ +package it.niedermann.android.markdown; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import it.niedermann.android.markdown.markwon.MarkwonMarkdownEditor; + +public class MarkdownEditorImpl extends AbstractMarkdownEditor<MarkwonMarkdownEditor> { + + public MarkdownEditorImpl(@NonNull Context context) { + super(context, new MarkwonMarkdownEditor(context)); + } + + public MarkdownEditorImpl(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs, new MarkwonMarkdownEditor(context, attrs)); + } + + public MarkdownEditorImpl(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr, new MarkwonMarkdownEditor(context, attrs, defStyleAttr)); + } +} diff --git a/markdown/src/main/java/it/niedermann/android/markdown/MarkdownViewerImpl.java b/markdown/src/main/java/it/niedermann/android/markdown/MarkdownViewerImpl.java new file mode 100644 index 000000000..534161384 --- /dev/null +++ b/markdown/src/main/java/it/niedermann/android/markdown/MarkdownViewerImpl.java @@ -0,0 +1,24 @@ +package it.niedermann.android.markdown; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import it.niedermann.android.markdown.markwon.MarkwonMarkdownViewer; + +public class MarkdownViewerImpl extends AbstractMarkdownEditor<MarkwonMarkdownViewer> { + + public MarkdownViewerImpl(@NonNull Context context) { + super(context, new MarkwonMarkdownViewer(context)); + } + + public MarkdownViewerImpl(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs, new MarkwonMarkdownViewer(context, attrs)); + } + + public MarkdownViewerImpl(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr, new MarkwonMarkdownViewer(context, attrs, defStyleAttr)); + } +} diff --git a/markdown/src/main/java/it/niedermann/android/markdown/MarkwonMarkdownViewer.java b/markdown/src/main/java/it/niedermann/android/markdown/MarkwonMarkdownViewer.java deleted file mode 100644 index 2e8380e72..000000000 --- a/markdown/src/main/java/it/niedermann/android/markdown/MarkwonMarkdownViewer.java +++ /dev/null @@ -1,74 +0,0 @@ -package it.niedermann.android.markdown; - -import android.content.Context; -import android.text.TextUtils; -import android.util.AttributeSet; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.core.util.Consumer; - -import io.noties.markwon.Markwon; -import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; -import io.noties.markwon.ext.tasklist.TaskListPlugin; -import io.noties.markwon.image.ImagesPlugin; -import io.noties.markwon.image.glide.GlideImagesPlugin; -import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin; -import io.noties.markwon.linkify.LinkifyPlugin; -import io.noties.markwon.simple.ext.SimpleExtPlugin; - -public class MarkwonMarkdownViewer extends AppCompatTextView implements MarkdownEditor { - - private final Markwon markwon; - private CharSequence unrenderedText; - @Nullable - protected Consumer<String> listener; - - public MarkwonMarkdownViewer(@NonNull Context context) { - super(context); - this.markwon = initMarkwon(context); - } - - public MarkwonMarkdownViewer(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - this.markwon = initMarkwon(context); - } - - public MarkwonMarkdownViewer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - this.markwon = initMarkwon(context); - } - - private static Markwon initMarkwon(@NonNull Context context) { - return Markwon.builder(context) - .usePlugin(StrikethroughPlugin.create()) - .usePlugin(TaskListPlugin.create(context)) - .usePlugin(ImagesPlugin.create()) - .usePlugin(GlideImagesPlugin.create(context)) - .usePlugin(SimpleExtPlugin.create()) - .usePlugin(MarkwonInlineParserPlugin.create()) - .usePlugin(LinkifyPlugin.create()) - .build(); - } - - @Override - public void setMarkdownString(CharSequence text) { - unrenderedText = text; - if (TextUtils.isEmpty(text)) { - setText(text); - } else { - markwon.setMarkdown(this, text.toString()); - } - } - - @Override - public CharSequence getText() { - return unrenderedText; - } - - @Override - public void setTextChangedListener(@NonNull Consumer<String> listener) { - this.listener = listener; - } -} diff --git a/markdown/src/main/java/it/niedermann/android/markdown/MarkwonMarkdownEditor.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownEditor.java index 064fe5201..92af0ea79 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/MarkwonMarkdownEditor.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownEditor.java @@ -1,4 +1,4 @@ -package it.niedermann.android.markdown; +package it.niedermann.android.markdown.markwon; import android.content.Context; import android.text.Editable; @@ -8,7 +8,8 @@ import android.util.AttributeSet; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatEditText; -import androidx.core.util.Consumer; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import java.util.concurrent.Executors; @@ -17,24 +18,18 @@ import io.noties.markwon.editor.MarkwonEditor; import io.noties.markwon.editor.MarkwonEditorTextWatcher; import io.noties.markwon.editor.handler.EmphasisEditHandler; import io.noties.markwon.editor.handler.StrongEmphasisEditHandler; -import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; -import io.noties.markwon.ext.tasklist.TaskListPlugin; -import io.noties.markwon.html.HtmlPlugin; -import io.noties.markwon.image.ImagesPlugin; -import io.noties.markwon.image.glide.GlideImagesPlugin; -import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin; -import io.noties.markwon.linkify.LinkifyPlugin; -import io.noties.markwon.simple.ext.SimpleExtPlugin; +import it.niedermann.android.markdown.MarkdownEditor; import it.niedermann.android.markdown.markwon.handler.BlockQuoteEditHandler; 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 static it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil.initMarkwon; + public class MarkwonMarkdownEditor extends AppCompatEditText implements MarkdownEditor { - @Nullable - protected Consumer<String> listener; + private final MutableLiveData<CharSequence> unrenderedText$ = new MutableLiveData<>(); public MarkwonMarkdownEditor(@NonNull Context context) { super(context); @@ -52,16 +47,7 @@ public class MarkwonMarkdownEditor extends AppCompatEditText implements Markdown } private void init(@NonNull Context context) { - final Markwon markwon = Markwon.builder(context) - .usePlugin(StrikethroughPlugin.create()) - .usePlugin(TaskListPlugin.create(context)) - .usePlugin(HtmlPlugin.create()) - .usePlugin(ImagesPlugin.create()) - .usePlugin(GlideImagesPlugin.create(context)) - .usePlugin(SimpleExtPlugin.create()) - .usePlugin(MarkwonInlineParserPlugin.create()) - .usePlugin(LinkifyPlugin.create()) - .build(); + final Markwon markwon = initMarkwon(context); final MarkwonEditor editor = MarkwonEditor.builder(markwon) .useEditHandler(new EmphasisEditHandler()) .useEditHandler(new StrongEmphasisEditHandler()) @@ -80,9 +66,7 @@ public class MarkwonMarkdownEditor extends AppCompatEditText implements Markdown @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - if (listener != null) { - listener.accept(s.toString()); - } + unrenderedText$.setValue(s.toString()); } @Override @@ -98,8 +82,7 @@ public class MarkwonMarkdownEditor extends AppCompatEditText implements Markdown } @Override - public void setTextChangedListener(@NonNull Consumer<String> listener) { - this.listener = listener; + public LiveData<CharSequence> getMarkdownString() { + return unrenderedText$; } - } 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 new file mode 100644 index 000000000..d31230e01 --- /dev/null +++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java @@ -0,0 +1,37 @@ +package it.niedermann.android.markdown.markwon; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; + +import io.noties.markwon.Markwon; +import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; +import io.noties.markwon.ext.tasklist.TaskListPlugin; +import io.noties.markwon.image.ImagesPlugin; +import io.noties.markwon.image.glide.GlideImagesPlugin; +import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin; +import io.noties.markwon.linkify.LinkifyPlugin; +import io.noties.markwon.simple.ext.SimpleExtPlugin; + +/** + * Created by stefan on 07.12.16. + */ +@RestrictTo(value = RestrictTo.Scope.LIBRARY) +public class MarkwonMarkdownUtil { + + private MarkwonMarkdownUtil() { + } + + public static Markwon initMarkwon(@NonNull Context context) { + return Markwon.builder(context) + .usePlugin(StrikethroughPlugin.create()) + .usePlugin(TaskListPlugin.create(context)) + .usePlugin(ImagesPlugin.create()) + .usePlugin(GlideImagesPlugin.create(context)) + .usePlugin(SimpleExtPlugin.create()) + .usePlugin(MarkwonInlineParserPlugin.create()) + .usePlugin(LinkifyPlugin.create()) + .build(); + } +} 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 new file mode 100644 index 000000000..c256c9ab3 --- /dev/null +++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownViewer.java @@ -0,0 +1,53 @@ +package it.niedermann.android.markdown.markwon; + +import android.content.Context; +import android.text.TextUtils; +import android.util.AttributeSet; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import io.noties.markwon.Markwon; +import it.niedermann.android.markdown.MarkdownEditor; + +import static androidx.lifecycle.Transformations.distinctUntilChanged; +import static it.niedermann.android.markdown.markwon.MarkwonMarkdownUtil.initMarkwon; + +public class MarkwonMarkdownViewer extends AppCompatTextView implements MarkdownEditor { + + private final Markwon markwon; + private final MutableLiveData<CharSequence> unrenderedText$ = new MutableLiveData<>(); + + public MarkwonMarkdownViewer(@NonNull Context context) { + super(context); + this.markwon = initMarkwon(context); + } + + public MarkwonMarkdownViewer(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + this.markwon = initMarkwon(context); + } + + public MarkwonMarkdownViewer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + this.markwon = initMarkwon(context); + } + + @Override + public void setMarkdownString(CharSequence text) { + unrenderedText$.setValue(text); + if (TextUtils.isEmpty(text)) { + setText(text); + } else { + markwon.setMarkdown(this, text.toString()); + } + } + + @Override + public LiveData<CharSequence> getMarkdownString() { + return distinctUntilChanged(unrenderedText$); + } +} diff --git a/markdown/src/main/java/it/niedermann/android/markdown/ProseMirrorMarkdownEditor.java b/markdown/src/main/java/it/niedermann/android/markdown/prosemirror/ProseMirrorMarkdownEditor.java index 4aec77786..68ddaf1ec 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/ProseMirrorMarkdownEditor.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/prosemirror/ProseMirrorMarkdownEditor.java @@ -1,4 +1,4 @@ -package it.niedermann.android.markdown; +package it.niedermann.android.markdown.prosemirror; import android.content.Context; import android.util.AttributeSet; @@ -6,7 +6,10 @@ import android.util.AttributeSet; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -public class ProseMirrorMarkdownEditor extends WebViewMarkdownEditor { +import it.niedermann.android.markdown.AbstractWebViewMarkdownEditor; + +@Deprecated +public class ProseMirrorMarkdownEditor extends AbstractWebViewMarkdownEditor { public ProseMirrorMarkdownEditor(@NonNull Context context) { super(context); diff --git a/markdown/src/main/java/it/niedermann/android/markdown/ProseMirrorMarkdownViewer.java b/markdown/src/main/java/it/niedermann/android/markdown/prosemirror/ProseMirrorMarkdownViewer.java index ac4b8779a..ae2e04cfe 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/ProseMirrorMarkdownViewer.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/prosemirror/ProseMirrorMarkdownViewer.java @@ -1,4 +1,4 @@ -package it.niedermann.android.markdown; +package it.niedermann.android.markdown.prosemirror; import android.content.Context; import android.util.AttributeSet; @@ -6,7 +6,10 @@ import android.util.AttributeSet; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -public class ProseMirrorMarkdownViewer extends WebViewMarkdownEditor { +import it.niedermann.android.markdown.AbstractWebViewMarkdownEditor; + +@Deprecated +public class ProseMirrorMarkdownViewer extends AbstractWebViewMarkdownEditor { public ProseMirrorMarkdownViewer(@NonNull Context context) { super(context); diff --git a/markdown/src/main/java/it/niedermann/android/markdown/RxMarkdownEditor.java b/markdown/src/main/java/it/niedermann/android/markdown/rxmarkdown/RxMarkdownEditor.java index 2d17d5600..664ac1268 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/RxMarkdownEditor.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/rxmarkdown/RxMarkdownEditor.java @@ -1,4 +1,4 @@ -package it.niedermann.android.markdown; +package it.niedermann.android.markdown.rxmarkdown; import android.content.Context; import android.text.Editable; @@ -6,20 +6,23 @@ import android.text.TextWatcher; import android.util.AttributeSet; import android.widget.FrameLayout; -import androidx.annotation.NonNull; -import androidx.core.util.Consumer; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import com.yydcdut.markdown.MarkdownEditText; import com.yydcdut.markdown.MarkdownProcessor; import com.yydcdut.markdown.syntax.edit.EditFactory; -import it.niedermann.android.markdown.rxmarkdown.MarkDownUtil; +import it.niedermann.android.markdown.MarkdownEditor; +import static androidx.lifecycle.Transformations.distinctUntilChanged; + +@Deprecated public class RxMarkdownEditor extends FrameLayout implements MarkdownEditor { + private final MutableLiveData<CharSequence> unrenderedText$ = new MutableLiveData<>(); private MarkdownProcessor markdownProcessor; private final MarkdownEditText editText; - private Consumer<String> listener; public RxMarkdownEditor(Context context) { super(context); @@ -42,7 +45,7 @@ public class RxMarkdownEditor extends FrameLayout implements MarkdownEditor { private void init(Context context) { addView(editText); markdownProcessor = new MarkdownProcessor(context); - markdownProcessor.config(MarkDownUtil.getMarkDownConfiguration(context).build()); + markdownProcessor.config(RxMarkdownUtil.getMarkDownConfiguration(context).build()); markdownProcessor.factory(EditFactory.create()); markdownProcessor.live(editText); editText.addTextChangedListener(new TextWatcher() { @@ -53,8 +56,7 @@ public class RxMarkdownEditor extends FrameLayout implements MarkdownEditor { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - final CharSequence text = getText(); - listener.accept(text == null ? null : text.toString()); + unrenderedText$.setValue(s.toString()); } @Override @@ -70,12 +72,7 @@ public class RxMarkdownEditor extends FrameLayout implements MarkdownEditor { } @Override - public CharSequence getText() { - return editText.getText(); - } - - @Override - public void setTextChangedListener(@NonNull Consumer<String> listener) { - this.listener = listener; + public LiveData<CharSequence> getMarkdownString() { + return distinctUntilChanged(unrenderedText$); } } diff --git a/markdown/src/main/java/it/niedermann/android/markdown/rxmarkdown/MarkDownUtil.java b/markdown/src/main/java/it/niedermann/android/markdown/rxmarkdown/RxMarkdownUtil.java index 0c119c1af..16c1652a0 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/rxmarkdown/MarkDownUtil.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/rxmarkdown/RxMarkdownUtil.java @@ -9,10 +9,11 @@ import com.yydcdut.rxmarkdown.RxMDConfiguration.Builder; /** * Created by stefan on 07.12.16. */ +@Deprecated @RestrictTo(value = RestrictTo.Scope.LIBRARY) -public class MarkDownUtil { +public class RxMarkdownUtil { - private MarkDownUtil() { + private RxMarkdownUtil() { } /** diff --git a/markdown/src/main/java/it/niedermann/android/markdown/RxMarkdownViewer.java b/markdown/src/main/java/it/niedermann/android/markdown/rxmarkdown/RxMarkdownViewer.java index 1b80e5d89..47c6486f1 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/RxMarkdownViewer.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/rxmarkdown/RxMarkdownViewer.java @@ -1,18 +1,19 @@ -package it.niedermann.android.markdown; +package it.niedermann.android.markdown.rxmarkdown; import android.content.Context; import android.util.AttributeSet; import android.widget.FrameLayout; -import androidx.annotation.NonNull; -import androidx.core.util.Consumer; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import com.yydcdut.markdown.MarkdownProcessor; import com.yydcdut.markdown.MarkdownTextView; import com.yydcdut.markdown.syntax.text.TextFactory; -import it.niedermann.android.markdown.rxmarkdown.MarkDownUtil; +import it.niedermann.android.markdown.MarkdownEditor; +@Deprecated public class RxMarkdownViewer extends FrameLayout implements MarkdownEditor { private MarkdownProcessor markdownProcessor; @@ -39,7 +40,7 @@ public class RxMarkdownViewer extends FrameLayout implements MarkdownEditor { private void init(Context context) { addView(textView); markdownProcessor = new MarkdownProcessor(context); - markdownProcessor.config(MarkDownUtil.getMarkDownConfiguration(context).build()); + markdownProcessor.config(RxMarkdownUtil.getMarkDownConfiguration(context).build()); markdownProcessor.factory(TextFactory.create()); } @@ -49,12 +50,7 @@ public class RxMarkdownViewer extends FrameLayout implements MarkdownEditor { } @Override - public CharSequence getText() { - return textView.getText(); - } - - @Override - public void setTextChangedListener(@NonNull Consumer<String> listener) { - // Nothing + public LiveData<CharSequence> getMarkdownString() { + return new MutableLiveData<>(); } } diff --git a/markdown/src/main/java/it/niedermann/android/markdown/SimpleMDEMarkdownEditor.java b/markdown/src/main/java/it/niedermann/android/markdown/simplemde/SimpleMDEMarkdownEditor.java index e8c575ce2..6d1c378c2 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/SimpleMDEMarkdownEditor.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/simplemde/SimpleMDEMarkdownEditor.java @@ -1,4 +1,4 @@ -package it.niedermann.android.markdown; +package it.niedermann.android.markdown.simplemde; import android.content.Context; import android.util.AttributeSet; @@ -6,7 +6,11 @@ import android.util.AttributeSet; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -public class SimpleMDEMarkdownEditor extends WebViewMarkdownEditor implements MarkdownEditor { +import it.niedermann.android.markdown.AbstractWebViewMarkdownEditor; +import it.niedermann.android.markdown.MarkdownEditor; + +@Deprecated +public class SimpleMDEMarkdownEditor extends AbstractWebViewMarkdownEditor implements MarkdownEditor { public SimpleMDEMarkdownEditor(@NonNull Context context) { super(context); diff --git a/markdown/src/main/java/it/niedermann/android/markdown/SimpleMDEMarkdownViewer.java b/markdown/src/main/java/it/niedermann/android/markdown/simplemde/SimpleMDEMarkdownViewer.java index e73364094..5f0b9a3d3 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/SimpleMDEMarkdownViewer.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/simplemde/SimpleMDEMarkdownViewer.java @@ -1,4 +1,4 @@ -package it.niedermann.android.markdown; +package it.niedermann.android.markdown.simplemde; import android.content.Context; import android.util.AttributeSet; @@ -6,7 +6,11 @@ import android.util.AttributeSet; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -public class SimpleMDEMarkdownViewer extends WebViewMarkdownEditor implements MarkdownEditor { +import it.niedermann.android.markdown.AbstractWebViewMarkdownEditor; +import it.niedermann.android.markdown.MarkdownEditor; + +@Deprecated +public class SimpleMDEMarkdownViewer extends AbstractWebViewMarkdownEditor implements MarkdownEditor { public SimpleMDEMarkdownViewer(@NonNull Context context) { super(context); |