mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 17:35:54 +03:00
Create the DM when sending an event
This commit is contained in:
parent
da70d520bc
commit
72896f1c8a
6 changed files with 319 additions and 17 deletions
1
changelog.d/5525.wip
Normal file
1
changelog.d/5525.wip
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Create DM room only on first message - Create the DM and navigate to the new room after sending an event
|
|
@ -16,10 +16,12 @@
|
||||||
package org.matrix.android.sdk.internal.crypto.tasks
|
package org.matrix.android.sdk.internal.crypto.tasks
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
|
||||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||||
import org.matrix.android.sdk.internal.network.executeRequest
|
import org.matrix.android.sdk.internal.network.executeRequest
|
||||||
import org.matrix.android.sdk.internal.session.room.RoomAPI
|
import org.matrix.android.sdk.internal.session.room.RoomAPI
|
||||||
|
import org.matrix.android.sdk.internal.session.room.create.CreateRoomFromLocalRoomTask
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
|
import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
|
||||||
import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
|
import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
|
||||||
import org.matrix.android.sdk.internal.task.Task
|
import org.matrix.android.sdk.internal.task.Task
|
||||||
|
@ -37,12 +39,18 @@ internal class DefaultSendEventTask @Inject constructor(
|
||||||
private val localEchoRepository: LocalEchoRepository,
|
private val localEchoRepository: LocalEchoRepository,
|
||||||
private val encryptEventTask: EncryptEventTask,
|
private val encryptEventTask: EncryptEventTask,
|
||||||
private val loadRoomMembersTask: LoadRoomMembersTask,
|
private val loadRoomMembersTask: LoadRoomMembersTask,
|
||||||
|
private val createRoomFromLocalRoomTask: CreateRoomFromLocalRoomTask,
|
||||||
private val roomAPI: RoomAPI,
|
private val roomAPI: RoomAPI,
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver
|
private val globalErrorReceiver: GlobalErrorReceiver
|
||||||
) : SendEventTask {
|
) : SendEventTask {
|
||||||
|
|
||||||
override suspend fun execute(params: SendEventTask.Params): String {
|
override suspend fun execute(params: SendEventTask.Params): String {
|
||||||
try {
|
try {
|
||||||
|
if (RoomLocalEcho.isLocalEchoId(params.event.roomId.orEmpty())) {
|
||||||
|
// Room is local, so create a real one and send the event to this new room
|
||||||
|
return createRoomAndSendEvent(params)
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure to load all members in the room before sending the event.
|
// Make sure to load all members in the room before sending the event.
|
||||||
params.event.roomId
|
params.event.roomId
|
||||||
?.takeIf { params.encrypt }
|
?.takeIf { params.encrypt }
|
||||||
|
@ -78,6 +86,12 @@ internal class DefaultSendEventTask @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun createRoomAndSendEvent(params: SendEventTask.Params): String {
|
||||||
|
val roomId = createRoomFromLocalRoomTask.execute(CreateRoomFromLocalRoomTask.Params(params.event.roomId.orEmpty()))
|
||||||
|
Timber.d("State event: convert local room (${params.event.roomId}) to existing room ($roomId) before sending the event.")
|
||||||
|
return execute(params.copy(event = params.event.copy(roomId = roomId)))
|
||||||
|
}
|
||||||
|
|
||||||
@Throws
|
@Throws
|
||||||
private suspend fun handleEncryption(params: SendEventTask.Params): Event {
|
private suspend fun handleEncryption(params: SendEventTask.Params): Event {
|
||||||
if (params.encrypt && !params.event.isEncrypted()) {
|
if (params.encrypt && !params.event.isEncrypted()) {
|
||||||
|
|
|
@ -44,8 +44,10 @@ import org.matrix.android.sdk.internal.session.room.alias.DeleteRoomAliasTask
|
||||||
import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask
|
import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask
|
||||||
import org.matrix.android.sdk.internal.session.room.alias.GetRoomLocalAliasesTask
|
import org.matrix.android.sdk.internal.session.room.alias.GetRoomLocalAliasesTask
|
||||||
import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomTask
|
import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomTask
|
||||||
|
import org.matrix.android.sdk.internal.session.room.create.CreateRoomFromLocalRoomTask
|
||||||
import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
|
import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
|
||||||
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateLocalRoomTask
|
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateLocalRoomTask
|
||||||
|
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomFromLocalRoomTask
|
||||||
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomTask
|
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomTask
|
||||||
import org.matrix.android.sdk.internal.session.room.delete.DefaultDeleteLocalRoomTask
|
import org.matrix.android.sdk.internal.session.room.delete.DefaultDeleteLocalRoomTask
|
||||||
import org.matrix.android.sdk.internal.session.room.delete.DeleteLocalRoomTask
|
import org.matrix.android.sdk.internal.session.room.delete.DeleteLocalRoomTask
|
||||||
|
@ -213,6 +215,9 @@ internal abstract class RoomModule {
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindCreateLocalRoomTask(task: DefaultCreateLocalRoomTask): CreateLocalRoomTask
|
abstract fun bindCreateLocalRoomTask(task: DefaultCreateLocalRoomTask): CreateLocalRoomTask
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindCreateRoomFromLocalRoomTask(task: DefaultCreateRoomFromLocalRoomTask): CreateRoomFromLocalRoomTask
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindDeleteLocalRoomTask(task: DefaultDeleteLocalRoomTask): DeleteLocalRoomTask
|
abstract fun bindDeleteLocalRoomTask(task: DefaultDeleteLocalRoomTask): DeleteLocalRoomTask
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,252 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* 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 org.matrix.android.sdk.internal.session.room.create
|
||||||
|
|
||||||
|
import android.util.Patterns
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import com.google.i18n.phonenumbers.NumberParseException
|
||||||
|
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import io.realm.Realm
|
||||||
|
import org.matrix.android.sdk.api.extensions.ensurePrefix
|
||||||
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
|
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomAliasesContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomNameContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.tombstone.RoomTombstoneContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||||
|
import org.matrix.android.sdk.internal.database.mapper.asDomain
|
||||||
|
import org.matrix.android.sdk.internal.database.mapper.toEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventInsertType
|
||||||
|
import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
|
||||||
|
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
||||||
|
import org.matrix.android.sdk.internal.database.query.where
|
||||||
|
import org.matrix.android.sdk.internal.database.query.whereRoomId
|
||||||
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
|
import org.matrix.android.sdk.internal.di.UserId
|
||||||
|
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
|
||||||
|
import org.matrix.android.sdk.internal.task.Task
|
||||||
|
import org.matrix.android.sdk.internal.util.awaitTransaction
|
||||||
|
import org.matrix.android.sdk.internal.util.time.Clock
|
||||||
|
import java.util.UUID
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Room from a "fake" local room.
|
||||||
|
* The configuration of the local room will be use to configure the new room.
|
||||||
|
* The potential local room members will also be invited to this new room.
|
||||||
|
*
|
||||||
|
* A "fake" local tombstone event will be created to indicate that the local room has been replacing by the new one.
|
||||||
|
*/
|
||||||
|
internal interface CreateRoomFromLocalRoomTask : Task<CreateRoomFromLocalRoomTask.Params, String> {
|
||||||
|
data class Params(val localRoomId: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultCreateRoomFromLocalRoomTask @Inject constructor(
|
||||||
|
@UserId private val userId: String,
|
||||||
|
@SessionDatabase private val monarchy: Monarchy,
|
||||||
|
private val createRoomTask: CreateRoomTask,
|
||||||
|
private val stateEventDataSource: StateEventDataSource,
|
||||||
|
private val clock: Clock,
|
||||||
|
) : CreateRoomFromLocalRoomTask {
|
||||||
|
|
||||||
|
override suspend fun execute(params: CreateRoomFromLocalRoomTask.Params): String {
|
||||||
|
val replacementRoomId = stateEventDataSource.getStateEvent(params.localRoomId, EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.NoCondition)
|
||||||
|
?.content?.toModel<RoomTombstoneContent>()
|
||||||
|
?.replacementRoomId
|
||||||
|
|
||||||
|
if (replacementRoomId != null) {
|
||||||
|
return replacementRoomId
|
||||||
|
}
|
||||||
|
|
||||||
|
val createRoomParams = getCreateRoomParams(params)
|
||||||
|
val roomId = createRoomTask.execute(createRoomParams)
|
||||||
|
createTombstoneEvent(params, roomId)
|
||||||
|
return roomId
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the room configuration by parsing the state events related to the local room.
|
||||||
|
*/
|
||||||
|
private suspend fun getCreateRoomParams(params: CreateRoomFromLocalRoomTask.Params): CreateRoomParams {
|
||||||
|
var createRoomParams = CreateRoomParams()
|
||||||
|
monarchy.awaitTransaction { realm ->
|
||||||
|
val stateEvents = CurrentStateEventEntity.whereRoomId(realm, params.localRoomId).findAll()
|
||||||
|
stateEvents.forEach { event ->
|
||||||
|
createRoomParams = when (event.type) {
|
||||||
|
EventType.STATE_ROOM_MEMBER -> handleRoomMemberEvent(realm, event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_HISTORY_VISIBILITY -> handleRoomHistoryVisibilityEvent(realm, event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_ALIASES -> handleRoomAliasesEvent(realm, event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_AVATAR -> handleRoomAvatarEvent(realm, event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_CANONICAL_ALIAS -> handleRoomCanonicalAliasEvent(realm, event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_GUEST_ACCESS -> handleRoomGuestAccessEvent(realm, event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_ENCRYPTION -> handleRoomEncryptionEvent(createRoomParams)
|
||||||
|
EventType.STATE_ROOM_POWER_LEVELS -> handleRoomPowerRoomLevelsEvent(realm, event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_NAME -> handleRoomNameEvent(realm, event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_TOPIC -> handleRoomTopicEvent(realm, event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_THIRD_PARTY_INVITE -> handleRoomThirdPartyInviteEvent(event, createRoomParams)
|
||||||
|
EventType.STATE_ROOM_JOIN_RULES -> handleRoomJoinRulesEvent(realm, event, createRoomParams)
|
||||||
|
else -> createRoomParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return createRoomParams
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Tombstone event to indicate that the local room has been replaced by a new one.
|
||||||
|
*/
|
||||||
|
private suspend fun createTombstoneEvent(params: CreateRoomFromLocalRoomTask.Params, roomId: String) {
|
||||||
|
val now = clock.epochMillis()
|
||||||
|
val event = Event(
|
||||||
|
type = EventType.STATE_ROOM_TOMBSTONE,
|
||||||
|
senderId = userId,
|
||||||
|
originServerTs = now,
|
||||||
|
stateKey = "",
|
||||||
|
eventId = UUID.randomUUID().toString(),
|
||||||
|
content = RoomTombstoneContent(
|
||||||
|
replacementRoomId = roomId
|
||||||
|
).toContent()
|
||||||
|
)
|
||||||
|
monarchy.awaitTransaction { realm ->
|
||||||
|
val eventEntity = event.toEntity(params.localRoomId, SendState.SYNCED, now).copyToRealmOrIgnore(realm, EventInsertType.INCREMENTAL_SYNC)
|
||||||
|
if (event.stateKey != null && event.type != null && event.eventId != null) {
|
||||||
|
CurrentStateEventEntity.getOrCreate(realm, params.localRoomId, event.stateKey, event.type).apply {
|
||||||
|
eventId = event.eventId
|
||||||
|
root = eventEntity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================================
|
||||||
|
* Local events handling
|
||||||
|
* ========================================================================================== */
|
||||||
|
|
||||||
|
private fun handleRoomMemberEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<RoomMemberContent>(realm, event.eventId) ?: return@apply
|
||||||
|
invitedUserIds.add(event.stateKey)
|
||||||
|
if (content.isDirect) {
|
||||||
|
setDirectMessage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomHistoryVisibilityEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<RoomHistoryVisibilityContent>(realm, event.eventId) ?: return@apply
|
||||||
|
historyVisibility = content.historyVisibility
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomAliasesEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<RoomAliasesContent>(realm, event.eventId) ?: return@apply
|
||||||
|
roomAliasName = content.aliases.firstOrNull()?.substringAfter("#")?.substringBefore(":")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomAvatarEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<RoomAvatarContent>(realm, event.eventId) ?: return@apply
|
||||||
|
avatarUri = content.avatarUrl?.toUri()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomCanonicalAliasEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<RoomCanonicalAliasContent>(realm, event.eventId) ?: return@apply
|
||||||
|
roomAliasName = content.canonicalAlias?.substringAfter("#")?.substringBefore(":")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomGuestAccessEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<RoomGuestAccessContent>(realm, event.eventId) ?: return@apply
|
||||||
|
guestAccess = content.guestAccess
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomEncryptionEvent(params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
// Having an encryption event means the room is encrypted, so just enable it again
|
||||||
|
enableEncryption()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomPowerRoomLevelsEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<PowerLevelsContent>(realm, event.eventId) ?: return@apply
|
||||||
|
powerLevelContentOverride = content
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomNameEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<RoomNameContent>(realm, event.eventId) ?: return@apply
|
||||||
|
name = content.name
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomTopicEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<RoomTopicContent>(realm, event.eventId) ?: return@apply
|
||||||
|
topic = content.topic
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomThirdPartyInviteEvent(event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
when {
|
||||||
|
event.stateKey.isEmail() -> invite3pids.add(ThreePid.Email(event.stateKey))
|
||||||
|
event.stateKey.isMsisdn() -> invite3pids.add(ThreePid.Msisdn(event.stateKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRoomJoinRulesEvent(realm: Realm, event: CurrentStateEventEntity, params: CreateRoomParams): CreateRoomParams = params.apply {
|
||||||
|
val content = getEventContent<RoomJoinRulesContent>(realm, event.eventId) ?: return@apply
|
||||||
|
preset = when {
|
||||||
|
// If preset has already been set for direct chat, keep it
|
||||||
|
preset == CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT -> CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT
|
||||||
|
content.joinRules == RoomJoinRules.PUBLIC -> CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||||
|
content.joinRules == RoomJoinRules.INVITE -> CreateRoomPreset.PRESET_PRIVATE_CHAT
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================================
|
||||||
|
* Helper methods
|
||||||
|
* ========================================================================================== */
|
||||||
|
|
||||||
|
private inline fun <reified T> getEventContent(realm: Realm, eventId: String): T? {
|
||||||
|
return EventEntity.where(realm, eventId).findFirst()?.asDomain()?.getClearContent().toModel<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a CharSequence is an email.
|
||||||
|
*/
|
||||||
|
private fun CharSequence.isEmail() = Patterns.EMAIL_ADDRESS.matcher(this).matches()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a CharSequence is a phone number.
|
||||||
|
*/
|
||||||
|
private fun CharSequence.isMsisdn(): Boolean {
|
||||||
|
return try {
|
||||||
|
PhoneNumberUtil.getInstance().parse(ensurePrefix("+"), null)
|
||||||
|
true
|
||||||
|
} catch (e: NumberParseException) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,10 +16,12 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.room.state
|
package org.matrix.android.sdk.internal.session.room.state
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
|
||||||
import org.matrix.android.sdk.api.util.JsonDict
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||||
import org.matrix.android.sdk.internal.network.executeRequest
|
import org.matrix.android.sdk.internal.network.executeRequest
|
||||||
import org.matrix.android.sdk.internal.session.room.RoomAPI
|
import org.matrix.android.sdk.internal.session.room.RoomAPI
|
||||||
|
import org.matrix.android.sdk.internal.session.room.create.CreateRoomFromLocalRoomTask
|
||||||
import org.matrix.android.sdk.internal.task.Task
|
import org.matrix.android.sdk.internal.task.Task
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -35,11 +37,16 @@ internal interface SendStateTask : Task<SendStateTask.Params, String> {
|
||||||
|
|
||||||
internal class DefaultSendStateTask @Inject constructor(
|
internal class DefaultSendStateTask @Inject constructor(
|
||||||
private val roomAPI: RoomAPI,
|
private val roomAPI: RoomAPI,
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver
|
private val globalErrorReceiver: GlobalErrorReceiver,
|
||||||
|
private val createRoomFromLocalRoomTask: CreateRoomFromLocalRoomTask,
|
||||||
) : SendStateTask {
|
) : SendStateTask {
|
||||||
|
|
||||||
override suspend fun execute(params: SendStateTask.Params): String {
|
override suspend fun execute(params: SendStateTask.Params): String {
|
||||||
return executeRequest(globalErrorReceiver) {
|
return executeRequest(globalErrorReceiver) {
|
||||||
|
if (RoomLocalEcho.isLocalEchoId(params.roomId)) {
|
||||||
|
// Room is local, so create a real one and send the event to this new room
|
||||||
|
createRoomAndSendEvent(params)
|
||||||
|
} else {
|
||||||
val response = if (params.stateKey.isEmpty()) {
|
val response = if (params.stateKey.isEmpty()) {
|
||||||
roomAPI.sendStateEvent(
|
roomAPI.sendStateEvent(
|
||||||
roomId = params.roomId,
|
roomId = params.roomId,
|
||||||
|
@ -59,4 +66,11 @@ internal class DefaultSendStateTask @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun createRoomAndSendEvent(params: SendStateTask.Params): String {
|
||||||
|
val roomId = createRoomFromLocalRoomTask.execute(CreateRoomFromLocalRoomTask.Params(params.roomId))
|
||||||
|
Timber.d("State event: convert local room (${params.roomId}) to existing room ($roomId) before sending the event.")
|
||||||
|
return execute(params.copy(roomId = roomId))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
import org.matrix.android.sdk.api.raw.RawService
|
import org.matrix.android.sdk.api.raw.RawService
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
|
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.events.model.LocalEcho
|
import org.matrix.android.sdk.api.session.events.model.LocalEcho
|
||||||
import org.matrix.android.sdk.api.session.events.model.RelationType
|
import org.matrix.android.sdk.api.session.events.model.RelationType
|
||||||
|
@ -1269,11 +1270,26 @@ class TimelineViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)?.also {
|
room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)?.also {
|
||||||
setState { copy(tombstoneEvent = it) }
|
onRoomTombstoneUpdated(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var roomTombstoneHandled = false
|
||||||
|
private fun onRoomTombstoneUpdated(tombstoneEvent: Event) = withState { state ->
|
||||||
|
if (roomTombstoneHandled) return@withState
|
||||||
|
if (state.isLocalRoom()) {
|
||||||
|
// Local room has been replaced, so navigate to the new room
|
||||||
|
val roomId = tombstoneEvent.getClearContent()?.toModel<RoomTombstoneContent>()
|
||||||
|
?.replacementRoomId
|
||||||
|
?: return@withState
|
||||||
|
_viewEvents.post(RoomDetailViewEvents.OpenRoom(roomId, closeCurrentRoom = true))
|
||||||
|
roomTombstoneHandled = true
|
||||||
|
} else {
|
||||||
|
setState { copy(tombstoneEvent = tombstoneEvent) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigates to the appropriate event (by paginating the thread timeline until the event is found
|
* Navigates to the appropriate event (by paginating the thread timeline until the event is found
|
||||||
* in the snapshot. The main reason for this function is to support the /relations api
|
* in the snapshot. The main reason for this function is to support the /relations api
|
||||||
|
|
Loading…
Reference in a new issue