diff --git a/CHANGES.md b/CHANGES.md index 79ea40de59..fa30acabd5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ Features ✨: - Improvements 🙌: - - + - Open an existing DM instead of creating a new one (#2319) Bugfix 🐛: - Fix issue when updating the avatar of a room diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomAction.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomAction.kt index f6fc3fed5b..ce91761fdd 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomAction.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomAction.kt @@ -20,5 +20,8 @@ import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.features.userdirectory.PendingInvitee sealed class CreateDirectRoomAction : VectorViewModelAction { - data class CreateRoomAndInviteSelectedUsers(val invitees: Set) : CreateDirectRoomAction() + data class CreateRoomAndInviteSelectedUsers( + val invitees: Set, + val existingDmRoomId: String? + ) : CreateDirectRoomAction() } 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 a1bb12a84b..10ab1673e4 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 @@ -91,7 +91,8 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { KnownUsersFragment::class.java, KnownUsersFragmentArgs( title = getString(R.string.fab_menu_create_chat), - menuResId = R.menu.vector_create_direct_room + menuResId = R.menu.vector_create_direct_room, + isCreatingRoom = true ) ) } @@ -121,7 +122,10 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { private fun onMenuItemSelected(action: UserDirectorySharedAction.OnMenuItemSelected) { if (action.itemId == R.id.action_create_direct_room) { - viewModel.handle(CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers(action.invitees)) + viewModel.handle(CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers( + action.invitees, + action.existingDmRoomId + )) } } 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 c42e10686f..be9449b77a 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 @@ -19,6 +19,7 @@ package im.vector.app.features.createdirect import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject @@ -56,7 +57,22 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted override fun handle(action: CreateDirectRoomAction) { when (action) { - is CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers -> createRoomAndInviteSelectedUsers(action.invitees) + is CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers -> onSubmitInvitees(action) + }.exhaustive + } + + /** + * If users already have a DM room then navigate to it instead of creating a new room. + */ + private fun onSubmitInvitees(action: CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers) { + if (action.existingDmRoomId != null) { + // Do not create a new DM, just tell that the creation is successful by passing the existing roomId + setState { + copy(createAndInviteState = Success(action.existingDmRoomId)) + } + } else { + // Create the DM + createRoomAndInviteSelectedUsers(action.invitees) } } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt index c832fe4833..0ca46cd154 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt @@ -91,13 +91,20 @@ class KnownUsersFragment @Inject constructor( val showMenuItem = it.pendingInvitees.isNotEmpty() menu.forEach { menuItem -> menuItem.isVisible = showMenuItem + if (args.isCreatingRoom) { + menuItem.setTitle(if (it.existingDmRoomId != null) R.string.action_open else R.string.create_room_action_create) + } } } super.onPrepareOptionsMenu(menu) } override fun onOptionsItemSelected(item: MenuItem): Boolean = withState(viewModel) { - sharedActionViewModel.post(UserDirectorySharedAction.OnMenuItemSelected(item.itemId, it.pendingInvitees)) + sharedActionViewModel.post(UserDirectorySharedAction.OnMenuItemSelected( + item.itemId, + it.pendingInvitees, + it.existingDmRoomId + )) return@withState true } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt index 65fd6681bf..c20aedb803 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt @@ -23,5 +23,6 @@ import kotlinx.android.parcel.Parcelize data class KnownUsersFragmentArgs( val title: String, val menuResId: Int, - val excludedUserIds: Set? = null + val excludedUserIds: Set? = null, + val isCreatingRoom: Boolean = false ) : Parcelable diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt index a4ae0d1be2..14daa67f25 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt @@ -23,5 +23,7 @@ sealed class UserDirectorySharedAction : VectorSharedAction { object OpenPhoneBook : UserDirectorySharedAction() object Close : UserDirectorySharedAction() object GoBack : UserDirectorySharedAction() - data class OnMenuItemSelected(val itemId: Int, val invitees: Set) : UserDirectorySharedAction() + data class OnMenuItemSelected(val itemId: Int, + val invitees: Set, + val existingDmRoomId: String?) : UserDirectorySharedAction() } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt index b8c42a0f08..0a24b85ce2 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt @@ -87,14 +87,32 @@ class UserDirectoryViewModel @AssistedInject constructor(@Assisted private fun handleRemoveSelectedUser(action: UserDirectoryAction.RemovePendingInvitee) = withState { state -> val selectedUsers = state.pendingInvitees.minus(action.pendingInvitee) - setState { copy(pendingInvitees = selectedUsers) } + setState { + copy( + pendingInvitees = selectedUsers, + existingDmRoomId = getExistingDmRoomId(selectedUsers) + ) + } } private fun handleSelectUser(action: UserDirectoryAction.SelectPendingInvitee) = withState { state -> // Reset the filter asap directoryUsersSearch.accept("") val selectedUsers = state.pendingInvitees.toggle(action.pendingInvitee) - setState { copy(pendingInvitees = selectedUsers) } + setState { + copy( + pendingInvitees = selectedUsers, + existingDmRoomId = getExistingDmRoomId(selectedUsers) + ) + } + } + + private fun getExistingDmRoomId(selectedUsers: Set): String? { + return selectedUsers + .takeIf { it.size == 1 } + ?.filterIsInstance(PendingInvitee.UserPendingInvitee::class.java) + ?.firstOrNull() + ?.let { invitee -> session.getExistingDirectRoomWithUser(invitee.user.userId) } } private fun observeDirectoryUsers() = withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt index 8bb555e0fa..fe79a8ab37 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt @@ -30,7 +30,8 @@ data class UserDirectoryViewState( val pendingInvitees: Set = emptySet(), val createAndInviteState: Async = Uninitialized, val directorySearchTerm: String = "", - val filterKnownUsersValue: Option = Option.empty() + val filterKnownUsersValue: Option = Option.empty(), + val existingDmRoomId: String? = null ) : MvRxState { constructor(args: KnownUsersFragmentArgs) : this(excludedUserIds = args.excludedUserIds)