From 0dc80db9b722b368bbbb936c76a8b94b883b13df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 23:06:02 +0000 Subject: [PATCH 001/175] Bump dokka-gradle-plugin from 1.7.0 to 1.7.10 Bumps dokka-gradle-plugin from 1.7.0 to 1.7.10. --- updated-dependencies: - dependency-name: org.jetbrains.dokka:dokka-gradle-plugin 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 61027a0bff..ac223ca55b 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ buildscript { classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5' classpath "com.likethesalad.android:stem-plugin:2.1.1" classpath 'org.owasp:dependency-check-gradle:7.1.1' - classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.0" + classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.10" classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files From 6ed36e804b19e45d36a6de49ccc849dc68e8685c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Jul 2022 23:10:44 +0000 Subject: [PATCH 002/175] Bump io.gitlab.arturbosch.detekt from 1.20.0 to 1.21.0 Bumps io.gitlab.arturbosch.detekt from 1.20.0 to 1.21.0. --- updated-dependencies: - dependency-name: io.gitlab.arturbosch.detekt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e8472097d5..a0523dfaf7 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ plugins { // ktlint Plugin id "org.jlleitschuh.gradle.ktlint" version "10.3.0" // Detekt - id "io.gitlab.arturbosch.detekt" version "1.20.0" + id "io.gitlab.arturbosch.detekt" version "1.21.0" // Dependency Analysis id 'com.autonomousapps.dependency-analysis' version "1.9.0" From 50b7f3ef2c79fee177e1eab2a1ff771285d25045 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 19 Jul 2022 14:51:29 +0200 Subject: [PATCH 003/175] Ad group `io.github.davidburstrom.contester` for detekt 1.21.0 --- dependencies_groups.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index e89c69a594..f60a77a92d 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -125,6 +125,7 @@ ext.groups = [ 'info.picocli', 'io.arrow-kt', 'io.element.android', + 'io.github.davidburstrom.contester', 'io.github.detekt.sarif4k', 'io.github.microutils', 'io.github.reactivecircus.flowbinding', From b4f833cb0d71a7e9d164538da14f57a9a813100e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 19 Jul 2022 14:53:12 +0200 Subject: [PATCH 004/175] Detekt: disable rule `InstanceOfCheckForException` --- tools/detekt/detekt.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/detekt/detekt.yml b/tools/detekt/detekt.yml index a836edc47a..ac79e9e6cb 100644 --- a/tools/detekt/detekt.yml +++ b/tools/detekt/detekt.yml @@ -43,6 +43,8 @@ exceptions: active: false TooGenericExceptionThrown: active: false + InstanceOfCheckForException: + active: false complexity: TooManyFunctions: From 40f8d94954a6997d506bbf2951305ebd251fb206 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 19 Jul 2022 14:58:44 +0200 Subject: [PATCH 005/175] Detekt: Use require() instead of throwing an IllegalArgumentException. [UseRequire] --- .../org/matrix/android/sdk/api/util/StringOrderUtils.kt | 2 +- .../crypto/algorithms/megolm/MXMegolmEncryption.kt | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/StringOrderUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/StringOrderUtils.kt index 83c8585941..1de0a36034 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/StringOrderUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/StringOrderUtils.kt @@ -76,7 +76,7 @@ object StringOrderUtils { } fun stringToBase(x: String, alphabet: CharArray): BigInteger { - if (x.isEmpty()) throw IllegalArgumentException() + require(x.isNotEmpty()) val len = alphabet.size.toBigInteger() var result = BigInteger("0") x.reversed().forEachIndexed { index, c -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt index 48a25f2a8b..db7246caf5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt @@ -250,8 +250,10 @@ internal class MXMegolmEncryption( * @param sessionInfo the session info * @param devicesByUser the devices map */ - private suspend fun shareUserDevicesKey(sessionInfo: MXOutboundSessionInfo, - devicesByUser: Map>) { + private suspend fun shareUserDevicesKey( + sessionInfo: MXOutboundSessionInfo, + devicesByUser: Map> + ) { val sessionKey = olmDevice.getSessionKey(sessionInfo.sessionId) ?: return Unit.also { Timber.tag(loggerTag.value).v("shareUserDevicesKey() Failed to share session, failed to export") } @@ -533,7 +535,7 @@ internal class MXMegolmEncryption( @Throws override suspend fun shareHistoryKeysWithDevice(inboundSessionWrapper: InboundGroupSessionHolder, deviceInfo: CryptoDeviceInfo) { - if (!inboundSessionWrapper.wrapper.sessionData.sharedHistory) throw IllegalArgumentException("This key can't be shared") + require(inboundSessionWrapper.wrapper.sessionData.sharedHistory) { "This key can't be shared" } Timber.tag(loggerTag.value).i("process shareHistoryKeys for ${inboundSessionWrapper.wrapper.safeSessionId} to ${deviceInfo.shortDebugString()}") val userId = deviceInfo.userId val deviceId = deviceInfo.deviceId From 62f2fe1c1665109bb2ab279fd121dc1e773a9a68 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 19 Jul 2022 14:59:57 +0200 Subject: [PATCH 006/175] Detekt: This explicit usage of `it` as the lambda parameter name can be omitted. [ExplicitItLambdaParameter] --- .../session/room/send/queue/EventSenderProcessorThread.kt | 2 +- .../features/roommemberprofile/RoomMemberProfileViewModel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt index c5b13043d7..51107c9655 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt @@ -119,7 +119,7 @@ internal class EventSenderProcessorThread @Inject constructor( override fun cancel(eventId: String, roomId: String) { (currentTask as? SendEventQueuedTask) - ?.takeIf { it -> it.event.eventId == eventId && it.event.roomId == roomId } + ?.takeIf { it.event.eventId == eventId && it.event.roomId == roomId } ?.cancel() } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt index 2c30555696..d38b2a0a69 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt @@ -117,7 +117,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor( it.fold(true) { prev, dev -> prev && (dev.trustLevel?.crossSigningVerified == true) } ) } - .execute { it -> + .execute { copy( allDevicesAreTrusted = it()?.first == true, allDevicesAreCrossSignedTrusted = it()?.second == true From 2d761385a1bd9708bc9457747bba97035068e298 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 19 Jul 2022 15:02:05 +0200 Subject: [PATCH 007/175] Detekt: disable rule `UseCheckOrError` --- tools/detekt/detekt.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/detekt/detekt.yml b/tools/detekt/detekt.yml index ac79e9e6cb..96adb3d117 100644 --- a/tools/detekt/detekt.yml +++ b/tools/detekt/detekt.yml @@ -23,6 +23,8 @@ style: active: false ProtectedMemberInFinalClass: active: false + UseCheckOrError: + active: false empty-blocks: EmptyFunctionBlock: From 4dccff4d788da05217cbf3d42ade9f662a21c55b Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 7 Jul 2022 16:59:38 +0100 Subject: [PATCH 008/175] Improves formatting in AppStateHandler --- .../java/im/vector/app/AppStateHandler.kt | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/vector/src/main/java/im/vector/app/AppStateHandler.kt b/vector/src/main/java/im/vector/app/AppStateHandler.kt index e1b8bfc474..a4e10f776e 100644 --- a/vector/src/main/java/im/vector/app/AppStateHandler.kt +++ b/vector/src/main/java/im/vector/app/AppStateHandler.kt @@ -47,9 +47,8 @@ import javax.inject.Singleton /** * This class handles the global app state. - * It requires to be added to ProcessLifecycleOwner.get().lifecycle + * It is required that this class is added as an observer to ProcessLifecycleOwner.get().lifecycle in [VectorApplication] */ -// TODO Keep this class for now, will maybe be used fro Space @Singleton class AppStateHandler @Inject constructor( private val sessionDataSource: ActiveSessionDataSource, @@ -71,30 +70,39 @@ class AppStateHandler @Inject constructor( } } - fun setCurrentSpace(spaceId: String?, session: Session? = null, persistNow: Boolean = false, isForwardNavigation: Boolean = true) { + fun setCurrentSpace( + spaceId: String?, + session: Session? = null, + persistNow: Boolean = false, + isForwardNavigation: Boolean = true, + ) { + val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return val currentSpace = selectedSpaceDataSource.currentValue?.orNull() - val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return - if (currentSpace != null && spaceId == currentSpace.roomId) return - val spaceSum = spaceId?.let { uSession.getRoomSummary(spaceId) } + val spaceSummary = spaceId?.let { activeSession.getRoomSummary(spaceId) } + val sameSpaceSelected = currentSpace != null && spaceId == currentSpace.roomId + + if (sameSpaceSelected) { + return + } if (isForwardNavigation) { spaceBackstack.addLast(currentSpace?.roomId) } if (persistNow) { - uiStateRepository.storeSelectedSpace(spaceSum?.roomId, uSession.sessionId) + uiStateRepository.storeSelectedSpace(spaceSummary?.roomId, activeSession.sessionId) } - if (spaceSum == null) { + if (spaceSummary == null) { selectedSpaceDataSource.post(Option.empty()) } else { - selectedSpaceDataSource.post(Option.just(spaceSum)) + selectedSpaceDataSource.post(Option.just(spaceSummary)) } if (spaceId != null) { - uSession.coroutineScope.launch(Dispatchers.IO) { + activeSession.coroutineScope.launch(Dispatchers.IO) { tryOrNull { - uSession.getRoom(spaceId)?.membershipService()?.loadRoomMembersIfNeeded() + activeSession.getRoom(spaceId)?.membershipService()?.loadRoomMembersIfNeeded() } } } From e4c8c88cee73c38c82d1db71151b5e9b0648e330 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 8 Jul 2022 10:05:05 +0100 Subject: [PATCH 009/175] Refactors AppStateHandler into interface implementation pattern --- .../java/im/vector/app/AppStateHandler.kt | 127 ++------------- .../java/im/vector/app/AppStateHandlerImpl.kt | 149 ++++++++++++++++++ .../app/features/home/HomeDetailViewModel.kt | 4 +- .../home/room/list/RoomListSectionBuilder.kt | 6 +- .../home/room/list/RoomListViewModel.kt | 2 +- .../createroom/CreateRoomViewModel.kt | 2 +- .../app/features/spaces/SpaceListViewModel.kt | 3 +- .../app/features/spaces/SpaceMenuViewModel.kt | 2 +- .../leave/SpaceLeaveAdvancedViewModel.kt | 24 +-- .../java/im/vector/app/AppStateHandlerTest.kt | 40 +++++ 10 files changed, 219 insertions(+), 140 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/AppStateHandlerImpl.kt create mode 100644 vector/src/test/java/im/vector/app/AppStateHandlerTest.kt diff --git a/vector/src/main/java/im/vector/app/AppStateHandler.kt b/vector/src/main/java/im/vector/app/AppStateHandler.kt index a4e10f776e..ebc9d36c1d 100644 --- a/vector/src/main/java/im/vector/app/AppStateHandler.kt +++ b/vector/src/main/java/im/vector/app/AppStateHandler.kt @@ -1,11 +1,11 @@ /* - * Copyright 2019 New Vector Ltd + * Copyright (c) 2022 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 + * 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, @@ -17,134 +17,25 @@ package im.vector.app import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.asFlow import arrow.core.Option -import im.vector.app.core.di.ActiveSessionHolder -import im.vector.app.core.utils.BehaviorDataSource -import im.vector.app.features.analytics.AnalyticsTracker -import im.vector.app.features.analytics.plan.UserProperties -import im.vector.app.features.session.coroutineScope -import im.vector.app.features.ui.UiStateRepository -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancelChildren -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.filterIsInstance -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.extensions.tryOrNull +import kotlinx.coroutines.flow.Flow import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.getRoom -import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary -import org.matrix.android.sdk.api.session.sync.SyncRequestState -import javax.inject.Inject -import javax.inject.Singleton -/** - * This class handles the global app state. - * It is required that this class is added as an observer to ProcessLifecycleOwner.get().lifecycle in [VectorApplication] - */ -@Singleton -class AppStateHandler @Inject constructor( - private val sessionDataSource: ActiveSessionDataSource, - private val uiStateRepository: UiStateRepository, - private val activeSessionHolder: ActiveSessionHolder, - private val analyticsTracker: AnalyticsTracker -) : DefaultLifecycleObserver { +interface AppStateHandler : DefaultLifecycleObserver { - private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) - private val selectedSpaceDataSource = BehaviorDataSource>(Option.empty()) - - val selectedSpaceFlow = selectedSpaceDataSource.stream() - - private val spaceBackstack = ArrayDeque() - - fun getCurrentSpace(): RoomSummary? { - return selectedSpaceDataSource.currentValue?.orNull()?.let { spaceSummary -> - activeSessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(spaceSummary.roomId) - } - } + fun getCurrentSpace(): RoomSummary? fun setCurrentSpace( spaceId: String?, session: Session? = null, persistNow: Boolean = false, isForwardNavigation: Boolean = true, - ) { - val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return - val currentSpace = selectedSpaceDataSource.currentValue?.orNull() - val spaceSummary = spaceId?.let { activeSession.getRoomSummary(spaceId) } - val sameSpaceSelected = currentSpace != null && spaceId == currentSpace.roomId + ) - if (sameSpaceSelected) { - return - } + fun getSpaceBackstack(): ArrayDeque - if (isForwardNavigation) { - spaceBackstack.addLast(currentSpace?.roomId) - } + fun getSelectedSpaceFlow(): Flow> - if (persistNow) { - uiStateRepository.storeSelectedSpace(spaceSummary?.roomId, activeSession.sessionId) - } - - if (spaceSummary == null) { - selectedSpaceDataSource.post(Option.empty()) - } else { - selectedSpaceDataSource.post(Option.just(spaceSummary)) - } - - if (spaceId != null) { - activeSession.coroutineScope.launch(Dispatchers.IO) { - tryOrNull { - activeSession.getRoom(spaceId)?.membershipService()?.loadRoomMembersIfNeeded() - } - } - } - } - - private fun observeActiveSession() { - sessionDataSource.stream() - .distinctUntilChanged() - .onEach { - // sessionDataSource could already return a session while activeSession holder still returns null - it.orNull()?.let { session -> - setCurrentSpace(uiStateRepository.getSelectedSpace(session.sessionId), session) - observeSyncStatus(session) - } - } - .launchIn(coroutineScope) - } - - private fun observeSyncStatus(session: Session) { - session.syncService().getSyncRequestStateLive() - .asFlow() - .filterIsInstance() - .map { session.spaceService().getRootSpaceSummaries().size } - .distinctUntilChanged() - .onEach { spacesNumber -> - analyticsTracker.updateUserProperties(UserProperties(numSpaces = spacesNumber)) - }.launchIn(session.coroutineScope) - } - - fun getSpaceBackstack() = spaceBackstack - - fun safeActiveSpaceId(): String? { - return selectedSpaceDataSource.currentValue?.orNull()?.roomId - } - - override fun onResume(owner: LifecycleOwner) { - observeActiveSession() - } - - override fun onPause(owner: LifecycleOwner) { - coroutineScope.coroutineContext.cancelChildren() - val session = activeSessionHolder.getSafeActiveSession() ?: return - uiStateRepository.storeSelectedSpace(selectedSpaceDataSource.currentValue?.orNull()?.roomId, session.sessionId) - } + fun getSafeActiveSpaceId(): String? } diff --git a/vector/src/main/java/im/vector/app/AppStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/AppStateHandlerImpl.kt new file mode 100644 index 0000000000..55a2a1a8bb --- /dev/null +++ b/vector/src/main/java/im/vector/app/AppStateHandlerImpl.kt @@ -0,0 +1,149 @@ +/* + * Copyright 2019 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 + +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.asFlow +import arrow.core.Option +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.utils.BehaviorDataSource +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.UserProperties +import im.vector.app.features.session.coroutineScope +import im.vector.app.features.ui.UiStateRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.getRoomSummary +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.sync.SyncRequestState +import javax.inject.Inject +import javax.inject.Singleton + +/** + * This class handles the global app state. + * It is required that this class is added as an observer to ProcessLifecycleOwner.get().lifecycle in [VectorApplication] + */ +@Singleton +class AppStateHandlerImpl @Inject constructor( + private val sessionDataSource: ActiveSessionDataSource, + private val uiStateRepository: UiStateRepository, + private val activeSessionHolder: ActiveSessionHolder, + private val analyticsTracker: AnalyticsTracker +) : AppStateHandler { + + private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) + private val selectedSpaceDataSource = BehaviorDataSource>(Option.empty()) + private val selectedSpaceFlow = selectedSpaceDataSource.stream() + private val spaceBackstack = ArrayDeque() + + override fun getCurrentSpace(): RoomSummary? { + return selectedSpaceDataSource.currentValue?.orNull()?.let { spaceSummary -> + activeSessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(spaceSummary.roomId) + } + } + + override fun setCurrentSpace( + spaceId: String?, + session: Session?, + persistNow: Boolean, + isForwardNavigation: Boolean, + ) { + val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return + val currentSpace = selectedSpaceDataSource.currentValue?.orNull() + val spaceSummary = spaceId?.let { activeSession.getRoomSummary(spaceId) } + val sameSpaceSelected = currentSpace != null && spaceId == currentSpace.roomId + + if (sameSpaceSelected) { + return + } + + if (isForwardNavigation) { + spaceBackstack.addLast(currentSpace?.roomId) + } + + if (persistNow) { + uiStateRepository.storeSelectedSpace(spaceSummary?.roomId, activeSession.sessionId) + } + + if (spaceSummary == null) { + selectedSpaceDataSource.post(Option.empty()) + } else { + selectedSpaceDataSource.post(Option.just(spaceSummary)) + } + + if (spaceId != null) { + activeSession.coroutineScope.launch(Dispatchers.IO) { + tryOrNull { + activeSession.getRoom(spaceId)?.membershipService()?.loadRoomMembersIfNeeded() + } + } + } + } + + private fun observeActiveSession() { + sessionDataSource.stream() + .distinctUntilChanged() + .onEach { + // sessionDataSource could already return a session while activeSession holder still returns null + it.orNull()?.let { session -> + setCurrentSpace(uiStateRepository.getSelectedSpace(session.sessionId), session) + observeSyncStatus(session) + } + } + .launchIn(coroutineScope) + } + + private fun observeSyncStatus(session: Session) { + session.syncService().getSyncRequestStateLive() + .asFlow() + .filterIsInstance() + .map { session.spaceService().getRootSpaceSummaries().size } + .distinctUntilChanged() + .onEach { spacesNumber -> + analyticsTracker.updateUserProperties(UserProperties(numSpaces = spacesNumber)) + }.launchIn(session.coroutineScope) + } + + override fun getSpaceBackstack() = spaceBackstack + + override fun getSelectedSpaceFlow() = selectedSpaceFlow + + override fun getSafeActiveSpaceId(): String? { + return selectedSpaceDataSource.currentValue?.orNull()?.roomId + } + + override fun onResume(owner: LifecycleOwner) { + observeActiveSession() + } + + override fun onPause(owner: LifecycleOwner) { + coroutineScope.coroutineContext.cancelChildren() + val session = activeSessionHolder.getSafeActiveSession() ?: return + uiStateRepository.storeSelectedSpace(selectedSpaceDataSource.currentValue?.orNull()?.roomId, session.sessionId) + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt index 357d2b7c69..f16df17ead 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt @@ -207,7 +207,7 @@ class HomeDetailViewModel @AssistedInject constructor( } private fun observeRoomGroupingMethod() { - appStateHandler.selectedSpaceFlow + appStateHandler.getSelectedSpaceFlow() .setOnEach { copy( selectedSpace = it.orNull() @@ -216,7 +216,7 @@ class HomeDetailViewModel @AssistedInject constructor( } private fun observeRoomSummaries() { - appStateHandler.selectedSpaceFlow.distinctUntilChanged().flatMapLatest { + appStateHandler.getSelectedSpaceFlow().distinctUntilChanged().flatMapLatest { // we use it as a trigger to all changes in room, but do not really load // the actual models session.roomService().getPagedRoomSummariesLive( diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt index 42634c237a..3e9498891a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt @@ -359,7 +359,7 @@ class RoomListSectionBuilder( query: (RoomSummaryQueryParams.Builder) -> Unit ) { withQueryParams(query) { roomQueryParams -> - val updatedQueryParams = roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()) + val updatedQueryParams = roomQueryParams.process(spaceFilterStrategy, appStateHandler.getSafeActiveSpaceId()) val liveQueryParams = MutableStateFlow(updatedQueryParams) val itemCountFlow = liveQueryParams .flatMapLatest { @@ -370,7 +370,7 @@ class RoomListSectionBuilder( val name = stringProvider.getString(nameRes) val filteredPagedRoomSummariesLive = session.roomService().getFilteredPagedRoomSummariesLive( - roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()), + roomQueryParams.process(spaceFilterStrategy, appStateHandler.getSafeActiveSpaceId()), pagedListConfig ) when (spaceFilterStrategy) { @@ -417,7 +417,7 @@ class RoomListSectionBuilder( RoomAggregateNotificationCount(it.size, it.size) } else { session.roomService().getNotificationCountForRooms( - roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()) + roomQueryParams.process(spaceFilterStrategy, appStateHandler.getSafeActiveSpaceId()) ) } ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index 44d61f9ed2..6a4d46dd05 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -148,7 +148,7 @@ class RoomListViewModel @AssistedInject constructor( private val roomListSectionBuilder = RoomListSectionBuilder( session, stringProvider, - appStateHandler, + appStateHandlerImpl, viewModelScope, autoAcceptInvites, { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index e068d21b36..121007cf2a 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -73,7 +73,7 @@ class CreateRoomViewModel @AssistedInject constructor( initHomeServerName() initAdminE2eByDefault() - val parentSpaceId = initialState.parentSpaceId ?: appStateHandler.safeActiveSpaceId() + val parentSpaceId = initialState.parentSpaceId ?: appStateHandler.getSafeActiveSpaceId() val restrictedSupport = session.homeServerCapabilitiesService().getHomeServerCapabilities() .isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED) 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 3b2fb31b74..a72c6cc0c2 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 @@ -85,8 +85,7 @@ class SpaceListViewModel @AssistedInject constructor( } observeSpaceSummaries() -// observeSelectionState() - appStateHandler.selectedSpaceFlow + appStateHandler.getSelectedSpaceFlow() .distinctUntilChanged() .setOnEach { selectedSpaceOption -> copy( diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt index 7b53b09187..e50fa5540c 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt @@ -73,7 +73,7 @@ class SpaceMenuViewModel @AssistedInject constructor( it.getOrNull()?.let { if (it.membership == Membership.LEAVE) { setState { copy(leavingState = Success(Unit)) } - if (appStateHandler.safeActiveSpaceId() == initialState.spaceId) { + if (appStateHandler.getSafeActiveSpaceId() == initialState.spaceId) { // switch to home? appStateHandler.setCurrentSpace(null, session) } diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt index 7413386709..4b6657fc47 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt @@ -75,19 +75,19 @@ class SpaceLeaveAdvancedViewModel @AssistedInject constructor( } setState { copy(spaceSummary = spaceSummary) } - session.getRoom(initialState.spaceId)?.let { room -> - room.flow().liveRoomSummary() - .unwrap() - .onEach { - if (it.membership == Membership.LEAVE) { - setState { copy(leaveState = Success(Unit)) } - if (appStateHandler.safeActiveSpaceId() == initialState.spaceId) { - // switch to home? - appStateHandler.setCurrentSpace(null, session) - } + session.getRoom(initialState.spaceId) + ?.flow() + ?.liveRoomSummary() + ?.unwrap() + ?.onEach { + if (it.membership == Membership.LEAVE) { + setState { copy(leaveState = Success(Unit)) } + if (appStateHandler.getSafeActiveSpaceId() == initialState.spaceId) { + // switch to home? + appStateHandler.setCurrentSpace(null, session) } - }.launchIn(viewModelScope) - } + } + }?.launchIn(viewModelScope) viewModelScope.launch { val children = session.roomService().getRoomSummaries( diff --git a/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt b/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt new file mode 100644 index 0000000000..ac839ac806 --- /dev/null +++ b/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 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 + +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.ui.UiStateRepository +import io.mockk.mockk + +internal class AppStateHandlerTest { + + private val sessionDataSource: ActiveSessionDataSource = mockk() + private val uiStateRepository: UiStateRepository = mockk() + private val activeSessionHolder: ActiveSessionHolder = mockk() + private val analyticsTracker: AnalyticsTracker = mockk() + + private val appStateHandlerImpl = AppStateHandlerImpl( + sessionDataSource, + uiStateRepository, + activeSessionHolder, + analyticsTracker, + ) + + + +} From fbdbfb6be272110db08193154b67de72937a107d Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 8 Jul 2022 11:56:00 +0100 Subject: [PATCH 010/175] Post cherry pick fix --- .../main/java/im/vector/app/core/di/SingletonModule.kt | 5 +++++ .../app/features/home/UnreadMessagesSharedViewModel.kt | 8 ++++---- .../features/home/room/list/RoomListSectionBuilder.kt | 10 +++++----- .../app/features/home/room/list/RoomListViewModel.kt | 4 ++-- .../src/test/java/im/vector/app/AppStateHandlerTest.kt | 7 +++++++ 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt index 602fd73034..c5e27af761 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt @@ -28,6 +28,8 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import im.vector.app.AppStateHandler +import im.vector.app.AppStateHandlerImpl import im.vector.app.BuildConfig import im.vector.app.EmojiCompatWrapper import im.vector.app.EmojiSpanify @@ -108,6 +110,9 @@ abstract class VectorBindModule { @Binds abstract fun bindSystemSettingsProvide(provider: AndroidSystemSettingsProvider): SystemSettingsProvider + + @Binds + abstract fun bindAppStateHandler(appStateHandlerImpl: AppStateHandlerImpl): AppStateHandler } @InstallIn(SingletonComponent::class) diff --git a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt index f2e6b7e064..074149a255 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt @@ -109,8 +109,8 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor( } combine( - appStateHandler.selectedSpaceFlow.distinctUntilChanged(), - appStateHandler.selectedSpaceFlow.flatMapLatest { + appStateHandler.getSelectedSpaceFlow().distinctUntilChanged(), + appStateHandler.getSelectedSpaceFlow().flatMapLatest { roomService.getPagedRoomSummariesLive( roomSummaryQueryParams { this.memberships = Membership.activeMemberships() @@ -161,10 +161,10 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor( CountInfo( homeCount = counts, otherCount = RoomAggregateNotificationCount( - notificationCount = rootCounts.fold(0, { acc, rs -> acc + rs.notificationCount }) + + notificationCount = rootCounts.fold(0) { acc, rs -> acc + rs.notificationCount } + (counts.notificationCount.takeIf { selectedSpace != null } ?: 0) + spaceInviteCount, - highlightCount = rootCounts.fold(0, { acc, rs -> acc + rs.highlightCount }) + + highlightCount = rootCounts.fold(0) { acc, rs -> acc + rs.highlightCount } + (counts.highlightCount.takeIf { selectedSpace != null } ?: 0) + spaceInviteCount ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt index 3e9498891a..d91f8f6e5d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt @@ -94,7 +94,7 @@ class RoomListSectionBuilder( } } - appStateHandler.selectedSpaceFlow + appStateHandler.getSelectedSpaceFlow() .distinctUntilChanged() .onEach { selectedSpaceOption -> val selectedSpace = selectedSpaceOption.orNull() @@ -149,7 +149,7 @@ class RoomListSectionBuilder( ) { it.memberships = listOf(Membership.JOIN) it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS - it.roomTagQueryFilter = RoomTagQueryFilter(false, false, false) + it.roomTagQueryFilter = RoomTagQueryFilter(isFavorite = false, isLowPriority = false, isServerNotice = false) } addSection( @@ -186,7 +186,7 @@ class RoomListSectionBuilder( // add suggested rooms val suggestedRoomsFlow = // MutableLiveData>() - appStateHandler.selectedSpaceFlow + appStateHandler.getSelectedSpaceFlow() .distinctUntilChanged() .flatMapLatest { selectedSpaceOption -> val selectedSpace = selectedSpaceOption.orNull() @@ -270,7 +270,7 @@ class RoomListSectionBuilder( ) { it.memberships = listOf(Membership.JOIN) it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM - it.roomTagQueryFilter = RoomTagQueryFilter(false, false, null) + it.roomTagQueryFilter = RoomTagQueryFilter(isFavorite = false, isLowPriority = false, isServerNotice = null) } addSection( @@ -282,7 +282,7 @@ class RoomListSectionBuilder( ) { it.memberships = listOf(Membership.JOIN) it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM - it.roomTagQueryFilter = RoomTagQueryFilter(false, true, null) + it.roomTagQueryFilter = RoomTagQueryFilter(isFavorite = false, isLowPriority = true, isServerNotice = null) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index 6a4d46dd05..e51bdc5841 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -100,7 +100,7 @@ class RoomListViewModel @AssistedInject constructor( observeMembershipChanges() observeLocalRooms() - appStateHandler.selectedSpaceFlow + appStateHandler.getSelectedSpaceFlow() .distinctUntilChanged() .execute { copy( @@ -148,7 +148,7 @@ class RoomListViewModel @AssistedInject constructor( private val roomListSectionBuilder = RoomListSectionBuilder( session, stringProvider, - appStateHandlerImpl, + appStateHandler, viewModelScope, autoAcceptInvites, { diff --git a/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt b/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt index ac839ac806..1ff645a9e5 100644 --- a/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt +++ b/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt @@ -20,6 +20,8 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.ui.UiStateRepository import io.mockk.mockk +import org.amshove.kluent.shouldBe +import org.junit.Test internal class AppStateHandlerTest { @@ -35,6 +37,11 @@ internal class AppStateHandlerTest { analyticsTracker, ) + @Test + fun `given selected space is null, when getCurrentSpace, then return null`() { + val currentSpace = appStateHandlerImpl.getCurrentSpace() + currentSpace shouldBe null + } } From 49992f682efb49eed4d028a5caebc63119275724 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 21 Jul 2022 08:12:04 +0200 Subject: [PATCH 011/175] Adds test for existing space --- .../java/im/vector/app/AppStateHandlerTest.kt | 34 ++++++++++++++++--- .../im/vector/app/test/fakes/FakeSession.kt | 10 ++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt b/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt index 1ff645a9e5..51e5308a92 100644 --- a/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt +++ b/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt @@ -16,32 +16,56 @@ package im.vector.app -import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.ui.UiStateRepository +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeSession +import io.mockk.every +import io.mockk.justRun import io.mockk.mockk import org.amshove.kluent.shouldBe +import org.junit.Before import org.junit.Test +import org.matrix.android.sdk.api.session.room.model.RoomSummary internal class AppStateHandlerTest { + private val spaceId = "spaceId" + private val spaceSummary: RoomSummary = mockk { + every { roomId } returns spaceId + } + private val session = FakeSession.withRoomSummary(spaceSummary) + private val sessionDataSource: ActiveSessionDataSource = mockk() private val uiStateRepository: UiStateRepository = mockk() - private val activeSessionHolder: ActiveSessionHolder = mockk() + private val activeSessionHolder = FakeActiveSessionHolder(session).instance private val analyticsTracker: AnalyticsTracker = mockk() - private val appStateHandlerImpl = AppStateHandlerImpl( + private val appStateHandler = AppStateHandlerImpl( sessionDataSource, uiStateRepository, activeSessionHolder, analyticsTracker, ) + @Before + fun setup() { + justRun { uiStateRepository.storeSelectedSpace(any(), any()) } + } + @Test - fun `given selected space is null, when getCurrentSpace, then return null`() { - val currentSpace = appStateHandlerImpl.getCurrentSpace() + fun `given selected space doesn't exist, when getCurrentSpace, then return null`() { + val currentSpace = appStateHandler.getCurrentSpace() currentSpace shouldBe null } + @Test + fun `given selected space exists, when getCurrentSpace, then return selected space`() { + appStateHandler.setCurrentSpace(spaceId, session) + + val currentSpace = appStateHandler.getCurrentSpace() + + currentSpace shouldBe spaceSummary + } } 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 3af15a7e5c..e62214e310 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 @@ -23,11 +23,14 @@ import im.vector.app.features.session.VectorSessionStore import im.vector.app.test.testCoroutineDispatchers import io.mockk.coEvery import io.mockk.coJustRun +import io.mockk.every import io.mockk.mockk import io.mockk.mockkStatic import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.profile.ProfileService +import org.matrix.android.sdk.api.session.room.model.RoomSummary class FakeSession( val fakeCryptoService: FakeCryptoService = FakeCryptoService(), @@ -65,4 +68,11 @@ class FakeSession( this@FakeSession.startSyncing(any()) } } + + companion object { + + fun withRoomSummary(roomSummary: RoomSummary) = FakeSession().apply { + every { getRoomSummary(any()) } returns roomSummary + } + } } From f770ae065318f747829e4e3fd74e81a3175e5c14 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 21 Jul 2022 08:53:08 +0200 Subject: [PATCH 012/175] Adds tests for persist space and backstack --- .../im/vector/app/AppStateHandlerImplTest.kt | 116 ++++++++++++++++++ .../java/im/vector/app/AppStateHandlerTest.kt | 71 ----------- .../app/test/fakes/FakeUiStateRepository.kt | 29 +++++ 3 files changed, 145 insertions(+), 71 deletions(-) create mode 100644 vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt delete mode 100644 vector/src/test/java/im/vector/app/AppStateHandlerTest.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeUiStateRepository.kt diff --git a/vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt b/vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt new file mode 100644 index 0000000000..f523208c97 --- /dev/null +++ b/vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2022 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 + +import im.vector.app.test.fakes.FakeActiveSessionDataSource +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeAnalyticsTracker +import im.vector.app.test.fakes.FakeSession +import im.vector.app.test.fakes.FakeUiStateRepository +import io.mockk.every +import io.mockk.justRun +import io.mockk.mockk +import org.amshove.kluent.shouldBe +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Before +import org.junit.Test +import org.matrix.android.sdk.api.session.room.model.RoomSummary + +internal class AppStateHandlerImplTest { + + private val spaceId = "spaceId" + private val spaceSummary: RoomSummary = mockk() + private val session = FakeSession.withRoomSummary(spaceSummary) + + private val sessionDataSource = FakeActiveSessionDataSource() + private val uiStateRepository = FakeUiStateRepository() + private val activeSessionHolder = FakeActiveSessionHolder(session) + private val analyticsTracker = FakeAnalyticsTracker() + + private val appStateHandler = AppStateHandlerImpl( + sessionDataSource.instance, + uiStateRepository, + activeSessionHolder.instance, + analyticsTracker, + ) + + @Before + fun setup() { + justRun { uiStateRepository.storeSelectedSpace(any(), any()) } + every { spaceSummary.roomId } returns spaceId + } + + @Test + fun `given selected space doesn't exist, when getCurrentSpace, then return null`() { + val currentSpace = appStateHandler.getCurrentSpace() + + currentSpace shouldBe null + } + + @Test + fun `given selected space exists, when getCurrentSpace, then return selected space`() { + appStateHandler.setCurrentSpace(spaceId, session) + + val currentSpace = appStateHandler.getCurrentSpace() + + currentSpace shouldBe spaceSummary + } + + @Test + fun `given persistNow is true, when setCurrentSpace, then immediately persist to ui state`() { + appStateHandler.setCurrentSpace(spaceId, session, persistNow = true) + + uiStateRepository.verifyStoreSelectedSpace(spaceId, session) + } + + @Test + fun `given persistNow is false, when setCurrentSpace, then don't immediately persist to ui state`() { + appStateHandler.setCurrentSpace(spaceId, session, persistNow = false) + + uiStateRepository.verifyStoreSelectedSpace(spaceId, session, inverse = true) + } + + @Test + fun `given is forward navigation and no current space, when setCurrentSpace, then null added to backstack`() { + appStateHandler.setCurrentSpace(spaceId, session, isForwardNavigation = true) + + val backstack = appStateHandler.getSpaceBackstack() + + backstack.size shouldBe 1 + backstack.first() shouldBe null + } + + @Test + fun `given is forward navigation and is in space, when setCurrentSpace, then previous space added to backstack`() { + appStateHandler.setCurrentSpace(spaceId, session, isForwardNavigation = true) + appStateHandler.setCurrentSpace("secondSpaceId", session, isForwardNavigation = true) + + val backstack = appStateHandler.getSpaceBackstack() + + backstack.size shouldBe 2 + backstack shouldBeEqualTo listOf(null, spaceId) + } + + @Test + fun `given is not forward navigation, when setCurrentSpace, then previous space not added to backstack`() { + appStateHandler.setCurrentSpace(spaceId, session, isForwardNavigation = false) + + val backstack = appStateHandler.getSpaceBackstack() + + backstack.size shouldBe 0 + } +} diff --git a/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt b/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt deleted file mode 100644 index 51e5308a92..0000000000 --- a/vector/src/test/java/im/vector/app/AppStateHandlerTest.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2022 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 - -import im.vector.app.features.analytics.AnalyticsTracker -import im.vector.app.features.ui.UiStateRepository -import im.vector.app.test.fakes.FakeActiveSessionHolder -import im.vector.app.test.fakes.FakeSession -import io.mockk.every -import io.mockk.justRun -import io.mockk.mockk -import org.amshove.kluent.shouldBe -import org.junit.Before -import org.junit.Test -import org.matrix.android.sdk.api.session.room.model.RoomSummary - -internal class AppStateHandlerTest { - - private val spaceId = "spaceId" - private val spaceSummary: RoomSummary = mockk { - every { roomId } returns spaceId - } - private val session = FakeSession.withRoomSummary(spaceSummary) - - private val sessionDataSource: ActiveSessionDataSource = mockk() - private val uiStateRepository: UiStateRepository = mockk() - private val activeSessionHolder = FakeActiveSessionHolder(session).instance - private val analyticsTracker: AnalyticsTracker = mockk() - - private val appStateHandler = AppStateHandlerImpl( - sessionDataSource, - uiStateRepository, - activeSessionHolder, - analyticsTracker, - ) - - @Before - fun setup() { - justRun { uiStateRepository.storeSelectedSpace(any(), any()) } - } - - @Test - fun `given selected space doesn't exist, when getCurrentSpace, then return null`() { - val currentSpace = appStateHandler.getCurrentSpace() - - currentSpace shouldBe null - } - - @Test - fun `given selected space exists, when getCurrentSpace, then return selected space`() { - appStateHandler.setCurrentSpace(spaceId, session) - - val currentSpace = appStateHandler.getCurrentSpace() - - currentSpace shouldBe spaceSummary - } -} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeUiStateRepository.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeUiStateRepository.kt new file mode 100644 index 0000000000..3b38e4512c --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeUiStateRepository.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 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 im.vector.app.features.ui.UiStateRepository +import io.mockk.mockk +import io.mockk.verify +import org.matrix.android.sdk.api.session.Session + +class FakeUiStateRepository : UiStateRepository by mockk() { + + fun verifyStoreSelectedSpace(roomId: String, session: Session, inverse: Boolean = false) { + verify(inverse = inverse) { storeSelectedSpace(roomId, session.sessionId) } + } +} From 9a649b6093e1e377bedea7e7a8ccd73d947bf9ed Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 21 Jul 2022 09:39:12 +0200 Subject: [PATCH 013/175] Adds tests for selectedSpaceFlow and activeSpaceId --- .../im/vector/app/AppStateHandlerImplTest.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt b/vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt index f523208c97..6f0c33f998 100644 --- a/vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt +++ b/vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt @@ -24,6 +24,8 @@ import im.vector.app.test.fakes.FakeUiStateRepository import io.mockk.every import io.mockk.justRun import io.mockk.mockk +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runTest import org.amshove.kluent.shouldBe import org.amshove.kluent.shouldBeEqualTo import org.junit.Before @@ -113,4 +115,29 @@ internal class AppStateHandlerImplTest { backstack.size shouldBe 0 } + + @Test + fun `when setCurrentSpace, then space is emitted to selectedSpaceFlow`() = runTest { + appStateHandler.setCurrentSpace(spaceId, session) + + val currentSpace = appStateHandler.getSelectedSpaceFlow().first().orNull() + + currentSpace shouldBeEqualTo spaceSummary + } + + @Test + fun `given current space exists, when getSafeActiveSpaceId, then return current space id`() { + appStateHandler.setCurrentSpace(spaceId, session) + + val activeSpaceId = appStateHandler.getSafeActiveSpaceId() + + activeSpaceId shouldBeEqualTo spaceId + } + + @Test + fun `given current space doesn't exist, when getSafeActiveSpaceId, then return current null`() { + val activeSpaceId = appStateHandler.getSafeActiveSpaceId() + + activeSpaceId shouldBe null + } } From f0ae458a5489bdb1ed8015de4dca13dc58d4d358 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 21 Jul 2022 10:10:44 +0200 Subject: [PATCH 014/175] Changes AppStateHandler to SpaceStateHandler --- ...ppStateHandler.kt => SpaceStateHandler.kt} | 2 +- ...andlerImpl.kt => SpaceStateHandlerImpl.kt} | 4 +- .../java/im/vector/app/VectorApplication.kt | 4 +- .../im/vector/app/core/di/SingletonModule.kt | 6 +-- .../vector/app/features/home/HomeActivity.kt | 4 +- .../app/features/home/HomeDetailFragment.kt | 14 +++---- .../app/features/home/HomeDetailViewModel.kt | 10 ++--- .../home/UnreadMessagesSharedViewModel.kt | 8 ++-- .../home/room/detail/TimelineViewModel.kt | 10 ++--- .../home/room/list/RoomListSectionBuilder.kt | 14 +++---- .../home/room/list/RoomListViewModel.kt | 8 ++-- .../features/navigation/DefaultNavigator.kt | 14 +++---- .../createroom/CreateRoomViewModel.kt | 6 +-- .../app/features/spaces/SpaceListViewModel.kt | 8 ++-- .../app/features/spaces/SpaceMenuViewModel.kt | 8 ++-- .../leave/SpaceLeaveAdvancedViewModel.kt | 8 ++-- ...plTest.kt => SpaceStateHandlerImplTest.kt} | 38 +++++++++---------- 17 files changed, 83 insertions(+), 83 deletions(-) rename vector/src/main/java/im/vector/app/{AppStateHandler.kt => SpaceStateHandler.kt} (95%) rename vector/src/main/java/im/vector/app/{AppStateHandlerImpl.kt => SpaceStateHandlerImpl.kt} (98%) rename vector/src/test/java/im/vector/app/{AppStateHandlerImplTest.kt => SpaceStateHandlerImplTest.kt} (73%) diff --git a/vector/src/main/java/im/vector/app/AppStateHandler.kt b/vector/src/main/java/im/vector/app/SpaceStateHandler.kt similarity index 95% rename from vector/src/main/java/im/vector/app/AppStateHandler.kt rename to vector/src/main/java/im/vector/app/SpaceStateHandler.kt index ebc9d36c1d..7a98025734 100644 --- a/vector/src/main/java/im/vector/app/AppStateHandler.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandler.kt @@ -22,7 +22,7 @@ import kotlinx.coroutines.flow.Flow import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.RoomSummary -interface AppStateHandler : DefaultLifecycleObserver { +interface SpaceStateHandler : DefaultLifecycleObserver { fun getCurrentSpace(): RoomSummary? diff --git a/vector/src/main/java/im/vector/app/AppStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt similarity index 98% rename from vector/src/main/java/im/vector/app/AppStateHandlerImpl.kt rename to vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt index 55a2a1a8bb..23c9d7e4c9 100644 --- a/vector/src/main/java/im/vector/app/AppStateHandlerImpl.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt @@ -49,12 +49,12 @@ import javax.inject.Singleton * It is required that this class is added as an observer to ProcessLifecycleOwner.get().lifecycle in [VectorApplication] */ @Singleton -class AppStateHandlerImpl @Inject constructor( +class SpaceStateHandlerImpl @Inject constructor( private val sessionDataSource: ActiveSessionDataSource, private val uiStateRepository: UiStateRepository, private val activeSessionHolder: ActiveSessionHolder, private val analyticsTracker: AnalyticsTracker -) : AppStateHandler { +) : SpaceStateHandler { private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private val selectedSpaceDataSource = BehaviorDataSource>(Option.empty()) diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index 3cb0423ca8..a0a3b20e11 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -90,7 +90,7 @@ class VectorApplication : @Inject lateinit var vectorPreferences: VectorPreferences @Inject lateinit var versionProvider: VersionProvider @Inject lateinit var notificationUtils: NotificationUtils - @Inject lateinit var appStateHandler: AppStateHandler + @Inject lateinit var spaceStateHandler: SpaceStateHandler @Inject lateinit var popupAlertManager: PopupAlertManager @Inject lateinit var pinLocker: PinLocker @Inject lateinit var callManager: WebRtcCallManager @@ -187,7 +187,7 @@ class VectorApplication : fcmHelper.onEnterBackground(activeSessionHolder) } }) - ProcessLifecycleOwner.get().lifecycle.addObserver(appStateHandler) + ProcessLifecycleOwner.get().lifecycle.addObserver(spaceStateHandler) ProcessLifecycleOwner.get().lifecycle.addObserver(pinLocker) ProcessLifecycleOwner.get().lifecycle.addObserver(callManager) // This should be done as early as possible diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt index c5e27af761..5c70e9be53 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt @@ -28,8 +28,8 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import im.vector.app.AppStateHandler -import im.vector.app.AppStateHandlerImpl +import im.vector.app.SpaceStateHandler +import im.vector.app.SpaceStateHandlerImpl import im.vector.app.BuildConfig import im.vector.app.EmojiCompatWrapper import im.vector.app.EmojiSpanify @@ -112,7 +112,7 @@ abstract class VectorBindModule { abstract fun bindSystemSettingsProvide(provider: AndroidSystemSettingsProvider): SystemSettingsProvider @Binds - abstract fun bindAppStateHandler(appStateHandlerImpl: AppStateHandlerImpl): AppStateHandler + abstract fun bindSpaceStateHandler(spaceStateHandlerImpl: SpaceStateHandlerImpl): SpaceStateHandler } @InstallIn(SingletonComponent::class) diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index d82621977f..9d59ba1574 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -35,7 +35,7 @@ import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.hideKeyboard @@ -129,7 +129,7 @@ class HomeActivity : @Inject lateinit var permalinkHandler: PermalinkHandler @Inject lateinit var avatarRenderer: AvatarRenderer @Inject lateinit var initSyncStepFormatter: InitSyncStepFormatter - @Inject lateinit var appStateHandler: AppStateHandler + @Inject lateinit var spaceStateHandler: SpaceStateHandler @Inject lateinit var unifiedPushHelper: UnifiedPushHelper @Inject lateinit var fcmHelper: FcmHelper diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index 828e4cc26c..54ff44d2c3 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -28,7 +28,7 @@ import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.google.android.material.badge.BadgeDrawable -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.R import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.toMvRxBundle @@ -66,7 +66,7 @@ class HomeDetailFragment @Inject constructor( private val alertManager: PopupAlertManager, private val callManager: WebRtcCallManager, private val vectorPreferences: VectorPreferences, - private val appStateHandler: AppStateHandler + private val spaceStateHandler: SpaceStateHandler ) : VectorBaseFragment(), KeysBackupBanner.Delegate, CurrentCallsView.Callback, @@ -183,13 +183,13 @@ class HomeDetailFragment @Inject constructor( } private fun navigateBack() { - val previousSpaceId = appStateHandler.getSpaceBackstack().removeLastOrNull() - val parentSpaceId = appStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull() + val previousSpaceId = spaceStateHandler.getSpaceBackstack().removeLastOrNull() + val parentSpaceId = spaceStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull() setCurrentSpace(previousSpaceId ?: parentSpaceId) } private fun setCurrentSpace(spaceId: String?) { - appStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false) + spaceStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false) sharedActionViewModel.post(HomeActivitySharedAction.OnCloseSpace) } @@ -212,7 +212,7 @@ class HomeDetailFragment @Inject constructor( } private fun refreshSpaceState() { - appStateHandler.getCurrentSpace()?.let { + spaceStateHandler.getCurrentSpace()?.let { onSpaceChange(it) } } @@ -466,7 +466,7 @@ class HomeDetailFragment @Inject constructor( return this } - override fun onBackPressed(toolbarButton: Boolean) = if (appStateHandler.getCurrentSpace() != null) { + override fun onBackPressed(toolbarButton: Boolean) = if (spaceStateHandler.getCurrentSpace() != null) { navigateBack() true } else { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt index f16df17ead..ede9872a9b 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt @@ -22,7 +22,7 @@ import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.extensions.singletonEntryPoint @@ -68,7 +68,7 @@ class HomeDetailViewModel @AssistedInject constructor( private val vectorDataStore: VectorDataStore, private val callManager: WebRtcCallManager, private val directRoomHelper: DirectRoomHelper, - private val appStateHandler: AppStateHandler, + private val spaceStateHandler: SpaceStateHandler, private val autoAcceptInvites: AutoAcceptInvites, private val vectorOverrides: VectorOverrides ) : VectorViewModel(initialState), @@ -207,7 +207,7 @@ class HomeDetailViewModel @AssistedInject constructor( } private fun observeRoomGroupingMethod() { - appStateHandler.getSelectedSpaceFlow() + spaceStateHandler.getSelectedSpaceFlow() .setOnEach { copy( selectedSpace = it.orNull() @@ -216,7 +216,7 @@ class HomeDetailViewModel @AssistedInject constructor( } private fun observeRoomSummaries() { - appStateHandler.getSelectedSpaceFlow().distinctUntilChanged().flatMapLatest { + spaceStateHandler.getSelectedSpaceFlow().distinctUntilChanged().flatMapLatest { // we use it as a trigger to all changes in room, but do not really load // the actual models session.roomService().getPagedRoomSummariesLive( @@ -228,7 +228,7 @@ class HomeDetailViewModel @AssistedInject constructor( } .throttleFirst(300) .onEach { - val activeSpaceRoomId = appStateHandler.getCurrentSpace()?.roomId + val activeSpaceRoomId = spaceStateHandler.getCurrentSpace()?.roomId var dmInvites = 0 var roomsInvite = 0 if (autoAcceptInvites.showInvites()) { diff --git a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt index 074149a255..fca106d3a5 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt @@ -22,7 +22,7 @@ import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.EmptyAction @@ -58,7 +58,7 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor( @Assisted initialState: UnreadMessagesState, session: Session, private val vectorPreferences: VectorPreferences, - appStateHandler: AppStateHandler, + spaceStateHandler: SpaceStateHandler, private val autoAcceptInvites: AutoAcceptInvites ) : VectorViewModel(initialState) { @@ -109,8 +109,8 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor( } combine( - appStateHandler.getSelectedSpaceFlow().distinctUntilChanged(), - appStateHandler.getSelectedSpaceFlow().flatMapLatest { + spaceStateHandler.getSelectedSpaceFlow().distinctUntilChanged(), + spaceStateHandler.getSelectedSpaceFlow().flatMapLatest { roomService.getPagedRoomSummariesLive( roomSummaryQueryParams { this.memberships = Membership.activeMemberships() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index e305ccbec1..d562609e42 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -28,7 +28,7 @@ import com.airbnb.mvrx.Uninitialized import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.R import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory @@ -136,7 +136,7 @@ class TimelineViewModel @AssistedInject constructor( private val locationSharingServiceConnection: LocationSharingServiceConnection, private val stopLiveLocationShareUseCase: StopLiveLocationShareUseCase, timelineFactory: TimelineFactory, - appStateHandler: AppStateHandler, + spaceStateHandler: SpaceStateHandler, ) : VectorViewModel(initialState), Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener, LocationSharingServiceConnection.Callback { @@ -218,16 +218,16 @@ class TimelineViewModel @AssistedInject constructor( if (initialState.switchToParentSpace) { // We are coming from a notification, try to switch to the most relevant space // so that when hitting back the room will appear in the list - appStateHandler.getCurrentSpace().let { currentSpace -> + spaceStateHandler.getCurrentSpace().let { currentSpace -> val currentRoomSummary = room.roomSummary() ?: return@let // nothing we are good if ((currentSpace == null && !vectorPreferences.prefSpacesShowAllRoomInHome()) || (currentSpace != null && !currentRoomSummary.flattenParentIds.contains(currentSpace.roomId))) { // take first one or switch to home - appStateHandler.setCurrentSpace( + spaceStateHandler.setCurrentSpace( currentRoomSummary .flattenParentIds.firstOrNull { it.isNotBlank() }, - // force persist, because if not on resume the AppStateHandler will resume + // force persist, because if not on resume the SpaceStateHandler will resume // the current space from what was persisted on enter background persistNow = true ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt index d91f8f6e5d..2408d157f3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt @@ -23,7 +23,7 @@ import androidx.lifecycle.asFlow import androidx.lifecycle.liveData import androidx.paging.PagedList import com.airbnb.mvrx.Async -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.R import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.RoomListDisplayMode @@ -58,7 +58,7 @@ import timber.log.Timber class RoomListSectionBuilder( private val session: Session, private val stringProvider: StringProvider, - private val appStateHandler: AppStateHandler, + private val spaceStateHandler: SpaceStateHandler, private val viewModelScope: CoroutineScope, private val autoAcceptInvites: AutoAcceptInvites, private val onUpdatable: (UpdatableLivePageResult) -> Unit, @@ -94,7 +94,7 @@ class RoomListSectionBuilder( } } - appStateHandler.getSelectedSpaceFlow() + spaceStateHandler.getSelectedSpaceFlow() .distinctUntilChanged() .onEach { selectedSpaceOption -> val selectedSpace = selectedSpaceOption.orNull() @@ -186,7 +186,7 @@ class RoomListSectionBuilder( // add suggested rooms val suggestedRoomsFlow = // MutableLiveData>() - appStateHandler.getSelectedSpaceFlow() + spaceStateHandler.getSelectedSpaceFlow() .distinctUntilChanged() .flatMapLatest { selectedSpaceOption -> val selectedSpace = selectedSpaceOption.orNull() @@ -359,7 +359,7 @@ class RoomListSectionBuilder( query: (RoomSummaryQueryParams.Builder) -> Unit ) { withQueryParams(query) { roomQueryParams -> - val updatedQueryParams = roomQueryParams.process(spaceFilterStrategy, appStateHandler.getSafeActiveSpaceId()) + val updatedQueryParams = roomQueryParams.process(spaceFilterStrategy, spaceStateHandler.getSafeActiveSpaceId()) val liveQueryParams = MutableStateFlow(updatedQueryParams) val itemCountFlow = liveQueryParams .flatMapLatest { @@ -370,7 +370,7 @@ class RoomListSectionBuilder( val name = stringProvider.getString(nameRes) val filteredPagedRoomSummariesLive = session.roomService().getFilteredPagedRoomSummariesLive( - roomQueryParams.process(spaceFilterStrategy, appStateHandler.getSafeActiveSpaceId()), + roomQueryParams.process(spaceFilterStrategy, spaceStateHandler.getSafeActiveSpaceId()), pagedListConfig ) when (spaceFilterStrategy) { @@ -417,7 +417,7 @@ class RoomListSectionBuilder( RoomAggregateNotificationCount(it.size, it.size) } else { session.roomService().getNotificationCountForRooms( - roomQueryParams.process(spaceFilterStrategy, appStateHandler.getSafeActiveSpaceId()) + roomQueryParams.process(spaceFilterStrategy, spaceStateHandler.getSafeActiveSpaceId()) ) } ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index e51bdc5841..4b76daf502 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -25,7 +25,7 @@ import com.airbnb.mvrx.Success import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel @@ -60,7 +60,7 @@ class RoomListViewModel @AssistedInject constructor( @Assisted initialState: RoomListViewState, private val session: Session, stringProvider: StringProvider, - appStateHandler: AppStateHandler, + spaceStateHandler: SpaceStateHandler, vectorPreferences: VectorPreferences, autoAcceptInvites: AutoAcceptInvites, private val analyticsTracker: AnalyticsTracker @@ -100,7 +100,7 @@ class RoomListViewModel @AssistedInject constructor( observeMembershipChanges() observeLocalRooms() - appStateHandler.getSelectedSpaceFlow() + spaceStateHandler.getSelectedSpaceFlow() .distinctUntilChanged() .execute { copy( @@ -148,7 +148,7 @@ class RoomListViewModel @AssistedInject constructor( private val roomListSectionBuilder = RoomListSectionBuilder( session, stringProvider, - appStateHandler, + spaceStateHandler, viewModelScope, autoAcceptInvites, { diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index 291eee307f..f851c75290 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -31,7 +31,7 @@ import androidx.core.app.TaskStackBuilder import androidx.core.util.Pair import androidx.core.view.ViewCompat import com.google.android.material.dialog.MaterialAlertDialogBuilder -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.error.fatalError @@ -120,7 +120,7 @@ class DefaultNavigator @Inject constructor( private val sessionHolder: ActiveSessionHolder, private val vectorPreferences: VectorPreferences, private val widgetArgsBuilder: WidgetArgsBuilder, - private val appStateHandler: AppStateHandler, + private val spaceStateHandler: SpaceStateHandler, private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider, private val features: VectorFeatures, private val analyticsTracker: AnalyticsTracker @@ -167,7 +167,7 @@ class DefaultNavigator @Inject constructor( analyticsTracker.capture( sessionHolder.getActiveSession().getRoomSummary(roomId).toAnalyticsViewRoom( trigger = trigger, - selectedSpace = appStateHandler.getCurrentSpace() + selectedSpace = spaceStateHandler.getCurrentSpace() ) ) } @@ -182,7 +182,7 @@ class DefaultNavigator @Inject constructor( fatalError("Trying to open an unknown space $spaceId", vectorPreferences.failFast()) return } - appStateHandler.setCurrentSpace(spaceId) + spaceStateHandler.setCurrentSpace(spaceId) when (postSwitchSpaceAction) { Navigator.PostSwitchSpaceAction.None -> { // go back to home if we are showing room details? @@ -318,7 +318,7 @@ class DefaultNavigator @Inject constructor( } override fun openRoomDirectory(context: Context, initialFilter: String) { - when (val currentSpace = appStateHandler.getCurrentSpace()) { + when (val currentSpace = spaceStateHandler.getCurrentSpace()) { null -> RoomDirectoryActivity.getIntent(context, initialFilter) else -> SpaceExploreActivity.newIntent(context, currentSpace.roomId) }.start(context) @@ -330,14 +330,14 @@ class DefaultNavigator @Inject constructor( } override fun openCreateDirectRoom(context: Context) { - when (val currentSpace = appStateHandler.getCurrentSpace()) { + when (val currentSpace = spaceStateHandler.getCurrentSpace()) { null -> CreateDirectRoomActivity.getIntent(context) else -> SpacePeopleActivity.newIntent(context, currentSpace.roomId) }.start(context) } override fun openInviteUsersToRoom(context: Context, roomId: String) { - when (val currentSpace = appStateHandler.getCurrentSpace()) { + when (val currentSpace = spaceStateHandler.getCurrentSpace()) { null -> InviteUsersToRoomActivity.getIntent(context, roomId).start(context) else -> showInviteToDialog(context, currentSpace, roomId) } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index 121007cf2a..2616d808f2 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -25,7 +25,7 @@ import com.airbnb.mvrx.Uninitialized import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel @@ -58,7 +58,7 @@ class CreateRoomViewModel @AssistedInject constructor( @Assisted private val initialState: CreateRoomViewState, private val session: Session, private val rawService: RawService, - appStateHandler: AppStateHandler, + spaceStateHandler: SpaceStateHandler, private val analyticsTracker: AnalyticsTracker ) : VectorViewModel(initialState) { @@ -73,7 +73,7 @@ class CreateRoomViewModel @AssistedInject constructor( initHomeServerName() initAdminE2eByDefault() - val parentSpaceId = initialState.parentSpaceId ?: appStateHandler.getSafeActiveSpaceId() + val parentSpaceId = initialState.parentSpaceId ?: spaceStateHandler.getSafeActiveSpaceId() val restrictedSupport = session.homeServerCapabilitiesService().getHomeServerCapabilities() .isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED) 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 a72c6cc0c2..e1b845e549 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 @@ -23,7 +23,7 @@ import com.airbnb.mvrx.Success import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel @@ -61,7 +61,7 @@ import org.matrix.android.sdk.flow.flow class SpaceListViewModel @AssistedInject constructor( @Assisted initialState: SpaceListViewState, - private val appStateHandler: AppStateHandler, + private val spaceStateHandler: SpaceStateHandler, private val session: Session, private val vectorPreferences: VectorPreferences, private val autoAcceptInvites: AutoAcceptInvites, @@ -85,7 +85,7 @@ class SpaceListViewModel @AssistedInject constructor( } observeSpaceSummaries() - appStateHandler.getSelectedSpaceFlow() + spaceStateHandler.getSelectedSpaceFlow() .distinctUntilChanged() .setOnEach { selectedSpaceOption -> copy( @@ -217,7 +217,7 @@ class SpaceListViewModel @AssistedInject constructor( if (state.selectedSpace?.roomId != action.spaceSummary?.roomId) { analyticsTracker.capture(Interaction(null, null, Interaction.Name.SpacePanelSwitchSpace)) setState { copy(selectedSpace = action.spaceSummary) } - appStateHandler.setCurrentSpace(action.spaceSummary?.roomId) + spaceStateHandler.setCurrentSpace(action.spaceSummary?.roomId) _viewEvents.post(SpaceListViewEvents.CloseDrawer) } else { analyticsTracker.capture(Interaction(null, null, Interaction.Name.SpacePanelSelectedSpace)) diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt index e50fa5540c..6b1f9f88d5 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt @@ -24,7 +24,7 @@ import com.airbnb.mvrx.Uninitialized import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.EmptyViewEvents @@ -50,7 +50,7 @@ import timber.log.Timber class SpaceMenuViewModel @AssistedInject constructor( @Assisted val initialState: SpaceMenuState, val session: Session, - val appStateHandler: AppStateHandler + val spaceStateHandler: SpaceStateHandler ) : VectorViewModel(initialState) { @AssistedFactory @@ -73,9 +73,9 @@ class SpaceMenuViewModel @AssistedInject constructor( it.getOrNull()?.let { if (it.membership == Membership.LEAVE) { setState { copy(leavingState = Success(Unit)) } - if (appStateHandler.getSafeActiveSpaceId() == initialState.spaceId) { + if (spaceStateHandler.getSafeActiveSpaceId() == initialState.spaceId) { // switch to home? - appStateHandler.setCurrentSpace(null, session) + spaceStateHandler.setCurrentSpace(null, session) } } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt index 4b6657fc47..800447d4c5 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt @@ -24,7 +24,7 @@ import com.airbnb.mvrx.Uninitialized import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.AppStateHandler +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.EmptyViewEvents @@ -53,7 +53,7 @@ import timber.log.Timber class SpaceLeaveAdvancedViewModel @AssistedInject constructor( @Assisted val initialState: SpaceLeaveAdvanceViewState, private val session: Session, - private val appStateHandler: AppStateHandler + private val spaceStateHandler: SpaceStateHandler ) : VectorViewModel(initialState) { init { @@ -82,9 +82,9 @@ class SpaceLeaveAdvancedViewModel @AssistedInject constructor( ?.onEach { if (it.membership == Membership.LEAVE) { setState { copy(leaveState = Success(Unit)) } - if (appStateHandler.getSafeActiveSpaceId() == initialState.spaceId) { + if (spaceStateHandler.getSafeActiveSpaceId() == initialState.spaceId) { // switch to home? - appStateHandler.setCurrentSpace(null, session) + spaceStateHandler.setCurrentSpace(null, session) } } }?.launchIn(viewModelScope) diff --git a/vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt b/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt similarity index 73% rename from vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt rename to vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt index 6f0c33f998..8c94d5912b 100644 --- a/vector/src/test/java/im/vector/app/AppStateHandlerImplTest.kt +++ b/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt @@ -32,7 +32,7 @@ import org.junit.Before import org.junit.Test import org.matrix.android.sdk.api.session.room.model.RoomSummary -internal class AppStateHandlerImplTest { +internal class SpaceStateHandlerImplTest { private val spaceId = "spaceId" private val spaceSummary: RoomSummary = mockk() @@ -43,7 +43,7 @@ internal class AppStateHandlerImplTest { private val activeSessionHolder = FakeActiveSessionHolder(session) private val analyticsTracker = FakeAnalyticsTracker() - private val appStateHandler = AppStateHandlerImpl( + private val spaceStateHandler = SpaceStateHandlerImpl( sessionDataSource.instance, uiStateRepository, activeSessionHolder.instance, @@ -58,39 +58,39 @@ internal class AppStateHandlerImplTest { @Test fun `given selected space doesn't exist, when getCurrentSpace, then return null`() { - val currentSpace = appStateHandler.getCurrentSpace() + val currentSpace = spaceStateHandler.getCurrentSpace() currentSpace shouldBe null } @Test fun `given selected space exists, when getCurrentSpace, then return selected space`() { - appStateHandler.setCurrentSpace(spaceId, session) + spaceStateHandler.setCurrentSpace(spaceId, session) - val currentSpace = appStateHandler.getCurrentSpace() + val currentSpace = spaceStateHandler.getCurrentSpace() currentSpace shouldBe spaceSummary } @Test fun `given persistNow is true, when setCurrentSpace, then immediately persist to ui state`() { - appStateHandler.setCurrentSpace(spaceId, session, persistNow = true) + spaceStateHandler.setCurrentSpace(spaceId, session, persistNow = true) uiStateRepository.verifyStoreSelectedSpace(spaceId, session) } @Test fun `given persistNow is false, when setCurrentSpace, then don't immediately persist to ui state`() { - appStateHandler.setCurrentSpace(spaceId, session, persistNow = false) + spaceStateHandler.setCurrentSpace(spaceId, session, persistNow = false) uiStateRepository.verifyStoreSelectedSpace(spaceId, session, inverse = true) } @Test fun `given is forward navigation and no current space, when setCurrentSpace, then null added to backstack`() { - appStateHandler.setCurrentSpace(spaceId, session, isForwardNavigation = true) + spaceStateHandler.setCurrentSpace(spaceId, session, isForwardNavigation = true) - val backstack = appStateHandler.getSpaceBackstack() + val backstack = spaceStateHandler.getSpaceBackstack() backstack.size shouldBe 1 backstack.first() shouldBe null @@ -98,10 +98,10 @@ internal class AppStateHandlerImplTest { @Test fun `given is forward navigation and is in space, when setCurrentSpace, then previous space added to backstack`() { - appStateHandler.setCurrentSpace(spaceId, session, isForwardNavigation = true) - appStateHandler.setCurrentSpace("secondSpaceId", session, isForwardNavigation = true) + spaceStateHandler.setCurrentSpace(spaceId, session, isForwardNavigation = true) + spaceStateHandler.setCurrentSpace("secondSpaceId", session, isForwardNavigation = true) - val backstack = appStateHandler.getSpaceBackstack() + val backstack = spaceStateHandler.getSpaceBackstack() backstack.size shouldBe 2 backstack shouldBeEqualTo listOf(null, spaceId) @@ -109,34 +109,34 @@ internal class AppStateHandlerImplTest { @Test fun `given is not forward navigation, when setCurrentSpace, then previous space not added to backstack`() { - appStateHandler.setCurrentSpace(spaceId, session, isForwardNavigation = false) + spaceStateHandler.setCurrentSpace(spaceId, session, isForwardNavigation = false) - val backstack = appStateHandler.getSpaceBackstack() + val backstack = spaceStateHandler.getSpaceBackstack() backstack.size shouldBe 0 } @Test fun `when setCurrentSpace, then space is emitted to selectedSpaceFlow`() = runTest { - appStateHandler.setCurrentSpace(spaceId, session) + spaceStateHandler.setCurrentSpace(spaceId, session) - val currentSpace = appStateHandler.getSelectedSpaceFlow().first().orNull() + val currentSpace = spaceStateHandler.getSelectedSpaceFlow().first().orNull() currentSpace shouldBeEqualTo spaceSummary } @Test fun `given current space exists, when getSafeActiveSpaceId, then return current space id`() { - appStateHandler.setCurrentSpace(spaceId, session) + spaceStateHandler.setCurrentSpace(spaceId, session) - val activeSpaceId = appStateHandler.getSafeActiveSpaceId() + val activeSpaceId = spaceStateHandler.getSafeActiveSpaceId() activeSpaceId shouldBeEqualTo spaceId } @Test fun `given current space doesn't exist, when getSafeActiveSpaceId, then return current null`() { - val activeSpaceId = appStateHandler.getSafeActiveSpaceId() + val activeSpaceId = spaceStateHandler.getSafeActiveSpaceId() activeSpaceId shouldBe null } From 1d77f991484bf5f912497aada0d20963f0aaed2d Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 21 Jul 2022 10:37:33 +0200 Subject: [PATCH 015/175] Adds RoomSummaryFixture --- .../vector/app/SpaceStateHandlerImplTest.kt | 7 ++--- .../app/test/fixtures/RoomSummaryFixture.kt | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 vector/src/test/java/im/vector/app/test/fixtures/RoomSummaryFixture.kt diff --git a/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt b/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt index 8c94d5912b..f47f5ea9bf 100644 --- a/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt +++ b/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt @@ -21,21 +21,19 @@ import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeAnalyticsTracker import im.vector.app.test.fakes.FakeSession import im.vector.app.test.fakes.FakeUiStateRepository -import io.mockk.every +import im.vector.app.test.fixtures.RoomSummaryFixture.aRoomSummary import io.mockk.justRun -import io.mockk.mockk import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.amshove.kluent.shouldBe import org.amshove.kluent.shouldBeEqualTo import org.junit.Before import org.junit.Test -import org.matrix.android.sdk.api.session.room.model.RoomSummary internal class SpaceStateHandlerImplTest { private val spaceId = "spaceId" - private val spaceSummary: RoomSummary = mockk() + private val spaceSummary = aRoomSummary(spaceId) private val session = FakeSession.withRoomSummary(spaceSummary) private val sessionDataSource = FakeActiveSessionDataSource() @@ -53,7 +51,6 @@ internal class SpaceStateHandlerImplTest { @Before fun setup() { justRun { uiStateRepository.storeSelectedSpace(any(), any()) } - every { spaceSummary.roomId } returns spaceId } @Test diff --git a/vector/src/test/java/im/vector/app/test/fixtures/RoomSummaryFixture.kt b/vector/src/test/java/im/vector/app/test/fixtures/RoomSummaryFixture.kt new file mode 100644 index 0000000000..ee37dac618 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fixtures/RoomSummaryFixture.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 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.fixtures + +import org.matrix.android.sdk.api.session.room.model.RoomSummary + +object RoomSummaryFixture { + + fun aRoomSummary(roomId: String) = RoomSummary( + roomId, + isEncrypted = false, + encryptionEventTs = 0, + typingUsers = emptyList(), + ) +} From d8fdaf0477ad4294215779080044f591ee514c5d Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 21 Jul 2022 10:38:31 +0200 Subject: [PATCH 016/175] Moves UiStateRepository stubbing to fake class --- .../test/java/im/vector/app/SpaceStateHandlerImplTest.kt | 7 ------- .../java/im/vector/app/test/fakes/FakeUiStateRepository.kt | 5 +++++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt b/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt index f47f5ea9bf..36d372cfac 100644 --- a/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt +++ b/vector/src/test/java/im/vector/app/SpaceStateHandlerImplTest.kt @@ -22,12 +22,10 @@ import im.vector.app.test.fakes.FakeAnalyticsTracker import im.vector.app.test.fakes.FakeSession import im.vector.app.test.fakes.FakeUiStateRepository import im.vector.app.test.fixtures.RoomSummaryFixture.aRoomSummary -import io.mockk.justRun import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.amshove.kluent.shouldBe import org.amshove.kluent.shouldBeEqualTo -import org.junit.Before import org.junit.Test internal class SpaceStateHandlerImplTest { @@ -48,11 +46,6 @@ internal class SpaceStateHandlerImplTest { analyticsTracker, ) - @Before - fun setup() { - justRun { uiStateRepository.storeSelectedSpace(any(), any()) } - } - @Test fun `given selected space doesn't exist, when getCurrentSpace, then return null`() { val currentSpace = spaceStateHandler.getCurrentSpace() diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeUiStateRepository.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeUiStateRepository.kt index 3b38e4512c..4e8af9042c 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeUiStateRepository.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeUiStateRepository.kt @@ -17,12 +17,17 @@ package im.vector.app.test.fakes import im.vector.app.features.ui.UiStateRepository +import io.mockk.justRun import io.mockk.mockk import io.mockk.verify import org.matrix.android.sdk.api.session.Session class FakeUiStateRepository : UiStateRepository by mockk() { + init { + justRun { storeSelectedSpace(any(), any()) } + } + fun verifyStoreSelectedSpace(roomId: String, session: Session, inverse: Boolean = false) { verify(inverse = inverse) { storeSelectedSpace(roomId, session.sessionId) } } From 8b220de9521b348977cdc2e88649d15a434da069 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 21 Jul 2022 10:50:21 +0200 Subject: [PATCH 017/175] Adds changelog file --- changelog.d/6598.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6598.misc diff --git a/changelog.d/6598.misc b/changelog.d/6598.misc new file mode 100644 index 0000000000..db65a30bdc --- /dev/null +++ b/changelog.d/6598.misc @@ -0,0 +1 @@ +Refactors SpaceStateHandler (previously AppStateHandler) and adds unit tests for it From d8668f70bc599eb2500ac01a4fce9a21f7fcbe9e Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 21 Jul 2022 11:34:49 +0200 Subject: [PATCH 018/175] Rearranges imports --- vector/src/main/java/im/vector/app/core/di/SingletonModule.kt | 4 ++-- .../src/main/java/im/vector/app/features/home/HomeActivity.kt | 2 +- .../java/im/vector/app/features/home/HomeDetailFragment.kt | 2 +- .../vector/app/features/home/room/detail/TimelineViewModel.kt | 2 +- .../app/features/home/room/list/RoomListSectionBuilder.kt | 2 +- .../im/vector/app/features/navigation/DefaultNavigator.kt | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt index 5c70e9be53..c969df74e4 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt @@ -28,11 +28,11 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import im.vector.app.SpaceStateHandler -import im.vector.app.SpaceStateHandlerImpl import im.vector.app.BuildConfig import im.vector.app.EmojiCompatWrapper import im.vector.app.EmojiSpanify +import im.vector.app.SpaceStateHandler +import im.vector.app.SpaceStateHandlerImpl import im.vector.app.config.analyticsConfig import im.vector.app.core.dispatchers.CoroutineDispatchers import im.vector.app.core.error.DefaultErrorFormatter diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 63808ba9fd..6e77975d46 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -35,8 +35,8 @@ import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint -import im.vector.app.SpaceStateHandler import im.vector.app.R +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.registerStartForActivityResult diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index 54ff44d2c3..68e012f16e 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -28,8 +28,8 @@ import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.google.android.material.badge.BadgeDrawable -import im.vector.app.SpaceStateHandler import im.vector.app.R +import im.vector.app.SpaceStateHandler import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.toMvRxBundle import im.vector.app.core.platform.OnBackPressed diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index 0d03d21ad3..2e313f04ae 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -28,8 +28,8 @@ import com.airbnb.mvrx.Uninitialized import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.SpaceStateHandler import im.vector.app.R +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.mvrx.runCatchingToAsync diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt index 2408d157f3..8c422e60b4 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt @@ -23,8 +23,8 @@ import androidx.lifecycle.asFlow import androidx.lifecycle.liveData import androidx.paging.PagedList import com.airbnb.mvrx.Async -import im.vector.app.SpaceStateHandler import im.vector.app.R +import im.vector.app.SpaceStateHandler import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.invite.AutoAcceptInvites diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index f851c75290..877aea4ba3 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -31,8 +31,8 @@ import androidx.core.app.TaskStackBuilder import androidx.core.util.Pair import androidx.core.view.ViewCompat import com.google.android.material.dialog.MaterialAlertDialogBuilder -import im.vector.app.SpaceStateHandler import im.vector.app.R +import im.vector.app.SpaceStateHandler import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.error.fatalError import im.vector.app.features.VectorFeatures From 3df337fa0761f1eb28b857e3acbd03a925012c02 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Tue, 26 Jul 2022 12:38:29 +0200 Subject: [PATCH 019/175] Adds new layout toolbar --- .../ui-styles/src/main/res/values/dimens.xml | 3 + .../src/main/res/values/styles_toolbar.xml | 11 ++- .../src/main/res/values/theme_common.xml | 2 +- .../src/main/res/values/theme_dark.xml | 3 + .../src/main/res/values/theme_light.xml | 4 + .../res/layout/fragment_new_home_detail.xml | 92 +++++++++++++++++++ vector/src/main/res/values/strings.xml | 1 + 7 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 vector/src/main/res/layout/fragment_new_home_detail.xml diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml index 70d051b457..53f1044a12 100644 --- a/library/ui-styles/src/main/res/values/dimens.xml +++ b/library/ui-styles/src/main/res/values/dimens.xml @@ -71,4 +71,7 @@ 8dp 12dp 22dp + + + 112dp diff --git a/library/ui-styles/src/main/res/values/styles_toolbar.xml b/library/ui-styles/src/main/res/values/styles_toolbar.xml index 505419c6fe..b822dd3db7 100644 --- a/library/ui-styles/src/main/res/values/styles_toolbar.xml +++ b/library/ui-styles/src/main/res/values/styles_toolbar.xml @@ -39,4 +39,13 @@ 12sp - \ No newline at end of file + + + + + diff --git a/library/ui-styles/src/main/res/values/theme_common.xml b/library/ui-styles/src/main/res/values/theme_common.xml index 2e9c2c5123..107534fe1a 100644 --- a/library/ui-styles/src/main/res/values/theme_common.xml +++ b/library/ui-styles/src/main/res/values/theme_common.xml @@ -25,4 +25,4 @@ false - \ No newline at end of file + diff --git a/library/ui-styles/src/main/res/values/theme_dark.xml b/library/ui-styles/src/main/res/values/theme_dark.xml index f86a05ed66..9f4e5c1e28 100644 --- a/library/ui-styles/src/main/res/values/theme_dark.xml +++ b/library/ui-styles/src/main/res/values/theme_dark.xml @@ -149,6 +149,9 @@ @color/vctr_live_location_dark + + + @dimen/collapsing_toolbar_layout_medium_size diff --git a/library/ui-styles/src/main/res/values/text_appearances.xml b/library/ui-styles/src/main/res/values/text_appearances.xml index 1e60e05acf..570d26fdfd 100644 --- a/library/ui-styles/src/main/res/values/text_appearances.xml +++ b/library/ui-styles/src/main/res/values/text_appearances.xml @@ -32,6 +32,15 @@ ?vctr_content_primary + + + -