Permalink: handle via parameters

This commit is contained in:
ganfra 2020-08-26 16:37:48 +02:00
parent 9970398cf2
commit b986bfd509
6 changed files with 91 additions and 21 deletions

View File

@ -25,7 +25,12 @@ import android.net.Uri
*/
sealed class PermalinkData {
data class RoomLink(val roomIdOrAlias: String, val isRoomAlias: Boolean, val eventId: String?) : PermalinkData()
data class RoomLink(
val roomIdOrAlias: String,
val isRoomAlias: Boolean,
val eventId: String?,
val viaParameters: List<String>
) : PermalinkData()
data class UserLink(val userId: String) : PermalinkData()

View File

@ -19,6 +19,10 @@ package org.matrix.android.sdk.api.session.permalinks
import android.net.Uri
import org.matrix.android.sdk.api.MatrixPatterns
import java.io.UnsupportedEncodingException
import java.net.URLEncoder
import java.util.ArrayList
import java.util.Collections
/**
* This class turns an uri to a [PermalinkData]
@ -40,14 +44,13 @@ object PermalinkParser {
if (!uri.toString().startsWith(PermalinkService.MATRIX_TO_URL_BASE)) {
return PermalinkData.FallbackLink(uri)
}
val fragment = uri.fragment
if (fragment.isNullOrEmpty()) {
return PermalinkData.FallbackLink(uri)
}
val indexOfQuery = fragment.indexOf("?")
val safeFragment = if (indexOfQuery != -1) fragment.substring(0, indexOfQuery) else fragment
val viaQueryParameters = fragment.getViaParameters(indexOfQuery)
// we are limiting to 2 params
val params = safeFragment
@ -65,17 +68,58 @@ object PermalinkParser {
PermalinkData.RoomLink(
roomIdOrAlias = identifier,
isRoomAlias = false,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
viaParameters = viaQueryParameters
)
}
MatrixPatterns.isRoomAlias(identifier) -> {
PermalinkData.RoomLink(
roomIdOrAlias = identifier,
isRoomAlias = true,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
viaParameters = viaQueryParameters
)
}
else -> PermalinkData.FallbackLink(uri)
}
}
private fun String.getViaParameters(indexOfQuery: Int): List<String> {
val query = try {
substring(indexOfQuery + 1)
} catch (e: IndexOutOfBoundsException) {
return emptyList()
}
val encodedKey = try {
URLEncoder.encode("via", "UTF-8")
} catch (e: UnsupportedEncodingException) {
return emptyList()
}
val values = ArrayList<String>()
var start = 0
do {
val nextAmpersand = query.indexOf('&', start)
val end = if (nextAmpersand != -1) nextAmpersand else query.length
var separator = query.indexOf('=', start)
if (separator > end || separator == -1) {
separator = end
}
if (separator - start == encodedKey.length
&& query.regionMatches(start, encodedKey, 0, encodedKey.length)) {
if (separator == end) {
values.add("")
} else {
values.add(Uri.decode(query.substring(separator + 1, end)))
}
}
// Move start to end of name.
start = if (nextAmpersand != -1) {
nextAmpersand + 1
} else {
break
}
} while (true)
return Collections.unmodifiableList(values)
}
}

View File

@ -56,7 +56,25 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
if (deepLink == null) {
return Single.just(false)
}
return when (val permalinkData = PermalinkParser.parse(deepLink)) {
return Single
.fromCallable {
PermalinkParser.parse(deepLink)
}
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.flatMap { permalinkData ->
handlePermalink(permalinkData, context, navigationInterceptor, buildTask)
}
.onErrorReturnItem(false)
}
private fun handlePermalink(
permalinkData: PermalinkData,
context: Context,
navigationInterceptor: NavigationInterceptor?,
buildTask: Boolean
): Single<Boolean> {
return when (permalinkData) {
is PermalinkData.RoomLink -> {
permalinkData.getRoomId()
.observeOn(AndroidSchedulers.mainThread())
@ -66,8 +84,7 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
openRoom(
context = context,
roomId = roomId,
roomAlias = permalinkData.getRoomAliasOrNull(),
eventId = permalinkData.eventId,
permalinkData = permalinkData,
buildTask = buildTask
)
}
@ -87,7 +104,7 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
is PermalinkData.FallbackLink -> {
Single.just(false)
}
}.onErrorReturnItem(false)
}
}
private fun PermalinkData.RoomLink.getRoomId(): Single<Optional<String>> {
@ -110,13 +127,20 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
/**
* Open room either joined, or not
*/
private fun openRoom(context: Context, roomId: String?, roomAlias: String?, eventId: String?, buildTask: Boolean) {
private fun openRoom(
context: Context,
roomId: String?,
permalinkData: PermalinkData.RoomLink,
buildTask: Boolean
) {
val session = activeSessionHolder.getSafeActiveSession() ?: return
if (roomId == null) {
context.toast(R.string.room_error_not_found)
return
}
val roomSummary = session.getRoomSummary(roomId)
val eventId = permalinkData.eventId
val roomAlias = permalinkData.getRoomAliasOrNull()
return when {
roomSummary?.membership?.isActive().orFalse() -> {
navigator.openRoom(context, roomId, eventId, buildTask)
@ -128,7 +152,8 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
roomAlias = roomAlias ?: roomSummary?.canonicalAlias,
roomName = roomSummary?.displayName,
avatarUrl = roomSummary?.avatarUrl,
buildTask = buildTask
buildTask = buildTask,
homeServers = permalinkData.viaParameters
)
navigator.openRoomPreview(context, roomPreviewData)
}

View File

@ -38,7 +38,7 @@ data class RoomPreviewData(
val topic: String? = null,
val worldReadable: Boolean = false,
val avatarUrl: String? = null,
val homeServer: String? = null,
val homeServers: List<String> = emptyList(),
val buildTask: Boolean = false
) : Parcelable {
val matrixItem: MatrixItem
@ -64,7 +64,7 @@ class RoomPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
topic = publicRoom.topic,
worldReadable = publicRoom.worldReadable,
avatarUrl = publicRoom.avatarUrl,
homeServer = roomDirectoryData.homeServer
homeServers = listOfNotNull(roomDirectoryData.homeServer)
)
return newIntent(context, roomPreviewData)
}

View File

@ -106,10 +106,7 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini
Timber.w("Try to join an already joining room. Should not happen")
return@withState
}
val viaServers = state.homeServer?.let {
listOf(it)
} ?: emptyList()
session.joinRoom(state.roomId, viaServers = viaServers, callback = object : MatrixCallback<Unit> {
session.joinRoom(state.roomId, viaServers = state.homeServers, callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
// We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data.
// Instead, we wait for the room to be joined

View File

@ -24,10 +24,9 @@ data class RoomPreviewViewState(
val roomId: String = "",
val roomAlias: String? = null,
/**
* The server name (might be null)
* Set null when the server is the current user's home server.
* Can be empty when the server is the current user's home server.
*/
val homeServer: String? = null,
val homeServers: List<String> = emptyList(),
// Current state of the room in preview
val roomJoinState: JoinState = JoinState.NOT_JOINED,
// Last error of join room request
@ -37,6 +36,6 @@ data class RoomPreviewViewState(
constructor(args: RoomPreviewData) : this(
roomId = args.roomId,
roomAlias = args.roomAlias,
homeServer = args.homeServer
homeServers = args.homeServers
)
}