Reply with formatted content

This commit is contained in:
Benoit Marty 2019-07-10 11:29:47 +02:00
parent 92e3a02389
commit 1918302297
5 changed files with 35 additions and 26 deletions

View File

@ -77,8 +77,9 @@ interface RelationService {
* https://matrix.org/docs/spec/client_server/r0.4.0.html#id350
* @param eventReplied the event referenced by the reply
* @param replyText the reply text
* @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present
*/
fun replyToMessage(eventReplied: Event, replyText: String): Cancelable?
fun replyToMessage(eventReplied: Event, replyText: String, autoMarkdown: Boolean = false): Cancelable?
fun getEventSummaryLive(eventId: String): LiveData<EventAnnotationsSummary>
}

View File

@ -127,8 +127,8 @@ internal class DefaultRelationService @Inject constructor(private val context: C
}
override fun replyToMessage(eventReplied: Event, replyText: String): Cancelable? {
val event = eventFactory.createReplyTextEvent(roomId, eventReplied, replyText)?.also {
override fun replyToMessage(eventReplied: Event, replyText: String, autoMarkdown: Boolean): Cancelable? {
val event = eventFactory.createReplyTextEvent(roomId, eventReplied, replyText, autoMarkdown)?.also {
saveLocalEcho(it)
} ?: return null

View File

@ -59,7 +59,7 @@ internal class DefaultSendService @Inject constructor(private val context: Conte
}
override fun sendFormattedTextMessage(text: String, formattedText: String): Cancelable {
val event = localEchoEventFactory.createFormattedTextEvent(roomId, text, formattedText).also {
val event = localEchoEventFactory.createFormattedTextEvent(roomId, TextContent(text, formattedText)).also {
saveLocalEcho(it)
}

View File

@ -52,30 +52,41 @@ import javax.inject.Inject
internal class LocalEchoEventFactory @Inject constructor(private val credentials: Credentials,
private val stringProvider: StringProvider,
private val roomSummaryUpdater: RoomSummaryUpdater) {
// TODO Inject
private val parser = Parser.builder().build()
// TODO Inject
private val renderer = HtmlRenderer.builder().build()
fun createTextEvent(roomId: String, msgType: String, text: String, autoMarkdown: Boolean): Event {
if (autoMarkdown && msgType == MessageType.MSGTYPE_TEXT) {
val parser = Parser.builder().build()
val document = parser.parse(text)
val renderer = HtmlRenderer.builder().build()
val htmlText = renderer.render(document)
if (isFormattedTextPertinent(text, htmlText)) { //FIXME
return createFormattedTextEvent(roomId, text, htmlText)
}
if (msgType == MessageType.MSGTYPE_TEXT) {
return createFormattedTextEvent(roomId, createTextContent(text, autoMarkdown))
}
val content = MessageTextContent(type = msgType, body = text)
return createEvent(roomId, content)
}
private fun createTextContent(text: String, autoMarkdown: Boolean): TextContent {
if (autoMarkdown) {
val document = parser.parse(text)
val htmlText = renderer.render(document)
if (isFormattedTextPertinent(text, htmlText)) {
return TextContent(text, htmlText)
}
}
return TextContent(text)
}
private fun isFormattedTextPertinent(text: String, htmlText: String?) =
text != htmlText && htmlText != "<p>${text.trim()}</p>\n"
fun createFormattedTextEvent(roomId: String, text: String, formattedText: String): Event {
fun createFormattedTextEvent(roomId: String, textContent: TextContent): Event {
val content = MessageTextContent(
type = MessageType.MSGTYPE_TEXT,
format = MessageType.FORMAT_MATRIX_HTML,
body = text,
formattedBody = formattedText
format = if (textContent.formattedText == null) MessageType.FORMAT_MATRIX_HTML else null,
body = textContent.text,
formattedBody = textContent.formattedText
)
return createEvent(roomId, content)
}
@ -87,7 +98,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
newBodyAutoMarkdown: Boolean,
msgType: String,
compatibilityText: String): Event {
// TODO Format newBodyText
var newContent = MessageTextContent(
type = MessageType.MSGTYPE_TEXT,
body = newBodyText
@ -202,7 +213,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
type = MessageType.MSGTYPE_AUDIO,
body = attachment.name ?: "audio",
audioInfo = AudioInfo(
mimeType = attachment.mimeType ?: "audio/mpeg",
mimeType = attachment.mimeType.takeIf { it.isNotBlank() } ?: "audio/mpeg",
size = attachment.size
),
url = attachment.path
@ -215,7 +226,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
type = MessageType.MSGTYPE_FILE,
body = attachment.name ?: "file",
info = FileInfo(
mimeType = attachment.mimeType ?: "application/octet-stream",
mimeType = attachment.mimeType.takeIf { it.isNotBlank() } ?: "application/octet-stream",
size = attachment.size
),
url = attachment.path
@ -244,7 +255,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
return "$LOCAL_ID_PREFIX${UUID.randomUUID()}"
}
fun createReplyTextEvent(roomId: String, eventReplied: Event, replyText: String): Event? {
fun createReplyTextEvent(roomId: String, eventReplied: Event, replyText: String, autoMarkdown: Boolean): Event? {
//Fallbacks and event representation
//TODO Add error/warning logs when any of this is null
val permalink = PermalinkFactory.createPermalink(eventReplied) ?: return null
@ -266,7 +277,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
userLink,
userId,
body.takeFormatted(),
replyText
createTextContent(replyText, autoMarkdown).takeFormatted()
)
//
// > <@alice:example.org> This is the original body
@ -294,8 +305,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
}
/**
* Returns a pair of <Plain Text, Formatted Text?> used for the fallback event representation
* in a reply message.
* Returns a TextContent used for the fallback event representation in a reply message.
*/
private fun bodyForReply(content: MessageContent?): TextContent {
when (content?.type) {

View File

@ -47,8 +47,6 @@ import im.vector.riotx.core.utils.LiveEvent
import im.vector.riotx.features.command.CommandParser
import im.vector.riotx.features.command.ParsedCommand
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.rxkotlin.subscribeBy
import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer
@ -272,7 +270,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
}
SendMode.REPLY -> {
state.selectedEvent?.let {
room.replyToMessage(it.root, action.text)
room.replyToMessage(it.root, action.text, action.autoMarkdown)
setState {
copy(
sendMode = SendMode.REGULAR,