Update add room screen as per design

This commit is contained in:
Valere 2021-04-27 14:15:52 +02:00
parent 7465ac2ef6
commit 31ffa65fd0
5 changed files with 174 additions and 16 deletions

View File

@ -24,4 +24,12 @@ interface UpdatableLivePageResult {
val livePagedList: LiveData<PagedList<RoomSummary>>
fun updateQuery(builder: (RoomSummaryQueryParams) -> RoomSummaryQueryParams)
val liveBoundaries: LiveData<ResultBoundaries>
}
data class ResultBoundaries(
val frontLoaded: Boolean = false,
val endLoaded: Boolean = false,
val zeroItemLoaded: Boolean = false
)

View File

@ -18,6 +18,7 @@
package org.matrix.android.sdk.internal.session.room.summary
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
@ -28,6 +29,7 @@ import io.realm.Sort
import io.realm.kotlin.where
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.session.room.ResultBoundaries
import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
@ -187,9 +189,25 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
roomSummaryMapper.map(it)
}
val boundaries = MutableLiveData(ResultBoundaries())
val mapped = monarchy.findAllPagedWithChanges(
realmDataSourceFactory,
LivePagedListBuilder(dataSourceFactory, pagedListConfig)
LivePagedListBuilder(dataSourceFactory, pagedListConfig).also {
it.setBoundaryCallback(object : PagedList.BoundaryCallback<RoomSummary>() {
override fun onItemAtEndLoaded(itemAtEnd: RoomSummary) {
boundaries.postValue(boundaries.value?.copy(frontLoaded = true))
}
override fun onItemAtFrontLoaded(itemAtFront: RoomSummary) {
boundaries.postValue(boundaries.value?.copy(endLoaded = true))
}
override fun onZeroItemsLoaded() {
boundaries.postValue(boundaries.value?.copy(zeroItemLoaded = true))
}
})
}
)
return object : UpdatableLivePageResult {
@ -200,6 +218,9 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
roomSummariesQuery(it, builder.invoke(queryParams)).process(sortOrder)
}
}
override val liveBoundaries: LiveData<ResultBoundaries>
get() = boundaries
}
}

View File

@ -22,6 +22,8 @@ import com.airbnb.epoxy.paging.PagedListEpoxyController
import im.vector.app.core.utils.DebouncedClickListener
import im.vector.app.core.utils.createUIHandler
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.list.RoomCategoryItem_
import org.matrix.android.sdk.api.session.room.ResultBoundaries
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.util.toMatrixItem
@ -54,6 +56,26 @@ class AddRoomListController @Inject constructor(
var listener: Listener? = null
var ignoreRooms: List<String>? = null
var initialLoadOccurred = false
fun boundaryChange(boundary: ResultBoundaries) {
val boundaryHasLoadedSomething = boundary.frontLoaded || boundary.zeroItemLoaded
if (initialLoadOccurred != boundaryHasLoadedSomething) {
initialLoadOccurred = boundaryHasLoadedSomething
requestForcedModelBuild()
}
}
var sectionName: String? = null
set(value) {
if (value != field) {
field = value
requestForcedModelBuild()
}
}
var totalSize: Int = 0
var selectedItems: Map<String, Boolean> = emptyMap()
set(value) {
field = value
@ -62,13 +84,27 @@ class AddRoomListController @Inject constructor(
}
override fun addModels(models: List<EpoxyModel<*>>) {
if (ignoreRooms == null) {
super.addModels(models)
val filteredModel = if (ignoreRooms == null) {
models
} else {
super.addModels(
models.filter {
it !is RoomSelectionItem || !ignoreRooms!!.contains(it.matrixItem.id)
}
}
val somethingToShow = filteredModel.isNotEmpty() || !initialLoadOccurred
if (somethingToShow || filteredModel.isNotEmpty()) {
add(
RoomCategoryItem_().apply {
id("header")
title(sectionName ?: "")
expanded(true)
}
)
}
super.addModels(filteredModel)
if (!initialLoadOccurred) {
add(
RoomSelectionPlaceHolderItem_().apply { id("loading") }
)
}
}

View File

@ -16,6 +16,9 @@
package im.vector.app.features.spaces.manage
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
@ -23,23 +26,30 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.epoxy.EpoxyViewHolder
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.fragmentViewModel
import com.jakewharton.rxbinding3.appcompat.queryTextChanges
import im.vector.app.R
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.FragmentSpaceAddRoomsBinding
import im.vector.app.features.home.room.list.RoomCategoryItem_
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 SpaceAddRoomFragment @Inject constructor(
private val epoxyController: AddRoomListController,
private val spaceEpoxyController: AddRoomListController,
private val roomEpoxyController: AddRoomListController,
private val viewModelFactory: SpaceAddRoomsViewModel.Factory
) : VectorBaseFragment<FragmentSpaceAddRoomsBinding>(),
OnBackPressed, AddRoomListController.Listener, SpaceAddRoomsViewModel.Factory {
@ -79,7 +89,8 @@ class SpaceAddRoomFragment @Inject constructor(
.disposeOnDestroyView()
viewModel.selectionListLiveData.observe(viewLifecycleOwner) {
epoxyController.selectedItems = it
spaceEpoxyController.selectedItems = it
roomEpoxyController.selectedItems = it
saveNeeded = it.values.any { it }
invalidateOptionsMenu()
}
@ -89,7 +100,8 @@ class SpaceAddRoomFragment @Inject constructor(
}.disposeOnDestroyView()
viewModel.selectSubscribe(this, SpaceAddRoomsState::ignoreRooms) {
epoxyController.ignoreRooms = it
spaceEpoxyController.ignoreRooms = it
roomEpoxyController.ignoreRooms = it
}.disposeOnDestroyView()
viewModel.selectSubscribe(this, SpaceAddRoomsState::isSaving) {
@ -142,16 +154,71 @@ class SpaceAddRoomFragment @Inject constructor(
override fun onDestroyView() {
views.roomList.cleanup()
epoxyController.listener = null
spaceEpoxyController.listener = null
roomEpoxyController.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
views.roomList.configureWith(epoxyController, showDivider = true)
epoxyController.listener = this
viewModel.updatableLivePageResult.livePagedList.observe(viewLifecycleOwner) {
epoxyController.submitList(it)
val concatAdapter = ConcatAdapter()
spaceEpoxyController.sectionName = getString(R.string.spaces_header)
roomEpoxyController.sectionName = getString(R.string.rooms_header)
spaceEpoxyController.listener = this
roomEpoxyController.listener = this
viewModel.updatableLiveSpacePageResult.liveBoundaries.observe(viewLifecycleOwner) {
spaceEpoxyController.boundaryChange(it)
}
viewModel.updatableLiveSpacePageResult.livePagedList.observe(viewLifecycleOwner) {
spaceEpoxyController.totalSize = it.size
spaceEpoxyController.submitList(it)
}
viewModel.updatableLivePageResult.liveBoundaries.observe(viewLifecycleOwner) {
roomEpoxyController.boundaryChange(it)
}
viewModel.updatableLivePageResult.livePagedList.observe(viewLifecycleOwner) {
roomEpoxyController.totalSize = it.size
roomEpoxyController.submitList(it)
}
views.roomList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
views.roomList.addItemDecoration(
object : DividerItemDecoration(context, VERTICAL) {
val decorationDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.divider_horizontal)
override fun getDrawable(): Drawable? {
return decorationDrawable
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val position = parent.getChildAdapterPosition(view)
val vh = parent.findViewHolderForAdapterPosition(position)
val nextIsSectionOrFinal = parent.findViewHolderForAdapterPosition(position + 1)?.let {
(it as? EpoxyViewHolder)?.model is RoomCategoryItem_
} ?: true
if (vh == null
|| (vh as? EpoxyViewHolder)?.model is RoomCategoryItem_
|| nextIsSectionOrFinal
) {
outRect.setEmpty()
} else {
super.getItemOffsets(outRect, view, parent, state)
}
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
}
}
)
views.roomList.setHasFixedSize(true)
concatAdapter.addAdapter(roomEpoxyController.adapter)
concatAdapter.addAdapter(spaceEpoxyController.adapter)
views.roomList.adapter = concatAdapter
}
override fun onBackPressed(toolbarButton: Boolean): Boolean {

View File

@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
class AddRoomError(val errorList: Map<String, Throwable>) : Throwable() {
@ -53,11 +54,31 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
private val session: Session
) : VectorViewModel<SpaceAddRoomsState, SpaceAddRoomActions, SpaceAddRoomsViewEvents>(initialState) {
val updatableLivePageResult: UpdatableLivePageResult by lazy {
val updatableLiveSpacePageResult: UpdatableLivePageResult by lazy {
session.getFilteredPagedRoomSummariesLive(
roomSummaryQueryParams {
this.memberships = listOf(Membership.JOIN)
this.excludeType = null
this.includeType = listOf(RoomType.SPACE)
this.activeSpaceId = ActiveSpaceFilter.ExcludeSpace(initialState.spaceId)
this.displayName = QueryStringValue.Contains(initialState.currentFilter, QueryStringValue.Case.INSENSITIVE)
},
pagedListConfig = PagedList.Config.Builder()
.setPageSize(10)
.setInitialLoadSizeHint(20)
.setEnablePlaceholders(true)
.setPrefetchDistance(10)
.build(),
sortOrder = RoomSortOrder.NAME
)
}
val updatableLivePageResult: UpdatableLivePageResult by lazy {
session.getFilteredPagedRoomSummariesLive(
roomSummaryQueryParams {
this.memberships = listOf(Membership.JOIN)
this.excludeType = listOf(RoomType.SPACE)
this.includeType = null
this.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
this.activeSpaceId = ActiveSpaceFilter.ExcludeSpace(initialState.spaceId)
this.displayName = QueryStringValue.Contains(initialState.currentFilter, QueryStringValue.Case.INSENSITIVE)
@ -116,6 +137,11 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.INSENSITIVE)
)
}
updatableLiveSpacePageResult.updateQuery {
it.copy(
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.INSENSITIVE)
)
}
setState {
copy(
currentFilter = action.filter