Using flow to show items counter

This commit is contained in:
Maxime Naturel 2022-02-07 16:10:26 +01:00
parent c7dae341c0
commit 0aaa650ac3
8 changed files with 56 additions and 47 deletions

View file

@ -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"
]
]
]

View file

@ -73,9 +73,6 @@ android {
kotlinOptions {
jvmTarget = "11"
freeCompilerArgs += [
"-Xopt-in=kotlin.RequiresOptIn"
]
}
sourceSets {

View file

@ -29,8 +29,10 @@ import io.realm.kotlin.toFlow
import io.realm.kotlin.where
import kotlinx.coroutines.Dispatchers
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
@ -63,7 +65,8 @@ 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? {
@ -237,28 +240,16 @@ internal class RoomSummaryDataSource @Inject constructor(
}
}
// @OptIn(ExperimentalCoroutinesApi::class)
// fun getCountFlow(queryParams: RoomSummaryQueryParams): Flow<Int> = callbackFlow {
// val realmResult = realmSessionProvider.withRealm { realm ->
// roomSummariesQuery(realm, queryParams).findAllAsync()
// }
// val changeListener = RealmChangeListener<RealmResults<RoomSummaryEntity>> {
// trySendBlocking(it.size)
// .onFailure { throwable -> Timber.e(throwable) }
// }
// realmResult.addChangeListener(changeListener)
// awaitClose { realmResult.removeChangeListener(changeListener) }
// }
fun getCountFlow(queryParams: RoomSummaryQueryParams): Flow<Int> =
// TODO handle properly threads and dispatchers otherwise use livedata of monarchy
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(Dispatchers.IO)
.flowOn(coroutineDispatchers.io)
.distinctUntilChanged()
// TODO should we improve how we update notification count with flow ??
fun getNotificationCountForRooms(queryParams: RoomSummaryQueryParams): RoomAggregateNotificationCount {
var notificationCount: RoomAggregateNotificationCount? = null
monarchy.doWithRealm { realm ->

View file

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

View file

@ -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,11 +291,14 @@ class RoomListFragment @Inject constructor(
))
checkEmptyState()
}
// TODO use flow if possible ?
section.itemCount.observe(viewLifecycleOwner) { count ->
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(
itemCount = count
))
lifecycleScope.launch {
section.itemCount
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.collect { count ->
sectionAdapter.updateSection(
sectionAdapter.roomsSectionData.copy(itemCount = count)
)
}
}
section.notificationCount.observe(viewLifecycleOwner) { counts ->
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(
@ -332,11 +339,14 @@ class RoomListFragment @Inject constructor(
isLoading = false))
checkEmptyState()
}
// TODO use flow instead ?
section.itemCount.observe(viewLifecycleOwner) { count ->
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(
itemCount = count
))
lifecycleScope.launch {
section.itemCount
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.collect { count ->
sectionAdapter.updateSection(
sectionAdapter.roomsSectionData.copy(itemCount = count)
)
}
}
section.notificationCount.observe(viewLifecycleOwner) { counts ->
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(

View file

@ -68,11 +68,18 @@ class RoomListSectionBuilderGroup(
it.memberships = Membership.activeMemberships()
},
{ qpm ->
// TODO find a way to show the filtered rooms count ?
val name = stringProvider.getString(R.string.bottom_action_rooms)
session.getFilteredPagedRoomSummariesLive(qpm)
.let { updatableFilterLivePageResult ->
onUpdatable(updatableFilterLivePageResult)
sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList))
sections.add(
RoomsSection(
sectionName = name,
livePages = updatableFilterLivePageResult.livePagedList,
itemCount = session.getRoomCountFlow(qpm)
)
)
}
}
)
@ -242,7 +249,6 @@ class RoomListSectionBuilderGroup(
@StringRes nameRes: Int,
notifyOfLocalEcho: Boolean = false,
query: (RoomSummaryQueryParams.Builder) -> Unit) {
// TODO check when this class is used: difference with RoomListSectionBuilderSpace ?
withQueryParams(
{ query.invoke(it) },
{ roomQueryParams ->
@ -252,7 +258,6 @@ class RoomListSectionBuilderGroup(
activeSpaceUpdaters.add(it)
}.livePagedList
.let { livePagedList ->
// TODO should we improve this ?
// use it also as a source to update count
livePagedList.asFlow()
.onEach {
@ -267,7 +272,8 @@ class RoomListSectionBuilderGroup(
RoomsSection(
sectionName = name,
livePages = livePagedList,
notifyOfLocalEcho = notifyOfLocalEcho
notifyOfLocalEcho = notifyOfLocalEcho,
itemCount = session.getRoomCountFlow(roomQueryParams)
)
)
}

View file

@ -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
@ -87,11 +88,18 @@ class RoomListSectionBuilderSpace(
it.memberships = Membership.activeMemberships()
},
{ qpm ->
// TODO find a way to show the filtered rooms count ?
val name = stringProvider.getString(R.string.bottom_action_rooms)
session.getFilteredPagedRoomSummariesLive(qpm)
.let { updatableFilterLivePageResult ->
onUpdatable(updatableFilterLivePageResult)
sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList))
sections.add(
RoomsSection(
sectionName = name,
livePages = updatableFilterLivePageResult.livePagedList,
itemCount = session.getRoomCountFlow(qpm)
)
)
}
}
)
@ -261,7 +269,8 @@ class RoomListSectionBuilderSpace(
RoomsSection(
sectionName = stringProvider.getString(R.string.suggested_header),
liveSuggested = liveSuggestedRooms,
notifyOfLocalEcho = false
notifyOfLocalEcho = false,
itemCount = suggestedRoomsFlow.map { suggestions -> suggestions.size }
)
)
}
@ -374,7 +383,6 @@ class RoomListSectionBuilderSpace(
// use it also as a source to update count
livePagedList.asFlow()
.onEach {
// TODO should we improve this ?
Timber.v("Thread space list: ${Thread.currentThread()}")
sections.find { it.sectionName == name }
?.notificationCount
@ -395,16 +403,11 @@ class RoomListSectionBuilderSpace(
RoomsSection(
sectionName = name,
livePages = livePagedList,
notifyOfLocalEcho = notifyOfLocalEcho
notifyOfLocalEcho = notifyOfLocalEcho,
itemCount = session.getRoomCountFlow(roomQueryParams)
)
)
}
// TODO extract into a dedicated private method
session.getRoomCountFlow(roomQueryParams)
.onEach { count -> sections.find { section -> section.sectionName == name }?.itemCount?.postValue(count) }
.flowOn(Dispatchers.Default)
.launchIn(viewModelScope)
}
)

View file

@ -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
@ -30,8 +31,7 @@ data class RoomsSection(
val liveList: LiveData<List<RoomSummary>>? = null,
val liveSuggested: LiveData<SuggestedRoomInfo>? = null,
val isExpanded: MutableLiveData<Boolean> = MutableLiveData(true),
// TODO expose a Flow<Int> instead ?
val itemCount: MutableLiveData<Int> = MutableLiveData(0),
val itemCount: Flow<Int>,
val notificationCount: MutableLiveData<RoomAggregateNotificationCount> = MutableLiveData(RoomAggregateNotificationCount(0, 0)),
val notifyOfLocalEcho: Boolean = false
)