From 932a43ef58a1b437f99f36b88190e757038c283e Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 27 Aug 2021 14:03:11 +0200 Subject: [PATCH] Add subspace action --- .../values/stylable_bottom_sheet_action.xml | 1 + .../java/im/vector/app/AppStateHandler.kt | 16 +- .../core/ui/views/BottomSheetActionButton.kt | 9 + .../app/features/home/HomeDetailFragment.kt | 16 +- .../createroom/CreateRoomActivity.kt | 9 +- .../createroom/CreateRoomFragment.kt | 46 +++++- .../createroom/CreateRoomViewModel.kt | 14 ++ .../createroom/CreateRoomViewState.kt | 6 +- .../createroom/CreateSubSpaceController.kt | 155 ++++++++++++++++++ .../joinrule/RoomJoinRuleBottomSheet.kt | 10 +- .../joinrule/RoomJoinRuleController.kt | 26 +-- .../settings/joinrule/RoomJoinRuleState.kt | 8 +- .../spaces/SpaceSettingsMenuBottomSheet.kt | 11 +- .../spaces/create/WizardButtonView.kt | 2 +- .../spaces/explore/SpaceDirectoryFragment.kt | 24 ++- .../spaces/manage/SpaceAddRoomFragment.kt | 25 ++- .../SpaceAddRoomSpaceChooserBottomSheet.kt | 76 +++++++++ .../spaces/manage/SpaceAddRoomsState.kt | 6 +- .../spaces/manage/SpaceAddRoomsViewModel.kt | 2 +- .../spaces/manage/SpaceManageActivity.kt | 12 +- .../manage/SpaceManageSharedViewModel.kt | 4 +- .../spaces/manage/SpaceManageViewState.kt | 1 + .../spaces/manage/SpaceManagedSharedAction.kt | 1 + .../manage/SpaceManagedSharedViewEvents.kt | 1 + .../spaces/manage/SpaceSettingsController.kt | 51 +++--- .../spaces/manage/SpaceSettingsFragment.kt | 8 +- ...tom_sheet_add_rooms_or_spaces_to_space.xml | 45 +++++ .../layout/bottom_sheet_space_settings.xml | 21 +-- .../res/layout/item_generic_pill_footer.xml | 2 +- .../view_bottom_sheet_action_button.xml | 15 +- vector/src/main/res/values/strings.xml | 8 + 31 files changed, 546 insertions(+), 85 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateSubSpaceController.kt create mode 100644 vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomSpaceChooserBottomSheet.kt create mode 100644 vector/src/main/res/layout/bottom_sheet_add_rooms_or_spaces_to_space.xml diff --git a/library/ui-styles/src/main/res/values/stylable_bottom_sheet_action.xml b/library/ui-styles/src/main/res/values/stylable_bottom_sheet_action.xml index d6fa160d6b..b0c45b1fea 100644 --- a/library/ui-styles/src/main/res/values/stylable_bottom_sheet_action.xml +++ b/library/ui-styles/src/main/res/values/stylable_bottom_sheet_action.xml @@ -8,6 +8,7 @@ + diff --git a/vector/src/main/java/im/vector/app/AppStateHandler.kt b/vector/src/main/java/im/vector/app/AppStateHandler.kt index 06174b9573..e0a26b9183 100644 --- a/vector/src/main/java/im/vector/app/AppStateHandler.kt +++ b/vector/src/main/java/im/vector/app/AppStateHandler.kt @@ -59,7 +59,21 @@ class AppStateHandler @Inject constructor( val selectedRoomGroupingObservable = selectedSpaceDataSource.observe() - fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? = selectedSpaceDataSource.currentValue?.orNull() + fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? { + // XXX we should somehow make it live :/ just a work around + // For example just after creating a space and switching to it the + // name in the app Bar could show Empty Room, and it will not update unless you + // switch space + return selectedSpaceDataSource.currentValue?.orNull()?.let { + if (it is RoomGroupingMethod.BySpace) { + // try to refresh sum? + return it.spaceSummary?.roomId?.let { activeSessionHolder.getSafeActiveSession()?.getRoomSummary(it) }?.let { + RoomGroupingMethod.BySpace(it) + } ?: it + } + return it + } + } fun setCurrentSpace(spaceId: String?, session: Session? = null) { val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return diff --git a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt index 97194f2c03..959767dd75 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt @@ -81,6 +81,7 @@ class BottomSheetActionButton @JvmOverloads constructor( set(value) { field = value views.bottomSheetActionIcon.setImageDrawable(value) + views.bottomSheetActionIcon.isVisible = field != null } var tint: Int? = null @@ -95,6 +96,12 @@ class BottomSheetActionButton @JvmOverloads constructor( value?.let { views.bottomSheetActionTitle.setTextColor(it) } } + var isBetaAction: Boolean? = null + set(value) { + field = value + views.bottomSheetActionBeta.isVisible = field ?: false + } + init { inflate(context, R.layout.view_bottom_sheet_action_button, this) views = ViewBottomSheetActionButtonBinding.bind(this) @@ -109,6 +116,8 @@ class BottomSheetActionButton @JvmOverloads constructor( tint = getColor(R.styleable.BottomSheetActionButton_tint, ThemeUtils.getColor(context, android.R.attr.textColor)) titleTextColor = getColor(R.styleable.BottomSheetActionButton_titleTextColor, ThemeUtils.getColor(context, R.attr.colorPrimary)) + + isBetaAction = getBoolean(R.styleable.BottomSheetActionButton_betaAction, false) } } } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index 9b71d1c90c..95430746a4 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -29,6 +29,7 @@ import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.google.android.material.badge.BadgeDrawable +import im.vector.app.AppStateHandler import im.vector.app.R import im.vector.app.RoomGroupingMethod import im.vector.app.core.extensions.commitTransaction @@ -69,7 +70,8 @@ class HomeDetailFragment @Inject constructor( private val colorProvider: ColorProvider, private val alertManager: PopupAlertManager, private val callManager: WebRtcCallManager, - private val vectorPreferences: VectorPreferences + private val vectorPreferences: VectorPreferences, + private val appStateHandler: AppStateHandler ) : VectorBaseFragment(), KeysBackupBanner.Delegate, CurrentCallsView.Callback, @@ -204,6 +206,18 @@ class HomeDetailFragment @Inject constructor( // update notification tab if needed updateTabVisibilitySafely(R.id.bottom_action_notification, vectorPreferences.labAddNotificationTab()) callManager.checkForProtocolsSupportIfNeeded() + + // Current space/group is not live so at least refresh toolbar on resume + appStateHandler.getCurrentRoomGroupingMethod()?.let { roomGroupingMethod -> + when (roomGroupingMethod) { + is RoomGroupingMethod.ByLegacyGroup -> { + onGroupChange(roomGroupingMethod.groupSummary) + } + is RoomGroupingMethod.BySpace -> { + onSpaceChange(roomGroupingMethod.spaceSummary) + } + } + } } private fun promptForNewUnknownDevices(uid: String, state: UnknownDevicesState, newest: DeviceInfo) { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt index 07dfadb753..08659187ad 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt @@ -53,7 +53,10 @@ class CreateRoomActivity : VectorBaseActivity(), ToolbarC addFragment( R.id.simpleFragmentContainer, CreateRoomFragment::class.java, - CreateRoomArgs(intent?.getStringExtra(INITIAL_NAME) ?: "") + CreateRoomArgs( + intent?.getStringExtra(INITIAL_NAME) ?: "", + isSubSpace = intent?.getBooleanExtra(IS_SPACE, false) ?: false + ) ) } } @@ -74,10 +77,12 @@ class CreateRoomActivity : VectorBaseActivity(), ToolbarC companion object { private const val INITIAL_NAME = "INITIAL_NAME" + private const val IS_SPACE = "IS_SPACE" - fun getIntent(context: Context, initialName: String = ""): Intent { + fun getIntent(context: Context, initialName: String = "", isSpace: Boolean = false): Intent { return Intent(context, CreateRoomActivity::class.java).apply { putExtra(INITIAL_NAME, initialName) + putExtra(IS_SPACE, isSpace) } } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt index fdc2bd8562..316de6729b 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -38,6 +38,7 @@ import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.databinding.FragmentCreateRoomBinding +import im.vector.app.features.navigation.Navigator import im.vector.app.features.roomdirectory.RoomDirectorySharedAction import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleBottomSheet @@ -51,11 +52,13 @@ import javax.inject.Inject @Parcelize data class CreateRoomArgs( val initialName: String, - val parentSpaceId: String? = null + val parentSpaceId: String? = null, + val isSubSpace: Boolean = false ) : Parcelable class CreateRoomFragment @Inject constructor( private val createRoomController: CreateRoomController, + private val createSpaceController: CreateSubSpaceController, val createRoomViewModelFactory: CreateRoomViewModel.Factory, colorProvider: ColorProvider ) : VectorBaseFragment(), @@ -93,6 +96,11 @@ class CreateRoomFragment @Inject constructor( } } + override fun onResume() { + super.onResume() + views.createRoomTitle.text = getString(if (args.isSubSpace) R.string.create_new_space else R.string.create_new_room) + } + private fun setupRoomJoinRuleSharedActionViewModel() { roomJoinRuleSharedActionViewModel = activityViewModelProvider.get(RoomJoinRuleSharedActionViewModel::class.java) roomJoinRuleSharedActionViewModel @@ -112,18 +120,26 @@ class CreateRoomFragment @Inject constructor( private fun setupWaitingView() { views.waitingView.waitingStatusText.isVisible = true - views.waitingView.waitingStatusText.setText(R.string.create_room_in_progress) + views.waitingView.waitingStatusText.setText( + if (args.isSubSpace) R.string.create_space_in_progress else R.string.create_room_in_progress + ) } override fun onDestroyView() { views.createRoomForm.cleanup() createRoomController.listener = null + createSpaceController.listener = null super.onDestroyView() } private fun setupRecyclerView() { - views.createRoomForm.configureWith(createRoomController) - createRoomController.listener = this + if (args.isSubSpace) { + views.createRoomForm.configureWith(createSpaceController) + createSpaceController.listener = this + } else { + views.createRoomForm.configureWith(createRoomController) + createRoomController.listener = this + } } override fun onAvatarDelete() { @@ -153,7 +169,11 @@ class CreateRoomFragment @Inject constructor( } else { listOf(RoomJoinRules.INVITE, RoomJoinRules.PUBLIC) } - RoomJoinRuleBottomSheet.newInstance(state.roomJoinRules, allowed.map { it.toOption(false) }) + RoomJoinRuleBottomSheet.newInstance(state.roomJoinRules, + allowed.map { it.toOption(false) }, + state.isSubSpace, + state.parentSpaceSummary?.displayName + ) .show(childFragmentManager, "RoomJoinRuleBottomSheet") } // override fun setIsPublic(isPublic: Boolean) { @@ -203,12 +223,24 @@ class CreateRoomFragment @Inject constructor( views.waitingView.root.isVisible = async is Loading if (async is Success) { // Navigate to freshly created room - navigator.openRoom(requireActivity(), async()) + if (state.isSubSpace) { + navigator.switchToSpace( + requireContext(), + async(), + Navigator.PostSwitchSpaceAction.None + ) + } else { + navigator.openRoom(requireActivity(), async()) + } sharedActionViewModel.post(RoomDirectorySharedAction.Close) } else { // Populate list with Epoxy - createRoomController.setData(state) + if (args.isSubSpace) { + createSpaceController.setData(state) + } else { + createRoomController.setData(state) + } } } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index fb70003dcf..9a9812933b 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -42,9 +42,11 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.room.alias.RoomAliasError import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure +import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry +import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset import org.matrix.android.sdk.api.session.room.model.create.RestrictedRoomPreset @@ -241,6 +243,18 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init name = state.roomName.takeIf { it.isNotBlank() } topic = state.roomTopic.takeIf { it.isNotBlank() } avatarUri = state.avatarUri + + if (state.isSubSpace) { + // Space-rooms are distinguished from regular messaging rooms by the m.room.type of m.space + roomType = RoomType.SPACE + + // Space-rooms should be created with a power level for events_default of 100, + // to prevent the rooms accidentally/maliciously clogging up with messages from random members of the space. + powerLevelContentOverride = PowerLevelsContent( + eventsDefault = 100 + ) + } + when (state.roomJoinRules) { RoomJoinRules.PUBLIC -> { // Directory visibility diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt index 06742ea690..3d813c3ee3 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt @@ -37,12 +37,14 @@ data class CreateRoomViewState( val parentSpaceId: String?, val parentSpaceSummary: RoomSummary? = null, val supportsRestricted: Boolean = false, - val aliasLocalPart: String? = null + val aliasLocalPart: String? = null, + val isSubSpace: Boolean = false ) : MvRxState { constructor(args: CreateRoomArgs) : this( roomName = args.initialName, - parentSpaceId = args.parentSpaceId + parentSpaceId = args.parentSpaceId, + isSubSpace = args.isSubSpace ) /** diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateSubSpaceController.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateSubSpaceController.kt new file mode 100644 index 0000000000..2dffd2bff8 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateSubSpaceController.kt @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.roomdirectory.createroom + +import com.airbnb.epoxy.TypedEpoxyController +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import im.vector.app.R +import im.vector.app.core.epoxy.profiles.buildProfileAction +import im.vector.app.core.resources.StringProvider +import im.vector.app.core.ui.list.genericPillItem +import im.vector.app.features.discovery.settingsSectionTitleItem +import im.vector.app.features.form.formEditTextItem +import im.vector.app.features.form.formEditableSquareAvatarItem +import im.vector.app.features.form.formMultiLineEditTextItem +import im.vector.app.features.form.formSubmitButtonItem +import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure +import org.matrix.android.sdk.api.session.room.model.RoomJoinRules +import javax.inject.Inject + +class CreateSubSpaceController @Inject constructor( + private val stringProvider: StringProvider, + private val roomAliasErrorFormatter: RoomAliasErrorFormatter +) : TypedEpoxyController() { + + var listener: CreateRoomController.Listener? = null + + override fun buildModels(viewState: CreateRoomViewState) { + // display the form + buildForm(viewState, viewState.asyncCreateRoomRequest !is Loading) + } + + private fun buildForm(data: CreateRoomViewState, enableFormElement: Boolean) { + val host = this + + if (data.isSubSpace) { + genericPillItem { + id("beta") + imageRes(R.drawable.ic_beta_pill) + tintIcon(false) + text(host.stringProvider.getString(R.string.space_add_space_to_any_space_you_manage)) + } + } + + formEditableSquareAvatarItem { + id("avatar") + enabled(enableFormElement) + imageUri(data.avatarUri) + clickListener { host.listener?.onAvatarChange() } + deleteListener { host.listener?.onAvatarDelete() } + } + + formEditTextItem { + id("name") + enabled(enableFormElement) + enabled(true) + value(data.roomName) + hint(host.stringProvider.getString(R.string.create_room_name_hint)) + onTextChange { text -> + host.listener?.onNameChange(text) + } + } + + if (data.roomJoinRules == RoomJoinRules.PUBLIC) { + formEditTextItem { + id("alias") + enabled(enableFormElement) + value(data.aliasLocalPart) + hint(host.stringProvider.getString(R.string.create_space_alias_hint)) + suffixText(":" + data.homeServerName) + prefixText("#") + errorMessage( + host.roomAliasErrorFormatter.format( + (((data.asyncCreateRoomRequest as? Fail)?.error) as? CreateRoomFailure.AliasError)?.aliasError) + ) + onTextChange { value -> + host.listener?.setAliasLocalPart(value) + } + } + } + + formMultiLineEditTextItem { + id("topic") + enabled(enableFormElement) + value(data.roomTopic) + hint(host.stringProvider.getString(R.string.create_space_topic_hint)) + textSizeSp(16) + onTextChange { text -> + host.listener?.onTopicChange(text) + } + } + + settingsSectionTitleItem { + id("visibility") + titleResId(R.string.room_settings_space_access_title) + } + + when (data.roomJoinRules) { + RoomJoinRules.INVITE -> { + buildProfileAction( + id = "joinRule", + title = stringProvider.getString(R.string.room_settings_room_access_private_title), + subtitle = stringProvider.getString(R.string.room_settings_room_access_private_description), + divider = false, + editable = true, + action = { host.listener?.selectVisibility() } + ) + } + RoomJoinRules.PUBLIC -> { + buildProfileAction( + id = "joinRule", + title = stringProvider.getString(R.string.room_settings_room_access_public_title), + subtitle = stringProvider.getString(R.string.room_settings_room_access_public_description), + divider = false, + editable = true, + action = { host.listener?.selectVisibility() } + ) + } + RoomJoinRules.RESTRICTED -> { + buildProfileAction( + id = "joinRule", + title = stringProvider.getString(R.string.room_settings_room_access_restricted_title), + subtitle = stringProvider.getString(R.string.room_create_member_of_space_name_can_join, data.parentSpaceSummary?.displayName), + divider = false, + editable = true, + action = { host.listener?.selectVisibility() } + ) + } + else -> { + // not yet supported + } + } + + formSubmitButtonItem { + id("submit") + enabled(enableFormElement && data.roomName.isNullOrBlank().not()) + buttonTitleId(R.string.create_room_action_create) + buttonClickListener { host.listener?.submit() } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt index f4c7eecf8f..f0f8193cc5 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt @@ -39,7 +39,9 @@ fun RoomJoinRules.toOption(needUpgrade: Boolean) = JoinRulesOptionSupport(this, @Parcelize data class RoomJoinRuleBottomSheetArgs( val currentRoomJoinRule: RoomJoinRules, - val allowedJoinedRules: List + val allowedJoinedRules: List, + val isSpace: Boolean = false, + val parentSpaceName: String? ) : Parcelable class RoomJoinRuleBottomSheet : BottomSheetGeneric() { @@ -73,11 +75,13 @@ class RoomJoinRuleBottomSheet : BottomSheetGeneric = listOf( RoomJoinRules.INVITE, RoomJoinRules.PUBLIC - ).map { it.toOption(true) } + ).map { it.toOption(true) }, + isSpace: Boolean = false, + parentSpaceName: String? = null ): RoomJoinRuleBottomSheet { return RoomJoinRuleBottomSheet().apply { setArguments( - RoomJoinRuleBottomSheetArgs(currentRoomJoinRule, allowedJoinedRules) + RoomJoinRuleBottomSheetArgs(currentRoomJoinRule, allowedJoinedRules, isSpace, parentSpaceName) ) } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleController.kt index edeb6e1099..2552a2568c 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleController.kt @@ -20,8 +20,6 @@ import im.vector.app.R import im.vector.app.core.resources.DrawableProvider import im.vector.app.core.resources.StringProvider import im.vector.app.core.ui.bottomsheet.BottomSheetGenericController -import me.gujun.android.span.image -import me.gujun.android.span.span import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import javax.inject.Inject @@ -30,7 +28,11 @@ class RoomJoinRuleController @Inject constructor( private val drawableProvider: DrawableProvider ) : BottomSheetGenericController() { - override fun getTitle() = stringProvider.getString(R.string.room_settings_room_access_rules_pref_dialog_title) + override fun getTitle() = + stringProvider.getString( + // generic title for both room and space + R.string.room_settings_access_rules_pref_dialog_title + ) override fun getActions(state: RoomJoinRuleState): List { return listOf( @@ -42,21 +44,21 @@ class RoomJoinRuleController @Inject constructor( ), RoomJoinRuleRadioAction( roomJoinRule = RoomJoinRules.PUBLIC, - description = stringProvider.getString(R.string.room_settings_room_access_public_description), + description = stringProvider.getString( + if (state.isSpace) R.string.room_settings_space_access_public_description + else R.string.room_settings_room_access_public_description + ), title = stringProvider.getString(R.string.room_settings_room_access_public_title), isSelected = state.currentRoomJoinRule == RoomJoinRules.PUBLIC ), RoomJoinRuleRadioAction( roomJoinRule = RoomJoinRules.RESTRICTED, - description = stringProvider.getString(R.string.room_settings_room_access_restricted_description), - title = span { - +stringProvider.getString(R.string.room_settings_room_access_restricted_title) - +" " - image( - drawableProvider.getDrawable(R.drawable.ic_beta_pill)!!, - "bottom" - ) + description = if (state.parentSpaceName != null) { + stringProvider.getString(R.string.room_create_member_of_space_name_can_join, state.parentSpaceName) + } else { + stringProvider.getString(R.string.room_settings_room_access_restricted_description) }, + title = stringProvider.getString(R.string.room_settings_room_access_restricted_title), isSelected = state.currentRoomJoinRule == RoomJoinRules.RESTRICTED ) ).filter { state.allowedJoinedRules.map { it.rule }.contains(it.roomJoinRule) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleState.kt index dd818a4631..dcf115cc4b 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleState.kt @@ -24,11 +24,15 @@ data class RoomJoinRuleState( val currentRoomJoinRule: RoomJoinRules = RoomJoinRules.INVITE, val allowedJoinedRules: List = listOf(RoomJoinRules.INVITE, RoomJoinRules.PUBLIC).map { it.toOption(true) }, - val currentGuestAccess: GuestAccess? = null + val currentGuestAccess: GuestAccess? = null, + val isSpace: Boolean = false, + val parentSpaceName: String? ) : BottomSheetGenericState() { constructor(args: RoomJoinRuleBottomSheetArgs) : this( currentRoomJoinRule = args.currentRoomJoinRule, - allowedJoinedRules = args.allowedJoinedRules + allowedJoinedRules = args.allowedJoinedRules, + isSpace = args.isSpace, + parentSpaceName = args.parentSpaceName ) } 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 fa035bebc9..040f1f9057 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 @@ -33,7 +33,6 @@ import im.vector.app.databinding.BottomSheetSpaceSettingsBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.navigation.Navigator import im.vector.app.features.rageshake.BugReporter -import im.vector.app.features.rageshake.ReportType import im.vector.app.features.roomprofile.RoomProfileActivity import im.vector.app.features.spaces.manage.ManageType import im.vector.app.features.spaces.manage.SpaceManageActivity @@ -79,10 +78,6 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment + + bundle.getString(SpaceAddRoomSpaceChooserBottomSheet.BUNDLE_KEY_ACTION)?.let { action -> + val spaceId = withState(viewModel) { it.spaceId } + when (action) { + SpaceAddRoomSpaceChooserBottomSheet.ACTION_ADD_ROOMS -> { + addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRooms)) + } + SpaceAddRoomSpaceChooserBottomSheet.ACTION_ADD_SPACES -> { + addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRoomsOnlySpaces)) + } + else -> { + // nop + } + } + } + } + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -170,7 +192,7 @@ class SpaceDirectoryFragment @Inject constructor( } override fun addExistingRooms(spaceId: String) { - addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRooms)) + SpaceAddRoomSpaceChooserBottomSheet.newInstance(spaceId).show(childFragmentManager, "SpaceAddRoomSpaceChooserBottomSheet") } override fun loadAdditionalItemsIfNeeded() { 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 b2fb061731..ee388b336c 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 @@ -27,6 +27,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.airbnb.mvrx.Loading import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.jakewharton.rxbinding3.appcompat.queryTextChanges import im.vector.app.R @@ -109,11 +110,23 @@ class SpaceAddRoomFragment @Inject constructor( }.disposeOnDestroyView() viewModel.selectSubscribe(this, SpaceAddRoomsState::shouldShowDMs) { - dmEpoxyController.disabled = !it + dmEpoxyController.disabled = !it + }.disposeOnDestroyView() + + viewModel.selectSubscribe(this, SpaceAddRoomsState::onlyShowSpaces) { + spaceEpoxyController.disabled = !it + roomEpoxyController.disabled = it + views.createNewRoom.text = if (it) getString(R.string.create_space) else getString(R.string.create_new_room) }.disposeOnDestroyView() views.createNewRoom.debouncedClicks { - sharedViewModel.handle(SpaceManagedSharedAction.CreateRoom) + withState(viewModel) { state -> + if (state.onlyShowSpaces) { + sharedViewModel.handle(SpaceManagedSharedAction.CreateSpace) + } else { + sharedViewModel.handle(SpaceManagedSharedAction.CreateRoom) + } + } } viewModel.observeViewEvents { @@ -139,6 +152,14 @@ class SpaceAddRoomFragment @Inject constructor( } } + override fun onResume() { + super.onResume() + withState(viewModel) { state -> + val title = if (state.onlyShowSpaces) getString(R.string.space_add_existing_spaces) else getString(R.string.space_add_existing_rooms_only) + views.appBarTitle.text = title + } + } + override fun onPrepareOptionsMenu(menu: Menu) { super.onPrepareOptionsMenu(menu) menu.findItem(R.id.spaceAddRoomSaveItem).isVisible = saveNeeded diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomSpaceChooserBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomSpaceChooserBottomSheet.kt new file mode 100644 index 0000000000..c4d4b84a18 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomSpaceChooserBottomSheet.kt @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.spaces.manage + +import android.os.Bundle +import android.os.Parcelable +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.setFragmentResult +import com.airbnb.mvrx.args +import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetAddRoomsOrSpacesToSpaceBinding +import kotlinx.parcelize.Parcelize + +class SpaceAddRoomSpaceChooserBottomSheet : VectorBaseBottomSheetDialogFragment() { + + @Parcelize + data class Args( + val spaceId: String + ) : Parcelable + + override val showExpanded = true + + private val addSubRoomsArgs: Args by args() + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = + BottomSheetAddRoomsOrSpacesToSpaceBinding.inflate(inflater, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + views.addSpaces.views.bottomSheetActionClickableZone.debouncedClicks { + setFragmentResult(REQUEST_KEY, Bundle().apply { + putString(BUNDLE_KEY_ACTION, ACTION_ADD_SPACES) + }) + dismiss() + } + + views.addRooms.views.bottomSheetActionClickableZone.debouncedClicks { + setFragmentResult(REQUEST_KEY, Bundle().apply { + putString(BUNDLE_KEY_ACTION, ACTION_ADD_ROOMS) + }) + dismiss() + } + } + + companion object { + + const val REQUEST_KEY = "SpaceAddRoomSpaceChooserBottomSheet" + const val BUNDLE_KEY_ACTION = "SpaceAddRoomSpaceChooserBottomSheet.Action" + const val ACTION_ADD_ROOMS = "Action.AddRoom" + const val ACTION_ADD_SPACES = "Action.AddSpaces" + + fun newInstance(spaceId: String) + : SpaceAddRoomSpaceChooserBottomSheet { + return SpaceAddRoomSpaceChooserBottomSheet().apply { + setArguments(Args(spaceId)) + } + } + } +} 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 2d9113ae68..e941d04b22 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 @@ -27,10 +27,12 @@ data class SpaceAddRoomsState( val spaceName: String = "", val ignoreRooms: List = emptyList(), val isSaving: Async> = Uninitialized, - val shouldShowDMs : Boolean = false + val shouldShowDMs: Boolean = false, + val onlyShowSpaces: Boolean = false // val selectionList: Map = emptyMap() ) : MvRxState { constructor(args: SpaceManageArgs) : this( - spaceId = args.spaceId + spaceId = args.spaceId, + onlyShowSpaces = args.manageType == ManageType.AddRoomsOnlySpaces ) } 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 35c415b087..9f5cd7d35e 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 @@ -127,7 +127,7 @@ class SpaceAddRoomsViewModel @AssistedInject constructor( copy( spaceName = spaceSummary?.displayName ?: "", ignoreRooms = (spaceSummary?.flattenParentIds ?: emptyList()) + listOf(initialState.spaceId), - shouldShowDMs = spaceSummary?.isPublic == false + shouldShowDMs = !onlyShowSpaces && spaceSummary?.isPublic == false ) } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt index 2fd0ff19bf..8185347aaa 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt @@ -99,7 +99,8 @@ class SpaceManageActivity : VectorBaseActivity(), if (isFirstCreation()) { withState(sharedViewModel) { when (it.manageType) { - ManageType.AddRooms -> { + ManageType.AddRooms, + ManageType.AddRoomsOnlySpaces -> { val simpleName = SpaceAddRoomFragment::class.java.simpleName if (supportFragmentManager.findFragmentByTag(simpleName) == null) { supportFragmentManager.commitTransaction { @@ -148,7 +149,14 @@ class SpaceManageActivity : VectorBaseActivity(), CreateRoomArgs("", parentSpaceId = args?.spaceId) ) } - SpaceManagedSharedViewEvents.NavigateToManageRooms -> { + SpaceManagedSharedViewEvents.NavigateToCreateSpace -> { + addFragmentToBackstack( + R.id.simpleFragmentContainer, + CreateRoomFragment::class.java, + CreateRoomArgs("", parentSpaceId = args?.spaceId, isSubSpace = true) + ) + } + SpaceManagedSharedViewEvents.NavigateToManageRooms -> { args?.spaceId?.let { spaceId -> addFragmentToBackstack( R.id.simpleFragmentContainer, diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt index 411c987776..8f23788d19 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt @@ -23,6 +23,7 @@ import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import org.matrix.android.sdk.api.session.Session @@ -55,9 +56,10 @@ class SpaceManageSharedViewModel @AssistedInject constructor( SpaceManagedSharedAction.HideLoading -> _viewEvents.post(SpaceManagedSharedViewEvents.HideLoading) SpaceManagedSharedAction.ShowLoading -> _viewEvents.post(SpaceManagedSharedViewEvents.ShowLoading) SpaceManagedSharedAction.CreateRoom -> _viewEvents.post(SpaceManagedSharedViewEvents.NavigateToCreateRoom) + SpaceManagedSharedAction.CreateSpace -> _viewEvents.post(SpaceManagedSharedViewEvents.NavigateToCreateSpace) SpaceManagedSharedAction.ManageRooms -> _viewEvents.post(SpaceManagedSharedViewEvents.NavigateToManageRooms) SpaceManagedSharedAction.OpenSpaceAliasesSettings -> _viewEvents.post(SpaceManagedSharedViewEvents.NavigateToAliasSettings) SpaceManagedSharedAction.OpenSpacePermissionSettings -> _viewEvents.post(SpaceManagedSharedViewEvents.NavigateToPermissionSettings) - } + }.exhaustive } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageViewState.kt index 91d49d90d1..35596f0884 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageViewState.kt @@ -20,6 +20,7 @@ import com.airbnb.mvrx.MvRxState enum class ManageType { AddRooms, + AddRoomsOnlySpaces, Settings, ManageRooms } diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedAction.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedAction.kt index 07c305e3eb..5f2032b25d 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedAction.kt @@ -23,6 +23,7 @@ sealed class SpaceManagedSharedAction : VectorViewModelAction { object ShowLoading : SpaceManagedSharedAction() object HideLoading : SpaceManagedSharedAction() object CreateRoom : SpaceManagedSharedAction() + object CreateSpace : SpaceManagedSharedAction() object ManageRooms : SpaceManagedSharedAction() object OpenSpaceAliasesSettings : SpaceManagedSharedAction() object OpenSpacePermissionSettings : SpaceManagedSharedAction() diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedViewEvents.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedViewEvents.kt index 3d66bde2ee..789f107341 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedViewEvents.kt @@ -23,6 +23,7 @@ sealed class SpaceManagedSharedViewEvents : VectorViewEvents { object ShowLoading : SpaceManagedSharedViewEvents() object HideLoading : SpaceManagedSharedViewEvents() object NavigateToCreateRoom : SpaceManagedSharedViewEvents() + object NavigateToCreateSpace : SpaceManagedSharedViewEvents() object NavigateToManageRooms : SpaceManagedSharedViewEvents() object NavigateToAliasSettings : SpaceManagedSharedViewEvents() object NavigateToPermissionSettings : SpaceManagedSharedViewEvents() diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt index a2b74eb93a..7cd5a70279 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt @@ -25,7 +25,6 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.features.form.formEditTextItem import im.vector.app.features.form.formEditableSquareAvatarItem import im.vector.app.features.form.formMultiLineEditTextItem -import im.vector.app.features.form.formSwitchItem import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.roomprofile.settings.RoomSettingsViewState import im.vector.app.features.settings.VectorPreferences @@ -106,27 +105,35 @@ class SpaceSettingsController @Inject constructor( } val isPublic = (data.newRoomJoinRules.newJoinRules ?: data.currentRoomJoinRules) == RoomJoinRules.PUBLIC - if (vectorPreferences.labsUseExperimentalRestricted()) { - buildProfileAction( - id = "joinRule", - title = stringProvider.getString(R.string.room_settings_room_access_title), - subtitle = data.getJoinRuleWording(stringProvider), - divider = false, - editable = data.actionPermissions.canChangeJoinRule, - action = { if (data.actionPermissions.canChangeJoinRule) callback?.onJoinRuleClicked() } - ) - } else { - formSwitchItem { - id("isPublic") - enabled(data.actionPermissions.canChangeJoinRule) - title(host.stringProvider.getString(R.string.make_this_space_public)) - switchChecked(isPublic) - - listener { value -> - host.callback?.setIsPublic(value) - } - } - } + buildProfileAction( + id = "joinRule", + title = stringProvider.getString(R.string.room_settings_space_access_title), + subtitle = data.getJoinRuleWording(stringProvider), + divider = true, + editable = data.actionPermissions.canChangeJoinRule, + action = { if (data.actionPermissions.canChangeJoinRule) callback?.onJoinRuleClicked() } + ) +// if (vectorPreferences.labsUseExperimentalRestricted()) { +// buildProfileAction( +// id = "joinRule", +// title = stringProvider.getString(R.string.room_settings_room_access_title), +// subtitle = data.getJoinRuleWording(stringProvider), +// divider = false, +// editable = data.actionPermissions.canChangeJoinRule, +// action = { if (data.actionPermissions.canChangeJoinRule) callback?.onJoinRuleClicked() } +// ) +// } else { +// formSwitchItem { +// id("isPublic") +// enabled(data.actionPermissions.canChangeJoinRule) +// title(host.stringProvider.getString(R.string.make_this_space_public)) +// switchChecked(isPublic) +// +// listener { value -> +// host.callback?.setIsPublic(value) +// } +// } +// } dividerItem { id("divider") } diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt index 8519f1d489..525afcbc9b 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt @@ -47,7 +47,7 @@ import im.vector.app.features.roomprofile.settings.RoomSettingsAction import im.vector.app.features.roomprofile.settings.RoomSettingsViewEvents import im.vector.app.features.roomprofile.settings.RoomSettingsViewModel import im.vector.app.features.roomprofile.settings.RoomSettingsViewState -import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleBottomSheet +import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleActivity import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleSharedActionViewModel import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility @@ -199,10 +199,8 @@ class SpaceSettingsFragment @Inject constructor( // N/A for space settings screen } - override fun onJoinRuleClicked() = withState(viewModel) { state -> - val currentJoinRule = state.newRoomJoinRules.newJoinRules ?: state.currentRoomJoinRules - RoomJoinRuleBottomSheet.newInstance(currentJoinRule) - .show(childFragmentManager, "RoomJoinRuleBottomSheet") + override fun onJoinRuleClicked() { + startActivity(RoomJoinRuleActivity.newIntent(requireContext(), roomProfileArgs.roomId)) } override fun onToggleGuestAccess() = withState(viewModel) { state -> diff --git a/vector/src/main/res/layout/bottom_sheet_add_rooms_or_spaces_to_space.xml b/vector/src/main/res/layout/bottom_sheet_add_rooms_or_spaces_to_space.xml new file mode 100644 index 0000000000..e86fb6e58d --- /dev/null +++ b/vector/src/main/res/layout/bottom_sheet_add_rooms_or_spaces_to_space.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/vector/src/main/res/layout/bottom_sheet_space_settings.xml b/vector/src/main/res/layout/bottom_sheet_space_settings.xml index 2975df65d5..33b879ae45 100644 --- a/vector/src/main/res/layout/bottom_sheet_space_settings.xml +++ b/vector/src/main/res/layout/bottom_sheet_space_settings.xml @@ -38,21 +38,12 @@ android:textStyle="bold" app:layout_constrainedWidth="true" app:layout_constraintBottom_toTopOf="@+id/spaceDescription" - app:layout_constraintEnd_toStartOf="@id/spaceBetaTag" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/spaceAvatarImageView" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" tools:text="@sample/spaces.json/data/name" /> - + + + Who can read history? Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged. Who can access this room? + Who can access? Room access + Space access Allow guests to join @@ -1533,6 +1535,7 @@ Only people invited can find and join Public Anyone can find the room and join + Anyone can find the space and join Space members only Anyone in a space with this room can find and join it. Only admins of this room can add it to a space. Members of Space %s can find, preview and join. @@ -2187,6 +2190,7 @@ Malformed event, cannot display Create New Room + Create New Space No network. Please check your Internet connection. "Change" "Change network" @@ -2672,6 +2676,7 @@ Please provide a room address Some characters are not allowed Creating room… + Creating space… Your email domain is not authorized to register on this server @@ -3493,6 +3498,9 @@ Pick things to leave Add existing rooms and space + Add existing rooms + Add existing spaces + Add a space to any space you manage. Add rooms Welcome to Spaces! Spaces are a new way to group rooms and people.