mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 05:31:21 +03:00
Udpate since msc 1772
This commit is contained in:
parent
a8d7c25244
commit
c8916ee83c
33 changed files with 544 additions and 99 deletions
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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 org.matrix.android.sdk.session.space
|
||||||
|
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.FixMethodOrder
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
import org.junit.runners.MethodSorters
|
||||||
|
import org.matrix.android.sdk.InstrumentedTest
|
||||||
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
|
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||||
|
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.create.RoomCreateContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||||
|
import org.matrix.android.sdk.api.session.space.SpaceService
|
||||||
|
import org.matrix.android.sdk.common.CommonTestHelper
|
||||||
|
import org.matrix.android.sdk.common.SessionTestParams
|
||||||
|
import org.matrix.android.sdk.internal.util.awaitCallback
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
@FixMethodOrder(MethodSorters.JVM)
|
||||||
|
class SpaceCreationTest : InstrumentedTest {
|
||||||
|
|
||||||
|
private val commonTestHelper = CommonTestHelper(context())
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createSimplePublicSpace() {
|
||||||
|
val session = commonTestHelper.createAccount("Hubble", SessionTestParams(true))
|
||||||
|
val roomName = "My Space"
|
||||||
|
val topic = "A public space for test"
|
||||||
|
val spaceId: String
|
||||||
|
runBlocking {
|
||||||
|
spaceId = session.spaceService().createSpace(roomName, topic, null, true)
|
||||||
|
// wait a bit to let the summry update it self :/
|
||||||
|
delay(400)
|
||||||
|
}
|
||||||
|
|
||||||
|
val syncedSpace = session.spaceService().getSpace(spaceId)
|
||||||
|
assertEquals(roomName, syncedSpace?.asRoom()?.roomSummary()?.name, "Room name should be set")
|
||||||
|
assertEquals(topic, syncedSpace?.asRoom()?.roomSummary()?.topic, "Room topic should be set")
|
||||||
|
// assertEquals(topic, syncedSpace.asRoom().roomSummary()?., "Room topic should be set")
|
||||||
|
|
||||||
|
assertNotNull(syncedSpace, "Space should be found by Id")
|
||||||
|
val creationEvent = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_CREATE)
|
||||||
|
val createContent = creationEvent?.content.toModel<RoomCreateContent>()
|
||||||
|
assertEquals(RoomType.SPACE, createContent?.type, "Room type should be space")
|
||||||
|
|
||||||
|
var powerLevelsContent: PowerLevelsContent? = null
|
||||||
|
commonTestHelper.waitWithLatch { latch ->
|
||||||
|
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||||
|
val toModel = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)?.content.toModel<PowerLevelsContent>()
|
||||||
|
powerLevelsContent = toModel
|
||||||
|
toModel != null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals(100, powerLevelsContent?.eventsDefault, "Space-rooms should be created with a power level for events_default of 100")
|
||||||
|
|
||||||
|
commonTestHelper.signOutAndClose(session)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testJoinSimplePublicSpace() {
|
||||||
|
val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
|
||||||
|
val bobSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
|
||||||
|
|
||||||
|
val roomName = "My Space"
|
||||||
|
val topic = "A public space for test"
|
||||||
|
val spaceId: String
|
||||||
|
runBlocking {
|
||||||
|
spaceId = aliceSession.spaceService().createSpace(roomName, topic, null, true)
|
||||||
|
// wait a bit to let the summry update it self :/
|
||||||
|
delay(400)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to join from bob, it's a public space no need to invite
|
||||||
|
|
||||||
|
val joinResult: SpaceService.JoinSpaceResult
|
||||||
|
runBlocking {
|
||||||
|
joinResult = bobSession.spaceService().joinSpace(spaceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(SpaceService.JoinSpaceResult.Success, joinResult)
|
||||||
|
|
||||||
|
val spaceBobPov = bobSession.spaceService().getSpace(spaceId)
|
||||||
|
assertEquals(roomName, spaceBobPov?.asRoom()?.roomSummary()?.name, "Room name should be set")
|
||||||
|
assertEquals(topic, spaceBobPov?.asRoom()?.roomSummary()?.topic, "Room topic should be set")
|
||||||
|
|
||||||
|
commonTestHelper.signOutAndClose(aliceSession)
|
||||||
|
commonTestHelper.signOutAndClose(bobSession)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSimplePublicSpaceWithChildren() {
|
||||||
|
val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
|
||||||
|
val bobSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
|
||||||
|
|
||||||
|
val roomName = "My Space"
|
||||||
|
val topic = "A public space for test"
|
||||||
|
val spaceId: String
|
||||||
|
val firstChild: String
|
||||||
|
val secondChild: String
|
||||||
|
|
||||||
|
spaceId = runBlocking { aliceSession.spaceService().createSpace(roomName, topic, null, true) }
|
||||||
|
val syncedSpace = aliceSession.spaceService().getSpace(spaceId)
|
||||||
|
|
||||||
|
// create a room
|
||||||
|
firstChild = runBlocking {
|
||||||
|
awaitCallback<String> {
|
||||||
|
aliceSession.createRoom(CreateRoomParams().apply {
|
||||||
|
this.name = "FirstRoom"
|
||||||
|
this.topic = "Description of first room"
|
||||||
|
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||||
|
}, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runBlocking {
|
||||||
|
syncedSpace?.addChildren(firstChild, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "a", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
secondChild = runBlocking {
|
||||||
|
awaitCallback {
|
||||||
|
aliceSession.createRoom(CreateRoomParams().apply {
|
||||||
|
this.name = "SecondRoom"
|
||||||
|
this.topic = "Description of second room"
|
||||||
|
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||||
|
}, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runBlocking {
|
||||||
|
syncedSpace?.addChildren(secondChild, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "b", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to join from bob, it's a public space no need to invite
|
||||||
|
|
||||||
|
val joinResult = runBlocking {
|
||||||
|
bobSession.spaceService().joinSpace(spaceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(SpaceService.JoinSpaceResult.Success, joinResult)
|
||||||
|
|
||||||
|
val spaceBobPov = bobSession.spaceService().getSpace(spaceId)
|
||||||
|
assertEquals(roomName, spaceBobPov?.asRoom()?.roomSummary()?.name, "Room name should be set")
|
||||||
|
assertEquals(topic, spaceBobPov?.asRoom()?.roomSummary()?.topic, "Room topic should be set")
|
||||||
|
|
||||||
|
// check if bob has joined automatically the first room
|
||||||
|
|
||||||
|
val bobMembershipFirstRoom = bobSession.getRoom(firstChild)?.roomSummary()?.membership
|
||||||
|
assertEquals(Membership.JOIN, bobMembershipFirstRoom, "Bob should have joined this room")
|
||||||
|
RoomSummaryQueryParams.Builder()
|
||||||
|
|
||||||
|
val spaceSummaryBobPov = bobSession.spaceService().getSpaceSummaries(roomSummaryQueryParams {
|
||||||
|
this.roomId = QueryStringValue.Equals(spaceId)
|
||||||
|
this.memberships = listOf(Membership.JOIN)
|
||||||
|
}).firstOrNull()
|
||||||
|
|
||||||
|
assertEquals(2, spaceSummaryBobPov?.children?.size ?: -1, "Unexpected number of children")
|
||||||
|
|
||||||
|
commonTestHelper.signOutAndClose(aliceSession)
|
||||||
|
commonTestHelper.signOutAndClose(bobSession)
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,9 +51,13 @@ object EventType {
|
||||||
const val STATE_ROOM_JOIN_RULES = "m.room.join_rules"
|
const val STATE_ROOM_JOIN_RULES = "m.room.join_rules"
|
||||||
const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access"
|
const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access"
|
||||||
const val STATE_ROOM_POWER_LEVELS = "m.room.power_levels"
|
const val STATE_ROOM_POWER_LEVELS = "m.room.power_levels"
|
||||||
// const val STATE_SPACE_CHILD = "m.space.child"
|
|
||||||
|
// const val STATE_SPACE_CHILD = "m.space.child"
|
||||||
const val STATE_SPACE_CHILD = "org.matrix.msc1772.space.child"
|
const val STATE_SPACE_CHILD = "org.matrix.msc1772.space.child"
|
||||||
|
|
||||||
|
// const val STATE_SPACE_PARENT = "m.space.parent"
|
||||||
|
const val STATE_SPACE_PARENT = "org.matrix.msc1772.space.parent"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note that this Event has been deprecated, see
|
* Note that this Event has been deprecated, see
|
||||||
* - https://matrix.org/docs/spec/client_server/r0.6.1#historical-events
|
* - https://matrix.org/docs/spec/client_server/r0.6.1#historical-events
|
||||||
|
@ -76,6 +80,7 @@ object EventType {
|
||||||
const val CALL_NEGOTIATE = "m.call.negotiate"
|
const val CALL_NEGOTIATE = "m.call.negotiate"
|
||||||
const val CALL_REJECT = "m.call.reject"
|
const val CALL_REJECT = "m.call.reject"
|
||||||
const val CALL_HANGUP = "m.call.hangup"
|
const val CALL_HANGUP = "m.call.hangup"
|
||||||
|
|
||||||
// This type is not processed by the client, just sent to the server
|
// This type is not processed by the client, just sent to the server
|
||||||
const val CALL_REPLACES = "m.call.replaces"
|
const val CALL_REPLACES = "m.call.replaces"
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
package org.matrix.android.sdk.api.session.room.alias
|
package org.matrix.android.sdk.api.session.room.alias
|
||||||
|
|
||||||
sealed class RoomAliasError : Throwable() {
|
sealed class RoomAliasError : Throwable() {
|
||||||
object AliasEmpty : RoomAliasError()
|
object AliasIsBlank : RoomAliasError()
|
||||||
object AliasNotAvailable : RoomAliasError()
|
object AliasNotAvailable : RoomAliasError()
|
||||||
object AliasInvalid : RoomAliasError()
|
object AliasInvalid : RoomAliasError()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 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.api.session.room.model
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing the EventType.EVENT_TYPE_STATE_ROOM_POWER_LEVELS state event content.
|
||||||
|
*/
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class PowerLevelsContentOverride(
|
||||||
|
/**
|
||||||
|
* The level required to ban a user. Defaults to 50 if unspecified.
|
||||||
|
*/
|
||||||
|
@Json(name = "ban") val ban: Int? = null,
|
||||||
|
/**
|
||||||
|
* The level required to kick a user. Defaults to 50 if unspecified.
|
||||||
|
*/
|
||||||
|
@Json(name = "kick") val kick: Int? = null,
|
||||||
|
/**
|
||||||
|
* The level required to invite a user. Defaults to 50 if unspecified.
|
||||||
|
*/
|
||||||
|
@Json(name = "invite") val invite: Int? = null,
|
||||||
|
/**
|
||||||
|
* The level required to redact an event. Defaults to 50 if unspecified.
|
||||||
|
*/
|
||||||
|
@Json(name = "redact") val redact: Int? = null,
|
||||||
|
/**
|
||||||
|
* The default level required to send message events. Can be overridden by the events key. Defaults to 0 if unspecified.
|
||||||
|
*/
|
||||||
|
@Json(name = "events_default") val eventsDefault: Int? = null,
|
||||||
|
/**
|
||||||
|
* The level required to send specific event types. This is a mapping from event type to power level required.
|
||||||
|
*/
|
||||||
|
@Json(name = "events") val events: Map<String, Int>? = null,
|
||||||
|
/**
|
||||||
|
* The default power level for every user in the room, unless their user_id is mentioned in the users key. Defaults to 0 if unspecified.
|
||||||
|
*/
|
||||||
|
@Json(name = "users_default") val usersDefault: Int? = null,
|
||||||
|
/**
|
||||||
|
* The power levels for specific users. This is a mapping from user_id to power level for that user.
|
||||||
|
*/
|
||||||
|
@Json(name = "users") val users: Map<String, Int>? = null,
|
||||||
|
/**
|
||||||
|
* The default level required to send state events. Can be overridden by the events key. Defaults to 50 if unspecified.
|
||||||
|
*/
|
||||||
|
@Json(name = "state_default") val stateDefault: Int? = null,
|
||||||
|
/**
|
||||||
|
* The power level requirements for specific notification types. This is a mapping from key to power level for that notifications key.
|
||||||
|
*/
|
||||||
|
@Json(name = "notifications") val notifications: Map<String, Any>? = null
|
||||||
|
)
|
|
@ -18,7 +18,6 @@ package org.matrix.android.sdk.api.session.room.model
|
||||||
|
|
||||||
data class SpaceChildInfo(
|
data class SpaceChildInfo(
|
||||||
val roomSummary: IRoomSummary?,
|
val roomSummary: IRoomSummary?,
|
||||||
val present: Boolean,
|
|
||||||
val order: String?,
|
val order: String?,
|
||||||
val autoJoin: Boolean,
|
val autoJoin: Boolean,
|
||||||
val viaServers: List<String>
|
val viaServers: List<String>
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.room.model.create
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
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.PowerLevelsContentOverride
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
|
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
|
||||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||||
|
@ -125,7 +125,7 @@ open class CreateRoomParams {
|
||||||
/**
|
/**
|
||||||
* The power level content to override in the default power level event
|
* The power level content to override in the default power level event
|
||||||
*/
|
*/
|
||||||
var powerLevelContentOverride: PowerLevelsContent? = null
|
var powerLevelContentOverride: PowerLevelsContentOverride? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark as a direct message room.
|
* Mark as a direct message room.
|
||||||
|
@ -149,6 +149,6 @@ open class CreateRoomParams {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"
|
private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"
|
||||||
private const val CREATION_CONTENT_KEY_ROOM_TYPE = "type"
|
private const val CREATION_CONTENT_KEY_ROOM_TYPE = "org.matrix.msc1772.type"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,8 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||||
* @return the power level
|
* @return the power level
|
||||||
*/
|
*/
|
||||||
fun getUserPowerLevelValue(userId: String): Int {
|
fun getUserPowerLevelValue(userId: String): Int {
|
||||||
return powerLevelsContent.users.getOrElse(userId) {
|
return powerLevelsContent.users?.get(userId)
|
||||||
powerLevelsContent.usersDefault
|
?: powerLevelsContent.usersDefault
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,12 +16,20 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.api.session.space
|
package org.matrix.android.sdk.api.session.space
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContentOverride
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||||
|
|
||||||
class CreateSpaceParams : CreateRoomParams() {
|
class CreateSpaceParams : CreateRoomParams() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
// Space-rooms are distinguished from regular messaging rooms by the m.room.type of m.space
|
||||||
roomType = RoomType.SPACE
|
roomType = RoomType.SPACE
|
||||||
|
|
||||||
|
// Space-rooms should be created with a power level for events_default of 100,
|
||||||
|
// to prevent the rooms accidentally/maliciously clogging up with messages from random members of the space.
|
||||||
|
powerLevelContentOverride = PowerLevelsContentOverride(
|
||||||
|
eventsDefault = 100
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,9 @@ interface Space {
|
||||||
|
|
||||||
fun asRoom() : Room
|
fun asRoom() : Room
|
||||||
|
|
||||||
suspend fun addRoom(roomId: String)
|
suspend fun addChildren(roomId: String, viaServers: List<String>, order: String?, autoJoin: Boolean = false)
|
||||||
|
|
||||||
|
suspend fun removeRoom(roomId: String)
|
||||||
|
|
||||||
// fun getChildren() : List<IRoomSummary>
|
// fun getChildren() : List<IRoomSummary>
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.api.session.space
|
package org.matrix.android.sdk.api.session.space
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
@ -31,6 +32,11 @@ interface SpaceService {
|
||||||
*/
|
*/
|
||||||
suspend fun createSpace(params: CreateSpaceParams): String
|
suspend fun createSpace(params: CreateSpaceParams): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just a shortcut for space creation for ease of use
|
||||||
|
*/
|
||||||
|
suspend fun createSpace(name: String, topic: String?, avatarUri: Uri?, isPublic: Boolean): String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a space from a roomId
|
* Get a space from a roomId
|
||||||
* @param roomId the roomId to look for.
|
* @param roomId the roomId to look for.
|
||||||
|
@ -43,12 +49,12 @@ interface SpaceService {
|
||||||
* Use this call get preview of children of this space, particularly useful to get a
|
* Use this call get preview of children of this space, particularly useful to get a
|
||||||
* preview of rooms that you did not join yet.
|
* preview of rooms that you did not join yet.
|
||||||
*/
|
*/
|
||||||
suspend fun peekSpace(spaceId: String) : SpacePeekResult
|
suspend fun peekSpace(spaceId: String): SpacePeekResult
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get's information of a space by querying the server
|
* Get's information of a space by querying the server
|
||||||
*/
|
*/
|
||||||
suspend fun querySpaceChildren(spaceId: String) : Pair<RoomSummary, List<SpaceChildInfo>>
|
suspend fun querySpaceChildren(spaceId: String): Pair<RoomSummary, List<SpaceChildInfo>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a live list of space summaries. This list is refreshed as soon as the data changes.
|
* Get a live list of space summaries. This list is refreshed as soon as the data changes.
|
||||||
|
@ -64,8 +70,9 @@ interface SpaceService {
|
||||||
)
|
)
|
||||||
|
|
||||||
sealed class JoinSpaceResult {
|
sealed class JoinSpaceResult {
|
||||||
object Success: JoinSpaceResult()
|
object Success : JoinSpaceResult()
|
||||||
data class Fail(val error: Throwable?): JoinSpaceResult()
|
data class Fail(val error: Throwable) : JoinSpaceResult()
|
||||||
|
|
||||||
/** Success fully joined the space, but failed to join all or some of it's rooms */
|
/** Success fully joined the space, but failed to join all or some of it's rooms */
|
||||||
data class PartialSuccess(val failedRooms: Map<String, Throwable>) : JoinSpaceResult()
|
data class PartialSuccess(val failedRooms: Map<String, Throwable>) : JoinSpaceResult()
|
||||||
|
|
||||||
|
@ -74,8 +81,7 @@ interface SpaceService {
|
||||||
|
|
||||||
suspend fun joinSpace(spaceIdOrAlias: String,
|
suspend fun joinSpace(spaceIdOrAlias: String,
|
||||||
reason: String? = null,
|
reason: String? = null,
|
||||||
viaServers: List<String> = emptyList(),
|
viaServers: List<String> = emptyList()): JoinSpaceResult
|
||||||
autoJoinChild: List<ChildAutoJoinInfo>) : JoinSpaceResult
|
|
||||||
|
|
||||||
suspend fun rejectInvite(spaceId: String, reason: String?)
|
suspend fun rejectInvite(spaceId: String, reason: String?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,13 +31,9 @@ import com.squareup.moshi.JsonClass
|
||||||
data class SpaceChildContent(
|
data class SpaceChildContent(
|
||||||
/**
|
/**
|
||||||
* Key which gives a list of candidate servers that can be used to join the room
|
* Key which gives a list of candidate servers that can be used to join the room
|
||||||
|
* Children where via is not present are ignored.
|
||||||
*/
|
*/
|
||||||
@Json(name = "via") val via: List<String>? = null,
|
@Json(name = "via") val via: List<String>? = null,
|
||||||
/**
|
|
||||||
* present: true key is included to distinguish from a deleted state event
|
|
||||||
* Children where present is not present or is not set to true are ignored.
|
|
||||||
*/
|
|
||||||
@Json(name = "present") val present: Boolean? = false,
|
|
||||||
/**
|
/**
|
||||||
* The order key is a string which is used to provide a default ordering of siblings in the room list.
|
* The order key is a string which is used to provide a default ordering of siblings in the room list.
|
||||||
* (Rooms are sorted based on a lexicographic ordering of order values; rooms with no order come last.
|
* (Rooms are sorted based on a lexicographic ordering of order values; rooms with no order come last.
|
||||||
|
@ -46,8 +42,25 @@ data class SpaceChildContent(
|
||||||
*/
|
*/
|
||||||
@Json(name = "order") val order: String? = null,
|
@Json(name = "order") val order: String? = null,
|
||||||
/**
|
/**
|
||||||
* The default flag on a child listing allows a space admin to list the "default" sub-spaces and rooms in that space.
|
* The auto_join flag on a child listing allows a space admin to list the sub-spaces and rooms in that space which should
|
||||||
* This means that when a user joins the parent space, they will automatically be joined to those default children.
|
* be automatically joined by members of that space.
|
||||||
|
* (This is not a force-join, which are descoped for a future MSC; the user can subsequently part these room if they desire.)
|
||||||
*/
|
*/
|
||||||
@Json(name = "default") val default: Boolean? = false
|
@Json(name = "auto_join") val autoJoin: Boolean? = false
|
||||||
)
|
) {
|
||||||
|
/**
|
||||||
|
* Orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7F (~),
|
||||||
|
* or consist of more than 50 characters, are forbidden and should be ignored if received.)
|
||||||
|
*/
|
||||||
|
fun validOrder(): String? {
|
||||||
|
order?.let {
|
||||||
|
if (order.length > 50) return null
|
||||||
|
if (!ORDER_VALID_CHAR_REGEX.matches(it)) return null
|
||||||
|
}
|
||||||
|
return order
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val ORDER_VALID_CHAR_REGEX = "[ -~]+".toRegex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 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.api.session.space.model
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rooms can claim parents via the m.space.parent state event.
|
||||||
|
* {
|
||||||
|
* "type": "m.space.parent",
|
||||||
|
* "state_key": "!space:example.com",
|
||||||
|
* "content": {
|
||||||
|
* "via": ["example.com"],
|
||||||
|
* "present": true,
|
||||||
|
* "canonical": true,
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class SpaceParentContent(
|
||||||
|
/**
|
||||||
|
* Key which gives a list of candidate servers that can be used to join the parent.
|
||||||
|
* Parents where via is not present are ignored.
|
||||||
|
*/
|
||||||
|
@Json(name = "via") val via: List<String>? = null,
|
||||||
|
/**
|
||||||
|
* present: true key is included to distinguish from a deleted state event
|
||||||
|
* Parent where present is not present (sic) or is not set to true are ignored.
|
||||||
|
*/
|
||||||
|
@Json(name = "present") val present: Boolean? = false,
|
||||||
|
/**
|
||||||
|
* Canonical determines whether this is the main parent for the space.
|
||||||
|
* When a user joins a room with a canonical parent, clients may switch to view the room
|
||||||
|
* in the context of that space, peeking into it in order to find other rooms and group them together.
|
||||||
|
* In practice, well behaved rooms should only have one canonical parent, but given this is not enforced:
|
||||||
|
* if multiple are present the client should select the one with the lowest room ID, as determined via a lexicographic utf-8 ordering.
|
||||||
|
*/
|
||||||
|
@Json(name = "canonical") val canonical: Boolean? = false
|
||||||
|
)
|
|
@ -209,8 +209,6 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
|
||||||
|
|
||||||
val spaceChildInfoSchema = realm.schema.create("SpaceChildInfoEntity")
|
val spaceChildInfoSchema = realm.schema.create("SpaceChildInfoEntity")
|
||||||
?.addField(SpaceChildInfoEntityFields.ORDER, String::class.java)
|
?.addField(SpaceChildInfoEntityFields.ORDER, String::class.java)
|
||||||
?.addField(SpaceChildInfoEntityFields.PRESENT, Boolean::class.java)
|
|
||||||
?.setNullable(SpaceChildInfoEntityFields.PRESENT, true)
|
|
||||||
?.addRealmListField(SpaceChildInfoEntityFields.VIA_SERVERS.`$`, String::class.java)
|
?.addRealmListField(SpaceChildInfoEntityFields.VIA_SERVERS.`$`, String::class.java)
|
||||||
?.addRealmObjectField(SpaceChildInfoEntityFields.ROOM_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
|
?.addRealmObjectField(SpaceChildInfoEntityFields.ROOM_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ internal class SpaceSummaryMapper @Inject constructor(private val roomSummaryMap
|
||||||
SpaceChildInfo(
|
SpaceChildInfo(
|
||||||
roomSummary = it.roomSummaryEntity?.let { rs -> roomSummaryMapper.map(rs) },
|
roomSummary = it.roomSummaryEntity?.let { rs -> roomSummaryMapper.map(rs) },
|
||||||
autoJoin = it.autoJoin ?: false,
|
autoJoin = it.autoJoin ?: false,
|
||||||
present = it.present ?: false,
|
|
||||||
viaServers = it.viaServers.map { it },
|
viaServers = it.viaServers.map { it },
|
||||||
order = it.order
|
order = it.order
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021 New Vector Ltd
|
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -24,8 +24,6 @@ import io.realm.RealmObject
|
||||||
*/
|
*/
|
||||||
internal open class SpaceChildInfoEntity(
|
internal open class SpaceChildInfoEntity(
|
||||||
var viaServers: RealmList<String> = RealmList(),
|
var viaServers: RealmList<String> = RealmList(),
|
||||||
// it's an active child of the space if and only if present is not null and true
|
|
||||||
var present: Boolean? = null,
|
|
||||||
// Use for alphabetic ordering of this child
|
// Use for alphabetic ordering of this child
|
||||||
var order: String? = null,
|
var order: String? = null,
|
||||||
// If true, this child should be join when parent is joined
|
// If true, this child should be join when parent is joined
|
||||||
|
|
|
@ -36,7 +36,11 @@ internal class RoomAliasAvailabilityChecker @Inject constructor(
|
||||||
@Throws(RoomAliasError::class)
|
@Throws(RoomAliasError::class)
|
||||||
suspend fun check(aliasLocalPart: String?) {
|
suspend fun check(aliasLocalPart: String?) {
|
||||||
if (aliasLocalPart.isNullOrEmpty()) {
|
if (aliasLocalPart.isNullOrEmpty()) {
|
||||||
throw RoomAliasError.AliasEmpty
|
// don't check empty or not provided alias
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (aliasLocalPart.isBlank()) {
|
||||||
|
throw RoomAliasError.AliasIsBlank
|
||||||
}
|
}
|
||||||
// Check alias availability
|
// Check alias availability
|
||||||
val fullAlias = aliasLocalPart.toFullLocalAlias(userId)
|
val fullAlias = aliasLocalPart.toFullLocalAlias(userId)
|
||||||
|
|
|
@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.session.room.create
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
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.PowerLevelsContent
|
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContentOverride
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
||||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePidInviteBody
|
import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePidInviteBody
|
||||||
|
@ -111,5 +111,5 @@ internal data class CreateRoomBody(
|
||||||
* The power level content to override in the default power level event
|
* The power level content to override in the default power level event
|
||||||
*/
|
*/
|
||||||
@Json(name = "power_level_content_override")
|
@Json(name = "power_level_content_override")
|
||||||
val powerLevelContentOverride: PowerLevelsContent?
|
val powerLevelContentOverride: PowerLevelsContentOverride?
|
||||||
)
|
)
|
||||||
|
|
|
@ -41,28 +41,31 @@ internal class RoomRelationshipHelper(private val realm: Realm,
|
||||||
|
|
||||||
data class SpaceChildInfo(
|
data class SpaceChildInfo(
|
||||||
val roomId: String,
|
val roomId: String,
|
||||||
val present: Boolean,
|
|
||||||
val order: String?,
|
val order: String?,
|
||||||
val autoJoin: Boolean,
|
val autoJoin: Boolean,
|
||||||
val viaServers: List<String>
|
val viaServers: List<String>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ordered list of valid child description.
|
||||||
|
*/
|
||||||
fun getDirectChildrenDescriptions(): List<SpaceChildInfo> {
|
fun getDirectChildrenDescriptions(): List<SpaceChildInfo> {
|
||||||
return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_CHILD)
|
return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_CHILD)
|
||||||
.findAll()
|
.findAll()
|
||||||
// .filter { ContentMapper.map(it.root?.content).toModel<SpaceChildContent>()?.present == true }
|
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
// ContentMapper.map(it.root?.content).toModel<SpaceChildContent>()
|
|
||||||
ContentMapper.map(it.root?.content).toModel<SpaceChildContent>()?.let { scc ->
|
ContentMapper.map(it.root?.content).toModel<SpaceChildContent>()?.let { scc ->
|
||||||
Timber.d("## Space child desc state event $scc")
|
Timber.d("## Space child desc state event $scc")
|
||||||
SpaceChildInfo(
|
// Children where via is not present are ignored.
|
||||||
roomId = it.stateKey,
|
scc.via?.let { via ->
|
||||||
present = scc.present ?: false,
|
SpaceChildInfo(
|
||||||
order = scc.order,
|
roomId = it.stateKey,
|
||||||
autoJoin = scc.default ?: false,
|
order = scc.validOrder(),
|
||||||
viaServers = scc.via ?: emptyList()
|
autoJoin = scc.autoJoin ?: false,
|
||||||
)
|
viaServers = via
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sortedBy { it.order }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ internal fun JsonDict.toSafePowerLevelsContentDict(): JsonDict {
|
||||||
eventsDefault = content.eventsDefault,
|
eventsDefault = content.eventsDefault,
|
||||||
events = content.events,
|
events = content.events,
|
||||||
usersDefault = content.usersDefault,
|
usersDefault = content.usersDefault,
|
||||||
users = content.users,
|
users = content.users ?: emptyMap(),
|
||||||
stateDefault = content.stateDefault,
|
stateDefault = content.stateDefault,
|
||||||
notifications = content.notifications.mapValues { content.notificationLevel(it.key) }
|
notifications = content.notifications.mapValues { content.notificationLevel(it.key) }
|
||||||
)
|
)
|
||||||
|
|
|
@ -99,6 +99,7 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||||
|
|
||||||
val roomType = ContentMapper.map(roomCreateEvent?.content).toModel<RoomCreateContent>()?.type
|
val roomType = ContentMapper.map(roomCreateEvent?.content).toModel<RoomCreateContent>()?.type
|
||||||
roomSummaryEntity.roomType = roomType
|
roomSummaryEntity.roomType = roomType
|
||||||
|
Timber.v("## Space: Updating summary room [$roomId] roomType: [$roomType]")
|
||||||
|
|
||||||
// Don't use current state for this one as we are only interested in having MXCRYPTO_ALGORITHM_MEGOLM event in the room
|
// Don't use current state for this one as we are only interested in having MXCRYPTO_ALGORITHM_MEGOLM event in the room
|
||||||
val encryptionEvent = EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
|
val encryptionEvent = EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
|
||||||
|
@ -176,7 +177,6 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||||
realm.createObject<SpaceChildInfoEntity>().apply {
|
realm.createObject<SpaceChildInfoEntity>().apply {
|
||||||
this.roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, it.roomId)
|
this.roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, it.roomId)
|
||||||
this.order = it.order
|
this.order = it.order
|
||||||
this.present = it.present
|
|
||||||
this.autoJoin = it.autoJoin
|
this.autoJoin = it.autoJoin
|
||||||
}.also {
|
}.also {
|
||||||
Timber.v("## Space: Updating summary for room $roomId with children $it")
|
Timber.v("## Space: Updating summary for room $roomId with children $it")
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.space
|
package org.matrix.android.sdk.internal.session.space
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
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.toContent
|
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.room.Room
|
import org.matrix.android.sdk.api.session.room.Room
|
||||||
import org.matrix.android.sdk.api.session.space.Space
|
import org.matrix.android.sdk.api.session.space.Space
|
||||||
import org.matrix.android.sdk.api.session.space.model.SpaceChildContent
|
import org.matrix.android.sdk.api.session.space.model.SpaceChildContent
|
||||||
|
@ -28,11 +30,34 @@ class DefaultSpace(private val room: Room) : Space {
|
||||||
return room
|
return room
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun addRoom(roomId: String) {
|
override suspend fun addChildren(roomId: String, viaServers: List<String>, order: String?, autoJoin: Boolean) {
|
||||||
asRoom().sendStateEvent(
|
asRoom().sendStateEvent(
|
||||||
eventType = EventType.STATE_SPACE_CHILD,
|
eventType = EventType.STATE_SPACE_CHILD,
|
||||||
stateKey = roomId,
|
stateKey = roomId,
|
||||||
body = SpaceChildContent(present = true).toContent()
|
body = SpaceChildContent(
|
||||||
|
via = viaServers,
|
||||||
|
autoJoin = autoJoin,
|
||||||
|
order = order
|
||||||
|
).toContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun removeRoom(roomId: String) {
|
||||||
|
val existing = asRoom().getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
|
||||||
|
.firstOrNull()
|
||||||
|
?.content.toModel<SpaceChildContent>()
|
||||||
|
?: // should we throw here?
|
||||||
|
return
|
||||||
|
|
||||||
|
// edit state event and set via to null
|
||||||
|
asRoom().sendStateEvent(
|
||||||
|
eventType = EventType.STATE_SPACE_CHILD,
|
||||||
|
stateKey = roomId,
|
||||||
|
body = SpaceChildContent(
|
||||||
|
order = existing.order,
|
||||||
|
via = null,
|
||||||
|
autoJoin = existing.autoJoin
|
||||||
|
).toContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.space
|
package org.matrix.android.sdk.internal.session.space
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
|
@ -23,6 +24,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
||||||
import org.matrix.android.sdk.api.session.space.CreateSpaceParams
|
import org.matrix.android.sdk.api.session.space.CreateSpaceParams
|
||||||
import org.matrix.android.sdk.api.session.space.Space
|
import org.matrix.android.sdk.api.session.space.Space
|
||||||
import org.matrix.android.sdk.api.session.space.SpaceService
|
import org.matrix.android.sdk.api.session.space.SpaceService
|
||||||
|
@ -66,6 +68,15 @@ internal class DefaultSpaceService @Inject constructor(
|
||||||
return createRoomTask.execute(params)
|
return createRoomTask.execute(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun createSpace(name: String, topic: String?, avatarUri: Uri?, isPublic: Boolean): String {
|
||||||
|
return createSpace(CreateSpaceParams().apply {
|
||||||
|
this.name = name
|
||||||
|
this.topic = topic
|
||||||
|
this.preset = if (isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT
|
||||||
|
this.avatarUri = avatarUri
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
override fun getSpace(spaceId: String): Space? {
|
override fun getSpace(spaceId: String): Space? {
|
||||||
return roomGetter.getRoom(spaceId)
|
return roomGetter.getRoom(spaceId)
|
||||||
?.takeIf { it.roomSummary()?.roomType == RoomType.SPACE }
|
?.takeIf { it.roomSummary()?.roomType == RoomType.SPACE }
|
||||||
|
@ -120,8 +131,7 @@ internal class DefaultSpaceService @Inject constructor(
|
||||||
isEncrypted = false
|
isEncrypted = false
|
||||||
),
|
),
|
||||||
order = childStateEv?.order,
|
order = childStateEv?.order,
|
||||||
present = childStateEv?.present ?: false,
|
autoJoin = childStateEv?.autoJoin ?: false,
|
||||||
autoJoin = childStateEv?.default ?: false,
|
|
||||||
viaServers = childStateEv?.via ?: emptyList()
|
viaServers = childStateEv?.via ?: emptyList()
|
||||||
)
|
)
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
|
@ -131,30 +141,8 @@ internal class DefaultSpaceService @Inject constructor(
|
||||||
|
|
||||||
override suspend fun joinSpace(spaceIdOrAlias: String,
|
override suspend fun joinSpace(spaceIdOrAlias: String,
|
||||||
reason: String?,
|
reason: String?,
|
||||||
viaServers: List<String>,
|
viaServers: List<String>): SpaceService.JoinSpaceResult {
|
||||||
autoJoinChild: List<SpaceService.ChildAutoJoinInfo>): SpaceService.JoinSpaceResult {
|
return joinSpaceTask.execute(JoinSpaceTask.Params(spaceIdOrAlias, reason, viaServers))
|
||||||
try {
|
|
||||||
joinSpaceTask.execute(JoinSpaceTask.Params(spaceIdOrAlias, reason, viaServers))
|
|
||||||
// TODO partial success
|
|
||||||
return SpaceService.JoinSpaceResult.Success
|
|
||||||
// val childJoinFailures = mutableMapOf<String, Throwable>()
|
|
||||||
// autoJoinChild.forEach { info ->
|
|
||||||
// // TODO what if the child is it self a subspace with some default children?
|
|
||||||
// try {
|
|
||||||
// joinRoomTask.execute(JoinRoomTask.Params(info.roomIdOrAlias, null, info.viaServers))
|
|
||||||
// } catch (failure: Throwable) {
|
|
||||||
// // TODO, i could already be a member of this room, handle that as it should not be an error in this context
|
|
||||||
// childJoinFailures[info.roomIdOrAlias] = failure
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return if (childJoinFailures.isEmpty()) {
|
|
||||||
// SpaceService.JoinSpaceResult.Success
|
|
||||||
// } else {
|
|
||||||
// SpaceService.JoinSpaceResult.PartialSuccess(childJoinFailures)
|
|
||||||
// }
|
|
||||||
} catch (throwable: Throwable) {
|
|
||||||
return SpaceService.JoinSpaceResult.Fail(throwable)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun rejectInvite(spaceId: String, reason: String?) {
|
override suspend fun rejectInvite(spaceId: String, reason: String?) {
|
||||||
|
|
|
@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.space
|
||||||
|
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||||
|
import org.matrix.android.sdk.api.session.space.SpaceService
|
||||||
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
||||||
import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntity
|
import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntityFields
|
import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntityFields
|
||||||
|
@ -32,7 +32,7 @@ import timber.log.Timber
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal interface JoinSpaceTask : Task<JoinSpaceTask.Params, Unit> {
|
internal interface JoinSpaceTask : Task<JoinSpaceTask.Params, SpaceService.JoinSpaceResult> {
|
||||||
data class Params(
|
data class Params(
|
||||||
val roomIdOrAlias: String,
|
val roomIdOrAlias: String,
|
||||||
val reason: String?,
|
val reason: String?,
|
||||||
|
@ -48,13 +48,17 @@ internal class DefaultJoinSpaceTask @Inject constructor(
|
||||||
private val spaceSummaryDataSource: SpaceSummaryDataSource
|
private val spaceSummaryDataSource: SpaceSummaryDataSource
|
||||||
) : JoinSpaceTask {
|
) : JoinSpaceTask {
|
||||||
|
|
||||||
override suspend fun execute(params: JoinSpaceTask.Params) {
|
override suspend fun execute(params: JoinSpaceTask.Params): SpaceService.JoinSpaceResult {
|
||||||
Timber.v("## Space: > Joining root space ${params.roomIdOrAlias} ...")
|
Timber.v("## Space: > Joining root space ${params.roomIdOrAlias} ...")
|
||||||
joinRoomTask.execute(JoinRoomTask.Params(
|
try {
|
||||||
params.roomIdOrAlias,
|
joinRoomTask.execute(JoinRoomTask.Params(
|
||||||
params.reason,
|
params.roomIdOrAlias,
|
||||||
params.viaServers
|
params.reason,
|
||||||
))
|
params.viaServers
|
||||||
|
))
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
return SpaceService.JoinSpaceResult.Fail(failure)
|
||||||
|
}
|
||||||
Timber.v("## Space: < Joining root space done for ${params.roomIdOrAlias}")
|
Timber.v("## Space: < Joining root space done for ${params.roomIdOrAlias}")
|
||||||
// we want to wait for sync result to check for auto join rooms
|
// we want to wait for sync result to check for auto join rooms
|
||||||
|
|
||||||
|
@ -73,19 +77,32 @@ internal class DefaultJoinSpaceTask @Inject constructor(
|
||||||
}
|
}
|
||||||
} catch (exception: TimeoutCancellationException) {
|
} catch (exception: TimeoutCancellationException) {
|
||||||
Timber.w("## Space: > Error created with timeout")
|
Timber.w("## Space: > Error created with timeout")
|
||||||
throw CreateRoomFailure.CreatedWithTimeout
|
return SpaceService.JoinSpaceResult.PartialSuccess(emptyMap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val errors = HashMap<String, Throwable>()
|
||||||
Timber.v("## Space: > Sync done ...")
|
Timber.v("## Space: > Sync done ...")
|
||||||
// after that i should have the children (? do i nead to paginate to get state)
|
// after that i should have the children (? do I need to paginate to get state)
|
||||||
val summary = spaceSummaryDataSource.getSpaceSummary(params.roomIdOrAlias)
|
val summary = spaceSummaryDataSource.getSpaceSummary(params.roomIdOrAlias)
|
||||||
Timber.v("## Space: Found space summary Name:[${summary?.roomSummary?.name}] children: ${summary?.children?.size}")
|
Timber.v("## Space: Found space summary Name:[${summary?.roomSummary?.name}] children: ${summary?.children?.size}")
|
||||||
summary?.children?.forEach {
|
summary?.children?.forEach {
|
||||||
val childRoomSummary = it.roomSummary ?: return@forEach
|
val childRoomSummary = it.roomSummary ?: return@forEach
|
||||||
Timber.v("## Space: Processing child :[${childRoomSummary.roomId}] present: ${it.present} autoJoin:${it.autoJoin}")
|
Timber.v("## Space: Processing child :[${childRoomSummary.roomId}] autoJoin:${it.autoJoin}")
|
||||||
if (it.present && it.autoJoin) {
|
if (it.autoJoin) {
|
||||||
// I should try to join as well
|
// I should try to join as well
|
||||||
if (childRoomSummary.roomType == RoomType.SPACE) {
|
if (childRoomSummary.roomType == RoomType.SPACE) {
|
||||||
|
// recursively join auto-joined child of this space?
|
||||||
|
when (val subspaceJoinResult = this.execute(JoinSpaceTask.Params(it.roomSummary.roomId, null, it.viaServers))) {
|
||||||
|
SpaceService.JoinSpaceResult.Success -> {
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
is SpaceService.JoinSpaceResult.Fail -> {
|
||||||
|
errors[it.roomSummary.roomId] = subspaceJoinResult.error
|
||||||
|
}
|
||||||
|
is SpaceService.JoinSpaceResult.PartialSuccess -> {
|
||||||
|
errors.putAll(subspaceJoinResult.failedRooms)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
Timber.v("## Space: Joining room child ${childRoomSummary.roomId}")
|
Timber.v("## Space: Joining room child ${childRoomSummary.roomId}")
|
||||||
|
@ -95,12 +112,18 @@ internal class DefaultJoinSpaceTask @Inject constructor(
|
||||||
viaServers = it.viaServers
|
viaServers = it.viaServers
|
||||||
))
|
))
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
// todo keep track for partial success
|
errors[it.roomSummary.roomId] = failure
|
||||||
Timber.e("## Space: Failed to join room child ${childRoomSummary.roomId}")
|
Timber.e("## Space: Failed to join room child ${childRoomSummary.roomId}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return if (errors.isEmpty()) {
|
||||||
|
SpaceService.JoinSpaceResult.Success
|
||||||
|
} else {
|
||||||
|
SpaceService.JoinSpaceResult.PartialSuccess(errors)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021 New Vector Ltd
|
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -75,8 +75,8 @@ internal class DefaultPeekSpaceTask @Inject constructor(
|
||||||
val childRoomsIds = stateEvents
|
val childRoomsIds = stateEvents
|
||||||
.filter {
|
.filter {
|
||||||
it.type == EventType.STATE_SPACE_CHILD && !it.stateKey.isNullOrEmpty()
|
it.type == EventType.STATE_SPACE_CHILD && !it.stateKey.isNullOrEmpty()
|
||||||
// Children where present is not present or is not set to true are ignored.
|
// Children where via is not present are ignored.
|
||||||
&& it.content?.toModel<SpaceChildContent>()?.present == true
|
&& it.content?.toModel<SpaceChildContent>()?.via != null
|
||||||
}
|
}
|
||||||
.map { it.stateKey to it.content?.toModel<SpaceChildContent>() }
|
.map { it.stateKey to it.content?.toModel<SpaceChildContent>() }
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ internal class DefaultPeekSpaceTask @Inject constructor(
|
||||||
// can't peek :/
|
// can't peek :/
|
||||||
spaceChildResults.add(
|
spaceChildResults.add(
|
||||||
SpaceChildPeekResult(
|
SpaceChildPeekResult(
|
||||||
childId, childPeek, entry.second?.default, entry.second?.order
|
childId, childPeek, entry.second?.autoJoin, entry.second?.order
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
// continue to next child
|
// continue to next child
|
||||||
|
@ -114,7 +114,7 @@ internal class DefaultPeekSpaceTask @Inject constructor(
|
||||||
SpaceSubChildPeekResult(
|
SpaceSubChildPeekResult(
|
||||||
childId,
|
childId,
|
||||||
childPeek,
|
childPeek,
|
||||||
entry.second?.default,
|
entry.second?.autoJoin,
|
||||||
entry.second?.order,
|
entry.second?.order,
|
||||||
peekChildren(childStateEvents, depth + 1, maxDepth)
|
peekChildren(childStateEvents, depth + 1, maxDepth)
|
||||||
)
|
)
|
||||||
|
@ -125,7 +125,7 @@ internal class DefaultPeekSpaceTask @Inject constructor(
|
||||||
Timber.v("## SPACE_PEEK: room child $entry")
|
Timber.v("## SPACE_PEEK: room child $entry")
|
||||||
spaceChildResults.add(
|
spaceChildResults.add(
|
||||||
SpaceChildPeekResult(
|
SpaceChildPeekResult(
|
||||||
childId, childPeek, entry.second?.default, entry.second?.order
|
childId, childPeek, entry.second?.autoJoin, entry.second?.order
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,9 @@ enum class Command(val command: String, val parameters: String, @StringRes val d
|
||||||
CONFETTI("/confetti", "<message>", R.string.command_confetti),
|
CONFETTI("/confetti", "<message>", R.string.command_confetti),
|
||||||
SNOW("/snow", "<message>", R.string.command_snow),
|
SNOW("/snow", "<message>", R.string.command_snow),
|
||||||
CREATE_SPACE("/createspace", "<name> <invitee>*", R.string.command_description_create_space),
|
CREATE_SPACE("/createspace", "<name> <invitee>*", R.string.command_description_create_space),
|
||||||
ADD_TO_SPACE("/addToSpace", "spaceId", R.string.command_description_create_space);
|
ADD_TO_SPACE("/addToSpace", "spaceId", R.string.command_description_create_space),
|
||||||
|
JOIN_SPACE("/joinSpace", "spaceId", R.string.command_description_join_space),
|
||||||
|
LEAVE_ROOM("/leave", "<roomId?>", R.string.command_description_leave_room);
|
||||||
|
|
||||||
val length
|
val length
|
||||||
get() = command.length + 1
|
get() = command.length + 1
|
||||||
|
|
|
@ -318,6 +318,18 @@ object CommandParser {
|
||||||
rawCommand
|
rawCommand
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Command.JOIN_SPACE.command -> {
|
||||||
|
val spaceIdOrAlias = textMessage.substring(Command.JOIN_SPACE.command.length).trim()
|
||||||
|
ParsedCommand.JoinSpace(
|
||||||
|
spaceIdOrAlias
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Command.LEAVE_ROOM.command -> {
|
||||||
|
val spaceIdOrAlias = textMessage.substring(Command.LEAVE_ROOM.command.length).trim()
|
||||||
|
ParsedCommand.LeaveRoom(
|
||||||
|
spaceIdOrAlias
|
||||||
|
)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// Unknown command
|
// Unknown command
|
||||||
ParsedCommand.ErrorUnknownSlashCommand(slashCommand)
|
ParsedCommand.ErrorUnknownSlashCommand(slashCommand)
|
||||||
|
|
|
@ -59,4 +59,6 @@ sealed class ParsedCommand {
|
||||||
class SendChatEffect(val chatEffect: ChatEffect, val message: String) : ParsedCommand()
|
class SendChatEffect(val chatEffect: ChatEffect, val message: String) : ParsedCommand()
|
||||||
class CreateSpace(val name: String, val invitees: List<String>) : ParsedCommand()
|
class CreateSpace(val name: String, val invitees: List<String>) : ParsedCommand()
|
||||||
class AddToSpace(val spaceId: String) : ParsedCommand()
|
class AddToSpace(val spaceId: String) : ParsedCommand()
|
||||||
|
class JoinSpace(val spaceIdOrAlias: String) : ParsedCommand()
|
||||||
|
class LeaveRoom(val roomId: String) : ParsedCommand()
|
||||||
}
|
}
|
||||||
|
|
|
@ -831,7 +831,13 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||||
invitedUserIds.addAll(slashCommandResult.invitees)
|
invitedUserIds.addAll(slashCommandResult.invitees)
|
||||||
}
|
}
|
||||||
val spaceId = session.spaceService().createSpace(params)
|
val spaceId = session.spaceService().createSpace(params)
|
||||||
session.spaceService().getSpace(spaceId)?.addRoom(state.roomId)
|
session.spaceService().getSpace(spaceId)
|
||||||
|
?.addChildren(
|
||||||
|
state.roomId,
|
||||||
|
listOf(session.sessionParams.homeServerHost ?: ""),
|
||||||
|
null,
|
||||||
|
true
|
||||||
|
)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
_viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure))
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure))
|
||||||
}
|
}
|
||||||
|
@ -842,7 +848,37 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||||
is ParsedCommand.AddToSpace -> {
|
is ParsedCommand.AddToSpace -> {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
session.spaceService().getSpace(slashCommandResult.spaceId)?.addRoom(room.roomId)
|
session.spaceService().getSpace(slashCommandResult.spaceId)
|
||||||
|
?.addChildren(
|
||||||
|
room.roomId,
|
||||||
|
listOf(session.sessionParams.homeServerHost ?: ""),
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandHandled())
|
||||||
|
popDraft()
|
||||||
|
}
|
||||||
|
is ParsedCommand.JoinSpace -> {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
session.spaceService().joinSpace(slashCommandResult.spaceIdOrAlias)
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandHandled())
|
||||||
|
popDraft()
|
||||||
|
}
|
||||||
|
is ParsedCommand.LeaveRoom -> {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
awaitCallback {
|
||||||
|
session.getRoom(slashCommandResult.roomId)?.leave(null, it)
|
||||||
|
}
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
_viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure))
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure))
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.features.raw.wellknown.getElementWellknown
|
import im.vector.app.features.raw.wellknown.getElementWellknown
|
||||||
|
@ -37,6 +37,8 @@ import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
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.room.alias.RoomAliasError
|
||||||
|
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
||||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
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.create.CreateRoomPreset
|
||||||
|
@ -182,6 +184,15 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr
|
||||||
return@withState
|
return@withState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.roomVisibilityType is CreateRoomViewState.RoomVisibilityType.Public
|
||||||
|
&& state.roomVisibilityType.aliasLocalPart.isBlank()) {
|
||||||
|
// we require an alias for public rooms
|
||||||
|
setState {
|
||||||
|
copy(asyncCreateRoomRequest = Fail(CreateRoomFailure.AliasError(RoomAliasError.AliasIsBlank)))
|
||||||
|
}
|
||||||
|
return@withState
|
||||||
|
}
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
copy(asyncCreateRoomRequest = Loading())
|
copy(asyncCreateRoomRequest = Loading())
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ class RoomAliasErrorFormatter @Inject constructor(
|
||||||
) {
|
) {
|
||||||
fun format(roomAliasError: RoomAliasError?): String? {
|
fun format(roomAliasError: RoomAliasError?): String? {
|
||||||
return when (roomAliasError) {
|
return when (roomAliasError) {
|
||||||
is RoomAliasError.AliasEmpty -> R.string.create_room_alias_empty
|
is RoomAliasError.AliasIsBlank -> R.string.create_room_alias_empty
|
||||||
is RoomAliasError.AliasNotAvailable -> R.string.create_room_alias_already_in_use
|
is RoomAliasError.AliasNotAvailable -> R.string.create_room_alias_already_in_use
|
||||||
is RoomAliasError.AliasInvalid -> R.string.create_room_alias_invalid
|
is RoomAliasError.AliasInvalid -> R.string.create_room_alias_invalid
|
||||||
else -> null
|
else -> null
|
||||||
|
|
|
@ -100,7 +100,7 @@ class SpacePreviewViewModel @AssistedInject constructor(
|
||||||
// trigger modal loading
|
// trigger modal loading
|
||||||
_viewEvents.post(SpacePreviewViewEvents.StartJoining)
|
_viewEvents.post(SpacePreviewViewEvents.StartJoining)
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val joinResult = session.spaceService().joinSpace(initialState.idOrAlias, null, spaceVia, emptyList())
|
val joinResult = session.spaceService().joinSpace(initialState.idOrAlias, null, spaceVia)
|
||||||
when (joinResult) {
|
when (joinResult) {
|
||||||
SpaceService.JoinSpaceResult.Success,
|
SpaceService.JoinSpaceResult.Success,
|
||||||
is SpaceService.JoinSpaceResult.PartialSuccess -> {
|
is SpaceService.JoinSpaceResult.PartialSuccess -> {
|
||||||
|
|
|
@ -3248,6 +3248,9 @@
|
||||||
<string name="dev_tools_event_content_hint">Event content</string>
|
<string name="dev_tools_event_content_hint">Event content</string>
|
||||||
|
|
||||||
<string name="command_description_create_space">Create a community</string>
|
<string name="command_description_create_space">Create a community</string>
|
||||||
|
<string name="command_description_create_space">Create a Spcae</string>
|
||||||
|
<string name="command_description_join_space">Join the Space with the given id</string>
|
||||||
|
<string name="command_description_leave_room">Leave room with given id (or current room if null)</string>
|
||||||
|
|
||||||
<string name="event_status_a11y_sending">Sending</string>
|
<string name="event_status_a11y_sending">Sending</string>
|
||||||
<string name="event_status_a11y_sent">Sent</string>
|
<string name="event_status_a11y_sent">Sent</string>
|
||||||
|
|
Loading…
Reference in a new issue