From 4b3a6a883d003bd20206429b08098487839ff25f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Jul 2020 14:07:00 +0200 Subject: [PATCH] CreateRoomParams has been replaced by CreateRoomParamsBuilder, to be able to invite 3pids --- CHANGES.md | 2 +- .../main/java/im/vector/matrix/rx/RxRoom.kt | 5 + .../java/im/vector/matrix/rx/RxSession.kt | 4 +- .../matrix/android/common/CryptoTestHelper.kt | 12 +- .../crypto/gossiping/KeyShareTests.kt | 9 +- .../android/api/session/room/RoomService.kt | 6 +- .../room/model/create/CreateRoomParams.kt | 268 ------------------ .../model/create/CreateRoomParamsBuilder.kt | 86 ++++++ .../session/room/model/create/Invite3Pid.kt | 50 ---- .../session/room/DefaultRoomService.kt | 4 +- .../android/internal/session/room/RoomAPI.kt | 6 +- .../session/room/create/CreateRoomParams.kt | 115 ++++++++ .../create/CreateRoomParamsInternalBuilder.kt | 147 ++++++++++ .../room}/create/CreateRoomResponse.kt | 4 +- .../session/room/create/CreateRoomTask.kt | 46 +-- .../room/membership/joining/JoinRoomTask.kt | 2 +- .../createdirect/CreateDirectRoomViewModel.kt | 19 +- .../VerificationBottomSheetViewModel.kt | 13 +- .../invite/InviteUsersToRoomAction.kt | 4 +- .../invite/InviteUsersToRoomViewModel.kt | 9 +- .../createroom/CreateRoomViewModel.kt | 24 +- .../userdirectory/KnownUsersFragment.kt | 5 +- .../features/userdirectory/PendingInvitee.kt | 11 +- .../userdirectory/UserDirectoryFragment.kt | 5 +- 24 files changed, 443 insertions(+), 413 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParamsBuilder.kt delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/Invite3Pid.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomParams.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomParamsInternalBuilder.kt rename matrix-sdk-android/src/main/java/im/vector/matrix/android/{api/session/room/model => internal/session/room}/create/CreateRoomResponse.kt (89%) diff --git a/CHANGES.md b/CHANGES.md index 32ab57fda8..5daced2228 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,7 +28,7 @@ Translations 🗣: - SDK API changes ⚠️: - - + - CreateRoomParams has been replaced by CreateRoomParamsBuilder Build 🧱: - Upgrade some dependencies diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt index b91949778d..2e96863d60 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt @@ -19,6 +19,7 @@ package im.vector.matrix.rx import android.net.Uri import im.vector.matrix.android.api.query.QueryStringValue import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.identity.ThreePid import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.members.RoomMemberQueryParams import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary @@ -104,6 +105,10 @@ class RxRoom(private val room: Room) { room.invite(userId, reason, it) } + fun invite3pid(threePid: ThreePid): Completable = completableBuilder { + room.invite3pid(threePid, it) + } + fun updateTopic(topic: String): Completable = completableBuilder { room.updateTopic(topic, it) } diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt index ca0bb46f4b..93e2dcae19 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt @@ -32,7 +32,7 @@ import im.vector.matrix.android.api.session.pushers.Pusher import im.vector.matrix.android.api.session.room.RoomSummaryQueryParams import im.vector.matrix.android.api.session.room.members.ChangeMembershipState 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.session.room.model.create.CreateRoomParamsBuilder import im.vector.matrix.android.api.session.sync.SyncState import im.vector.matrix.android.api.session.user.model.User import im.vector.matrix.android.api.session.widgets.model.Widget @@ -110,7 +110,7 @@ class RxSession(private val session: Session) { .startWithCallable { session.getThreePids() } } - fun createRoom(roomParams: CreateRoomParams): Single = singleBuilder { + fun createRoom(roomParams: CreateRoomParamsBuilder): Single = singleBuilder { session.createRoom(roomParams, it) } diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/common/CryptoTestHelper.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/common/CryptoTestHelper.kt index 5425f97fc4..7e8410a440 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/common/CryptoTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/common/CryptoTestHelper.kt @@ -30,7 +30,7 @@ import im.vector.matrix.android.api.session.events.model.toContent import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.model.Membership 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.session.room.model.create.CreateRoomParamsBuilder import im.vector.matrix.android.api.session.room.roomSummaryQueryParams import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent @@ -65,7 +65,7 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) { val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams) val roomId = mTestHelper.doSync { - aliceSession.createRoom(CreateRoomParams(name = "MyRoom"), it) + aliceSession.createRoom(CreateRoomParamsBuilder().apply { name = "MyRoom" }, it) } if (encryptedRoom) { @@ -286,9 +286,11 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) { fun createDM(alice: Session, bob: Session): String { val roomId = mTestHelper.doSync { alice.createRoom( - CreateRoomParams(invitedUserIds = listOf(bob.myUserId)) - .setDirectMessage() - .enableEncryptionIfInvitedUsersSupportIt(), + CreateRoomParamsBuilder().apply { + invitedUserIds.add(bob.myUserId) + setDirectMessage() + enableEncryptionIfInvitedUsersSupportIt = true + }, it ) } diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt index e78ef04050..e90822a0c7 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt @@ -27,7 +27,7 @@ import im.vector.matrix.android.api.session.crypto.verification.VerificationTran import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility -import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams +import im.vector.matrix.android.api.session.room.model.create.CreateRoomParamsBuilder import im.vector.matrix.android.common.CommonTestHelper import im.vector.matrix.android.common.CryptoTestHelper import im.vector.matrix.android.common.SessionTestParams @@ -66,7 +66,10 @@ class KeyShareTests : InstrumentedTest { // Create an encrypted room and add a message val roomId = mTestHelper.doSync { aliceSession.createRoom( - CreateRoomParams(RoomDirectoryVisibility.PRIVATE).enableEncryptionWithAlgorithm(true), + CreateRoomParamsBuilder().apply { + visibility = RoomDirectoryVisibility.PRIVATE + enableEncryption() + }, it ) } @@ -285,7 +288,7 @@ class KeyShareTests : InstrumentedTest { mTestHelper.waitWithLatch(60_000) { latch -> val keysBackupService = aliceSession2.cryptoService().keysBackupService() mTestHelper.retryPeriodicallyWithLatch(latch) { - Log.d("#TEST", "Recovery :${ keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey}") + Log.d("#TEST", "Recovery :${keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey}") keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey == creationInfo.recoveryKey } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt index 3319cecfef..788a074c65 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt @@ -20,7 +20,7 @@ import androidx.lifecycle.LiveData import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.room.members.ChangeMembershipState 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.session.room.model.create.CreateRoomParamsBuilder import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.api.util.Optional @@ -32,7 +32,7 @@ interface RoomService { /** * Create a room asynchronously */ - fun createRoom(createRoomParams: CreateRoomParams, + fun createRoom(createRoomParams: CreateRoomParamsBuilder, callback: MatrixCallback): Cancelable /** @@ -113,5 +113,5 @@ interface RoomService { */ fun getChangeMembershipsLive(): LiveData> - fun getExistingDirectRoomWithUser(otherUserId: String) : Room? + fun getExistingDirectRoomWithUser(otherUserId: String): Room? } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt deleted file mode 100644 index 1abbe9ef3a..0000000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt +++ /dev/null @@ -1,268 +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.android.api.session.room.model.create - -import android.util.Patterns -import androidx.annotation.CheckResult -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass -import im.vector.matrix.android.api.MatrixPatterns.isUserId -import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig -import im.vector.matrix.android.api.session.events.model.Event -import im.vector.matrix.android.api.session.events.model.EventType -import im.vector.matrix.android.api.session.events.model.toContent -import im.vector.matrix.android.api.session.room.model.PowerLevelsContent -import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility -import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility -import im.vector.matrix.android.internal.auth.data.ThreePidMedium -import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM -import timber.log.Timber - -/** - * Parameter to create a room, with facilities functions to configure it - */ -@JsonClass(generateAdapter = true) -data class CreateRoomParams( - /** - * A public visibility indicates that the room will be shown in the published room list. - * A private visibility will hide the room from the published room list. - * Rooms default to private visibility if this key is not included. - * NB: This should not be confused with join_rules which also uses the word public. One of: ["public", "private"] - */ - @Json(name = "visibility") - val visibility: RoomDirectoryVisibility? = null, - - /** - * The desired room alias local part. If this is included, a room alias will be created and mapped to the newly created room. - * The alias will belong on the same homeserver which created the room. - * For example, if this was set to "foo" and sent to the homeserver "example.com" the complete room alias would be #foo:example.com. - */ - @Json(name = "room_alias_name") - val roomAliasName: String? = null, - - /** - * If this is included, an m.room.name event will be sent into the room to indicate the name of the room. - * See Room Events for more information on m.room.name. - */ - @Json(name = "name") - val name: String? = null, - - /** - * If this is included, an m.room.topic event will be sent into the room to indicate the topic for the room. - * See Room Events for more information on m.room.topic. - */ - @Json(name = "topic") - val topic: String? = null, - - /** - * A list of user IDs to invite to the room. - * This will tell the server to invite everyone in the list to the newly created room. - */ - @Json(name = "invite") - val invitedUserIds: List? = null, - - /** - * A list of objects representing third party IDs to invite into the room. - */ - @Json(name = "invite_3pid") - val invite3pids: List? = null, - - /** - * Extra keys to be added to the content of the m.room.create. - * The server will clobber the following keys: creator. - * Future versions of the specification may allow the server to clobber other keys. - */ - @Json(name = "creation_content") - val creationContent: Any? = null, - - /** - * A list of state events to set in the new room. - * This allows the user to override the default state events set in the new room. - * The expected format of the state events are an object with type, state_key and content keys set. - * Takes precedence over events set by presets, but gets overridden by name and topic keys. - */ - @Json(name = "initial_state") - val initialStates: List? = null, - - /** - * Convenience parameter for setting various default state events based on a preset. Must be either: - * private_chat => join_rules is set to invite. history_visibility is set to shared. - * trusted_private_chat => join_rules is set to invite. history_visibility is set to shared. All invitees are given the same power level as the - * room creator. - * public_chat: => join_rules is set to public. history_visibility is set to shared. - */ - @Json(name = "preset") - val preset: CreateRoomPreset? = null, - - /** - * This flag makes the server set the is_direct flag on the m.room.member events sent to the users in invite and invite_3pid. - * See Direct Messaging for more information. - */ - @Json(name = "is_direct") - val isDirect: Boolean? = null, - - /** - * The power level content to override in the default power level event - */ - @Json(name = "power_level_content_override") - val powerLevelContentOverride: PowerLevelsContent? = null -) { - @Transient - internal var enableEncryptionIfInvitedUsersSupportIt: Boolean = false - private set - - /** - * After calling this method, when the room will be created, if cross-signing is enabled and we can get keys for every invited users, - * the encryption will be enabled on the created room - * @param value true to activate this behavior. - * @return this, to allow chaining methods - */ - fun enableEncryptionIfInvitedUsersSupportIt(value: Boolean = true): CreateRoomParams { - enableEncryptionIfInvitedUsersSupportIt = value - return this - } - - /** - * Add the crypto algorithm to the room creation parameters. - * - * @param enable true to enable encryption. - * @param algorithm the algorithm, default to [MXCRYPTO_ALGORITHM_MEGOLM], which is actually the only supported algorithm for the moment - * @return a modified copy of the CreateRoomParams object, or this if there is no modification - */ - @CheckResult - fun enableEncryptionWithAlgorithm(enable: Boolean = true, - algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM): CreateRoomParams { - // Remove the existing value if any. - val newInitialStates = initialStates - ?.filter { it.type != EventType.STATE_ROOM_ENCRYPTION } - - return if (algorithm == MXCRYPTO_ALGORITHM_MEGOLM) { - if (enable) { - val contentMap = mapOf("algorithm" to algorithm) - - val algoEvent = Event( - type = EventType.STATE_ROOM_ENCRYPTION, - stateKey = "", - content = contentMap.toContent() - ) - - copy( - initialStates = newInitialStates.orEmpty() + algoEvent - ) - } else { - return copy( - initialStates = newInitialStates - ) - } - } else { - Timber.e("Unsupported algorithm: $algorithm") - this - } - } - - /** - * Force the history visibility in the room creation parameters. - * - * @param historyVisibility the expected history visibility, set null to remove any existing value. - * @return a modified copy of the CreateRoomParams object - */ - @CheckResult - fun setHistoryVisibility(historyVisibility: RoomHistoryVisibility?): CreateRoomParams { - // Remove the existing value if any. - val newInitialStates = initialStates - ?.filter { it.type != EventType.STATE_ROOM_HISTORY_VISIBILITY } - - if (historyVisibility != null) { - val contentMap = mapOf("history_visibility" to historyVisibility) - - val historyVisibilityEvent = Event( - type = EventType.STATE_ROOM_HISTORY_VISIBILITY, - stateKey = "", - content = contentMap.toContent()) - - return copy( - initialStates = newInitialStates.orEmpty() + historyVisibilityEvent - ) - } else { - return copy( - initialStates = newInitialStates - ) - } - } - - /** - * Mark as a direct message room. - * @return a modified copy of the CreateRoomParams object - */ - @CheckResult - fun setDirectMessage(): CreateRoomParams { - return copy( - preset = CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT, - isDirect = true - ) - } - - /** - * Tells if the created room can be a direct chat one. - * - * @return true if it is a direct chat - */ - fun isDirect(): Boolean { - return preset == CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT - && isDirect == true - } - - /** - * @return the first invited user id - */ - fun getFirstInvitedUserId(): String? { - return invitedUserIds?.firstOrNull() ?: invite3pids?.firstOrNull()?.address - } - - /** - * Add some ids to the room creation - * ids might be a matrix id or an email address. - * - * @param ids the participant ids to add. - * @return a modified copy of the CreateRoomParams object - */ - @CheckResult - fun addParticipantIds(hsConfig: HomeServerConnectionConfig, - userId: String, - ids: List): CreateRoomParams { - return copy( - invite3pids = (invite3pids.orEmpty() + ids - .takeIf { hsConfig.identityServerUri != null } - ?.filter { id -> Patterns.EMAIL_ADDRESS.matcher(id).matches() } - ?.map { id -> - Invite3Pid( - idServer = hsConfig.identityServerUri!!.host!!, - medium = ThreePidMedium.EMAIL, - address = id - ) - } - .orEmpty()) - .distinct(), - invitedUserIds = (invitedUserIds.orEmpty() + ids - .filter { id -> isUserId(id) } - // do not invite oneself - .filter { id -> id != userId }) - .distinct() - ) - // TODO add phonenumbers when it will be available - } -} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParamsBuilder.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParamsBuilder.kt new file mode 100644 index 0000000000..6637e3bcb2 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParamsBuilder.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 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.android.api.session.room.model.create + +import im.vector.matrix.android.api.session.identity.ThreePid +import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility +import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility +import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM + +class CreateRoomParamsBuilder { + var visibility: RoomDirectoryVisibility? = null + var roomAliasName: String? = null + var name: String? = null + var topic: String? = null + + /** + * UserIds to invite + */ + val invitedUserIds = mutableListOf() + + /** + * ThreePids to invite + */ + val invite3pids = mutableListOf() + + /** + * If set to true, when the room will be created, if cross-signing is enabled and we can get keys for every invited users, + * the encryption will be enabled on the created room + */ + var enableEncryptionIfInvitedUsersSupportIt: Boolean = false + + var preset: CreateRoomPreset? = null + + var isDirect: Boolean? = null + + /** + * Mark as a direct message room. + */ + fun setDirectMessage() { + preset = CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT + isDirect = true + } + + /** + * Supported value: MXCRYPTO_ALGORITHM_MEGOLM + */ + var algorithm: String? = null + private set + + var historyVisibility: RoomHistoryVisibility? = null + + fun enableEncryption() { + algorithm = MXCRYPTO_ALGORITHM_MEGOLM + } + + /** + * Tells if the created room can be a direct chat one. + * + * @return true if it is a direct chat + */ + fun isDirect(): Boolean { + return preset == CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT + && isDirect == true + } + + /** + * @return the first invited user id + */ + fun getFirstInvitedUserId(): String? { + return invitedUserIds.firstOrNull() ?: invite3pids.firstOrNull()?.value + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/Invite3Pid.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/Invite3Pid.kt deleted file mode 100644 index 66c8f1b2e8..0000000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/Invite3Pid.kt +++ /dev/null @@ -1,50 +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.android.api.session.room.model.create - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -data class Invite3Pid( - /** - * Required. - * The hostname+port of the identity server which should be used for third party identifier lookups. - */ - @Json(name = "id_server") - val idServer: String, - - /** - * Required. - * An access token previously registered with the identity server. Servers can treat this as optional to - * distinguish between r0.5-compatible clients and this specification version. - */ - @Json(name = "id_access_token") - val idAccessToken: String, - - /** - * Required. - * The kind of address being passed in the address field, for example email. - */ - val medium: String, - - /** - * Required. - * The invitee's third party identifier. - */ - val address: String -) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt index b8b4c968b1..7d5b8ac341 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt @@ -23,7 +23,7 @@ import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.api.session.room.RoomSummaryQueryParams import im.vector.matrix.android.api.session.room.members.ChangeMembershipState 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.session.room.model.create.CreateRoomParamsBuilder import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.internal.session.room.alias.GetRoomIdByAliasTask @@ -49,7 +49,7 @@ internal class DefaultRoomService @Inject constructor( private val taskExecutor: TaskExecutor ) : RoomService { - override fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback): Cancelable { + override fun createRoom(createRoomParams: CreateRoomParamsBuilder, callback: MatrixCallback): Cancelable { return createRoomTask .configureWith(createRoomParams) { this.callback = callback diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt index e00a94297a..a82c96f93d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt @@ -18,9 +18,6 @@ package im.vector.matrix.android.internal.session.room import im.vector.matrix.android.api.session.events.model.Content import im.vector.matrix.android.api.session.events.model.Event -import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams -import im.vector.matrix.android.api.session.room.model.create.CreateRoomResponse -import im.vector.matrix.android.api.session.room.model.create.JoinRoomResponse import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol @@ -28,6 +25,9 @@ import im.vector.matrix.android.api.util.JsonDict import im.vector.matrix.android.internal.network.NetworkConstants import im.vector.matrix.android.internal.session.room.alias.AddRoomAliasBody import im.vector.matrix.android.internal.session.room.alias.RoomAliasDescription +import im.vector.matrix.android.internal.session.room.create.CreateRoomParams +import im.vector.matrix.android.internal.session.room.create.CreateRoomResponse +import im.vector.matrix.android.internal.session.room.create.JoinRoomResponse import im.vector.matrix.android.internal.session.room.membership.RoomMembersResponse import im.vector.matrix.android.internal.session.room.membership.admin.UserIdAndReason import im.vector.matrix.android.internal.session.room.membership.joining.InviteBody diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomParams.kt new file mode 100644 index 0000000000..525a0501fc --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomParams.kt @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2020 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.android.internal.session.room.create + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.room.model.PowerLevelsContent +import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility +import im.vector.matrix.android.api.session.room.model.create.CreateRoomPreset +import im.vector.matrix.android.internal.session.room.membership.threepid.ThreePidInviteBody + +/** + * Parameter to create a room + */ +@JsonClass(generateAdapter = true) +internal data class CreateRoomParams( + /** + * A public visibility indicates that the room will be shown in the published room list. + * A private visibility will hide the room from the published room list. + * Rooms default to private visibility if this key is not included. + * NB: This should not be confused with join_rules which also uses the word public. One of: ["public", "private"] + */ + @Json(name = "visibility") + val visibility: RoomDirectoryVisibility?, + + /** + * The desired room alias local part. If this is included, a room alias will be created and mapped to the newly created room. + * The alias will belong on the same homeserver which created the room. + * For example, if this was set to "foo" and sent to the homeserver "example.com" the complete room alias would be #foo:example.com. + */ + @Json(name = "room_alias_name") + val roomAliasName: String?, + + /** + * If this is included, an m.room.name event will be sent into the room to indicate the name of the room. + * See Room Events for more information on m.room.name. + */ + @Json(name = "name") + val name: String?, + + /** + * If this is included, an m.room.topic event will be sent into the room to indicate the topic for the room. + * See Room Events for more information on m.room.topic. + */ + @Json(name = "topic") + val topic: String?, + + /** + * A list of user IDs to invite to the room. + * This will tell the server to invite everyone in the list to the newly created room. + */ + @Json(name = "invite") + val invitedUserIds: List?, + + /** + * A list of objects representing third party IDs to invite into the room. + */ + @Json(name = "invite_3pid") + val invite3pids: List?, + + /** + * Extra keys to be added to the content of the m.room.create. + * The server will clobber the following keys: creator. + * Future versions of the specification may allow the server to clobber other keys. + */ + @Json(name = "creation_content") + val creationContent: Any?, + + /** + * A list of state events to set in the new room. + * This allows the user to override the default state events set in the new room. + * The expected format of the state events are an object with type, state_key and content keys set. + * Takes precedence over events set by presets, but gets overridden by name and topic keys. + */ + @Json(name = "initial_state") + val initialStates: List?, + + /** + * Convenience parameter for setting various default state events based on a preset. Must be either: + * private_chat => join_rules is set to invite. history_visibility is set to shared. + * trusted_private_chat => join_rules is set to invite. history_visibility is set to shared. All invitees are given the same power level as the + * room creator. + * public_chat: => join_rules is set to public. history_visibility is set to shared. + */ + @Json(name = "preset") + val preset: CreateRoomPreset?, + + /** + * This flag makes the server set the is_direct flag on the m.room.member events sent to the users in invite and invite_3pid. + * See Direct Messaging for more information. + */ + @Json(name = "is_direct") + val isDirect: Boolean?, + + /** + * The power level content to override in the default power level event + */ + @Json(name = "power_level_content_override") + val powerLevelContentOverride: PowerLevelsContent? +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomParamsInternalBuilder.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomParamsInternalBuilder.kt new file mode 100644 index 0000000000..29cf0bbac6 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomParamsInternalBuilder.kt @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2020 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.android.internal.session.room.create + +import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningService +import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.api.session.events.model.toContent +import im.vector.matrix.android.api.session.identity.IdentityServiceError +import im.vector.matrix.android.api.session.identity.toMedium +import im.vector.matrix.android.api.session.room.model.create.CreateRoomParamsBuilder +import im.vector.matrix.android.internal.crypto.DeviceListManager +import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM +import im.vector.matrix.android.internal.di.AuthenticatedIdentity +import im.vector.matrix.android.internal.network.token.AccessTokenProvider +import im.vector.matrix.android.internal.session.identity.EnsureIdentityTokenTask +import im.vector.matrix.android.internal.session.identity.data.IdentityStore +import im.vector.matrix.android.internal.session.identity.data.getIdentityServerUrlWithoutProtocol +import im.vector.matrix.android.internal.session.room.membership.threepid.ThreePidInviteBody +import java.security.InvalidParameterException +import javax.inject.Inject + +internal class CreateRoomParamsInternalBuilder @Inject constructor( + private val ensureIdentityTokenTask: EnsureIdentityTokenTask, + private val crossSigningService: CrossSigningService, + private val deviceListManager: DeviceListManager, + private val identityStore: IdentityStore, + @AuthenticatedIdentity + private val accessTokenProvider: AccessTokenProvider +) { + + suspend fun build(builder: CreateRoomParamsBuilder): CreateRoomParams { + val invite3pids = builder.invite3pids + .takeIf { it.isNotEmpty() } + .let { + // This can throw Exception if Identity server is not configured + ensureIdentityTokenTask.execute(Unit) + + val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() + ?: throw IdentityServiceError.NoIdentityServerConfigured + val identityServerAccessToken = accessTokenProvider.getToken() ?: throw IdentityServiceError.NoIdentityServerConfigured + + builder.invite3pids.map { + ThreePidInviteBody( + id_server = identityServerUrlWithoutProtocol, + id_access_token = identityServerAccessToken, + medium = it.toMedium(), + address = it.value + ) + } + } + + val initialStates = listOfNotNull( + buildEncryptionWithAlgorithmEvent(builder), + buildHistoryVisibilityEvent(builder) + ) + .takeIf { it.isNotEmpty() } + + return CreateRoomParams( + visibility = builder.visibility, + roomAliasName = builder.roomAliasName, + name = builder.name, + topic = builder.topic, + invitedUserIds = builder.invitedUserIds, + invite3pids = invite3pids, + // TODO Support this + creationContent = null, + initialStates = initialStates, + preset = builder.preset, + isDirect = builder.isDirect, + // TODO Support this + powerLevelContentOverride = null + ) + } + + private fun buildHistoryVisibilityEvent(builder: CreateRoomParamsBuilder): Event? { + return builder.historyVisibility + ?.let { + val contentMap = mapOf("history_visibility" to it) + + Event( + type = EventType.STATE_ROOM_HISTORY_VISIBILITY, + stateKey = "", + content = contentMap.toContent()) + } + } + + /** + * Add the crypto algorithm to the room creation parameters. + */ + private suspend fun buildEncryptionWithAlgorithmEvent(builder: CreateRoomParamsBuilder): Event? { + if (builder.algorithm == null + && canEnableEncryption(builder)) { + // Enable the encryption + builder.enableEncryption() + } + return builder.algorithm + ?.let { + if (it != MXCRYPTO_ALGORITHM_MEGOLM) { + throw InvalidParameterException("Unsupported algorithm: $it") + } + val contentMap = mapOf("algorithm" to it) + + Event( + type = EventType.STATE_ROOM_ENCRYPTION, + stateKey = "", + content = contentMap.toContent() + ) + } + } + + private suspend fun canEnableEncryption(builder: CreateRoomParamsBuilder): Boolean { + return (builder.enableEncryptionIfInvitedUsersSupportIt + && crossSigningService.isCrossSigningVerified() + && builder.invite3pids.isEmpty()) + && builder.invitedUserIds.isNotEmpty() + && builder.invitedUserIds.let { userIds -> + val keys = deviceListManager.downloadKeys(userIds, forceDownload = false) + + userIds.all { userId -> + keys.map[userId].let { deviceMap -> + if (deviceMap.isNullOrEmpty()) { + // A user has no device, so do not enable encryption + false + } else { + // Check that every user's device have at least one key + deviceMap.values.all { !it.keys.isNullOrEmpty() } + } + } + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomResponse.kt similarity index 89% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomResponse.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomResponse.kt index da54b344a2..62208941cc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomResponse.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019 New Vector Ltd + * Copyright (c) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.api.session.room.model.create +package im.vector.matrix.android.internal.session.room.create import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomTask.kt index 2071b7736e..e32f8e39ab 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomTask.kt @@ -17,11 +17,8 @@ package im.vector.matrix.android.internal.session.room.create import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningService import im.vector.matrix.android.api.session.room.failure.CreateRoomFailure -import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams -import im.vector.matrix.android.api.session.room.model.create.CreateRoomResponse -import im.vector.matrix.android.internal.crypto.DeviceListManager +import im.vector.matrix.android.api.session.room.model.create.CreateRoomParamsBuilder import im.vector.matrix.android.internal.database.awaitNotEmptyResult import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.RoomEntityFields @@ -41,7 +38,7 @@ import org.greenrobot.eventbus.EventBus import java.util.concurrent.TimeUnit import javax.inject.Inject -internal interface CreateRoomTask : Task +internal interface CreateRoomTask : Task internal class DefaultCreateRoomTask @Inject constructor( private val roomAPI: RoomAPI, @@ -51,17 +48,12 @@ internal class DefaultCreateRoomTask @Inject constructor( private val readMarkersTask: SetReadMarkersTask, @SessionDatabase private val realmConfiguration: RealmConfiguration, - private val crossSigningService: CrossSigningService, - private val deviceListManager: DeviceListManager, + private val createRoomParamsInternalBuilder: CreateRoomParamsInternalBuilder, private val eventBus: EventBus ) : CreateRoomTask { - override suspend fun execute(params: CreateRoomParams): String { - val createRoomParams = if (canEnableEncryption(params)) { - params.enableEncryptionWithAlgorithm() - } else { - params - } + override suspend fun execute(params: CreateRoomParamsBuilder): String { + val createRoomParams = createRoomParamsInternalBuilder.build(params) val createRoomResponse = executeRequest(eventBus) { apiCall = roomAPI.createRoom(createRoomParams) @@ -76,36 +68,14 @@ internal class DefaultCreateRoomTask @Inject constructor( } catch (exception: TimeoutCancellationException) { throw CreateRoomFailure.CreatedWithTimeout } - if (createRoomParams.isDirect()) { - handleDirectChatCreation(createRoomParams, roomId) + if (params.isDirect()) { + handleDirectChatCreation(params, roomId) } setReadMarkers(roomId) return roomId } - private suspend fun canEnableEncryption(params: CreateRoomParams): Boolean { - return params.enableEncryptionIfInvitedUsersSupportIt - && crossSigningService.isCrossSigningVerified() - && params.invite3pids.isNullOrEmpty() - && params.invitedUserIds?.isNotEmpty() == true - && params.invitedUserIds.let { userIds -> - val keys = deviceListManager.downloadKeys(userIds, forceDownload = false) - - userIds.all { userId -> - keys.map[userId].let { deviceMap -> - if (deviceMap.isNullOrEmpty()) { - // A user has no device, so do not enable encryption - false - } else { - // Check that every user's device have at least one key - deviceMap.values.all { !it.keys.isNullOrEmpty() } - } - } - } - } - } - - private suspend fun handleDirectChatCreation(params: CreateRoomParams, roomId: String) { + private suspend fun handleDirectChatCreation(params: CreateRoomParamsBuilder, roomId: String) { val otherUserId = params.getFirstInvitedUserId() ?: throw IllegalStateException("You can't create a direct room without an invitedUser") diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt index 7467a595bc..8fb9a1f065 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt @@ -18,13 +18,13 @@ package im.vector.matrix.android.internal.session.room.membership.joining import im.vector.matrix.android.api.session.room.failure.JoinRoomFailure import im.vector.matrix.android.api.session.room.members.ChangeMembershipState -import im.vector.matrix.android.api.session.room.model.create.JoinRoomResponse import im.vector.matrix.android.internal.database.awaitNotEmptyResult import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.RoomEntityFields import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.room.RoomAPI +import im.vector.matrix.android.internal.session.room.create.JoinRoomResponse import im.vector.matrix.android.internal.session.room.membership.RoomChangeMembershipStateDataSource import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask import im.vector.matrix.android.internal.task.Task diff --git a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt index 90340c5cd8..44acdc0032 100644 --- a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt @@ -22,8 +22,9 @@ import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session -import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams +import im.vector.matrix.android.api.session.room.model.create.CreateRoomParamsBuilder import im.vector.matrix.rx.rx +import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.features.userdirectory.PendingInvitee @@ -53,11 +54,17 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted } private fun createRoomAndInviteSelectedUsers(selectedUsers: Set) { - val roomParams = CreateRoomParams( - invitedUserIds = selectedUsers.map { it.userId } - ) - .setDirectMessage() - .enableEncryptionIfInvitedUsersSupportIt() + val roomParams = CreateRoomParamsBuilder() + .apply { + selectedUsers.forEach { + when (it) { + is PendingInvitee.UserPendingInvitee -> invitedUserIds.add(it.user.userId) + is PendingInvitee.ThreePidPendingInvitee -> invite3pids.add(it.threePid) + }.exhaustive + } + setDirectMessage() + enableEncryptionIfInvitedUsersSupportIt = true + } session.rx() .createRoom(roomParams) diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt index 9b454436d9..1833688c35 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt @@ -43,7 +43,7 @@ import im.vector.matrix.android.api.session.crypto.verification.VerificationServ import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState import im.vector.matrix.android.api.session.events.model.LocalEcho -import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams +import im.vector.matrix.android.api.session.room.model.create.CreateRoomParamsBuilder import im.vector.matrix.android.api.util.MatrixItem import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.internal.crypto.crosssigning.fromBase64 @@ -235,11 +235,12 @@ class VerificationBottomSheetViewModel @AssistedInject constructor( pendingRequest = Loading() ) } - val roomParams = CreateRoomParams( - invitedUserIds = listOf(otherUserId) - ) - .setDirectMessage() - .enableEncryptionIfInvitedUsersSupportIt() + val roomParams = CreateRoomParamsBuilder() + .apply { + invitedUserIds.add(otherUserId) + setDirectMessage() + enableEncryptionIfInvitedUsersSupportIt = true + } session.createRoom(roomParams, object : MatrixCallback { override fun onSuccess(data: String) { diff --git a/vector/src/main/java/im/vector/riotx/features/invite/InviteUsersToRoomAction.kt b/vector/src/main/java/im/vector/riotx/features/invite/InviteUsersToRoomAction.kt index 8a62935bdd..253b557cca 100644 --- a/vector/src/main/java/im/vector/riotx/features/invite/InviteUsersToRoomAction.kt +++ b/vector/src/main/java/im/vector/riotx/features/invite/InviteUsersToRoomAction.kt @@ -16,9 +16,9 @@ package im.vector.riotx.features.invite -import im.vector.matrix.android.api.session.user.model.User import im.vector.riotx.core.platform.VectorViewModelAction +import im.vector.riotx.features.userdirectory.PendingInvitee sealed class InviteUsersToRoomAction : VectorViewModelAction { - data class InviteSelectedUsers(val selectedUsers: Set) : InviteUsersToRoomAction() + data class InviteSelectedUsers(val selectedUsers: Set) : InviteUsersToRoomAction() } diff --git a/vector/src/main/java/im/vector/riotx/features/invite/InviteUsersToRoomViewModel.kt b/vector/src/main/java/im/vector/riotx/features/invite/InviteUsersToRoomViewModel.kt index fc2f34b7a0..78a9961884 100644 --- a/vector/src/main/java/im/vector/riotx/features/invite/InviteUsersToRoomViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/invite/InviteUsersToRoomViewModel.kt @@ -22,11 +22,11 @@ import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session -import im.vector.matrix.android.api.session.user.model.User import im.vector.matrix.rx.rx import im.vector.riotx.R import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.resources.StringProvider +import im.vector.riotx.features.userdirectory.PendingInvitee import io.reactivex.Observable class InviteUsersToRoomViewModel @AssistedInject constructor(@Assisted @@ -57,11 +57,14 @@ class InviteUsersToRoomViewModel @AssistedInject constructor(@Assisted } } - private fun inviteUsersToRoom(selectedUsers: Set) { + private fun inviteUsersToRoom(selectedUsers: Set) { _viewEvents.post(InviteUsersToRoomViewEvents.Loading) Observable.fromIterable(selectedUsers).flatMapCompletable { user -> - room.rx().invite(user.userId, null) + when (user) { + is PendingInvitee.UserPendingInvitee -> room.rx().invite(user.user.userId, null) + is PendingInvitee.ThreePidPendingInvitee -> room.rx().invite3pid(user.threePid) + } }.subscribe( { val successMessage = when (selectedUsers.size) { diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomViewModel.kt index cfe50bb2f7..5cb279c848 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -28,7 +28,7 @@ import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility -import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams +import im.vector.matrix.android.api.session.room.model.create.CreateRoomParamsBuilder import im.vector.matrix.android.api.session.room.model.create.CreateRoomPreset import im.vector.riotx.core.platform.EmptyViewEvents import im.vector.riotx.core.platform.VectorViewModel @@ -84,15 +84,19 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr copy(asyncCreateRoomRequest = Loading()) } - val createRoomParams = CreateRoomParams( - name = state.roomName.takeIf { it.isNotBlank() }, - // Directory visibility - visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE, - // Public room - preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT - ) - // Encryption - .enableEncryptionWithAlgorithm(state.isEncrypted) + val createRoomParams = CreateRoomParamsBuilder() + .apply { + name = state.roomName.takeIf { it.isNotBlank() } + // Directory visibility + visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE + // Public room + preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT + + // Encryption + if (state.isEncrypted) { + enableEncryption() + } + } session.createRoom(createRoomParams, object : MatrixCallback { override fun onSuccess(data: String) { diff --git a/vector/src/main/java/im/vector/riotx/features/userdirectory/KnownUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/userdirectory/KnownUsersFragment.kt index dc7ec5ee04..5367ec270c 100644 --- a/vector/src/main/java/im/vector/riotx/features/userdirectory/KnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/userdirectory/KnownUsersFragment.kt @@ -160,10 +160,7 @@ class KnownUsersFragment @Inject constructor( val chip = Chip(requireContext()) chip.setChipBackgroundColorResource(android.R.color.transparent) chip.chipStrokeWidth = dimensionConverter.dpToPx(1).toFloat() - chip.text = when (pendingInvitee) { - is PendingInvitee.UserPendingInvitee -> pendingInvitee.user.getBestName() - is PendingInvitee.ThreePidPendingInvitee -> pendingInvitee.threePid.value - } + chip.text = pendingInvitee.getBestName() chip.isClickable = true chip.isCheckable = false chip.isCloseIconVisible = true diff --git a/vector/src/main/java/im/vector/riotx/features/userdirectory/PendingInvitee.kt b/vector/src/main/java/im/vector/riotx/features/userdirectory/PendingInvitee.kt index b213061e4a..c9aad1cf65 100644 --- a/vector/src/main/java/im/vector/riotx/features/userdirectory/PendingInvitee.kt +++ b/vector/src/main/java/im/vector/riotx/features/userdirectory/PendingInvitee.kt @@ -20,6 +20,13 @@ import im.vector.matrix.android.api.session.identity.ThreePid import im.vector.matrix.android.api.session.user.model.User sealed class PendingInvitee { - data class UserPendingInvitee(val user: User): PendingInvitee() - data class ThreePidPendingInvitee(val threePid: ThreePid): PendingInvitee() + data class UserPendingInvitee(val user: User) : PendingInvitee() + data class ThreePidPendingInvitee(val threePid: ThreePid) : PendingInvitee() + + fun getBestName(): String { + return when (this) { + is UserPendingInvitee -> user.getBestName() + is ThreePidPendingInvitee -> threePid.value + } + } } diff --git a/vector/src/main/java/im/vector/riotx/features/userdirectory/UserDirectoryFragment.kt b/vector/src/main/java/im/vector/riotx/features/userdirectory/UserDirectoryFragment.kt index 8dd4025350..a6d22dfbe3 100644 --- a/vector/src/main/java/im/vector/riotx/features/userdirectory/UserDirectoryFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/userdirectory/UserDirectoryFragment.kt @@ -21,6 +21,7 @@ import android.view.View import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import com.jakewharton.rxbinding3.widget.textChanges +import im.vector.matrix.android.api.session.user.model.User import im.vector.riotx.R import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.configureWith @@ -81,9 +82,9 @@ class UserDirectoryFragment @Inject constructor( directRoomController.setData(it) } - override fun onItemClick(pendingInvitee: PendingInvitee) { + override fun onItemClick(user: User) { view?.hideKeyboard() - viewModel.handle(UserDirectoryAction.SelectPendingInvitee(pendingInvitee)) + viewModel.handle(UserDirectoryAction.SelectPendingInvitee(PendingInvitee.UserPendingInvitee(user))) sharedActionViewModel.post(UserDirectorySharedAction.GoBack) }