Parse permalink using parseMatrixEntityFrom.
Create new PermalinkData type for link to Events. Keep matrixToConverter for now to first convert to matrix.to link. At some point it may be done by the SDK. Remove parse(Uri)
This commit is contained in:
parent
3346610f25
commit
9b6ab9b484
14 changed files with 125 additions and 241 deletions
|
|
@ -17,7 +17,6 @@
|
||||||
package io.element.android.features.messages.impl
|
package io.element.android.features.messages.impl
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -108,13 +107,19 @@ class MessagesNode @AssistedInject constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
url: String,
|
url: String,
|
||||||
) {
|
) {
|
||||||
when (val permalink = permalinkParser.parse(Uri.parse(url))) {
|
when (val permalink = permalinkParser.parse(url)) {
|
||||||
is PermalinkData.UserLink -> {
|
is PermalinkData.UserLink -> {
|
||||||
callback?.onUserDataClicked(UserId(permalink.userId))
|
callback?.onUserDataClicked(permalink.userId)
|
||||||
}
|
}
|
||||||
is PermalinkData.RoomLink -> {
|
is PermalinkData.RoomLink -> {
|
||||||
// TODO Implement room link handling
|
// TODO Implement room link handling
|
||||||
}
|
}
|
||||||
|
is PermalinkData.EventIdAliasLink -> {
|
||||||
|
// TODO Implement room and Event link handling
|
||||||
|
}
|
||||||
|
is PermalinkData.EventIdLink -> {
|
||||||
|
// TODO Implement room and Event link handling
|
||||||
|
}
|
||||||
is PermalinkData.FallbackLink,
|
is PermalinkData.FallbackLink,
|
||||||
is PermalinkData.RoomEmailInviteLink -> {
|
is PermalinkData.RoomEmailInviteLink -> {
|
||||||
context.openUrlInExternalApp(url)
|
context.openUrlInExternalApp(url)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package io.element.android.features.messages.impl.messagecomposer
|
package io.element.android.features.messages.impl.messagecomposer
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.features.messages.impl.mentions.MentionSuggestion
|
import io.element.android.features.messages.impl.mentions.MentionSuggestion
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
|
@ -49,7 +48,6 @@ fun aMessageComposerState(
|
||||||
richTextEditorState = richTextEditorState,
|
richTextEditorState = richTextEditorState,
|
||||||
permalinkParser = object : PermalinkParser {
|
permalinkParser = object : PermalinkParser {
|
||||||
override fun parse(uriString: String): PermalinkData = TODO()
|
override fun parse(uriString: String): PermalinkData = TODO()
|
||||||
override fun parse(uri: Uri): PermalinkData = TODO()
|
|
||||||
},
|
},
|
||||||
isFullScreen = isFullScreen,
|
isFullScreen = isFullScreen,
|
||||||
mode = mode,
|
mode = mode,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@ package io.element.android.libraries.matrix.api.permalink
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -27,28 +29,44 @@ import kotlinx.collections.immutable.ImmutableList
|
||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
sealed interface PermalinkData {
|
sealed interface PermalinkData {
|
||||||
data class RoomLink(
|
sealed interface RoomLink : PermalinkData {
|
||||||
val roomIdOrAlias: String,
|
|
||||||
val isRoomAlias: Boolean,
|
|
||||||
val eventId: String?,
|
|
||||||
val viaParameters: ImmutableList<String>
|
val viaParameters: ImmutableList<String>
|
||||||
) : PermalinkData {
|
|
||||||
fun getRoomId(): RoomId? {
|
|
||||||
return roomIdOrAlias.takeIf { !isRoomAlias }?.let(::RoomId)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRoomAlias(): String? {
|
|
||||||
return roomIdOrAlias.takeIf { isRoomAlias }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class RoomIdLink(
|
||||||
|
val roomId: RoomId,
|
||||||
|
override val viaParameters: ImmutableList<String>
|
||||||
|
) : RoomLink
|
||||||
|
|
||||||
|
data class RoomAliasLink(
|
||||||
|
val roomAlias: String,
|
||||||
|
override val viaParameters: ImmutableList<String>
|
||||||
|
) : RoomLink
|
||||||
|
|
||||||
|
sealed interface EventLink : PermalinkData {
|
||||||
|
val eventId: EventId
|
||||||
|
val viaParameters: ImmutableList<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
data class EventIdLink(
|
||||||
|
val roomId: RoomId,
|
||||||
|
override val eventId: EventId,
|
||||||
|
override val viaParameters: ImmutableList<String>
|
||||||
|
) : EventLink
|
||||||
|
|
||||||
|
data class EventIdAliasLink(
|
||||||
|
val roomAlias: String,
|
||||||
|
override val eventId: EventId,
|
||||||
|
override val viaParameters: ImmutableList<String>
|
||||||
|
) : EventLink
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* &room_name=Team2
|
* &room_name=Team2
|
||||||
* &room_avatar_url=mxc:
|
* &room_avatar_url=mxc:
|
||||||
* &inviter_name=bob
|
* &inviter_name=bob
|
||||||
*/
|
*/
|
||||||
data class RoomEmailInviteLink(
|
data class RoomEmailInviteLink(
|
||||||
val roomId: String,
|
val roomId: RoomId,
|
||||||
val email: String,
|
val email: String,
|
||||||
val signUrl: String,
|
val signUrl: String,
|
||||||
val roomName: String?,
|
val roomName: String?,
|
||||||
|
|
@ -60,7 +78,7 @@ sealed interface PermalinkData {
|
||||||
val roomType: String?
|
val roomType: String?
|
||||||
) : PermalinkData
|
) : PermalinkData
|
||||||
|
|
||||||
data class UserLink(val userId: String) : PermalinkData
|
data class UserLink(val userId: UserId) : PermalinkData
|
||||||
|
|
||||||
data class FallbackLink(val uri: Uri, val isLegacyGroupLink: Boolean = false) : PermalinkData
|
data class FallbackLink(val uri: Uri, val isLegacyGroupLink: Boolean = false) : PermalinkData
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.permalink
|
package io.element.android.libraries.matrix.api.permalink
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class turns a uri to a [PermalinkData].
|
* This class turns a uri to a [PermalinkData].
|
||||||
* element-based domains (e.g. https://app.element.io/#/user/@chagai95:matrix.org) permalinks
|
* element-based domains (e.g. https://app.element.io/#/user/@chagai95:matrix.org) permalinks
|
||||||
|
|
@ -27,12 +25,7 @@ import android.net.Uri
|
||||||
interface PermalinkParser {
|
interface PermalinkParser {
|
||||||
/**
|
/**
|
||||||
* Turns a uri string to a [PermalinkData].
|
* Turns a uri string to a [PermalinkData].
|
||||||
*/
|
|
||||||
fun parse(uriString: String): PermalinkData
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns a uri to a [PermalinkData].
|
|
||||||
* https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
|
* https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
|
||||||
*/
|
*/
|
||||||
fun parse(uri: Uri): PermalinkData
|
fun parse(uriString: String): PermalinkData
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,5 +22,6 @@ import io.element.android.libraries.matrix.api.core.UserId
|
||||||
sealed interface Mention {
|
sealed interface Mention {
|
||||||
data class User(val userId: UserId) : Mention
|
data class User(val userId: UserId) : Mention
|
||||||
data object AtRoom : Mention
|
data object AtRoom : Mention
|
||||||
data class Room(val roomId: RoomId?, val roomAlias: String?) : Mention
|
data class Room(val roomId: RoomId) : Mention
|
||||||
|
data class RoomAlias(val roomAlias: String?) : Mention
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2023 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 io.element.android.libraries.matrix.api.permalink
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class PermalinkDataTest {
|
|
||||||
@Test
|
|
||||||
fun `getRoomId() returns value when isRoomAlias is false`() {
|
|
||||||
val permalinkData = PermalinkData.RoomLink(
|
|
||||||
roomIdOrAlias = "!abcdef123456:matrix.org",
|
|
||||||
isRoomAlias = false,
|
|
||||||
eventId = null,
|
|
||||||
viaParameters = persistentListOf(),
|
|
||||||
)
|
|
||||||
assertThat(permalinkData.getRoomId()).isNotNull()
|
|
||||||
assertThat(permalinkData.getRoomAlias()).isNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `getRoomAlias() returns value when isRoomAlias is true`() {
|
|
||||||
val permalinkData = PermalinkData.RoomLink(
|
|
||||||
roomIdOrAlias = "#room:matrix.org",
|
|
||||||
isRoomAlias = true,
|
|
||||||
eventId = null,
|
|
||||||
viaParameters = persistentListOf(),
|
|
||||||
)
|
|
||||||
assertThat(permalinkData.getRoomId()).isNull()
|
|
||||||
assertThat(permalinkData.getRoomAlias()).isNotNull()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -17,16 +17,17 @@
|
||||||
package io.element.android.libraries.matrix.impl.permalink
|
package io.element.android.libraries.matrix.impl.permalink
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.net.UrlQuerySanitizer
|
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import io.element.android.libraries.di.AppScope
|
import io.element.android.libraries.di.AppScope
|
||||||
import io.element.android.libraries.matrix.api.core.MatrixPatterns
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.permalink.MatrixToConverter
|
import io.element.android.libraries.matrix.api.permalink.MatrixToConverter
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import timber.log.Timber
|
import org.matrix.rustcomponents.sdk.MatrixId
|
||||||
import java.net.URLDecoder
|
import org.matrix.rustcomponents.sdk.parseMatrixEntityFrom
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -41,118 +42,45 @@ class DefaultPermalinkParser @Inject constructor(
|
||||||
) : PermalinkParser {
|
) : PermalinkParser {
|
||||||
/**
|
/**
|
||||||
* Turns a uri string to a [PermalinkData].
|
* Turns a uri string to a [PermalinkData].
|
||||||
|
* https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
|
||||||
*/
|
*/
|
||||||
override fun parse(uriString: String): PermalinkData {
|
override fun parse(uriString: String): PermalinkData {
|
||||||
val uri = Uri.parse(uriString)
|
val uri = Uri.parse(uriString)
|
||||||
return parse(uri)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns a uri to a [PermalinkData].
|
|
||||||
* https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
|
|
||||||
*/
|
|
||||||
override fun parse(uri: Uri): PermalinkData {
|
|
||||||
// the client or element-based domain permalinks (e.g. https://app.element.io/#/user/@chagai95:matrix.org) don't have the
|
// the client or element-based domain permalinks (e.g. https://app.element.io/#/user/@chagai95:matrix.org) don't have the
|
||||||
// mxid in the first param (like matrix.to does - https://matrix.to/#/@chagai95:matrix.org) but rather in the second after /user/ so /user/mxid
|
// mxid in the first param (like matrix.to does - https://matrix.to/#/@chagai95:matrix.org) but rather in the second after /user/ so /user/mxid
|
||||||
// so convert URI to matrix.to to simplify parsing process
|
// so convert URI to matrix.to to simplify parsing process
|
||||||
val matrixToUri = matrixToConverter.convert(uri) ?: return PermalinkData.FallbackLink(uri)
|
val matrixToUri = matrixToConverter.convert(uri) ?: return PermalinkData.FallbackLink(uri)
|
||||||
|
|
||||||
// We can't use uri.fragment as it is decoding to early and it will break the parsing
|
val result = runCatching {
|
||||||
// of parameters that represents url (like signurl)
|
parseMatrixEntityFrom(matrixToUri.toString())
|
||||||
val fragment = matrixToUri.toString().substringAfter("#") // uri.fragment
|
}.getOrNull()
|
||||||
if (fragment.isEmpty()) {
|
return if (result == null) {
|
||||||
return PermalinkData.FallbackLink(uri)
|
PermalinkData.FallbackLink(uri)
|
||||||
}
|
|
||||||
val safeFragment = fragment.substringBefore('?')
|
|
||||||
val viaQueryParameters = fragment.getViaParameters()
|
|
||||||
|
|
||||||
// we are limiting to 2 params
|
|
||||||
val params = safeFragment
|
|
||||||
.split(MatrixPatterns.SEP_REGEX)
|
|
||||||
.filter { it.isNotEmpty() }
|
|
||||||
.take(2)
|
|
||||||
|
|
||||||
val decodedParams = params
|
|
||||||
.map { URLDecoder.decode(it, "UTF-8") }
|
|
||||||
|
|
||||||
val identifier = params.getOrNull(0)
|
|
||||||
val decodedIdentifier = decodedParams.getOrNull(0)
|
|
||||||
val extraParameter = decodedParams.getOrNull(1)
|
|
||||||
return when {
|
|
||||||
identifier.isNullOrEmpty() || decodedIdentifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri)
|
|
||||||
MatrixPatterns.isUserId(decodedIdentifier) -> PermalinkData.UserLink(userId = decodedIdentifier)
|
|
||||||
MatrixPatterns.isRoomId(decodedIdentifier) -> {
|
|
||||||
handleRoomIdCase(fragment, decodedIdentifier, matrixToUri, extraParameter, viaQueryParameters)
|
|
||||||
}
|
|
||||||
MatrixPatterns.isRoomAlias(decodedIdentifier) -> {
|
|
||||||
PermalinkData.RoomLink(
|
|
||||||
roomIdOrAlias = decodedIdentifier,
|
|
||||||
isRoomAlias = true,
|
|
||||||
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
|
|
||||||
viaParameters = viaQueryParameters.toImmutableList()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleRoomIdCase(fragment: String, identifier: String, uri: Uri, extraParameter: String?, viaQueryParameters: List<String>): PermalinkData {
|
|
||||||
// Can't rely on built in parsing because it's messing around the signurl
|
|
||||||
val paramList = safeExtractParams(fragment)
|
|
||||||
val signUrl = paramList.firstOrNull { it.first == "signurl" }?.second
|
|
||||||
val email = paramList.firstOrNull { it.first == "email" }?.second
|
|
||||||
return if (signUrl.isNullOrEmpty().not() && email.isNullOrEmpty().not()) {
|
|
||||||
try {
|
|
||||||
val signValidUri = Uri.parse(signUrl)
|
|
||||||
val identityServerHost = signValidUri.authority ?: throw IllegalArgumentException("missing `authority`")
|
|
||||||
val token = signValidUri.getQueryParameter("token") ?: throw IllegalArgumentException("missing `token`")
|
|
||||||
val privateKey = signValidUri.getQueryParameter("private_key") ?: throw IllegalArgumentException("missing `private_key`")
|
|
||||||
PermalinkData.RoomEmailInviteLink(
|
|
||||||
roomId = identifier,
|
|
||||||
email = email!!,
|
|
||||||
signUrl = signUrl!!,
|
|
||||||
roomName = paramList.firstOrNull { it.first == "room_name" }?.second,
|
|
||||||
inviterName = paramList.firstOrNull { it.first == "inviter_name" }?.second,
|
|
||||||
roomAvatarUrl = paramList.firstOrNull { it.first == "room_avatar_url" }?.second,
|
|
||||||
roomType = paramList.firstOrNull { it.first == "room_type" }?.second,
|
|
||||||
identityServer = identityServerHost,
|
|
||||||
token = token,
|
|
||||||
privateKey = privateKey
|
|
||||||
)
|
|
||||||
} catch (failure: Throwable) {
|
|
||||||
Timber.i("## Permalink: Failed to parse permalink $signUrl")
|
|
||||||
PermalinkData.FallbackLink(uri)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
PermalinkData.RoomLink(
|
val viaParameters = result.via.toImmutableList()
|
||||||
roomIdOrAlias = identifier,
|
when (val id = result.id) {
|
||||||
isRoomAlias = false,
|
is MatrixId.Room -> PermalinkData.RoomIdLink(
|
||||||
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
|
roomId = RoomId(id.id),
|
||||||
viaParameters = viaQueryParameters.toImmutableList()
|
viaParameters = viaParameters,
|
||||||
)
|
)
|
||||||
}
|
is MatrixId.User -> PermalinkData.UserLink(
|
||||||
}
|
userId = UserId(id.id),
|
||||||
|
)
|
||||||
private fun safeExtractParams(fragment: String) =
|
is MatrixId.RoomAlias -> PermalinkData.RoomAliasLink(
|
||||||
fragment.substringAfter("?").split('&').mapNotNull {
|
roomAlias = id.alias,
|
||||||
val splitNameValue = it.split("=")
|
viaParameters = viaParameters,
|
||||||
if (splitNameValue.size == 2) {
|
)
|
||||||
Pair(splitNameValue[0], URLDecoder.decode(splitNameValue[1], "UTF-8"))
|
is MatrixId.EventOnRoomId -> PermalinkData.EventIdLink(
|
||||||
} else {
|
roomId = RoomId(id.roomId),
|
||||||
null
|
eventId = EventId(id.eventId),
|
||||||
|
viaParameters = viaParameters,
|
||||||
|
)
|
||||||
|
is MatrixId.EventOnRoomAlias -> PermalinkData.EventIdAliasLink(
|
||||||
|
roomAlias = id.alias,
|
||||||
|
eventId = EventId(id.eventId),
|
||||||
|
viaParameters = viaParameters,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.getViaParameters(): List<String> {
|
|
||||||
return runCatching {
|
|
||||||
UrlQuerySanitizer(this)
|
|
||||||
.parameterList
|
|
||||||
.filter {
|
|
||||||
it.mParameter == "via"
|
|
||||||
}
|
|
||||||
.map {
|
|
||||||
URLDecoder.decode(it.mValue, "UTF-8")
|
|
||||||
}
|
|
||||||
}.getOrDefault(emptyList())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@
|
||||||
package io.element.android.libraries.matrix.impl.permalink
|
package io.element.android.libraries.matrix.impl.permalink
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -69,7 +72,7 @@ class DefaultPermalinkParserTest {
|
||||||
val url = "https://app.element.io/#/user/@test:matrix.org"
|
val url = "https://app.element.io/#/user/@test:matrix.org"
|
||||||
assertThat(sut.parse(url)).isEqualTo(
|
assertThat(sut.parse(url)).isEqualTo(
|
||||||
PermalinkData.UserLink(
|
PermalinkData.UserLink(
|
||||||
userId = "@test:matrix.org"
|
userId = UserId("@test:matrix.org")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -81,10 +84,8 @@ class DefaultPermalinkParserTest {
|
||||||
)
|
)
|
||||||
val url = "https://app.element.io/#/room/!aBCD1234:matrix.org"
|
val url = "https://app.element.io/#/room/!aBCD1234:matrix.org"
|
||||||
assertThat(sut.parse(url)).isEqualTo(
|
assertThat(sut.parse(url)).isEqualTo(
|
||||||
PermalinkData.RoomLink(
|
PermalinkData.RoomIdLink(
|
||||||
roomIdOrAlias = "!aBCD1234:matrix.org",
|
roomId = RoomId("!aBCD1234:matrix.org"),
|
||||||
isRoomAlias = false,
|
|
||||||
eventId = null,
|
|
||||||
viaParameters = persistentListOf(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -97,10 +98,9 @@ class DefaultPermalinkParserTest {
|
||||||
)
|
)
|
||||||
val url = "https://app.element.io/#/room/!aBCD1234:matrix.org/$1234567890abcdef:matrix.org"
|
val url = "https://app.element.io/#/room/!aBCD1234:matrix.org/$1234567890abcdef:matrix.org"
|
||||||
assertThat(sut.parse(url)).isEqualTo(
|
assertThat(sut.parse(url)).isEqualTo(
|
||||||
PermalinkData.RoomLink(
|
PermalinkData.EventIdLink(
|
||||||
roomIdOrAlias = "!aBCD1234:matrix.org",
|
roomId = RoomId("!aBCD1234:matrix.org"),
|
||||||
isRoomAlias = false,
|
eventId = EventId("$1234567890abcdef:matrix.org"),
|
||||||
eventId = "\$1234567890abcdef:matrix.org",
|
|
||||||
viaParameters = persistentListOf(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -113,10 +113,8 @@ class DefaultPermalinkParserTest {
|
||||||
)
|
)
|
||||||
val url = "https://app.element.io/#/room/!aBCD1234:matrix.org/1234567890abcdef:matrix.org"
|
val url = "https://app.element.io/#/room/!aBCD1234:matrix.org/1234567890abcdef:matrix.org"
|
||||||
assertThat(sut.parse(url)).isEqualTo(
|
assertThat(sut.parse(url)).isEqualTo(
|
||||||
PermalinkData.RoomLink(
|
PermalinkData.RoomIdLink(
|
||||||
roomIdOrAlias = "!aBCD1234:matrix.org",
|
roomId = RoomId("!aBCD1234:matrix.org"),
|
||||||
isRoomAlias = false,
|
|
||||||
eventId = null,
|
|
||||||
viaParameters = persistentListOf(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -129,10 +127,9 @@ class DefaultPermalinkParserTest {
|
||||||
)
|
)
|
||||||
val url = "https://app.element.io/#/room/!aBCD1234:matrix.org/$1234567890abcdef:matrix.org?via=matrix.org&via=matrix.com"
|
val url = "https://app.element.io/#/room/!aBCD1234:matrix.org/$1234567890abcdef:matrix.org?via=matrix.org&via=matrix.com"
|
||||||
assertThat(sut.parse(url)).isEqualTo(
|
assertThat(sut.parse(url)).isEqualTo(
|
||||||
PermalinkData.RoomLink(
|
PermalinkData.EventIdLink(
|
||||||
roomIdOrAlias = "!aBCD1234:matrix.org",
|
roomId = RoomId("!aBCD1234:matrix.org"),
|
||||||
isRoomAlias = false,
|
eventId = EventId("$1234567890abcdef:matrix.org"),
|
||||||
eventId = "\$1234567890abcdef:matrix.org",
|
|
||||||
viaParameters = persistentListOf("matrix.org", "matrix.com"),
|
viaParameters = persistentListOf("matrix.org", "matrix.com"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -145,10 +142,23 @@ class DefaultPermalinkParserTest {
|
||||||
)
|
)
|
||||||
val url = "https://app.element.io/#/room/#element-android:matrix.org"
|
val url = "https://app.element.io/#/room/#element-android:matrix.org"
|
||||||
assertThat(sut.parse(url)).isEqualTo(
|
assertThat(sut.parse(url)).isEqualTo(
|
||||||
PermalinkData.RoomLink(
|
PermalinkData.RoomAliasLink(
|
||||||
roomIdOrAlias = "#element-android:matrix.org",
|
roomAlias = "#element-android:matrix.org",
|
||||||
isRoomAlias = true,
|
viaParameters = persistentListOf(),
|
||||||
eventId = null,
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `parsing a valid room alias with eventId url returns a room link`() {
|
||||||
|
val sut = DefaultPermalinkParser(
|
||||||
|
matrixToConverter = DefaultMatrixToConverter(),
|
||||||
|
)
|
||||||
|
val url = "https://app.element.io/#/room/#element-android:matrix.org/$1234567890abcdef:matrix.org"
|
||||||
|
assertThat(sut.parse(url)).isEqualTo(
|
||||||
|
PermalinkData.EventIdAliasLink(
|
||||||
|
roomAlias = "#element-android:matrix.org",
|
||||||
|
eventId = EventId("$1234567890abcdef:matrix.org"),
|
||||||
viaParameters = persistentListOf(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -188,7 +198,7 @@ class DefaultPermalinkParserTest {
|
||||||
"&room_type="
|
"&room_type="
|
||||||
assertThat(sut.parse(url)).isEqualTo(
|
assertThat(sut.parse(url)).isEqualTo(
|
||||||
PermalinkData.RoomEmailInviteLink(
|
PermalinkData.RoomEmailInviteLink(
|
||||||
roomId = "!aBCDEF12345:matrix.org",
|
roomId = RoomId("!aBCDEF12345:matrix.org"),
|
||||||
email = "testuser@element.io",
|
email = "testuser@element.io",
|
||||||
signUrl = "https://vector.im/_matrix/identity/api/v1/sign-ed25519?token=a_token&private_key=a_private_key",
|
signUrl = "https://vector.im/_matrix/identity/api/v1/sign-ed25519?token=a_token&private_key=a_private_key",
|
||||||
roomName = "TestRoom",
|
roomName = "TestRoom",
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.test.permalink
|
package io.element.android.libraries.matrix.test.permalink
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||||
|
|
||||||
|
|
@ -30,8 +29,4 @@ class FakePermalinkParser(
|
||||||
override fun parse(uriString: String): PermalinkData {
|
override fun parse(uriString: String): PermalinkData {
|
||||||
return result()
|
return result()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(uri: Uri): PermalinkData {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package io.element.android.libraries.matrixui.messages
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody
|
import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody
|
||||||
|
|
@ -78,10 +79,8 @@ class ToHtmlDocumentTest {
|
||||||
|
|
||||||
val document = body.toHtmlDocument(permalinkParser = object : PermalinkParser {
|
val document = body.toHtmlDocument(permalinkParser = object : PermalinkParser {
|
||||||
override fun parse(uriString: String): PermalinkData {
|
override fun parse(uriString: String): PermalinkData {
|
||||||
return PermalinkData.UserLink("@alice:matrix.org")
|
return PermalinkData.UserLink(UserId("@alice:matrix.org"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(uri: Uri): PermalinkData = TODO("Not yet implemented")
|
|
||||||
})
|
})
|
||||||
assertThat(document?.text()).isEqualTo("Hey @Alice!")
|
assertThat(document?.text()).isEqualTo("Hey @Alice!")
|
||||||
}
|
}
|
||||||
|
|
@ -95,10 +94,8 @@ class ToHtmlDocumentTest {
|
||||||
|
|
||||||
val document = body.toHtmlDocument(permalinkParser = object : PermalinkParser {
|
val document = body.toHtmlDocument(permalinkParser = object : PermalinkParser {
|
||||||
override fun parse(uriString: String): PermalinkData {
|
override fun parse(uriString: String): PermalinkData {
|
||||||
return PermalinkData.UserLink("@alice:matrix.org")
|
return PermalinkData.UserLink(UserId("@alice:matrix.org"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(uri: Uri): PermalinkData = TODO("Not yet implemented")
|
|
||||||
})
|
})
|
||||||
assertThat(document?.text()).isEqualTo("Hey @Alice!")
|
assertThat(document?.text()).isEqualTo("Hey @Alice!")
|
||||||
}
|
}
|
||||||
|
|
@ -114,8 +111,6 @@ class ToHtmlDocumentTest {
|
||||||
override fun parse(uriString: String): PermalinkData {
|
override fun parse(uriString: String): PermalinkData {
|
||||||
return PermalinkData.FallbackLink(uri = Uri.parse("https://matrix.org"))
|
return PermalinkData.FallbackLink(uri = Uri.parse("https://matrix.org"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(uri: Uri): PermalinkData = TODO("Not yet implemented")
|
|
||||||
})
|
})
|
||||||
assertThat(document?.text()).isEqualTo("Hey Alice!")
|
assertThat(document?.text()).isEqualTo("Hey Alice!")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -914,7 +914,6 @@ private fun ATextComposer(
|
||||||
voiceMessageState = voiceMessageState,
|
voiceMessageState = voiceMessageState,
|
||||||
permalinkParser = object : PermalinkParser {
|
permalinkParser = object : PermalinkParser {
|
||||||
override fun parse(uriString: String): PermalinkData = TODO("Not yet implemented")
|
override fun parse(uriString: String): PermalinkData = TODO("Not yet implemented")
|
||||||
override fun parse(uri: Uri): PermalinkData = TODO("Not yet implemented")
|
|
||||||
},
|
},
|
||||||
composerMode = composerMode,
|
composerMode = composerMode,
|
||||||
enableTextFormatting = enableTextFormatting,
|
enableTextFormatting = enableTextFormatting,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package io.element.android.libraries.textcomposer.mentions
|
||||||
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.net.Uri
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
|
@ -41,6 +40,7 @@ import io.element.android.libraries.designsystem.theme.currentUserMentionPillTex
|
||||||
import io.element.android.libraries.designsystem.theme.mentionPillBackground
|
import io.element.android.libraries.designsystem.theme.mentionPillBackground
|
||||||
import io.element.android.libraries.designsystem.theme.mentionPillText
|
import io.element.android.libraries.designsystem.theme.mentionPillText
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
@ -80,7 +80,7 @@ class MentionSpanProvider(
|
||||||
val (startPaddingPx, endPaddingPx) = paddingValuesPx.value
|
val (startPaddingPx, endPaddingPx) = paddingValuesPx.value
|
||||||
return when {
|
return when {
|
||||||
permalinkData is PermalinkData.UserLink -> {
|
permalinkData is PermalinkData.UserLink -> {
|
||||||
val isCurrentUser = permalinkData.userId == currentSessionId.value
|
val isCurrentUser = permalinkData.userId == currentSessionId
|
||||||
MentionSpan(
|
MentionSpan(
|
||||||
type = MentionSpan.Type.USER,
|
type = MentionSpan.Type.USER,
|
||||||
backgroundColor = if (isCurrentUser) currentUserBackgroundColor else otherBackgroundColor,
|
backgroundColor = if (isCurrentUser) currentUserBackgroundColor else otherBackgroundColor,
|
||||||
|
|
@ -137,19 +137,15 @@ internal fun MentionSpanPreview() {
|
||||||
permalinkParser = object : PermalinkParser {
|
permalinkParser = object : PermalinkParser {
|
||||||
override fun parse(uriString: String): PermalinkData {
|
override fun parse(uriString: String): PermalinkData {
|
||||||
return when (uriString) {
|
return when (uriString) {
|
||||||
"https://matrix.to/#/@me:matrix.org" -> PermalinkData.UserLink("@me:matrix.org")
|
"https://matrix.to/#/@me:matrix.org" -> PermalinkData.UserLink(UserId("@me:matrix.org"))
|
||||||
"https://matrix.to/#/@other:matrix.org" -> PermalinkData.UserLink("@other:matrix.org")
|
"https://matrix.to/#/@other:matrix.org" -> PermalinkData.UserLink(UserId("@other:matrix.org"))
|
||||||
"https://matrix.to/#/#room:matrix.org" -> PermalinkData.RoomLink(
|
"https://matrix.to/#/#room:matrix.org" -> PermalinkData.RoomAliasLink(
|
||||||
roomIdOrAlias = "#room:matrix.org",
|
roomAlias = "#room:matrix.org",
|
||||||
isRoomAlias = true,
|
|
||||||
eventId = null,
|
|
||||||
viaParameters = persistentListOf(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
else -> TODO()
|
else -> TODO()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(uri: Uri): PermalinkData = TODO()
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
ElementPreview {
|
ElementPreview {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package io.element.android.libraries.textcomposer.impl.mentions
|
||||||
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||||
|
|
@ -50,7 +51,7 @@ class MentionSpanProviderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getting mention span for current user should return a MentionSpan with custom colors`() {
|
fun `getting mention span for current user should return a MentionSpan with custom colors`() {
|
||||||
permalinkParser.givenResult(PermalinkData.UserLink(currentUserId.value))
|
permalinkParser.givenResult(PermalinkData.UserLink(currentUserId))
|
||||||
val mentionSpan = mentionSpanProvider.getMentionSpanFor("@me:matrix.org", "https://matrix.to/#/${currentUserId.value}")
|
val mentionSpan = mentionSpanProvider.getMentionSpanFor("@me:matrix.org", "https://matrix.to/#/${currentUserId.value}")
|
||||||
assertThat(mentionSpan.backgroundColor).isEqualTo(myUserColor)
|
assertThat(mentionSpan.backgroundColor).isEqualTo(myUserColor)
|
||||||
assertThat(mentionSpan.textColor).isEqualTo(myUserColor)
|
assertThat(mentionSpan.textColor).isEqualTo(myUserColor)
|
||||||
|
|
@ -58,7 +59,7 @@ class MentionSpanProviderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getting mention span for other user should return a MentionSpan with normal colors`() {
|
fun `getting mention span for other user should return a MentionSpan with normal colors`() {
|
||||||
permalinkParser.givenResult(PermalinkData.UserLink("@other:matrix.org"))
|
permalinkParser.givenResult(PermalinkData.UserLink(UserId("@other:matrix.org")))
|
||||||
val mentionSpan = mentionSpanProvider.getMentionSpanFor("@other:matrix.org", "https://matrix.to/#/@other:matrix.org")
|
val mentionSpan = mentionSpanProvider.getMentionSpanFor("@other:matrix.org", "https://matrix.to/#/@other:matrix.org")
|
||||||
assertThat(mentionSpan.backgroundColor).isEqualTo(otherColor)
|
assertThat(mentionSpan.backgroundColor).isEqualTo(otherColor)
|
||||||
assertThat(mentionSpan.textColor).isEqualTo(otherColor)
|
assertThat(mentionSpan.textColor).isEqualTo(otherColor)
|
||||||
|
|
@ -67,10 +68,8 @@ class MentionSpanProviderTest {
|
||||||
@Test
|
@Test
|
||||||
fun `getting mention span for a room should return a MentionSpan with normal colors`() {
|
fun `getting mention span for a room should return a MentionSpan with normal colors`() {
|
||||||
permalinkParser.givenResult(
|
permalinkParser.givenResult(
|
||||||
PermalinkData.RoomLink(
|
PermalinkData.RoomAliasLink(
|
||||||
roomIdOrAlias = "#room:matrix.org",
|
roomAlias = "#room:matrix.org",
|
||||||
isRoomAlias = true,
|
|
||||||
eventId = null,
|
|
||||||
viaParameters = persistentListOf(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -82,10 +81,8 @@ class MentionSpanProviderTest {
|
||||||
@Test
|
@Test
|
||||||
fun `getting mention span for @room should return a MentionSpan with normal colors`() {
|
fun `getting mention span for @room should return a MentionSpan with normal colors`() {
|
||||||
permalinkParser.givenResult(
|
permalinkParser.givenResult(
|
||||||
PermalinkData.RoomLink(
|
PermalinkData.RoomAliasLink(
|
||||||
roomIdOrAlias = "#",
|
roomAlias = "#",
|
||||||
isRoomAlias = true,
|
|
||||||
eventId = null,
|
|
||||||
viaParameters = persistentListOf(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,4 @@ class OnlyFallbackPermalinkParser : PermalinkParser {
|
||||||
override fun parse(uriString: String): PermalinkData {
|
override fun parse(uriString: String): PermalinkData {
|
||||||
return PermalinkData.FallbackLink(Uri.parse(uriString))
|
return PermalinkData.FallbackLink(Uri.parse(uriString))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(uri: Uri): PermalinkData {
|
|
||||||
return PermalinkData.FallbackLink(uri)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue