Improve leave space (all + none)

This commit is contained in:
Valere 2021-07-28 19:55:47 +02:00
parent bb459a6e5e
commit 8fd784e275
9 changed files with 538 additions and 92 deletions

View File

@ -162,7 +162,7 @@ Formatter\.formatShortFileSize===1
# android\.text\.TextUtils
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
enum class===105
enum class===106
### Do not import temporary legacy classes
import org.matrix.android.sdk.internal.legacy.riot===3

View File

@ -84,6 +84,7 @@ import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheet
import im.vector.app.features.share.IncomingShareActivity
import im.vector.app.features.signout.soft.SoftLogoutActivity
import im.vector.app.features.spaces.InviteRoomSpaceChooserBottomSheet
import im.vector.app.features.spaces.LeaveSpaceBottomSheet
import im.vector.app.features.spaces.SpaceCreationActivity
import im.vector.app.features.spaces.SpaceExploreActivity
import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
@ -199,6 +200,7 @@ interface ScreenComponent {
fun inject(bottomSheet: SpaceInviteBottomSheet)
fun inject(bottomSheet: JoinReplacementRoomBottomSheet)
fun inject(bottomSheet: MigrateRoomBottomSheet)
fun inject(bottomSheet: LeaveSpaceBottomSheet)
/* ==========================================================================================
* Others

View File

@ -0,0 +1,167 @@
/*
* 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
import android.graphics.Typeface
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.text.toSpannable
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.args
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import com.jakewharton.rxbinding3.widget.checkedChanges
import im.vector.app.R
import im.vector.app.core.di.ScreenComponent
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.core.utils.styleMatchingText
import im.vector.app.databinding.BottomSheetLeaveSpaceBinding
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.parcelize.Parcelize
import me.gujun.android.span.span
import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject
class LeaveSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetLeaveSpaceBinding>() {
val settingsViewModel: SpaceMenuViewModel by parentFragmentViewModel()
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetLeaveSpaceBinding {
return BottomSheetLeaveSpaceBinding.inflate(inflater, container, false)
}
@Inject lateinit var colorProvider: ColorProvider
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
@Parcelize
data class Args(
val spaceId: String
) : Parcelable
override val showExpanded = true
private val spaceArgs: SpaceBottomSheetSettingsArgs by args()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
views.autoLeaveRadioGroup.checkedChanges()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
when (it) {
views.leaveAll.id -> {
settingsViewModel.handle(SpaceMenuViewAction.SetAutoLeaveAll)
}
views.leaveNone.id -> {
settingsViewModel.handle(SpaceMenuViewAction.SetAutoLeaveNone)
}
views.leaveSelected.id -> {
settingsViewModel.handle(SpaceMenuViewAction.SetAutoLeaveSelected)
}
}
}
.disposeOnDestroyView()
views.leaveButton.debouncedClicks {
settingsViewModel.handle(SpaceMenuViewAction.LeaveSpace)
}
views.cancelButton.debouncedClicks {
dismiss()
}
}
override fun invalidate() = withState(settingsViewModel) { state ->
super.invalidate()
val spaceSummary = state.spaceSummary ?: return@withState
val bestName = spaceSummary.toMatrixItem().getBestName()
val commonText = getString(R.string.space_leave_prompt_msg, bestName)
.toSpannable().styleMatchingText(bestName, Typeface.BOLD)
val warningMessage: CharSequence = if (spaceSummary.otherMemberIds.isEmpty()) {
span {
+commonText
+"\n\n"
span(getString(R.string.space_leave_prompt_msg_only_you)) {
textColor = colorProvider.getColorFromAttribute(R.attr.colorError)
}
}
} else if (state.isLastAdmin) {
span {
+commonText
+"\n\n"
span(getString(R.string.space_leave_prompt_msg_as_admin)) {
textColor = colorProvider.getColorFromAttribute(R.attr.colorError)
}
}
} else if (!spaceSummary.isPublic) {
span {
+commonText
+"\n\n"
span(getString(R.string.space_leave_prompt_msg_private)) {
textColor = colorProvider.getColorFromAttribute(R.attr.colorError)
}
}
} else {
commonText
}
views.bottomLeaveSpaceWarningText.setTextOrHide(warningMessage)
if (state.leavingState is Loading) {
views.leaveButton.isInvisible = true
views.cancelButton.isInvisible = true
views.leaveProgress.isVisible = true
} else {
views.leaveButton.isInvisible = false
views.cancelButton.isInvisible = false
views.leaveProgress.isVisible = false
}
when (state.leaveMode) {
SpaceMenuState.LeaveMode.LEAVE_ALL -> {
views.autoLeaveRadioGroup.check(views.leaveAll.id)
}
SpaceMenuState.LeaveMode.LEAVE_NONE -> {
views.autoLeaveRadioGroup.check(views.leaveNone.id)
}
SpaceMenuState.LeaveMode.LEAVE_SELECTED -> {
views.autoLeaveRadioGroup.check(views.leaveSelected.id)
}
}
}
companion object {
fun newInstance(spaceId: String)
: LeaveSpaceBottomSheet {
return LeaveSpaceBottomSheet().apply {
setArguments(SpaceBottomSheetSettingsArgs(spaceId))
}
}
}
}

View File

@ -0,0 +1,39 @@
/*
* 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
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.Uninitialized
import org.matrix.android.sdk.api.session.room.model.RoomSummary
data class SpaceMenuState(
val spaceId: String,
val spaceSummary: RoomSummary? = null,
val canEditSettings: Boolean = false,
val canInvite: Boolean = false,
val canAddChild: Boolean = false,
val isLastAdmin: Boolean = false,
val leaveMode: LeaveMode = LeaveMode.LEAVE_ALL,
val leavingState: Async<Unit> = Uninitialized
) : MvRxState {
constructor(args: SpaceBottomSheetSettingsArgs) : this(spaceId = args.spaceId)
enum class LeaveMode {
LEAVE_ALL, LEAVE_NONE, LEAVE_SELECTED
}
}

View File

@ -0,0 +1,26 @@
/*
* 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
import im.vector.app.core.platform.VectorViewModelAction
sealed class SpaceMenuViewAction : VectorViewModelAction {
object SetAutoLeaveAll : SpaceMenuViewAction()
object SetAutoLeaveNone : SpaceMenuViewAction()
object SetAutoLeaveSelected : SpaceMenuViewAction()
object LeaveSpace : SpaceMenuViewAction()
}

View File

@ -0,0 +1,160 @@
/*
* 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
import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.AppStateHandler
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
import im.vector.app.features.session.coroutineScope
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.model.Membership
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.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.rx.rx
import timber.log.Timber
class SpaceMenuViewModel @AssistedInject constructor(
@Assisted val initialState: SpaceMenuState,
val session: Session,
val appStateHandler: AppStateHandler
) : VectorViewModel<SpaceMenuState, SpaceMenuViewAction, EmptyViewEvents>(initialState) {
@AssistedFactory
interface Factory {
fun create(initialState: SpaceMenuState): SpaceMenuViewModel
}
companion object : MvRxViewModelFactory<SpaceMenuViewModel, SpaceMenuState> {
@JvmStatic
override fun create(viewModelContext: ViewModelContext, state: SpaceMenuState): SpaceMenuViewModel? {
val factory = when (viewModelContext) {
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
is ActivityViewModelContext -> viewModelContext.activity as? Factory
}
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
}
}
init {
val roomSummary = session.getRoomSummary(initialState.spaceId)
setState {
copy(spaceSummary = roomSummary)
}
session.getRoom(initialState.spaceId)?.let { room ->
room.rx().liveRoomSummary().subscribe {
it.getOrNull()?.let {
if (it.membership == Membership.LEAVE) {
setState { copy(leavingState = Success(Unit)) }
// switch to home?
appStateHandler.setCurrentSpace(null, session)
}
}
}
PowerLevelsObservableFactory(room)
.createObservable()
.subscribe {
val powerLevelsHelper = PowerLevelsHelper(it)
val canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId)
val canAddChild = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_SPACE_CHILD)
val canChangeAvatar = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR)
val canChangeName = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_NAME)
val canChangeTopic = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_TOPIC)
val isAdmin = powerLevelsHelper.getUserRole(session.myUserId) is Role.Admin
val otherAdminCount = roomSummary?.otherMemberIds
?.map { powerLevelsHelper.getUserRole(it) }
?.count { it is Role.Admin }
?: 0
val isLastAdmin = isAdmin && otherAdminCount == 0
setState {
copy(
canEditSettings = canChangeAvatar || canChangeName || canChangeTopic,
canInvite = canInvite,
canAddChild = canAddChild,
isLastAdmin = isLastAdmin
)
}
}
.disposeOnClear()
}
}
override fun handle(action: SpaceMenuViewAction) {
when (action) {
SpaceMenuViewAction.SetAutoLeaveAll -> setState { copy(leaveMode = SpaceMenuState.LeaveMode.LEAVE_ALL) }
SpaceMenuViewAction.SetAutoLeaveNone -> setState { copy(leaveMode = SpaceMenuState.LeaveMode.LEAVE_NONE) }
SpaceMenuViewAction.SetAutoLeaveSelected -> setState { copy(leaveMode = SpaceMenuState.LeaveMode.LEAVE_SELECTED) }
SpaceMenuViewAction.LeaveSpace -> handleLeaveSpace()
}
}
private fun handleLeaveSpace() = withState { state ->
setState { copy(leavingState = Loading()) }
session.coroutineScope.launch {
try {
if (state.leaveMode == SpaceMenuState.LeaveMode.LEAVE_NONE) {
session.getRoom(initialState.spaceId)?.leave(null)
} else if (state.leaveMode == SpaceMenuState.LeaveMode.LEAVE_ALL) {
// need to find all child rooms that i have joined
try {
session.getRoomSummaries(
roomSummaryQueryParams {
excludeType = null
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(initialState.spaceId)
memberships = listOf(Membership.JOIN)
}
).forEach {
session.getRoom(it.roomId)?.leave(null)
}
} catch (failure: Throwable) {
// silently ignore?
Timber.e(failure, "Fail to leave sub rooms/spaces")
}
session.getRoom(initialState.spaceId)?.leave(null)
}
// We observe the membership and to dismiss when we have remote echo of leaving
} catch (failure: Throwable) {
setState { copy(leavingState = Fail(failure)) }
}
}
}
}

View File

@ -22,35 +22,24 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.args
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.core.di.ScreenComponent
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
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
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.session.coroutineScope
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.spaces.manage.ManageType
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
@Parcelize
@ -58,15 +47,12 @@ data class SpaceBottomSheetSettingsArgs(
val spaceId: String
) : Parcelable
// XXX make proper view model before leaving beta
class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceSettingsBinding>() {
class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceSettingsBinding>(), SpaceMenuViewModel.Factory {
@Inject lateinit var navigator: Navigator
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
@Inject lateinit var avatarRenderer: AvatarRenderer
@Inject lateinit var vectorPreferences: VectorPreferences
@Inject lateinit var bugReporter: BugReporter
@Inject lateinit var colorProvider: ColorProvider
@Inject lateinit var viewModelFactory: SpaceMenuViewModel.Factory
private val spaceArgs: SpaceBottomSheetSettingsArgs by args()
@ -74,6 +60,8 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
fun onShareSpaceSelected(spaceId: String)
}
val settingsViewModel: SpaceMenuViewModel by fragmentViewModel()
var interactionListener: InteractionListener? = null
override val showExpanded = true
@ -91,41 +79,6 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val session = activeSessionHolder.getSafeActiveSession() ?: return
val roomSummary = session.getRoomSummary(spaceArgs.spaceId)
roomSummary?.toMatrixItem()?.let {
avatarRenderer.render(it, views.spaceAvatarImageView)
}
views.spaceNameView.text = roomSummary?.displayName
views.spaceDescription.setTextOrHide(roomSummary?.topic?.takeIf { it.isNotEmpty() })
val room = session.getRoom(spaceArgs.spaceId) ?: return
PowerLevelsObservableFactory(room)
.createObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { powerLevelContent ->
val powerLevelsHelper = PowerLevelsHelper(powerLevelContent)
val canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId)
val canAddChild = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_SPACE_CHILD)
val canChangeAvatar = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR)
val canChangeName = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_NAME)
val canChangeTopic = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_TOPIC)
views.spaceSettings.isVisible = canChangeAvatar || canChangeName || canChangeTopic
views.invitePeople.isVisible = canInvite || roomSummary?.isPublic.orFalse()
views.addRooms.isVisible = canAddChild
val isAdmin = powerLevelsHelper.getUserRole(session.myUserId) is Role.Admin
val otherAdminCount = roomSummary?.otherMemberIds
?.map { powerLevelsHelper.getUserRole(it) }
?.count { it is Role.Admin }
?: 0
isLastAdmin = isAdmin && otherAdminCount == 0
}.disposeOnDestroyView()
views.spaceBetaTag.debouncedClicks {
bugReporter.openBugReportScreen(requireActivity(), ReportType.SPACE_BETA_FEEDBACK)
}
@ -154,42 +107,29 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
}
views.leaveSpace.views.bottomSheetActionClickableZone.debouncedClicks {
val spaceSummary = activeSessionHolder.getSafeActiveSession()?.getRoomSummary(spaceArgs.spaceId)
?: return@debouncedClicks
val warningMessage: CharSequence? = if (spaceSummary.otherMemberIds.isEmpty()) {
span(getString(R.string.space_leave_prompt_msg_only_you)) {
textColor = colorProvider.getColorFromAttribute(R.attr.colorError)
}
} else if (isLastAdmin) {
span(getString(R.string.space_leave_prompt_msg_as_admin)) {
textColor = colorProvider.getColorFromAttribute(R.attr.colorError)
}
} else if (!spaceSummary.isPublic) {
span(getString(R.string.space_leave_prompt_msg_private)) {
textColor = colorProvider.getColorFromAttribute(R.attr.colorError)
}
} else {
null
}
MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_Destructive)
.setMessage(warningMessage)
.setTitle(getString(R.string.space_leave_prompt_msg))
.setPositiveButton(R.string.leave) { _, _ ->
session.coroutineScope.launch {
try {
session.getRoom(spaceArgs.spaceId)?.leave(null)
} catch (failure: Throwable) {
Timber.e(failure, "Failed to leave space")
}
}
dismiss()
}
.setNegativeButton(R.string.cancel, null)
.show()
LeaveSpaceBottomSheet.newInstance(spaceArgs.spaceId).show(childFragmentManager, "LOGOUT")
}
}
override fun invalidate() = withState(settingsViewModel) { state ->
super.invalidate()
if (state.leavingState is Success) {
dismiss()
}
state.spaceSummary?.toMatrixItem()?.let {
avatarRenderer.render(it, views.spaceAvatarImageView)
}
views.spaceNameView.text = state.spaceSummary?.displayName
views.spaceDescription.setTextOrHide(state.spaceSummary?.topic?.takeIf { it.isNotEmpty() })
views.spaceSettings.isVisible = state.canEditSettings
views.invitePeople.isVisible = state.canInvite || state.spaceSummary?.isPublic.orFalse()
views.addRooms.isVisible = state.canAddChild
}
companion object {
fun newInstance(spaceId: String, interactionListener: InteractionListener): SpaceSettingsMenuBottomSheet {
return SpaceSettingsMenuBottomSheet().apply {
@ -198,4 +138,8 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
}
}
}
override fun create(initialState: SpaceMenuState): SpaceMenuViewModel {
return viewModelFactory.create(initialState)
}
}

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorSurface"
android:orientation="vertical">
<TextView
android:id="@+id/bottom_leave_space_warning_text"
style="@style/Widget.Vector.TextView.Subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginTop="20dp"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
android:layout_marginBottom="8dp"
android:textColor="?vctr_content_primary"
tools:text="@string/space_leave_prompt_msg" />
<RadioGroup
android:id="@+id/autoLeaveRadioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="?dialogPreferredPadding"
android:paddingTop="12dp"
android:paddingEnd="?dialogPreferredPadding"
android:paddingBottom="12dp">
<RadioButton
android:id="@+id/leave_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/leave_all_rooms_and_spaces"
tools:checked="true" />
<RadioButton
android:id="@+id/leave_none"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="180dp"
android:text="@string/dont_leave_any" />
<RadioButton
android:id="@+id/leave_selected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="180dp"
android:text="@string/leave_specific_ones" />
</RadioGroup>
<TextView
android:id="@+id/inlineErrorText"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginTop="4dp"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
android:textColor="?vctr_content_secondary"
android:visibility="gone" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp">
<ProgressBar
android:id="@+id/leaveProgress"
style="?android:attr/progressBarStyle"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:visibility="gone"
tools:visibility="visible" />
<Button
android:id="@+id/leaveButton"
style="@style/Widget.Vector.Button.Destructive"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_gravity="center_horizontal"
android:text="@string/leave_space" />
</FrameLayout>
<Button
android:id="@+id/cancelButton"
style="@style/Widget.Vector.Button.Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:text="@string/cancel" />
</LinearLayout>

View File

@ -3479,11 +3479,14 @@
<string name="space_explore_activity_title">Explore rooms</string>
<string name="space_add_child_title">Add rooms</string>
<string name="leave_space">Leave Space</string>
<string name="space_leave_prompt_msg">Are you sure you want to leave the space?</string>
<string name="space_leave_prompt_msg">Are you sure you want to leave %s?</string>
<string name="space_leave_prompt_msg_only_you">You are the only person here. If you leave, no one will be able to join in the future, including you.</string>
<string name="space_leave_prompt_msg_private">This space is not public. You will not be able to rejoin without an invite.</string>
<string name="space_leave_prompt_msg_as_admin">You are admin of this space, ensure that you have transferred admin right to another member before leaving.</string>
<string name="space_leave_prompt_msg_private">You won\'t be able to rejoin unless you are re-invited.</string>
<string name="space_leave_prompt_msg_as_admin">You\'re the only admin of this space. Leaving it will mean no one has control over it.</string>
<string name="leave_all_rooms_and_spaces">Leave all rooms and spaces</string>
<string name="you_will_leave_all_in">You will leave all rooms and spaces in %s.</string>
<string name="dont_leave_any">Dont leave any rooms and spaces</string>
<string name="leave_specific_ones">Leave specific rooms and spaces</string>
<string name="space_add_existing_rooms">Add existing rooms and space</string>
<string name="space_add_rooms">Add rooms</string>