From 597081e9a8fad521b454eb4a256b16c7b60f736e Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:22:08 +0100 Subject: [PATCH 01/14] Adding unread counter badge view --- .../res/layout/fragment_new_home_detail.xml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/vector/src/main/res/layout/fragment_new_home_detail.xml b/vector/src/main/res/layout/fragment_new_home_detail.xml index ced71a7863..8f603e57ab 100644 --- a/vector/src/main/res/layout/fragment_new_home_detail.xml +++ b/vector/src/main/res/layout/fragment_new_home_detail.xml @@ -120,6 +120,28 @@ tools:targetApi="lollipop_mr1" tools:visibility="visible" /> + + Date: Tue, 21 Feb 2023 16:28:30 +0100 Subject: [PATCH 02/14] Use case to compute the notification counter for spaces --- .../app/features/spaces/SpaceListViewModel.kt | 37 ++-------- .../GetNotificationCountForSpacesUseCase.kt | 70 +++++++++++++++++++ 2 files changed, 74 insertions(+), 33 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt index 99f6a254b8..e5ebce0c11 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt @@ -32,13 +32,11 @@ import im.vector.app.features.analytics.plan.Interaction import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences -import kotlinx.coroutines.Dispatchers +import im.vector.app.features.spaces.notification.GetNotificationCountForSpacesUseCase import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.query.QueryStringValue @@ -48,12 +46,9 @@ import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getUserOrDefault -import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes import org.matrix.android.sdk.api.session.room.model.Membership -import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams -import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount import org.matrix.android.sdk.api.session.space.SpaceOrderUtils import org.matrix.android.sdk.api.session.space.model.SpaceOrderContent import org.matrix.android.sdk.api.session.space.model.TopLevelSpaceComparator @@ -67,6 +62,7 @@ class SpaceListViewModel @AssistedInject constructor( private val vectorPreferences: VectorPreferences, private val autoAcceptInvites: AutoAcceptInvites, private val analyticsTracker: AnalyticsTracker, + private val getNotificationCountForSpacesUseCase: GetNotificationCountForSpacesUseCase, ) : VectorViewModel(initialState) { @AssistedFactory @@ -92,39 +88,14 @@ class SpaceListViewModel @AssistedInject constructor( copy(selectedSpace = selectedSpaceOption.orNull()) } - // XXX there should be a way to refactor this and share it - session.roomService().getPagedRoomSummariesLive( - roomSummaryQueryParams { - this.memberships = listOf(Membership.JOIN) - this.spaceFilter = roomsInSpaceFilter() - }, sortOrder = RoomSortOrder.NONE - ).asFlow() - .sample(300) - .onEach { - val inviteCount = if (autoAcceptInvites.hideInvites) { - 0 - } else { - session.roomService().getRoomSummaries( - roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) } - ).size - } - val totalCount = session.roomService().getNotificationCountForRooms( - roomSummaryQueryParams { - this.memberships = listOf(Membership.JOIN) - this.spaceFilter = roomsInSpaceFilter() - } - ) - val counts = RoomAggregateNotificationCount( - totalCount.notificationCount + inviteCount, - totalCount.highlightCount + inviteCount - ) + getNotificationCountForSpacesUseCase.execute(roomsInSpaceFilter()) + .onEach { counts -> setState { copy( homeAggregateCount = counts ) } } - .flowOn(Dispatchers.Default) .launchIn(viewModelScope) } diff --git a/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt b/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt new file mode 100644 index 0000000000..5f79619c92 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 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.notification + +import androidx.lifecycle.asFlow +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.features.invite.AutoAcceptInvites +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.sample +import org.matrix.android.sdk.api.query.SpaceFilter +import org.matrix.android.sdk.api.session.room.RoomSortOrder +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams +import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount +import javax.inject.Inject + +// TODO add unit tests +class GetNotificationCountForSpacesUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, + private val autoAcceptInvites: AutoAcceptInvites, +) { + + fun execute(spaceFilter: SpaceFilter): Flow { + val session = activeSessionHolder.getSafeActiveSession() + + val spaceQueryParams = roomSummaryQueryParams { + this.memberships = listOf(Membership.JOIN) + this.spaceFilter = spaceFilter + } + return session + ?.roomService() + ?.getPagedRoomSummariesLive(queryParams = spaceQueryParams, sortOrder = RoomSortOrder.NONE) + ?.asFlow() + ?.sample(300) + ?.mapLatest { + val inviteCount = if (autoAcceptInvites.hideInvites) { + 0 + } else { + session.roomService().getRoomSummaries( + roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) } + ).size + } + val totalCount = session.roomService().getNotificationCountForRooms(spaceQueryParams) + RoomAggregateNotificationCount( + notificationCount = totalCount.notificationCount + inviteCount, + highlightCount = totalCount.highlightCount + inviteCount, + ) + } + ?.flowOn(Dispatchers.Default) + ?: emptyFlow() + } +} From 0e8a2254f8a7e8dbd2ed5d8430773962d736351d Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Tue, 21 Feb 2023 17:44:31 +0100 Subject: [PATCH 03/14] Listen for spaces notification count to refresh the badge --- .../app/core/di/MavericksViewModelModule.kt | 6 ++ .../features/home/NewHomeDetailFragment.kt | 15 +++++ .../features/home/NewHomeDetailViewModel.kt | 60 +++++++++++++++++++ .../features/home/NewHomeDetailViewState.kt | 24 ++++++++ 4 files changed, 105 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index 35d8d0e896..27981c3d36 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -40,6 +40,7 @@ import im.vector.app.features.discovery.DiscoverySettingsViewModel import im.vector.app.features.discovery.change.SetIdentityServerViewModel import im.vector.app.features.home.HomeActivityViewModel import im.vector.app.features.home.HomeDetailViewModel +import im.vector.app.features.home.NewHomeDetailViewModel import im.vector.app.features.home.UnknownDeviceDetectorSharedViewModel import im.vector.app.features.home.UnreadMessagesSharedViewModel import im.vector.app.features.home.UserColorAccountDataViewModel @@ -717,4 +718,9 @@ interface MavericksViewModelModule { @IntoMap @MavericksViewModelKey(RoomPollDetailViewModel::class) fun roomPollDetailViewModelFactory(factory: RoomPollDetailViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + + @Binds + @IntoMap + @MavericksViewModelKey(NewHomeDetailViewModel::class) + fun newHomeDetailViewModelFactory(factory: NewHomeDetailViewModel.Factory): MavericksAssistedViewModelFactory<*, *> } diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index 3189c2b99e..ff995311e6 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -47,6 +47,7 @@ import im.vector.app.features.call.SharedKnownCallsViewModel import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.dialpad.PstnDialActivity import im.vector.app.features.call.webrtc.WebRtcCallManager +import im.vector.app.features.home.room.list.UnreadCounterBadgeView import im.vector.app.features.home.room.list.actions.RoomListSharedAction import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel import im.vector.app.features.home.room.list.home.HomeRoomListFragment @@ -63,6 +64,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount import javax.inject.Inject @AndroidEntryPoint @@ -82,6 +84,7 @@ class NewHomeDetailFragment : @Inject lateinit var buildMeta: BuildMeta private val viewModel: HomeDetailViewModel by fragmentViewModel() + private val newHomeDetailViewModel: NewHomeDetailViewModel by fragmentViewModel() private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel() private val serverBackupStatusViewModel: ServerBackupStatusViewModel by activityViewModel() @@ -180,6 +183,10 @@ class NewHomeDetailFragment : currentCallsViewPresenter.updateCall(callManager.getCurrentCall(), callManager.getCalls()) invalidateOptionsMenu() } + + newHomeDetailViewModel.onEach { viewState -> + refreshUnreadCounterBadge(viewState.spacesNotificationCount) + } } private fun setupObservers() { @@ -379,6 +386,14 @@ class NewHomeDetailFragment : } } + private fun refreshUnreadCounterBadge(roomAggregateNotificationCount: RoomAggregateNotificationCount) { + val badgeState = UnreadCounterBadgeView.State.Count( + count = roomAggregateNotificationCount.notificationCount, + highlighted = roomAggregateNotificationCount.isHighlight, + ) + views.spacesUnreadCounterBadge.render(badgeState) + } + override fun onTapToReturnToCall() { callManager.getCurrentCall()?.let { call -> VectorCallActivity.newIntent( diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt new file mode 100644 index 0000000000..6f3ba79cf8 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 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.home + +import com.airbnb.mvrx.MavericksViewModelFactory +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.platform.EmptyAction +import im.vector.app.core.platform.EmptyViewEvents +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.roomprofile.polls.RoomPollsViewModel +import im.vector.app.features.roomprofile.polls.RoomPollsViewState +import im.vector.app.features.spaces.notification.GetNotificationCountForSpacesUseCase +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import org.matrix.android.sdk.api.query.SpaceFilter + +class NewHomeDetailViewModel @AssistedInject constructor( + @Assisted initialState: NewHomeDetailViewState, + private val getNotificationCountForSpacesUseCase: GetNotificationCountForSpacesUseCase, +) : VectorViewModel(initialState) { + + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: NewHomeDetailViewState): NewHomeDetailViewModel + } + + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + + init { + observeSpacesNotificationCount() + } + + private fun observeSpacesNotificationCount() { + getNotificationCountForSpacesUseCase.execute(SpaceFilter.NoFilter) + .onEach { setState { copy(spacesNotificationCount = it) } } + .launchIn(viewModelScope) + } + + override fun handle(action: EmptyAction) { + // do nothing + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt new file mode 100644 index 0000000000..20ad9be4b4 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 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.home + +import com.airbnb.mvrx.MavericksState +import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount + +data class NewHomeDetailViewState( + val spacesNotificationCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(notificationCount = 0, highlightCount = 0), +) : MavericksState From c36869cd03c14d00dfc8c025ee63606193545c33 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Tue, 21 Feb 2023 17:57:23 +0100 Subject: [PATCH 04/14] Adding knowledge of pending space invites --- .../features/home/NewHomeDetailFragment.kt | 22 ++++++++++++++----- .../features/home/NewHomeDetailViewState.kt | 1 + 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index ff995311e6..51a217c526 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -185,7 +185,7 @@ class NewHomeDetailFragment : } newHomeDetailViewModel.onEach { viewState -> - refreshUnreadCounterBadge(viewState.spacesNotificationCount) + refreshUnreadCounterBadge(viewState.spacesNotificationCount, viewState.hasPendingSpaceInvites) } } @@ -386,11 +386,21 @@ class NewHomeDetailFragment : } } - private fun refreshUnreadCounterBadge(roomAggregateNotificationCount: RoomAggregateNotificationCount) { - val badgeState = UnreadCounterBadgeView.State.Count( - count = roomAggregateNotificationCount.notificationCount, - highlighted = roomAggregateNotificationCount.isHighlight, - ) + private fun refreshUnreadCounterBadge( + spacesNotificationCount: RoomAggregateNotificationCount, + hasPendingSpaceInvites: Boolean, + ) { + val badgeState = if (hasPendingSpaceInvites && spacesNotificationCount.notificationCount == 0) { + UnreadCounterBadgeView.State.Text( + text = "!", + highlighted = true, + ) + } else { + UnreadCounterBadgeView.State.Count( + count = spacesNotificationCount.notificationCount, + highlighted = spacesNotificationCount.isHighlight, + ) + } views.spacesUnreadCounterBadge.render(badgeState) } diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt index 20ad9be4b4..1ff0b86511 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt @@ -21,4 +21,5 @@ import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotification data class NewHomeDetailViewState( val spacesNotificationCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(notificationCount = 0, highlightCount = 0), + val hasPendingSpaceInvites: Boolean = false, ) : MavericksState From c74cdb9540cbf34b711dde2313ea1e043b174a18 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 22 Feb 2023 10:44:55 +0100 Subject: [PATCH 05/14] Observe the spaces invites --- .../features/home/NewHomeDetailViewModel.kt | 19 +++++++++- .../app/features/spaces/GetSpacesUseCase.kt | 37 +++++++++++++++++++ .../app/features/spaces/SpaceListViewModel.kt | 8 ++-- 3 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/spaces/GetSpacesUseCase.kt diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt index 6f3ba79cf8..7f68accd90 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt @@ -25,16 +25,20 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.roomprofile.polls.RoomPollsViewModel -import im.vector.app.features.roomprofile.polls.RoomPollsViewState +import im.vector.app.features.spaces.GetSpacesUseCase import im.vector.app.features.spaces.notification.GetNotificationCountForSpacesUseCase import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.SpaceFilter +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams +// TODO add unit tests class NewHomeDetailViewModel @AssistedInject constructor( @Assisted initialState: NewHomeDetailViewState, private val getNotificationCountForSpacesUseCase: GetNotificationCountForSpacesUseCase, + private val getSpacesUseCase: GetSpacesUseCase, ) : VectorViewModel(initialState) { @AssistedFactory @@ -46,6 +50,7 @@ class NewHomeDetailViewModel @AssistedInject constructor( init { observeSpacesNotificationCount() + observeSpacesInvite() } private fun observeSpacesNotificationCount() { @@ -54,6 +59,16 @@ class NewHomeDetailViewModel @AssistedInject constructor( .launchIn(viewModelScope) } + private fun observeSpacesInvite() { + val params = spaceSummaryQueryParams { + memberships = listOf(Membership.INVITE) + displayName = QueryStringValue.IsNotEmpty + } + getSpacesUseCase.execute(params) + .onEach { setState { copy(hasPendingSpaceInvites = it.isNotEmpty()) } } + .launchIn(viewModelScope) + } + override fun handle(action: EmptyAction) { // do nothing } diff --git a/vector/src/main/java/im/vector/app/features/spaces/GetSpacesUseCase.kt b/vector/src/main/java/im/vector/app/features/spaces/GetSpacesUseCase.kt new file mode 100644 index 0000000000..d3f462f9f9 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/GetSpacesUseCase.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 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 + +import im.vector.app.core.di.ActiveSessionHolder +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams +import org.matrix.android.sdk.flow.flow +import javax.inject.Inject + +// TODO add unit tests +class GetSpacesUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, +) { + + fun execute(params: SpaceSummaryQueryParams): Flow> { + val session = activeSessionHolder.getSafeActiveSession() + + return session?.flow()?.liveSpaceSummaries(params) ?: emptyFlow() + } +} diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt index e5ebce0c11..b2776e5f87 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt @@ -29,7 +29,6 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.plan.Interaction -import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.spaces.notification.GetNotificationCountForSpacesUseCase @@ -53,16 +52,15 @@ import org.matrix.android.sdk.api.session.space.SpaceOrderUtils import org.matrix.android.sdk.api.session.space.model.SpaceOrderContent import org.matrix.android.sdk.api.session.space.model.TopLevelSpaceComparator import org.matrix.android.sdk.api.util.toMatrixItem -import org.matrix.android.sdk.flow.flow class SpaceListViewModel @AssistedInject constructor( @Assisted initialState: SpaceListViewState, private val spaceStateHandler: SpaceStateHandler, private val session: Session, private val vectorPreferences: VectorPreferences, - private val autoAcceptInvites: AutoAcceptInvites, private val analyticsTracker: AnalyticsTracker, - private val getNotificationCountForSpacesUseCase: GetNotificationCountForSpacesUseCase, + getNotificationCountForSpacesUseCase: GetNotificationCountForSpacesUseCase, + private val getSpacesUseCase: GetSpacesUseCase, ) : VectorViewModel(initialState) { @AssistedFactory @@ -238,7 +236,7 @@ class SpaceListViewModel @AssistedInject constructor( } combine( - session.flow().liveSpaceSummaries(params), + getSpacesUseCase.execute(params), session.accountDataService() .getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)) .asFlow() From a509da54e80014b385f5b8840c4964774947d4ad Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 22 Feb 2023 11:58:26 +0100 Subject: [PATCH 06/14] Adding unit tests for GetSpacesUseCase --- .../app/features/spaces/GetSpacesUseCase.kt | 1 - .../features/spaces/GetSpacesUseCaseTest.kt | 104 ++++++++++++++++++ .../im/vector/app/test/fakes/FakeSession.kt | 2 + .../vector/app/test/fakes/FakeSpaceService.kt | 37 +++++++ 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 vector/src/test/java/im/vector/app/features/spaces/GetSpacesUseCaseTest.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeSpaceService.kt diff --git a/vector/src/main/java/im/vector/app/features/spaces/GetSpacesUseCase.kt b/vector/src/main/java/im/vector/app/features/spaces/GetSpacesUseCase.kt index d3f462f9f9..048e4b01bd 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/GetSpacesUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/GetSpacesUseCase.kt @@ -24,7 +24,6 @@ import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams import org.matrix.android.sdk.flow.flow import javax.inject.Inject -// TODO add unit tests class GetSpacesUseCase @Inject constructor( private val activeSessionHolder: ActiveSessionHolder, ) { diff --git a/vector/src/test/java/im/vector/app/features/spaces/GetSpacesUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/spaces/GetSpacesUseCaseTest.kt new file mode 100644 index 0000000000..2e8d50ff3f --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/spaces/GetSpacesUseCaseTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023 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 + +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeFlowLiveDataConversions +import im.vector.app.test.fakes.givenAsFlow +import im.vector.app.test.test +import io.mockk.mockk +import io.mockk.unmockkAll +import io.mockk.verify +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams + +internal class GetSpacesUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions() + + private val getSpacesUseCase = GetSpacesUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance, + ) + + @Before + fun setUp() { + fakeFlowLiveDataConversions.setup() + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given params when execute then the list of summaries is returned`() = runTest { + // Given + val queryParams = givenSpaceQueryParams() + val firstSummaries = listOf(mockk()) + val nextSummaries = listOf(mockk()) + fakeActiveSessionHolder.fakeSession + .fakeSpaceService + .givenGetSpaceSummariesReturns(firstSummaries) + fakeActiveSessionHolder.fakeSession + .fakeSpaceService + .givenGetSpaceSummariesLiveReturns(nextSummaries) + .givenAsFlow() + + // When + val testObserver = getSpacesUseCase.execute(queryParams).test(this) + advanceUntilIdle() + + // Then + testObserver + .assertValues(firstSummaries, nextSummaries) + .finish() + verify { + fakeActiveSessionHolder.fakeSession.fakeSpaceService.getSpaceSummaries(queryParams) + fakeActiveSessionHolder.fakeSession.fakeSpaceService.getSpaceSummariesLive(queryParams) + } + } + + @Test + fun `given no active session when execute then empty flow is returned`() = runTest { + // Given + fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null) + val queryParams = givenSpaceQueryParams() + + // When + val testObserver = getSpacesUseCase.execute(queryParams).test(this) + advanceUntilIdle() + + // Then + testObserver + .assertNoValues() + .finish() + verify(inverse = true) { + fakeActiveSessionHolder.fakeSession.fakeSpaceService.getSpaceSummaries(queryParams) + fakeActiveSessionHolder.fakeSession.fakeSpaceService.getSpaceSummariesLive(queryParams) + } + } + + private fun givenSpaceQueryParams(): SpaceSummaryQueryParams { + return mockk() + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt index 1b6d3e2729..ada23c159e 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt @@ -46,6 +46,7 @@ class FakeSession( val fakeUserService: FakeUserService = FakeUserService(), private val fakeEventService: FakeEventService = FakeEventService(), val fakeSessionAccountDataService: FakeSessionAccountDataService = FakeSessionAccountDataService(), + val fakeSpaceService: FakeSpaceService = FakeSpaceService(), ) : Session by mockk(relaxed = true) { init { @@ -66,6 +67,7 @@ class FakeSession( override fun pushersService() = fakePushersService override fun accountDataService() = fakeSessionAccountDataService override fun userService() = fakeUserService + override fun spaceService() = fakeSpaceService fun givenVectorStore(vectorSessionStore: VectorSessionStore) { coEvery { diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSpaceService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSpaceService.kt new file mode 100644 index 0000000000..59c7d5524d --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSpaceService.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 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.test.fakes + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import io.mockk.every +import io.mockk.mockk +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.space.SpaceService + +class FakeSpaceService : SpaceService by mockk() { + + fun givenGetSpaceSummariesLiveReturns(roomSummaries: List): LiveData> { + return MutableLiveData(roomSummaries).also { + every { getSpaceSummariesLive(any()) } returns it + } + } + + fun givenGetSpaceSummariesReturns(roomSummaries: List) { + every { getSpaceSummaries(any()) } returns roomSummaries + } +} From e8c95551c1d69e30f6b760fa45ae3317be6bf462 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 22 Feb 2023 14:19:21 +0100 Subject: [PATCH 07/14] Adding unit tests for GetNotificationCountForSpacesUseCase --- .../GetNotificationCountForSpacesUseCase.kt | 3 +- ...etNotificationCountForSpacesUseCaseTest.kt | 174 ++++++++++++++++++ .../app/test/fakes/FakeAutoAcceptInvites.kt | 4 + .../test/fakes/FakeFlowLiveDataConversions.kt | 7 +- .../vector/app/test/fakes/FakeRoomService.kt | 18 ++ 5 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 vector/src/test/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCaseTest.kt diff --git a/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt b/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt index 5f79619c92..031015757d 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt @@ -32,7 +32,6 @@ import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount import javax.inject.Inject -// TODO add unit tests class GetNotificationCountForSpacesUseCase @Inject constructor( private val activeSessionHolder: ActiveSessionHolder, private val autoAcceptInvites: AutoAcceptInvites, @@ -64,7 +63,7 @@ class GetNotificationCountForSpacesUseCase @Inject constructor( highlightCount = totalCount.highlightCount + inviteCount, ) } - ?.flowOn(Dispatchers.Default) + ?.flowOn(session.coroutineDispatchers.main) ?: emptyFlow() } } diff --git a/vector/src/test/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCaseTest.kt new file mode 100644 index 0000000000..2813b9d79f --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCaseTest.kt @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2023 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.notification + +import androidx.paging.PagedList +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeAutoAcceptInvites +import im.vector.app.test.fakes.FakeFlowLiveDataConversions +import im.vector.app.test.fakes.givenAsFlow +import im.vector.app.test.test +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import io.mockk.verify +import kotlinx.coroutines.flow.sample +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.matrix.android.sdk.api.query.SpaceFilter +import org.matrix.android.sdk.api.session.room.RoomSortOrder +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount + +internal class GetNotificationCountForSpacesUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeAutoAcceptInvites = FakeAutoAcceptInvites() + private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions() + + private val getNotificationCountForSpacesUseCase = GetNotificationCountForSpacesUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance, + autoAcceptInvites = fakeAutoAcceptInvites, + ) + + @Before + fun setUp() { + fakeFlowLiveDataConversions.setup() + mockkStatic("kotlinx.coroutines.flow.FlowKt") + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given space filter and hide invites when execute then correct notification count is returned`() = runTest { + // given + val spaceFilter = SpaceFilter.NoFilter + val pagedList = mockk>() + val pagedListFlow = fakeActiveSessionHolder.fakeSession + .fakeRoomService + .givenGetPagedRoomSummariesLiveReturns(pagedList) + .givenAsFlow() + every { pagedListFlow.sample(any()) } returns pagedListFlow + val expectedNotificationCount = RoomAggregateNotificationCount( + notificationCount = 1, + highlightCount = 0, + ) + fakeActiveSessionHolder.fakeSession + .fakeRoomService + .givenGetNotificationCountForRoomsReturns(expectedNotificationCount) + fakeAutoAcceptInvites._hideInvites = true + + // When + val testObserver = getNotificationCountForSpacesUseCase.execute(spaceFilter).test(this) + advanceUntilIdle() + + // Then + testObserver + .assertValues(expectedNotificationCount) + .finish() + verify { + fakeActiveSessionHolder.fakeSession.fakeRoomService.getNotificationCountForRooms( + queryParams = match { it.memberships == listOf(Membership.JOIN) && it.spaceFilter == spaceFilter } + ) + fakeActiveSessionHolder.fakeSession.fakeRoomService.getPagedRoomSummariesLive( + queryParams = match { it.memberships == listOf(Membership.JOIN) && it.spaceFilter == spaceFilter }, + pagedListConfig = any(), + sortOrder = RoomSortOrder.NONE, + ) + } + } + + @Test + fun `given space filter and show invites when execute then correct notification count is returned`() = runTest { + // given + val spaceFilter = SpaceFilter.NoFilter + val pagedList = mockk>() + val pagedListFlow = fakeActiveSessionHolder.fakeSession + .fakeRoomService + .givenGetPagedRoomSummariesLiveReturns(pagedList) + .givenAsFlow() + every { pagedListFlow.sample(any()) } returns pagedListFlow + val notificationCount = RoomAggregateNotificationCount( + notificationCount = 1, + highlightCount = 0, + ) + fakeActiveSessionHolder.fakeSession + .fakeRoomService + .givenGetNotificationCountForRoomsReturns(notificationCount) + val invitedRooms = listOf(mockk()) + fakeActiveSessionHolder.fakeSession + .fakeRoomService + .givenGetRoomSummaries(invitedRooms) + fakeAutoAcceptInvites._hideInvites = false + val expectedNotificationCount = RoomAggregateNotificationCount( + notificationCount = notificationCount.notificationCount + invitedRooms.size, + highlightCount = notificationCount.highlightCount + invitedRooms.size, + ) + + // When + val testObserver = getNotificationCountForSpacesUseCase.execute(spaceFilter).test(this) + advanceUntilIdle() + + // Then + testObserver + .assertValues(expectedNotificationCount) + .finish() + verify { + fakeActiveSessionHolder.fakeSession.fakeRoomService.getRoomSummaries( + queryParams = match { it.memberships == listOf(Membership.INVITE) } + ) + fakeActiveSessionHolder.fakeSession.fakeRoomService.getNotificationCountForRooms( + queryParams = match { it.memberships == listOf(Membership.JOIN) && it.spaceFilter == spaceFilter } + ) + fakeActiveSessionHolder.fakeSession.fakeRoomService.getPagedRoomSummariesLive( + queryParams = match { it.memberships == listOf(Membership.JOIN) && it.spaceFilter == spaceFilter }, + pagedListConfig = any(), + sortOrder = RoomSortOrder.NONE, + ) + } + } + + @Test + fun `given no active session when execute then empty flow is returned`() = runTest { + // given + val spaceFilter = SpaceFilter.NoFilter + fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null) + + // When + val testObserver = getNotificationCountForSpacesUseCase.execute(spaceFilter).test(this) + + // Then + testObserver + .assertNoValues() + .finish() + verify(inverse = true) { + fakeActiveSessionHolder.fakeSession.fakeRoomService.getPagedRoomSummariesLive( + queryParams = any(), + pagedListConfig = any(), + sortOrder = any(), + ) + } + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt index 778c2f113d..d1160cedfd 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt @@ -21,7 +21,11 @@ import im.vector.app.features.invite.AutoAcceptInvites class FakeAutoAcceptInvites : AutoAcceptInvites { var _isEnabled: Boolean = false + var _hideInvites: Boolean = false override val isEnabled: Boolean get() = _isEnabled + + override val hideInvites: Boolean + get() = _hideInvites } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeFlowLiveDataConversions.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeFlowLiveDataConversions.kt index 956a86f32e..cdbe828521 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeFlowLiveDataConversions.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeFlowLiveDataConversions.kt @@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.asFlow import io.mockk.every import io.mockk.mockkStatic +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf class FakeFlowLiveDataConversions { @@ -28,6 +29,8 @@ class FakeFlowLiveDataConversions { } } -fun LiveData.givenAsFlow() { - every { asFlow() } returns flowOf(value!!) +fun LiveData.givenAsFlow(): Flow { + return flowOf(value!!).also { + every { asFlow() } returns it + } } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeRoomService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeRoomService.kt index e957266383..63209222b2 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeRoomService.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeRoomService.kt @@ -16,10 +16,14 @@ package im.vector.app.test.fakes +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.paging.PagedList import io.mockk.every import io.mockk.mockk import org.matrix.android.sdk.api.session.room.RoomService import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount class FakeRoomService( private val fakeRoom: FakeRoom = FakeRoom() @@ -34,4 +38,18 @@ class FakeRoomService( fun set(roomSummary: RoomSummary?) { every { getRoomSummary(any()) } returns roomSummary } + + fun givenGetPagedRoomSummariesLiveReturns(pagedList: PagedList): LiveData> { + return MutableLiveData(pagedList).also { + every { getPagedRoomSummariesLive(queryParams = any(), pagedListConfig = any(), sortOrder = any()) } returns it + } + } + + fun givenGetNotificationCountForRoomsReturns(roomAggregateNotificationCount: RoomAggregateNotificationCount) { + every { getNotificationCountForRooms(queryParams = any()) } returns roomAggregateNotificationCount + } + + fun givenGetRoomSummaries(roomSummaries: List) { + every { getRoomSummaries(any()) } returns roomSummaries + } } From b78da9824d7d3a9218b4b33e8ee56c47e09fbfa4 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 22 Feb 2023 14:38:35 +0100 Subject: [PATCH 08/14] Adding unit tests for NewHomeDetailViewModel --- .../features/home/NewHomeDetailViewModel.kt | 1 - .../home/NewHomeDetailViewModelTest.kt | 80 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt index 7f68accd90..b26d010137 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt @@ -34,7 +34,6 @@ import org.matrix.android.sdk.api.query.SpaceFilter import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams -// TODO add unit tests class NewHomeDetailViewModel @AssistedInject constructor( @Assisted initialState: NewHomeDetailViewState, private val getNotificationCountForSpacesUseCase: GetNotificationCountForSpacesUseCase, diff --git a/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt b/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt new file mode 100644 index 0000000000..23882bf7c4 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023 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.home + +import com.airbnb.mvrx.test.MavericksTestRule +import im.vector.app.features.spaces.GetSpacesUseCase +import im.vector.app.features.spaces.notification.GetNotificationCountForSpacesUseCase +import im.vector.app.test.test +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import org.junit.Rule +import org.junit.Test +import org.matrix.android.sdk.api.query.SpaceFilter +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount + +internal class NewHomeDetailViewModelTest { + + @get:Rule + val mavericksTestRule = MavericksTestRule(testDispatcher = UnconfinedTestDispatcher()) + + private val initialState = NewHomeDetailViewState() + private val fakeGetNotificationCountForSpacesUseCase = mockk() + private val fakeGetSpacesUseCase = mockk() + + private fun createViewModel(): NewHomeDetailViewModel { + return NewHomeDetailViewModel( + initialState = initialState, + getNotificationCountForSpacesUseCase = fakeGetNotificationCountForSpacesUseCase, + getSpacesUseCase = fakeGetSpacesUseCase, + ) + } + + @Test + fun `given the viewModel is created then viewState is updated with space notifications count and pending space invites`() { + // Given + val spacesNotificationCount = RoomAggregateNotificationCount( + notificationCount = 1, + highlightCount = 1, + ) + every { fakeGetNotificationCountForSpacesUseCase.execute(any()) } returns flowOf(spacesNotificationCount) + val spaceInvites = listOf(mockk()) + every { fakeGetSpacesUseCase.execute(any()) } returns flowOf(spaceInvites) + val expectedViewState = initialState.copy( + spacesNotificationCount = spacesNotificationCount, + hasPendingSpaceInvites = true, + ) + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + + // Then + viewModelTest + .assertLatestState(expectedViewState) + .finish() + verify { + fakeGetNotificationCountForSpacesUseCase.execute(SpaceFilter.NoFilter) + fakeGetSpacesUseCase.execute(match { it.memberships == listOf(Membership.INVITE) }) + } + } +} From 18c7f0d894e1d5867e4eee7092c118e0526189e9 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 22 Feb 2023 14:39:44 +0100 Subject: [PATCH 09/14] Remove unused import --- .../spaces/notification/GetNotificationCountForSpacesUseCase.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt b/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt index 031015757d..08d63e2653 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCase.kt @@ -19,7 +19,6 @@ package im.vector.app.features.spaces.notification import androidx.lifecycle.asFlow import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.features.invite.AutoAcceptInvites -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flowOn From 1b0265662dc4bffe7eae381f58e7392705b440c5 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 22 Feb 2023 14:50:01 +0100 Subject: [PATCH 10/14] Adding changelog entry --- changelog.d/8157.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/8157.feature diff --git a/changelog.d/8157.feature b/changelog.d/8157.feature new file mode 100644 index 0000000000..3cab2b600b --- /dev/null +++ b/changelog.d/8157.feature @@ -0,0 +1 @@ +Add aggregated unread indicator for spaces in the new layout From af4ab418510bd9b8cd35ae2f92382b91d2d536de Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:04:14 +0100 Subject: [PATCH 11/14] Highlight the badge when there is pending space invite --- .../java/im/vector/app/features/home/NewHomeDetailFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index 51a217c526..a13487afc8 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -398,7 +398,7 @@ class NewHomeDetailFragment : } else { UnreadCounterBadgeView.State.Count( count = spacesNotificationCount.notificationCount, - highlighted = spacesNotificationCount.isHighlight, + highlighted = spacesNotificationCount.isHighlight || hasPendingSpaceInvites, ) } views.spacesUnreadCounterBadge.render(badgeState) From f782a315929b46db9bac0de3b19b23bfb7c986c6 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Thu, 23 Feb 2023 10:15:34 +0100 Subject: [PATCH 12/14] Fix unit tests --- .../GetNotificationCountForSpacesUseCaseTest.kt | 6 +++--- .../java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/vector/src/test/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCaseTest.kt index 2813b9d79f..8d4bdb1b30 100644 --- a/vector/src/test/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/spaces/notification/GetNotificationCountForSpacesUseCaseTest.kt @@ -62,7 +62,7 @@ internal class GetNotificationCountForSpacesUseCaseTest { } @Test - fun `given space filter and hide invites when execute then correct notification count is returned`() = runTest { + fun `given space filter and auto accept invites when execute then correct notification count is returned`() = runTest { // given val spaceFilter = SpaceFilter.NoFilter val pagedList = mockk>() @@ -78,7 +78,7 @@ internal class GetNotificationCountForSpacesUseCaseTest { fakeActiveSessionHolder.fakeSession .fakeRoomService .givenGetNotificationCountForRoomsReturns(expectedNotificationCount) - fakeAutoAcceptInvites._hideInvites = true + fakeAutoAcceptInvites._isEnabled = true // When val testObserver = getNotificationCountForSpacesUseCase.execute(spaceFilter).test(this) @@ -121,7 +121,7 @@ internal class GetNotificationCountForSpacesUseCaseTest { fakeActiveSessionHolder.fakeSession .fakeRoomService .givenGetRoomSummaries(invitedRooms) - fakeAutoAcceptInvites._hideInvites = false + fakeAutoAcceptInvites._isEnabled = false val expectedNotificationCount = RoomAggregateNotificationCount( notificationCount = notificationCount.notificationCount + invitedRooms.size, highlightCount = notificationCount.highlightCount + invitedRooms.size, diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt index d1160cedfd..778c2f113d 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt @@ -21,11 +21,7 @@ import im.vector.app.features.invite.AutoAcceptInvites class FakeAutoAcceptInvites : AutoAcceptInvites { var _isEnabled: Boolean = false - var _hideInvites: Boolean = false override val isEnabled: Boolean get() = _isEnabled - - override val hideInvites: Boolean - get() = _hideInvites } From 2bd0126523cca2b15ce7d89a9e18fd5888fdf6bc Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Thu, 23 Feb 2023 13:59:32 +0100 Subject: [PATCH 13/14] Extracting logic to compute the badge state into a usecase --- .../GetSpacesNotificationBadgeStateUseCase.kt | 67 ++++++++++++++ .../features/home/NewHomeDetailFragment.kt | 19 +--- .../features/home/NewHomeDetailViewModel.kt | 28 ++---- .../features/home/NewHomeDetailViewState.kt | 5 +- ...SpacesNotificationBadgeStateUseCaseTest.kt | 88 +++++++++++++++++++ .../home/NewHomeDetailViewModelTest.kt | 33 +++---- 6 files changed, 174 insertions(+), 66 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/home/GetSpacesNotificationBadgeStateUseCase.kt create mode 100644 vector/src/test/java/im/vector/app/features/home/GetSpacesNotificationBadgeStateUseCaseTest.kt diff --git a/vector/src/main/java/im/vector/app/features/home/GetSpacesNotificationBadgeStateUseCase.kt b/vector/src/main/java/im/vector/app/features/home/GetSpacesNotificationBadgeStateUseCase.kt new file mode 100644 index 0000000000..62d1501dab --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/GetSpacesNotificationBadgeStateUseCase.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 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.home + +import im.vector.app.features.home.room.list.UnreadCounterBadgeView +import im.vector.app.features.spaces.GetSpacesUseCase +import im.vector.app.features.spaces.notification.GetNotificationCountForSpacesUseCase +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.query.SpaceFilter +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams +import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount +import javax.inject.Inject + +class GetSpacesNotificationBadgeStateUseCase @Inject constructor( + private val getNotificationCountForSpacesUseCase: GetNotificationCountForSpacesUseCase, + private val getSpacesUseCase: GetSpacesUseCase, +) { + + fun execute(): Flow { + val params = spaceSummaryQueryParams { + memberships = listOf(Membership.INVITE) + displayName = QueryStringValue.IsNotEmpty + } + return combine( + getNotificationCountForSpacesUseCase.execute(SpaceFilter.NoFilter), + getSpacesUseCase.execute(params), + ) { spacesNotificationCount, spaceInvites -> + computeSpacesNotificationCounterBadgeState(spacesNotificationCount, spaceInvites) + } + } + + private fun computeSpacesNotificationCounterBadgeState( + spacesNotificationCount: RoomAggregateNotificationCount, + spaceInvites: List, + ): UnreadCounterBadgeView.State { + val hasPendingSpaceInvites = spaceInvites.isNotEmpty() + return if (hasPendingSpaceInvites && spacesNotificationCount.notificationCount == 0) { + UnreadCounterBadgeView.State.Text( + text = "!", + highlighted = true, + ) + } else { + UnreadCounterBadgeView.State.Count( + count = spacesNotificationCount.notificationCount, + highlighted = spacesNotificationCount.isHighlight || hasPendingSpaceInvites, + ) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index a13487afc8..ef855ff15b 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -64,7 +64,6 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo import org.matrix.android.sdk.api.session.room.model.RoomSummary -import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount import javax.inject.Inject @AndroidEntryPoint @@ -185,7 +184,7 @@ class NewHomeDetailFragment : } newHomeDetailViewModel.onEach { viewState -> - refreshUnreadCounterBadge(viewState.spacesNotificationCount, viewState.hasPendingSpaceInvites) + refreshUnreadCounterBadge(viewState.spacesNotificationCounterBadgeState) } } @@ -386,21 +385,7 @@ class NewHomeDetailFragment : } } - private fun refreshUnreadCounterBadge( - spacesNotificationCount: RoomAggregateNotificationCount, - hasPendingSpaceInvites: Boolean, - ) { - val badgeState = if (hasPendingSpaceInvites && spacesNotificationCount.notificationCount == 0) { - UnreadCounterBadgeView.State.Text( - text = "!", - highlighted = true, - ) - } else { - UnreadCounterBadgeView.State.Count( - count = spacesNotificationCount.notificationCount, - highlighted = spacesNotificationCount.isHighlight || hasPendingSpaceInvites, - ) - } + private fun refreshUnreadCounterBadge(badgeState: UnreadCounterBadgeView.State) { views.spacesUnreadCounterBadge.render(badgeState) } diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt index b26d010137..67b4645944 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewModel.kt @@ -25,19 +25,12 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.spaces.GetSpacesUseCase -import im.vector.app.features.spaces.notification.GetNotificationCountForSpacesUseCase import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import org.matrix.android.sdk.api.query.QueryStringValue -import org.matrix.android.sdk.api.query.SpaceFilter -import org.matrix.android.sdk.api.session.room.model.Membership -import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams class NewHomeDetailViewModel @AssistedInject constructor( @Assisted initialState: NewHomeDetailViewState, - private val getNotificationCountForSpacesUseCase: GetNotificationCountForSpacesUseCase, - private val getSpacesUseCase: GetSpacesUseCase, + private val getSpacesNotificationBadgeStateUseCase: GetSpacesNotificationBadgeStateUseCase, ) : VectorViewModel(initialState) { @AssistedFactory @@ -48,23 +41,12 @@ class NewHomeDetailViewModel @AssistedInject constructor( companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() init { - observeSpacesNotificationCount() - observeSpacesInvite() + observeSpacesNotificationBadgeState() } - private fun observeSpacesNotificationCount() { - getNotificationCountForSpacesUseCase.execute(SpaceFilter.NoFilter) - .onEach { setState { copy(spacesNotificationCount = it) } } - .launchIn(viewModelScope) - } - - private fun observeSpacesInvite() { - val params = spaceSummaryQueryParams { - memberships = listOf(Membership.INVITE) - displayName = QueryStringValue.IsNotEmpty - } - getSpacesUseCase.execute(params) - .onEach { setState { copy(hasPendingSpaceInvites = it.isNotEmpty()) } } + private fun observeSpacesNotificationBadgeState() { + getSpacesNotificationBadgeStateUseCase.execute() + .onEach { badgeState -> setState { copy(spacesNotificationCounterBadgeState = badgeState) } } .launchIn(viewModelScope) } diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt index 1ff0b86511..7e368fb2d1 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailViewState.kt @@ -17,9 +17,8 @@ package im.vector.app.features.home import com.airbnb.mvrx.MavericksState -import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount +import im.vector.app.features.home.room.list.UnreadCounterBadgeView data class NewHomeDetailViewState( - val spacesNotificationCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(notificationCount = 0, highlightCount = 0), - val hasPendingSpaceInvites: Boolean = false, + val spacesNotificationCounterBadgeState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State.Count(count = 0, highlighted = false), ) : MavericksState diff --git a/vector/src/test/java/im/vector/app/features/home/GetSpacesNotificationBadgeStateUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/home/GetSpacesNotificationBadgeStateUseCaseTest.kt new file mode 100644 index 0000000000..4d7d0d98f4 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/home/GetSpacesNotificationBadgeStateUseCaseTest.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023 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.home + +import im.vector.app.features.home.room.list.UnreadCounterBadgeView +import im.vector.app.features.spaces.GetSpacesUseCase +import im.vector.app.features.spaces.notification.GetNotificationCountForSpacesUseCase +import im.vector.app.test.test +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.query.SpaceFilter +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount + +internal class GetSpacesNotificationBadgeStateUseCaseTest { + + private val fakeGetNotificationCountForSpacesUseCase = mockk() + private val fakeGetSpacesUseCase = mockk() + + private val getSpacesNotificationBadgeStateUseCase = GetSpacesNotificationBadgeStateUseCase( + getNotificationCountForSpacesUseCase = fakeGetNotificationCountForSpacesUseCase, + getSpacesUseCase = fakeGetSpacesUseCase, + ) + + @Test + fun `given flow of spaces invite and notification count then flow of state is correct`() = runTest { + // Given + val noSpacesInvite = emptyList() + val existingSpaceInvite = listOf(mockk()) + val noNotification = RoomAggregateNotificationCount( + notificationCount = 0, + highlightCount = 0, + ) + val existingNotificationNotHighlighted = RoomAggregateNotificationCount( + notificationCount = 1, + highlightCount = 0, + ) + val existingNotificationHighlighted = RoomAggregateNotificationCount( + notificationCount = 1, + highlightCount = 1, + ) + every { fakeGetSpacesUseCase.execute(any()) } returns + flowOf(noSpacesInvite, existingSpaceInvite, existingSpaceInvite, noSpacesInvite, noSpacesInvite) + every { fakeGetNotificationCountForSpacesUseCase.execute(any()) } returns + flowOf(noNotification, noNotification, existingNotificationNotHighlighted, existingNotificationNotHighlighted, existingNotificationHighlighted) + + // When + val testObserver = getSpacesNotificationBadgeStateUseCase.execute().test(this) + advanceUntilIdle() + + // Then + val expectedState1 = UnreadCounterBadgeView.State.Count(count = 0, highlighted = false) + val expectedState2 = UnreadCounterBadgeView.State.Text(text = "!", highlighted = true) + val expectedState3 = UnreadCounterBadgeView.State.Count(count = 1, highlighted = true) + val expectedState4 = UnreadCounterBadgeView.State.Count(count = 1, highlighted = false) + val expectedState5 = UnreadCounterBadgeView.State.Count(count = 1, highlighted = true) + testObserver + .assertValues(expectedState1, expectedState2, expectedState3, expectedState4, expectedState5) + .finish() + verify { + fakeGetSpacesUseCase.execute(match { + it.memberships == listOf(Membership.INVITE) && it.displayName == QueryStringValue.IsNotEmpty + }) + } + verify { fakeGetNotificationCountForSpacesUseCase.execute(SpaceFilter.NoFilter) } + } +} diff --git a/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt b/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt index 23882bf7c4..a92c4be0d7 100644 --- a/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt @@ -17,8 +17,8 @@ package im.vector.app.features.home import com.airbnb.mvrx.test.MavericksTestRule +import im.vector.app.features.home.room.list.UnreadCounterBadgeView import im.vector.app.features.spaces.GetSpacesUseCase -import im.vector.app.features.spaces.notification.GetNotificationCountForSpacesUseCase import im.vector.app.test.test import io.mockk.every import io.mockk.mockk @@ -27,10 +27,6 @@ import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.UnconfinedTestDispatcher import org.junit.Rule import org.junit.Test -import org.matrix.android.sdk.api.query.SpaceFilter -import org.matrix.android.sdk.api.session.room.model.Membership -import org.matrix.android.sdk.api.session.room.model.RoomSummary -import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount internal class NewHomeDetailViewModelTest { @@ -38,43 +34,34 @@ internal class NewHomeDetailViewModelTest { val mavericksTestRule = MavericksTestRule(testDispatcher = UnconfinedTestDispatcher()) private val initialState = NewHomeDetailViewState() - private val fakeGetNotificationCountForSpacesUseCase = mockk() - private val fakeGetSpacesUseCase = mockk() + private val fakeGetSpacesNotificationBadgeStateUseCase = mockk() private fun createViewModel(): NewHomeDetailViewModel { return NewHomeDetailViewModel( initialState = initialState, - getNotificationCountForSpacesUseCase = fakeGetNotificationCountForSpacesUseCase, - getSpacesUseCase = fakeGetSpacesUseCase, + getSpacesNotificationBadgeStateUseCase = fakeGetSpacesNotificationBadgeStateUseCase, ) } @Test - fun `given the viewModel is created then viewState is updated with space notifications count and pending space invites`() { + fun `given the viewModel is created then viewState is updated with space notifications badge state`() { // Given - val spacesNotificationCount = RoomAggregateNotificationCount( - notificationCount = 1, - highlightCount = 1, - ) - every { fakeGetNotificationCountForSpacesUseCase.execute(any()) } returns flowOf(spacesNotificationCount) - val spaceInvites = listOf(mockk()) - every { fakeGetSpacesUseCase.execute(any()) } returns flowOf(spaceInvites) - val expectedViewState = initialState.copy( - spacesNotificationCount = spacesNotificationCount, - hasPendingSpaceInvites = true, - ) + val aBadgeState = UnreadCounterBadgeView.State.Count(count = 1, highlighted = false) + every { fakeGetSpacesNotificationBadgeStateUseCase.execute() } returns flowOf(aBadgeState) // When val viewModel = createViewModel() val viewModelTest = viewModel.test() // Then + val expectedViewState = initialState.copy( + spacesNotificationCounterBadgeState = aBadgeState, + ) viewModelTest .assertLatestState(expectedViewState) .finish() verify { - fakeGetNotificationCountForSpacesUseCase.execute(SpaceFilter.NoFilter) - fakeGetSpacesUseCase.execute(match { it.memberships == listOf(Membership.INVITE) }) + fakeGetSpacesNotificationBadgeStateUseCase.execute() } } } From 53d03335abcf92853c636535a5e4bbc2d915f5f0 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Thu, 23 Feb 2023 14:18:21 +0100 Subject: [PATCH 14/14] Remove unused import --- .../im/vector/app/features/home/NewHomeDetailViewModelTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt b/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt index a92c4be0d7..39adc0a811 100644 --- a/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/home/NewHomeDetailViewModelTest.kt @@ -18,7 +18,6 @@ package im.vector.app.features.home import com.airbnb.mvrx.test.MavericksTestRule import im.vector.app.features.home.room.list.UnreadCounterBadgeView -import im.vector.app.features.spaces.GetSpacesUseCase import im.vector.app.test.test import io.mockk.every import io.mockk.mockk