Markwon icon indicating copy to clipboard operation
Markwon copied to clipboard

Markwon silently fails to show any image in TextView

Open Mek101 opened this issue 4 years ago • 4 comments

  • Markwon version: 4.6.2

I'm giving my try to a WYSIWYG Markdown editor. Following the mvvm architecture I decopulated the markdown renderer from the UI fragment and re-implemented part of MarkwonEditorTextWatcher to use Kotlin coroutines in order to render the markdown on a background thread; then following your original implementation, I send the PreRenderResult back to the UI and update the TextView with the following lambda:

// Register to receive the rendering results
// I use MutableLiveData.postValue to call this here, which queues the callback into the main thread loop
editorViewModel.editableData.observe(this.viewLifecycleOwner) { result ->
    if (result !== null && binding !== null) {
        // editorText is a androidx.appcompat.widget.AppCompatEditText
        binding?.editorText?.post {
            binding?.editorText?.text?.let {
                selfChange = true
                // The text editor starts with 0 spans. `dispatchTo` sets them immediately
                // by index, causing an OutOfRange exception.
                if (it.length < result.resultEditable().length) {
                    binding!!.editorText.text = result.resultEditable()
                } else {
                    result.dispatchTo(it)
                }
                selfChange = false
            }
        }
    }
}

And since I use SAF, I implemented a custom scheme handler for android's content uirs:

class ContentUriSchemeHandler(private val application: Application): SchemeHandler() {

    override fun handle(raw: String, uri: Uri): ImageItem {
        if (uri.scheme != SCHEME) {
            throw IllegalArgumentException("Invalid scheme ${uri.scheme}")
        }

        Log.i(ContentUriSchemeHandler::class.simpleName, "Handling $uri")

        val stream = application.contentResolver.openInputStream(uri)
        val drawable = Drawable.createFromStream(stream, uri.toString())
        return ImageItem.withResult(drawable)
    }

    override fun supportedSchemes(): Collection<String> = Collections.singleton("content")

    companion object {
        const val SCHEME = "content"
    }
}

While the Markwon and MarkwonEditor instances are built in the following manner:

val markwon = Markwon.builder(application.applicationContext)
            .usePlugin(SoftBreakAddsNewLinePlugin.create())
            .usePlugin(ImagesPlugin.create {
                it.errorHandler(imageErrorHandlerImpl)
                it.placeholderProvider(imagePlaceholderImpl)
                it.addSchemeHandler(ContentUriSchemeHandler(application))
                it.addSchemeHandler(NetworkSchemeHandler.create())
            })
            .build()
return MarkwonEditor.builder(markwon)
            .punctuationSpan(
                HidePunctuationSpan::class.java
            ) { HidePunctuationSpan() }
            .useEditHandler(EmphasisEditHandler())
            .useEditHandler(StrongEmphasisEditHandler())
            .useEditHandler(StrikethroughEditHandler())
            .useEditHandler(CodeEditHandler())
            .useEditHandler(BlockQuoteEditHandler())
            .useEditHandler(LinkEditHandler { widget, link ->
                linkListener?.invoke(widget, link)
            })
            .useEditHandler(HeadingEditHandler())
            .build()
    }

The problem is that in the end result no image is shown. Adding Log.i() to the various callbacks show that neither the error handler, the place holder provider or the scheme handler are ever called.

The markdown I used to test:

![Local Image](./image.jpg)    // Kinda expected this not to work out of the box with SAF
![Remote Image](https://i.redd.it/yssl1fdzvzy71.jpg)    // Trouble is, this also doesn't work

I already added the internet permissions

Sorry If I've been a bit verbose but I'm not sure if using a different thread for rendering influences the image rendering or they also somehow depend on the rest of the library's architecture(?)

Mek101 avatar Dec 01 '21 16:12 Mek101

Hello @Mek101 ,

you would need to use an edit handler for the image span. But it looks like an edit handler for image won't be possible because of current limitations. The same limitations are applied to tables and latex and come from the fact that they are not represented as text when displayed in a TextView.

noties avatar Dec 06 '21 11:12 noties

So I would need some kind of custom spannable?

Mek101 avatar Dec 06 '21 22:12 Mek101

Well, it would be nessesary for a few things more.

  • a specific spannable for editor
  • special handler for this span, but as edit handler processes text of a TextView (instead of markdown):
    • change of image span, that would be reflected in a TextView (right now images are just an empty spaces )
  • a change to actual edit handlers as they are designed to be reused and do not hold any specific arguments (like an URL for an image)

noties avatar Dec 06 '21 23:12 noties

come from the fact that they are not represented as text when displayed in a TextView.

If markwon uses ImageSpan, then couldn't it simply call getSource() on it to retrieve the text from the span? I'm not sure if I understand the roadblock

Mek101 avatar Dec 12 '21 17:12 Mek101