Cherry pick room on leave space

This commit is contained in:
Valere 2021-07-30 11:06:52 +02:00
parent 8fd784e275
commit 9a9a3d8cc6
14 changed files with 656 additions and 14 deletions

View File

@ -319,6 +319,7 @@
<activity android:name=".features.spaces.SpaceCreationActivity" />
<activity android:name=".features.spaces.manage.SpaceManageActivity" />
<activity android:name=".features.spaces.people.SpacePeopleActivity" />
<activity android:name=".features.spaces.leave.SpaceLeaveAdvancedActivity" />
<!-- Services -->
<service

View File

@ -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.CreateSpaceDetailsFragment
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.SpaceManageRoomsFragment
import im.vector.app.features.spaces.manage.SpaceSettingsFragment
@ -828,4 +829,9 @@ interface FragmentModule {
@IntoMap
@FragmentKey(RoomJoinRuleChooseRestrictedFragment::class)
fun bindRoomJoinRuleChooseRestrictedFragment(fragment: RoomJoinRuleChooseRestrictedFragment): Fragment
@Binds
@IntoMap
@FragmentKey(SpaceLeaveAdvancedFragment::class)
fun bindSpaceLeaveAdvancedFragment(fragment: SpaceLeaveAdvancedFragment): Fragment
}

View File

@ -89,6 +89,7 @@ import im.vector.app.features.spaces.SpaceCreationActivity
import im.vector.app.features.spaces.SpaceExploreActivity
import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
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.share.ShareSpaceBottomSheet
import im.vector.app.features.terms.ReviewTermsActivity
@ -172,6 +173,7 @@ interface ScreenComponent {
fun inject(activity: SpaceExploreActivity)
fun inject(activity: SpaceManageActivity)
fun inject(activity: RoomJoinRuleActivity)
fun inject(activity: SpaceLeaveAdvancedActivity)
/* ==========================================================================================
* BottomSheets

View File

@ -16,6 +16,7 @@
package im.vector.app.features.spaces
import android.app.Activity
import android.graphics.Typeface
import android.os.Bundle
import android.os.Parcelable
@ -32,11 +33,13 @@ 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.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
@ -66,6 +69,15 @@ class LeaveSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetLea
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(SpaceMenuViewAction.SetAutoLeaveAll)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
views.autoLeaveRadioGroup.checkedChanges()
@ -80,6 +92,10 @@ class LeaveSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetLea
}
views.leaveSelected.id -> {
settingsViewModel.handle(SpaceMenuViewAction.SetAutoLeaveSelected)
// launch dedicated activity
cherryPickLeaveActivityResult.launch(
SpaceLeaveAdvancedActivity.newIntent(requireContext(), spaceArgs.spaceId)
)
}
}
}
@ -142,16 +158,22 @@ class LeaveSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetLea
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)
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
}
}

View File

@ -78,8 +78,10 @@ class SpaceMenuViewModel @AssistedInject constructor(
it.getOrNull()?.let {
if (it.membership == Membership.LEAVE) {
setState { copy(leavingState = Success(Unit)) }
// switch to home?
appStateHandler.setCurrentSpace(null, session)
if (appStateHandler.safeActiveSpaceId() == initialState.spaceId) {
// switch to home?
appStateHandler.setCurrentSpace(null, session)
}
}
}
}

View File

@ -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()
}
}
}
}

View File

@ -0,0 +1,25 @@
/*
* 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()
}

View File

@ -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
)
}

View File

@ -0,0 +1,127 @@
/*
* 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 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.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.text = null
views.waitingView.waitingStatusText.isGone = true
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()
showSnackbar(errorFormatter.toHumanReadable(state.leaveState.error))
}
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)
}
}

View File

@ -0,0 +1,85 @@
/*
* 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.OnBackPressed
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>(),
OnBackPressed,
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))
}
override fun onBackPressed(toolbarButton: Boolean): Boolean {
requireActivity().finish()
return true
}
}

View File

@ -0,0 +1,135 @@
/*
* 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.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 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.toList()
)
}
}
is SpaceLeaveAdvanceViewAction.UpdateFilter -> {
setState { copy(currentFilter = action.filter) }
}
SpaceLeaveAdvanceViewAction.DoLeave -> {
setState { copy(leaveState = Loading()) }
viewModelScope.launch {
try {
try {
state.selectedRooms.forEach {
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)) }
}
}
}
}
}
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")
}
}
}

View File

@ -30,21 +30,21 @@
<RadioButton
android:id="@+id/leave_all"
android:layout_width="wrap_content"
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="wrap_content"
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="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="180dp"
android:text="@string/leave_specific_ones" />

View 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>

View File

@ -3487,6 +3487,7 @@
<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="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_rooms">Add rooms</string>