mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Room alias and matrix.to link: we can now open a room though roomAlias as long as it's a joined one
This commit is contained in:
parent
02febfb01b
commit
abf0796794
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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.rx
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import io.reactivex.CompletableEmitter
|
||||
|
||||
internal class MatrixCallbackCompletable<T>(private val completableEmitter: CompletableEmitter) : MatrixCallback<T> {
|
||||
|
||||
override fun onSuccess(data: T) {
|
||||
completableEmitter.onComplete()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
completableEmitter.tryOnError(failure)
|
||||
}
|
||||
}
|
||||
|
||||
fun Cancelable.toCompletable(completableEmitter: CompletableEmitter) {
|
||||
completableEmitter.setCancellable {
|
||||
this.cancel()
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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.rx
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import io.reactivex.SingleEmitter
|
||||
|
||||
internal class MatrixCallbackSingle<T>(private val singleEmitter: SingleEmitter<T>) : MatrixCallback<T> {
|
||||
|
||||
override fun onSuccess(data: T) {
|
||||
singleEmitter.onSuccess(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
singleEmitter.tryOnError(failure)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Cancelable.toSingle(singleEmitter: SingleEmitter<T>) {
|
||||
singleEmitter.setCancellable {
|
||||
this.cancel()
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.rx
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
|
||||
fun <T> singleBuilder(builder: (callback: MatrixCallback<T>) -> Cancelable): Single<T> = Single.create {
|
||||
val callback: MatrixCallback<T> = object : MatrixCallback<T> {
|
||||
override fun onSuccess(data: T) {
|
||||
it.onSuccess(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
it.tryOnError(failure)
|
||||
}
|
||||
}
|
||||
val cancelable = builder(callback)
|
||||
it.setCancellable {
|
||||
cancelable.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> completableBuilder(builder: (callback: MatrixCallback<T>) -> Cancelable): Completable = Completable.create {
|
||||
val callback: MatrixCallback<T> = object : MatrixCallback<T> {
|
||||
override fun onSuccess(data: T) {
|
||||
it.onComplete()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
it.tryOnError(failure)
|
||||
}
|
||||
}
|
||||
val cancelable = builder(callback)
|
||||
it.setCancellable {
|
||||
cancelable.cancel()
|
||||
}
|
||||
}
|
@ -53,13 +53,13 @@ class RxRoom(private val room: Room) {
|
||||
return room.getMyReadReceiptLive().asObservable()
|
||||
}
|
||||
|
||||
fun loadRoomMembersIfNeeded(): Single<Unit> = Single.create {
|
||||
room.loadRoomMembersIfNeeded(MatrixCallbackSingle(it)).toSingle(it)
|
||||
fun loadRoomMembersIfNeeded(): Single<Unit> = singleBuilder {
|
||||
room.loadRoomMembersIfNeeded(it)
|
||||
}
|
||||
|
||||
fun joinRoom(reason: String? = null,
|
||||
viaServers: List<String> = emptyList()): Single<Unit> = Single.create {
|
||||
room.join(reason, viaServers, MatrixCallbackSingle(it)).toSingle(it)
|
||||
viaServers: List<String> = emptyList()): Single<Unit> = singleBuilder {
|
||||
room.join(reason, viaServers, it)
|
||||
}
|
||||
|
||||
fun liveEventReadReceipts(eventId: String): Observable<List<ReadReceipt>> {
|
||||
|
@ -66,20 +66,25 @@ class RxSession(private val session: Session) {
|
||||
return session.livePagedUsers(filter).asObservable()
|
||||
}
|
||||
|
||||
fun createRoom(roomParams: CreateRoomParams): Single<String> = Single.create {
|
||||
session.createRoom(roomParams, MatrixCallbackSingle(it)).toSingle(it)
|
||||
fun createRoom(roomParams: CreateRoomParams): Single<String> = singleBuilder {
|
||||
session.createRoom(roomParams, it)
|
||||
}
|
||||
|
||||
fun searchUsersDirectory(search: String,
|
||||
limit: Int,
|
||||
excludedUserIds: Set<String>): Single<List<User>> = Single.create {
|
||||
session.searchUsersDirectory(search, limit, excludedUserIds, MatrixCallbackSingle(it)).toSingle(it)
|
||||
excludedUserIds: Set<String>): Single<List<User>> = singleBuilder {
|
||||
session.searchUsersDirectory(search, limit, excludedUserIds, it)
|
||||
}
|
||||
|
||||
fun joinRoom(roomId: String,
|
||||
reason: String? = null,
|
||||
viaServers: List<String> = emptyList()): Single<Unit> = Single.create {
|
||||
session.joinRoom(roomId, reason, viaServers, MatrixCallbackSingle(it)).toSingle(it)
|
||||
viaServers: List<String> = emptyList()): Single<Unit> = singleBuilder {
|
||||
session.joinRoom(roomId, reason, viaServers, it)
|
||||
}
|
||||
|
||||
fun getRoomIdByAlias(roomAlias: String,
|
||||
searchOnServer: Boolean): Single<Optional<String>> = singleBuilder {
|
||||
session.getRoomIdByAlias(roomAlias, searchOnServer, it)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,7 @@ import android.net.Uri
|
||||
*/
|
||||
sealed class PermalinkData {
|
||||
|
||||
data class EventLink(val roomIdOrAlias: String, val eventId: String, val isRoomAlias: Boolean) : PermalinkData()
|
||||
|
||||
data class RoomLink(val roomIdOrAlias: String, val isRoomAlias: Boolean) : PermalinkData()
|
||||
data class RoomLink(val roomIdOrAlias: String, val isRoomAlias: Boolean, val eventId: String?) : PermalinkData()
|
||||
|
||||
data class UserLink(val userId: String) : PermalinkData()
|
||||
|
||||
|
@ -18,8 +18,6 @@ package im.vector.matrix.android.api.permalinks
|
||||
|
||||
import android.net.Uri
|
||||
import im.vector.matrix.android.api.MatrixPatterns
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* This class turns an uri to a [PermalinkData]
|
||||
@ -65,18 +63,16 @@ object PermalinkParser {
|
||||
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, isRoomAlias = false)
|
||||
} else {
|
||||
PermalinkData.RoomLink(roomIdOrAlias = identifier, isRoomAlias = false)
|
||||
val eventId = extraParameter.takeIf {
|
||||
!it.isNullOrEmpty() && MatrixPatterns.isEventId(it)
|
||||
}
|
||||
PermalinkData.RoomLink(roomIdOrAlias = identifier, isRoomAlias = false, eventId = eventId)
|
||||
}
|
||||
MatrixPatterns.isRoomAlias(identifier) -> {
|
||||
if (!extraParameter.isNullOrEmpty() && MatrixPatterns.isEventId(extraParameter)) {
|
||||
PermalinkData.EventLink(roomIdOrAlias = identifier, eventId = extraParameter, isRoomAlias = true)
|
||||
} else {
|
||||
PermalinkData.RoomLink(roomIdOrAlias = identifier, isRoomAlias = true)
|
||||
val eventId = extraParameter.takeIf {
|
||||
!it.isNullOrEmpty() && MatrixPatterns.isEventId(it)
|
||||
}
|
||||
PermalinkData.RoomLink(roomIdOrAlias = identifier, isRoomAlias = true, eventId = eventId)
|
||||
}
|
||||
else -> PermalinkData.FallbackLink(uri)
|
||||
}
|
||||
|
@ -18,10 +18,10 @@ package im.vector.matrix.android.api.session.room
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.internal.session.room.alias.RoomAliasDescription
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
|
||||
/**
|
||||
* This interface defines methods to get rooms. It's implemented at the session level.
|
||||
@ -80,5 +80,6 @@ interface RoomService {
|
||||
* Resolve a room alias to a room ID.
|
||||
*/
|
||||
fun getRoomIdByAlias(roomAlias: String,
|
||||
callback: MatrixCallback<String?>): Cancelable
|
||||
searchOnServer: Boolean,
|
||||
callback: MatrixCallback<Optional<String>>): Cancelable
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ interface MembershipService {
|
||||
/**
|
||||
* Join the room, or accept an invitation.
|
||||
*/
|
||||
|
||||
fun join(reason: String? = null,
|
||||
viaServers: List<String> = emptyList(),
|
||||
callback: MatrixCallback<Unit>): Cancelable
|
||||
|
@ -19,7 +19,6 @@ package im.vector.matrix.android.api.session.room.model
|
||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||
import im.vector.matrix.android.api.session.room.send.UserDraft
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import io.realm.RealmList
|
||||
|
||||
/**
|
||||
* This class holds some data of a room.
|
||||
|
@ -41,7 +41,8 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||
var userDrafts: UserDraftsEntity? = null,
|
||||
var breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS
|
||||
var canonicalAlias: String? = null,
|
||||
var aliases: RealmList<String> = RealmList()
|
||||
var aliases: RealmList<String> = RealmList(),
|
||||
var flatAliases: String = ""
|
||||
) : RealmObject() {
|
||||
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
|
@ -40,7 +40,7 @@ internal fun RoomSummaryEntity.Companion.findByAlias(realm: Realm, roomAlias: St
|
||||
return roomSummary
|
||||
}
|
||||
return realm.where<RoomSummaryEntity>()
|
||||
.`in`(RoomSummaryEntityFields.ALIASES.`$`, arrayOf(roomAlias))
|
||||
.contains(RoomSummaryEntityFields.FLAT_ALIASES, "|$roomAlias")
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,11 @@ import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.internal.session.room.alias.RoomAliasDescription
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.VersioningState
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
@ -51,7 +51,6 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona
|
||||
private val roomFactory: RoomFactory,
|
||||
private val taskExecutor: TaskExecutor) : RoomService {
|
||||
|
||||
|
||||
override fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback<String>): Cancelable {
|
||||
return createRoomTask
|
||||
.configureWith(createRoomParams) {
|
||||
@ -116,9 +115,9 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override fun getRoomIdByAlias(roomAlias: String, callback: MatrixCallback<String?>): Cancelable {
|
||||
override fun getRoomIdByAlias(roomAlias: String, searchOnServer: Boolean, callback: MatrixCallback<Optional<String>>): Cancelable {
|
||||
return roomIdByAliasTask
|
||||
.configureWith(GetRoomIdByAliasTask.Params(roomAlias)) {
|
||||
.configureWith(GetRoomIdByAliasTask.Params(roomAlias, searchOnServer)) {
|
||||
this.callback = callback
|
||||
}
|
||||
.executeBy(taskExecutor)
|
||||
|
@ -110,7 +110,7 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
|
||||
val roomAliases = ContentMapper.map(lastAliasesEvent?.content).toModel<RoomAliasesContent>()?.aliases ?: emptyList()
|
||||
roomSummaryEntity.aliases.clear()
|
||||
roomSummaryEntity.aliases.addAll(roomAliases)
|
||||
|
||||
roomSummaryEntity.flatAliases = roomAliases.joinToString(separator = "|", prefix = "|")
|
||||
|
||||
if (updateMembers) {
|
||||
val otherRoomMembers = RoomMembers(realm, roomId)
|
||||
|
@ -17,6 +17,7 @@
|
||||
package im.vector.matrix.android.internal.session.room.alias
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.findByAlias
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
@ -25,24 +26,29 @@ import im.vector.matrix.android.internal.task.Task
|
||||
import io.realm.Realm
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetRoomIdByAliasTask : Task<GetRoomIdByAliasTask.Params, String?> {
|
||||
internal interface GetRoomIdByAliasTask : Task<GetRoomIdByAliasTask.Params, Optional<String>> {
|
||||
data class Params(
|
||||
val roomAlias: String
|
||||
val roomAlias: String,
|
||||
val searchOnServer: Boolean
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultGetRoomIdByAliasTask @Inject constructor(private val monarchy: Monarchy,
|
||||
private val roomAPI: RoomAPI) : GetRoomIdByAliasTask {
|
||||
|
||||
override suspend fun execute(params: GetRoomIdByAliasTask.Params): String? {
|
||||
val roomId = Realm.getInstance(monarchy.realmConfiguration).use {
|
||||
override suspend fun execute(params: GetRoomIdByAliasTask.Params): Optional<String> {
|
||||
var roomId = Realm.getInstance(monarchy.realmConfiguration).use {
|
||||
RoomSummaryEntity.findByAlias(it, params.roomAlias)?.roomId
|
||||
}
|
||||
if (roomId != null) {
|
||||
return roomId
|
||||
return if (roomId != null) {
|
||||
Optional.from(roomId)
|
||||
} else if (!params.searchOnServer) {
|
||||
Optional.from<String>(null)
|
||||
} else {
|
||||
roomId = executeRequest<RoomAliasDescription> {
|
||||
apiCall = roomAPI.getRoomIdByAlias(params.roomAlias)
|
||||
}.roomId
|
||||
Optional.from(roomId)
|
||||
}
|
||||
return executeRequest<RoomAliasDescription> {
|
||||
apiCall = roomAPI.getRoomIdByAlias(params.roomAlias)
|
||||
}.roomId
|
||||
}
|
||||
}
|
||||
|
@ -113,6 +113,8 @@ import im.vector.riotx.features.reactions.EmojiReactionPickerActivity
|
||||
import im.vector.riotx.features.settings.VectorPreferences
|
||||
import im.vector.riotx.features.share.SharedData
|
||||
import im.vector.riotx.features.themes.ThemeUtils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
||||
import kotlinx.android.synthetic.main.merge_composer_layout.view.*
|
||||
@ -851,30 +853,33 @@ class RoomDetailFragment @Inject constructor(
|
||||
// TimelineEventController.Callback ************************************************************
|
||||
|
||||
override fun onUrlClicked(url: String): Boolean {
|
||||
val managed = permalinkHandler.launch(requireActivity(), url, object : NavigateToRoomInterceptor {
|
||||
override fun navToRoom(roomId: String, eventId: String?): Boolean {
|
||||
// Same room?
|
||||
if (roomId == roomDetailArgs.roomId) {
|
||||
// Navigation to same room
|
||||
if (eventId == null) {
|
||||
showSnackWithMessage(getString(R.string.navigate_to_room_when_already_in_the_room))
|
||||
} else {
|
||||
// Highlight and scroll to this event
|
||||
roomDetailViewModel.handle(RoomDetailAction.NavigateToEvent(eventId, true))
|
||||
permalinkHandler
|
||||
.launch(requireActivity(), url, object : NavigateToRoomInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?): Boolean {
|
||||
// Same room?
|
||||
if (roomId == roomDetailArgs.roomId) {
|
||||
// Navigation to same room
|
||||
if (eventId == null) {
|
||||
showSnackWithMessage(getString(R.string.navigate_to_room_when_already_in_the_room))
|
||||
} else {
|
||||
// Highlight and scroll to this event
|
||||
roomDetailViewModel.handle(RoomDetailAction.NavigateToEvent(eventId, true))
|
||||
}
|
||||
return true
|
||||
}
|
||||
// Not handled
|
||||
return false
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { managed ->
|
||||
if (!managed) {
|
||||
// Open in external browser, in a new Tab
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Not handled
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
if (!managed) {
|
||||
// Open in external browser, in a new Tab
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
|
||||
.disposeOnDestroyView()
|
||||
// In fact it is always managed
|
||||
return true
|
||||
}
|
||||
@ -1022,12 +1027,15 @@ class RoomDetailFragment @Inject constructor(
|
||||
}
|
||||
|
||||
override fun onRoomCreateLinkClicked(url: String) {
|
||||
permalinkHandler.launch(requireContext(), url, object : NavigateToRoomInterceptor {
|
||||
override fun navToRoom(roomId: String, eventId: String?): Boolean {
|
||||
requireActivity().finish()
|
||||
return false
|
||||
}
|
||||
})
|
||||
permalinkHandler
|
||||
.launch(requireContext(), url, object : NavigateToRoomInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?): Boolean {
|
||||
requireActivity().finish()
|
||||
return false
|
||||
}
|
||||
})
|
||||
.subscribe()
|
||||
.disposeOnDestroyView()
|
||||
}
|
||||
|
||||
override fun onReadReceiptsClicked(readReceipts: List<ReadReceiptData>) {
|
||||
|
@ -40,7 +40,6 @@ import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import androidx.core.app.TaskStackBuilder
|
||||
|
||||
|
||||
@Singleton
|
||||
class DefaultNavigator @Inject constructor() : Navigator {
|
||||
|
||||
@ -56,7 +55,7 @@ class DefaultNavigator @Inject constructor() : Navigator {
|
||||
}
|
||||
}
|
||||
|
||||
override fun openNotJoinedRoom(context: Context, roomIdOrAlias: String, eventId: String?, buildTask: Boolean) {
|
||||
override fun openNotJoinedRoom(context: Context, roomIdOrAlias: String?, eventId: String?, buildTask: Boolean) {
|
||||
if (context is VectorBaseActivity) {
|
||||
context.notImplemented("Open not joined room")
|
||||
} else {
|
||||
@ -64,13 +63,20 @@ class DefaultNavigator @Inject constructor() : Navigator {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun openGroupDetail(groupId: String, context: Context, buildTask: Boolean) {
|
||||
Timber.v("Open group detail $groupId")
|
||||
if (context is VectorBaseActivity) {
|
||||
context.notImplemented("Open group detail")
|
||||
} else {
|
||||
context.toast(R.string.not_implemented)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openUserDetail(userId: String, context: Context, buildTask: Boolean) {
|
||||
Timber.v("Open user detail $userId")
|
||||
if (context is VectorBaseActivity) {
|
||||
context.notImplemented("Open user detail")
|
||||
} else {
|
||||
context.toast(R.string.not_implemented)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openRoomForSharing(activity: Activity, roomId: String, sharedData: SharedData) {
|
||||
|
@ -27,7 +27,7 @@ interface Navigator {
|
||||
|
||||
fun openRoomForSharing(activity: Activity, roomId: String, sharedData: SharedData)
|
||||
|
||||
fun openNotJoinedRoom(context: Context, roomIdOrAlias: String, eventId: String? = null, buildTask: Boolean = false)
|
||||
fun openNotJoinedRoom(context: Context, roomIdOrAlias: String?, eventId: String? = null, buildTask: Boolean = false)
|
||||
|
||||
fun openRoomPreview(publicRoom: PublicRoom, context: Context)
|
||||
|
||||
|
@ -21,7 +21,12 @@ import android.net.Uri
|
||||
import im.vector.matrix.android.api.permalinks.PermalinkData
|
||||
import im.vector.matrix.android.api.permalinks.PermalinkParser
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotx.features.navigation.Navigator
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import javax.inject.Inject
|
||||
|
||||
class PermalinkHandler @Inject constructor(private val session: Session,
|
||||
@ -32,7 +37,7 @@ class PermalinkHandler @Inject constructor(private val session: Session,
|
||||
deepLink: String?,
|
||||
navigateToRoomInterceptor: NavigateToRoomInterceptor? = null,
|
||||
buildTask: Boolean = false
|
||||
): Boolean {
|
||||
): Single<Boolean> {
|
||||
val uri = deepLink?.let { Uri.parse(it) }
|
||||
return launch(context, uri, navigateToRoomInterceptor, buildTask)
|
||||
}
|
||||
@ -42,47 +47,53 @@ class PermalinkHandler @Inject constructor(private val session: Session,
|
||||
deepLink: Uri?,
|
||||
navigateToRoomInterceptor: NavigateToRoomInterceptor? = null,
|
||||
buildTask: Boolean = false
|
||||
): Boolean {
|
||||
): Single<Boolean> {
|
||||
if (deepLink == null) {
|
||||
return false
|
||||
return Single.just(false)
|
||||
}
|
||||
|
||||
return when (val permalinkData = PermalinkParser.parse(deepLink)) {
|
||||
is PermalinkData.EventLink -> {
|
||||
if (navigateToRoomInterceptor?.navToRoom(permalinkData.roomIdOrAlias, permalinkData.eventId) != true) {
|
||||
openRoom(context, permalinkData.roomIdOrAlias, permalinkData.eventId, buildTask)
|
||||
}
|
||||
true
|
||||
}
|
||||
is PermalinkData.RoomLink -> {
|
||||
if (navigateToRoomInterceptor?.navToRoom(permalinkData.roomIdOrAlias) != true) {
|
||||
openRoom(context, permalinkData.roomIdOrAlias, null, buildTask)
|
||||
}
|
||||
|
||||
true
|
||||
permalinkData.getRoomId()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map {
|
||||
val roomId = it.getOrNull()
|
||||
if (navigateToRoomInterceptor?.navToRoom(roomId) != true) {
|
||||
openRoom(context, roomId, permalinkData.eventId, buildTask)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
is PermalinkData.GroupLink -> {
|
||||
navigator.openGroupDetail(permalinkData.groupId, context, buildTask)
|
||||
false
|
||||
Single.just(true)
|
||||
}
|
||||
is PermalinkData.UserLink -> {
|
||||
navigator.openUserDetail(permalinkData.userId, context, buildTask)
|
||||
true
|
||||
Single.just(false)
|
||||
}
|
||||
is PermalinkData.FallbackLink -> {
|
||||
false
|
||||
Single.just(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun PermalinkData.RoomLink.getRoomId(): Single<Optional<String>> {
|
||||
return if (isRoomAlias) {
|
||||
// At the moment we are not fetching on the server as we don't handle not join room
|
||||
session.rx().getRoomIdByAlias(roomIdOrAlias, false).subscribeOn(Schedulers.io())
|
||||
} else {
|
||||
Single.just(Optional.from(roomIdOrAlias))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open room either joined, or not unknown
|
||||
*/
|
||||
private fun openRoom(context: Context, roomIdOrAlias: String, eventId: String? = null, buildTask: Boolean) {
|
||||
if (session.getRoom(roomIdOrAlias) != null) {
|
||||
navigator.openRoom(context, roomIdOrAlias, eventId, buildTask)
|
||||
private fun openRoom(context: Context, roomId: String?, eventId: String? = null, buildTask: Boolean) {
|
||||
return if (roomId != null && session.getRoom(roomId) != null) {
|
||||
navigator.openRoom(context, roomId, eventId, buildTask)
|
||||
} else {
|
||||
navigator.openNotJoinedRoom(context, roomIdOrAlias, eventId, buildTask)
|
||||
navigator.openNotJoinedRoom(context, roomId, eventId, buildTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,5 +103,5 @@ interface NavigateToRoomInterceptor {
|
||||
/**
|
||||
* Return true if the navigation has been intercepted
|
||||
*/
|
||||
fun navToRoom(roomId: String, eventId: String? = null): Boolean
|
||||
fun navToRoom(roomId: String?, eventId: String? = null): Boolean
|
||||
}
|
||||
|
@ -18,11 +18,14 @@ package im.vector.riotx.features.permalink
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
import im.vector.riotx.core.utils.toast
|
||||
import im.vector.riotx.features.login.LoginActivity
|
||||
import timber.log.Timber
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.debug.activity_test_material_theme.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class PermalinkHandlerActivity : VectorBaseActivity() {
|
||||
@ -36,18 +39,23 @@ class PermalinkHandlerActivity : VectorBaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
// If we are not logged in, stop the sharing process and open login screen.
|
||||
// In the future, we might want to relaunch the sharing process after login.
|
||||
setContentView(R.layout.activity)
|
||||
// If we are not logged in, open login screen.
|
||||
// In the future, we might want to relaunch the process after login.
|
||||
if (!sessionHolder.hasActiveSession()) {
|
||||
startLoginActivity()
|
||||
return
|
||||
}
|
||||
val uri = intent.dataString
|
||||
val isHandled = permalinkHandler.launch(this, uri, buildTask = true)
|
||||
if (!isHandled) {
|
||||
Timber.v("Couldn't handle permalink")
|
||||
}
|
||||
finish()
|
||||
permalinkHandler.launch(this, uri, buildTask = true)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { isHandled ->
|
||||
if (!isHandled) {
|
||||
toast("Your matrix.to link was malformed")
|
||||
}
|
||||
finish()
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
}
|
||||
|
||||
private fun startLoginActivity() {
|
||||
@ -56,6 +64,4 @@ class PermalinkHandlerActivity : VectorBaseActivity() {
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user