diff --git a/CHANGES.md b/CHANGES.md index c5d863ba71..b76b001268 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,9 @@ Bugfix 🐛: - Fix a problem with database migration on nightly builds (#3335) - Implement a workaround to render <del> and <u> in the timeline (#1817) - Make sure the SDK can retrieve the secret storage if the system is upgraded (#3304) + - Spaces | Personal spaces add DM - Web Parity (#3271) + - Spaces | Improve 'Leave Space' UX/UI (#3359) + - Don't create private spaces with encryption enabled (#3363) - #+ button on lower right when looking at an empty space goes to an empty 'Explore rooms' (#3327) Translations 🗣: diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index cac0d715f5..d488fdfc2a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -344,10 +344,9 @@ internal class RoomSummaryUpdater @Inject constructor( if (it != null) addAll(it) } }.distinct() - if (flattenRelated.isEmpty()) { - dmRoom.flattenParentIds = null - } else { - dmRoom.flattenParentIds = "|${flattenRelated.joinToString("|")}|" + if (flattenRelated.isNotEmpty()) { + // we keep real m.child/m.parent relations and add the one for common memberships + dmRoom.flattenParentIds += "|${flattenRelated.joinToString("|")}|" } // Timber.v("## SPACES: flatten of ${dmRoom.otherMemberIds.joinToString(",")} is ${dmRoom.flattenParentIds}") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt index f7fd77c528..4c29692213 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt @@ -81,7 +81,6 @@ internal class DefaultSpaceService @Inject constructor( } else { this.preset = CreateRoomPreset.PRESET_PRIVATE_CHAT visibility = RoomDirectoryVisibility.PRIVATE - enableEncryption() } }) } diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceSettingsMenuBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceSettingsMenuBottomSheet.kt index 491c14e415..66572f5a82 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceSettingsMenuBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceSettingsMenuBottomSheet.kt @@ -16,6 +16,7 @@ package im.vector.app.features.spaces +import android.content.DialogInterface import android.os.Bundle import android.os.Parcelable import android.view.LayoutInflater @@ -27,8 +28,10 @@ import com.airbnb.mvrx.args import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ScreenComponent +import im.vector.app.core.dialogs.withColoredButton import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.core.resources.ColorProvider import im.vector.app.databinding.BottomSheetSpaceSettingsBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.navigation.Navigator @@ -43,9 +46,11 @@ import im.vector.app.features.spaces.manage.SpaceManageActivity import io.reactivex.android.schedulers.AndroidSchedulers import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize +import me.gujun.android.span.span import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper +import org.matrix.android.sdk.api.session.room.powerlevels.Role import org.matrix.android.sdk.api.util.toMatrixItem import timber.log.Timber import javax.inject.Inject @@ -55,6 +60,7 @@ data class SpaceBottomSheetSettingsArgs( val spaceId: String ) : Parcelable +// XXX make proper view model before leaving beta class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment() { @Inject lateinit var navigator: Navigator @@ -62,6 +68,7 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment session.coroutineScope.launch { try { @@ -152,6 +189,7 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment>) { + if (disabled) { + super.addModels(emptyList()) + return + } val host = this val filteredModel = if (ignoreRooms == null) { models @@ -102,10 +122,13 @@ class AddRoomListController @Inject constructor( RoomCategoryItem_().apply { id("header") title(host.sectionName ?: "") - expanded(true) + expanded(host.expanded) + listener { + host.expanded = !host.expanded + } } ) - if (subHeaderText != null) { + if (expanded && subHeaderText != null) { add( GenericPillItem_().apply { id("sub_header") @@ -115,11 +138,13 @@ class AddRoomListController @Inject constructor( ) } } - super.addModels(filteredModel) - if (!initialLoadOccurred) { - add( - RoomSelectionPlaceHolderItem_().apply { id("loading") } - ) + if (expanded) { + super.addModels(filteredModel) + if (!initialLoadOccurred) { + add( + RoomSelectionPlaceHolderItem_().apply { id("loading") } + ) + } } } @@ -129,7 +154,7 @@ class AddRoomListController @Inject constructor( return RoomSelectionItem_().apply { id(item.roomId) matrixItem(item.toMatrixItem()) - avatarRenderer(this@AddRoomListController.avatarRenderer) + avatarRenderer(host.avatarRenderer) space(item.roomType == RoomType.SPACE) selected(host.selectedItems[item.roomId] ?: false) itemClickListener(DebouncedClickListener({ diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt index 203098d32b..05a2f19941 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt @@ -42,6 +42,7 @@ import javax.inject.Inject class SpaceAddRoomFragment @Inject constructor( private val spaceEpoxyController: AddRoomListController, private val roomEpoxyController: AddRoomListController, + private val dmEpoxyController: AddRoomListController, private val viewModelFactory: SpaceAddRoomsViewModel.Factory ) : VectorBaseFragment(), OnBackPressed, AddRoomListController.Listener, SpaceAddRoomsViewModel.Factory { @@ -84,6 +85,7 @@ class SpaceAddRoomFragment @Inject constructor( viewModel.selectionListLiveData.observe(viewLifecycleOwner) { spaceEpoxyController.selectedItems = it roomEpoxyController.selectedItems = it + dmEpoxyController.selectedItems = it saveNeeded = it.values.any { it } invalidateOptionsMenu() } @@ -95,6 +97,7 @@ class SpaceAddRoomFragment @Inject constructor( viewModel.selectSubscribe(this, SpaceAddRoomsState::ignoreRooms) { spaceEpoxyController.ignoreRooms = it roomEpoxyController.ignoreRooms = it + dmEpoxyController.ignoreRooms = it }.disposeOnDestroyView() viewModel.selectSubscribe(this, SpaceAddRoomsState::isSaving) { @@ -105,6 +108,10 @@ class SpaceAddRoomFragment @Inject constructor( } }.disposeOnDestroyView() + viewModel.selectSubscribe(this, SpaceAddRoomsState::shouldShowDMs) { + dmEpoxyController.disabled = !it + }.disposeOnDestroyView() + views.createNewRoom.debouncedClicks { sharedViewModel.handle(SpaceManagedSharedAction.CreateRoom) } @@ -121,11 +128,11 @@ class SpaceAddRoomFragment @Inject constructor( .setNegativeButton(R.string.cancel, null) .show() } - is SpaceAddRoomsViewEvents.SaveFailed -> { + is SpaceAddRoomsViewEvents.SaveFailed -> { showErrorInSnackbar(it.reason) invalidateOptionsMenu() } - SpaceAddRoomsViewEvents.SavedDone -> { + SpaceAddRoomsViewEvents.SavedDone -> { sharedViewModel.handle(SpaceManagedSharedAction.HandleBack) } } @@ -149,6 +156,7 @@ class SpaceAddRoomFragment @Inject constructor( views.roomList.cleanup() spaceEpoxyController.listener = null roomEpoxyController.listener = null + dmEpoxyController.listener = null super.onDestroyView() } @@ -181,6 +189,19 @@ class SpaceAddRoomFragment @Inject constructor( concatAdapter.addAdapter(roomEpoxyController.adapter) concatAdapter.addAdapter(spaceEpoxyController.adapter) + // This controller can be disabled depending on the space type (public or not) + viewModel.updatableDMLivePageResult.liveBoundaries.observe(viewLifecycleOwner) { + dmEpoxyController.boundaryChange(it) + } + viewModel.updatableDMLivePageResult.livePagedList.observe(viewLifecycleOwner) { + dmEpoxyController.totalSize = it.size + dmEpoxyController.submitList(it) + } + dmEpoxyController.sectionName = getString(R.string.direct_chats_header) + dmEpoxyController.listener = this + + concatAdapter.addAdapter(dmEpoxyController.adapter) + views.roomList.adapter = concatAdapter } diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsState.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsState.kt index 6ce3468fe1..2d9113ae68 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsState.kt @@ -26,7 +26,8 @@ data class SpaceAddRoomsState( val currentFilter: String = "", val spaceName: String = "", val ignoreRooms: List = emptyList(), - val isSaving: Async> = Uninitialized + val isSaving: Async> = Uninitialized, + val shouldShowDMs : Boolean = false // val selectionList: Map = emptyMap() ) : MvRxState { constructor(args: SpaceManageArgs) : this( diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt index 55e65eb171..35c415b087 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt @@ -98,6 +98,26 @@ class SpaceAddRoomsViewModel @AssistedInject constructor( ) } + val updatableDMLivePageResult: UpdatableLivePageResult by lazy { + session.getFilteredPagedRoomSummariesLive( + roomSummaryQueryParams { + this.memberships = listOf(Membership.JOIN) + this.excludeType = listOf(RoomType.SPACE) + this.includeType = null + this.roomCategoryFilter = RoomCategoryFilter.ONLY_DM + this.activeSpaceFilter = ActiveSpaceFilter.ExcludeSpace(initialState.spaceId) + this.displayName = QueryStringValue.Contains(initialState.currentFilter, QueryStringValue.Case.INSENSITIVE) + }, + pagedListConfig = PagedList.Config.Builder() + .setPageSize(10) + .setInitialLoadSizeHint(20) + .setEnablePlaceholders(true) + .setPrefetchDistance(10) + .build(), + sortOrder = RoomSortOrder.NAME + ) + } + private val selectionList = mutableMapOf() val selectionListLiveData = MutableLiveData>() @@ -106,7 +126,8 @@ class SpaceAddRoomsViewModel @AssistedInject constructor( setState { copy( spaceName = spaceSummary?.displayName ?: "", - ignoreRooms = (spaceSummary?.flattenParentIds ?: emptyList()) + listOf(initialState.spaceId) + ignoreRooms = (spaceSummary?.flattenParentIds ?: emptyList()) + listOf(initialState.spaceId), + shouldShowDMs = spaceSummary?.isPublic == false ) } } diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 56e27dce86..9473f01ccd 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -3353,6 +3353,9 @@ Add rooms Leave Space Are you sure you want to leave the space? + You are the only person here. If you leave, no one will be able to join in the future, including you. + This space is not public. You will not be able to rejoin without an invite. + You are admin of this space, ensure that you have transferred admin right to another member before leaving. Add existing rooms and space