From 5ac590a8e046dd8ca781c4f90c96ab854c91c8f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Feb 2023 23:01:53 +0000 Subject: [PATCH 01/32] Bump androidx.work:work-runtime-ktx from 2.7.1 to 2.8.0 Bumps androidx.work:work-runtime-ktx from 2.7.1 to 2.8.0. --- updated-dependencies: - dependency-name: androidx.work:work-runtime-ktx dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index a87fd3f868..dbe647e384 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -59,7 +59,7 @@ ext.libs = [ 'fragmentTesting' : "androidx.fragment:fragment-testing:$fragment", 'fragmentTestingManifest' : "androidx.fragment:fragment-testing-manifest:$fragment", 'constraintLayout' : "androidx.constraintlayout:constraintlayout:2.1.4", - 'work' : "androidx.work:work-runtime-ktx:2.7.1", + 'work' : "androidx.work:work-runtime-ktx:2.8.0", 'autoFill' : "androidx.autofill:autofill:1.1.0", 'preferenceKtx' : "androidx.preference:preference-ktx:1.2.0", 'junit' : "androidx.test.ext:junit:1.1.5", From 35b7860ec240d424935a962553c34aa41116f78b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Feb 2023 23:03:07 +0000 Subject: [PATCH 02/32] Bump androidx.browser:browser from 1.4.0 to 1.5.0 Bumps androidx.browser:browser from 1.4.0 to 1.5.0. --- updated-dependencies: - dependency-name: androidx.browser:browser dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- vector/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/build.gradle b/vector/build.gradle index 5a9037288e..8d5a132e4e 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -199,7 +199,7 @@ dependencies { implementation 'com.github.hyuwah:DraggableView:1.0.0' // Custom Tab - implementation 'androidx.browser:browser:1.4.0' + implementation 'androidx.browser:browser:1.5.0' // Passphrase strength helper implementation 'com.nulab-inc:zxcvbn:1.7.0' From 9cd3a9e13d60c8b65e717e0fae8fcfb38a9871d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 23:57:06 +0000 Subject: [PATCH 03/32] Bump io.element.android:wysiwyg from 1.0.0 to 1.1.1 Bumps [io.element.android:wysiwyg](https://github.com/matrix-org/matrix-wysiwyg) from 1.0.0 to 1.1.1. - [Release notes](https://github.com/matrix-org/matrix-wysiwyg/releases) - [Changelog](https://github.com/matrix-org/matrix-rich-text-editor/blob/main/CHANGELOG.md) - [Commits](https://github.com/matrix-org/matrix-wysiwyg/compare/1.0.0...1.1.1) --- updated-dependencies: - dependency-name: io.element.android:wysiwyg dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 72172fc61e..72fd140f71 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -103,7 +103,7 @@ ext.libs = [ ], element : [ 'opusencoder' : "io.element.android:opusencoder:1.1.0", - 'wysiwyg' : "io.element.android:wysiwyg:1.0.0" + 'wysiwyg' : "io.element.android:wysiwyg:1.1.1" ], squareup : [ 'moshi' : "com.squareup.moshi:moshi:$moshi", 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 04/32] 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 05/32] 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 06/32] 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 07/32] 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 13c8ff4ff5c6194c70dc024e677f4c0122a29a31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Feb 2023 07:45:40 +0000 Subject: [PATCH 08/32] Bump com.google.firebase:firebase-bom from 31.2.1 to 31.2.2 Bumps com.google.firebase:firebase-bom from 31.2.1 to 31.2.2. --- updated-dependencies: - dependency-name: com.google.firebase:firebase-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 7120789e10..aef478a733 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -11,7 +11,7 @@ def gradle = "7.4.1" def kotlin = "1.8.10" def kotlinCoroutines = "1.6.4" def dagger = "2.45" -def firebaseBom = "31.2.1" +def firebaseBom = "31.2.2" def appDistribution = "16.0.0-beta05" def retrofit = "2.9.0" def markwon = "4.6.2" 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 09/32] 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 10/32] 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 11/32] 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 12/32] 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 13/32] 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 14/32] 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 15/32] 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 f8449f956723ddd50d447628bac9a4f4f84622f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Feb 2023 23:16:01 +0000 Subject: [PATCH 16/32] Bump androidx.arch.core:core-testing from 2.1.0 to 2.2.0 Bumps androidx.arch.core:core-testing from 2.1.0 to 2.2.0. --- updated-dependencies: - dependency-name: androidx.arch.core:core-testing dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 7120789e10..3021c8560d 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -70,7 +70,7 @@ ext.libs = [ 'datastore' : "androidx.datastore:datastore:1.0.0", 'datastorepreferences' : "androidx.datastore:datastore-preferences:1.0.0", 'pagingRuntimeKtx' : "androidx.paging:paging-runtime-ktx:2.1.2", - 'coreTesting' : "androidx.arch.core:core-testing:2.1.0", + 'coreTesting' : "androidx.arch.core:core-testing:2.2.0", 'testCore' : "androidx.test:core:$androidxTest", 'orchestrator' : "androidx.test:orchestrator:$androidxOrchestrator", 'testRunner' : "androidx.test:runner:$androidxTest", 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 17/32] 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 18/32] 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 19/32] 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 From 8192bb5442898f1d65007f558698922471f12dbc Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Thu, 23 Feb 2023 19:44:03 +0100 Subject: [PATCH 20/32] matrix-sdk: Ensure correct room for events loaded by chunks Chunks should not load events from other rooms if they happen to be requested for one eventId that already exists in a different room. Motivation from a client that renders rich replies (although the broken scenario can appear in other cases as well): If somebody links an invalid eventId in a room, which however is valid in a different room, this can mess up our timelines badly. This can be reproduced by replying to an event in a room, then forward the reply to a different room with a client that also forwards the replied-to information (such as FluffyChat). Then click on the rich reply to open the eventId. Previously, Android could find the event from the other room and thus replace the correct timeline with the wrong one. Compare e.g. https://matrix.to/#/!bfebJVBOZMnORmkVdO:matrix.org/$wUyRiMQEjaWOpJ-XpdBJzuXkh95N7bce2pVT4IMXW50?via=schildi.chat&via=matrix.org&via=envs.net linking to an event that exists here https://matrix.to/#/!SDwMepdfgrmExhyxYZ:schildi.chat/$MO2G4MZZ1zg0Ymc9gTfekIyw7QFkNn4OvYQKK1PAGlE Change-Id: I4dcee94353d954fb6ed57c3970686a620b831c6f --- changelog.d/8168.bugfix | 1 + .../sdk/internal/database/helper/ThreadEventsHelper.kt | 2 +- .../sdk/internal/database/query/ChunkEntityQueries.kt | 7 ++++--- .../android/sdk/internal/database/query/ReadQueries.kt | 6 +++--- .../session/room/timeline/FetchTokenAndPaginateTask.kt | 2 +- .../internal/session/room/timeline/LoadTimelineStrategy.kt | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 changelog.d/8168.bugfix diff --git a/changelog.d/8168.bugfix b/changelog.d/8168.bugfix new file mode 100644 index 0000000000..39baa3f60a --- /dev/null +++ b/changelog.d/8168.bugfix @@ -0,0 +1 @@ +Fix timeline loading a wrong room on permalink if a matching event id is found in a different room diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt index 7999a2ea14..a100741452 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt @@ -297,7 +297,7 @@ internal fun updateThreadNotifications(roomId: String, realm: Realm, currentUser val readReceipt = findMyReadReceipt(realm, roomId, currentUserId, threadId = rootThreadEventId) ?: return val readReceiptChunk = ChunkEntity - .findIncludingEvent(realm, readReceipt) ?: return + .findIncludingEvent(realm, roomId, readReceipt) ?: return val readReceiptChunkThreadEvents = readReceiptChunk .timelineEvents diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt index 1e5d96b496..08c8bcf86e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt @@ -72,15 +72,16 @@ internal fun ChunkEntity.Companion.findEventInThreadChunk(realm: Realm, roomId: .findFirst() } -internal fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List): RealmResults { +internal fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, roomId: String, eventIds: List): RealmResults { return realm.where() + .equalTo(ChunkEntityFields.ROOM.ROOM_ID, roomId) .`in`(ChunkEntityFields.TIMELINE_EVENTS.EVENT_ID, eventIds.toTypedArray()) .isNull(ChunkEntityFields.ROOT_THREAD_EVENT_ID) .findAll() } -internal fun ChunkEntity.Companion.findIncludingEvent(realm: Realm, eventId: String): ChunkEntity? { - return findAllIncludingEvents(realm, listOf(eventId)).firstOrNull() +internal fun ChunkEntity.Companion.findIncludingEvent(realm: Realm, roomId: String, eventId: String): ChunkEntity? { + return findAllIncludingEvents(realm, roomId, listOf(eventId)).firstOrNull() } internal fun ChunkEntity.Companion.create( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt index ebfe23105e..0cc4abcb3d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt @@ -76,11 +76,11 @@ private fun hasReadMissingEvent(realm: Realm, userId: String, eventId: String, threadId: String? = ReadService.THREAD_ID_MAIN): Boolean { - return realm.doesEventExistInChunkHistory(eventId) && realm.hasReadReceiptInLatestChunk(latestChunkEntity, roomId, userId, threadId) + return realm.doesEventExistInChunkHistory(roomId, eventId) && realm.hasReadReceiptInLatestChunk(latestChunkEntity, roomId, userId, threadId) } -private fun Realm.doesEventExistInChunkHistory(eventId: String): Boolean { - return ChunkEntity.findIncludingEvent(this, eventId) != null +private fun Realm.doesEventExistInChunkHistory(roomId: String, eventId: String): Boolean { + return ChunkEntity.findIncludingEvent(this, roomId, eventId) != null } private fun Realm.hasReadReceiptInLatestChunk(latestChunkEntity: ChunkEntity, roomId: String, userId: String, threadId: String?): Boolean { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/FetchTokenAndPaginateTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/FetchTokenAndPaginateTask.kt index 9d8d8ecbf1..b73dd8160b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/FetchTokenAndPaginateTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/FetchTokenAndPaginateTask.kt @@ -59,7 +59,7 @@ internal class DefaultFetchTokenAndPaginateTask @Inject constructor( ?: throw IllegalStateException("No token found") monarchy.awaitTransaction { realm -> - val chunkToUpdate = ChunkEntity.findIncludingEvent(realm, params.lastKnownEventId) + val chunkToUpdate = ChunkEntity.findIncludingEvent(realm, params.roomId, params.lastKnownEventId) if (params.direction == PaginationDirection.FORWARDS) { chunkToUpdate?.nextToken = fromToken } else { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt index 6654eeadfc..2143ac1d21 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt @@ -278,7 +278,7 @@ internal class LoadTimelineStrategy constructor( .findAll() } is Mode.Permalink -> { - ChunkEntity.findAllIncludingEvents(realm, listOf(mode.originEventId)) + ChunkEntity.findAllIncludingEvents(realm, roomId, listOf(mode.originEventId)) } is Mode.Thread -> { recreateThreadChunkEntity(realm, mode.rootThreadEventId) From 370d58e876aede5d9d3c3b60eea7b27a52f43aa5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 23:58:00 +0000 Subject: [PATCH 21/32] Bump glide from 4.14.2 to 4.15.0 Bumps `glide` from 4.14.2 to 4.15.0. Updates `com.github.bumptech.glide:glide` from 4.14.2 to 4.15.0 - [Release notes](https://github.com/bumptech/glide/releases) - [Commits](https://github.com/bumptech/glide/compare/v4.14.2...v4.15.0) Updates `com.github.bumptech.glide:compiler` from 4.14.2 to 4.15.0 - [Release notes](https://github.com/bumptech/glide/releases) - [Commits](https://github.com/bumptech/glide/compare/v4.14.2...v4.15.0) --- updated-dependencies: - dependency-name: com.github.bumptech.glide:glide dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.github.bumptech.glide:compiler dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 67bb90eb43..a32d067792 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -21,7 +21,7 @@ def flowBinding = "1.2.0" def flipper = "0.182.0" def epoxy = "5.0.0" def mavericks = "3.0.1" -def glide = "4.14.2" +def glide = "4.15.0" def bigImageViewer = "1.8.1" def jjwt = "0.11.5" // Temporary version to unblock #6929. Once 0.16.0 is released we should use it, and revert From a30e4a9d86e0266eea14584f728575b8d31afec4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 23:58:26 +0000 Subject: [PATCH 22/32] Bump androidx.transition:transition from 1.2.0 to 1.4.1 Bumps androidx.transition:transition from 1.2.0 to 1.4.1. --- updated-dependencies: - dependency-name: androidx.transition:transition dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 67bb90eb43..f29927de8b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -79,7 +79,7 @@ ext.libs = [ 'espressoContrib' : "androidx.test.espresso:espresso-contrib:$espresso", 'espressoIntents' : "androidx.test.espresso:espresso-intents:$espresso", 'viewpager2' : "androidx.viewpager2:viewpager2:1.0.0", - 'transition' : "androidx.transition:transition:1.2.0", + 'transition' : "androidx.transition:transition:1.4.1", ], google : [ 'material' : "com.google.android.material:material:1.8.0", From 62ee6c8033bd6e708f03e86afc85b5c3d5bad2bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 23:59:47 +0000 Subject: [PATCH 23/32] Bump com.googlecode.libphonenumber:libphonenumber from 8.13.6 to 8.13.7 Bumps [com.googlecode.libphonenumber:libphonenumber](https://github.com/google/libphonenumber) from 8.13.6 to 8.13.7. - [Release notes](https://github.com/google/libphonenumber/releases) - [Changelog](https://github.com/google/libphonenumber/blob/master/making-metadata-changes.md) - [Commits](https://github.com/google/libphonenumber/compare/v8.13.6...v8.13.7) --- updated-dependencies: - dependency-name: com.googlecode.libphonenumber:libphonenumber dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 67bb90eb43..1f3009da57 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -88,7 +88,7 @@ ext.libs = [ 'appdistributionApi' : "com.google.firebase:firebase-appdistribution-api-ktx:$appDistribution", 'appdistribution' : "com.google.firebase:firebase-appdistribution:$appDistribution", // Phone number https://github.com/google/libphonenumber - 'phonenumber' : "com.googlecode.libphonenumber:libphonenumber:8.13.6" + 'phonenumber' : "com.googlecode.libphonenumber:libphonenumber:8.13.7" ], dagger : [ 'dagger' : "com.google.dagger:dagger:$dagger", From 39d9591b26964f8ee9881a727136e9c486684b9e Mon Sep 17 00:00:00 2001 From: jonnyandrew Date: Mon, 27 Feb 2023 09:24:56 +0000 Subject: [PATCH 24/32] [Rich text editor] Fix code appearance (#8171) Code does not use the correct theme colour when the theme is manually selected in the app settings. https://github.com/vector-im/verticals-internal/issues/23 --- changelog.d/8171.bugfix | 1 + .../src/main/res/drawable/bg_code_block.xml | 22 ++++++++++++++++++ .../bg_inline_code_multi_line_left.xml | 23 +++++++++++++++++++ .../bg_inline_code_multi_line_mid.xml | 21 +++++++++++++++++ .../bg_inline_code_multi_line_right.xml | 23 +++++++++++++++++++ .../drawable/bg_inline_code_single_line.xml | 22 ++++++++++++++++++ .../res/layout/composer_rich_text_layout.xml | 5 ++++ ..._timeline_event_text_message_rich_stub.xml | 6 +++++ 8 files changed, 123 insertions(+) create mode 100644 changelog.d/8171.bugfix create mode 100644 vector/src/main/res/drawable/bg_code_block.xml create mode 100644 vector/src/main/res/drawable/bg_inline_code_multi_line_left.xml create mode 100644 vector/src/main/res/drawable/bg_inline_code_multi_line_mid.xml create mode 100644 vector/src/main/res/drawable/bg_inline_code_multi_line_right.xml create mode 100644 vector/src/main/res/drawable/bg_inline_code_single_line.xml diff --git a/changelog.d/8171.bugfix b/changelog.d/8171.bugfix new file mode 100644 index 0000000000..799fecabaf --- /dev/null +++ b/changelog.d/8171.bugfix @@ -0,0 +1 @@ +[Rich text editor] Fix code appearance \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_code_block.xml b/vector/src/main/res/drawable/bg_code_block.xml new file mode 100644 index 0000000000..c492ce02c2 --- /dev/null +++ b/vector/src/main/res/drawable/bg_code_block.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/vector/src/main/res/drawable/bg_inline_code_multi_line_left.xml b/vector/src/main/res/drawable/bg_inline_code_multi_line_left.xml new file mode 100644 index 0000000000..fa5b052562 --- /dev/null +++ b/vector/src/main/res/drawable/bg_inline_code_multi_line_left.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/vector/src/main/res/drawable/bg_inline_code_multi_line_mid.xml b/vector/src/main/res/drawable/bg_inline_code_multi_line_mid.xml new file mode 100644 index 0000000000..0f55cbbbbb --- /dev/null +++ b/vector/src/main/res/drawable/bg_inline_code_multi_line_mid.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/vector/src/main/res/drawable/bg_inline_code_multi_line_right.xml b/vector/src/main/res/drawable/bg_inline_code_multi_line_right.xml new file mode 100644 index 0000000000..0f0d004869 --- /dev/null +++ b/vector/src/main/res/drawable/bg_inline_code_multi_line_right.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/vector/src/main/res/drawable/bg_inline_code_single_line.xml b/vector/src/main/res/drawable/bg_inline_code_single_line.xml new file mode 100644 index 0000000000..e70625152a --- /dev/null +++ b/vector/src/main/res/drawable/bg_inline_code_single_line.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/vector/src/main/res/layout/composer_rich_text_layout.xml b/vector/src/main/res/layout/composer_rich_text_layout.xml index 8992b632c0..f5ad5c51db 100644 --- a/vector/src/main/res/layout/composer_rich_text_layout.xml +++ b/vector/src/main/res/layout/composer_rich_text_layout.xml @@ -126,6 +126,11 @@ app:layout_constraintTop_toBottomOf="@id/composerModeBarrier" app:bulletRadius="4sp" app:bulletGap="8sp" + app:codeBlockBackgroundDrawable="@drawable/bg_code_block" + app:inlineCodeSingleLineBg="@drawable/bg_inline_code_single_line" + app:inlineCodeMultiLineBgLeft="@drawable/bg_inline_code_multi_line_left" + app:inlineCodeMultiLineBgMid="@drawable/bg_inline_code_multi_line_mid" + app:inlineCodeMultiLineBgRight="@drawable/bg_inline_code_multi_line_right" tools:text="@tools:sample/lorem/random" /> From 67d25dfcd8ebe8d613337609dbdaadcd910b9625 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 00:01:45 +0000 Subject: [PATCH 25/32] Bump org.json:json from 20220924 to 20230227 Bumps [org.json:json](https://github.com/douglascrockford/JSON-java) from 20220924 to 20230227. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- library/external/jsonviewer/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/external/jsonviewer/build.gradle b/library/external/jsonviewer/build.gradle index a5d297b860..7b3b62c082 100644 --- a/library/external/jsonviewer/build.gradle +++ b/library/external/jsonviewer/build.gradle @@ -65,7 +65,7 @@ dependencies { implementation libs.jetbrains.coroutinesCore implementation libs.jetbrains.coroutinesAndroid - testImplementation 'org.json:json:20220924' + testImplementation 'org.json:json:20230227' testImplementation libs.tests.junit androidTestImplementation libs.androidx.junit androidTestImplementation libs.androidx.espressoCore From 69f8715d0319081037d49b2d2ae40ea40a7054e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 09:34:53 +0000 Subject: [PATCH 26/32] Bump org.owasp:dependency-check-gradle from 8.1.0 to 8.1.1 (#8184) Bumps org.owasp:dependency-check-gradle from 8.1.0 to 8.1.1. --- updated-dependencies: - dependency-name: org.owasp:dependency-check-gradle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ecd1cd557b..63430431bc 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ buildscript { classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.5.0.2730' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6' classpath "com.likethesalad.android:stem-plugin:2.3.0" - classpath 'org.owasp:dependency-check-gradle:8.1.0' + classpath 'org.owasp:dependency-check-gradle:8.1.1' classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.20" classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0" classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3' From 8e14579886c5c800936624d622d74065dd67fcba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 09:35:39 +0000 Subject: [PATCH 27/32] Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin Bumps org.sonarsource.scanner.gradle:sonarqube-gradle-plugin from 3.5.0.2730 to 4.0.0.2929. --- updated-dependencies: - dependency-name: org.sonarsource.scanner.gradle:sonarqube-gradle-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 63430431bc..9b6136e94f 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ buildscript { classpath libs.gradle.hiltPlugin classpath 'com.google.firebase:firebase-appdistribution-gradle:3.2.0' classpath 'com.google.gms:google-services:4.3.15' - classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.5.0.2730' + classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.0.0.2929' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6' classpath "com.likethesalad.android:stem-plugin:2.3.0" classpath 'org.owasp:dependency-check-gradle:8.1.1' From 05c16dd09a7bc35c9e581a7858895c4bcaa006b3 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 1 Mar 2023 10:08:22 +0100 Subject: [PATCH 28/32] Reducing size of the empty title in poll list screen --- vector/src/main/res/layout/fragment_room_polls_list.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/layout/fragment_room_polls_list.xml b/vector/src/main/res/layout/fragment_room_polls_list.xml index 6a627d73b8..d92111456a 100644 --- a/vector/src/main/res/layout/fragment_room_polls_list.xml +++ b/vector/src/main/res/layout/fragment_room_polls_list.xml @@ -54,7 +54,7 @@ android:gravity="center" android:textAppearance="@style/TextAppearance.Vector.Body" android:textColor="?vctr_content_secondary" - android:textSize="17sp" + android:textSize="15sp" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" From c54de67e03a32d4abc6186b30fc09c42b12c7f22 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 1 Mar 2023 10:29:14 +0100 Subject: [PATCH 29/32] Increase line spacing of the empty title in poll list screen --- vector/src/main/res/layout/fragment_room_polls_list.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/res/layout/fragment_room_polls_list.xml b/vector/src/main/res/layout/fragment_room_polls_list.xml index d92111456a..85077034ca 100644 --- a/vector/src/main/res/layout/fragment_room_polls_list.xml +++ b/vector/src/main/res/layout/fragment_room_polls_list.xml @@ -55,6 +55,7 @@ android:textAppearance="@style/TextAppearance.Vector.Body" android:textColor="?vctr_content_secondary" android:textSize="15sp" + android:lineSpacingMultiplier="1.2" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" From b0c8008fe0e0ec637219e5166345eb47c1c81083 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com> Date: Wed, 1 Mar 2023 10:40:53 +0100 Subject: [PATCH 30/32] Adding changelog entry --- changelog.d/8190.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/8190.bugfix diff --git a/changelog.d/8190.bugfix b/changelog.d/8190.bugfix new file mode 100644 index 0000000000..95790f7c0c --- /dev/null +++ b/changelog.d/8190.bugfix @@ -0,0 +1 @@ +[Poll history] Fixing small issue about font style From 7388279eb72f97d39654a08fff7fa26e41f13d2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Mar 2023 00:00:34 +0000 Subject: [PATCH 31/32] Bump flipper from 0.182.0 to 0.183.0 Bumps `flipper` from 0.182.0 to 0.183.0. Updates `com.facebook.flipper:flipper` from 0.182.0 to 0.183.0 - [Release notes](https://github.com/facebook/flipper/releases) - [Commits](https://github.com/facebook/flipper/compare/v0.182.0...v0.183.0) Updates `com.facebook.flipper:flipper-network-plugin` from 0.182.0 to 0.183.0 - [Release notes](https://github.com/facebook/flipper/releases) - [Commits](https://github.com/facebook/flipper/compare/v0.182.0...v0.183.0) --- updated-dependencies: - dependency-name: com.facebook.flipper:flipper dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.facebook.flipper:flipper-network-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 1f3009da57..9a6920f5c5 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -18,7 +18,7 @@ def markwon = "4.6.2" def moshi = "1.14.0" def lifecycle = "2.5.1" def flowBinding = "1.2.0" -def flipper = "0.182.0" +def flipper = "0.183.0" def epoxy = "5.0.0" def mavericks = "3.0.1" def glide = "4.14.2" From c4a540722b69de2f952c845963eeafbae00f7759 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Mar 2023 11:14:05 +0000 Subject: [PATCH 32/32] Bump org.owasp:dependency-check-gradle from 8.1.1 to 8.1.2 Bumps org.owasp:dependency-check-gradle from 8.1.1 to 8.1.2. --- updated-dependencies: - dependency-name: org.owasp:dependency-check-gradle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9b6136e94f..285713cacf 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ buildscript { classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.0.0.2929' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6' classpath "com.likethesalad.android:stem-plugin:2.3.0" - classpath 'org.owasp:dependency-check-gradle:8.1.1' + classpath 'org.owasp:dependency-check-gradle:8.1.2' classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.20" classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0" classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3'