Merge pull request #5181 from vector-im/feature/mna/4533-dm-rooms-headers
#4533: improve headers UI in room/messages lists
This commit is contained in:
commit
4939a98689
1
changelog.d/4533.misc
Normal file
1
changelog.d/4533.misc
Normal file
@ -0,0 +1 @@
|
||||
Improve headers UI in Rooms/Messages lists
|
@ -58,6 +58,7 @@ ext.libs = [
|
||||
'lifecycleCommon' : "androidx.lifecycle:lifecycle-common:$lifecycle",
|
||||
'lifecycleLivedata' : "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle",
|
||||
'lifecycleProcess' : "androidx.lifecycle:lifecycle-process:$lifecycle",
|
||||
'lifecycleRuntimeKtx' : "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle",
|
||||
'datastore' : "androidx.datastore:datastore:1.0.0",
|
||||
'datastorepreferences' : "androidx.datastore:datastore-preferences:1.0.0",
|
||||
'pagingRuntimeKtx' : "androidx.paging:paging-runtime-ktx:2.1.2",
|
||||
@ -141,4 +142,4 @@ ext.libs = [
|
||||
'timberJunitRule' : "net.lachlanmckee:timber-junit-rule:1.0.1",
|
||||
'junit' : "junit:junit:4.13.2"
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.room
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.paging.PagedList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
@ -216,6 +217,11 @@ interface RoomService {
|
||||
pagedListConfig: PagedList.Config = defaultPagedListConfig,
|
||||
sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): UpdatableLivePageResult
|
||||
|
||||
/**
|
||||
* Retrieve a flow on the number of rooms.
|
||||
*/
|
||||
fun getRoomCountFlow(queryParams: RoomSummaryQueryParams): Flow<Int>
|
||||
|
||||
/**
|
||||
* TODO Doc
|
||||
*/
|
||||
|
@ -22,10 +22,8 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
|
||||
interface UpdatableLivePageResult {
|
||||
val livePagedList: LiveData<PagedList<RoomSummary>>
|
||||
|
||||
fun updateQuery(builder: (RoomSummaryQueryParams) -> RoomSummaryQueryParams)
|
||||
|
||||
val liveBoundaries: LiveData<ResultBoundaries>
|
||||
var queryParams: RoomSummaryQueryParams
|
||||
}
|
||||
|
||||
data class ResultBoundaries(
|
||||
|
@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import androidx.paging.PagedList
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.RoomService
|
||||
@ -109,6 +110,10 @@ internal class DefaultRoomService @Inject constructor(
|
||||
return roomSummaryDataSource.getUpdatablePagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder)
|
||||
}
|
||||
|
||||
override fun getRoomCountFlow(queryParams: RoomSummaryQueryParams): Flow<Int> {
|
||||
return roomSummaryDataSource.getCountFlow(queryParams)
|
||||
}
|
||||
|
||||
override fun getNotificationCountForRooms(queryParams: RoomSummaryQueryParams): RoomAggregateNotificationCount {
|
||||
return roomSummaryDataSource.getNotificationCountForRooms(queryParams)
|
||||
}
|
||||
|
@ -25,7 +25,13 @@ import androidx.paging.PagedList
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.kotlin.toFlow
|
||||
import io.realm.kotlin.where
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||
import org.matrix.android.sdk.api.query.isNormalized
|
||||
@ -42,6 +48,7 @@ import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotification
|
||||
import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.api.util.toOptional
|
||||
import org.matrix.android.sdk.internal.database.RealmSessionProvider
|
||||
import org.matrix.android.sdk.internal.database.mapper.RoomSummaryMapper
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||
@ -55,8 +62,10 @@ import javax.inject.Inject
|
||||
|
||||
internal class RoomSummaryDataSource @Inject constructor(
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
private val realmSessionProvider: RealmSessionProvider,
|
||||
private val roomSummaryMapper: RoomSummaryMapper,
|
||||
private val queryStringValueProcessor: QueryStringValueProcessor
|
||||
private val queryStringValueProcessor: QueryStringValueProcessor,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers
|
||||
) {
|
||||
|
||||
fun getRoomSummary(roomIdOrAlias: String): RoomSummary? {
|
||||
@ -219,17 +228,29 @@ internal class RoomSummaryDataSource @Inject constructor(
|
||||
return object : UpdatableLivePageResult {
|
||||
override val livePagedList: LiveData<PagedList<RoomSummary>> = mapped
|
||||
|
||||
override fun updateQuery(builder: (RoomSummaryQueryParams) -> RoomSummaryQueryParams) {
|
||||
realmDataSourceFactory.updateQuery {
|
||||
roomSummariesQuery(it, builder.invoke(queryParams)).process(sortOrder)
|
||||
}
|
||||
}
|
||||
|
||||
override val liveBoundaries: LiveData<ResultBoundaries>
|
||||
get() = boundaries
|
||||
|
||||
override var queryParams: RoomSummaryQueryParams = queryParams
|
||||
set(value) {
|
||||
field = value
|
||||
realmDataSourceFactory.updateQuery {
|
||||
roomSummariesQuery(it, value).process(sortOrder)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCountFlow(queryParams: RoomSummaryQueryParams): Flow<Int> =
|
||||
realmSessionProvider
|
||||
.withRealm { realm -> roomSummariesQuery(realm, queryParams).findAllAsync() }
|
||||
.toFlow()
|
||||
// need to create the flow on a context dispatcher with a thread with attached Looper
|
||||
.flowOn(coroutineDispatchers.main)
|
||||
.map { it.size }
|
||||
.flowOn(coroutineDispatchers.io)
|
||||
.distinctUntilChanged()
|
||||
|
||||
fun getNotificationCountForRooms(queryParams: RoomSummaryQueryParams): RoomAggregateNotificationCount {
|
||||
var notificationCount: RoomAggregateNotificationCount? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
|
@ -355,6 +355,7 @@ dependencies {
|
||||
// Lifecycle
|
||||
implementation libs.androidx.lifecycleLivedata
|
||||
implementation libs.androidx.lifecycleProcess
|
||||
implementation libs.androidx.lifecycleRuntimeKtx
|
||||
|
||||
implementation libs.androidx.datastore
|
||||
implementation libs.androidx.datastorepreferences
|
||||
|
@ -33,6 +33,7 @@ import im.vector.app.features.themes.ThemeUtils
|
||||
abstract class RoomCategoryItem : VectorEpoxyModel<RoomCategoryItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute lateinit var title: String
|
||||
@EpoxyAttribute var itemCount: Int = 0
|
||||
@EpoxyAttribute var expanded: Boolean = false
|
||||
@EpoxyAttribute var unreadNotificationCount: Int = 0
|
||||
@EpoxyAttribute var showHighlighted: Boolean = false
|
||||
@ -46,14 +47,16 @@ abstract class RoomCategoryItem : VectorEpoxyModel<RoomCategoryItem.Holder>() {
|
||||
DrawableCompat.setTint(it, tintColor)
|
||||
}
|
||||
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
|
||||
holder.titleView.setCompoundDrawablesWithIntrinsicBounds(null, null, expandedArrowDrawable, null)
|
||||
holder.titleView.text = title
|
||||
holder.counterView.text = itemCount.takeIf { it > 0 }?.toString().orEmpty()
|
||||
holder.counterView.setCompoundDrawablesWithIntrinsicBounds(null, null, expandedArrowDrawable, null)
|
||||
holder.rootView.onClick(listener)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomCategoryUnreadCounterBadgeView)
|
||||
val titleView by bind<TextView>(R.id.roomCategoryTitleView)
|
||||
val counterView by bind<TextView>(R.id.roomCategoryCounterView)
|
||||
val rootView by bind<ViewGroup>(R.id.roomCategoryRootView)
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.flowWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@ -50,8 +52,10 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA
|
||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||
import im.vector.app.features.home.room.list.widget.NotifsFabMenuView
|
||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.extensions.orTrue
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
@ -287,6 +291,7 @@ class RoomListFragment @Inject constructor(
|
||||
))
|
||||
checkEmptyState()
|
||||
}
|
||||
observeItemCount(section, sectionAdapter)
|
||||
section.notificationCount.observe(viewLifecycleOwner) { counts ->
|
||||
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(
|
||||
notificationCount = counts.totalCount,
|
||||
@ -310,6 +315,7 @@ class RoomListFragment @Inject constructor(
|
||||
))
|
||||
checkEmptyState()
|
||||
}
|
||||
observeItemCount(section, sectionAdapter)
|
||||
section.isExpanded.observe(viewLifecycleOwner) { _ ->
|
||||
refreshCollapseStates()
|
||||
}
|
||||
@ -326,6 +332,7 @@ class RoomListFragment @Inject constructor(
|
||||
isLoading = false))
|
||||
checkEmptyState()
|
||||
}
|
||||
observeItemCount(section, sectionAdapter)
|
||||
section.notificationCount.observe(viewLifecycleOwner) { counts ->
|
||||
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(
|
||||
notificationCount = counts.totalCount,
|
||||
@ -373,6 +380,18 @@ class RoomListFragment @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeItemCount(section: RoomsSection, sectionAdapter: SectionHeaderAdapter) {
|
||||
lifecycleScope.launch {
|
||||
section.itemCount
|
||||
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
|
||||
.collect { count ->
|
||||
sectionAdapter.updateSection(
|
||||
sectionAdapter.roomsSectionData.copy(itemCount = count)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) {
|
||||
when (quickAction) {
|
||||
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
||||
|
@ -28,6 +28,7 @@ import im.vector.app.features.invite.showInvites
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -72,7 +73,18 @@ class RoomListSectionBuilderGroup(
|
||||
session.getFilteredPagedRoomSummariesLive(qpm)
|
||||
.let { updatableFilterLivePageResult ->
|
||||
onUpdatable(updatableFilterLivePageResult)
|
||||
sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList))
|
||||
|
||||
val itemCountFlow = updatableFilterLivePageResult.livePagedList.asFlow()
|
||||
.flatMapLatest { session.getRoomCountFlow(updatableFilterLivePageResult.queryParams) }
|
||||
.distinctUntilChanged()
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = updatableFilterLivePageResult.livePagedList,
|
||||
itemCount = itemCountFlow
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -109,9 +121,7 @@ class RoomListSectionBuilderGroup(
|
||||
.onEach { groupingMethod ->
|
||||
val selectedGroupId = (groupingMethod.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
|
||||
activeGroupAwareQueries.onEach { updater ->
|
||||
updater.updateQuery { query ->
|
||||
query.copy(activeGroupId = selectedGroupId)
|
||||
}
|
||||
updater.queryParams = updater.queryParams.copy(activeGroupId = selectedGroupId)
|
||||
}
|
||||
}.launchIn(coroutineScope)
|
||||
|
||||
@ -265,7 +275,8 @@ class RoomListSectionBuilderGroup(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = livePagedList,
|
||||
notifyOfLocalEcho = notifyOfLocalEcho
|
||||
notifyOfLocalEcho = notifyOfLocalEcho,
|
||||
itemCount = session.getRoomCountFlow(roomQueryParams)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||
@ -91,7 +92,18 @@ class RoomListSectionBuilderSpace(
|
||||
session.getFilteredPagedRoomSummariesLive(qpm)
|
||||
.let { updatableFilterLivePageResult ->
|
||||
onUpdatable(updatableFilterLivePageResult)
|
||||
sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList))
|
||||
|
||||
val itemCountFlow = updatableFilterLivePageResult.livePagedList.asFlow()
|
||||
.flatMapLatest { session.getRoomCountFlow(updatableFilterLivePageResult.queryParams) }
|
||||
.distinctUntilChanged()
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = updatableFilterLivePageResult.livePagedList,
|
||||
itemCount = itemCountFlow
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -261,7 +273,8 @@ class RoomListSectionBuilderSpace(
|
||||
RoomsSection(
|
||||
sectionName = stringProvider.getString(R.string.suggested_header),
|
||||
liveSuggested = liveSuggestedRooms,
|
||||
notifyOfLocalEcho = false
|
||||
notifyOfLocalEcho = false,
|
||||
itemCount = suggestedRoomsFlow.map { suggestions -> suggestions.size }
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -338,11 +351,9 @@ class RoomListSectionBuilderSpace(
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> {
|
||||
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
|
||||
override fun updateForSpaceId(roomId: String?) {
|
||||
it.updateQuery {
|
||||
it.copy(
|
||||
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(roomId)
|
||||
)
|
||||
}
|
||||
it.queryParams = roomQueryParams.copy(
|
||||
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(roomId)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -350,17 +361,13 @@ class RoomListSectionBuilderSpace(
|
||||
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
|
||||
override fun updateForSpaceId(roomId: String?) {
|
||||
if (roomId != null) {
|
||||
it.updateQuery {
|
||||
it.copy(
|
||||
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(roomId)
|
||||
)
|
||||
}
|
||||
it.queryParams = roomQueryParams.copy(
|
||||
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(roomId)
|
||||
)
|
||||
} else {
|
||||
it.updateQuery {
|
||||
it.copy(
|
||||
activeSpaceFilter = ActiveSpaceFilter.None
|
||||
)
|
||||
}
|
||||
it.queryParams = roomQueryParams.copy(
|
||||
activeSpaceFilter = ActiveSpaceFilter.None
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -390,11 +397,19 @@ class RoomListSectionBuilderSpace(
|
||||
.flowOn(Dispatchers.Default)
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
val itemCountFlow = livePagedList.asFlow()
|
||||
.flatMapLatest {
|
||||
val queryParams = roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId())
|
||||
session.getRoomCountFlow(queryParams)
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = livePagedList,
|
||||
notifyOfLocalEcho = notifyOfLocalEcho
|
||||
notifyOfLocalEcho = notifyOfLocalEcho,
|
||||
itemCount = itemCountFlow
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -192,8 +192,8 @@ class RoomListViewModel @AssistedInject constructor(
|
||||
roomFilter = action.filter
|
||||
)
|
||||
}
|
||||
updatableQuery?.updateQuery {
|
||||
it.copy(
|
||||
updatableQuery?.apply {
|
||||
queryParams = queryParams.copy(
|
||||
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.NORMALIZED)
|
||||
)
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package im.vector.app.features.home.room.list
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.paging.PagedList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||
|
||||
@ -29,6 +30,7 @@ data class RoomsSection(
|
||||
val liveList: LiveData<List<RoomSummary>>? = null,
|
||||
val liveSuggested: LiveData<SuggestedRoomInfo>? = null,
|
||||
val isExpanded: MutableLiveData<Boolean> = MutableLiveData(true),
|
||||
val itemCount: Flow<Int>,
|
||||
val notificationCount: MutableLiveData<RoomAggregateNotificationCount> = MutableLiveData(RoomAggregateNotificationCount(0, 0)),
|
||||
val notifyOfLocalEcho: Boolean = false
|
||||
)
|
||||
|
@ -33,6 +33,7 @@ class SectionHeaderAdapter constructor(
|
||||
|
||||
data class RoomsSectionData(
|
||||
val name: String,
|
||||
val itemCount: Int = 0,
|
||||
val isExpanded: Boolean = true,
|
||||
val notificationCount: Int = 0,
|
||||
val isHighlighted: Boolean = false,
|
||||
@ -85,8 +86,9 @@ class SectionHeaderAdapter constructor(
|
||||
val expandedArrowDrawable = ContextCompat.getDrawable(binding.root.context, expandedArrowDrawableRes)?.also {
|
||||
DrawableCompat.setTint(it, tintColor)
|
||||
}
|
||||
binding.roomCategoryCounterView.setCompoundDrawablesWithIntrinsicBounds(null, null, expandedArrowDrawable, null)
|
||||
binding.roomCategoryCounterView.text = roomsSectionData.itemCount.takeIf { it > 0 }?.toString().orEmpty()
|
||||
binding.roomCategoryUnreadCounterBadgeView.render(UnreadCounterBadgeView.State(roomsSectionData.notificationCount, roomsSectionData.isHighlighted))
|
||||
binding.roomCategoryTitleView.setCompoundDrawablesWithIntrinsicBounds(null, null, expandedArrowDrawable, null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -94,6 +94,12 @@ class AddRoomListController @Inject constructor(
|
||||
}
|
||||
|
||||
var totalSize: Int = 0
|
||||
set(value) {
|
||||
if (value != field) {
|
||||
field = value
|
||||
requestForcedModelBuild()
|
||||
}
|
||||
}
|
||||
|
||||
var selectedItems: Map<String, Boolean> = emptyMap()
|
||||
set(value) {
|
||||
@ -120,7 +126,8 @@ class AddRoomListController @Inject constructor(
|
||||
add(
|
||||
RoomCategoryItem_().apply {
|
||||
id("header")
|
||||
title(host.sectionName ?: "")
|
||||
title(host.sectionName.orEmpty())
|
||||
itemCount(host.totalSize)
|
||||
expanded(host.expanded)
|
||||
listener {
|
||||
host.expanded = !host.expanded
|
||||
|
@ -22,6 +22,8 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.flowWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@ -35,9 +37,12 @@ import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.platform.OnBackPressed
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentSpaceAddRoomsBinding
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import reactivecircus.flowbinding.appcompat.queryTextChanges
|
||||
import javax.inject.Inject
|
||||
@ -169,48 +174,63 @@ class SpaceAddRoomFragment @Inject constructor(
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
val concatAdapter = ConcatAdapter()
|
||||
spaceEpoxyController.sectionName = getString(R.string.spaces_header)
|
||||
roomEpoxyController.sectionName = getString(R.string.rooms_header)
|
||||
spaceEpoxyController.listener = this
|
||||
roomEpoxyController.listener = this
|
||||
setupSpaceSection()
|
||||
setupRoomSection()
|
||||
setupDmSection()
|
||||
|
||||
viewModel.updatableLiveSpacePageResult.liveBoundaries.observe(viewLifecycleOwner) {
|
||||
views.roomList.adapter = ConcatAdapter().apply {
|
||||
addAdapter(roomEpoxyController.adapter)
|
||||
addAdapter(spaceEpoxyController.adapter)
|
||||
addAdapter(dmEpoxyController.adapter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupSpaceSection() {
|
||||
spaceEpoxyController.sectionName = getString(R.string.spaces_header)
|
||||
spaceEpoxyController.listener = this
|
||||
viewModel.spaceUpdatableLivePageResult.liveBoundaries.observe(viewLifecycleOwner) {
|
||||
spaceEpoxyController.boundaryChange(it)
|
||||
}
|
||||
viewModel.updatableLiveSpacePageResult.livePagedList.observe(viewLifecycleOwner) {
|
||||
spaceEpoxyController.totalSize = it.size
|
||||
viewModel.spaceUpdatableLivePageResult.livePagedList.observe(viewLifecycleOwner) {
|
||||
spaceEpoxyController.submitList(it)
|
||||
}
|
||||
listenItemCount(viewModel.spaceCountFlow) { spaceEpoxyController.totalSize = it }
|
||||
}
|
||||
|
||||
viewModel.updatableLivePageResult.liveBoundaries.observe(viewLifecycleOwner) {
|
||||
private fun setupRoomSection() {
|
||||
roomEpoxyController.sectionName = getString(R.string.rooms_header)
|
||||
roomEpoxyController.listener = this
|
||||
|
||||
viewModel.roomUpdatableLivePageResult.liveBoundaries.observe(viewLifecycleOwner) {
|
||||
roomEpoxyController.boundaryChange(it)
|
||||
}
|
||||
viewModel.updatableLivePageResult.livePagedList.observe(viewLifecycleOwner) {
|
||||
roomEpoxyController.totalSize = it.size
|
||||
viewModel.roomUpdatableLivePageResult.livePagedList.observe(viewLifecycleOwner) {
|
||||
roomEpoxyController.submitList(it)
|
||||
}
|
||||
|
||||
listenItemCount(viewModel.roomCountFlow) { roomEpoxyController.totalSize = it }
|
||||
views.roomList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
views.roomList.setHasFixedSize(true)
|
||||
}
|
||||
|
||||
concatAdapter.addAdapter(roomEpoxyController.adapter)
|
||||
concatAdapter.addAdapter(spaceEpoxyController.adapter)
|
||||
|
||||
private fun setupDmSection() {
|
||||
// This controller can be disabled depending on the space type (public or not)
|
||||
viewModel.updatableDMLivePageResult.liveBoundaries.observe(viewLifecycleOwner) {
|
||||
dmEpoxyController.boundaryChange(it)
|
||||
}
|
||||
viewModel.updatableDMLivePageResult.livePagedList.observe(viewLifecycleOwner) {
|
||||
dmEpoxyController.totalSize = it.size
|
||||
dmEpoxyController.submitList(it)
|
||||
}
|
||||
dmEpoxyController.sectionName = getString(R.string.direct_chats_header)
|
||||
dmEpoxyController.listener = this
|
||||
viewModel.dmUpdatableLivePageResult.liveBoundaries.observe(viewLifecycleOwner) {
|
||||
dmEpoxyController.boundaryChange(it)
|
||||
}
|
||||
viewModel.dmUpdatableLivePageResult.livePagedList.observe(viewLifecycleOwner) {
|
||||
dmEpoxyController.submitList(it)
|
||||
}
|
||||
listenItemCount(viewModel.dmCountFlow) { dmEpoxyController.totalSize = it }
|
||||
}
|
||||
|
||||
concatAdapter.addAdapter(dmEpoxyController.adapter)
|
||||
|
||||
views.roomList.adapter = concatAdapter
|
||||
private fun listenItemCount(itemCountFlow: Flow<Int>, onEachAction: (Int) -> Unit) {
|
||||
lifecycleScope.launch {
|
||||
itemCountFlow
|
||||
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
|
||||
.collect { count -> onEachAction(count) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed(toolbarButton: Boolean): Boolean {
|
||||
|
@ -17,7 +17,7 @@
|
||||
package im.vector.app.features.spaces.manage
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.paging.PagedList
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
@ -30,6 +30,9 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||
@ -60,7 +63,7 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
|
||||
|
||||
companion object : MavericksViewModelFactory<SpaceAddRoomsViewModel, SpaceAddRoomsState> by hiltMavericksViewModelFactory()
|
||||
|
||||
val updatableLiveSpacePageResult: UpdatableLivePageResult by lazy {
|
||||
val spaceUpdatableLivePageResult: UpdatableLivePageResult by lazy {
|
||||
session.getFilteredPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
@ -79,7 +82,13 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
val updatableLivePageResult: UpdatableLivePageResult by lazy {
|
||||
val spaceCountFlow: Flow<Int> by lazy {
|
||||
spaceUpdatableLivePageResult.livePagedList.asFlow()
|
||||
.flatMapLatest { session.getRoomCountFlow(spaceUpdatableLivePageResult.queryParams) }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
val roomUpdatableLivePageResult: UpdatableLivePageResult by lazy {
|
||||
session.getFilteredPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
@ -99,7 +108,13 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
val updatableDMLivePageResult: UpdatableLivePageResult by lazy {
|
||||
val roomCountFlow: Flow<Int> by lazy {
|
||||
roomUpdatableLivePageResult.livePagedList.asFlow()
|
||||
.flatMapLatest { session.getRoomCountFlow(roomUpdatableLivePageResult.queryParams) }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
val dmUpdatableLivePageResult: UpdatableLivePageResult by lazy {
|
||||
session.getFilteredPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
@ -119,6 +134,12 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
val dmCountFlow: Flow<Int> by lazy {
|
||||
dmUpdatableLivePageResult.livePagedList.asFlow()
|
||||
.flatMapLatest { session.getRoomCountFlow(dmUpdatableLivePageResult.queryParams) }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private val selectionList = mutableMapOf<String, Boolean>()
|
||||
val selectionListLiveData = MutableLiveData<Map<String, Boolean>>()
|
||||
|
||||
@ -143,17 +164,13 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
|
||||
|
||||
override fun handle(action: SpaceAddRoomActions) {
|
||||
when (action) {
|
||||
is SpaceAddRoomActions.UpdateFilter -> {
|
||||
updatableLivePageResult.updateQuery {
|
||||
it.copy(
|
||||
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.INSENSITIVE)
|
||||
)
|
||||
}
|
||||
updatableLiveSpacePageResult.updateQuery {
|
||||
it.copy(
|
||||
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.INSENSITIVE)
|
||||
)
|
||||
}
|
||||
is SpaceAddRoomActions.UpdateFilter -> {
|
||||
roomUpdatableLivePageResult.queryParams = roomUpdatableLivePageResult.queryParams.copy(
|
||||
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.INSENSITIVE)
|
||||
)
|
||||
roomUpdatableLivePageResult.queryParams = roomUpdatableLivePageResult.queryParams.copy(
|
||||
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.INSENSITIVE)
|
||||
)
|
||||
setState {
|
||||
copy(
|
||||
currentFilter = action.filter
|
||||
@ -164,7 +181,7 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
|
||||
selectionList[action.roomSummary.roomId] = (selectionList[action.roomSummary.roomId] ?: false).not()
|
||||
selectionListLiveData.postValue(selectionList.toMap())
|
||||
}
|
||||
SpaceAddRoomActions.Save -> {
|
||||
SpaceAddRoomActions.Save -> {
|
||||
doAddSelectedRooms()
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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/roomCategoryRootView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:colorBackground"
|
||||
android:background="?attr/vctr_header_background"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="@dimen/layout_horizontal_margin"
|
||||
android:paddingBottom="4dp">
|
||||
android:paddingHorizontal="@dimen/layout_horizontal_margin"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomCategoryTitleView"
|
||||
style="@style/Widget.Vector.TextView.Body"
|
||||
android:layout_width="wrap_content"
|
||||
style="@style/Widget.Vector.TextView.Subtitle.Medium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textColor="?vctr_content_secondary"
|
||||
android:textStyle="bold"
|
||||
app:drawableTint="?vctr_content_secondary"
|
||||
tools:drawableEnd="@drawable/ic_expand_more"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?vctr_content_primary"
|
||||
app:layout_constraintEnd_toStartOf="@id/roomCategoryCounterView"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth="wrap_content_constrained"
|
||||
tools:text="@string/room_participants_header_direct_chats" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomCategoryCounterView"
|
||||
style="@style/Widget.Vector.TextView.Subtitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:drawablePadding="2dp"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textColor="?vctr_content_secondary"
|
||||
app:drawableTint="?vctr_content_secondary"
|
||||
app:layout_constraintBottom_toBottomOf="@id/roomCategoryTitleView"
|
||||
app:layout_constraintEnd_toStartOf="@id/roomCategoryUnreadCounterBadgeView"
|
||||
app:layout_constraintStart_toEndOf="@id/roomCategoryTitleView"
|
||||
app:layout_constraintTop_toTopOf="@id/roomCategoryTitleView"
|
||||
app:layout_constraintWidth="wrap_content_constrained"
|
||||
tools:drawableEnd="@drawable/ic_expand_more"
|
||||
tools:text="14" />
|
||||
|
||||
<im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||
android:id="@+id/roomCategoryUnreadCounterBadgeView"
|
||||
style="@style/Widget.Vector.TextView.Micro"
|
||||
@ -39,10 +59,12 @@
|
||||
android:gravity="center"
|
||||
android:minWidth="16dp"
|
||||
android:minHeight="16dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingHorizontal="4dp"
|
||||
android:textColor="?colorOnError"
|
||||
app:layout_constraintBottom_toBottomOf="@id/roomCategoryTitleView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/roomCategoryTitleView"
|
||||
tools:background="@drawable/bg_unread_highlight"
|
||||
tools:text="24" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
Loading…
x
Reference in New Issue
Block a user