fix / strip reply prefix on history

This commit is contained in:
Valere 2019-07-15 17:18:31 +02:00
parent 6effb90361
commit d8092abc4e
5 changed files with 67 additions and 31 deletions

View File

@ -2,11 +2,12 @@ Changes in RiotX 0.2.1 (2019-XX-XX)
=================================================== ===================================================
Features: Features:
- Message Editing: View edit history - Message Editing: View edit history (#121)
- Rooms filtering (#304) - Rooms filtering (#304)
Improvements: Improvements:
- Handle click on redacted events: view source and create permalink - Handle click on redacted events: view source and create permalink
- Improve edit of replies
Other changes: Other changes:
- -

View File

@ -0,0 +1,45 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.util
object ContentUtils {
fun extractUsefulTextFromReply(repliedBody: String): String {
val lines = repliedBody.lines()
var wellFormed = repliedBody.startsWith(">")
var endOfPreviousFound = false
val usefullines = ArrayList<String>()
lines.forEach {
if (it == "") {
endOfPreviousFound = true
return@forEach
}
if (!endOfPreviousFound) {
wellFormed = wellFormed && it.startsWith(">")
} else {
usefullines.add(it)
}
}
return usefullines.joinToString("\n").takeIf { wellFormed } ?: repliedBody
}
fun extractUsefulTextFromHtmlReply(repliedBody: String): String {
if (repliedBody.startsWith("<mx-reply>")) {
return repliedBody.substring(repliedBody.lastIndexOf("</mx-reply>") + "</mx-reply>".length).trim()
}
return repliedBody
}
}

View File

@ -18,6 +18,8 @@ package im.vector.matrix.android.internal.session.room.send
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
import im.vector.matrix.android.api.session.room.model.message.MessageType import im.vector.matrix.android.api.session.room.model.message.MessageType
import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromHtmlReply
import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromReply
/** /**
* Contains a text and eventually a formatted text * Contains a text and eventually a formatted text
@ -47,28 +49,4 @@ fun TextContent.removeInReplyFallbacks(): TextContent {
) )
} }
fun extractUsefulTextFromReply(repliedBody: String): String {
val lines = repliedBody.lines()
var wellFormed = repliedBody.startsWith(">")
var endOfPreviousFound = false
val usefullines = ArrayList<String>()
lines.forEach {
if (it == "") {
endOfPreviousFound = true
return@forEach
}
if (!endOfPreviousFound) {
wellFormed = wellFormed && it.startsWith(">")
} else {
usefullines.add(it)
}
}
return usefullines.joinToString("\n").takeIf { wellFormed } ?: repliedBody
}
fun extractUsefulTextFromHtmlReply(repliedBody: String): String {
if (repliedBody.startsWith("<mx-reply>")) {
return repliedBody.substring(repliedBody.lastIndexOf("</mx-reply>") + "</mx-reply>".length).trim()
}
return repliedBody
}

View File

@ -26,6 +26,7 @@ import com.airbnb.mvrx.Success
import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromReply
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.extensions.localDateTime import im.vector.riotx.core.extensions.localDateTime
import im.vector.riotx.core.ui.list.genericFooterItem import im.vector.riotx.core.ui.list.genericFooterItem
@ -60,13 +61,13 @@ class ViewEditHistoryEpoxyController(private val context: Context,
} }
} }
is Success -> { is Success -> {
state.editList()?.let { renderEvents(it) } state.editList()?.let { renderEvents(it, state.isOriginalAReply) }
} }
} }
} }
private fun renderEvents(sourceEvents: List<Event>) { private fun renderEvents(sourceEvents: List<Event>, isOriginalReply: Boolean) {
if (sourceEvents.isEmpty()) { if (sourceEvents.isEmpty()) {
genericItem { genericItem {
id("footer") id("footer")
@ -92,7 +93,7 @@ class ViewEditHistoryEpoxyController(private val context: Context,
} }
} }
lastDate = evDate lastDate = evDate
val cContent = getCorrectContent(timelineEvent) val cContent = getCorrectContent(timelineEvent, isOriginalReply)
val body = cContent.second?.let { eventHtmlRenderer.render(it) } val body = cContent.second?.let { eventHtmlRenderer.render(it) }
?: cContent.first ?: cContent.first
@ -101,7 +102,7 @@ class ViewEditHistoryEpoxyController(private val context: Context,
var spannedDiff: Spannable? = null var spannedDiff: Spannable? = null
if (nextEvent != null && cContent.second == null /*No diff for html*/) { if (nextEvent != null && cContent.second == null /*No diff for html*/) {
//compares the body //compares the body
val nContent = getCorrectContent(nextEvent) val nContent = getCorrectContent(nextEvent, isOriginalReply)
val nextBody = nContent.second?.let { eventHtmlRenderer.render(it) } val nextBody = nContent.second?.let { eventHtmlRenderer.render(it) }
?: nContent.first ?: nContent.first
val dmp = diff_match_patch() val dmp = diff_match_patch()
@ -144,11 +145,14 @@ class ViewEditHistoryEpoxyController(private val context: Context,
} }
} }
private fun getCorrectContent(event: Event): Pair<String, String?> { private fun getCorrectContent(event: Event, isOriginalReply: Boolean): Pair<String, String?> {
val clearContent = event.getClearContent().toModel<MessageTextContent>() val clearContent = event.getClearContent().toModel<MessageTextContent>()
val newContent = clearContent val newContent = clearContent
?.newContent ?.newContent
?.toModel<MessageTextContent>() ?.toModel<MessageTextContent>()
if (isOriginalReply) {
return extractUsefulTextFromReply(newContent?.body ?: clearContent?.body ?: "") to null
}
return (newContent?.body ?: clearContent?.body ?: "") to (newContent?.formattedBody return (newContent?.body ?: clearContent?.body ?: "") to (newContent?.formattedBody
?: clearContent?.formattedBody) ?: clearContent?.formattedBody)
} }

View File

@ -21,6 +21,8 @@ import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.message.MessageContent
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDateFormatter import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDateFormatter
@ -28,6 +30,7 @@ import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDateFor
data class ViewEditHistoryViewState( data class ViewEditHistoryViewState(
val eventId: String, val eventId: String,
val roomId: String, val roomId: String,
val isOriginalAReply: Boolean = false,
val editList: Async<List<Event>> = Uninitialized) val editList: Async<List<Event>> = Uninitialized)
: MvRxState { : MvRxState {
@ -77,11 +80,16 @@ class ViewEditHistoryViewModel @AssistedInject constructor(@Assisted
override fun onSuccess(data: List<Event>) { override fun onSuccess(data: List<Event>) {
//TODO until supported by API Add original event manually //TODO until supported by API Add original event manually
val withOriginal = data.toMutableList() val withOriginal = data.toMutableList()
var originalIsReply = false
room.getTimeLineEvent(eventId)?.let { room.getTimeLineEvent(eventId)?.let {
withOriginal.add(it.root) withOriginal.add(it.root)
originalIsReply = it.root.getClearContent().toModel<MessageContent>()?.relatesTo?.inReplyTo?.eventId != null
} }
setState { setState {
copy(editList = Success(withOriginal)) copy(
editList = Success(withOriginal),
isOriginalAReply = originalIsReply
)
} }
} }
}) })