Permalinks : add a parser to get data from permalink (userId, eventId...)

This commit is contained in:
ganfra 2018-12-19 19:08:30 +01:00
parent fdd4642cbb
commit 9b8800ec55
7 changed files with 80 additions and 11 deletions

View File

@ -9,6 +9,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.permalinks.PermalinkParser
import im.vector.matrix.android.api.session.events.model.EnrichedEvent import im.vector.matrix.android.api.session.events.model.EnrichedEvent
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.room.Room import im.vector.matrix.android.api.session.room.Room
@ -105,7 +106,8 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
// TimelineEventController.Callback ************************************************************ // TimelineEventController.Callback ************************************************************


override fun onUrlClicked(url: String) { override fun onUrlClicked(url: String) {
Timber.v("Url clicked: $url") val permalinkData = PermalinkParser.parse(url)
Timber.v("Permalink data : $permalinkData")
} }


} }

View File

@ -3,8 +3,8 @@ package im.vector.riotredesign.features.home.room.detail.timeline
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import im.vector.matrix.android.api.permalinks.MatrixURLSpan import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan
import im.vector.matrix.android.api.permalinks.MatrixUrlLinkify import im.vector.matrix.android.api.permalinks.MatrixLinkify
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.KotlinModel import im.vector.riotredesign.core.epoxy.KotlinModel
import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.AvatarRenderer
@ -25,7 +25,7 @@ data class MessageItem(


override fun bind() { override fun bind() {
messageView.text = message messageView.text = message
MatrixUrlLinkify.addLinks(messageView, object : MatrixURLSpan.Callback { MatrixLinkify.addLinks(messageView, object : MatrixPermalinkSpan.Callback {
override fun onUrlClicked(url: String) { override fun onUrlClicked(url: String) {
onUrlClickedListener?.invoke(url) onUrlClickedListener?.invoke(url)
} }

View File

@ -5,14 +5,14 @@ import android.text.SpannableString
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.widget.TextView import android.widget.TextView


object MatrixUrlLinkify { object MatrixLinkify {


/** /**
* Find the matrix spans i.e matrix id , user id ... to display them as URL. * Find the matrix spans i.e matrix id , user id ... to display them as URL.
* *
* @param spannable 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(spannable: Spannable?, callback: MatrixURLSpan.Callback?): Boolean { fun addLinks(spannable: Spannable?, callback: MatrixPermalinkSpan.Callback?): Boolean {
// sanity checks // sanity checks
if (spannable.isNullOrEmpty()) { if (spannable.isNullOrEmpty()) {
return false return false
@ -28,7 +28,7 @@ object MatrixUrlLinkify {
if (startPos == 0 || text[startPos - 1] != '/') { if (startPos == 0 || text[startPos - 1] != '/') {
val endPos = matcher.end(0) val endPos = matcher.end(0)
val url = text.substring(matcher.start(0), matcher.end(0)) val url = text.substring(matcher.start(0), matcher.end(0))
val span = MatrixURLSpan(url, callback) val span = MatrixPermalinkSpan(url, callback)
spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
} }
} }
@ -36,7 +36,7 @@ object MatrixUrlLinkify {
return hasMatch return hasMatch
} }


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

View File

@ -3,8 +3,8 @@ package im.vector.matrix.android.api.permalinks
import android.text.style.ClickableSpan import android.text.style.ClickableSpan
import android.view.View import android.view.View


class MatrixURLSpan(private val url: String, class MatrixPermalinkSpan(private val url: String,
private val callback: Callback? = null) : ClickableSpan() { private val callback: Callback? = null) : ClickableSpan() {


interface Callback { interface Callback {
fun onUrlClicked(url: String) fun onUrlClicked(url: String)

View File

@ -0,0 +1,17 @@
package im.vector.matrix.android.api.permalinks

import android.net.Uri

sealed class PermalinkData {

data class EventLink(val roomIdOrAlias: String, val eventId: String) : PermalinkData()

data class RoomLink(val roomIdOrAlias: String) : PermalinkData()

data class UserLink(val userId: String) : PermalinkData()

data class GroupLink(val groupId: String) : PermalinkData()

data class FallbackLink(val uri: Uri) : PermalinkData()

}

View File

@ -6,7 +6,7 @@ import im.vector.matrix.android.api.session.events.model.Event
/** /**
* Useful methods to deals with Matrix permalink * Useful methods to deals with Matrix permalink
*/ */
object PermalinkUtils { object PermalinkFactory {


private val MATRIX_TO_URL_BASE = "https://matrix.to/#/" private val MATRIX_TO_URL_BASE = "https://matrix.to/#/"


View File

@ -0,0 +1,50 @@
package im.vector.matrix.android.api.permalinks

import android.net.Uri

object PermalinkParser {

private const val MATRIX_NAVIGATE_TO_HOST = "matrix.to"

fun parse(uriString: String): PermalinkData {
val uri = Uri.parse(uriString)
return parse(uri)
}

fun parse(uri: Uri): PermalinkData {
val host = uri.host
val path = uri.path
val fragment = uri.fragment

if (path.isNullOrEmpty()
|| host.isNullOrEmpty()
|| fragment.isNullOrEmpty()
|| host != MATRIX_NAVIGATE_TO_HOST) {
return PermalinkData.FallbackLink(uri)
}
// we are limiting to 2 params
val params = fragment
.split(MatrixPatterns.SEP_REGEX.toRegex())
.filter { it.isNotEmpty() }
.take(2)

val identifier = params.getOrNull(0)
val extraParameter = params.getOrNull(1)
if (identifier.isNullOrEmpty()) {
return PermalinkData.FallbackLink(uri)
}
return when {
MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier)
MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier)
MatrixPatterns.isRoomId(identifier) -> {
if (!extraParameter.isNullOrEmpty() && MatrixPatterns.isEventId(extraParameter)) {
PermalinkData.EventLink(roomIdOrAlias = identifier, eventId = extraParameter)
} else {
PermalinkData.RoomLink(roomIdOrAlias = identifier)
}
}
else -> PermalinkData.FallbackLink(uri)
}
}

}