Merge pull request #3759 from vector-im/feature/bca/improve_leave_space
Feature/bca/improve leave space
This commit is contained in:
commit
8b980e5227
1
changelog.d/3692.feature
Normal file
1
changelog.d/3692.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Allow to also leave rooms when leaving a space
|
@ -162,7 +162,7 @@ Formatter\.formatShortFileSize===1
|
|||||||
# android\.text\.TextUtils
|
# 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
|
### 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
|
### Do not import temporary legacy classes
|
||||||
import org.matrix.android.sdk.internal.legacy.riot===3
|
import org.matrix.android.sdk.internal.legacy.riot===3
|
||||||
|
@ -319,6 +319,7 @@
|
|||||||
<activity android:name=".features.spaces.SpaceCreationActivity" />
|
<activity android:name=".features.spaces.SpaceCreationActivity" />
|
||||||
<activity android:name=".features.spaces.manage.SpaceManageActivity" />
|
<activity android:name=".features.spaces.manage.SpaceManageActivity" />
|
||||||
<activity android:name=".features.spaces.people.SpacePeopleActivity" />
|
<activity android:name=".features.spaces.people.SpacePeopleActivity" />
|
||||||
|
<activity android:name=".features.spaces.leave.SpaceLeaveAdvancedActivity" />
|
||||||
<!-- Services -->
|
<!-- Services -->
|
||||||
|
|
||||||
<service
|
<service
|
||||||
|
@ -146,6 +146,7 @@ import im.vector.app.features.spaces.create.CreateSpaceAdd3pidInvitesFragment
|
|||||||
import im.vector.app.features.spaces.create.CreateSpaceDefaultRoomsFragment
|
import im.vector.app.features.spaces.create.CreateSpaceDefaultRoomsFragment
|
||||||
import im.vector.app.features.spaces.create.CreateSpaceDetailsFragment
|
import im.vector.app.features.spaces.create.CreateSpaceDetailsFragment
|
||||||
import im.vector.app.features.spaces.explore.SpaceDirectoryFragment
|
import im.vector.app.features.spaces.explore.SpaceDirectoryFragment
|
||||||
|
import im.vector.app.features.spaces.leave.SpaceLeaveAdvancedFragment
|
||||||
import im.vector.app.features.spaces.manage.SpaceAddRoomFragment
|
import im.vector.app.features.spaces.manage.SpaceAddRoomFragment
|
||||||
import im.vector.app.features.spaces.manage.SpaceManageRoomsFragment
|
import im.vector.app.features.spaces.manage.SpaceManageRoomsFragment
|
||||||
import im.vector.app.features.spaces.manage.SpaceSettingsFragment
|
import im.vector.app.features.spaces.manage.SpaceSettingsFragment
|
||||||
@ -828,4 +829,9 @@ interface FragmentModule {
|
|||||||
@IntoMap
|
@IntoMap
|
||||||
@FragmentKey(RoomJoinRuleChooseRestrictedFragment::class)
|
@FragmentKey(RoomJoinRuleChooseRestrictedFragment::class)
|
||||||
fun bindRoomJoinRuleChooseRestrictedFragment(fragment: RoomJoinRuleChooseRestrictedFragment): Fragment
|
fun bindRoomJoinRuleChooseRestrictedFragment(fragment: RoomJoinRuleChooseRestrictedFragment): Fragment
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FragmentKey(SpaceLeaveAdvancedFragment::class)
|
||||||
|
fun bindSpaceLeaveAdvancedFragment(fragment: SpaceLeaveAdvancedFragment): Fragment
|
||||||
}
|
}
|
||||||
|
@ -84,10 +84,12 @@ import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheet
|
|||||||
import im.vector.app.features.share.IncomingShareActivity
|
import im.vector.app.features.share.IncomingShareActivity
|
||||||
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
||||||
import im.vector.app.features.spaces.InviteRoomSpaceChooserBottomSheet
|
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.SpaceCreationActivity
|
||||||
import im.vector.app.features.spaces.SpaceExploreActivity
|
import im.vector.app.features.spaces.SpaceExploreActivity
|
||||||
import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
|
import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
|
||||||
import im.vector.app.features.spaces.invite.SpaceInviteBottomSheet
|
import im.vector.app.features.spaces.invite.SpaceInviteBottomSheet
|
||||||
|
import im.vector.app.features.spaces.leave.SpaceLeaveAdvancedActivity
|
||||||
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
||||||
import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
|
import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
|
||||||
import im.vector.app.features.terms.ReviewTermsActivity
|
import im.vector.app.features.terms.ReviewTermsActivity
|
||||||
@ -171,6 +173,7 @@ interface ScreenComponent {
|
|||||||
fun inject(activity: SpaceExploreActivity)
|
fun inject(activity: SpaceExploreActivity)
|
||||||
fun inject(activity: SpaceManageActivity)
|
fun inject(activity: SpaceManageActivity)
|
||||||
fun inject(activity: RoomJoinRuleActivity)
|
fun inject(activity: RoomJoinRuleActivity)
|
||||||
|
fun inject(activity: SpaceLeaveAdvancedActivity)
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* BottomSheets
|
* BottomSheets
|
||||||
@ -199,6 +202,7 @@ interface ScreenComponent {
|
|||||||
fun inject(bottomSheet: SpaceInviteBottomSheet)
|
fun inject(bottomSheet: SpaceInviteBottomSheet)
|
||||||
fun inject(bottomSheet: JoinReplacementRoomBottomSheet)
|
fun inject(bottomSheet: JoinReplacementRoomBottomSheet)
|
||||||
fun inject(bottomSheet: MigrateRoomBottomSheet)
|
fun inject(bottomSheet: MigrateRoomBottomSheet)
|
||||||
|
fun inject(bottomSheet: LeaveSpaceBottomSheet)
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* Others
|
* Others
|
||||||
|
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* 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.app.Activity
|
||||||
|
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.Fail
|
||||||
|
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.error.ErrorFormatter
|
||||||
|
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
|
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 im.vector.app.features.spaces.leave.SpaceLeaveAdvancedActivity
|
||||||
|
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
|
||||||
|
@Inject lateinit var errorFormatter: ErrorFormatter
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
private val cherryPickLeaveActivityResult = registerStartForActivityResult { activityResult ->
|
||||||
|
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||||
|
// nothing actually?
|
||||||
|
} else {
|
||||||
|
// move back to default
|
||||||
|
settingsViewModel.handle(SpaceLeaveViewAction.SetAutoLeaveAll)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(SpaceLeaveViewAction.SetAutoLeaveAll)
|
||||||
|
}
|
||||||
|
views.leaveNone.id -> {
|
||||||
|
settingsViewModel.handle(SpaceLeaveViewAction.SetAutoLeaveNone)
|
||||||
|
}
|
||||||
|
views.leaveSelected.id -> {
|
||||||
|
settingsViewModel.handle(SpaceLeaveViewAction.SetAutoLeaveSelected)
|
||||||
|
// launch dedicated activity
|
||||||
|
cherryPickLeaveActivityResult.launch(
|
||||||
|
SpaceLeaveAdvancedActivity.newIntent(requireContext(), spaceArgs.spaceId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
|
views.leaveButton.debouncedClicks {
|
||||||
|
settingsViewModel.handle(SpaceLeaveViewAction.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_with_name, 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)
|
||||||
|
|
||||||
|
views.inlineErrorText.setTextOrHide(null)
|
||||||
|
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
|
||||||
|
if (state.leavingState is Fail) {
|
||||||
|
views.inlineErrorText.setTextOrHide(errorFormatter.toHumanReadable(state.leavingState.error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasChildren = (spaceSummary.spaceChildren?.size ?: 0) > 0
|
||||||
|
if (hasChildren) {
|
||||||
|
views.autoLeaveRadioGroup.isVisible = true
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
views.autoLeaveRadioGroup.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newInstance(spaceId: String)
|
||||||
|
: LeaveSpaceBottomSheet {
|
||||||
|
return LeaveSpaceBottomSheet().apply {
|
||||||
|
setArguments(SpaceBottomSheetSettingsArgs(spaceId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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 SpaceLeaveViewAction : VectorViewModelAction {
|
||||||
|
object SetAutoLeaveAll : SpaceLeaveViewAction()
|
||||||
|
object SetAutoLeaveNone : SpaceLeaveViewAction()
|
||||||
|
object SetAutoLeaveSelected : SpaceLeaveViewAction()
|
||||||
|
object LeaveSpace : SpaceLeaveViewAction()
|
||||||
|
}
|
@ -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_NONE,
|
||||||
|
val leavingState: Async<Unit> = Uninitialized
|
||||||
|
) : MvRxState {
|
||||||
|
constructor(args: SpaceBottomSheetSettingsArgs) : this(spaceId = args.spaceId)
|
||||||
|
|
||||||
|
enum class LeaveMode {
|
||||||
|
LEAVE_ALL, LEAVE_NONE, LEAVE_SELECTED
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* 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.Uninitialized
|
||||||
|
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, SpaceLeaveViewAction, 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)) }
|
||||||
|
if (appStateHandler.safeActiveSpaceId() == initialState.spaceId) {
|
||||||
|
// switch to home?
|
||||||
|
appStateHandler.setCurrentSpace(null, session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.disposeOnClear()
|
||||||
|
|
||||||
|
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: SpaceLeaveViewAction) {
|
||||||
|
when (action) {
|
||||||
|
SpaceLeaveViewAction.SetAutoLeaveAll -> setState {
|
||||||
|
copy(leaveMode = SpaceMenuState.LeaveMode.LEAVE_ALL, leavingState = Uninitialized)
|
||||||
|
}
|
||||||
|
SpaceLeaveViewAction.SetAutoLeaveNone -> setState {
|
||||||
|
copy(leaveMode = SpaceMenuState.LeaveMode.LEAVE_NONE, leavingState = Uninitialized)
|
||||||
|
}
|
||||||
|
SpaceLeaveViewAction.SetAutoLeaveSelected -> setState {
|
||||||
|
copy(leaveMode = SpaceMenuState.LeaveMode.LEAVE_SELECTED, leavingState = Uninitialized)
|
||||||
|
}
|
||||||
|
SpaceLeaveViewAction.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
|
||||||
|
|
||||||
|
session.getRoomSummaries(
|
||||||
|
roomSummaryQueryParams {
|
||||||
|
excludeType = null
|
||||||
|
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(initialState.spaceId)
|
||||||
|
memberships = listOf(Membership.JOIN)
|
||||||
|
}
|
||||||
|
).forEach {
|
||||||
|
try {
|
||||||
|
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)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,35 +22,24 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.args
|
import com.airbnb.mvrx.args
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import im.vector.app.R
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
|
||||||
import im.vector.app.core.di.ScreenComponent
|
import im.vector.app.core.di.ScreenComponent
|
||||||
import im.vector.app.core.extensions.setTextOrHide
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
|
||||||
import im.vector.app.databinding.BottomSheetSpaceSettingsBinding
|
import im.vector.app.databinding.BottomSheetSpaceSettingsBinding
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.navigation.Navigator
|
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.BugReporter
|
||||||
import im.vector.app.features.rageshake.ReportType
|
import im.vector.app.features.rageshake.ReportType
|
||||||
import im.vector.app.features.roomprofile.RoomProfileActivity
|
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.ManageType
|
||||||
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import me.gujun.android.span.span
|
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
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 org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
import timber.log.Timber
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@ -58,15 +47,12 @@ data class SpaceBottomSheetSettingsArgs(
|
|||||||
val spaceId: String
|
val spaceId: String
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
// XXX make proper view model before leaving beta
|
class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceSettingsBinding>(), SpaceMenuViewModel.Factory {
|
||||||
class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceSettingsBinding>() {
|
|
||||||
|
|
||||||
@Inject lateinit var navigator: Navigator
|
@Inject lateinit var navigator: Navigator
|
||||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
|
||||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
|
||||||
@Inject lateinit var bugReporter: BugReporter
|
@Inject lateinit var bugReporter: BugReporter
|
||||||
@Inject lateinit var colorProvider: ColorProvider
|
@Inject lateinit var viewModelFactory: SpaceMenuViewModel.Factory
|
||||||
|
|
||||||
private val spaceArgs: SpaceBottomSheetSettingsArgs by args()
|
private val spaceArgs: SpaceBottomSheetSettingsArgs by args()
|
||||||
|
|
||||||
@ -74,6 +60,8 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
|
|||||||
fun onShareSpaceSelected(spaceId: String)
|
fun onShareSpaceSelected(spaceId: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val settingsViewModel: SpaceMenuViewModel by fragmentViewModel()
|
||||||
|
|
||||||
var interactionListener: InteractionListener? = null
|
var interactionListener: InteractionListener? = null
|
||||||
|
|
||||||
override val showExpanded = true
|
override val showExpanded = true
|
||||||
@ -91,41 +79,6 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
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 {
|
views.spaceBetaTag.debouncedClicks {
|
||||||
bugReporter.openBugReportScreen(requireActivity(), ReportType.SPACE_BETA_FEEDBACK)
|
bugReporter.openBugReportScreen(requireActivity(), ReportType.SPACE_BETA_FEEDBACK)
|
||||||
}
|
}
|
||||||
@ -154,40 +107,27 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
|
|||||||
}
|
}
|
||||||
|
|
||||||
views.leaveSpace.views.bottomSheetActionClickableZone.debouncedClicks {
|
views.leaveSpace.views.bottomSheetActionClickableZone.debouncedClicks {
|
||||||
val spaceSummary = activeSessionHolder.getSafeActiveSession()?.getRoomSummary(spaceArgs.spaceId)
|
LeaveSpaceBottomSheet.newInstance(spaceArgs.spaceId).show(childFragmentManager, "LOGOUT")
|
||||||
?: 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)
|
override fun invalidate() = withState(settingsViewModel) { state ->
|
||||||
.setMessage(warningMessage)
|
super.invalidate()
|
||||||
.setTitle(getString(R.string.space_leave_prompt_msg))
|
|
||||||
.setPositiveButton(R.string.leave) { _, _ ->
|
if (state.leavingState is Success) {
|
||||||
session.coroutineScope.launch {
|
|
||||||
try {
|
|
||||||
session.getRoom(spaceArgs.spaceId)?.leave(null)
|
|
||||||
} catch (failure: Throwable) {
|
|
||||||
Timber.e(failure, "Failed to leave space")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.show()
|
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 {
|
companion object {
|
||||||
@ -198,4 +138,8 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun create(initialState: SpaceMenuState): SpaceMenuViewModel {
|
||||||
|
return viewModelFactory.create(initialState)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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.leave
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import com.airbnb.mvrx.Fail
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.loadingItem
|
||||||
|
import im.vector.app.core.epoxy.noResultItem
|
||||||
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
import im.vector.app.features.spaces.manage.roomSelectionItem
|
||||||
|
import io.reactivex.functions.Predicate
|
||||||
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SelectChildrenController @Inject constructor(
|
||||||
|
val avatarRenderer: AvatarRenderer,
|
||||||
|
val stringProvider: StringProvider
|
||||||
|
) : TypedEpoxyController<SpaceLeaveAdvanceViewState>() {
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun onItemSelected(roomSummary: RoomSummary)
|
||||||
|
}
|
||||||
|
|
||||||
|
var listener: Listener? = null
|
||||||
|
private val matchFilter = RoomSearchMatchFilter()
|
||||||
|
override fun buildModels(data: SpaceLeaveAdvanceViewState?) {
|
||||||
|
val children = data?.allChildren ?: return
|
||||||
|
val host = this
|
||||||
|
when (children) {
|
||||||
|
Uninitialized -> return
|
||||||
|
is Loading -> {
|
||||||
|
loadingItem {
|
||||||
|
id("loading")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Success -> {
|
||||||
|
matchFilter.filter = data.currentFilter
|
||||||
|
val roomList = children.invoke().filter { matchFilter.test(it) }
|
||||||
|
|
||||||
|
if (roomList.isEmpty()) {
|
||||||
|
noResultItem {
|
||||||
|
id("empty")
|
||||||
|
text(host.stringProvider.getString(R.string.no_result_placeholder))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
roomList.forEach { item ->
|
||||||
|
roomSelectionItem {
|
||||||
|
id(item.roomId)
|
||||||
|
matrixItem(item.toMatrixItem())
|
||||||
|
avatarRenderer(host.avatarRenderer)
|
||||||
|
selected(data.selectedRooms.contains(item.roomId))
|
||||||
|
itemClickListener {
|
||||||
|
host.listener?.onItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Fail -> {
|
||||||
|
// errorWithRetryItem {
|
||||||
|
// id("failed_to_load")
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoomSearchMatchFilter : Predicate<RoomSummary> {
|
||||||
|
var filter: String = ""
|
||||||
|
|
||||||
|
override fun test(roomSummary: RoomSummary): Boolean {
|
||||||
|
if (filter.isEmpty()) {
|
||||||
|
// No filter
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// if filter is "Jo Do", it should match "John Doe"
|
||||||
|
return filter.split(" ").all {
|
||||||
|
roomSummary.name.contains(it, ignoreCase = true).orFalse()
|
||||||
|
|| roomSummary.topic.contains(it, ignoreCase = true).orFalse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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.leave
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
|
||||||
|
sealed class SpaceLeaveAdvanceViewAction : VectorViewModelAction {
|
||||||
|
data class ToggleSelection(val roomId: String) : SpaceLeaveAdvanceViewAction()
|
||||||
|
data class UpdateFilter(val filter: String) : SpaceLeaveAdvanceViewAction()
|
||||||
|
object DoLeave : SpaceLeaveAdvanceViewAction()
|
||||||
|
object ClearError : SpaceLeaveAdvanceViewAction()
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.leave
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.app.features.spaces.SpaceBottomSheetSettingsArgs
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
|
data class SpaceLeaveAdvanceViewState(
|
||||||
|
val spaceId: String,
|
||||||
|
val spaceSummary: RoomSummary? = null,
|
||||||
|
val allChildren: Async<List<RoomSummary>> = Uninitialized,
|
||||||
|
val selectedRooms: List<String> = emptyList(),
|
||||||
|
val currentFilter: String = "",
|
||||||
|
val leaveState: Async<Unit> = Uninitialized
|
||||||
|
) : MvRxState {
|
||||||
|
constructor(args: SpaceBottomSheetSettingsArgs) : this(
|
||||||
|
spaceId = args.spaceId
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* 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.leave
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.core.view.isGone
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.airbnb.mvrx.Fail
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.MvRx
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.viewModel
|
||||||
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.di.ScreenComponent
|
||||||
|
import im.vector.app.core.error.ErrorFormatter
|
||||||
|
import im.vector.app.core.extensions.commitTransaction
|
||||||
|
import im.vector.app.core.extensions.hideKeyboard
|
||||||
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
|
import im.vector.app.core.platform.ToolbarConfigurable
|
||||||
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.app.databinding.ActivitySimpleLoadingBinding
|
||||||
|
import im.vector.app.features.spaces.SpaceBottomSheetSettingsArgs
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SpaceLeaveAdvancedActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>(),
|
||||||
|
SpaceLeaveAdvancedViewModel.Factory,
|
||||||
|
ToolbarConfigurable {
|
||||||
|
|
||||||
|
override fun getBinding(): ActivitySimpleLoadingBinding = ActivitySimpleLoadingBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
val leaveViewModel: SpaceLeaveAdvancedViewModel by viewModel()
|
||||||
|
|
||||||
|
@Inject lateinit var viewModelFactory: SpaceLeaveAdvancedViewModel.Factory
|
||||||
|
@Inject lateinit var errorFormatter: ErrorFormatter
|
||||||
|
|
||||||
|
override fun create(initialState: SpaceLeaveAdvanceViewState) = viewModelFactory.create(initialState)
|
||||||
|
|
||||||
|
override fun injectWith(injector: ScreenComponent) {
|
||||||
|
super.injectWith(injector)
|
||||||
|
injector.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showWaitingView(text: String?) {
|
||||||
|
hideKeyboard()
|
||||||
|
views.waitingView.waitingStatusText.isGone = views.waitingView.waitingStatusText.text.isNullOrBlank()
|
||||||
|
super.showWaitingView(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hideWaitingView() {
|
||||||
|
views.waitingView.waitingStatusText.setTextOrHide(null)
|
||||||
|
views.waitingView.waitingHorizontalProgress.progress = 0
|
||||||
|
views.waitingView.waitingHorizontalProgress.isVisible = false
|
||||||
|
super.hideWaitingView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val args = intent?.getParcelableExtra<SpaceBottomSheetSettingsArgs>(MvRx.KEY_ARG)
|
||||||
|
|
||||||
|
if (isFirstCreation()) {
|
||||||
|
val simpleName = SpaceLeaveAdvancedFragment::class.java.simpleName
|
||||||
|
if (supportFragmentManager.findFragmentByTag(simpleName) == null) {
|
||||||
|
supportFragmentManager.commitTransaction {
|
||||||
|
replace(
|
||||||
|
R.id.simpleFragmentContainer,
|
||||||
|
SpaceLeaveAdvancedFragment::class.java,
|
||||||
|
Bundle().apply { this.putParcelable(MvRx.KEY_ARG, args) },
|
||||||
|
simpleName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initUiAndData() {
|
||||||
|
super.initUiAndData()
|
||||||
|
waitingView = views.waitingView.waitingView
|
||||||
|
leaveViewModel.subscribe(this) { state ->
|
||||||
|
when (state.leaveState) {
|
||||||
|
is Loading -> {
|
||||||
|
showWaitingView()
|
||||||
|
}
|
||||||
|
is Success -> {
|
||||||
|
setResult(RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
is Fail -> {
|
||||||
|
hideWaitingView()
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.dialog_title_error)
|
||||||
|
.setMessage(errorFormatter.toHumanReadable(state.leaveState.error))
|
||||||
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
|
leaveViewModel.handle(SpaceLeaveAdvanceViewAction.ClearError)
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
hideWaitingView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newIntent(context: Context, spaceId: String): Intent {
|
||||||
|
return Intent(context, SpaceLeaveAdvancedActivity::class.java).apply {
|
||||||
|
putExtra(MvRx.KEY_ARG, SpaceBottomSheetSettingsArgs(spaceId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun configure(toolbar: MaterialToolbar) {
|
||||||
|
configureToolbar(toolbar)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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.leave
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import com.airbnb.mvrx.activityViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import com.jakewharton.rxbinding3.appcompat.queryTextChanges
|
||||||
|
import im.vector.app.core.extensions.cleanup
|
||||||
|
import im.vector.app.core.extensions.configureWith
|
||||||
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentSpaceLeaveAdvancedBinding
|
||||||
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SpaceLeaveAdvancedFragment @Inject constructor(
|
||||||
|
val controller: SelectChildrenController
|
||||||
|
) : VectorBaseFragment<FragmentSpaceLeaveAdvancedBinding>(),
|
||||||
|
SelectChildrenController.Listener {
|
||||||
|
|
||||||
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) =
|
||||||
|
FragmentSpaceLeaveAdvancedBinding.inflate(layoutInflater, container, false)
|
||||||
|
|
||||||
|
val viewModel: SpaceLeaveAdvancedViewModel by activityViewModel()
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
setupToolbar(views.toolbar)
|
||||||
|
controller.listener = this
|
||||||
|
views.roomList.configureWith(controller)
|
||||||
|
views.spaceLeaveCancel.debouncedClicks { requireActivity().finish() }
|
||||||
|
|
||||||
|
views.spaceLeaveButton.debouncedClicks {
|
||||||
|
viewModel.handle(SpaceLeaveAdvanceViewAction.DoLeave)
|
||||||
|
}
|
||||||
|
|
||||||
|
views.publicRoomsFilter.queryTextChanges()
|
||||||
|
.debounce(100, TimeUnit.MILLISECONDS)
|
||||||
|
.subscribeBy {
|
||||||
|
viewModel.handle(SpaceLeaveAdvanceViewAction.UpdateFilter(it.toString()))
|
||||||
|
}
|
||||||
|
.disposeOnDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
controller.listener = null
|
||||||
|
views.roomList.cleanup()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
|
super.invalidate()
|
||||||
|
controller.setData(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemSelected(roomSummary: RoomSummary) {
|
||||||
|
viewModel.handle(SpaceLeaveAdvanceViewAction.ToggleSelection(roomSummary.roomId))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* 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.leave
|
||||||
|
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
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.Uninitialized
|
||||||
|
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 kotlinx.coroutines.launch
|
||||||
|
import okhttp3.internal.toImmutableList
|
||||||
|
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||||
|
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||||
|
import org.matrix.android.sdk.rx.rx
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class SpaceLeaveAdvancedViewModel @AssistedInject constructor(
|
||||||
|
@Assisted val initialState: SpaceLeaveAdvanceViewState,
|
||||||
|
private val session: Session,
|
||||||
|
private val appStateHandler: AppStateHandler
|
||||||
|
) : VectorViewModel<SpaceLeaveAdvanceViewState, SpaceLeaveAdvanceViewAction, EmptyViewEvents>(initialState) {
|
||||||
|
|
||||||
|
override fun handle(action: SpaceLeaveAdvanceViewAction) = withState { state ->
|
||||||
|
when (action) {
|
||||||
|
is SpaceLeaveAdvanceViewAction.ToggleSelection -> {
|
||||||
|
val existing = state.selectedRooms.toMutableList()
|
||||||
|
if (existing.contains(action.roomId)) {
|
||||||
|
existing.remove(action.roomId)
|
||||||
|
} else {
|
||||||
|
existing.add(action.roomId)
|
||||||
|
}
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
selectedRooms = existing.toImmutableList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is SpaceLeaveAdvanceViewAction.UpdateFilter -> {
|
||||||
|
setState { copy(currentFilter = action.filter) }
|
||||||
|
}
|
||||||
|
SpaceLeaveAdvanceViewAction.DoLeave -> {
|
||||||
|
setState { copy(leaveState = Loading()) }
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
state.selectedRooms.forEach {
|
||||||
|
try {
|
||||||
|
session.getRoom(it)?.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(leaveState = Fail(failure)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpaceLeaveAdvanceViewAction.ClearError -> {
|
||||||
|
setState { copy(leaveState = Uninitialized) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val spaceSummary = session.getRoomSummary(initialState.spaceId)
|
||||||
|
setState { copy(spaceSummary = spaceSummary) }
|
||||||
|
session.getRoom(initialState.spaceId)?.let { room ->
|
||||||
|
room.rx().liveRoomSummary().subscribe {
|
||||||
|
it.getOrNull()?.let {
|
||||||
|
if (it.membership == Membership.LEAVE) {
|
||||||
|
setState { copy(leaveState = Success(Unit)) }
|
||||||
|
if (appStateHandler.safeActiveSpaceId() == initialState.spaceId) {
|
||||||
|
// switch to home?
|
||||||
|
appStateHandler.setCurrentSpace(null, session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
val children = session.getRoomSummaries(
|
||||||
|
roomSummaryQueryParams {
|
||||||
|
includeType = null
|
||||||
|
memberships = listOf(Membership.JOIN)
|
||||||
|
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(initialState.spaceId)
|
||||||
|
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(allChildren = Success(children))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: SpaceLeaveAdvanceViewState): SpaceLeaveAdvancedViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<SpaceLeaveAdvancedViewModel, SpaceLeaveAdvanceViewState> {
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: SpaceLeaveAdvanceViewState): SpaceLeaveAdvancedViewModel? {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
107
vector/src/main/res/layout/bottom_sheet_leave_space.xml
Normal file
107
vector/src/main/res/layout/bottom_sheet_leave_space.xml
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?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="?android:colorBackground"
|
||||||
|
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_with_name" />
|
||||||
|
|
||||||
|
<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="match_parent"
|
||||||
|
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="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="180dp"
|
||||||
|
android:text="@string/dont_leave_any" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/leave_selected"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
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="?colorError"
|
||||||
|
tools:visibility="visible"
|
||||||
|
tools:text="@string/error_no_network"
|
||||||
|
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>
|
97
vector/src/main/res/layout/fragment_space_leave_advanced.xml
Normal file
97
vector/src/main/res/layout/fragment_space_leave_advanced.xml
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/coordinatorLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/roomList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?android:colorBackground"
|
||||||
|
android:overScrollMode="always"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
tools:listitem="@layout/item_room_to_add_in_space" />
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<!-- minHeight="0dp" is important to collapse on scroll -->
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:minHeight="0dp"
|
||||||
|
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap|enterAlways">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical|start"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/appBarTitle"
|
||||||
|
style="@style/Widget.Vector.TextView.HeadlineMedium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start|center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@string/pick_tings_to_leave"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.MaterialToolbar>
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SearchView
|
||||||
|
android:id="@+id/publicRoomsFilter"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/addRoomToSpaceToolbar"
|
||||||
|
app:queryHint="@string/search_hint_room_name" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/spacePreviewButtonBar"
|
||||||
|
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:background="?vctr_system"
|
||||||
|
android:elevation="2dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/spaceLeaveCancel"
|
||||||
|
style="@style/Widget.Vector.Button.Text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/cancel" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/spaceLeaveButton"
|
||||||
|
style="@style/Widget.Vector.Button.Destructive"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/leave_space" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -1165,6 +1165,7 @@
|
|||||||
<string name="space_explore_activity_title">استكشِف الغُرف</string>
|
<string name="space_explore_activity_title">استكشِف الغُرف</string>
|
||||||
<string name="space_add_child_title">أضف غُرف</string>
|
<string name="space_add_child_title">أضف غُرف</string>
|
||||||
<string name="leave_space">غادر المساحة</string>
|
<string name="leave_space">غادر المساحة</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">هل أنت متأكد أنك تريد مغادرة المساحة؟</string>
|
<string name="space_leave_prompt_msg">هل أنت متأكد أنك تريد مغادرة المساحة؟</string>
|
||||||
<string name="space_leave_prompt_msg_only_you">انت الشخص الوحيد هنا إذا غادرت، فلن يتمكن أي شخص من الانضمام في المستقبل، بما في ذلك أنت.</string>
|
<string name="space_leave_prompt_msg_only_you">انت الشخص الوحيد هنا إذا غادرت، فلن يتمكن أي شخص من الانضمام في المستقبل، بما في ذلك أنت.</string>
|
||||||
<string name="space_leave_prompt_msg_private">هذه المساحة ليست عامة. لن تتمكن من الانضمام مرة أخرى بدون دعوة.</string>
|
<string name="space_leave_prompt_msg_private">هذه المساحة ليست عامة. لن تتمكن من الانضمام مرة أخرى بدون دعوة.</string>
|
||||||
|
@ -2737,6 +2737,7 @@
|
|||||||
<string name="you_are_invited">Jste zváni</string>
|
<string name="you_are_invited">Jste zváni</string>
|
||||||
<string name="spaces_beta_welcome_to_spaces">Vítejte v prostorech!</string>
|
<string name="spaces_beta_welcome_to_spaces">Vítejte v prostorech!</string>
|
||||||
<string name="space_add_existing_rooms">Přidat existující místnosti a prostor</string>
|
<string name="space_add_existing_rooms">Přidat existující místnosti a prostor</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Jste si jisti, že chcete opustit tento prostor\?</string>
|
<string name="space_leave_prompt_msg">Jste si jisti, že chcete opustit tento prostor\?</string>
|
||||||
<string name="leave_space">Opustit prostor</string>
|
<string name="leave_space">Opustit prostor</string>
|
||||||
<string name="space_add_child_title">Přidat místnosti</string>
|
<string name="space_add_child_title">Přidat místnosti</string>
|
||||||
|
@ -2770,6 +2770,7 @@
|
|||||||
<string name="command_description_leave_room">Verlasse den Raum mit der angegebenen ID (oder den aktuellen Raum, wenn keine ID angegeben wird)</string>
|
<string name="command_description_leave_room">Verlasse den Raum mit der angegebenen ID (oder den aktuellen Raum, wenn keine ID angegeben wird)</string>
|
||||||
<string name="search_hint_room_name">Name suchen</string>
|
<string name="search_hint_room_name">Name suchen</string>
|
||||||
<string name="you_are_invited">Du wurdest eingeladen</string>
|
<string name="you_are_invited">Du wurdest eingeladen</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Bist du dir sicher, dass du den Space verlassen willst\?</string>
|
<string name="space_leave_prompt_msg">Bist du dir sicher, dass du den Space verlassen willst\?</string>
|
||||||
<string name="leave_space">Space verlassen</string>
|
<string name="leave_space">Space verlassen</string>
|
||||||
<string name="space_add_child_title">Räume hinzufügen</string>
|
<string name="space_add_child_title">Räume hinzufügen</string>
|
||||||
|
@ -2674,6 +2674,7 @@
|
|||||||
<string name="space_leave_prompt_msg_as_admin">Vi estas administranto de ĉi tiu aro. Certigu, ke vi transdonis administrajn rajtojn al alia ano, antaŭ ol vi vere foriros.</string>
|
<string name="space_leave_prompt_msg_as_admin">Vi estas administranto de ĉi tiu aro. Certigu, ke vi transdonis administrajn rajtojn al alia ano, antaŭ ol vi vere foriros.</string>
|
||||||
<string name="space_leave_prompt_msg_private">Ĉi tiu aro ne estas publika. Vi ne povos ree aliĝi sen invito.</string>
|
<string name="space_leave_prompt_msg_private">Ĉi tiu aro ne estas publika. Vi ne povos ree aliĝi sen invito.</string>
|
||||||
<string name="space_leave_prompt_msg_only_you">Vi estas la sola persono ĉi tie. Se vi foriros, neniu plu povos aliĝi, inkluzive vin mem.</string>
|
<string name="space_leave_prompt_msg_only_you">Vi estas la sola persono ĉi tie. Se vi foriros, neniu plu povos aliĝi, inkluzive vin mem.</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Ĉu vi certe volas foriri de la aro\?</string>
|
<string name="space_leave_prompt_msg">Ĉu vi certe volas foriri de la aro\?</string>
|
||||||
<string name="leave_space">Foriri de aro</string>
|
<string name="leave_space">Foriri de aro</string>
|
||||||
<string name="space_add_child_title">Aldoni ĉambrojn</string>
|
<string name="space_add_child_title">Aldoni ĉambrojn</string>
|
||||||
|
@ -2619,6 +2619,7 @@ Por favor permite el acceso en la próxima ventana emergente para descubrir usua
|
|||||||
<string name="labs_use_restricted_join_rule">Espacio Experimental - Sala Restringida.</string>
|
<string name="labs_use_restricted_join_rule">Espacio Experimental - Sala Restringida.</string>
|
||||||
<string name="you_are_invited">Estas invitado</string>
|
<string name="you_are_invited">Estas invitado</string>
|
||||||
<string name="space_add_rooms">Añadir salas</string>
|
<string name="space_add_rooms">Añadir salas</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Estas seguro de que quieres salir de este espacio\?</string>
|
<string name="space_leave_prompt_msg">Estas seguro de que quieres salir de este espacio\?</string>
|
||||||
<string name="leave_space">Salir de este espacio</string>
|
<string name="leave_space">Salir de este espacio</string>
|
||||||
<string name="space_add_child_title">Añadir salas</string>
|
<string name="space_add_child_title">Añadir salas</string>
|
||||||
|
@ -2679,6 +2679,7 @@
|
|||||||
<string name="spaces_beta_welcome_to_spaces_desc">Kogukonnakeskused on uus võimalus siduda jututubasid ja inimesi.</string>
|
<string name="spaces_beta_welcome_to_spaces_desc">Kogukonnakeskused on uus võimalus siduda jututubasid ja inimesi.</string>
|
||||||
<string name="spaces_beta_welcome_to_spaces">Tere tulemast kasutama kogukonnakeskuseid!</string>
|
<string name="spaces_beta_welcome_to_spaces">Tere tulemast kasutama kogukonnakeskuseid!</string>
|
||||||
<string name="space_add_existing_rooms">Lisa olemasolevaid jututubasid ja kogukonnakeskuseid</string>
|
<string name="space_add_existing_rooms">Lisa olemasolevaid jututubasid ja kogukonnakeskuseid</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Kas oled kindel, et soovid lahkuda kogukonnakeskusest\?</string>
|
<string name="space_leave_prompt_msg">Kas oled kindel, et soovid lahkuda kogukonnakeskusest\?</string>
|
||||||
<string name="leave_space">Lahku kogukonnakeskusest</string>
|
<string name="leave_space">Lahku kogukonnakeskusest</string>
|
||||||
<string name="space_add_child_title">Lisa jututuba</string>
|
<string name="space_add_child_title">Lisa jututuba</string>
|
||||||
|
@ -2679,6 +2679,7 @@
|
|||||||
<string name="spaces_beta_welcome_to_spaces_desc">فضاها شیوهای جدید برای گروهبندی اتاقها و افراد است.</string>
|
<string name="spaces_beta_welcome_to_spaces_desc">فضاها شیوهای جدید برای گروهبندی اتاقها و افراد است.</string>
|
||||||
<string name="spaces_beta_welcome_to_spaces">به فضاها خوش آمدید!</string>
|
<string name="spaces_beta_welcome_to_spaces">به فضاها خوش آمدید!</string>
|
||||||
<string name="space_add_existing_rooms">افزودن فضا و اتاقهای موجود</string>
|
<string name="space_add_existing_rooms">افزودن فضا و اتاقهای موجود</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">مطمئنید که میخواهید فضا را ترک کنید؟</string>
|
<string name="space_leave_prompt_msg">مطمئنید که میخواهید فضا را ترک کنید؟</string>
|
||||||
<string name="leave_space">ترک فضا</string>
|
<string name="leave_space">ترک فضا</string>
|
||||||
<string name="space_add_child_title">افزودن اتاق</string>
|
<string name="space_add_child_title">افزودن اتاق</string>
|
||||||
|
@ -2748,6 +2748,7 @@
|
|||||||
<string name="space_leave_prompt_msg_as_admin">Vous êtes admin de cet espace, assurez-vous d’avoir transféré les droits d’admin à un autre membre avant de partir.</string>
|
<string name="space_leave_prompt_msg_as_admin">Vous êtes admin de cet espace, assurez-vous d’avoir transféré les droits d’admin à un autre membre avant de partir.</string>
|
||||||
<string name="space_leave_prompt_msg_private">Cet espace n’est pas public. Vous ne pourrez pas le rejoindre sans invitation.</string>
|
<string name="space_leave_prompt_msg_private">Cet espace n’est pas public. Vous ne pourrez pas le rejoindre sans invitation.</string>
|
||||||
<string name="space_leave_prompt_msg_only_you">Vous êtes la seule personne ici. Si vous partez, personne ne pourra entrer à l’avenir, même pas vous.</string>
|
<string name="space_leave_prompt_msg_only_you">Vous êtes la seule personne ici. Si vous partez, personne ne pourra entrer à l’avenir, même pas vous.</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Voulez-vous vraiment quitter l’espace\?</string>
|
<string name="space_leave_prompt_msg">Voulez-vous vraiment quitter l’espace\?</string>
|
||||||
<string name="leave_space">Quitter l’espace</string>
|
<string name="leave_space">Quitter l’espace</string>
|
||||||
<string name="space_add_child_title">Ajouter des salons</string>
|
<string name="space_add_child_title">Ajouter des salons</string>
|
||||||
|
@ -2708,6 +2708,7 @@
|
|||||||
<string name="spaces_beta_welcome_to_spaces_desc">Les espaces sont une nouvelle manière de regrouper les salons et les gens.</string>
|
<string name="spaces_beta_welcome_to_spaces_desc">Les espaces sont une nouvelle manière de regrouper les salons et les gens.</string>
|
||||||
<string name="spaces_beta_welcome_to_spaces">Bienvenue dans les espaces !</string>
|
<string name="spaces_beta_welcome_to_spaces">Bienvenue dans les espaces !</string>
|
||||||
<string name="space_add_existing_rooms">Ajouter des salons et espaces existants</string>
|
<string name="space_add_existing_rooms">Ajouter des salons et espaces existants</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Voulez-vous vraiment quitter l’espace \?</string>
|
<string name="space_leave_prompt_msg">Voulez-vous vraiment quitter l’espace \?</string>
|
||||||
<string name="leave_space">Quitter l’espace</string>
|
<string name="leave_space">Quitter l’espace</string>
|
||||||
<string name="space_add_child_title">Ajouter des salons</string>
|
<string name="space_add_child_title">Ajouter des salons</string>
|
||||||
|
@ -2490,6 +2490,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró
|
|||||||
<string name="space_leave_prompt_msg_as_admin">Most te vagy a tér adminisztrátora, bizonyosodj meg arról, hogy kineveztél mást adminisztrátornak mielőtt elhagyod.</string>
|
<string name="space_leave_prompt_msg_as_admin">Most te vagy a tér adminisztrátora, bizonyosodj meg arról, hogy kineveztél mást adminisztrátornak mielőtt elhagyod.</string>
|
||||||
<string name="space_leave_prompt_msg_private">Ez a tér nem nyilvános. Kilépés után csak újabb meghívóval lehet újra belépni.</string>
|
<string name="space_leave_prompt_msg_private">Ez a tér nem nyilvános. Kilépés után csak újabb meghívóval lehet újra belépni.</string>
|
||||||
<string name="space_leave_prompt_msg_only_you">Csak te van itt. Ha kilépsz, akkor a jövőben senki nem tud majd ide belépni, beleértve téged is.</string>
|
<string name="space_leave_prompt_msg_only_you">Csak te van itt. Ha kilépsz, akkor a jövőben senki nem tud majd ide belépni, beleértve téged is.</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Biztos el akarod hagyni a teret\?</string>
|
<string name="space_leave_prompt_msg">Biztos el akarod hagyni a teret\?</string>
|
||||||
<string name="leave_space">Tér elhagyása</string>
|
<string name="leave_space">Tér elhagyása</string>
|
||||||
<string name="space_add_child_title">Szobák hozzáadása</string>
|
<string name="space_add_child_title">Szobák hozzáadása</string>
|
||||||
|
@ -2732,6 +2732,7 @@
|
|||||||
<string name="spaces_beta_welcome_to_spaces_desc">Gli Spazi sono un nuovo modo per raggruppare stanze e contatti.</string>
|
<string name="spaces_beta_welcome_to_spaces_desc">Gli Spazi sono un nuovo modo per raggruppare stanze e contatti.</string>
|
||||||
<string name="spaces_beta_welcome_to_spaces">Benvenuto negli Spazi!</string>
|
<string name="spaces_beta_welcome_to_spaces">Benvenuto negli Spazi!</string>
|
||||||
<string name="space_add_existing_rooms">Aggiungi stanze e Spazi esistenti</string>
|
<string name="space_add_existing_rooms">Aggiungi stanze e Spazi esistenti</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Vuoi veramente uscire dallo Spazio\?</string>
|
<string name="space_leave_prompt_msg">Vuoi veramente uscire dallo Spazio\?</string>
|
||||||
<string name="leave_space">Esci dallo Spazio</string>
|
<string name="leave_space">Esci dallo Spazio</string>
|
||||||
<string name="space_add_child_title">Aggiungi stanze</string>
|
<string name="space_add_child_title">Aggiungi stanze</string>
|
||||||
|
@ -2815,6 +2815,7 @@
|
|||||||
<string name="space_leave_prompt_msg_as_admin">Você é admin deste espaço, assegure-se que você tem transferido direito de admin a um outro membro antes de sair.</string>
|
<string name="space_leave_prompt_msg_as_admin">Você é admin deste espaço, assegure-se que você tem transferido direito de admin a um outro membro antes de sair.</string>
|
||||||
<string name="space_leave_prompt_msg_private">Este espaço não é público. Você não vai ser capaz de se rejuntar sem um convite.</string>
|
<string name="space_leave_prompt_msg_private">Este espaço não é público. Você não vai ser capaz de se rejuntar sem um convite.</string>
|
||||||
<string name="space_leave_prompt_msg_only_you">Você é a única pessoa aqui. Se você sair, ninguém vai ser capaz de se juntar no futuro, incluindo você.</string>
|
<string name="space_leave_prompt_msg_only_you">Você é a única pessoa aqui. Se você sair, ninguém vai ser capaz de se juntar no futuro, incluindo você.</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Você tem certeza que você quer sair do espaço\?</string>
|
<string name="space_leave_prompt_msg">Você tem certeza que você quer sair do espaço\?</string>
|
||||||
<string name="leave_space">Sair de Espaço</string>
|
<string name="leave_space">Sair de Espaço</string>
|
||||||
<string name="space_add_child_title">Adicionar salas</string>
|
<string name="space_add_child_title">Adicionar salas</string>
|
||||||
|
@ -2868,6 +2868,7 @@
|
|||||||
<string name="space_leave_prompt_msg_as_admin">Вы являетесь администратором этого пространства, перед уходом убедитесь, что передали права администратора другому пользователю.</string>
|
<string name="space_leave_prompt_msg_as_admin">Вы являетесь администратором этого пространства, перед уходом убедитесь, что передали права администратора другому пользователю.</string>
|
||||||
<string name="space_leave_prompt_msg_private">Это пространство не является публичным. Вы не сможете присоединиться к нему без приглашения.</string>
|
<string name="space_leave_prompt_msg_private">Это пространство не является публичным. Вы не сможете присоединиться к нему без приглашения.</string>
|
||||||
<string name="space_leave_prompt_msg_only_you">Вы здесь единственный человек. Если вы уйдёте, никто не сможет присоединиться в будущем, включая вас.</string>
|
<string name="space_leave_prompt_msg_only_you">Вы здесь единственный человек. Если вы уйдёте, никто не сможет присоединиться в будущем, включая вас.</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Вы уверены, что хотите покинуть пространство\?</string>
|
<string name="space_leave_prompt_msg">Вы уверены, что хотите покинуть пространство\?</string>
|
||||||
<string name="leave_space">Покинуть пространство</string>
|
<string name="leave_space">Покинуть пространство</string>
|
||||||
<string name="space_add_child_title">Добавить комнаты</string>
|
<string name="space_add_child_title">Добавить комнаты</string>
|
||||||
|
@ -2668,6 +2668,7 @@
|
|||||||
<string name="you_are_invited">Jeni ftuar</string>
|
<string name="you_are_invited">Jeni ftuar</string>
|
||||||
<string name="spaces_beta_welcome_to_spaces">Mirë se vini te Hapësira!</string>
|
<string name="spaces_beta_welcome_to_spaces">Mirë se vini te Hapësira!</string>
|
||||||
<string name="space_add_existing_rooms">Shtoni dhoma ekzistuese dhe hapësira</string>
|
<string name="space_add_existing_rooms">Shtoni dhoma ekzistuese dhe hapësira</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Jeni i sigurt se doni të dilni nga hapësira\?</string>
|
<string name="space_leave_prompt_msg">Jeni i sigurt se doni të dilni nga hapësira\?</string>
|
||||||
<string name="leave_space">Braktiseni Hapësirën</string>
|
<string name="leave_space">Braktiseni Hapësirën</string>
|
||||||
<string name="space_add_child_title">Shtoni dhoma</string>
|
<string name="space_add_child_title">Shtoni dhoma</string>
|
||||||
|
@ -2737,6 +2737,7 @@
|
|||||||
<string name="spaces_beta_welcome_to_spaces_desc">Utrymmen är ett nytt sätt att gruppera rum och personer.</string>
|
<string name="spaces_beta_welcome_to_spaces_desc">Utrymmen är ett nytt sätt att gruppera rum och personer.</string>
|
||||||
<string name="spaces_beta_welcome_to_spaces">Välkommen till utrymmen!</string>
|
<string name="spaces_beta_welcome_to_spaces">Välkommen till utrymmen!</string>
|
||||||
<string name="space_add_existing_rooms">Lägg till existerande rum och utrymme</string>
|
<string name="space_add_existing_rooms">Lägg till existerande rum och utrymme</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">Är du säker på att du vill lämna utrymmet\?</string>
|
<string name="space_leave_prompt_msg">Är du säker på att du vill lämna utrymmet\?</string>
|
||||||
<string name="leave_space">Lämna utrymme</string>
|
<string name="leave_space">Lämna utrymme</string>
|
||||||
<string name="space_add_child_title">Lägg till rum</string>
|
<string name="space_add_child_title">Lägg till rum</string>
|
||||||
|
@ -2602,6 +2602,7 @@
|
|||||||
<string name="space_leave_prompt_msg_as_admin">你是此空间的管理员,请确保你在离开前已将管理权限转让给另一位成员。</string>
|
<string name="space_leave_prompt_msg_as_admin">你是此空间的管理员,请确保你在离开前已将管理权限转让给另一位成员。</string>
|
||||||
<string name="space_leave_prompt_msg_private">此空间并非公开空间。你将无法在没有邀请的情况下重新加入。</string>
|
<string name="space_leave_prompt_msg_private">此空间并非公开空间。你将无法在没有邀请的情况下重新加入。</string>
|
||||||
<string name="space_leave_prompt_msg_only_you">你是这唯一的人。如果你离开,包括你在内的所有人都将无法加入此空间。</string>
|
<string name="space_leave_prompt_msg_only_you">你是这唯一的人。如果你离开,包括你在内的所有人都将无法加入此空间。</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">你确定你想要离开此空间吗?</string>
|
<string name="space_leave_prompt_msg">你确定你想要离开此空间吗?</string>
|
||||||
<string name="leave_space">离开空间</string>
|
<string name="leave_space">离开空间</string>
|
||||||
<string name="space_add_child_title">添加聊天室</string>
|
<string name="space_add_child_title">添加聊天室</string>
|
||||||
|
@ -2628,6 +2628,7 @@
|
|||||||
<string name="spaces_beta_welcome_to_spaces_desc">空間是將聊天室與人們分組的新方式。</string>
|
<string name="spaces_beta_welcome_to_spaces_desc">空間是將聊天室與人們分組的新方式。</string>
|
||||||
<string name="spaces_beta_welcome_to_spaces">歡迎使用空間!</string>
|
<string name="spaces_beta_welcome_to_spaces">歡迎使用空間!</string>
|
||||||
<string name="space_add_existing_rooms">新增既有的聊天室與空間</string>
|
<string name="space_add_existing_rooms">新增既有的聊天室與空間</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<string name="space_leave_prompt_msg">您確定您想要離開空間嗎?</string>
|
<string name="space_leave_prompt_msg">您確定您想要離開空間嗎?</string>
|
||||||
<string name="leave_space">離開空間</string>
|
<string name="leave_space">離開空間</string>
|
||||||
<string name="space_add_child_title">新增聊天室</string>
|
<string name="space_add_child_title">新增聊天室</string>
|
||||||
|
@ -3479,11 +3479,17 @@
|
|||||||
<string name="space_explore_activity_title">Explore rooms</string>
|
<string name="space_explore_activity_title">Explore rooms</string>
|
||||||
<string name="space_add_child_title">Add rooms</string>
|
<string name="space_add_child_title">Add rooms</string>
|
||||||
<string name="leave_space">Leave Space</string>
|
<string name="leave_space">Leave Space</string>
|
||||||
|
<string name="space_leave_prompt_msg_with_name">Are you sure you want to leave %s?</string>
|
||||||
|
<!-- TO BE REMOVED -->
|
||||||
<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 the space?</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_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_private">You won\'t be able to rejoin unless you are re-invited.</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_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">Don’t leave any rooms and spaces</string>
|
||||||
|
<string name="leave_specific_ones">Leave specific rooms and spaces…</string>
|
||||||
|
<string name="pick_tings_to_leave">Pick things to leave</string>
|
||||||
|
|
||||||
<string name="space_add_existing_rooms">Add existing rooms and space</string>
|
<string name="space_add_existing_rooms">Add existing rooms and space</string>
|
||||||
<string name="space_add_rooms">Add rooms</string>
|
<string name="space_add_rooms">Add rooms</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user