diff --git a/changelog.d/6912.misc b/changelog.d/6912.misc
new file mode 100644
index 0000000000..c43830e902
--- /dev/null
+++ b/changelog.d/6912.misc
@@ -0,0 +1 @@
+Direct Message: Manage encrypted DM in case of invite by email
diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index 2ee623cf88..62f061f009 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -1817,6 +1817,7 @@
Add by QR code
QR code
"Creating room…"
+ You can only invite one email at a time
Known Users
Suggestions
@@ -2561,6 +2562,8 @@
Messages in this room are end-to-end encrypted. Learn more & verify users in their profile.
Messages in this chat are end-to-end encrypted.
Messages in this chat will be end-to-end encrypted.
+ Waiting for users to join ${app_name}
+ Once invited users have joined ${app_name}, you will be able to chat and the room will be end-to-end encrypted
Encryption not enabled
Encryption is misconfigured
The encryption used by this room is not supported
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
index 4105c77cc8..92081885af 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
@@ -190,10 +190,8 @@ internal class CreateRoomBodyBuilder @Inject constructor(
private suspend fun canEnableEncryption(params: CreateRoomParams): Boolean {
return params.enableEncryptionIfInvitedUsersSupportIt &&
// Parity with web, enable if users have encryption ready devices
- // for now remove checks on cross signing and 3pid invites
+ // for now remove checks on cross signing
// && crossSigningService.isCrossSigningVerified()
- params.invite3pids.isEmpty() &&
- params.invitedUserIds.isNotEmpty() &&
params.invitedUserIds.let { userIds ->
val keys = deviceListManager.downloadKeys(userIds, forceDownload = false)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
index 4645bb05ab..7497ecf21b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
@@ -115,7 +115,12 @@ internal class RoomDisplayNameResolver @Inject constructor(
val leftMembersNames = roomMembers.queryLeftRoomMembersEvent()
.findAll()
.map { displayNameResolver.getBestName(it.toMatrixItem()) }
- roomDisplayNameFallbackProvider.getNameForEmptyRoom(roomSummary?.isDirect.orFalse(), leftMembersNames)
+ val directUserId = roomSummary?.directUserId
+ if (!directUserId.isNullOrBlank() && leftMembersNames.isEmpty()) {
+ directUserId
+ } else {
+ roomDisplayNameFallbackProvider.getNameForEmptyRoom(roomSummary?.isDirect.orFalse(), leftMembersNames)
+ }
}
1 -> {
roomDisplayNameFallbackProvider.getNameFor1member(
diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
index 27981c3d36..8b435c9e6c 100644
--- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
@@ -57,7 +57,6 @@ import im.vector.app.features.home.room.list.RoomListViewModel
import im.vector.app.features.home.room.list.home.HomeRoomListViewModel
import im.vector.app.features.home.room.list.home.invites.InvitesViewModel
import im.vector.app.features.home.room.list.home.release.ReleaseNotesViewModel
-import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
import im.vector.app.features.invite.InviteUsersToRoomViewModel
import im.vector.app.features.location.LocationSharingViewModel
import im.vector.app.features.location.live.map.LiveLocationMapViewModel
@@ -500,11 +499,6 @@ interface MavericksViewModelModule {
@MavericksViewModelKey(StartAppViewModel::class)
fun startAppViewModelFactory(factory: StartAppViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
- @Binds
- @IntoMap
- @MavericksViewModelKey(HomeServerCapabilitiesViewModel::class)
- fun homeServerCapabilitiesViewModelFactory(factory: HomeServerCapabilitiesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
-
@Binds
@IntoMap
@MavericksViewModelKey(InviteUsersToRoomViewModel::class)
diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
index acaf24dca7..fbddf815c6 100644
--- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
@@ -93,6 +93,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
title = getString(R.string.fab_menu_create_chat),
menuResId = R.menu.vector_create_direct_room,
submitMenuItemId = R.id.action_create_direct_room,
+ single3pidSelection = true,
)
)
}
diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt
index 3f67708a28..dce1e63766 100644
--- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt
@@ -124,7 +124,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(
}
val result = runCatchingToAsync {
- if (vectorPreferences.isDeferredDmEnabled()) {
+ if (vectorPreferences.isDeferredDmEnabled() && roomParams.invite3pids.isEmpty()) {
session.roomService().createLocalRoom(roomParams)
} else {
analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse()))
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
index 2bb6fdb3e6..f363128ad5 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
@@ -1176,6 +1176,10 @@ class TimelineFragment :
views.hideComposerViews()
views.notificationAreaView.render(NotificationAreaView.State.Tombstone(mainState.tombstoneEvent))
}
+
+ if (summary.isDirect && summary.isEncrypted && summary.joinedMembersCount == 1 && summary.invitedMembersCount == 0) {
+ views.hideComposerViews()
+ }
} else if (summary?.membership == Membership.INVITE && inviter != null) {
views.hideComposerViews()
lazyLoadedViews.inviteView(true)?.apply {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt
index 69b4f6e039..9d757a5f2e 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt
@@ -56,22 +56,37 @@ class EncryptionItemFactory @Inject constructor(
val description: String
val shield: StatusTileTimelineItem.ShieldUIState
if (isSafeAlgorithm) {
- val isDirect = session.getRoomSummary(event.root.roomId.orEmpty())?.isDirect.orFalse()
- title = stringProvider.getString(R.string.encryption_enabled)
- description = stringProvider.getString(
+ val roomSummary = session.getRoomSummary(event.root.roomId.orEmpty())
+ val isDirect = roomSummary?.isDirect.orFalse()
+ val (resTitle, resDescription, resShield) = when {
+ isDirect -> {
+ val isWaitingUser = roomSummary?.isEncrypted.orFalse() && roomSummary?.joinedMembersCount == 1 && roomSummary.invitedMembersCount == 0
when {
- isDirect && RoomLocalEcho.isLocalEchoId(event.root.roomId.orEmpty()) -> {
- R.string.direct_room_encryption_enabled_tile_description_future
- }
- isDirect -> {
- R.string.direct_room_encryption_enabled_tile_description
- }
- else -> {
- R.string.encryption_enabled_tile_description
- }
+ RoomLocalEcho.isLocalEchoId(event.root.roomId.orEmpty()) -> Triple(
+ R.string.encryption_enabled,
+ R.string.direct_room_encryption_enabled_tile_description_future,
+ StatusTileTimelineItem.ShieldUIState.BLACK
+ )
+ isWaitingUser -> Triple(
+ R.string.direct_room_encryption_enabled_waiting_users,
+ R.string.direct_room_encryption_enabled_waiting_users_tile_description,
+ StatusTileTimelineItem.ShieldUIState.WAITING
+ )
+ else -> Triple(
+ R.string.encryption_enabled,
+ R.string.direct_room_encryption_enabled_tile_description,
+ StatusTileTimelineItem.ShieldUIState.BLACK
+ )
}
- )
- shield = StatusTileTimelineItem.ShieldUIState.BLACK
+ }
+ else -> {
+ Triple(R.string.encryption_enabled, R.string.encryption_enabled_tile_description, StatusTileTimelineItem.ShieldUIState.BLACK)
+ }
+ }
+
+ title = stringProvider.getString(resTitle)
+ description = stringProvider.getString(resDescription)
+ shield = resShield
} else {
title = stringProvider.getString(R.string.encryption_misconfigured)
description = stringProvider.getString(R.string.encryption_unknown_algorithm_tile_description)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt
index a5e2b0d064..d8a9170402 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt
@@ -40,6 +40,7 @@ import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.home.room.detail.timeline.tools.linkify
import im.vector.app.features.themes.ThemeUtils
import me.gujun.android.span.span
+import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
import org.matrix.android.sdk.api.util.toMatrixItem
@@ -127,26 +128,38 @@ abstract class MergedRoomCreationItem : BasedMergedItem {
- if (attributes.isLocalRoom) {
- resources.getString(R.string.direct_room_encryption_enabled_tile_description_future)
- } else {
- resources.getString(R.string.direct_room_encryption_enabled_tile_description)
+ val isWaitingUser = roomSummary?.isEncrypted.orFalse() && roomSummary?.joinedMembersCount == 1 && roomSummary?.invitedMembersCount == 0
+ when {
+ attributes.isLocalRoom -> Triple(
+ R.string.encryption_enabled,
+ R.string.direct_room_encryption_enabled_tile_description_future,
+ R.drawable.ic_shield_black
+ )
+ isWaitingUser -> Triple(
+ R.string.direct_room_encryption_enabled_waiting_users,
+ R.string.direct_room_encryption_enabled_waiting_users_tile_description,
+ R.drawable.ic_room_profile_member_list
+ )
+ else -> Triple(
+ R.string.encryption_enabled,
+ R.string.direct_room_encryption_enabled_tile_description,
+ R.drawable.ic_shield_black
+ )
}
}
else -> {
- resources.getString(R.string.encryption_enabled_tile_description)
+ Triple(R.string.encryption_enabled, R.string.encryption_enabled_tile_description, R.drawable.ic_shield_black)
}
}
- holder.e2eTitleTextView.text = holder.expandView.resources.getString(R.string.encryption_enabled)
+ holder.e2eTitleTextView.text = holder.expandView.resources.getString(title)
holder.e2eTitleTextView.setCompoundDrawablesWithIntrinsicBounds(
- ContextCompat.getDrawable(holder.view.context, R.drawable.ic_shield_black),
+ ContextCompat.getDrawable(holder.view.context, drawable),
null, null, null
)
- holder.e2eTitleDescriptionView.text = description
+ holder.e2eTitleDescriptionView.text = holder.expandView.resources.getString(description)
holder.e2eTitleDescriptionView.textAlignment = View.TEXT_ALIGNMENT_CENTER
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/StatusTileTimelineItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/StatusTileTimelineItem.kt
index 1e5bb0521d..5a0c024ec8 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/StatusTileTimelineItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/StatusTileTimelineItem.kt
@@ -57,6 +57,7 @@ abstract class StatusTileTimelineItem : AbsBaseMessageItem R.drawable.ic_shield_trusted
ShieldUIState.BLACK -> R.drawable.ic_shield_black
ShieldUIState.RED -> R.drawable.ic_shield_warning
+ ShieldUIState.WAITING -> R.drawable.ic_room_profile_member_list
ShieldUIState.ERROR -> R.drawable.ic_warning_badge
}
@@ -101,6 +102,7 @@ abstract class StatusTileTimelineItem : AbsBaseMessageItem(initialState) {
-
- @AssistedFactory
- interface Factory : MavericksAssistedViewModelFactory {
- override fun create(initialState: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel
- }
-
- companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() {
-
- override fun initialState(viewModelContext: ViewModelContext): HomeServerCapabilitiesViewState {
- val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getSafeActiveSession()
- return HomeServerCapabilitiesViewState(
- capabilities = session?.homeServerCapabilitiesService()?.getHomeServerCapabilities() ?: HomeServerCapabilities()
- )
- }
- }
-
- init {
-
- initAdminE2eByDefault()
- }
-
- private fun initAdminE2eByDefault() {
- viewModelScope.launch(Dispatchers.IO) {
- val adminE2EByDefault = tryOrNull {
- rawService.getElementWellknown(session.sessionParams)
- ?.isE2EByDefault()
- ?: true
- } ?: true
-
- setState {
- copy(
- isE2EByDefault = adminE2EByDefault
- )
- }
- }
- }
-
- override fun handle(action: EmptyAction) {}
-}
diff --git a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt
deleted file mode 100644
index d7ced5e632..0000000000
--- a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.app.features.homeserver
-
-import com.airbnb.mvrx.MavericksState
-import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
-
-data class HomeServerCapabilitiesViewState(
- val capabilities: HomeServerCapabilities = HomeServerCapabilities(),
- val isE2EByDefault: Boolean = true
-) : MavericksState
diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt
index 2131eda60e..54e43038b1 100644
--- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt
+++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt
@@ -25,6 +25,7 @@ import im.vector.app.R
import im.vector.app.core.epoxy.errorWithRetryItem
import im.vector.app.core.epoxy.loadingItem
import im.vector.app.core.epoxy.noResultItem
+import im.vector.app.core.epoxy.profiles.notifications.textHeaderItem
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.resources.StringProvider
@@ -61,6 +62,13 @@ class UserListController @Inject constructor(
val currentState = state ?: return
val host = this
+ if (currentState.isE2EByDefault && currentState.single3pidSelection && currentState.pendingSelections.isNotEmpty()) {
+ textHeaderItem {
+ id("userListNotificationHeader")
+ textRes(R.string.direct_room_user_list_only_invite_one_email)
+ }
+ }
+
// Build generic items
if (currentState.searchTerm.isBlank()) {
if (currentState.showInviteActions()) {
diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt
index fbb6a8ee14..6447452e5b 100644
--- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt
@@ -27,7 +27,6 @@ import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.args
-import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.google.android.material.chip.Chip
import dagger.hilt.android.AndroidEntryPoint
@@ -42,7 +41,6 @@ import im.vector.app.core.utils.DimensionConverter
import im.vector.app.core.utils.showIdentityServerConsentDialog
import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.databinding.FragmentUserListBinding
-import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
import im.vector.app.features.settings.VectorSettingsActivity
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -63,7 +61,6 @@ class UserListFragment :
private val args: UserListFragmentArgs by args()
private val viewModel: UserListViewModel by activityViewModel()
- private val homeServerCapabilitiesViewModel: HomeServerCapabilitiesViewModel by fragmentViewModel()
private lateinit var sharedActionViewModel: UserListSharedActionViewModel
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentUserListBinding {
@@ -86,7 +83,7 @@ class UserListFragment :
setupRecyclerView()
setupSearchView()
- homeServerCapabilitiesViewModel.onEach {
+ viewModel.onEach {
views.userListE2EbyDefaultDisabled.isVisible = !it.isE2EByDefault
}
diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt
index d6e55c29ae..0a0ae8127a 100644
--- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt
+++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt
@@ -26,6 +26,7 @@ data class UserListFragmentArgs(
val submitMenuItemId: Int,
val excludedUserIds: Set? = null,
val singleSelection: Boolean = false,
+ val single3pidSelection: Boolean = false,
val showInviteActions: Boolean = true,
val showContactBookAction: Boolean = true,
val showToolbar: Boolean = true
diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt
index 5a764f11fd..ae28ff020d 100644
--- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt
@@ -31,6 +31,9 @@ import im.vector.app.core.extensions.toggle
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.discovery.fetchIdentityServerWithTerms
+import im.vector.app.features.raw.wellknown.getElementWellknown
+import im.vector.app.features.raw.wellknown.isE2EByDefault
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter
@@ -41,6 +44,7 @@ import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
import org.matrix.android.sdk.api.session.identity.IdentityServiceListener
@@ -57,6 +61,7 @@ data class ThreePidUser(
class UserListViewModel @AssistedInject constructor(
@Assisted initialState: UserListViewState,
private val stringProvider: StringProvider,
+ private val rawService: RawService,
private val session: Session
) : VectorViewModel(initialState) {
@@ -84,6 +89,7 @@ class UserListViewModel @AssistedInject constructor(
}
init {
+ initAdminE2eByDefault()
observeUsers()
setState {
copy(
@@ -93,6 +99,22 @@ class UserListViewModel @AssistedInject constructor(
session.identityService().addListener(identityServerListener)
}
+ private fun initAdminE2eByDefault() {
+ viewModelScope.launch(Dispatchers.IO) {
+ val adminE2EByDefault = tryOrNull {
+ rawService.getElementWellknown(session.sessionParams)
+ ?.isE2EByDefault()
+ ?: true
+ } ?: true
+
+ setState {
+ copy(
+ isE2EByDefault = adminE2EByDefault
+ )
+ }
+ }
+ }
+
private fun cleanISURL(url: String?): String? {
return url?.removePrefix("https://")
}
@@ -258,8 +280,13 @@ class UserListViewModel @AssistedInject constructor(
}
private fun handleSelectUser(action: UserListAction.AddPendingSelection) = withState { state ->
- val selections = state.pendingSelections.toggle(action.pendingSelection, singleElement = state.singleSelection)
- setState { copy(pendingSelections = selections) }
+ val canSelectUser = !state.isE2EByDefault || state.pendingSelections.isEmpty() || !state.single3pidSelection ||
+ (action.pendingSelection is PendingSelection.UserPendingSelection &&
+ state.pendingSelections.last() is PendingSelection.UserPendingSelection)
+ if (canSelectUser) {
+ val selections = state.pendingSelections.toggle(action.pendingSelection, singleElement = state.singleSelection)
+ setState { copy(pendingSelections = selections) }
+ }
}
private fun handleRemoveSelectedUser(action: UserListAction.RemovePendingSelection) = withState { state ->
diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt
index f91e273aeb..ec932a2a57 100644
--- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt
@@ -32,6 +32,8 @@ data class UserListViewState(
val pendingSelections: Set = emptySet(),
val searchTerm: String = "",
val singleSelection: Boolean,
+ val single3pidSelection: Boolean,
+ val isE2EByDefault: Boolean = false,
val configuredIdentityServer: String? = null,
private val showInviteActions: Boolean,
val showContactBookAction: Boolean
@@ -40,6 +42,7 @@ data class UserListViewState(
constructor(args: UserListFragmentArgs) : this(
excludedUserIds = args.excludedUserIds,
singleSelection = args.singleSelection,
+ single3pidSelection = args.single3pidSelection,
showInviteActions = args.showInviteActions,
showContactBookAction = args.showContactBookAction
)