Use addLinks method on message. Next step is to proceed the url to navigate.

This commit is contained in:
ganfra 2018-12-19 11:50:44 +01:00
parent 58f60eaab4
commit fdd4642cbb
5 changed files with 78 additions and 15 deletions

View File

@ -23,8 +23,9 @@ import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventCo
import kotlinx.android.synthetic.main.fragment_room_detail.*
import org.koin.android.ext.android.inject
import org.koin.core.parameter.parametersOf
import timber.log.Timber

class RoomDetailFragment : RiotFragment() {
class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {

companion object {

@ -80,6 +81,7 @@ class RoomDetailFragment : RiotFragment() {
recyclerView.layoutManager = layoutManager
timelineEventController.addModelBuildListener { it.dispatchTo(scrollOnNewMessageCallback) }
recyclerView.setController(timelineEventController)
timelineEventController.callback = this
}

private fun renderRoomSummary(roomSummary: RoomSummary?) {
@ -100,4 +102,10 @@ class RoomDetailFragment : RiotFragment() {
timelineEventController.timeline = events
}

// TimelineEventController.Callback ************************************************************

override fun onUrlClicked(url: String) {
Timber.v("Url clicked: $url")
}

}

View File

@ -3,6 +3,8 @@ package im.vector.riotredesign.features.home.room.detail.timeline
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import im.vector.matrix.android.api.permalinks.MatrixURLSpan
import im.vector.matrix.android.api.permalinks.MatrixUrlLinkify
import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.KotlinModel
import im.vector.riotredesign.features.home.AvatarRenderer
@ -12,7 +14,8 @@ data class MessageItem(
val time: CharSequence? = null,
val avatarUrl: String?,
val memberName: CharSequence? = null,
val showInformation: Boolean = true
val showInformation: Boolean = true,
val onUrlClickedListener: ((url: String) -> Unit)? = null
) : KotlinModel(R.layout.item_event_message) {

private val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
@ -22,6 +25,11 @@ data class MessageItem(

override fun bind() {
messageView.text = message
MatrixUrlLinkify.addLinks(messageView, object : MatrixURLSpan.Callback {
override fun onUrlClicked(url: String) {
onUrlClickedListener?.invoke(url)
}
})
if (showInformation) {
avatarImageView.visibility = View.VISIBLE
memberNameView.visibility = View.VISIBLE

View File

@ -9,7 +9,13 @@ class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatte

private val messagesDisplayedWithInformation = HashSet<String?>()

fun create(event: EnrichedEvent, nextEvent: EnrichedEvent?, addDaySeparator: Boolean, date: LocalDateTime): MessageItem? {
fun create(event: EnrichedEvent,
nextEvent: EnrichedEvent?,
addDaySeparator: Boolean,
date: LocalDateTime,
callback: TimelineEventController.Callback?
): MessageItem? {

val messageContent: MessageContent? = event.root.content.toModel()
val roomMember = event.roomMember
if (messageContent == null || roomMember == null) {
@ -20,13 +26,13 @@ class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatte
messagesDisplayedWithInformation.add(event.root.eventId)
}
val showInformation = messagesDisplayedWithInformation.contains(event.root.eventId)

return MessageItem(
message = messageContent.body,
avatarUrl = roomMember.avatarUrl,
showInformation = showInformation,
time = timelineDateFormatter.formatMessageHour(date),
memberName = roomMember.displayName ?: event.root.sender
memberName = roomMember.displayName ?: event.root.sender,
onUrlClickedListener = { callback?.onUrlClicked(it) }
)
}


View File

@ -44,6 +44,8 @@ class TimelineEventController(private val roomId: String,
buildSnapshotList()
}

var callback: Callback? = null

override fun buildModels() {
buildModels(snapshotList)
}
@ -61,8 +63,8 @@ class TimelineEventController(private val roomId: String,
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()

val item = when (event.root.type) {
EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, addDaySeparator, date)
else -> textItemFactory.create(event)
EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, addDaySeparator, date, callback)
else -> textItemFactory.create(event)
}
item
?.onBind { timeline?.loadAround(index) }
@ -87,4 +89,8 @@ class TimelineEventController(private val roomId: String,
requestModelBuild()
}

interface Callback {
fun onUrlClicked(url: String)
}

}

View File

@ -1,34 +1,69 @@
package im.vector.matrix.android.api.permalinks

import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.SpannableString
import android.text.method.LinkMovementMethod
import android.widget.TextView

object MatrixUrlLinkify {

/**
* Find the matrix spans i.e matrix id , user id ... to display them as URL.
*
* @param spannableStringBuilder the text in which the matrix items has to be clickable.
* @param spannable the text in which the matrix items has to be clickable.
*/
fun addLinks(spannableStringBuilder: SpannableStringBuilder, callback: MatrixURLSpan.Callback?) {
fun addLinks(spannable: Spannable?, callback: MatrixURLSpan.Callback?): Boolean {
// sanity checks
if (spannableStringBuilder.isEmpty()) {
return
if (spannable.isNullOrEmpty()) {
return false
}
val text = spannableStringBuilder.toString()
val text = spannable.toString()
var hasMatch = false
for (index in MatrixPatterns.MATRIX_PATTERNS.indices) {
val pattern = MatrixPatterns.MATRIX_PATTERNS[index]
val matcher = pattern.matcher(spannableStringBuilder)
val matcher = pattern.matcher(spannable)
while (matcher.find()) {
hasMatch = true
val startPos = matcher.start(0)
if (startPos == 0 || text[startPos - 1] != '/') {
val endPos = matcher.end(0)
val url = text.substring(matcher.start(0), matcher.end(0))
val span = MatrixURLSpan(url, callback)
spannableStringBuilder.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
}
return hasMatch
}

fun addLinks(textView: TextView, callback: MatrixURLSpan.Callback?): Boolean {
val text = textView.text
if (text is Spannable) {
if (addLinks(text, callback)) {
addLinkMovementMethod(textView)
return true
}

return false
} else {
val spannableString = SpannableString.valueOf(text)
if (addLinks(spannableString, callback)) {
addLinkMovementMethod(textView)
textView.text = spannableString
return true
}
return false
}
}


private fun addLinkMovementMethod(textView: TextView) {
val movementMethod = textView.movementMethod
if (movementMethod == null || movementMethod !is LinkMovementMethod) {
if (textView.linksClickable) {
textView.movementMethod = LinkMovementMethod.getInstance()
}
}
}