diff --git a/dependencies.gradle b/dependencies.gradle index 87b8e3c12f..1f2a08b6a6 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -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" ] -] \ No newline at end of file +] diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 8a66d188fd..2b2c38e22a 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -73,9 +73,6 @@ android { kotlinOptions { jvmTarget = "11" - freeCompilerArgs += [ - "-Xopt-in=kotlin.RequiresOptIn" - ] } sourceSets { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt index cabef69e2e..eecbb0ecfe 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt @@ -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 = callbackFlow { -// val realmResult = realmSessionProvider.withRealm { realm -> -// roomSummariesQuery(realm, queryParams).findAllAsync() -// } -// val changeListener = RealmChangeListener> { -// trySendBlocking(it.size) -// .onFailure { throwable -> Timber.e(throwable) } -// } -// realmResult.addChangeListener(changeListener) -// awaitClose { realmResult.removeChangeListener(changeListener) } -// } - fun getCountFlow(queryParams: RoomSummaryQueryParams): Flow = - // 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 -> diff --git a/vector/build.gradle b/vector/build.gradle index 2b37c12323..2d9c097da8 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -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 diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index d6b529e1ca..4e7e679ad5 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -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( diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt index b90283e86e..84d1450a5e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt @@ -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) ) ) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt index b4c6240688..383dacdefb 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt @@ -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) } ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomsSection.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomsSection.kt index b8d03a30b0..be00f3f61b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomsSection.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomsSection.kt @@ -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>? = null, val liveSuggested: LiveData? = null, val isExpanded: MutableLiveData = MutableLiveData(true), - // TODO expose a Flow instead ? - val itemCount: MutableLiveData = MutableLiveData(0), + val itemCount: Flow, val notificationCount: MutableLiveData = MutableLiveData(RoomAggregateNotificationCount(0, 0)), val notifyOfLocalEcho: Boolean = false )